home *** CD-ROM | disk | FTP | other *** search
/ Acorn User 2 / AUCD2.iso / program / vista.arc / c / thread < prev    next >
Text File  |  1996-02-01  |  19KB  |  751 lines

  1. // **************************************************************************
  2. //                     Copyright 1996 David Allison
  3. //
  4. //             VV    VV    IIIIII     SSSSS     TTTTTT       AA
  5. //             VV    VV      II      SS           TT       AA  AA
  6. //             VV    VV      II        SSSS       TT      AA    AA
  7. //              VV  VV       II           SS      TT      AAAAAAAA
  8. //                VV       IIIIII     SSSS        TT      AA    AA
  9. //
  10. //                    MULTI-THREADED C++ WIMP CLASS LIBRARY
  11. //                                for RISC OS
  12. // **************************************************************************
  13. //
  14. //             P U B L I C    D O M A I N    L I C E N C E
  15. //             -------------------------------------------
  16. //
  17. //     This library is copyright. You may not sell the library for
  18. //     profit, but you may sell products which use it providing
  19. //     those products are presented as executable code and are not
  20. //     libraries themselves.  The library is supplied without any
  21. //     warranty and the copyright owner cannot be held responsible for
  22. //     damage resulting from failure of any part of this library.
  23. //
  24. //          See the User Manual for details of the licence.
  25. //
  26. // *************************************************************************
  27.  
  28.  
  29. //
  30. // threads
  31. //
  32.  
  33. #include "Vista:thread.h"
  34. #include <stdio.h>
  35. #include <stdlib.h>
  36. #include <signal.h>
  37. #include <swis.h>
  38. #include <stdarg.h>
  39. #include <string.h>
  40.  
  41. ThreadManager *ThreadManager::current_manager ;
  42.  
  43.  
  44. extern void print (char*...) ;
  45. extern void dprintf (char*...) ;
  46.  
  47. ThreadResource::ThreadResource()
  48.    {
  49.    available = 0 ;
  50.    }
  51.  
  52.  
  53. ThreadTimer::ThreadTimer (ThreadManager *m, int delay)
  54.     {
  55.     manager = m ;
  56.     next = prev = NULL ;
  57.     _kernel_swi_regs r ;
  58.     _kernel_swi (OS_ReadMonotonicTime, &r, &r) ;
  59.     time_set = r.r[0] + delay ;
  60.     manager->insert_timer (this) ;
  61.     }
  62.  
  63. ThreadTimer::~ThreadTimer()
  64.    {
  65.    manager->delete_timer (this) ;
  66.    }
  67.  
  68. void ThreadTimer::check_time (int time)
  69.    {
  70.    if (time >= time_set)
  71.       available = 1 ;
  72.    }
  73.  
  74. ThreadPipe::ThreadPipe ()
  75.    {
  76.    data = NULL ;
  77.    size = 0 ;
  78.    max = 0 ;
  79.    }
  80.  
  81. ThreadPipe::~ThreadPipe()
  82.    {
  83.    }
  84.  
  85. void ThreadPipe::write (char *buffer, int nbytes)
  86.    {
  87.    if (nbytes > max)                                 // enough space?
  88.       {
  89.       if (data == NULL)                              // any buffer
  90.          data = (char*)malloc (nbytes * 2) ;         // no - allocate one
  91.       else
  92.          data = (char*)realloc (data, nbytes * 2) ;  // yes, extend it
  93.       max = nbytes * 2 ;
  94.       }
  95.    memcpy (data, buffer, nbytes) ;                   // copy in the data
  96.    size = nbytes ;
  97.    available = 1 ;                                   // data is now available
  98.    }
  99.  
  100. void ThreadPipe::read (char *buffer, int max, int &nbytes)
  101.    {
  102.    if (max >= size)             // enough space supplied?
  103.       {
  104.       memcpy (buffer, data, size) ;
  105.       nbytes = size ;
  106.       available = 0 ;           // no data available now
  107.       }
  108.    else                         // not enough space - partial read (data still available)
  109.       {
  110.       memcpy (buffer, data, max) ;           // copy one buffer full
  111.       nbytes = max ;                         // say what size
  112.       memmove (buffer, buffer + max, size - max) ;     // move the rest down
  113.       size -= max ;                                    // size is now smaller
  114.       }
  115.    }
  116.  
  117.  
  118. Thread::Thread(char *name, int pri, int newstack)
  119.    {
  120.    this->name = name ;
  121.    manager = ThreadManager::current_manager ;
  122.    next = prev = NULL ;
  123.    nextq = prevq = NULL ;
  124.    if (newstack)
  125.       stack = manager->new_stack() ;
  126.    else
  127.       stack = NULL ;
  128.    state = IDLE ;
  129.    priority = THREAD_STARTUP_PRIORITY ;
  130.    base_priority = pri ;
  131.    cputime = 0 ;
  132.    accumulated_cputime = 0 ;
  133.    manager->insert_thread (this) ;
  134.    }
  135.  
  136. Thread::~Thread()
  137.    {
  138.    kill() ;
  139.    manager->delete_thread (this) ;
  140.    manager->delete_stack (stack) ;
  141.    }
  142.  
  143. // start a thread running.  This must return as soon as the thread has been placed
  144. // in the run queue of the thread manager.  The thread will self terminate when the
  145. // run function returns.
  146. //
  147. // To start a thread we need to:
  148. //   1. Insert it into the run queue at the end of the queue
  149. //   2. Load the sp, sl, fp, lr and pc regs in the thread save area with:
  150. //      - sp: thread->stack + 4096
  151. //      - sl: thread->stack + 560
  152. //      - fp: 0
  153. //      - pc: address of code to call the run function
  154. //   3. return from this function to the caller right away
  155.  
  156. void Thread::start()
  157.    {
  158.    thread_disable_ints() ;
  159.    if (state == READY)
  160.       manager->stop_thread (this) ;                                    // remove from run queue if on it
  161.    thread_init_save_area (save_area) ;
  162. #ifdef __EASY_C
  163.    memset (exception_state, 0, sizeof (exception_state)) ;
  164. #endif
  165.    *(int*)&save_area[13*4] = (int)((char*)stack + 4096) ;         // set sp
  166.    *(int*)&save_area[10*4] = (int)((char*)stack + 560) ;          // set sl
  167.    *(int*)&save_area[11*4] = 0 ;                           // set fp
  168.    *(int*)&save_area[0] = (int)this ;                      // set R0
  169.    *(int*)&save_area[15*4] = (int)thread_call_start2 ;     // set pc
  170.    manager->run_thread(this) ;                             // place on run queue
  171.    manager->num_running_threads++ ;
  172.    available = 0 ;
  173. //   printf ("starting thread %s\n",name) ;
  174.    thread_enable_ints() ;
  175.    }
  176.  
  177. void Thread::start2()
  178.    {
  179. #ifdef DEBUG
  180.    printf ("start2 thread %s\n",name) ;
  181. #endif
  182.    run() ;                      // run the thread body
  183.    thread_disable_ints() ;
  184.    state = IDLE ;
  185.    available = 1 ;
  186.    manager->num_running_threads-- ;
  187.    thread_enable_ints() ;
  188.    for (;;)
  189.       yield() ;
  190.    }
  191.  
  192. void Thread::exit (int status)
  193.    {
  194.    exit_status = status ;
  195.    thread_disable_ints() ;
  196.    state = DEAD ;
  197.    available = 1 ;
  198.    manager->num_running_threads-- ;
  199.    thread_enable_ints() ;
  200.    for(;;)                     // nothing to return to so just loop until interrupted
  201.       yield() ;
  202.    }
  203.  
  204. //
  205. //  kill a thread.  This may be yourself or another thread.  Cannot be restarted
  206. //
  207.  
  208. void Thread::kill()
  209.    {
  210.    thread_disable_ints() ;
  211.    int running = manager->running == this ;
  212.    if (!running && state == READY)
  213.       manager->stop_thread (this) ;
  214.    if (state == READY)
  215.       manager->num_running_threads-- ;
  216.    state = DEAD ;
  217.    available = 1 ;
  218.    thread_enable_ints() ;
  219.    if (running)
  220.       for (;;)              // cant get out of here
  221.          yield() ;
  222.    }
  223.  
  224. //
  225. // stop a thread temporarily until resumed
  226. //
  227.  
  228.  
  229. void Thread::stop()
  230.    {
  231.    if (state == STOPPED)
  232.       return ;
  233.    thread_disable_ints() ;
  234.    int running = manager->running == this ;
  235.    if (!running)
  236.       manager->stop_thread (this) ;
  237.    state = STOPPED ;
  238.    thread_enable_ints() ;
  239.    if (running)
  240.       while (state == STOPPED)
  241.          yield() ;
  242.    }
  243.  
  244. //
  245. // resume a stopped thread
  246. //
  247.  
  248. void Thread::resume()
  249.    {
  250.    if (state != STOPPED)
  251.       return ;
  252.    manager->run_thread (this) ;
  253.    }
  254.  
  255. void Thread::yield()
  256.    {
  257.    thread_yield (manager) ;
  258.    }
  259.  
  260. void Thread::wakeup()
  261.    {
  262.    if (state != SLEEPING)
  263.       return ;
  264.    manager->wakeup_thread (this) ;         // remove from sleep queue
  265.    manager->run_thread (this) ;            // place on run queue
  266.    }
  267.  
  268.  
  269. //
  270. // cause a thread to sleep for a period of time
  271. //
  272. // This calculates the wakeup time and places the thread on the sleep queue
  273. // It then schedules the next thread and enters a loop.
  274. // the loop will be terminated when the quantum expires and restarted
  275. // when the manager wakes the thred up by placing it in the run queue again
  276. // and resetting the sleeping flag
  277.  
  278. void Thread::sleep (int time)      // sleep for centiseconds
  279.    {
  280. //   printf ("sleep(time) %s\n",name) ;
  281.    if (manager->running != this)
  282.       throw ("Can't put another thread to sleep") ;
  283.    ThreadTimer *timer = new ThreadTimer (manager,time) ;   // allocate a new timer
  284.    sleep (timer) ;
  285.    delete timer ;
  286.    }
  287.  
  288. //
  289. // sleep until the given thread terminates
  290. //
  291.  
  292.  
  293.  
  294. //
  295. // This is the general sleep routine.  You can put yourself or another thread to sleep waiting
  296. // for a particular resource.
  297. //
  298.  
  299.  
  300. void Thread::sleep (ThreadResource *r, int pri)
  301.    {
  302.    thread_disable_ints() ;
  303.    int running = manager->running == this ;
  304.    resource = r ;                              // wait for this resource
  305.    if (!running)
  306.       manager->stop_thread(this) ;
  307.    base_priority = pri ;
  308. #ifdef DEBUG
  309.    printf ("sleep(resource) %s\n",name) ;
  310. #endif
  311.    manager->sleep_thread (this) ;        // place myself on sleep queue
  312.    thread_enable_ints() ;
  313.    if (running)
  314.       while (state == SLEEPING)                      // will wake up when manager resets sleeping
  315.          yield() ;
  316.    }
  317.  
  318.  
  319.  
  320. void Thread::write (ThreadPipe *pipe, char *buffer, int nbytes)
  321.    {
  322.    while (pipe->available)         // any data already in pipe?
  323.       sleep (pipe) ;               // sleep until space available
  324.    pipe->write (buffer, nbytes) ;  // write the data
  325.    }
  326.  
  327. void Thread::read (ThreadPipe *pipe, char *buffer, int max, int &nbytes)
  328.    {
  329.    while (!pipe->available)            // any data available
  330.       sleep (pipe) ;                   // sleep until some is
  331.    pipe->read (buffer, max, nbytes) ;  // read the data
  332.    }
  333.  
  334. void Thread::setpriority (int pri)
  335.    {
  336.    base_priority = pri ;
  337.    }
  338.  
  339. int Thread::resource_available()
  340.    {
  341.    return resource->available ;
  342.    }
  343.  
  344. MainThread::MainThread()
  345.    : Thread ("main", 50,0)
  346.    {
  347.    quantum_limit = 0 ;
  348.    }
  349.  
  350. MainThread::~MainThread()
  351.    {
  352.    }
  353.  
  354.  
  355.  
  356. void MainThread::set_limit(int quanta)
  357.    {
  358.    quantum_limit = quanta ;
  359.    }
  360.  
  361. void MainThread::run()
  362.    {
  363. #ifdef DEBUG
  364.    printf ("main thread running for %d quanta\n",quantum_limit) ;
  365. #endif
  366.    manager->quantum_count = 0 ;
  367.    while (manager->quantum_count < quantum_limit && manager->num_running_threads > 0)
  368.       yield() ;
  369.    }
  370.  
  371. ResourceThread::ResourceThread()
  372.    : Thread ("resource", 55,1)
  373.    {
  374.    }
  375.  
  376. void ResourceThread::run()
  377.    {
  378.    _kernel_swi_regs r ;
  379.    Thread *t, *nextt ;
  380. //
  381. // process all timers
  382. //
  383.    for (;;)
  384.       {
  385.       if (manager->timers != NULL)
  386.          {
  387.          _kernel_swi (OS_ReadMonotonicTime, &r, &r) ;
  388.          for (ThreadTimer *timer = manager->timers ; timer != NULL ; timer = timer->next)
  389.             timer->check_time (r.r[0]) ;
  390.          }
  391.  
  392. //
  393. // now process all sleeping threads
  394. //
  395.       for (t = manager->sleepqueue ; t != NULL ; t = nextt)      // process all sleeping threads
  396.          {
  397.          nextt = t->nextq ;
  398.          if (t->resource_available())
  399.             {
  400.             thread_disable_ints() ;
  401.             manager->wakeup_thread(t) ;            // remove from sleep queue
  402.         manager->run_thread (t) ;              // insert in run queue
  403.             thread_enable_ints() ;
  404.         }
  405.          }
  406.       yield() ;
  407.       }
  408.    }
  409.  
  410.  
  411. ThreadManager::ThreadManager()
  412.    {
  413.    current_manager = this ;
  414.    stack_pool = NULL ;
  415. //   printf ("starting thread manager %x\n",this) ;
  416.    threads = last_thread = NULL ;
  417.    runqueue = end_runqueue = NULL ;
  418.    sleepqueue = end_sleepqueue = NULL ;
  419.    timers = last_timer = NULL ;
  420.    running = NULL ;
  421.    num_threads = 0 ;
  422.    main_thread = new MainThread ;          // low priority
  423.    resource_thread = new ResourceThread ; // high priority
  424.    resource_thread->start() ;             // start resource thread
  425.    num_running_threads = 0 ;
  426.    thread_poll_rate = 1 ;
  427.    }
  428.  
  429. ThreadManager::~ThreadManager()
  430.    {
  431.    thread_disable_ints() ;
  432.    thread_stop_ticker(this) ;
  433.    Thread *nextt ;
  434.    for (Thread *t = threads ; t != NULL ; t = nextt)
  435.       {
  436.       nextt = t->next ;
  437.       delete t ;
  438.       }
  439.    }
  440.  
  441. //
  442. // run all the threads for the specified number of quanta
  443. //
  444.  
  445. void ThreadManager::run (int quanta)
  446.    {
  447.    current_manager = this ;
  448.    main_thread->set_limit(quanta) ;
  449.    running = main_thread ;
  450. #ifdef __EASY_C
  451.    __save_exception_state__ (main_thread->exception_state) ;
  452. #endif
  453.    running->state = Thread::RUNNING ;
  454.    thread_callback_regs = main_thread->save_area ;        // set callback save area
  455.    thread_start_ticker(this) ;
  456.    thread_enable_ints() ;
  457.    thread_system_running = 1 ;
  458.    main_thread->run() ;
  459.    thread_system_running = 0 ;
  460.    thread_disable_ints() ;
  461.    thread_stop_ticker(this) ;
  462. #ifdef __EASY_C
  463.    __restore_exception_state__ (main_thread->exception_state) ;
  464. #endif
  465.    }
  466.  
  467. //
  468. // switch to the next available thread in the run queue.  Called from the
  469. // callback handler to switch to the next available thread
  470. //
  471.  
  472. void ThreadManager::context_switch()
  473.    {
  474.    int time = thread_get_time() ;
  475. #ifdef DEBUG
  476.    printf ("context switch %x\n",this) ;
  477. #endif
  478.    quantum_count++ ;
  479.    running->cputime += (thread_poll_rate + 1) * 100 ;
  480.    running->accumulated_cputime += (time - running->time)*100 ;
  481.    if (running->state == Thread::RUNNING)
  482.       run_thread(running) ;                // put current thread on run queue
  483.    next_thread() ;                      // get next thread running
  484.    }
  485.  
  486.  
  487. // insert a thread onto the end of the run queue
  488.  
  489. void ThreadManager::run_thread (Thread *t)
  490.    {
  491. #ifdef DEBUG
  492.    printf ("running thread %s\n",t->name) ;
  493. #endif
  494.    if (t->state == Thread::DEAD)
  495.       throw ("Can't resurrect a dead thread") ;
  496.    if (runqueue == NULL)
  497.       runqueue = end_runqueue = t ;
  498.    else
  499.       {
  500.       end_runqueue->nextq = t ;
  501.       t->prevq = end_runqueue ;
  502.       end_runqueue = t ;
  503.       }
  504.    t->state = Thread::READY ;
  505.    }
  506.  
  507. //
  508. // remove a thread from the run queue
  509. //
  510.  
  511. void ThreadManager::stop_thread (Thread *t)
  512.    {
  513.    if (t->state != Thread::READY)
  514.       throw ("Thread is not ready to run") ;
  515.    if (t->prevq == NULL)
  516.       runqueue = t->nextq ;
  517.    else
  518.       t->prevq->nextq = t->nextq ;
  519.    if (t->nextq == NULL)
  520.       end_runqueue = t->prevq ;
  521.    else
  522.       t->nextq->prevq = t->prevq ;
  523.    t->nextq = t->prevq = NULL ;
  524.    t->state = Thread::IDLE ;
  525.    }
  526.  
  527. void ThreadManager::next_thread ()
  528.    {
  529.    Thread *t, *next ;
  530.    int highest_pri = 0x7fffffff ;
  531.    for (t = runqueue ; t != NULL ; t = t->nextq)
  532.       {
  533.       t->cputime = t->cputime / 2 ;
  534.       t->priority = (t->cputime / 2) + t->base_priority ;
  535. #ifdef DEBUG
  536.       printf ("%x: thread %s, cpu: %d, pri = %d\n",t,t->name,t->cputime,t->priority) ;
  537. #endif
  538.       if (t->priority < highest_pri)
  539.          {
  540.          highest_pri = t->priority ;
  541.          next = t ;
  542.          }
  543.       }
  544. #ifdef __EASY_C
  545.    __save_exception_state__ (running->exception_state) ;
  546. #endif
  547.    stop_thread (next) ;                  // remove from run queue
  548.    running = next ;
  549.    running->state = Thread::RUNNING ;
  550. #ifdef __EASY_C
  551.    __restore_exception_state__ (running->exception_state) ;
  552. #endif
  553. #ifdef DEBUG
  554.    printf ("running %s, pc = %x\n",running->name,*(int*)&running->save_area[15*4]) ;
  555. #endif
  556.    thread_callback_regs = running->save_area ;     // set callback reg save area
  557.    running->time = thread_get_time() ;             // read time gained CPU
  558.    }
  559.  
  560. void ThreadManager::sleep_thread (Thread *t)
  561.    {
  562. #ifdef DEBUG
  563.    printf ("sleeping %s\n",t->name) ;
  564. #endif
  565.    if (sleepqueue == NULL)
  566.       sleepqueue = end_sleepqueue = t ;
  567.    else
  568.       {
  569.       end_sleepqueue->nextq = t ;
  570.       t->prevq = end_sleepqueue ;
  571.       end_sleepqueue = t ;
  572.       }
  573.    t->state = Thread::SLEEPING ;
  574. #ifdef DEBUG
  575.    printf ("now sleeping\n") ;
  576. #endif
  577.    }
  578.  
  579. //
  580. // remove a thread from the sleep queue
  581. //
  582.  
  583. void ThreadManager::wakeup_thread (Thread *t)
  584.    {
  585. #ifdef DEBUG
  586.    printf ("waking up %s\n",t->name) ;
  587. #endif
  588.    if (t->prevq == NULL)
  589.       sleepqueue = t->nextq ;
  590.    else
  591.       t->prevq->nextq = t->nextq ;
  592.    if (t->nextq == NULL)
  593.       end_sleepqueue = t->prevq ;
  594.    else
  595.       t->nextq->prevq = t->prevq ;
  596.  
  597.    t->nextq = t->prevq = NULL ;
  598.    t->state = Thread::IDLE ;
  599.    t->cputime = (t->cputime / 2) ;
  600.    t->priority = (t->cputime / 2) + t->base_priority ;
  601.    }
  602.  
  603.  
  604. void ThreadManager::insert_thread (Thread *t)
  605.    {
  606. //   printf ("thread inserted\n") ;
  607.    if (threads == NULL)
  608.       threads = last_thread = t ;
  609.    else
  610.       {
  611.       last_thread->next = t ;
  612.       t->prev = last_thread ;
  613.       last_thread = t ;
  614.       }
  615.    num_threads++ ;
  616.    }
  617.  
  618. void ThreadManager::delete_thread (Thread *t)
  619.    {
  620.    if (t->prev == NULL)
  621.       threads = t->next ;
  622.    else
  623.       t->prev->next = t->next ;
  624.    if (t->next == NULL)
  625.       last_thread = t->prev ;
  626.    else
  627.       t->next->prev = t->prev ;
  628.    num_threads-- ;
  629.    }
  630.  
  631. void ThreadManager::insert_timer (ThreadTimer *t)
  632.    {
  633. //   printf ("thread inserted\n") ;
  634.    if (timers == NULL)
  635.       timers = last_timer = t ;
  636.    else
  637.       {
  638.       last_timer->next = t ;
  639.       t->prev = last_timer ;
  640.       last_timer = t ;
  641.       }
  642.    }
  643.  
  644. void ThreadManager::delete_timer (ThreadTimer *t)
  645.    {
  646.    if (t->prev == NULL)
  647.       timers = t->next ;
  648.    else
  649.       t->prev->next = t->next ;
  650.    if (t->next == NULL)
  651.       last_timer = t->prev ;
  652.    else
  653.       t->next->prev = t->prev ;
  654.    }
  655.  
  656.  
  657. _kernel_stack_chunk *ThreadManager::new_stack()
  658.    {
  659.    Thread *t ;
  660.    _kernel_stack_chunk *stack ;
  661.    if (stack_pool == NULL)
  662.       {
  663.       _kernel_stack_chunk *s = _kernel_current_stack_chunk() ;
  664.       for (int i = 0 ; i < THREAD_STACK_BLOCK ; i++)
  665.          {
  666.          stack = (_kernel_stack_chunk*)malloc (THREAD_STACK_SIZE) ;
  667.          if (stack == NULL)
  668.             throw ("Out of memory - cant allocate stack for thread") ;
  669.          stack->sc_next = stack_pool ;
  670.          stack->sc_mark = 0xf60690ff ;   // see PRM page 4-239
  671.          stack->sc_prev = NULL ;
  672.          stack->sc_size = THREAD_STACK_SIZE ;
  673.          stack->sc_deallocate = 0 ;
  674.          memcpy (stack+1, s+1, 7*4) ;                 // copy in 7 reserved words
  675.          stack_pool = stack ;
  676.          }
  677.       }
  678.    stack = stack_pool ;
  679.    stack_pool = stack_pool->sc_next ;
  680.    stack->sc_next = NULL ;
  681.    return stack ;
  682.    }
  683.  
  684. void ThreadManager::delete_stack (_kernel_stack_chunk *stack)
  685.    {
  686.    _kernel_stack_chunk *next ;
  687.    while (stack != NULL)
  688.       {
  689.       next = stack->sc_next ;
  690.       stack->sc_next = stack_pool ;
  691.       stack->sc_prev = NULL ;
  692.       stack_pool = stack ;
  693.       stack = next ;
  694.       }
  695.    }
  696.  
  697.  
  698. void ThreadManager::exit()
  699.    {
  700.    thread_disable_ints() ;
  701.    thread_stop_ticker(this) ;
  702.    }
  703.  
  704. void ThreadManager::sleep (int time)
  705.    {
  706.    running->sleep (time) ;
  707.    }
  708.  
  709. void ThreadManager::sleep (ThreadResource *r, int pri)
  710.    {
  711.    running->sleep (r,pri) ;
  712.    }
  713.  
  714. void ThreadManager::yield ()
  715.    {
  716.    running->yield () ;
  717.    }
  718.  
  719.  
  720. void ThreadManager::show_threads()
  721.    {
  722.    Thread *t ;
  723.    dprintf ("NAME         STATE      PRI  BPRI CPU ACCCPU") ;
  724.    dprintf ("----         -----      ---  ---- --- ------") ;
  725.    for (t = threads ; t != NULL ; t = t->next)
  726.       dprintf ("%-12s %-10s %-4d %-4d %-4d %-8d",t->name,
  727.                 t->state == Thread::IDLE?"IDLE":
  728.                 t->state == Thread::READY?"READY":
  729.                 t->state == Thread::RUNNING?"RUNNING":
  730.                 t->state == Thread::SLEEPING?"SLEEPING":
  731.                 t->state == Thread::STOPPED?"STOPPED":
  732.                 t->state == Thread::DEAD?"DEAD":"UNKNOWN",t->priority,t->base_priority,t->cputime,
  733.                    t->accumulated_cputime) ;
  734.     dprintf ("") ;
  735.    }
  736.  
  737. void ThreadManager::stop_threads()
  738.    {
  739.    thread_system_running = 0 ;
  740.    thread_disable_ints() ;
  741.    thread_stop_ticker (this) ;
  742.    }
  743.  
  744. void ThreadManager::resume_threads()
  745.    {
  746.    thread_start_ticker (this) ;
  747.    thread_enable_ints() ;
  748.    thread_system_running = 1 ;
  749.    }
  750.  
  751.