diff options
author | Ulrich Drepper <drepper@redhat.com> | 2003-05-17 20:49:02 +0000 |
---|---|---|
committer | Ulrich Drepper <drepper@redhat.com> | 2003-05-17 20:49:02 +0000 |
commit | 68a396e83a8e1e50d0dfde8ffb090a8df311453f (patch) | |
tree | 1722f8620a6d09bfc480c749becee6b875959f2d /nptl/sem_close.c | |
parent | 2384fe204b6de4a45402b48af89b2f01bdb08e73 (diff) | |
download | glibc-68a396e83a8e1e50d0dfde8ffb090a8df311453f.tar glibc-68a396e83a8e1e50d0dfde8ffb090a8df311453f.tar.gz glibc-68a396e83a8e1e50d0dfde8ffb090a8df311453f.tar.bz2 glibc-68a396e83a8e1e50d0dfde8ffb090a8df311453f.zip |
Fix one endless loop. Implement correct semantics wrt opening the same semaphore more then once.
Diffstat (limited to 'nptl/sem_close.c')
-rw-r--r-- | nptl/sem_close.c | 58 |
1 files changed, 55 insertions, 3 deletions
diff --git a/nptl/sem_close.c b/nptl/sem_close.c index 379565f518..279522d086 100644 --- a/nptl/sem_close.c +++ b/nptl/sem_close.c @@ -1,4 +1,4 @@ -/* Copyright (C) 2002 Free Software Foundation, Inc. +/* Copyright (C) 2002, 2003 Free Software Foundation, Inc. This file is part of the GNU C Library. Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. @@ -17,13 +17,65 @@ Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. */ -#include <semaphore.h> +#include <errno.h> +#include <search.h> #include <sys/mman.h> +#include "semaphoreP.h" + + +/* Global variables to parametrize the walk function. This works + since we always have to use locks. And we have to use the twalk + function since the entries are not sorted wrt the mapping + address. */ +static sem_t *the_sem; +static struct inuse_sem *rec; + +static void +walker (const void *inodep, const VISIT which, const int depth) +{ + struct inuse_sem *nodep = *(struct inuse_sem **) inodep; + + if (nodep->sem == the_sem) + rec = nodep; +} int sem_close (sem) sem_t *sem; { - return munmap (sem, sizeof (sem_t)); + int result = 0; + + /* Get the lock. */ + lll_lock (__sem_mappings_lock); + + /* Locate the entry for the mapping the caller provided. */ + rec = NULL; + the_sem = sem; + twalk (__sem_mappings, walker); + if (rec != NULL) + { + /* Check the reference counter. If it is going to be zero, free + all the resources. */ + if (--rec->refcnt == 0) + { + /* Remove the record from the tree. */ + (void) tdelete (rec, &__sem_mappings, __sem_search); + + result = munmap (rec->sem, sizeof (sem_t)); + + free (rec); + } + } + else + { + /* This is no valid semaphore. */ + result = -1; + __set_errno (EINVAL); + } + + /* Release the lock. */ + lll_unlock (__sem_mappings_lock); + + return result; } |