|
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 long 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 PyOS_snprintf(name, sizeof(name), |
|
127 "python thread (%d)", this_thread ); |
|
128 |
|
129 tid = spawn_thread( (thread_func)func, name, |
|
130 B_NORMAL_PRIORITY, arg ); |
|
131 if( tid > B_NO_ERROR ) { |
|
132 success = resume_thread( tid ); |
|
133 } |
|
134 |
|
135 return ( success == B_NO_ERROR ? tid : -1 ); |
|
136 } |
|
137 |
|
138 long PyThread_get_thread_ident( void ) |
|
139 { |
|
140 /* Presumed to return the current thread's ID... */ |
|
141 thread_id tid; |
|
142 tid = find_thread( NULL ); |
|
143 |
|
144 return ( tid != B_NAME_NOT_FOUND ? tid : -1 ); |
|
145 } |
|
146 |
|
147 static void do_PyThread_exit_thread( int no_cleanup ) |
|
148 { |
|
149 int32 threads; |
|
150 |
|
151 dprintf(("PyThread_exit_thread called\n")); |
|
152 |
|
153 /* Thread-safe way to read a variable without a mutex: */ |
|
154 threads = atomic_add( &thread_count, 0 ); |
|
155 |
|
156 if( threads == 0 ) { |
|
157 /* No threads around, so exit main(). */ |
|
158 if( no_cleanup ) { |
|
159 _exit(0); |
|
160 } else { |
|
161 exit(0); |
|
162 } |
|
163 } else { |
|
164 /* Oh, we're a thread, let's try to exit gracefully... */ |
|
165 exit_thread( B_NO_ERROR ); |
|
166 } |
|
167 } |
|
168 |
|
169 void PyThread_exit_thread( void ) |
|
170 { |
|
171 do_PyThread_exit_thread(0); |
|
172 } |
|
173 |
|
174 void PyThread__exit_thread( void ) |
|
175 { |
|
176 do_PyThread_exit_thread(1); |
|
177 } |
|
178 |
|
179 #ifndef NO_EXIT_PROG |
|
180 static void do_PyThread_exit_prog( int status, int no_cleanup ) |
|
181 { |
|
182 dprintf(("PyThread_exit_prog(%d) called\n", status)); |
|
183 |
|
184 /* No need to do anything, the threads get torn down if main() exits. */ |
|
185 |
|
186 if (no_cleanup) { |
|
187 _exit(status); |
|
188 } else { |
|
189 exit(status); |
|
190 } |
|
191 } |
|
192 |
|
193 void PyThread_exit_prog( int status ) |
|
194 { |
|
195 do_PyThread_exit_prog(status, 0); |
|
196 } |
|
197 |
|
198 void PyThread__exit_prog( int status ) |
|
199 { |
|
200 do_PyThread_exit_prog(status, 1); |
|
201 } |
|
202 #endif /* NO_EXIT_PROG */ |
|
203 |
|
204 /* ---------------------------------------------------------------------- |
|
205 * Lock support. |
|
206 */ |
|
207 |
|
208 static int32 lock_count = 0; |
|
209 |
|
210 PyThread_type_lock PyThread_allocate_lock( void ) |
|
211 { |
|
212 benaphore_t *lock; |
|
213 status_t retval; |
|
214 char name[B_OS_NAME_LENGTH]; |
|
215 int32 this_lock; |
|
216 |
|
217 dprintf(("PyThread_allocate_lock called\n")); |
|
218 |
|
219 lock = (benaphore_t *)malloc( sizeof( benaphore_t ) ); |
|
220 if( lock == NULL ) { |
|
221 /* TODO: that's bad, raise MemoryError */ |
|
222 return (PyThread_type_lock)NULL; |
|
223 } |
|
224 |
|
225 this_lock = atomic_add( &lock_count, 1 ); |
|
226 PyOS_snprintf(name, sizeof(name), "python lock (%d)", this_lock); |
|
227 |
|
228 retval = benaphore_create( name, lock ); |
|
229 if( retval != EOK ) { |
|
230 /* TODO: that's bad, raise an exception */ |
|
231 return (PyThread_type_lock)NULL; |
|
232 } |
|
233 |
|
234 dprintf(("PyThread_allocate_lock() -> %p\n", lock)); |
|
235 return (PyThread_type_lock) lock; |
|
236 } |
|
237 |
|
238 void PyThread_free_lock( PyThread_type_lock lock ) |
|
239 { |
|
240 status_t retval; |
|
241 |
|
242 dprintf(("PyThread_free_lock(%p) called\n", lock)); |
|
243 |
|
244 retval = benaphore_destroy( (benaphore_t *)lock ); |
|
245 if( retval != EOK ) { |
|
246 /* TODO: that's bad, raise an exception */ |
|
247 return; |
|
248 } |
|
249 } |
|
250 |
|
251 int PyThread_acquire_lock( PyThread_type_lock lock, int waitflag ) |
|
252 { |
|
253 int success; |
|
254 status_t retval; |
|
255 |
|
256 dprintf(("PyThread_acquire_lock(%p, %d) called\n", lock, waitflag)); |
|
257 |
|
258 if( waitflag ) { |
|
259 retval = benaphore_lock( (benaphore_t *)lock ); |
|
260 } else { |
|
261 retval = benaphore_timedlock( (benaphore_t *)lock, 0 ); |
|
262 } |
|
263 |
|
264 if( retval == EOK ) { |
|
265 success = 1; |
|
266 } else { |
|
267 success = 0; |
|
268 |
|
269 /* TODO: that's bad, raise an exception */ |
|
270 } |
|
271 |
|
272 dprintf(("PyThread_acquire_lock(%p, %d) -> %d\n", lock, waitflag, success)); |
|
273 return success; |
|
274 } |
|
275 |
|
276 void PyThread_release_lock( PyThread_type_lock lock ) |
|
277 { |
|
278 status_t retval; |
|
279 |
|
280 dprintf(("PyThread_release_lock(%p) called\n", lock)); |
|
281 |
|
282 retval = benaphore_unlock( (benaphore_t *)lock ); |
|
283 if( retval != EOK ) { |
|
284 /* TODO: that's bad, raise an exception */ |
|
285 return; |
|
286 } |
|
287 } |