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

Reply via email to