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 */