You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

248 lines
5.9 KiB

  1. #include <kernel/OS.h>
  2. #include <support/SupportDefs.h>
  3. #include <errno.h>
  4. /* ----------------------------------------------------------------------
  5. * Fast locking mechanism described by Benoit Schillings (benoit@be.com)
  6. * in the Be Developer's Newsletter, Issue #26 (http://www.be.com/).
  7. */
  8. typedef struct benaphore {
  9. sem_id _sem;
  10. int32 _atom;
  11. } benaphore_t;
  12. static status_t benaphore_create( const char *name, benaphore_t *ben );
  13. static status_t benaphore_destroy( benaphore_t *ben );
  14. static status_t benaphore_lock( benaphore_t *ben );
  15. static status_t benaphore_timedlock( benaphore_t *ben, bigtime_t micros );
  16. static status_t benaphore_unlock( benaphore_t *ben );
  17. static status_t benaphore_create( const char *name, benaphore_t *ben )
  18. {
  19. if( ben != NULL ) {
  20. ben->_atom = 0;
  21. ben->_sem = create_sem( 0, name );
  22. if( ben->_sem < B_NO_ERROR ) {
  23. return B_BAD_SEM_ID;
  24. }
  25. } else {
  26. return EFAULT;
  27. }
  28. return EOK;
  29. }
  30. static status_t benaphore_destroy( benaphore_t *ben )
  31. {
  32. if( ben->_sem >= B_NO_ERROR ) {
  33. status_t retval = benaphore_timedlock( ben, 0 );
  34. if( retval == EOK || retval == EWOULDBLOCK ) {
  35. status_t del_retval = delete_sem( ben->_sem );
  36. return del_retval;
  37. }
  38. }
  39. return B_BAD_SEM_ID;
  40. }
  41. static status_t benaphore_lock( benaphore_t *ben )
  42. {
  43. int32 prev = atomic_add( &(ben->_atom), 1 );
  44. if( prev > 0 ) {
  45. return acquire_sem( ben->_sem );
  46. }
  47. return EOK;
  48. }
  49. static status_t benaphore_timedlock( benaphore_t *ben, bigtime_t micros )
  50. {
  51. int32 prev = atomic_add( &(ben->_atom), 1 );
  52. if( prev > 0 ) {
  53. status_t retval = acquire_sem_etc( ben->_sem, 1, B_TIMEOUT, micros );
  54. switch( retval ) {
  55. case B_WOULD_BLOCK: /* Fall through... */
  56. case B_TIMED_OUT:
  57. return EWOULDBLOCK;
  58. break;
  59. case B_OK:
  60. return EOK;
  61. break;
  62. default:
  63. return retval;
  64. break;
  65. }
  66. }
  67. return EOK;
  68. }
  69. static status_t benaphore_unlock( benaphore_t *ben )
  70. {
  71. int32 prev = atomic_add( &(ben->_atom), -1 );
  72. if( prev > 1 ) {
  73. return release_sem( ben->_sem );
  74. }
  75. return EOK;
  76. }
  77. /* ----------------------------------------------------------------------
  78. * Initialization.
  79. */
  80. static void PyThread__init_thread( void )
  81. {
  82. /* Do nothing. */
  83. return;
  84. }
  85. /* ----------------------------------------------------------------------
  86. * Thread support.
  87. *
  88. * Only ANSI C, renamed functions here; you can't use K&R on BeOS,
  89. * and there's no legacy thread module to support.
  90. */
  91. static int32 thread_count = 0;
  92. long PyThread_start_new_thread( void (*func)(void *), void *arg )
  93. {
  94. status_t success = 0;
  95. thread_id tid;
  96. char name[B_OS_NAME_LENGTH];
  97. int32 this_thread;
  98. dprintf(("PyThread_start_new_thread called\n"));
  99. /* We are so very thread-safe... */
  100. this_thread = atomic_add( &thread_count, 1 );
  101. PyOS_snprintf(name, sizeof(name),
  102. "python thread (%d)", this_thread );
  103. tid = spawn_thread( (thread_func)func, name,
  104. B_NORMAL_PRIORITY, arg );
  105. if( tid > B_NO_ERROR ) {
  106. success = resume_thread( tid );
  107. }
  108. return ( success == B_NO_ERROR ? tid : -1 );
  109. }
  110. long PyThread_get_thread_ident( void )
  111. {
  112. /* Presumed to return the current thread's ID... */
  113. thread_id tid;
  114. tid = find_thread( NULL );
  115. return ( tid != B_NAME_NOT_FOUND ? tid : -1 );
  116. }
  117. void PyThread_exit_thread( void )
  118. {
  119. int32 threads;
  120. dprintf(("PyThread_exit_thread called\n"));
  121. /* Thread-safe way to read a variable without a mutex: */
  122. threads = atomic_add( &thread_count, 0 );
  123. if( threads == 0 ) {
  124. /* No threads around, so exit main(). */
  125. exit(0);
  126. } else {
  127. /* Oh, we're a thread, let's try to exit gracefully... */
  128. exit_thread( B_NO_ERROR );
  129. }
  130. }
  131. /* ----------------------------------------------------------------------
  132. * Lock support.
  133. */
  134. static int32 lock_count = 0;
  135. PyThread_type_lock PyThread_allocate_lock( void )
  136. {
  137. benaphore_t *lock;
  138. status_t retval;
  139. char name[B_OS_NAME_LENGTH];
  140. int32 this_lock;
  141. dprintf(("PyThread_allocate_lock called\n"));
  142. lock = (benaphore_t *)malloc( sizeof( benaphore_t ) );
  143. if( lock == NULL ) {
  144. /* TODO: that's bad, raise MemoryError */
  145. return (PyThread_type_lock)NULL;
  146. }
  147. this_lock = atomic_add( &lock_count, 1 );
  148. PyOS_snprintf(name, sizeof(name), "python lock (%d)", this_lock);
  149. retval = benaphore_create( name, lock );
  150. if( retval != EOK ) {
  151. /* TODO: that's bad, raise an exception */
  152. return (PyThread_type_lock)NULL;
  153. }
  154. dprintf(("PyThread_allocate_lock() -> %p\n", lock));
  155. return (PyThread_type_lock) lock;
  156. }
  157. void PyThread_free_lock( PyThread_type_lock lock )
  158. {
  159. status_t retval;
  160. dprintf(("PyThread_free_lock(%p) called\n", lock));
  161. retval = benaphore_destroy( (benaphore_t *)lock );
  162. if( retval != EOK ) {
  163. /* TODO: that's bad, raise an exception */
  164. return;
  165. }
  166. }
  167. int PyThread_acquire_lock( PyThread_type_lock lock, int waitflag )
  168. {
  169. int success;
  170. status_t retval;
  171. dprintf(("PyThread_acquire_lock(%p, %d) called\n", lock, waitflag));
  172. if( waitflag ) {
  173. retval = benaphore_lock( (benaphore_t *)lock );
  174. } else {
  175. retval = benaphore_timedlock( (benaphore_t *)lock, 0 );
  176. }
  177. if( retval == EOK ) {
  178. success = 1;
  179. } else {
  180. success = 0;
  181. /* TODO: that's bad, raise an exception */
  182. }
  183. dprintf(("PyThread_acquire_lock(%p, %d) -> %d\n", lock, waitflag, success));
  184. return success;
  185. }
  186. void PyThread_release_lock( PyThread_type_lock lock )
  187. {
  188. status_t retval;
  189. dprintf(("PyThread_release_lock(%p) called\n", lock));
  190. retval = benaphore_unlock( (benaphore_t *)lock );
  191. if( retval != EOK ) {
  192. /* TODO: that's bad, raise an exception */
  193. return;
  194. }
  195. }