mirror of
https://sourceware.org/git/glibc.git
synced 2025-07-30 22:43:12 +03:00
Update.
2000-01-12 Ulrich Drepper <drepper@cygnus.com> * iconvdata/gconv-modules: Add aliases ISO-IR-199 and ISO-IR-203. Reported by Bruno Haible <haible@ilog.fr>. 2000-01-11 Andreas Schwab <schwab@suse.de> * sysdeps/i386/fpu/libm-test-ulps: Adjust some epsilons. 2000-01-10 Thorsten Kukuk <kukuk@suse.de> * nss/getent.c: Add ipv6 support for hosts. 2000-01-05 Philip Blundell <pb@futuretv.com> * sysdeps/unix/sysv/linux/arm/Versions: Add getrlimit, setrlimit, getrlimit64, setrlimit64 for GLIBC_2.1.3. * sysdeps/unix/sysv/linux/arm/syscalls.list: Add oldgetrlimit, oldsetrlimit. * sysdeps/unix/sysv/linux/arm/oldsetrlimit64.c: New file. * sysdeps/unix/sysv/linux/arm/oldgetrlimit64.c: Likewise. * sysdeps/unix/sysv/linux/arm/setrlimit64.c: Likewise. * sysdeps/unix/sysv/linux/arm/getrlimit64.c: Likewise. * sysdeps/unix/sysv/linux/arm/setrlimit.c: Likewise. * sysdeps/unix/sysv/linux/arm/getrlimit.c: Likewise. * sysdeps/unix/sysv/linux/arm/Makefile [subdir=resource] (sysdep_routines): Add oldgetrlimit64, oldsetrlimit64. [subdir=misc] (sysdep_headers): Add sys/elf.h. 2000-01-09 Andreas Jaeger <aj@suse.de> * manual/install.texi (Tools for Compilation): Update required compiler version. (Configuring and compiling): Restore old comments about configparms; modify to reflect current usage. 2000-01-09 Philip Blundell <philb@gnu.org> * sysdeps/posix/getaddrinfo.c (gaih_inet): Don't attempt name resolution if the hints included AI_NUMERICHOST.
This commit is contained in:
@ -1,5 +1,5 @@
|
||||
/* Read-write lock implementation.
|
||||
Copyright (C) 1998 Free Software Foundation, Inc.
|
||||
Copyright (C) 1998, 2000 Free Software Foundation, Inc.
|
||||
This file is part of the GNU C Library.
|
||||
Contributed by Xavier Leroy <Xavier.Leroy@inria.fr>
|
||||
and Ulrich Drepper <drepper@cygnus.com>, 1998.
|
||||
@ -21,11 +21,167 @@
|
||||
|
||||
#include <errno.h>
|
||||
#include <pthread.h>
|
||||
#include <stdlib.h>
|
||||
#include "internals.h"
|
||||
#include "queue.h"
|
||||
#include "spinlock.h"
|
||||
#include "restart.h"
|
||||
|
||||
/*
|
||||
* Check whether the calling thread already owns one or more read locks on the
|
||||
* specified lock. If so, return a pointer to the read lock info structure
|
||||
* corresponding to that lock.
|
||||
*/
|
||||
|
||||
static pthread_readlock_info *
|
||||
rwlock_is_in_list(pthread_descr self, pthread_rwlock_t *rwlock)
|
||||
{
|
||||
pthread_readlock_info *info;
|
||||
|
||||
for (info = self->p_readlock_list; info != NULL; info = info->pr_next)
|
||||
{
|
||||
if (info->pr_lock == rwlock)
|
||||
return info;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/*
|
||||
* Add a new lock to the thread's list of locks for which it has a read lock.
|
||||
* A new info node must be allocated for this, which is taken from the thread's
|
||||
* free list, or by calling malloc. If malloc fails, a null pointer is
|
||||
* returned. Otherwise the lock info structure is initialized and pushed
|
||||
* onto the thread's list.
|
||||
*/
|
||||
|
||||
static pthread_readlock_info *
|
||||
rwlock_add_to_list(pthread_descr self, pthread_rwlock_t *rwlock)
|
||||
{
|
||||
pthread_readlock_info *info = self->p_readlock_free;
|
||||
|
||||
if (info != NULL)
|
||||
self->p_readlock_free = info->pr_next;
|
||||
else
|
||||
info = malloc(sizeof *info);
|
||||
|
||||
if (info == NULL)
|
||||
return NULL;
|
||||
|
||||
info->pr_lock_count = 1;
|
||||
info->pr_lock = rwlock;
|
||||
info->pr_next = self->p_readlock_list;
|
||||
self->p_readlock_list = info;
|
||||
|
||||
return info;
|
||||
}
|
||||
|
||||
/*
|
||||
* If the thread owns a read lock over the given pthread_rwlock_t,
|
||||
* and this read lock is tracked in the thread's lock list,
|
||||
* this function returns a pointer to the info node in that list.
|
||||
* It also decrements the lock count within that node, and if
|
||||
* it reaches zero, it removes the node from the list.
|
||||
* If nothing is found, it returns a null pointer.
|
||||
*/
|
||||
|
||||
static pthread_readlock_info *
|
||||
rwlock_remove_from_list(pthread_descr self, pthread_rwlock_t *rwlock)
|
||||
{
|
||||
pthread_readlock_info **pinfo;
|
||||
|
||||
for (pinfo = &self->p_readlock_list; *pinfo != NULL; pinfo = &(*pinfo)->pr_next)
|
||||
{
|
||||
if ((*pinfo)->pr_lock == rwlock)
|
||||
{
|
||||
pthread_readlock_info *info = *pinfo;
|
||||
if (--info->pr_lock_count == 0)
|
||||
*pinfo = info->pr_next;
|
||||
return info;
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/*
|
||||
* This function checks whether the conditions are right to place a read lock.
|
||||
* It returns 1 if so, otherwise zero. The rwlock's internal lock must be
|
||||
* locked upon entry.
|
||||
*/
|
||||
|
||||
static int
|
||||
rwlock_can_rdlock(pthread_rwlock_t *rwlock, int have_lock_already)
|
||||
{
|
||||
/* Can't readlock; it is write locked. */
|
||||
if (rwlock->__rw_writer != NULL)
|
||||
return 0;
|
||||
|
||||
/* Lock prefers readers; get it. */
|
||||
if (rwlock->__rw_kind == PTHREAD_RWLOCK_PREFER_READER_NP)
|
||||
return 1;
|
||||
|
||||
/* Lock prefers writers, but none are waiting. */
|
||||
if (queue_is_empty(&rwlock->__rw_write_waiting))
|
||||
return 1;
|
||||
|
||||
/* Writers are waiting, but this thread already has a read lock */
|
||||
if (have_lock_already)
|
||||
return 1;
|
||||
|
||||
/* Writers are waiting, and this is a new lock */
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* This function helps support brain-damaged recursive read locking
|
||||
* semantics required by Unix 98, while maintaining write priority.
|
||||
* This basically determines whether this thread already holds a read lock
|
||||
* already. It returns 1 if so, otherwise it returns 0.
|
||||
*
|
||||
* If the thread has any ``untracked read locks'' then it just assumes
|
||||
* that this lock is among them, just to be safe, and returns 1.
|
||||
*
|
||||
* Also, if it finds the thread's lock in the list, it sets the pointer
|
||||
* referenced by pexisting to refer to the list entry.
|
||||
*
|
||||
* If the thread has no untracked locks, and the lock is not found
|
||||
* in its list, then it is added to the list. If this fails,
|
||||
* then *pout_of_mem is set to 1.
|
||||
*/
|
||||
|
||||
static int
|
||||
rwlock_have_already(pthread_descr *pself, pthread_rwlock_t *rwlock,
|
||||
pthread_readlock_info **pexisting, int *pout_of_mem)
|
||||
{
|
||||
pthread_readlock_info *existing = NULL;
|
||||
int out_of_mem = 0, have_lock_already = 0;
|
||||
pthread_descr self = *pself;
|
||||
|
||||
if (rwlock->__rw_kind == PTHREAD_RWLOCK_PREFER_WRITER_NP)
|
||||
{
|
||||
if (!self)
|
||||
self = thread_self();
|
||||
|
||||
existing = rwlock_is_in_list(self, rwlock);
|
||||
|
||||
if (existing != NULL || self->p_untracked_readlock_count > 0)
|
||||
have_lock_already = 1;
|
||||
else
|
||||
{
|
||||
existing = rwlock_add_to_list(self, rwlock);
|
||||
if (existing == NULL)
|
||||
out_of_mem = 1;
|
||||
}
|
||||
}
|
||||
|
||||
*pout_of_mem = out_of_mem;
|
||||
*pexisting = existing;
|
||||
*pself = self;
|
||||
|
||||
return have_lock_already;
|
||||
}
|
||||
|
||||
int
|
||||
pthread_rwlock_init (pthread_rwlock_t *rwlock,
|
||||
const pthread_rwlockattr_t *attr)
|
||||
@ -68,24 +224,26 @@ pthread_rwlock_destroy (pthread_rwlock_t *rwlock)
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
pthread_rwlock_rdlock (pthread_rwlock_t *rwlock)
|
||||
{
|
||||
pthread_descr self = NULL;
|
||||
pthread_readlock_info *existing;
|
||||
int out_of_mem, have_lock_already;
|
||||
|
||||
while (1)
|
||||
have_lock_already = rwlock_have_already(&self, rwlock,
|
||||
&existing, &out_of_mem);
|
||||
|
||||
for (;;)
|
||||
{
|
||||
__pthread_lock (&rwlock->__rw_lock, self);
|
||||
if (rwlock->__rw_writer == NULL
|
||||
|| (rwlock->__rw_kind == PTHREAD_RWLOCK_PREFER_READER_NP
|
||||
&& rwlock->__rw_readers != 0))
|
||||
/* We can add a reader lock. */
|
||||
break;
|
||||
|
||||
/* Suspend ourselves, then try again */
|
||||
if (self == NULL)
|
||||
self = thread_self ();
|
||||
|
||||
__pthread_lock (&rwlock->__rw_lock, self);
|
||||
|
||||
if (rwlock_can_rdlock(rwlock, have_lock_already))
|
||||
break;
|
||||
|
||||
enqueue (&rwlock->__rw_read_waiting, self);
|
||||
__pthread_unlock (&rwlock->__rw_lock);
|
||||
suspend (self); /* This is not a cancellation point */
|
||||
@ -94,26 +252,56 @@ pthread_rwlock_rdlock (pthread_rwlock_t *rwlock)
|
||||
++rwlock->__rw_readers;
|
||||
__pthread_unlock (&rwlock->__rw_lock);
|
||||
|
||||
if (have_lock_already || out_of_mem)
|
||||
{
|
||||
if (existing != NULL)
|
||||
existing->pr_lock_count++;
|
||||
else
|
||||
self->p_untracked_readlock_count++;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
pthread_rwlock_tryrdlock (pthread_rwlock_t *rwlock)
|
||||
{
|
||||
int result = EBUSY;
|
||||
pthread_descr self = thread_self();
|
||||
pthread_readlock_info *existing;
|
||||
int out_of_mem, have_lock_already;
|
||||
int retval = EBUSY;
|
||||
|
||||
__pthread_lock (&rwlock->__rw_lock, NULL);
|
||||
if (rwlock->__rw_writer == NULL
|
||||
|| (rwlock->__rw_kind == PTHREAD_RWLOCK_PREFER_READER_NP
|
||||
&& rwlock->__rw_readers != 0))
|
||||
have_lock_already = rwlock_have_already(&self, rwlock,
|
||||
&existing, &out_of_mem);
|
||||
|
||||
__pthread_lock (&rwlock->__rw_lock, self);
|
||||
|
||||
/* 0 is passed to here instead of have_lock_already.
|
||||
This is to meet Single Unix Spec requirements:
|
||||
if writers are waiting, pthread_rwlock_tryrdlock
|
||||
does not acquire a read lock, even if the caller has
|
||||
one or more read locks already. */
|
||||
|
||||
if (rwlock_can_rdlock(rwlock, 0))
|
||||
{
|
||||
++rwlock->__rw_readers;
|
||||
result = 0;
|
||||
retval = 0;
|
||||
}
|
||||
|
||||
__pthread_unlock (&rwlock->__rw_lock);
|
||||
|
||||
return result;
|
||||
if (retval == 0)
|
||||
{
|
||||
if (have_lock_already || out_of_mem)
|
||||
{
|
||||
if (existing != NULL)
|
||||
existing->pr_lock_count++;
|
||||
else
|
||||
self->p_untracked_readlock_count++;
|
||||
}
|
||||
}
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
|
||||
@ -210,6 +398,28 @@ pthread_rwlock_unlock (pthread_rwlock_t *rwlock)
|
||||
__pthread_unlock (&rwlock->__rw_lock);
|
||||
if (th != NULL)
|
||||
restart (th);
|
||||
|
||||
/* Recursive lock fixup */
|
||||
|
||||
if (rwlock->__rw_kind == PTHREAD_RWLOCK_PREFER_WRITER_NP)
|
||||
{
|
||||
pthread_descr self = thread_self();
|
||||
pthread_readlock_info *victim = rwlock_remove_from_list(self, rwlock);
|
||||
|
||||
if (victim != NULL)
|
||||
{
|
||||
if (victim->pr_lock_count == 0)
|
||||
{
|
||||
victim->pr_next = self->p_readlock_free;
|
||||
self->p_readlock_free = victim;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (self->p_untracked_readlock_count > 0)
|
||||
self->p_untracked_readlock_count--;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
Reference in New Issue
Block a user