threads.c

Go to the documentation of this file.
00001 
00002 /*  $Id: threads.c 1208 2006-04-05 23:51:45Z karstenw $    */
00003 
00004 /******************************************************************************
00005 
00006     UserLand Frontier(tm) -- High performance Web content management,
00007     object database, system-level and Internet scripting environment,
00008     including source code editing and debugging.
00009 
00010     Copyright (C) 1992-2004 UserLand Software, Inc.
00011 
00012     This program is free software; you can redistribute it and/or modify
00013     it under the terms of the GNU General Public License as published by
00014     the Free Software Foundation; either version 2 of the License, or
00015     (at your option) any later version.
00016 
00017     This program is distributed in the hope that it will be useful,
00018     but WITHOUT ANY WARRANTY; without even the implied warranty of
00019     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00020     GNU General Public License for more details.
00021 
00022     You should have received a copy of the GNU General Public License
00023     along with this program; if not, write to the Free Software
00024     Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
00025 
00026 ******************************************************************************/
00027 
00028 #include "frontier.h"
00029 #include "standard.h"
00030 
00031 #ifdef MACVERSION
00032 #include <SetUpA5.h>
00033 #include "mac.h"
00034 #include "processinternal.h"
00035 #endif
00036 
00037 #include "error.h"
00038 #include "ops.h"
00039 #include "memory.h"
00040 #include "threads.h"
00041 #include "shell.h"
00042 
00043 //#define flprofile
00044 
00045 #ifdef flprofile
00046 static long ctcreated = 0;
00047 static long cttickstostart = 0;
00048 static long latency;
00049 #endif
00050 
00051 tythreadcallbacks threadcallbacks;
00052 
00053 
00054 #ifdef MACVERSION
00055     static ThreadID idwaitingthread = kNoThreadID;
00056 
00057     static ThreadID idmainthread;
00058 
00059 #endif
00060 
00061 #ifdef WIN95VERSION
00062     typedef struct tythreadmaininfo {
00063         
00064         HANDLE threadhandle;
00065 
00066         tythreadmaincallback threadmain;
00067 
00068         tythreadmainparams threadparams;
00069 
00070         void *threadglobals;
00071 
00072     #ifdef flprofile
00073         unsigned long tickscreated;
00074     #endif
00075         } tythreadmaininfo, **hdlthreadmaininfo;
00076 
00077     HANDLE hsharedthreadglobals;            // the mutex object for thread globals sharing
00078         
00079     DWORD ixlocalthreadglobals;             // Tls index for each thread's globals
00080     DWORD ixthreadglobalsgrabcount;         // Tls index of counter for nest globals grabbing
00081     DWORD idwaitingthread = 0;
00082     DWORD idmainthread;
00083 
00084     long GLOBALgrabcount;
00085 #endif
00086 
00087 
00088 #ifdef MACVERSION
00089 
00090 static pascal void copythreadcontext (ThreadID hthread, void * hglobals) {
00091 #pragma unused (hthread)
00092 
00093 #if TARGET_API_MAC_OS8
00094     long curA5 = SetUpAppA5 ();
00095 #endif
00096     
00097     (*threadcallbacks.swapoutcallback) (hglobals);
00098     
00099 #if TARGET_API_MAC_OS8
00100     RestoreA5 (curA5);
00101 #endif
00102     } /*copythreadcontext*/
00103 
00104 
00105 static pascal void swapinthreadcontext (ThreadID hthread, void * hglobals) {
00106 #pragma unused (hthread)
00107 
00108 #if TARGET_API_MAC_OS8
00109     long curA5 = SetUpAppA5 ();
00110 #endif
00111     
00112     (*threadcallbacks.swapincallback) (hglobals);
00113     
00114 #if TARGET_API_MAC_OS8
00115     RestoreA5 (curA5);
00116 #endif
00117     } /*swapinthreadcontext*/
00118 
00119 
00120 static pascal void disposethreadcontext (ThreadID hthread, void * hglobals) {
00121 #pragma unused (hthread)
00122 
00123 #if TARGET_API_MAC_OS8
00124     long curA5 = SetUpAppA5 ();
00125 #endif
00126     //Code change by Timothy Paustian Thursday, May 11, 2000 4:44:59 PM
00127     //Get rid of the UPPs for carbon here
00128     #if TARGET_API_MAC_CARBON == 1
00129     hdlthreadglobals    globals = (hdlthreadglobals)hglobals;
00130     HLock((Handle) globals);
00131     DisposeThreadSwitchUPP((**globals).threadInCallbackUPP);
00132     DisposeThreadSwitchUPP((**globals).threadOutCallbackUPP);
00133     DisposeThreadTerminationUPP((**globals).threadTerminateUPP);
00134     DisposeThreadEntryUPP((**globals).threadEntryCallbackUPP);
00135     HUnlock((Handle) globals);
00136     #endif
00137         
00138     (*threadcallbacks.disposecallback) (hglobals);
00139     
00140 #if TARGET_API_MAC_OS8
00141     RestoreA5 (curA5);
00142 #endif
00143     } /*disposethreadcontext*/
00144 
00145 
00146 static void setthreadprocs (ThreadID idthread, void * hglobals) {
00147     
00148     /*
00149     before a thread is set loose, establish our custom swapping routines
00150     */
00151     //Code change by Timothy Paustian Thursday, May 11, 2000 4:38:48 PM
00152     //creating the UPPs for use on carbon.
00153     #if TARGET_API_MAC_CARBON == 1
00154     hdlthreadglobals    globals = (hdlthreadglobals)hglobals;
00155     HLock((Handle) globals);
00156     (**globals).threadInCallbackUPP = NewThreadSwitchUPP(&swapinthreadcontext);
00157     (**globals).threadOutCallbackUPP = NewThreadSwitchUPP(&copythreadcontext);
00158     (**globals).threadTerminateUPP = NewThreadTerminationUPP(&disposethreadcontext);
00159     
00160     SetThreadSwitcher (idthread, (**globals).threadInCallbackUPP, hglobals, true);
00161     
00162     SetThreadSwitcher (idthread, (**globals).threadOutCallbackUPP, hglobals, false);
00163     
00164     SetThreadTerminator (idthread, (**globals).threadTerminateUPP, hglobals);
00165     
00166     HUnlock((Handle) globals);
00167     #else
00168         
00169     SetThreadSwitcher (idthread, &swapinthreadcontext, hglobals, true);
00170     
00171     SetThreadSwitcher (idthread, &copythreadcontext, hglobals, false);
00172     
00173     SetThreadTerminator (idthread, &disposethreadcontext, hglobals);
00174     #endif
00175         } /*setthreadprocs*/
00176 
00177 #endif
00178 
00179 boolean initmainthread (void * hglobals) {
00180 
00181 
00182     /*
00183     if (oserror (CreateThreadPool (kCooperativeThread, threadpoolsize, (Size) macmemoryconfig.minstacksize)))
00184         return (false);
00185     */
00186     
00187 #ifdef MACVERSION
00188     #if !TARGET_API_MAC_CARBON
00189         RememberA5 ();
00190         #endif /*for thread procs*/
00191     
00192     setthreadprocs (kApplicationThreadID, hglobals);
00193     
00194     GetCurrentThread (&idmainthread);
00195     
00196     return (true);
00197 #endif
00198 
00199 #ifdef WIN95VERSION
00200 
00201 #ifdef PIKE
00202 #ifndef OPMLEDITOR
00203     hsharedthreadglobals = CreateMutex (NULL, false, "Pike Thread Globals");
00204 #else  // OPMLEDITOR
00205     hsharedthreadglobals = CreateMutex (NULL, false, "OPML Thread Globals");
00206 #endif // !OPMLEDITOR
00207 #else // !PIKE
00208     hsharedthreadglobals = CreateMutex (NULL, false, "Frontier Thread Globals");
00209 #endif 
00210 
00211     ixlocalthreadglobals = TlsAlloc ();
00212     
00213     if (ixlocalthreadglobals == (DWORD) -1) {
00214         
00215         oserror (GetLastError ());
00216 
00217         return (false);
00218         }
00219 
00220     if (!TlsSetValue (ixlocalthreadglobals, hglobals)) {
00221         
00222         oserror (GetLastError ());
00223 
00224         return (false);
00225         }
00226     
00227     (*threadcallbacks.swapincallback) (hglobals);
00228 
00229     ixthreadglobalsgrabcount = TlsAlloc ();
00230     
00231     TlsSetValue (ixthreadglobalsgrabcount, 0);
00232 
00233     GLOBALgrabcount = 0;
00234 
00235     idmainthread = GetCurrentThreadId ();
00236 
00237     return (true);
00238 #endif
00239     } /*initmainthread*/
00240 
00241 
00242 boolean inmainthread (void) {
00243     
00244 #ifdef MACVERSION
00245     ThreadID idthread;
00246 
00247     GetCurrentThread (&idthread);
00248 #endif
00249 
00250 #ifdef WIN95VERSION
00251     DWORD idthread;
00252     
00253     idthread = GetCurrentThreadId ();
00254 #endif
00255     
00256     return (idthread == idmainthread);
00257     } /*inmainthread*/
00258 
00259 
00260 boolean attachtomainthread (long idthread) {
00261 #ifdef MACVERSION
00262 #   pragma unused (idthread)
00263 #endif
00264 
00265 #ifdef WIN95VERSION
00266     return (AttachThreadInput (idthread, idmainthread, true));
00267 #else
00268     return (true); /*it's a no-op*/
00269 #endif
00270     }/*attachtomainthread*/
00271 
00272 
00273 #ifdef WIN95VERSION
00274 
00275 static void *threadentry (hdlthreadmaininfo htmi) {
00276     
00277     /*
00278     5.0b14 dmb: plugged one memory leak: the handle to our thread
00279 
00280     5.0.2 dmb/rab: call disposecallback before releasing mutex
00281 
00282     5.1.5 dmb: attach thread input to main thread
00283     */
00284 
00285     tythreadmaininfo tmi = **htmi;
00286     ptrvoid hglobals = tmi.threadglobals;
00287     ptrvoid x;
00288 
00289     disposehandle ((Handle) htmi); // we have local copy, we're done with them
00290 
00291     // attach globals to the thread
00292     if (!TlsSetValue (ixlocalthreadglobals, tmi.threadglobals)) {
00293         
00294         oserror (GetLastError ());
00295 
00296         return (NULL);
00297         }
00298     
00299     // swap self in
00300     TlsSetValue (ixthreadglobalsgrabcount, (ptrvoid) 1);
00301 
00302     GLOBALgrabcount = 1;
00303     
00304     if (WaitForSingleObject (hsharedthreadglobals, INFINITE) == WAIT_FAILED) {
00305         
00306         oserror (GetLastError ());
00307         }
00308     else {
00309         
00310         DWORD idthread = GetCurrentThreadId ();
00311         BOOL res;
00312 
00313         #ifdef flprofile
00314         cttickstostart += gettickcount () - tmi.tickscreated;
00315         ctcreated += 1;
00316         latency = cttickstostart / ctcreated;
00317         #endif
00318 
00319         if (idthread == idwaitingthread)
00320             idwaitingthread = 0;
00321         
00322         (*threadcallbacks.swapincallback) (tmi.threadglobals);
00323         
00324         res = attachtomainthread (idthread); //5.1.5
00325 
00326         srand (GetTickCount ()); // 5.1.5 dmb: for multithreaded stdlib
00327 
00328         // call main
00329         x = (*tmi.threadmain) (tmi.threadparams);
00330         
00331         (*threadcallbacks.swapoutcallback) (tmi.threadglobals);
00332         
00333         // clean up
00334         (*threadcallbacks.disposecallback) (tmi.threadglobals);
00335 
00336         // swap self out, clean up
00337         ReleaseMutex (hsharedthreadglobals);
00338         }
00339     
00340     verify (CloseHandle (tmi.threadhandle));
00341     
00342     return (x);
00343     } /*threadentry*/
00344 
00345 #endif
00346 
00347 
00348 boolean newthread (tythreadmaincallback threadmain, tythreadmainparams threadparams, void *hglobals, hdlthread *hthread) {
00349 
00350 #ifdef MACVERSION
00351     OSErr err;
00352     ThreadID idthread;
00353     //Code change by Timothy Paustian Thursday, May 11, 2000 4:49:58 PM
00354     //we need to create a thread callback UPP for carbon. 
00355     #if TARGET_API_MAC_CARBON == 1
00356     hdlthreadglobals    globals = (hdlthreadglobals)hglobals;
00357     (**globals).threadEntryCallbackUPP = NewThreadEntryUPP((ThreadEntryProcPtr)threadmain);
00358     err = NewThread (kCooperativeThread, (**globals).threadEntryCallbackUPP, threadparams, (Size) macmemoryconfig.minstacksize, kUsePremadeThread + kCreateIfNeeded + kFPUNotNeeded, nil, &idthread);
00359     #else
00360         
00361 
00362     err = NewThread (kCooperativeThread, threadmain, threadparams, (Size) macmemoryconfig.minstacksize, 
00363         
00364         kUsePremadeThread + kCreateIfNeeded + kFPUNotNeeded, nil, &idthread);
00365     #endif
00366         
00367     if (oserror (err))
00368         return (false);
00369     
00370     setthreadprocs (idthread, hglobals);
00371     
00372     idwaitingthread = idthread; /*make sure we get scheduled*/
00373     
00374     *hthread = (hdlthread) idthread;
00375     
00376     return (true);
00377 #endif
00378 
00379 #ifdef WIN95VERSION
00380     Handle h;
00381     DWORD idthread;
00382     tythreadmaininfo tmi;
00383     hdlthreadmaininfo htmi;
00384     
00385     tmi.threadmain = threadmain;
00386     tmi.threadparams = threadparams;
00387     tmi.threadglobals = hglobals;
00388     
00389     if (!newfilledhandle (&tmi, sizeof (tmi), (Handle *) &htmi))
00390         return (false);
00391 
00392     h = CreateThread (NULL,  // no security attributes 
00393                     0,      // use default stack size 
00394                     (LPTHREAD_START_ROUTINE) threadentry, 
00395                     (LPVOID) htmi, // param to thread func 
00396                     CREATE_SUSPENDED, // creation flag 
00397                     &idthread);       // thread identifier
00398 
00399     if (h == NULL) {
00400         
00401         oserror (GetLastError ());
00402         
00403         return (false);
00404         }
00405     
00406     idwaitingthread = idthread;
00407 
00408     #ifdef flprofile
00409     (**htmi).tickscreated = gettickcount();
00410     #endif
00411 
00412     (**htmi).threadhandle = h;
00413 
00414     *hthread = (hdlthread) h;
00415     
00416     ResumeThread (h); // let'r fly next yield
00417 
00418     return (true);
00419 #endif
00420     } /*newthread*/
00421 
00422 
00423 boolean threadiswaiting (void) {
00424 
00425     /*
00426     5.1.5 dmb: support this verb on windows
00427     */
00428 
00429 #ifdef MACVERSION
00430     return (idwaitingthread != kNoThreadID);
00431 #endif
00432 
00433 #ifdef WIN95VERSION
00434     return (idwaitingthread != 0);
00435 #endif
00436     } /*threadiswaiting*/
00437 
00438 
00439 boolean threadyield (boolean flresting) {
00440 #pragma unused(flresting)
00441 
00442     /*
00443     5.0a19 dmb: added flresting parameter
00444     */
00445 
00446 #ifdef MACVERSION
00447     ThreadID idthread = idwaitingthread;
00448     
00449     idwaitingthread = kNoThreadID;
00450     
00451     return (YieldToThread (idthread) == noErr);
00452 #endif
00453 
00454 #ifdef WIN95VERSION
00455     ptrvoid hglobals = TlsGetValue (ixlocalthreadglobals);
00456     
00457     (*threadcallbacks.swapoutcallback) (hglobals);
00458     
00459     if (flresting)
00460         SetThreadPriority (GetCurrentThread (), THREAD_PRIORITY_BELOW_NORMAL);
00461 
00462     ReleaseMutex (hsharedthreadglobals);
00463 
00464     Sleep (0L); /*6.1b12 AR: give up the rest of our timeslice*/
00465     
00466     WaitForSingleObject (hsharedthreadglobals, INFINITE);
00467 
00468     if (flresting) {
00469         
00470     //  if (inmainthread ())
00471     //      SetThreadPriority (GetCurrentThread (), THREAD_PRIORITY_ABOVE_NORMAL);
00472     //  else
00473             SetThreadPriority (GetCurrentThread (), THREAD_PRIORITY_NORMAL);
00474         }
00475 
00476     (*threadcallbacks.swapincallback) (hglobals);
00477     
00478     return (true);
00479 #endif
00480     } /*threadyield*/
00481 
00482 
00483 #ifdef MACVERSION
00484 
00485 long grabthreadglobals (void) {return 0;}
00486 
00487 long releasethreadglobals (void) {return 0;}
00488 
00489 long grabthreadglobalsnopriority (void) {return 0;}
00490 
00491 long releasethreadglobalsnopriority (void) {return 0;}
00492 
00493 #endif
00494 
00495 #ifdef WIN95VERSION
00496 
00497 static threadglobalsgrabcount = 0; // to allow nested calls
00498 
00499 #ifdef fldebug
00500 
00501 void checkthreadglobals (void) {
00502     
00503     extern ptrvoid getcurrentthreadglobals ();
00504     
00505     assert (TlsGetValue (ixlocalthreadglobals) == getcurrentthreadglobals ());
00506     } /*checkthreadglobals*/
00507 
00508 #endif
00509 
00510 long grabthreadglobals (void) {
00511     
00512     /*
00513     intended to be called only from main, when it actually needs 
00514     its globals to be set, and is willing to be blocked.to get them.
00515     must be balanced with a call to releasethreadglobals
00516     */
00517     
00518     ptrvoid hglobals;
00519     long grabcount = (long) TlsGetValue (ixthreadglobalsgrabcount);
00520     
00521 //  assert (inmainthread ());
00522 
00523     if (grabcount++ == 0) {
00524     
00525         DWORD idthread = GetCurrentThreadId ();
00526 
00527         idwaitingthread = idthread;
00528         
00529         WaitForSingleObject (hsharedthreadglobals, INFINITE);
00530         
00531         if (idwaitingthread == idthread)
00532             idwaitingthread = 0;
00533 
00534     //  if (idthread == idmainthread)
00535     //      SetThreadPriority (GetCurrentThread (), THREAD_PRIORITY_ABOVE_NORMAL);
00536     //  else
00537             SetThreadPriority (GetCurrentThread (), THREAD_PRIORITY_NORMAL);
00538 
00539         hglobals = TlsGetValue (ixlocalthreadglobals);
00540         
00541         (*threadcallbacks.swapincallback) (hglobals);
00542         }
00543 
00544     TlsSetValue (ixthreadglobalsgrabcount, (ptrvoid) grabcount);
00545 
00546     GLOBALgrabcount = grabcount;
00547 
00548     return (grabcount);
00549     } /*grabthreadglobals*/
00550 
00551 
00552 long releasethreadglobals (void) {
00553 
00554     ptrvoid hglobals;
00555     long grabcount = (long) TlsGetValue (ixthreadglobalsgrabcount);
00556     
00557     if (--grabcount == 0) {
00558         
00559         hglobals = TlsGetValue (ixlocalthreadglobals);
00560         
00561         (*threadcallbacks.swapoutcallback) (hglobals);
00562         
00563         SetThreadPriority (GetCurrentThread (), THREAD_PRIORITY_ABOVE_NORMAL);
00564 
00565         ReleaseMutex (hsharedthreadglobals);
00566         }
00567     
00568     TlsSetValue (ixthreadglobalsgrabcount, (ptrvoid) grabcount);
00569 
00570     GLOBALgrabcount = grabcount;
00571 
00572     return (grabcount);
00573     } /*releasethreadglobals*/
00574 
00575 long grabthreadglobalsnopriority (void) {
00576     
00577     /*
00578     intended to be called only from main, when it actually needs 
00579     its globals to be set, and is willing to be blocked.to get them.
00580     must be balanced with a call to releasethreadglobalsnopriority
00581     */
00582     
00583     ptrvoid hglobals;
00584     long grabcount = (long) TlsGetValue (ixthreadglobalsgrabcount);
00585     
00586 //  assert (inmainthread ());
00587 
00588     if (grabcount++ == 0) {
00589         
00590         DWORD idthread = GetCurrentThreadId ();
00591 
00592         idwaitingthread = idthread;
00593         
00594         WaitForSingleObject (hsharedthreadglobals, INFINITE);
00595         
00596         if (idwaitingthread == idthread)
00597             idwaitingthread = 0;
00598         
00599         hglobals = TlsGetValue (ixlocalthreadglobals);
00600         
00601         (*threadcallbacks.swapincallback) (hglobals);
00602         }
00603 
00604     TlsSetValue (ixthreadglobalsgrabcount, (ptrvoid) grabcount);
00605 
00606     GLOBALgrabcount = grabcount;
00607 
00608     return (grabcount);
00609     } /*grabthreadglobalsnopriority*/
00610 
00611 
00612 long releasethreadglobalsnopriority (void) {
00613 
00614     ptrvoid hglobals;
00615     long grabcount = (long) TlsGetValue (ixthreadglobalsgrabcount);
00616     
00617     if (--grabcount == 0) {
00618         
00619         hglobals = TlsGetValue (ixlocalthreadglobals);
00620         
00621         (*threadcallbacks.swapoutcallback) (hglobals);
00622         
00623         ReleaseMutex (hsharedthreadglobals);
00624         }
00625     
00626     TlsSetValue (ixthreadglobalsgrabcount, (ptrvoid) grabcount);
00627 
00628     GLOBALgrabcount = grabcount;
00629 
00630     return (grabcount);
00631     } /*releasethreadglobalsnopriority*/
00632 
00633 #endif
00634 
00635 
00636 boolean threadstartup (void) {
00637     
00638     /*
00639     called by thread mains to let us know that hnow thead is waiting anymore
00640 
00641     under windows, we must grab a critical section before we can proceed.
00642 
00643     5.0a10 dmb: return true for windows! (was random)
00644     */
00645 
00646 #ifdef MACVERSION
00647     idwaitingthread = kNoThreadID; /*not waiting any more*/
00648     
00649     return (true);
00650 #endif
00651 
00652 #ifdef WIN95VERSION
00653     return (true);
00654 #endif
00655     } /*threadstartup*/
00656 
00657 
00658 void threadshutdown (void) {
00659     
00660 #ifdef WIN95VERSION
00661 #endif
00662     } /*threadshutdown*/
00663 
00664 
00665 boolean threadsleep (hdlthread hthread) {
00666 
00667 #ifdef MACVERSION
00668     ThreadID idthread = kCurrentThreadID;
00669     OSErr err;
00670     
00671     if (hthread != nil)
00672         idthread = (ThreadID) hthread;
00673     
00674     err = SetThreadState (idthread, kStoppedThreadState, kNoThreadID);
00675 
00676     if (err != noErr)
00677         return (false);
00678     
00679     if (idthread == idwaitingthread) //set by wakeup?
00680         idwaitingthread = 0;
00681     
00682     return (true);
00683 #endif
00684 
00685 #ifdef WIN95VERSION
00686     DWORD count;
00687     HANDLE hcurrent = GetCurrentThread ();
00688 
00689     if (hthread == nil)
00690         hthread = hcurrent;
00691     
00692     if (hthread == hcurrent)
00693         releasethreadglobalsnopriority ();
00694 
00695     count = SuspendThread (hthread);
00696 
00697     //if (idthread == idwaitingthread) //set by wakeup?
00698     //  idwaitingthread = 0;
00699     
00700     if (hthread == hcurrent)
00701         grabthreadglobalsnopriority ();
00702 
00703     return (count == 0);
00704 #endif
00705     } /*threadsleep*/
00706 
00707 
00708 boolean threadissleeping (hdlthread hthread) {
00709     
00710     /*
00711     see if the thread is sleeping
00712     */
00713     
00714 #ifdef MACVERSION
00715     ThreadState state;
00716     
00717     if (hthread == nil)
00718         return (false);
00719     
00720     if (GetThreadState ((ThreadID) hthread, &state) != noErr)
00721         return (false);
00722     
00723     return (state == kStoppedThreadState);
00724 #endif
00725 
00726 #ifdef WIN95VERSION
00727     shellerrormessage ("\x29" "Can't call threadissleeping under Windows");
00728     
00729     return (true);
00730 #endif
00731     } /*threadissleeping*/
00732 
00733 
00734 boolean threadwake (hdlthread hthread, boolean flpriority) {
00735     
00736     /*
00737     wake the thread
00738     */
00739     
00740 #ifdef MACVERSION
00741     OSErr err;
00742     
00743     if (!threadissleeping (hthread))
00744         return (false);
00745     
00746     err = SetThreadState ((ThreadID) hthread, kReadyThreadState, kNoThreadID);
00747     
00748     if (err != noErr)
00749         return (false);
00750     
00751     if (flpriority && !idwaitingthread)
00752         idwaitingthread = (ThreadID) hthread;
00753     
00754     return (true);
00755 #endif
00756 
00757 #ifdef WIN95VERSION
00758     DWORD count;
00759     
00760     count = ResumeThread (hthread);
00761     
00762     if (count != (DWORD) 1)
00763         return (false); /*either an error or it's still suspended*/
00764     
00765     // can't use idwaitingthread; maybe we should make it and idmainthread HANDLEs
00766     
00767     return (true);
00768 #endif
00769     } /*threadwake*/
00770 
00771 
00772 boolean initthreads (void) {
00773     
00774 #ifdef MACVERSION
00775     long attrs;
00776     
00777     if (!gestalt (gestaltThreadMgrAttr, &attrs))
00778         return (false);
00779     
00780     if ((attrs & (1 << gestaltThreadMgrPresent)) == 0)
00781         return (false);
00782     
00783     return (true);
00784 #endif
00785 
00786 #ifdef WIN95VERSION 
00787     return (true);
00788 #endif
00789     } /*inittheads*/
00790 
00791 

Generated on Wed May 31 18:20:03 2006 for frontierkernel 10.1.10a by  doxygen 1.4.6