/* Copyright (C) 2000,02 Free Software Foundation, Inc. This file is part of the GNU C Library. Written by Ga?l Le Mignot 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 */ #include #include #include #include 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; }