On Sun, Oct 27, 2002 at 06:06:08PM +0100, Ga?l Le Mignot wrote: > > Hello, > > While trying to compile abiword, and so gnome-vfs, on GNU/Hurd, I've > seen that it uses POSIX semaphore, that we don't implement yet. > > So, I've done an implementation of POSIX semaphores using a pthread_mutex > and a pthread_cond. I didn't test it yet, but it compiles, and I'm pretty > confident in it (but I'm sure of the correct behavior of the destroy > function if some threads are locked on the semaphore). The behavior is undefined ;) > > Anyway, here it is. I think it should be merged in libpthreads as soon > as someone reviewed it. I tried to make it return errno and be async-cancel resistant.
Anyway the header should be basically the same, just the implementation changes a bit. -- Michal Suchanek [EMAIL PROTECTED]
/* Copyright (C) 2000,02 Free Software Foundation, Inc. This file is part of the GNU C Library. Written by Gaël Le Mignot <[EMAIL PROTECTED]> The GNU C Library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. The GNU C Library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with the GNU C Library; see the file COPYING.LIB. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /* * POSIX Threads Extension: Semaphores <semaphore.c> */ #include <semaphore.h> #include <stdlib.h> #include <errno.h> #include <assert.h> static void pmut_unlock(void * pmutex) { pthread_mutex_unlock((pthread_mutex_t *)pmutex); } #define pmutex_safe_lock(pmut) \ { \ int __pmutex_safe_lock_old_state; \ pthread_mutex_t *__pmutext_safe_lock_pmut_test = pmut; \ pthread_setcanceltype (PTHREAD_CANCEL_DEFERRED, \ &__pmutex_safe_lock_old_state); \ pthread_cleanup_push (&pmut_unlock, (pmut)); \ pthread_mutex_lock (pmut) #define pmutex_safe_unlock(pmut) \ pthread_cleanup_pop (1); \ assert (__pmutext_safe_lock_pmut_test == pmut); \ pthread_setcanceltype (__pmutex_safe_lock_old_state, NULL); \ } #define psemaph_check_valid \ { \ int res = 0; \ pmutex_safe_lock (&sem->count_lock); \ if (sem->count == SEM_VALUE_INVALID) { \ errno = EINVAL; \ res = -1; \ } else { #define psemaph_ret_res \ } \ pmutex_safe_unlock (&sem->count_lock); \ return res; \ } /* Initialize the semaphore and set the initial value - as in LinuxThreads pshared must be zero right now. */ int sem_init (sem_t *sem, int pshared, unsigned int value) { if (pshared) { errno = ENOTSUP; return -1; } if (value > SEM_VALUE_MAX) { errno = ERANGE; return -1; } sem->count = value; sem->ID = NULL; pthread_cond_init (&sem->lock, NULL); pthread_mutex_init (&sem->count_lock, NULL); return 0; } /* Destroys the semaphore */ int sem_destroy (sem_t *sem) { int res = 0; pmutex_safe_lock (&sem->count_lock); sem->count = SEM_VALUE_INVALID; pthread_cond_broadcast (&sem->lock); if (pthread_cond_destroy (&sem->lock)) res = -1; pmutex_safe_unlock(&sem->count_lock); if (pthread_mutex_destroy (&sem->count_lock)) res = -1; return res; } /* Wait until the count is > 0, and then decrease it */ int sem_wait (sem_t *sem) { psemaph_check_valid; while (1) { if (sem->count) { sem->count--; break; } pthread_cond_wait (&sem->lock, &sem->count_lock); } psemaph_ret_res; } /* Non-blocking variant of sem_wait. Returns -1 if count == 0. */ int sem_trywait (sem_t *sem) { psemaph_check_valid; if (sem->count) { sem->count--; } else { res = -1; errno = EAGAIN; } psemaph_ret_res; } /* Increments the count */ int sem_post (sem_t *sem) { psemaph_check_valid; if (sem->count < SEM_VALUE_MAX) { sem->count++; pthread_cond_signal (&sem->lock); } else { errno = ERANGE; res = -1; } psemaph_ret_res; } /* Return the value of the semaphore */ int sem_getvalue (sem_t *sem, int *sval) { psemaph_check_valid; *sval = sem->count; psemaph_ret_res; }
/* Copyright (C) 2000,02 Free Software Foundation, Inc. This file is part of the GNU C Library. Written by Gaël Le Mignot <[EMAIL PROTECTED]> The GNU C Library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. The GNU C Library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with the GNU C Library; see the file COPYING.LIB. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /* * POSIX Threads Extension: Semaphores <semaphore.h> */ #ifndef _SEMAPHORE_H #define _SEMAPHORE_H 1 #include <pthread.h> #include <fcntl.h> #include <sys/types.h> #include <limits.h> #define SEM_VALUE_MAX (UINT_MAX - 1) #define SEM_VALUE_INVALID UINT_MAX struct __sem_t { unsigned int count; pthread_mutex_t count_lock; pthread_cond_t lock; char * ID; /* may be used in future to store semaphore name */ }; typedef struct __sem_t sem_t; __BEGIN_DECLS /* Initialize the semaphore and set the initial value - as in LinuxThreads pshared must be zero right now. */ extern int sem_init (sem_t *sem, int pshared, unsigned int value); /* Destroys the semaphore */ extern int sem_destroy (sem_t *sem); /* Wait until the count is > 0, and then decrease it */ extern int sem_wait (sem_t *sem); /* Non-blocking variant of sem_wait. Returns -1 if count == 0. */ extern int sem_trywait (sem_t *sem); /* Increments the count */ extern int sem_post (sem_t *sem); /* Return the value of the semaphore */ extern int sem_getvalue (sem_t *sem, int *sval); __END_DECLS #endif /* semaphore.h */