home *** CD-ROM | disk | FTP | other *** search
/ The Datafile PD-CD 5 / DATAFILE_PDCD5.iso / utilities / v / vista / 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 ru