51 |
|
extern int __clone(int (*fn)(void *), void *, int, void *); |
52 |
|
|
53 |
|
/* struct sem_t */ |
54 |
+ |
#define status __status |
55 |
+ |
#define spinlock __spinlock |
56 |
|
#define sem_lock __sem_lock |
57 |
|
#define sem_value __sem_value |
58 |
|
#define sem_waiting __sem_waiting |
59 |
|
|
60 |
+ |
/* Wait for "clone" children only (Linux 2.4+ specific) */ |
61 |
+ |
#ifndef __WCLONE |
62 |
+ |
#define __WCLONE 0 |
63 |
+ |
#endif |
64 |
+ |
|
65 |
|
|
66 |
|
/* |
67 |
|
* Return pthread ID of self |
142 |
|
int pthread_join(pthread_t thread, void **ret) |
143 |
|
{ |
144 |
|
do { |
145 |
< |
if (waitpid(thread, NULL, 0) >= 0) |
145 |
> |
if (waitpid(thread, NULL, __WCLONE) >= 0); |
146 |
|
break; |
147 |
|
} while (errno == EINTR); |
148 |
|
if (ret) |
175 |
|
* Spinlocks |
176 |
|
*/ |
177 |
|
|
178 |
+ |
static int try_acquire_spinlock(int *lock) |
179 |
+ |
{ |
180 |
+ |
return test_and_set(lock, 1) == 0; |
181 |
+ |
} |
182 |
+ |
|
183 |
|
static void acquire_spinlock(volatile int *lock) |
184 |
|
{ |
185 |
|
do { |
194 |
|
|
195 |
|
|
196 |
|
/* |
197 |
+ |
* Initialize mutex |
198 |
+ |
*/ |
199 |
+ |
|
200 |
+ |
int pthread_mutex_init(pthread_mutex_t *mutex, const pthread_mutexattr_t *mutex_attr) |
201 |
+ |
{ |
202 |
+ |
// pthread_init_lock |
203 |
+ |
mutex->__m_lock.__status = 0; |
204 |
+ |
mutex->__m_lock.__spinlock = 0; |
205 |
+ |
|
206 |
+ |
mutex->__m_kind = mutex_attr ? mutex_attr->__mutexkind : PTHREAD_MUTEX_TIMED_NP; |
207 |
+ |
mutex->__m_count = 0; |
208 |
+ |
mutex->__m_owner = NULL; |
209 |
+ |
return 0; |
210 |
+ |
} |
211 |
+ |
|
212 |
+ |
|
213 |
+ |
/* |
214 |
+ |
* Destroy mutex |
215 |
+ |
*/ |
216 |
+ |
|
217 |
+ |
int pthread_mutex_destroy(pthread_mutex_t *mutex) |
218 |
+ |
{ |
219 |
+ |
switch (mutex->__m_kind) { |
220 |
+ |
case PTHREAD_MUTEX_TIMED_NP: |
221 |
+ |
return (mutex->__m_lock.__status != 0) ? EBUSY : 0; |
222 |
+ |
default: |
223 |
+ |
return EINVAL; |
224 |
+ |
} |
225 |
+ |
} |
226 |
+ |
|
227 |
+ |
|
228 |
+ |
/* |
229 |
+ |
* Lock mutex |
230 |
+ |
*/ |
231 |
+ |
|
232 |
+ |
int pthread_mutex_lock(pthread_mutex_t *mutex) |
233 |
+ |
{ |
234 |
+ |
switch (mutex->__m_kind) { |
235 |
+ |
case PTHREAD_MUTEX_TIMED_NP: |
236 |
+ |
acquire_spinlock(&mutex->__m_lock.__spinlock); |
237 |
+ |
return 0; |
238 |
+ |
default: |
239 |
+ |
return EINVAL; |
240 |
+ |
} |
241 |
+ |
} |
242 |
+ |
|
243 |
+ |
|
244 |
+ |
/* |
245 |
+ |
* Try to lock mutex |
246 |
+ |
*/ |
247 |
+ |
|
248 |
+ |
int pthread_mutex_trylock(pthread_mutex_t *mutex) |
249 |
+ |
{ |
250 |
+ |
switch (mutex->__m_kind) { |
251 |
+ |
case PTHREAD_MUTEX_TIMED_NP: |
252 |
+ |
if (!try_acquire_spinlock(&mutex->__m_lock.__spinlock)) |
253 |
+ |
return EBUSY; |
254 |
+ |
return 0; |
255 |
+ |
default: |
256 |
+ |
return EINVAL; |
257 |
+ |
} |
258 |
+ |
} |
259 |
+ |
|
260 |
+ |
|
261 |
+ |
/* |
262 |
+ |
* Unlock mutex |
263 |
+ |
*/ |
264 |
+ |
|
265 |
+ |
int pthread_mutex_unlock(pthread_mutex_t *mutex) |
266 |
+ |
{ |
267 |
+ |
switch (mutex->__m_kind) { |
268 |
+ |
case PTHREAD_MUTEX_TIMED_NP: |
269 |
+ |
release_spinlock(&mutex->__m_lock.__spinlock); |
270 |
+ |
return 0; |
271 |
+ |
default: |
272 |
+ |
return EINVAL; |
273 |
+ |
} |
274 |
+ |
} |
275 |
+ |
|
276 |
+ |
|
277 |
+ |
/* |
278 |
+ |
* Create mutex attribute |
279 |
+ |
*/ |
280 |
+ |
|
281 |
+ |
int pthread_mutexattr_init(pthread_mutexattr_t *attr) |
282 |
+ |
{ |
283 |
+ |
attr->__mutexkind = PTHREAD_MUTEX_TIMED_NP; |
284 |
+ |
return 0; |
285 |
+ |
} |
286 |
+ |
|
287 |
+ |
|
288 |
+ |
/* |
289 |
+ |
* Destroy mutex attribute |
290 |
+ |
*/ |
291 |
+ |
|
292 |
+ |
int pthread_mutexattr_destroy(pthread_mutexattr_t *attr) |
293 |
+ |
{ |
294 |
+ |
return 0; |
295 |
+ |
} |
296 |
+ |
|
297 |
+ |
|
298 |
+ |
/* |
299 |
|
* Init semaphore |
300 |
|
*/ |
301 |
|
|
330 |
|
int sem_wait(sem_t *sem) |
331 |
|
{ |
332 |
|
acquire_spinlock(&sem->sem_lock.spinlock); |
333 |
< |
if (atomic_add((int *)&sem->sem_value, -1) >= 0) { |
333 |
> |
if (sem->sem_value > 0) |
334 |
> |
atomic_add((int *)&sem->sem_value, -1); |
335 |
> |
else { |
336 |
|
sigset_t mask; |
337 |
|
if (!sem->sem_lock.status) { |
338 |
|
struct sigaction sa; |
359 |
|
int sem_post(sem_t *sem) |
360 |
|
{ |
361 |
|
acquire_spinlock(&sem->sem_lock.spinlock); |
362 |
< |
atomic_add((int *)&sem->sem_value, 1); |
363 |
< |
if (sem->sem_waiting) |
362 |
> |
if (sem->sem_waiting == NULL) |
363 |
> |
atomic_add((int *)&sem->sem_value, 1); |
364 |
> |
else |
365 |
|
kill((pid_t)sem->sem_waiting, sem->sem_lock.status); |
366 |
|
release_spinlock(&sem->sem_lock.spinlock); |
367 |
|
return 0; |
368 |
|
} |
369 |
+ |
|
370 |
+ |
|
371 |
+ |
/* |
372 |
+ |
* Simple producer/consumer test program |
373 |
+ |
*/ |
374 |
+ |
|
375 |
+ |
#ifdef TEST |
376 |
+ |
#include <stdio.h> |
377 |
+ |
|
378 |
+ |
static sem_t p_sem, c_sem; |
379 |
+ |
static int data = 0; |
380 |
+ |
|
381 |
+ |
static void *producer_func(void *arg) |
382 |
+ |
{ |
383 |
+ |
int i, n = (int)arg; |
384 |
+ |
for (i = 0; i < n; i++) { |
385 |
+ |
sem_wait(&p_sem); |
386 |
+ |
data++; |
387 |
+ |
sem_post(&c_sem); |
388 |
+ |
} |
389 |
+ |
return NULL; |
390 |
+ |
} |
391 |
+ |
|
392 |
+ |
static void *consumer_func(void *arg) |
393 |
+ |
{ |
394 |
+ |
int i, n = (int)arg; |
395 |
+ |
for (i = 0; i < n; i++) { |
396 |
+ |
sem_wait(&c_sem); |
397 |
+ |
printf("data: %d\n", data); |
398 |
+ |
sem_post(&p_sem); |
399 |
+ |
} |
400 |
+ |
sleep(1); // for testing pthread_join() |
401 |
+ |
return NULL; |
402 |
+ |
} |
403 |
+ |
|
404 |
+ |
int main(void) |
405 |
+ |
{ |
406 |
+ |
pthread_t producer_thread, consumer_thread; |
407 |
+ |
static const int N = 5; |
408 |
+ |
|
409 |
+ |
if (sem_init(&c_sem, 0, 0) < 0) |
410 |
+ |
return 1; |
411 |
+ |
if (sem_init(&p_sem, 0, 1) < 0) |
412 |
+ |
return 2; |
413 |
+ |
if (pthread_create(&producer_thread, NULL, producer_func, (void *)N) != 0) |
414 |
+ |
return 3; |
415 |
+ |
if (pthread_create(&consumer_thread, NULL, consumer_func, (void *)N) != 0) |
416 |
+ |
return 4; |
417 |
+ |
pthread_join(producer_thread, NULL); |
418 |
+ |
pthread_join(consumer_thread, NULL); |
419 |
+ |
sem_destroy(&p_sem); |
420 |
+ |
sem_destroy(&c_sem); |
421 |
+ |
if (data != N) |
422 |
+ |
return 5; |
423 |
+ |
return 0; |
424 |
+ |
} |
425 |
+ |
#endif |