home *** CD-ROM | disk | FTP | other *** search
/ Language/OS - Multiplatform Resource Library / LANGUAGE OS.iso / oper_sys / quartz / quartz10.lha / src / presto / threads.c < prev    next >
Encoding:
C/C++ Source or Header  |  1990-05-02  |  19.2 KB  |  787 lines

  1. /*
  2.  * threads.c
  3.  *
  4.  *    Main implementation for threads.
  5.  *
  6.  *      Last modified:          12/5/89
  7.  *      by:                     jef
  8.  *      reason:                 Remove all stack free lists.  Allocate stacks
  9.  *                              of fixed size when thread is allocated.  Stack
  10.  *                              remains associated with owning thread.  More
  11.  *                              efficient (removes search of stack freelist for
  12.  *                              stack of proper size, allocation of stack if
  13.  *                              one of proper size not found, and eliminates
  14.  *                              need to balance stack freelists).
  15.  *
  16.  *      Last modified:          11/8/89
  17.  *      by:                     jef
  18.  *      reason:                 implement local free lists of thread
  19.  *                              templates.
  20.  *
  21.  *      Last modified:          2/4/88
  22.  *      by:                     bnf
  23.  *      reason:                 streamline free pool code
  24.  *
  25.  *    Last modified:        1/6/88
  26.  *    by:            bnb
  27.  *    reason:            remove knowledge of specific sycnchroobjects
  28.  *
  29.  *    Last modified:        1/2/88
  30.  *    by:            bnb
  31.  *    reason:            willjoin and join
  32.  *
  33.  *
  34.  *    Last modified:        12/21/87
  35.  *    by:            bnb
  36.  *    reason:            nuke old version (non asm) of swtch
  37.  *
  38.  *    Last modified:        8/15/88
  39.  *    by:            chase
  40.  *    reason:            VAX/Unix and other support etc.
  41.  */
  42.  
  43. #define _THREADS_C
  44.  
  45. #include "presto.h"
  46. #include "machdep.h"
  47.  
  48.  
  49. //
  50. // thisthread ALWAYS refers to the currently running thread in the
  51. // context of the user.  thisthread must be private to each processor,
  52. // but is set on context switches appropriately.
  53. // Use staticthread to give us something to reference into before
  54. // the system gets going during the static construction.
  55. //
  56.  
  57. private_t Thread staticthread(-1);
  58. Thread *systhread = &staticthread;
  59.  
  60. private_t Thread *thisthread = &staticthread;
  61. private_t int _rtmp;    // must be private (hack to simplify asm movs)
  62.  
  63. extern Main *MAIN;
  64.  
  65. //
  66. //
  67. // Some notes on constructors:
  68. //    Automatic constructors of base and sub classes are painful.
  69. //    If we are resurrecting an old thread, we don't need to go
  70. //    through all of the  rigamarole to reinit its member
  71. //    elements.  Instead, when first constructed,
  72. //    we call "init" on them, and 
  73. //    let them do the work involved in making themnselves for the
  74. //    first time.  After that, they are presumed to be "reusable"
  75. //    after calling "reinit".
  76. //
  77. //      NOTE - ssiz is ignored (replaced by Main::stacksize unless ssiz is 0.
  78. //
  79.  
  80. Thread::Thread(char *name, int tid, long ssiz)     : (OBJ_THREAD, name)
  81. {
  82. #ifdef DEBUG_STARTUP
  83.         cout << form("creating thread %s, thisproc = %x, ssiz = %d\n",
  84.                      name, thisproc, ssiz);
  85. #endif DEBUG_STARTUP
  86.  
  87.     if (this == 0)    {        // no derived class
  88.                 int    init_reqd;
  89.                 this = thisproc->get_thread (&init_reqd);
  90.                 if (init_reqd)          // initialization reqd if allocated
  91.                 {                       //   instead of being reused.
  92.                     t_stack_size = 0;// no stack yet
  93.                 }
  94.         t_slockcount = 0;
  95.         t_callstate.init();    // intentional ctor
  96.         t_expired = 0;
  97.     } else    {            // derived class
  98.         this = this;
  99.         t_slockcount = 0;
  100.         t_callstate.init();
  101.         t_expired = 0;
  102.     }    
  103.  
  104. #ifdef debug
  105.     dout << form("thisthread creating thread %s (%x)\n",
  106.         name, this);
  107. #endif debug
  108.  
  109.     t_flags = 0;
  110.     t_data = (Objany)0;
  111.     
  112.         //
  113.         //  Make sure this thread has a stack.
  114.         //
  115.     if (ssiz == 0)    {
  116.                 // ssiz of 0 means run on existing stack.
  117.  
  118.                 // If this thread already has a stack then delete it.
  119.                 if (t_stack_size) {
  120. //                  cout << "deleting existing stack for size=0\n";
  121.                     delete t_stack;
  122.                 }
  123.                 t_stack = new Stack(0);
  124.                 t_stack_size = 0;
  125.                 t_flags = TF_KEEPSTACK;
  126.         }
  127.  
  128.         //
  129.         //  If stack is not of proper size, get new stack.
  130.         //
  131.         else if (t_stack_size != MAIN->get_stacksize()) {
  132.                 // Delete old one if it exists.
  133.                 if (t_stack_size) {
  134. //                  cout << "existing stack not default size - deleting it\n";
  135.                     delete t_stack;
  136.                 }
  137. //              else
  138. //                    cout << "thread had no stack\n";
  139.  
  140.                 // now get new stack of proper size
  141.                 t_stack = new Stack (MAIN->get_stacksize());
  142.                 t_stack_size = MAIN->get_stacksize();
  143. //              cout << "allocating stack of size "
  144. //                   << MAIN->get_stacksize() << "\n";
  145.         }
  146.  
  147.     t_csp = 0;
  148.     t_fp = 0;
  149.     // t_stack already set
  150.     t_state =  TS_IDLE;
  151.     // t_flags already set
  152.     t_tag = tid;
  153.     t_tid = tid;
  154.     t_pri = TP_BASEPRIO;
  155.     t_proc = 0;            // running on
  156.     t_blockedon = 0;        // waiting on
  157.     t_jthread = 0;            // joining thread
  158.  
  159. #ifdef PROFILE
  160.     qThread = 0;
  161. #endif
  162. #ifdef DEBUG_STARTUP
  163.         cout << "exiting thread ctor\n";
  164. #endif DEBUG_STARTUP
  165. }
  166.  
  167. //
  168. // Thread constructor for staticthread.
  169. //
  170.  
  171. extern Process staticproc;
  172.  
  173. Thread::Thread(int tid)
  174. {
  175. #ifdef DEBUG_STARTUP
  176.     //cout << "ctor for static thread\n";     cout here causes seg fault!
  177. #endif DEBUG_STARTUP
  178.  
  179.     setflags(TF_SCHEDULER | TF_NONPREEMPTABLE);
  180.     setproc(&staticproc);
  181.     t_expired = 0;
  182.     t_slockcount = 0;
  183.     t_tid = tid;
  184. #ifdef PROFILE
  185.     qThread = 0;
  186. #endif
  187. }
  188.  
  189. //
  190. // "Virtual" constructor
  191. //
  192. Thread*
  193. Thread::newthread(char *name, int tid, long ssiz)
  194. {
  195.     return new Thread (name, tid, ssiz);
  196. }
  197.  
  198.  
  199. //
  200. // Delete a thread:
  201. //        When a thread comes here, it will never run again.
  202. //        If the thread will be joined upon, don't restore it to
  203. //        the thread free pool, otherwise do.
  204. //        
  205. //        if we make it to the final return, the regular deallocation
  206. //        will take place.
  207. //
  208. //
  209. //        We make sure that the guy being deleted is
  210. //        actually finished.   Eventually, we should be
  211. //        able to halt him midstream, for now, we just
  212. //        wait until he is done.  This is used by join
  213. //        to make sure that we don't destroy a thread
  214. //        before it has finished executing.
  215. //
  216. Thread::~Thread()
  217. {
  218. #ifdef PROFILE
  219.         QThreadRelease(qThread);
  220. #endif
  221.     if (this == &staticthread) {
  222.         this = 0;
  223.         return;
  224.     }
  225.  
  226.     while (t_state&TS_RUNNING)
  227.         ;
  228.  
  229.         //
  230.         //  If thread is not idle (created but not started) then
  231.         //  if it is not finished then report an error.
  232.         //
  233.         if ( (t_state&TS_IDLE) == 0)
  234.             if (((t_state&TS_FINISHED) == 0) && ((t_state&TS_DELETE) == 0))
  235.                 error("Destroying an unfinished thread");
  236.  
  237.  
  238.         if ((t_state&TS_DELETE) == 0) {
  239.                 thisproc->free_thread (this);
  240.                 this = 0;
  241.         return;
  242.         }
  243.  
  244.         //
  245.         // if this != 0, regular deallocation will occur here.
  246.         // if a stack was allocated, be sure to give it back first.
  247.         //
  248.         if ( (this != 0) && (t_stack != 0) ) delete t_stack;
  249. }
  250.  
  251.  
  252. //
  253. // Start a thread running in some invocation function of an object.
  254. //    We save the callstate from the the start call and use it
  255. //    later when we actually get this puppy scheduled.  We are
  256. //    trying not to be machine dependent here, but we are still
  257. //    assuming:
  258. //    -    sizeof(Objany) == sizeof(PFany) == sizeof(int*)
  259. //    -    args are pushed in the stack in a sensible order so
  260. //        we can figure out what comes next
  261. //    --    that we can figure out how many longwords we
  262. //        were called with through some func nargs().
  263. //        On the vax this is just an inspection of *(ap).  On
  264. //        the ns32000 we can get away with using libpps's nargs()
  265. //        though what they are doing is very simple (see nargs.c 
  266. //        in the distribution directory).
  267. //
  268. //    Fork:
  269. //        if (this == thisthread) 
  270. //        then we just start up an asynchronous invocation using 
  271. //        an anonymous
  272. //        thread having the same params as the starting thread.
  273. //        This allows people to make asynchronous invocation
  274. //        without having to create threads explicitly.  First arg
  275. //        specifies if they will join on the thread or not.  Forked
  276. //        thread is returned.
  277. // 
  278. //
  279.  
  280. #define NUMSTARTARGS    3
  281.  
  282. int
  283. Thread::start(Objany obj, PFany pf, ...)
  284. {
  285.     extern int nargs();
  286.     
  287.     if ( (t_state&TS_IDLE) == 0)
  288.         error("Can't start an invocation in a busy thread");
  289.     
  290.     //
  291.     // We don't want the hidden first arg this, obj, or pf.
  292.     //    -NUMSTARTARGS is the first argument that we need to save.
  293.     //
  294. /*XX MACHDEP */
  295. #ifdef PROFILE
  296.     qThread = QThreadStart(this->name(), this->flags() & TF_SCHEDULER);
  297. #endif
  298.     t_callstate.set(pf, nargs()-NUMSTARTARGS, ((int*)(&pf)+1));
  299.     t_start1(obj);
  300.     return 0;
  301. }
  302.         
  303.     
  304. #define NUMFORKARGS    4
  305.  
  306. Thread*
  307. Thread::fork(int needjoin, Objany obj, PFany pf, ...)
  308. {
  309.     register Thread* startthread;
  310.     extern int nargs();
  311.     
  312.     if (this == thisthread)    {
  313.         // newthread here
  314.         startthread = newthread(name(), 0, stack()->size());
  315.         if (startthread == 0)
  316.             thisthread->error("Can't create asynch invocation");
  317.     }  else        {
  318.         // can't control thread if its not thisthread
  319.         // must disallow forking on threads other than thisthread
  320.         this->error("Can only fork off of thisthread");
  321.     }
  322.             
  323.     if (needjoin == TF_WILLJOIN)
  324.         startthread->willjoin();
  325.     
  326.     //
  327.     // We don't want the hidden first arg this, needjoin, obj, or pf.
  328.     //    -NUMFORKARGS is the first argumennt that we need to save.
  329.     // 
  330. /*XX MACHDEP */
  331. #ifdef PROFILE
  332.     startthread->qThread = QThreadStart(startthread->name());
  333. #endif
  334.     startthread->t_callstate.set(pf, nargs()-NUMFORKARGS, ((int*)(&pf)+1));
  335.     startthread->t_start1(obj);
  336.     return startthread;
  337. }
  338.  
  339.  
  340.  
  341. //
  342. // Pass new thread to the scheduler
  343. //
  344. void
  345. Thread::t_start1(Objany obj)
  346. {
  347.     extern shared_t ThreadQ    *preschedthreads;
  348.     t_boundobj = obj;
  349.     setstate(TS_VIRGIN);
  350.     if ((t_flags&TF_SCHEDULER)==0) {    
  351.         // don't schedule the scheduler 
  352.         if (sched)
  353.             sched->begin(this); 
  354.         else    {            // must deal with early thread
  355.             if (preschedthreads == 0)
  356.                 preschedthreads = new ThreadQ(TS_VIRGIN);
  357.             preschedthreads->append(this);
  358.         }
  359.     }
  360.     return;
  361. }
  362.  
  363.  
  364. //
  365. // Spinning wait for thread to stop running
  366. //
  367. void
  368. Thread::isrunning2()
  369. {
  370.     while (t_state&TS_RUNNING)
  371.         ;
  372. }
  373.  
  374.  
  375.  
  376. //
  377. // Why do we need to know why we woke up?  I don't think so
  378. //
  379.  
  380. void
  381. Thread::wakeup(SynchroObject* so = 0)
  382. {
  383.     //
  384.     // Hold off on waking a thread that is running, but going to sleep.
  385.     // Not doing so may cause us to trash the thread's object fields.
  386.     //
  387.     isrunning2();
  388.         
  389.     if ( (t_state & (TS_BLOCKED)) == 0)
  390.         error("Waking a non-blocked object");
  391.  
  392.     if (so && t_blockedon != so)    
  393.         error("Wokeup on the wrong thing!");
  394.         
  395.     andstate(~(TS_BLOCKED));    
  396.     t_blockedon = 0;
  397.     sched->resume(this);
  398. }
  399.  
  400.  
  401. int
  402. Thread::run()
  403. {
  404.     int    results;
  405.     Thread *schedthread = thisthread;
  406.  
  407. #ifdef DEBUG_STARTUP
  408.         cout << "in Thread::run()\n"; cout.flush ();
  409. #endif DEBUG_STARTUP
  410.  
  411.     this->setproc(thisproc);
  412.  
  413.     thisthread = this;
  414.  
  415.     schedthread->isnotrunning();
  416.     this->isrunning();
  417.     results = this->runrun();        // BOOM
  418.     this->isnotrunning();
  419.  
  420. #ifdef PROFILE
  421.     QThreadIdle(qThread);    /* before deleting the old thread */
  422. #endif
  423.  
  424.     // if finished, and nobody will join on this thread, delete it.
  425.     if (t_state & TS_FINISHED)
  426.         if ((t_flags & TF_WILLJOIN) == 0)
  427.             delete this;
  428.  
  429.     thisthread = schedthread;
  430.  
  431.     schedthread->isrunning();
  432.     return results;
  433. }
  434.  
  435.  
  436. // 
  437. // runrun:
  438. //
  439. // This is a very central and somewhat difficult routine.
  440. //
  441. //
  442. // Begin the invocation in the invocation object using the current
  443. // thread running in the current processor
  444. //
  445. // This is essentialy a synchronous fork.  Control returns the processor
  446. // thread when forked thread blocks or terminates via a swtch back
  447. // from the invocation function.
  448. //
  449. // We don't worry about saving the regs on the right stack when we do
  450. // the stack switch inside the virgin test.  No register context ever
  451. // needs to be restored since threads, once they terminate, never return.
  452. //
  453.  
  454. int
  455. Thread::runrun()
  456. {
  457.     int dummy;            /// MUST BE FIRST
  458. #ifdef vax
  459.     int _rtmp = 0;            /// MUST BE SECOND
  460. #endif vax
  461.  
  462. #ifdef DEBUG_STARTUP
  463.         cout << form("runrun: begin thread %x\n", this); cout.flush();
  464. #endif DEBUG_STARTUP
  465.  
  466. #ifdef debug
  467.         dout << form("runrun: begin thread %x\n", this);
  468. #endif debug
  469.  
  470. //    t_timer.timerstart();  XXX
  471.     t_expired = 0;
  472.  
  473.     if (t_state & TS_VIRGIN)        {
  474.  
  475. #ifdef DEBUG_STARTUP
  476.                 cout << "runrun: virgin thread\n"; cout.flush();
  477. #endif DEBUG_STARTUP
  478.  
  479.         //
  480.         // Thread must be nonpreemptable while we are first
  481.         // initializing it (a swtch back before it has enough
  482.         // state to determine to whom we should switch would
  483.         // be bad news)
  484.  
  485.                 //
  486.                 // If not a whole thread, report an error.  Thread stacks
  487.                 // are allocated in the thread constructor now.
  488.                 //
  489.                 if (t_flags&TF_INCOMPLETE)      {
  490.                         error ("Thread is incomplete in runrun");
  491.                 }
  492.  
  493. #if    (i386 || sun)
  494.         //
  495.         // Insure stack of calling (process) thread is cleanly restored
  496.         // (including registers) when new thread next switches.
  497.         //
  498.         // Do this cleanly -- push a proper "swtch" context in
  499.         // current stack, and return on new stack.  When the
  500.         // thread swtch()'s back, will return from runrun(), but
  501.         // with proper register state.  Must insure runrun()
  502.         // doesn't have any register variables (if so, need to get
  503.         // them from the stack).  Older technique (ns32000,
  504.         // anyhow) has stack-pointer pass frame-pointer, then
  505.         // adjust frame pointer back on 1st swtch() back from new
  506.         // thread, and restores "random" register contents.
  507.         //
  508.         // First call to runrun() by "slave" process thread starts
  509.         // process thread itself; in this case, TF_KEEPSTACK is on.
  510.         // Since keeping calling stack, have the new stack top out
  511.         // at the dummy variable in this procedure (leaving enough
  512.         // room for swtch() context).
  513.         //
  514.         extern init_stack(Thread*,int*);
  515.         init_stack(this, (this->t_flags&TF_KEEPSTACK)
  516.             ? &dummy-16 : t_stack->top());
  517. #endif    (i386 || sun)
  518.  
  519. #if (ns32000 || vax)
  520.         t_fp = FP(dummy);
  521.         if ((this->t_flags&TF_KEEPSTACK) == 0)    {
  522.             //
  523.             // remember current sp
  524.             //
  525. #ifdef ns32000
  526.             { asm("sprd    sp, __rtmp"); }
  527. #endif
  528. #ifdef vax
  529.             { asm("movl    sp, -8(fp)"); }
  530. #endif
  531.             t_csp = (int*)_rtmp;            
  532.  
  533.             //
  534.             // load new sp with the top of the new stack
  535.             //
  536.             _rtmp = (int)(t_stack->top());
  537.             // lose any stored regs from previous context...
  538.             // but not important.
  539. #ifdef vax
  540.             { asm("movl    -8(fp), sp"); }
  541. #endif
  542. #ifdef ns32000
  543.             { asm("lprd    sp, __rtmp"); }
  544. #endif
  545.         }
  546. #endif    (vax || ns32000)
  547.  
  548.         // We invoke the saved callstate with a "zero" sp
  549.         // indicator to say "just go ahead and use whatever
  550.         // stack you are currently running on.
  551.         //
  552.  
  553. #ifdef DEBUG_STARTUP
  554.                 cout << "runrun: invoking saved callstate\n"; cout.flush();
  555. #endif DEBUG_STARTUP
  556.  
  557.         (void)this->t_callstate.call(0,t_boundobj);
  558.  
  559.         // NOT REACHED:
  560.         // We can never return normally from the invocation
  561.         // since the fp which is created on the call points
  562.         // back to the stack of the processor thread which
  563.         // is handling the invocation.  Since its not likely
  564.         // that processor's thread will be in the same state 
  565.         // when the invocation return we can't use it for
  566.         // anything.  callstate->call must swtch back to us, after
  567.         // returning the thread to the free pool.
  568.         //
  569.         // We wouldn't have to worry about any of this if we
  570.         // were running on a uniprocessor
  571.         //
  572.         error("Return to runrun!");
  573.         
  574.     }  else    {
  575.         (void)swtch();    
  576.     //
  577.     // NOTREACHED
  578.     //        
  579.     }
  580.     return 0;        // for the compiler only
  581. }
  582.  
  583.  
  584. //
  585. // Go to sleep on a synchronization object.  
  586. // The synchronization object has already taken care of the semantics
  587. // of going to sleep.  We just change our state and conk out...
  588. //
  589. void
  590. Thread::sleep(SynchroObject* so = 0)
  591. {
  592.  
  593.     if (this != thisthread)
  594.         error("this!=thisthread in sleep. HELP!");
  595.         
  596.     t_blockedon = so;
  597.     
  598.     if ((t_state&TS_RUNNING)==0)
  599.         error("Can't block a non running thread");
  600.  
  601.     (void)swtch();
  602.     // wakeup here    
  603. }
  604.  
  605.  
  606. double 
  607. Thread::cputime()
  608. {
  609.     return 0;     
  610. }
  611.  
  612. int
  613. Thread::canpreempt()
  614.     if ((t_state&TS_RUNNING) &&            // is running
  615.        ((t_flags&TF_NONPREEMPTABLE) == 0)    &&     // is preemptable
  616.        ( t_slockcount == 0) &&            // not in spinlock cs
  617.        ((t_state&TS_VIRGIN) == 0)    &&        // is not a virgin
  618.          t_expired)                    // has run long enough
  619.     {
  620.         t_expired = 1;
  621.         return 1;
  622.     } else {
  623.         t_expired = 1;
  624.         return 0;
  625.     }
  626. }
  627.  
  628. //
  629. // Threads come here when they want to terminate.  If they send
  630. // any arguments, it will be returned to any thread which waits
  631. // to join on thisthread (assuming someone has marked it as TF_WILLJOIN)
  632. //
  633. // All joining (and joinee) threads serialize at a single j_lock.
  634. // Until this is demonstrated to be a problem, it will stand.
  635. //
  636. // Note: this code is called in the context of the terminating
  637. // thread.  The thread destructor is automatically invoked in the
  638. // context of the scheduler thread when we return to it via swtch().
  639. //
  640.  
  641. static shared_t Spinlock j_lock;    // share single lock
  642.  
  643. void
  644. Thread::terminate(Objany retobj=0)
  645. {
  646.     int rtmp;
  647.  
  648.     if (this != thisthread)    {
  649.         thisthread->error("terminate: Can only finish self");
  650.         return;
  651.     }
  652.         
  653.     if (t_flags&TF_WILLJOIN)    {
  654.         Thread *t;
  655.         j_lock.lock();            
  656.         
  657.         orstate(TS_FINISHED);
  658.         t = t_jthread;            // shared union
  659.         t_jvalue = retobj;
  660.         if (t)        {    // someone waiting
  661.             j_lock.unlock();
  662.             t->wakeup((SynchroObject*)this);
  663.         } else
  664.             j_lock.unlock();
  665.     } else
  666.         orstate(TS_FINISHED);
  667.  
  668. #ifdef debug
  669.     dout << form("terminate: thread %x t_csp %x t_fp %x\n",
  670.         this, t_csp, t_fp);
  671. #endif debug
  672.  
  673.     this->swtch();
  674.     // NOT REACHED
  675.     return;
  676. }
  677.  
  678. //
  679. // Join:
  680. //
  681. //    If a thread is joining on another thread, block that thread
  682. //    until the joined thread terminates.  When it does, the joiner
  683. //    is responsible for deleting it.
  684. //
  685.  
  686.  
  687. void
  688. Thread::willjoin()
  689. {
  690.     if (t_flags&TF_WILLJOIN)
  691.         thisthread->error("Can only join once on a thread");
  692.     else
  693.         t_flags |= TF_WILLJOIN;
  694. }    
  695.  
  696. Objany
  697. Thread::join()
  698. {
  699.     Thread *me = thisthread;
  700.     
  701. #ifdef debug
  702.     dout << form("join: thread %x joining on %x\n", thisthread, this);
  703. #endif debug
  704.  
  705.     // want to join on someone else.  Wait until they finish
  706.     //
  707.     
  708.     if ( (t_flags&TF_WILLJOIN) == 0)
  709.         error("Can't join on a free thread");
  710.     
  711.     j_lock.lock();
  712.     if (this->state()&TS_FINISHED)    {    // thread is done,
  713.         j_lock.unlock();        // return results
  714.     } else    {                // sleep on "this"
  715.         me->orstate(TS_BLOCKED);
  716.         t_jthread = me;            // careful of coercion
  717.         me->nonpreemptable();
  718.         j_lock.unlock();
  719. #ifdef debug
  720.         dout << "join: thread not finished, sleeping\n";
  721. #endif debug
  722.         me->sleep((SynchroObject*)this);
  723.         me->preemptable();
  724.     }
  725.     
  726.     if ((this->state()&TS_FINISHED) == 0)
  727.         this->error("erroneous join");
  728.     
  729.     Objany retobj = t_jvalue;
  730.     delete this;            // will wait for other to terminate
  731.     return retobj;
  732. }
  733.  
  734. /*
  735. void
  736. Thread::setaffinity(Process* p)
  737. {
  738.     t_proc = p;    // shouldn't really use t_proc here
  739. }
  740. */
  741.  
  742. void
  743. Thread::print(ostream& s)
  744. {
  745.     s << "Thread:";
  746.     Object::print(s);     // get base class to show 
  747.     s << "\n"; 
  748.     s << form("t_sp=0x%x, t_sp.limit=0x%x t_ssz=0x%x, t_csp=0x%x, t_fp=0x%x\n",
  749.            stack()->top(), stack()->limit(),stack()->size(), t_csp, t_fp) <<
  750.       form("t_state=0x%x, t_flags=0x%x, t_tag=%d, t_tid=%d, t_pri=%d\n",
  751.             t_state,    t_flags,    t_tag,  t_tid, t_pri);
  752. //    s << "t_timer=" << &t_timer << "\n";
  753.     s << "t_proc=" << t_proc << "\n";
  754.     s << "t_callstate=" << t_callstate << "\n";
  755.     s << "t_blockedon=" << t_blockedon << "\n";
  756. }
  757.  
  758.  
  759. int
  760. Thread::tagcnt()
  761. {
  762. //    return int(t_freetag);
  763.     return -1;  // atomic int t_freetag not currently used
  764. }
  765.  
  766.         
  767. void 
  768. ThreadQUnlocked::print(ostream& s)
  769. {
  770.   s << form( "(ThreadQUnlocked)this=0x%x, tq_neededstate=0x%x, tq_length=0x%x",
  771.             this, tq_neededstate, tq_length);
  772.   s << "\tElements: ";
  773.   Oqueue::print(s);
  774. }
  775.  
  776. void
  777. ThreadQ::print(ostream& s)
  778. {
  779.     s << form("(ThreadQ)this=0x%x, tq_neededstate=0x%x, tq_length=0x%x",
  780.         this, tq_neededstate, tq_length);
  781.     s << " tq_lock= " << tq_lock << "\n";
  782.     s << "\tElements: ";
  783.     Oqueue::print(s);
  784. }
  785.  
  786.