home *** CD-ROM | disk | FTP | other *** search
/ AmigActive 15 / AACD15.ISO / AACD / Programming / Python2 / Python20_source / Python / thread_beos.h < prev    next >
Encoding:
C/C++ Source or Header  |  2000-10-25  |  7.5 KB  |  357 lines

  1. #include <kernel/OS.h>
  2. #include <support/SupportDefs.h>
  3. #include <errno.h>
  4.  
  5. /* ----------------------------------------------------------------------
  6.  * Fast locking mechanism described by Benoit Schillings (benoit@be.com)
  7.  * in the Be Developer's Newsletter, Issue #26 (http://www.be.com/).
  8.  */
  9. typedef struct benaphore {
  10.     sem_id _sem;
  11.     int32  _atom;
  12. } benaphore_t;
  13.  
  14. static status_t benaphore_create( const char *name, benaphore_t *ben );
  15. static status_t benaphore_destroy( benaphore_t *ben );
  16. static status_t benaphore_lock( benaphore_t *ben );
  17. static status_t benaphore_timedlock( benaphore_t *ben, bigtime_t micros );
  18. static status_t benaphore_unlock( benaphore_t *ben );
  19.  
  20. static status_t benaphore_create( const char *name, benaphore_t *ben )
  21. {
  22.     if( ben != NULL ) {
  23.         ben->_atom = 0;
  24.         ben->_sem = create_sem( 0, name );
  25.         
  26.         if( ben->_sem < B_NO_ERROR ) {
  27.             return B_BAD_SEM_ID;
  28.         }
  29.     } else {
  30.         return EFAULT;
  31.     }
  32.     
  33.     return EOK;
  34. }
  35.  
  36. static status_t benaphore_destroy( benaphore_t *ben )
  37. {
  38.     if( ben->_sem >= B_NO_ERROR ) {
  39.         status_t retval = benaphore_timedlock( ben, 0 );
  40.         
  41.         if( retval == EOK || retval == EWOULDBLOCK ) {
  42.             status_t del_retval = delete_sem( ben->_sem );
  43.             
  44.             return del_retval;
  45.         }
  46.     }
  47.  
  48.     return B_BAD_SEM_ID;
  49. }
  50.  
  51. static status_t benaphore_lock( benaphore_t *ben )
  52. {
  53.     int32 prev = atomic_add( &(ben->_atom), 1 );
  54.     
  55.     if( prev > 0 ) {
  56.         return acquire_sem( ben->_sem );
  57.     }
  58.     
  59.     return EOK;
  60. }
  61.  
  62. static status_t benaphore_timedlock( benaphore_t *ben, bigtime_t micros )
  63. {
  64.     int32 prev = atomic_add( &(ben->_atom), 1 );
  65.     
  66.     if( prev > 0 ) {
  67.         status_t retval = acquire_sem_etc( ben->_sem, 1, B_TIMEOUT, micros );
  68.         
  69.         switch( retval ) {
  70.         case B_WOULD_BLOCK:    /* Fall through... */
  71.         case B_TIMED_OUT:
  72.             return EWOULDBLOCK;
  73.             break;
  74.         case B_OK:
  75.             return EOK;
  76.             break;
  77.         default:
  78.             return retval;
  79.             break;
  80.         }
  81.     }
  82.     
  83.     return EOK;
  84. }
  85.  
  86. static status_t benaphore_unlock( benaphore_t *ben )
  87. {
  88.     int32 prev = atomic_add( &(ben->_atom), -1 );
  89.     
  90.     if( prev > 1 ) {
  91.         return release_sem( ben->_sem );
  92.     }
  93.     
  94.     return EOK;
  95. }
  96.  
  97. /* ----------------------------------------------------------------------
  98.  * Initialization.
  99.  */
  100. static void PyThread__init_thread( void )
  101. {
  102.     /* Do nothing. */
  103.     return;
  104. }
  105.  
  106. /* ----------------------------------------------------------------------
  107.  * Thread support.
  108.  *
  109.  * Only ANSI C, renamed functions here; you can't use K&R on BeOS,
  110.  * and there's no legacy thread module to support.
  111.  */
  112.  
  113. static int32 thread_count = 0;
  114.  
  115. int PyThread_start_new_thread( void (*func)(void *), void *arg )
  116. {
  117.     status_t success = 0;
  118.     thread_id tid;
  119.     char name[B_OS_NAME_LENGTH];
  120.     int32 this_thread;
  121.  
  122.     dprintf(("PyThread_start_new_thread called\n"));
  123.  
  124.     /* We are so very thread-safe... */
  125.     this_thread = atomic_add( &thread_count, 1 );
  126.     sprintf( name, "python thread (%d)", this_thread );
  127.  
  128.     tid = spawn_thread( (thread_func)func, name,
  129.                         B_NORMAL_PRIORITY, arg );
  130.     if( tid > B_NO_ERROR ) {
  131.         success = resume_thread( tid );
  132.     }
  133.  
  134.     return ( success == B_NO_ERROR ? 1 : 0 );
  135. }
  136.  
  137. long PyThread_get_thread_ident( void )
  138. {
  139.     /* Presumed to return the current thread's ID... */
  140.     thread_id tid;
  141.     tid = find_thread( NULL );
  142.     
  143.     return ( tid != B_NAME_NOT_FOUND ? tid : -1 );
  144. }
  145.  
  146. static void do_PyThread_exit_thread( int no_cleanup )
  147. {
  148.     int32 threads;
  149.  
  150.     dprintf(("PyThread_exit_thread called\n"));
  151.  
  152.     /* Thread-safe way to read a variable without a mutex: */
  153.     threads = atomic_add( &thread_count, 0 );
  154.  
  155.     if( threads == 0 ) {
  156.         /* No threads around, so exit main(). */
  157.         if( no_cleanup ) {
  158.             _exit(0);
  159.         } else {
  160.             exit(0);
  161.         }
  162.     } else {
  163.         /* Oh, we're a thread, let's try to exit gracefully... */
  164.         exit_thread( B_NO_ERROR );
  165.     }
  166. }
  167.  
  168. void PyThread_exit_thread( void )
  169. {
  170.     do_PyThread_exit_thread(0);
  171. }
  172.  
  173. void PyThread__exit_thread( void )
  174. {
  175.     do_PyThread_exit_thread(1);
  176. }
  177.  
  178. #ifndef NO_EXIT_PROG
  179. static void do_PyThread_exit_prog( int status, int no_cleanup )
  180. {
  181.     dprintf(("PyThread_exit_prog(%d) called\n", status));
  182.  
  183.     /* No need to do anything, the threads get torn down if main() exits. */
  184.  
  185.     if (no_cleanup) {
  186.         _exit(status);
  187.     } else {
  188.         exit(status);
  189.     }
  190. }
  191.  
  192. void PyThread_exit_prog( int status )
  193. {
  194.     do_PyThread_exit_prog(status, 0);
  195. }
  196.  
  197. void PyThread__exit_prog( int status )
  198. {
  199.     do_PyThread_exit_prog(status, 1);
  200. }
  201. #endif /* NO_EXIT_PROG */
  202.  
  203. /* ----------------------------------------------------------------------
  204.  * Lock support.
  205.  */
  206.  
  207. static int32 lock_count = 0;
  208.  
  209. PyThread_type_lock PyThread_allocate_lock( void )
  210. {
  211.     benaphore_t *lock;
  212.     status_t retval;
  213.     char name[B_OS_NAME_LENGTH];
  214.     int32 this_lock;
  215.     
  216.     dprintf(("PyThread_allocate_lock called\n"));
  217.  
  218.     lock = (benaphore_t *)malloc( sizeof( benaphore_t ) );
  219.     if( lock == NULL ) {
  220.         /* TODO: that's bad, raise MemoryError */
  221.         return (PyThread_type_lock)NULL;
  222.     }
  223.  
  224.     this_lock = atomic_add( &lock_count, 1 );
  225.     sprintf( name, "python lock (%d)", this_lock );
  226.  
  227.     retval = benaphore_create( name, lock );
  228.     if( retval != EOK ) {
  229.         /* TODO: that's bad, raise an exception */
  230.         return (PyThread_type_lock)NULL;
  231.     }
  232.  
  233.     dprintf(("PyThread_allocate_lock() -> %p\n", lock));
  234.     return (PyThread_type_lock) lock;
  235. }
  236.  
  237. void PyThread_free_lock( PyThread_type_lock lock )
  238. {
  239.     status_t retval;
  240.  
  241.     dprintf(("PyThread_free_lock(%p) called\n", lock));
  242.     
  243.     retval = benaphore_destroy( (benaphore_t *)lock );
  244.     if( retval != EOK ) {
  245.         /* TODO: that's bad, raise an exception */
  246.         return;
  247.     }
  248. }
  249.  
  250. int PyThread_acquire_lock( PyThread_type_lock lock, int waitflag )
  251. {
  252.     int success;
  253.     status_t retval;
  254.  
  255.     dprintf(("PyThread_acquire_lock(%p, %d) called\n", lock, waitflag));
  256.  
  257.     if( waitflag ) {
  258.         retval = benaphore_lock( (benaphore_t *)lock );
  259.     } else {
  260.         retval = benaphore_timedlock( (benaphore_t *)lock, 0 );
  261.     }
  262.     
  263.     if( retval == EOK ) {
  264.         success = 1;
  265.     } else {
  266.         success = 0;
  267.         
  268.         /* TODO: that's bad, raise an exception */
  269.     }
  270.  
  271.     dprintf(("PyThread_acquire_lock(%p, %d) -> %d\n", lock, waitflag, success));
  272.     return success;
  273. }
  274.  
  275. void PyThread_release_lock( PyThread_type_lock lock )
  276. {
  277.     status_t retval;
  278.     
  279.     dprintf(("PyThread_release_lock(%p) called\n", lock));
  280.     
  281.     retval = benaphore_unlock( (benaphore_t *)lock );
  282.     if( retval != EOK ) {
  283.         /* TODO: that's bad, raise an exception */
  284.         return;
  285.     }
  286. }
  287.  
  288. /* ----------------------------------------------------------------------
  289.  * Semaphore support.
  290.  *
  291.  * Guido says not to implement this because it's not used anywhere;
  292.  * I'll do it anyway, you never know when it might be handy, and it's
  293.  * easy...
  294.  */
  295. PyThread_type_sema PyThread_allocate_sema( int value )
  296. {
  297.     sem_id sema;
  298.     
  299.     dprintf(("PyThread_allocate_sema called\n"));
  300.  
  301.     sema = create_sem( value, "python semaphore" );
  302.     if( sema < B_NO_ERROR ) {
  303.         /* TODO: that's bad, raise an exception */
  304.         return 0;
  305.     }
  306.  
  307.     dprintf(("PyThread_allocate_sema() -> %p\n", sema));
  308.     return (PyThread_type_sema) sema;
  309. }
  310.  
  311. void PyThread_free_sema( PyThread_type_sema sema )
  312. {
  313.     status_t retval;
  314.     
  315.     dprintf(("PyThread_free_sema(%p) called\n", sema));
  316.     
  317.     retval = delete_sem( (sem_id)sema );
  318.     if( retval != B_NO_ERROR ) {
  319.         /* TODO: that's bad, raise an exception */
  320.         return;
  321.     }
  322. }
  323.  
  324. int PyThread_down_sema( PyThread_type_sema sema, int waitflag )
  325. {
  326.     status_t retval;
  327.  
  328.     dprintf(("PyThread_down_sema(%p, %d) called\n", sema, waitflag));
  329.  
  330.     if( waitflag ) {
  331.         retval = acquire_sem( (sem_id)sema );
  332.     } else {
  333.         retval = acquire_sem_etc( (sem_id)sema, 1, B_TIMEOUT, 0 );
  334.     }
  335.     
  336.     if( retval != B_NO_ERROR ) {
  337.         /* TODO: that's bad, raise an exception */
  338.         return 0;
  339.     }
  340.  
  341.     dprintf(("PyThread_down_sema(%p) return\n", sema));
  342.     return -1;
  343. }
  344.  
  345. void PyThread_up_sema( PyThread_type_sema sema )
  346. {
  347.     status_t retval;
  348.     
  349.     dprintf(("PyThread_up_sema(%p)\n", sema));
  350.     
  351.     retval = release_sem( (sem_id)sema );
  352.     if( retval != B_NO_ERROR ) {
  353.         /* TODO: that's bad, raise an exception */
  354.         return;
  355.     }
  356. }
  357.