00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035
00036
00037
00038
00039
00040
00041
00042
00043
00044
00045
00046
00047
00048
00049
00050
00051
00052
00053
00054
00055
00056
00057 #ifdef HAVE_CONFIG_H
00058 # include "config.h"
00059 #endif
00060 #if NEED_GNUG_PRAGMAS
00061 # pragma implementation
00062 #endif
00063
00064
00065
00066
00067
00068
00069
00070
00071
00072 #include "GThreads.h"
00073 #include "GException.h"
00074 #include "DjVuMessageLite.h"
00075 #include <stdlib.h>
00076 #include <stdio.h>
00077
00078
00079
00080
00081 #if THREADMODEL!=NOTHREADS
00082 #ifdef USE_EXCEPTION_EMULATION
00083 #warning "Compiler must support thread safe exceptions"
00084 #endif //USE_EXCEPTION_EMULATION
00085 #if defined(__GNUC__)
00086 #if (__GNUC__<2) || ((__GNUC__==2) && (__GNUC_MINOR__<=8))
00087 #warning "GCC 2.8 exceptions are not thread safe."
00088 #warning "Use properly configured EGCS-1.1 or greater."
00089 #endif // (__GNUC__<2 ...
00090 #endif // defined(__GNUC__)
00091 #endif // THREADMODEL!=NOTHREADS
00092
00093 #ifndef _DEBUG
00094 #if defined(DEBUG)
00095 #define _DEBUG
00096 #elif DEBUGLVL >= 1
00097 #define _DEBUG
00098 #endif
00099 #endif
00100
00101 #if THREADMODEL==WINTHREADS
00102 # include <process.h>
00103 #endif
00104 #if THREADMODEL==COTHREADS
00105 # include <setjmp.h>
00106 # include <string.h>
00107 # include <unistd.h>
00108 # include <sys/types.h>
00109 # include <sys/time.h>
00110 #endif
00111
00112
00113 #ifdef HAVE_NAMESPACES
00114 namespace DJVU {
00115 # ifdef NOT_DEFINED // Just to fool emacs c++ mode
00116 }
00117 #endif
00118 #endif
00119
00120
00121
00122
00123
00124
00125 #if THREADMODEL==NOTHREADS
00126 int
00127 GThread::create( void (*entry)(void*), void *arg)
00128 {
00129 (*entry)(arg);
00130 return 0;
00131 }
00132 #endif
00133
00134
00135
00136
00137
00138
00139 #if THREADMODEL==WINTHREADS
00140
00141 static unsigned __stdcall
00142 start(void *arg)
00143 {
00144 GThread *gt = (GThread*)arg;
00145 try
00146 {
00147 G_TRY
00148 {
00149 gt->xentry( gt->xarg );
00150 }
00151 G_CATCH(ex)
00152 {
00153 ex.perror();
00154 DjVuMessageLite::perror( ERR_MSG("GThreads.uncaught") );
00155 #ifdef _DEBUG
00156 abort();
00157 #endif
00158 }
00159 G_ENDCATCH;
00160 }
00161 catch(...)
00162 {
00163 DjVuMessageLite::perror( ERR_MSG("GThreads.unrecognized") );
00164 #ifdef _DEBUG
00165 abort();
00166 #endif
00167 }
00168 return 0;
00169 }
00170
00171 GThread::GThread(int stacksize)
00172 : hthr(0), thrid(0), xentry(0), xarg(0)
00173 {
00174 }
00175
00176 GThread::~GThread()
00177 {
00178 if (hthr)
00179 CloseHandle(hthr);
00180 hthr = 0;
00181 thrid = 0;
00182 }
00183
00184 int
00185 GThread::create(void (*entry)(void*), void *arg)
00186 {
00187 if (hthr)
00188 return -1;
00189 xentry = entry;
00190 xarg = arg;
00191 unsigned uthread = 0;
00192 hthr = (HANDLE)_beginthreadex(NULL, 0, start, (void*)this, 0, &uthread);
00193 thrid = (DWORD) uthread;
00194 if (hthr)
00195 return 0;
00196 return -1;
00197 }
00198
00199 void
00200 GThread::terminate()
00201 {
00202 OutputDebugString("Terminating thread.\n");
00203 if (hthr)
00204 TerminateThread(hthr,0);
00205 }
00206
00207 int
00208 GThread::yield()
00209 {
00210 Sleep(0);
00211 return 0;
00212 }
00213
00214 void *
00215 GThread::current()
00216 {
00217 return (void*) GetCurrentThreadId();
00218 }
00219
00220 struct thr_waiting {
00221 struct thr_waiting *next;
00222 struct thr_waiting *prev;
00223 BOOL waiting;
00224 HANDLE gwait;
00225 };
00226
00227 GMonitor::GMonitor()
00228 : ok(0), count(1), head(0), tail(0)
00229 {
00230 InitializeCriticalSection(&cs);
00231 locker = GetCurrentThreadId();
00232 ok = 1;
00233 }
00234
00235 GMonitor::~GMonitor()
00236 {
00237 ok = 0;
00238 EnterCriticalSection(&cs);
00239 for (struct thr_waiting *w=head; w; w=w->next)
00240 SetEvent(w->gwait);
00241 LeaveCriticalSection(&cs);
00242 DeleteCriticalSection(&cs);
00243 }
00244
00245 void
00246 GMonitor::enter()
00247 {
00248 DWORD self = GetCurrentThreadId();
00249 if (count>0 || self!=locker)
00250 {
00251 if (ok)
00252 EnterCriticalSection(&cs);
00253 locker = self;
00254 count = 1;
00255 }
00256 count -= 1;
00257 }
00258
00259 void
00260 GMonitor::leave()
00261 {
00262 DWORD self = GetCurrentThreadId();
00263 if (ok && (count>0 || self!=locker))
00264 G_THROW( ERR_MSG("GThreads.not_acq_broad") );
00265 count += 1;
00266 if (count > 0)
00267 {
00268 count = 1;
00269 if (ok)
00270 LeaveCriticalSection(&cs);
00271 }
00272 }
00273
00274 void
00275 GMonitor::signal()
00276 {
00277 if (ok)
00278 {
00279 DWORD self = GetCurrentThreadId();
00280 if (count>0 || self!=locker)
00281 G_THROW( ERR_MSG("GThreads.not_acq_signal") );
00282 for (struct thr_waiting *w=head; w; w=w->next)
00283 if (w->waiting)
00284 {
00285 SetEvent(w->gwait);
00286 w->waiting = FALSE;
00287 break;
00288 }
00289 }
00290 }
00291
00292 void
00293 GMonitor::broadcast()
00294 {
00295 if (ok)
00296 {
00297 DWORD self = GetCurrentThreadId();
00298 if (count>0 || self!=locker)
00299 G_THROW( ERR_MSG("GThreads.not_acq_broad") );
00300 for (struct thr_waiting *w=head; w; w=w->next)
00301 if (w->waiting)
00302 {
00303 SetEvent(w->gwait);
00304 w->waiting = FALSE;
00305 }
00306 }
00307 }
00308
00309 void
00310 GMonitor::wait()
00311 {
00312
00313 DWORD self = GetCurrentThreadId();
00314 if (count>0 || self!=locker)
00315 G_THROW( ERR_MSG("GThreads.not_acq_wait") );
00316
00317 if (ok)
00318 {
00319
00320 struct thr_waiting waitrec;
00321 waitrec.waiting = TRUE;
00322 waitrec.gwait = CreateEvent(NULL,FALSE,FALSE,NULL);
00323 waitrec.next = 0;
00324 waitrec.prev = tail;
00325
00326 *(waitrec.next ? &waitrec.next->prev : &tail) = &waitrec;
00327 *(waitrec.prev ? &waitrec.prev->next : &head) = &waitrec;
00328
00329 int sav_count = count;
00330 count = 1;
00331 LeaveCriticalSection(&cs);
00332 WaitForSingleObject(waitrec.gwait,INFINITE);
00333
00334 EnterCriticalSection(&cs);
00335 count = sav_count;
00336 locker = self;
00337
00338 *(waitrec.next ? &waitrec.next->prev : &tail) = waitrec.prev;
00339 *(waitrec.prev ? &waitrec.prev->next : &head) = waitrec.next;
00340 CloseHandle(waitrec.gwait);
00341 }
00342 }
00343
00344 void
00345 GMonitor::wait(unsigned long timeout)
00346 {
00347
00348 DWORD self = GetCurrentThreadId();
00349 if (count>0 || self!=locker)
00350 G_THROW( ERR_MSG("GThreads.not_acq_wait") );
00351
00352 if (ok)
00353 {
00354
00355 struct thr_waiting waitrec;
00356 waitrec.waiting = TRUE;
00357 waitrec.gwait = CreateEvent(NULL,FALSE,FALSE,NULL);
00358 waitrec.next = 0;
00359 waitrec.prev = tail;
00360
00361 *(waitrec.prev ? &waitrec.prev->next : &head) = &waitrec;
00362 *(waitrec.next ? &waitrec.next->prev : &tail) = &waitrec;
00363
00364 int sav_count = count;
00365 count = 1;
00366 LeaveCriticalSection(&cs);
00367 WaitForSingleObject(waitrec.gwait,timeout);
00368
00369 EnterCriticalSection(&cs);
00370 count = sav_count;
00371 locker = self;
00372
00373 *(waitrec.next ? &waitrec.next->prev : &tail) = waitrec.prev;
00374 *(waitrec.prev ? &waitrec.prev->next : &head) = waitrec.next;
00375 CloseHandle(waitrec.gwait);
00376 }
00377 }
00378
00379 #endif
00380
00381
00382
00383
00384
00385
00386
00387 #if THREADMODEL==MACTHREADS
00388
00389
00390 struct thr_waiting {
00391 struct thr_waiting *next;
00392 struct thr_waiting *prev;
00393 unsigned long thid;
00394 int *wchan;
00395 };
00396 static struct thr_waiting *first_waiting_thr = 0;
00397 static struct thr_waiting *last_waiting_thr = 0;
00398
00399
00400
00401
00402
00403 static void
00404 macthread_wait(ThreadID self, int *wchan)
00405 {
00406
00407 struct thr_waiting wait;
00408 wait.thid = self;
00409 wait.wchan = wchan;
00410 wait.next = 0;
00411 wait.prev = last_waiting_thr;
00412 *(wait.prev ? &wait.prev->next : &first_waiting_thr ) = &wait;
00413 *(wait.next ? &wait.next->prev : &last_waiting_thr ) = &wait;
00414
00415 (*wchan)++;
00416 SetThreadStateEndCritical(self, kStoppedThreadState, kNoThreadID);
00417
00418
00419 ThreadBeginCritical();
00420 (*wchan)--;
00421
00422 *(wait.prev ? &wait.prev->next : &first_waiting_thr ) = wait.next;
00423 *(wait.next ? &wait.next->prev : &last_waiting_thr ) = wait.prev;
00424
00425 }
00426
00427
00428 static void
00429 macthread_wakeup(int *wchan, int onlyone)
00430 {
00431 if (*wchan == 0)
00432 return;
00433 for (struct thr_waiting *q=first_waiting_thr; q; q=q->next)
00434 if (q->wchan == wchan) {
00435
00436 q->wchan = 0;
00437 SetThreadState(q->thid, kReadyThreadState, kNoThreadID);
00438 if (onlyone)
00439 return;
00440 }
00441 }
00442
00443 GThread::GThread(int stacksize)
00444 : thid(kNoThreadID), xentry(0), xarg(0)
00445 {
00446 }
00447
00448 GThread::~GThread(void)
00449 {
00450 thid = kNoThreadID;
00451 }
00452
00453 pascal void *
00454 GThread::start(void *arg)
00455 {
00456 GThread *gt = (GThread*)arg;
00457 try
00458 {
00459 G_TRY
00460 {
00461 (gt->xentry)(gt->xarg);
00462 }
00463 G_CATCH(ex)
00464 {
00465 ex.perror();
00466 DjVuMessageLite::perror( ERR_MSG("GThreads.uncaught") );
00467 #ifdef _DEBUG
00468 abort();
00469 #endif
00470 }
00471 G_ENDCATCH;
00472 }
00473 catch(...)
00474 {
00475 DjVuMessageLite::perror( ERR_MSG("GThreads.unrecognized") );
00476 #ifdef _DEBUG
00477 abort();
00478 #endif
00479 }
00480 return 0;
00481 }
00482
00483 int
00484 GThread::create(void (*entry)(void*), void *arg)
00485 {
00486 if (xentry || thid!=kNoThreadID)
00487 return -1;
00488 xentry = entry;
00489 xarg = arg;
00490 int err = NewThread( kCooperativeThread, GThread::start , this, 0,
00491 kCreateIfNeeded, (void**)nil, &thid );
00492 if( err != noErr )
00493 return err;
00494 return 0;
00495 }
00496
00497 void
00498 GThread::terminate()
00499 {
00500 if (thid != kNoThreadID) {
00501 DisposeThread( thid, NULL, false );
00502 thid = kNoThreadID;
00503 }
00504 }
00505
00506 int
00507 GThread::yield()
00508 {
00509 YieldToAnyThread();
00510 return 0;
00511 }
00512
00513 void*
00514 GThread::current()
00515 {
00516 unsigned long thid = kNoThreadID;
00517 GetCurrentThread(&thid);
00518 return (void*) thid;
00519 }
00520
00521
00522
00523 GMonitor::GMonitor()
00524 : ok(0), count(1), locker(0), wlock(0), wsig(0)
00525 {
00526 locker = kNoThreadID;
00527 ok = 1;
00528 }
00529
00530 GMonitor::~GMonitor()
00531 {
00532 ok = 0;
00533 ThreadBeginCritical();
00534 macthread_wakeup(&wsig, 0);
00535 macthread_wakeup(&wlock, 0);
00536 ThreadEndCritical();
00537 YieldToAnyThread();
00538 }
00539
00540 void
00541 GMonitor::enter()
00542 {
00543 ThreadID self;
00544 GetCurrentThread(&self);
00545 ThreadBeginCritical();
00546 if (count>0 || self!=locker)
00547 {
00548 while (ok && count<=0)
00549 macthread_wait(self, &wlock);
00550 count = 1;
00551 locker = self;
00552 }
00553 count -= 1;
00554 ThreadEndCritical();
00555 }
00556
00557 void
00558 GMonitor::leave()
00559 {
00560 ThreadID self;
00561 GetCurrentThread(&self);
00562 if (ok && (count>0 || self!=locker))
00563 G_THROW( ERR_MSG("GThreads.not_acq_leave") );
00564 ThreadBeginCritical();
00565 if (++count > 0)
00566 macthread_wakeup(&wlock, 1);
00567 ThreadEndCritical();
00568 }
00569
00570 void
00571 GMonitor::signal()
00572 {
00573 ThreadID self;
00574 GetCurrentThread(&self);
00575 if (count>0 || self!=locker)
00576 G_THROW( ERR_MSG("GThreads.not_acq_signal") );
00577 ThreadBeginCritical();
00578 macthread_wakeup(&wsig, 1);
00579 ThreadEndCritical();
00580 }
00581
00582 void
00583 GMonitor::broadcast()
00584 {
00585 ThreadID self;
00586 GetCurrentThread(&self);
00587 if (count>0 || self!=locker)
00588 G_THROW( ERR_MSG("GThreads.not_acq_broad") );
00589 ThreadBeginCritical();
00590 macthread_wakeup(&wsig, 0);
00591 ThreadEndCritical();
00592 }
00593
00594 void
00595 GMonitor::wait()
00596 {
00597
00598 ThreadID self;
00599 GetCurrentThread(&self);
00600 if (count>0 || locker!=self)
00601 G_THROW( ERR_MSG("GThreads.not_acq_wait") );
00602
00603 if (ok)
00604 {
00605
00606 ThreadBeginCritical();
00607 int sav_count = count;
00608 count = 1;
00609 macthread_wakeup(&wlock, 1);
00610 macthread_wait(self, &wsig);
00611
00612 while (ok && count<=0)
00613 macthread_wait(self, &wlock);
00614 count = sav_count;
00615 locker = self;
00616 ThreadEndCritical();
00617 }
00618 }
00619
00620 void
00621 GMonitor::wait(unsigned long timeout)
00622 {
00623
00624
00625 wait();
00626 }
00627
00628 #endif
00629
00630
00631
00632
00633
00634
00635
00636 #if THREADMODEL==POSIXTHREADS
00637
00638 #if defined(CMA_INCLUDE)
00639 #define DCETHREADS
00640 #define pthread_key_create pthread_keycreate
00641 #else
00642 #define pthread_mutexattr_default NULL
00643 #define pthread_condattr_default NULL
00644 #endif
00645
00646
00647 void *
00648 GThread::start(void *arg)
00649 {
00650 GThread *gt = (GThread*)arg;
00651 #ifdef DCETHREADS
00652 #ifdef CANCEL_ON
00653 pthread_setcancel(CANCEL_ON);
00654 pthread_setasynccancel(CANCEL_ON);
00655 #endif
00656 #else // !DCETHREADS
00657 #ifdef PTHREAD_CANCEL_ENABLE
00658 pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, 0);
00659 #endif
00660 #ifdef PTHREAD_CANCEL_ASYNCHRONOUS
00661 pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, 0);
00662 #endif
00663 #endif
00664
00665 #ifdef __EXCEPTIONS
00666 try
00667 {
00668 #endif
00669 G_TRY
00670 {
00671 (gt->xentry)(gt->xarg);
00672 }
00673 G_CATCH(ex)
00674 {
00675 ex.perror();
00676 DjVuMessageLite::perror( ERR_MSG("GThreads.uncaught") );
00677 #ifdef _DEBUG
00678 abort();
00679 #endif
00680 }
00681 G_ENDCATCH;
00682 #ifdef __EXCEPTIONS
00683 }
00684 catch(...)
00685 {
00686 DjVuMessageLite::perror( ERR_MSG("GThreads.unrecognized") );
00687 #ifdef _DEBUG
00688 abort();
00689 #endif
00690 }
00691 #endif
00692 return 0;
00693 }
00694
00695
00696
00697
00698 GThread::GThread(int stacksize) :
00699 hthr(0), xentry(0), xarg(0)
00700 {
00701 }
00702
00703 GThread::~GThread()
00704 {
00705 hthr = 0;
00706 }
00707
00708 int
00709 GThread::create(void (*entry)(void*), void *arg)
00710 {
00711 if (xentry || xarg)
00712 return -1;
00713 xentry = entry;
00714 xarg = arg;
00715 #ifdef DCETHREADS
00716 int ret = pthread_create(&hthr, pthread_attr_default, GThread::start, (void*)this);
00717 if (ret >= 0)
00718 pthread_detach(hthr);
00719 #else
00720 pthread_attr_t attr;
00721 pthread_attr_init(&attr);
00722 pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
00723 int ret = pthread_create(&hthr, &attr, start, (void*)this);
00724 pthread_attr_destroy(&attr);
00725 #endif
00726 return ret;
00727 }
00728
00729 void
00730 GThread::terminate()
00731 {
00732 if (xentry || xarg)
00733 pthread_cancel(hthr);
00734 }
00735
00736 int
00737 GThread::yield()
00738 {
00739 #ifdef DCETHREADS
00740 pthread_yield();
00741 #else
00742
00743 static struct timeval timeout = { 0, 0 };
00744 ::select(0, 0,0,0, &timeout);
00745 #endif
00746 return 0;
00747 }
00748
00749 void*
00750 GThread::current()
00751 {
00752 pthread_t self = pthread_self();
00753 #if defined(pthread_getunique_np)
00754 return (void*) pthread_getunique_np( & self );
00755 #elif defined(cma_thread_get_unique)
00756 return (void*) cma_thread_get_unique( & self );
00757 #else
00758 return (void*) self;
00759 #endif
00760 }
00761
00762
00763
00764 GMonitor::GMonitor()
00765 : ok(0), count(1), locker(0)
00766 {
00767
00768 #ifdef PTHREAD_MUTEX_INITIALIZER
00769 static pthread_mutex_t tmutex=PTHREAD_MUTEX_INITIALIZER;
00770 memcpy(&mutex,&tmutex,sizeof(mutex));
00771 #endif
00772 #ifdef PTHREAD_COND_INITIALIZER
00773 static pthread_cond_t tcond=PTHREAD_COND_INITIALIZER;
00774 memcpy(&cond,&tcond,sizeof(cond));
00775 #endif
00776
00777 pthread_mutex_init(&mutex, pthread_mutexattr_default);
00778 pthread_cond_init(&cond, pthread_condattr_default);
00779 locker = pthread_self();
00780 ok = 1;
00781 }
00782
00783 GMonitor::~GMonitor()
00784 {
00785 ok = 0;
00786 pthread_cond_destroy(&cond);
00787 pthread_mutex_destroy(&mutex);
00788 }
00789
00790
00791 void
00792 GMonitor::enter()
00793 {
00794 pthread_t self = pthread_self();
00795 if (count>0 || !pthread_equal(locker, self))
00796 {
00797 if (ok)
00798 pthread_mutex_lock(&mutex);
00799 locker = self;
00800 count = 1;
00801 }
00802 count -= 1;
00803 }
00804
00805 void
00806 GMonitor::leave()
00807 {
00808 pthread_t self = pthread_self();
00809 if (ok && (count>0 || !pthread_equal(locker, self)))
00810 G_THROW( ERR_MSG("GThreads.not_acq_broad") );
00811 count += 1;
00812 if (count > 0)
00813 {
00814 count = 1;
00815 if (ok)
00816 pthread_mutex_unlock(&mutex);
00817 }
00818 }
00819
00820 void
00821 GMonitor::signal()
00822 {
00823 if (ok)
00824 {
00825 pthread_t self = pthread_self();
00826 if (count>0 || !pthread_equal(locker, self))
00827 G_THROW( ERR_MSG("GThreads.not_acq_signal") );
00828 pthread_cond_signal(&cond);
00829 }
00830 }
00831
00832 void
00833 GMonitor::broadcast()
00834 {
00835 if (ok)
00836 {
00837 pthread_t self = pthread_self();
00838 if (count>0 || !pthread_equal(locker, self))
00839 G_THROW( ERR_MSG("GThreads.not_acq_broad") );
00840 pthread_cond_broadcast(&cond);
00841 }
00842 }
00843
00844 void
00845 GMonitor::wait()
00846 {
00847
00848 pthread_t self = pthread_self();
00849 if (count>0 || !pthread_equal(locker, self))
00850 G_THROW( ERR_MSG("GThreads.not_acq_wait") );
00851
00852 if (ok)
00853 {
00854
00855 int sav_count = count;
00856 count = 1;
00857
00858 pthread_cond_wait(&cond, &mutex);
00859
00860 count = sav_count;
00861 locker = self;
00862 }
00863 }
00864
00865 void
00866 GMonitor::wait(unsigned long timeout)
00867 {
00868
00869 pthread_t self = pthread_self();
00870 if (count>0 || !pthread_equal(locker, self))
00871 G_THROW( ERR_MSG("GThreads.not_acq_wait") );
00872
00873 if (ok)
00874 {
00875
00876 int sav_count = count;
00877 count = 1;
00878
00879 struct timeval abstv;
00880 struct timespec absts;
00881 gettimeofday(&abstv, NULL);
00882 absts.tv_sec = abstv.tv_sec + timeout/1000;
00883 absts.tv_nsec = abstv.tv_usec*1000 + (timeout%1000)*1000000;
00884 if (absts.tv_nsec > 1000000000) {
00885 absts.tv_nsec -= 1000000000;
00886 absts.tv_sec += 1;
00887 }
00888 pthread_cond_timedwait(&cond, &mutex, &absts);
00889
00890 count = sav_count;
00891 locker = self;
00892 }
00893 }
00894
00895 #endif
00896
00897
00898
00899
00900
00901
00902
00903 #if THREADMODEL==COTHREADS
00904
00905 #ifndef __GNUG__
00906 #error "COTHREADS require G++"
00907 #endif
00908 #if (__GNUC__<2) || ((__GNUC__==2) && (__GNUC_MINOR__<=90))
00909 #warning "COTHREADS require EGCS-1.1.1 with Leon's libgcc patch."
00910 #warning "You may have trouble with thread-unsafe exceptions..."
00911 #define NO_LIBGCC_HOOKS
00912 #endif
00913
00914
00915
00916
00917 #define MINSTACK (32*1024)
00918
00919 #define DEFSTACK (127*1024)
00920
00921 #define MAXFDWAIT (200)
00922
00923 #define MAXWAIT (60*60*1000)
00924
00925 #define MAXPENALTY (1000)
00926
00927 #undef COTHREAD_TRACE
00928 #undef COTHREAD_TRACE_VERBOSE
00929
00930
00931
00932 struct mach_state {
00933 jmp_buf buf;
00934 };
00935
00936 static void
00937 mach_switch(mach_state *st1, mach_state *st2)
00938 {
00939 #if #cpu(sparc)
00940 asm("ta 3");
00941 #endif
00942 if (! setjmp(st1->buf))
00943 longjmp(st2->buf, 1);
00944 }
00945
00946 static void
00947 mach_start(mach_state *st1, void *pc, char *stacklo, char *stackhi)
00948 {
00949 #if #cpu(sparc)
00950 asm("ta 3");
00951 #endif
00952 if (! setjmp(st1->buf))
00953 {
00954
00955
00956
00957
00958 #if #cpu(mips)
00959 char *sp = (char*)(((unsigned long)stackhi-16) & ~0xff);
00960 asm volatile ("move $sp,%0\n\t"
00961 "move $25,%1\n\t"
00962 "jal $25\n\t"
00963 "nop"
00964 : : "r" (sp), "r" (pc) );
00965 #elif #cpu(i386)
00966 char *sp = (char*)(((unsigned long)stackhi-16) & ~0xff);
00967 asm volatile ("movl %0,%%esp\n\t"
00968 "call *%1"
00969 : : "r" (sp), "r" (pc) );
00970 #elif #cpu(sparc)
00971 char *sp = (char*)(((unsigned long)stackhi-16) & ~0xff);
00972 asm volatile ("ta 3\n\t"
00973 "mov %0,%%sp\n\t"
00974 "call %1,0\n\t"
00975 "nop"
00976 : : "r" (sp), "r" (pc) );
00977 #elif #cpu(hppa)
00978 char *sp = (char*)(((unsigned long)stacklo+128+255) & ~0xff);
00979 asm volatile("copy %0,%%sp\n\t"
00980 "copy %1,%%r22\n\t"
00981 ".CALL\n\t"
00982 "bl $$dyncall,%%r31\n\t"
00983 "copy %%r31,%%r2"
00984 : : "r" (sp), "r" (pc) );
00985 #elif #cpu(alpha)
00986 char *sp = (char*)(((unsigned long)stackhi-16) & ~0xff);
00987 asm volatile ("bis $31,%0,$30\n\t"
00988 "bis $31,%1,$27\n\t"
00989 "jsr $26,($27),0"
00990 : : "r" (sp), "r" (pc) );
00991 #elif #cpu(powerpc)
00992 char *sp = (char*)(((unsigned long)stackhi-16) & ~0xff);
00993 asm volatile ("mr 1,%0\n\t"
00994 "mr 0,%1\n\t"
00995 "mtlr 0\n\t"
00996 "blrl"
00997 : : "r" (sp), "r" (pc) );
00998 #elif #cpu(m68k) && defined(COTHREAD_UNTESTED)
00999 char *sp = (char*)(((unsigned long)stackhi-16) & ~0xff);
01000 asm volatile ("move%.l %0,%Rsp\n\t"
01001 "jmp %a1"
01002 : : "r" (sp), "a" (pc) );
01003 #elif #cpu(arm) && defined(COTHREAD_UNTESTED)
01004 char *sp = (char*)(((unsigned long)stackhi-16) & ~0xff);
01005 asm volatile ("mov%?\t%|sp, %0\n\t"
01006 "mov%?\t%|pc, %1"
01007 : : "r" (sp), "r" (pc) );
01008 #else
01009 #error "COTHREADS not supported on this machine."
01010 #error "Try -DTHREADMODEL=NOTHREADS."
01011 #endif
01012
01013 abort();
01014
01015
01016
01017
01018
01019 }
01020 }
01021
01022 #ifdef CHECK
01023
01024 char stack[16384];
01025 mach_state st1, st2;
01026 void th2() {
01027 puts("2b"); mach_switch(&st2, &st1);
01028 puts("4b"); mach_switch(&st2, &st1);
01029 puts("6b"); mach_switch(&st2, &st1);
01030 }
01031 void th2relay() {
01032 th2(); puts("ooops\n");
01033 }
01034 void th1() {
01035 mach_start(&st1, (void*)th2relay, stack, stack+sizeof(stack));
01036 puts("3a"); mach_switch(&st1, &st2);
01037 puts("5a"); mach_switch(&st1, &st2);
01038 }
01039 int main() {
01040 puts("1a"); th1(); puts("6a");
01041 }
01042 #endif
01043
01044
01045
01046
01047
01048 struct coselect {
01049 int nfds;
01050 fd_set rset;
01051 fd_set wset;
01052 fd_set eset;
01053 };
01054
01055 static void
01056 coselect_merge(coselect *dest, coselect *from)
01057 {
01058 int i;
01059 int nfds = from->nfds;
01060 if (nfds > dest->nfds)
01061 dest->nfds = nfds;
01062 for (i=0; i<nfds; i++) if (FD_ISSET(i, &from->rset)) FD_SET(i, &dest->rset);
01063 for (i=0; i<nfds; i++) if (FD_ISSET(i, &from->wset)) FD_SET(i, &dest->wset);
01064 for (i=0; i<nfds; i++) if (FD_ISSET(i, &from->eset)) FD_SET(i, &dest->eset);
01065 }
01066
01067 static int
01068 coselect_test(coselect *c)
01069 {
01070 static timeval tmzero = {0,0};
01071 fd_set copyr = c->rset;
01072 fd_set copyw = c->wset;
01073 fd_set copye = c->eset;
01074 return select(c->nfds, ©r, ©w, ©e, &tmzero);
01075 }
01076
01077
01078
01079
01080 class GThread::cotask {
01081 public:
01082 #ifndef NO_LIBGCC_HOOKS
01083 cotask(const int xstacksize,void *);
01084 #else
01085 cotask(const int xstacksize);
01086 #endif
01087 ~cotask();
01088 class GThread::cotask *next;
01089 class GThread::cotask *prev;
01090
01091 mach_state regs;
01092
01093 char *stack;
01094 GPBuffer<char> gstack;
01095 int stacksize;
01096
01097 unsigned long over;
01098
01099 void *wchan;
01100 coselect *wselect;
01101 unsigned long *maxwait;
01102
01103 bool autodelete;
01104
01105 #ifndef NO_LIBGCC_HOOKS
01106 void *ehctx;
01107 #endif
01108 };
01109
01110 #ifndef NO_LIBGCC_HOOKS
01111 GThread::cotask::cotask(const int xstacksize, void *xehctx)
01112 #else
01113 GThread::cotask::cotask(const int xstacksize)
01114 #endif
01115 : next(0), prev(0), gstack(stack,xstacksize), stacksize(xstacksize),
01116 over(0), wchan(0), wselect(0), maxwait(0), autodelete(false)
01117 #ifndef NO_LIBGCC_HOOKS
01118 ,ehctx(xehctx)
01119 #endif
01120 {
01121 memset(®s,0,sizeof(regs));
01122 }
01123
01124 static GThread::cotask *maintask = 0;
01125 static GThread::cotask *curtask = 0;
01126 static GThread::cotask *autodeletetask = 0;
01127 static unsigned long globalmaxwait = 0;
01128 static void (*scheduling_callback)(int) = 0;
01129 static timeval time_base;
01130
01131
01132 GThread::cotask::~cotask()
01133 {
01134 gstack.resize(0);
01135 #ifndef NO_LIBGCC_HOOKS
01136 if (ehctx)
01137 free(ehctx);
01138 ehctx = 0;
01139 #endif
01140 }
01141
01142 static void
01143 cotask_free(GThread::cotask *task)
01144 {
01145 #ifdef COTHREAD_TRACE
01146 DjVuPrintErrorUTF8("cothreads: freeing task %p with autodelete=%d\n",
01147 task,task->autodelete);
01148 #endif
01149 if (task!=maintask)
01150 {
01151 delete task;
01152 }
01153 }
01154
01155
01156
01157
01158 static unsigned long
01159 time_elapsed(int reset=1)
01160 {
01161 timeval tm;
01162 gettimeofday(&tm, NULL);
01163 long msec = (tm.tv_usec-time_base.tv_usec)/1000;
01164 unsigned long elapsed = (long)(tm.tv_sec-time_base.tv_sec)*1000 + msec;
01165 if (reset && elapsed>0)
01166 {
01167 #ifdef COTHREAD_TRACE
01168 #ifdef COTHREAD_TRACE_VERBOSE
01169 DjVuPrintErrorUTF8("cothreads: %4ld ms in task %p\n", elapsed, curtask);
01170 #endif
01171 #endif
01172 time_base.tv_sec = tm.tv_sec;
01173 time_base.tv_usec += msec*1000;
01174 }
01175 return elapsed;
01176 }
01177
01178
01179
01180
01181 static int
01182 cotask_yield()
01183 {
01184
01185 if (! maintask)
01186 return 0;
01187
01188 unsigned long elapsed = time_elapsed();
01189 if (elapsed==0 && curtask->wchan==0 && curtask->prev && curtask->next)
01190 return 0;
01191
01192 curtask->over += elapsed;
01193 if (curtask->over > MAXPENALTY)
01194 curtask->over = MAXPENALTY;
01195
01196 reschedule:
01197
01198 GThread::cotask *n = curtask->next;
01199 GThread::cotask *q = n;
01200 do
01201 {
01202 if (q->wchan)
01203 {
01204 if (q->maxwait && *q->maxwait<=elapsed)
01205 {
01206 *q->maxwait = 0;
01207 q->wchan=0;
01208 q->maxwait=0;
01209 q->wselect=0;
01210 }
01211 else if (q->wselect && globalmaxwait<=elapsed && coselect_test(q->wselect))
01212 {
01213 q->wchan=0;
01214 if (q->maxwait)
01215 *q->maxwait -= elapsed;
01216 q->maxwait = 0;
01217 q->wselect=0;
01218 }
01219 if (q->maxwait)
01220 *q->maxwait -= elapsed;
01221 }
01222 q = q->next;
01223 }
01224 while (q!=n);
01225
01226 if (globalmaxwait < elapsed)
01227 globalmaxwait = MAXFDWAIT;
01228 else
01229 globalmaxwait -= elapsed;
01230
01231 static int count;
01232 unsigned long best = MAXPENALTY + 1;
01233 GThread::cotask *r = 0;
01234 count = 0;
01235 q = n;
01236 do
01237 {
01238 if (! q->wchan)
01239 {
01240 count += 1;
01241 if (best > q->over)
01242 {
01243 r = q;
01244 best = r->over;
01245 }
01246 }
01247 q = q->next;
01248 }
01249 while (q != n);
01250
01251 if (count > 0)
01252 {
01253
01254 q = n;
01255 do
01256 {
01257 q->over = (q->over>best ? q->over-best : 0);
01258 q = q->next;
01259 }
01260 while (q != n);
01261
01262 if (r != curtask)
01263 {
01264 #ifdef COTHREAD_TRACE
01265 DjVuPrintErrorUTF8("cothreads: ----- switch to %p [%ld]\n", r, best);
01266 #endif
01267 GThread::cotask *old = curtask;
01268 curtask = r;
01269 mach_switch(&old->regs, &curtask->regs);
01270 }
01271
01272 if (autodeletetask && autodeletetask->autodelete)
01273 cotask_free(autodeletetask);
01274 autodeletetask = 0;
01275
01276 if (count == 1)
01277 return 1;
01278 return 0;
01279 }
01280
01281 count = 0;
01282 unsigned long minwait = MAXWAIT;
01283 coselect allfds;
01284 allfds.nfds = 1;
01285 FD_ZERO(&allfds.rset);
01286 FD_ZERO(&allfds.wset);
01287 FD_ZERO(&allfds.eset);
01288 q = n;
01289 do
01290 {
01291 if (q->maxwait || q->wselect)
01292 count += 1;
01293 if (q->maxwait && *q->maxwait<minwait)
01294 minwait = *q->maxwait;
01295 if (q->wselect)
01296 coselect_merge(&allfds, q->wselect);
01297 q = q->next;
01298 }
01299 while (q != n);
01300
01301 if (count == 0) {
01302 DjVuMessageLite::perror( ERR_MSG("GThreads.panic") );
01303 abort();
01304 }
01305
01306 timeval tm;
01307 tm.tv_sec = minwait/1000;
01308 tm.tv_usec = 1000*(minwait-1000*tm.tv_sec);
01309 select(allfds.nfds,&allfds.rset, &allfds.wset, &allfds.eset, &tm);
01310
01311 globalmaxwait = 0;
01312 elapsed = time_elapsed();
01313 goto reschedule;
01314 }
01315
01316
01317 static void
01318 cotask_terminate(GThread::cotask *task)
01319 {
01320 #ifdef COTHREAD_TRACE
01321 DjVuPrintErrorUTF8("cothreads: terminating task %p\n", task);
01322 #endif
01323 if (task && task!=maintask)
01324 {
01325 if (task->prev && task->next)
01326 {
01327 if (scheduling_callback)
01328 (*scheduling_callback)(GThread::CallbackTerminate);
01329 task->prev->next = task->next;
01330 task->next->prev = task->prev;
01331
01332 task->prev = 0;
01333
01334 if (task == curtask)
01335 {
01336 if (task->autodelete)
01337 autodeletetask = task;
01338 cotask_yield();
01339 }
01340 }
01341 }
01342 }
01343
01344
01345 static void
01346 cotask_wakeup(void *wchan, int onlyone)
01347 {
01348 if (maintask && curtask)
01349 {
01350 GThread::cotask *n = curtask->next;
01351 GThread::cotask *q = n;
01352 do
01353 {
01354 if (q->wchan == wchan)
01355 {
01356 q->wchan=0;
01357 q->maxwait=0;
01358 q->wselect=0;
01359 q->over = 0;
01360 if (onlyone)
01361 return;
01362 }
01363 q = q->next;
01364 }
01365 while (q!=n);
01366 }
01367 }
01368
01369
01370
01371
01372 static int
01373 cotask_select(int nfds,
01374 fd_set *rfds, fd_set *wfds, fd_set *efds,
01375 struct timeval *tm)
01376 {
01377
01378 if (maintask==0 || (tm && tm->tv_sec==0 && tm->tv_usec<1000))
01379 return select(nfds, rfds, wfds, efds, tm);
01380
01381 unsigned long maxwait = 0;
01382 coselect parm;
01383
01384 curtask->wchan = (void*)&parm;
01385 if (rfds || wfds || efds)
01386 {
01387 parm.nfds = nfds;
01388 if (rfds) { parm.rset=*rfds; } else { FD_ZERO(&parm.rset); }
01389 if (wfds) { parm.wset=*wfds; } else { FD_ZERO(&parm.wset); }
01390 if (efds) { parm.eset=*efds; } else { FD_ZERO(&parm.eset); }
01391 curtask->wselect = &parm;
01392 }
01393 if (tm)
01394 {
01395 maxwait = time_elapsed(0) + tm->tv_sec*1000 + tm->tv_usec/1000;
01396 curtask->maxwait = &maxwait;
01397 }
01398
01399 cotask_yield();
01400
01401 if (tm)
01402 {
01403 tm->tv_sec = maxwait/1000;
01404 tm->tv_usec = 1000*(maxwait-1000*tm->tv_sec);
01405 }
01406 static timeval tmzero = {0,0};
01407 return select(nfds, rfds, wfds, efds, &tmzero);
01408 }
01409
01410
01411 static void
01412 cotask_get_select(int &nfds, fd_set *rfds, fd_set *wfds, fd_set *efds,
01413 unsigned long &timeout)
01414 {
01415 int ready = 1;
01416 unsigned long minwait = MAXWAIT;
01417 unsigned long elapsed = time_elapsed(0);
01418 coselect allfds;
01419 allfds.nfds=0;
01420 FD_ZERO(&allfds.rset);
01421 FD_ZERO(&allfds.wset);
01422 FD_ZERO(&allfds.eset);
01423 if (curtask)
01424 {
01425 GThread::cotask *q=curtask->next;
01426 while (q != curtask)
01427 {
01428 ready++;
01429 if (q->wchan)
01430 {
01431 if (q->wselect)
01432 coselect_merge(&allfds, q->wselect);
01433 if (q->maxwait && *q->maxwait<minwait)
01434 minwait = *q->maxwait;
01435 ready--;
01436 }
01437 q = q->next;
01438 }
01439 }
01440 timeout = 0;
01441 nfds=allfds.nfds;
01442 *rfds=allfds.rset;
01443 *wfds=allfds.wset;
01444 *efds=allfds.eset;
01445 if (ready==1 && minwait>elapsed)
01446 timeout = minwait-elapsed;
01447 }
01448
01449
01450
01451
01452
01453 #ifndef NO_LIBGCC_HOOKS
01454
01455
01456
01457 extern "C"
01458 {
01459 extern void* (*__get_eh_context_ptr)(void);
01460 extern void* __new_eh_context(void);
01461 }
01462
01463
01464
01465
01466
01467
01468 static void *
01469 cotask_get_eh_context()
01470 {
01471 if (curtask)
01472 return curtask->ehctx;
01473 else if (maintask)
01474 return maintask->ehctx;
01475 DjVuMessageLite::perror( ERR_MSG("GThreads.co_panic") );
01476 abort();
01477 }
01478 #endif
01479
01480
01481
01482
01483
01484 void
01485 GThread::set_scheduling_callback(void (*call)(int))
01486 {
01487 if (scheduling_callback)
01488 G_THROW( ERR_MSG("GThreads.dupl_callback") );
01489 scheduling_callback = call;
01490 }
01491
01492
01493 GThread::GThread(int stacksize)
01494 : task(0), xentry(0), xarg(0)
01495 {
01496
01497 if (stacksize < 0)
01498 stacksize = DEFSTACK;
01499 if (stacksize < MINSTACK)
01500 stacksize = MINSTACK;
01501
01502 if (! maintask)
01503 {
01504 #ifndef NO_LIBGCC_HOOKS
01505 static GThread::cotask comaintask(0,(*__get_eh_context_ptr)());
01506 __get_eh_context_ptr = cotask_get_eh_context;
01507 #else
01508 static GThread::cotask comaintask(0);
01509 #endif
01510 maintask = &comaintask;
01511
01512 maintask->next = maintask;
01513 maintask->prev = maintask;
01514 gettimeofday(&time_base,NULL);
01515 curtask = maintask;
01516 }
01517
01518 #ifndef NO_LIBGCC_HOOKS
01519 task = new GThread::cotask(stacksize,__new_eh_context());
01520 #else
01521 task = new GThread::cotask(stacksize);
01522 #endif
01523 }
01524
01525
01526 GThread::~GThread()
01527 {
01528 if (task && task!=maintask)
01529 {
01530 if (task->prev)
01531 task->autodelete = true;
01532 else
01533 cotask_free(task);
01534 task = 0;
01535 }
01536 }
01537
01538 #if __GNUC__ >= 3
01539 # if __GNUC_MINOR__ >= 4
01540 # define noinline __attribute__((noinline,used))
01541 # elif __GNUC_MINOR >= 2
01542 # define noinline __attribute__((noinline))
01543 # endif
01544 #endif
01545 #ifndef noinline
01546 # define noinline
01547 #endif
01548
01549 static noinline void startone(void);
01550 static noinline void starttwo(GThread *thr);
01551 static GThread * volatile starter;
01552
01553 static void
01554 startone(void)
01555 {
01556 GThread *thr = starter;
01557 mach_switch(&thr->task->regs, &curtask->regs);
01558
01559
01560
01561 starttwo(thr);
01562 abort();
01563 }
01564
01565 static void
01566 starttwo(GThread *thr)
01567 {
01568
01569
01570
01571
01572 #ifdef __EXCEPTIONS
01573 try
01574 {
01575 #endif
01576 G_TRY
01577 {
01578 thr->xentry( thr->xarg );
01579 }
01580 G_CATCH(ex)
01581 {
01582 ex.perror();
01583 DjVuMessageLite::perror( ERR_MSG("GThreads.uncaught") );
01584 #ifdef _DEBUG
01585 abort();
01586 #endif
01587 }
01588 G_ENDCATCH;
01589 #ifdef __EXCEPTIONS
01590 }
01591 catch(...)
01592 {
01593 DjVuMessageLite::perror( ERR_MSG("GThreads.unrecognized") );
01594 #ifdef _DEBUG
01595 abort();
01596 #endif
01597 }
01598 #endif
01599 cotask_terminate(curtask);
01600 GThread::yield();
01601
01602
01603 abort();
01604 }
01605
01606 int
01607 GThread::create(void (*entry)(void*), void *arg)
01608 {
01609 if (task->next || task->prev)
01610 return -1;
01611 xentry = entry;
01612 xarg = arg;
01613 task->wchan = 0;
01614 task->next = curtask;
01615 task->prev = curtask->prev;
01616 task->next->prev = task;
01617 task->prev->next = task;
01618 GThread::cotask *old = curtask;
01619 starter = this;
01620 mach_start(&old->regs, (void*)startone,
01621 task->stack, task->stack+task->stacksize);
01622 if (scheduling_callback)
01623 (*scheduling_callback)(CallbackCreate);
01624 return 0;
01625 }
01626
01627
01628 void
01629 GThread::terminate()
01630 {
01631 if (task && task!=maintask)
01632 cotask_terminate(task);
01633 }
01634
01635 int
01636 GThread::yield()
01637 {
01638 return cotask_yield();
01639 }
01640
01641 int
01642 GThread::select(int nfds,
01643 fd_set *readfds, fd_set *writefds, fd_set *exceptfds,
01644 struct timeval *timeout)
01645 {
01646 return cotask_select(nfds, readfds, writefds, exceptfds, timeout);
01647 }
01648
01649 void
01650 GThread::get_select(int &nfds, fd_set *rfds, fd_set *wfds, fd_set *efds,
01651 unsigned long &timeout)
01652 {
01653 cotask_get_select(nfds, rfds, wfds, efds, timeout);
01654 }
01655
01656 inline void *
01657 GThread::current()
01658 {
01659 if (curtask && curtask!=maintask)
01660 return (void*)curtask;
01661 return (void*)0;
01662 }
01663
01664
01665
01666
01667 GMonitor::GMonitor()
01668 : count(1), locker(0), wlock(0), wsig(0)
01669 {
01670 locker = 0;
01671 ok = 1;
01672 }
01673
01674 GMonitor::~GMonitor()
01675 {
01676 ok = 0;
01677 cotask_wakeup((void*)&wsig, 0);
01678 cotask_wakeup((void*)&wlock, 0);
01679 cotask_yield();
01680
01681
01682
01683 }
01684
01685 void
01686 GMonitor::enter()
01687 {
01688 void *self = GThread::current();
01689 if (count>0 || self!=locker)
01690 {
01691 while (ok && count<=0)
01692 {
01693 curtask->wchan = (void*)&wlock;
01694 wlock++;
01695 cotask_yield();
01696 wlock--;
01697 }
01698 count = 1;
01699 locker = self;
01700 }
01701 count -= 1;
01702 }
01703
01704 void
01705 GMonitor::leave()
01706 {
01707 void *self = GThread::current();
01708 if (ok && (count>0 || self!=locker))
01709 G_THROW( ERR_MSG("GThreads.not_acq_leave") );
01710 if (++count > 0 && wlock > 0)
01711 cotask_wakeup((void*)&wlock, 1);
01712 }
01713
01714 void
01715 GMonitor::signal()
01716 {
01717 void *self = GThread::current();
01718 if (count>0 || self!=locker)
01719 G_THROW( ERR_MSG("GThreads.not_acq_signal") );
01720 if (wsig > 0)
01721 {
01722 cotask_wakeup((void*)&wsig, 1);
01723 if (scheduling_callback)
01724 (*scheduling_callback)(GThread::CallbackUnblock);
01725 }
01726 }
01727
01728 void
01729 GMonitor::broadcast()
01730 {
01731 void *self = GThread::current();
01732 if (count>0 || self!=locker)
01733 G_THROW( ERR_MSG("GThreads.not_acq_broad") );
01734 if (wsig > 0)
01735 {
01736 cotask_wakeup((void*)&wsig, 0);
01737 if (scheduling_callback)
01738 (*scheduling_callback)(GThread::CallbackUnblock);
01739 }
01740 }
01741
01742 void
01743 GMonitor::wait()
01744 {
01745
01746 void *self = GThread::current();
01747 if (count>0 || locker!=self)
01748 G_THROW( ERR_MSG("GThreads.not_acq_wait") );
01749
01750 if (ok)
01751 {
01752
01753 int sav_count = count;
01754 count = 1;
01755 curtask->wchan = (void*)&wsig;
01756 cotask_wakeup((void*)&wlock, 1);
01757 wsig++;
01758 cotask_yield();
01759 wsig--;
01760
01761 while (ok && count <= 0)
01762 {
01763 curtask->wchan = (void*)&wlock;
01764 wlock++;
01765 cotask_yield();
01766 wlock--;
01767 }
01768 count = sav_count;
01769 locker = self;
01770 }
01771 }
01772
01773 void
01774 GMonitor::wait(unsigned long timeout)
01775 {
01776
01777 void *self = GThread::current();
01778 if (count>0 || locker!=self)
01779 G_THROW( ERR_MSG("GThreads.not_acq_wait") );
01780
01781 if (ok)
01782 {
01783
01784 int sav_count = count;
01785 count = 1;
01786 unsigned long maxwait = time_elapsed(0) + timeout;
01787 curtask->maxwait = &maxwait;
01788 curtask->wchan = (void*)&wsig;
01789 cotask_wakeup((void*)&wlock, 1);
01790 wsig++;
01791 cotask_yield();
01792 wsig--;
01793
01794 while (ok && count<=0)
01795 {
01796 curtask->wchan = (void*)&wlock;
01797 wlock++;
01798 cotask_yield();
01799 wlock--;
01800 }
01801 count = sav_count;
01802 locker = self;
01803 }
01804 }
01805
01806 #endif
01807
01808
01809
01810
01811
01812
01813
01814
01815
01816
01817 GSafeFlags &
01818 GSafeFlags::operator=(long xflags)
01819 {
01820 enter();
01821 if (flags!=xflags)
01822 {
01823 flags=xflags;
01824 broadcast();
01825 }
01826 leave();
01827 return *this;
01828 }
01829
01830 GSafeFlags::operator long(void) const
01831 {
01832 long f;
01833 ((GSafeFlags *) this)->enter();
01834 f=flags;
01835 ((GSafeFlags *) this)->leave();
01836 return f;
01837 }
01838
01839 bool
01840 GSafeFlags::test_and_modify(long set_mask, long clr_mask,
01841 long set_mask1, long clr_mask1)
01842 {
01843 enter();
01844 if ((flags & set_mask)==set_mask &&
01845 (~flags & clr_mask)==clr_mask)
01846 {
01847 long new_flags=flags;
01848 new_flags|=set_mask1;
01849 new_flags&=~clr_mask1;
01850 if (new_flags!=flags)
01851 {
01852 flags=new_flags;
01853 broadcast();
01854 }
01855 leave();
01856 return true;
01857 }
01858 leave();
01859 return false;
01860 }
01861
01862 void
01863 GSafeFlags::wait_and_modify(long set_mask, long clr_mask,
01864 long set_mask1, long clr_mask1)
01865 {
01866 enter();
01867 while((flags & set_mask)!=set_mask ||
01868 (~flags & clr_mask)!=clr_mask) wait();
01869 long new_flags=flags;
01870 new_flags|=set_mask1;
01871 new_flags&=~clr_mask1;
01872 if (flags!=new_flags)
01873 {
01874 flags=new_flags;
01875 broadcast();
01876 }
01877 leave();
01878 }
01879
01880
01881
01882 #ifdef HAVE_NAMESPACES
01883 }
01884 # ifndef NOT_USING_DJVU_NAMESPACE
01885 using namespace DJVU;
01886 # endif
01887 #endif