diff options
author | David 'Digit' Turner <digit@google.com> | 2010-03-18 14:07:42 -0700 |
---|---|---|
committer | David 'Digit' Turner <digit@google.com> | 2010-03-18 14:07:42 -0700 |
commit | ee7b077abf1d99503b986489ad93374a057cb354 (patch) | |
tree | 2f424373469e9e040312951e59a9627cb17d6a8d /libc | |
parent | 40e6b822866ee59f7823000384321bb899416cb1 (diff) | |
download | bionic-ee7b077abf1d99503b986489ad93374a057cb354.zip bionic-ee7b077abf1d99503b986489ad93374a057cb354.tar.gz bionic-ee7b077abf1d99503b986489ad93374a057cb354.tar.bz2 |
Add pthread_condattr_init/destroy/setpshared/getpshared
Note that this does not change the implementation of conditional variables
which still use shared futexes, independent on the flags being selected.
This will be fixed in a later patch, once our system is modified to use
pthread_condattr_setpshared(attr, PTHREAD_PROCESS_SHARED) properly.
Change-Id: I935de50964cd41f97a13dbfd6626d3407b0406c3
Diffstat (limited to 'libc')
-rw-r--r-- | libc/bionic/pthread.c | 85 | ||||
-rw-r--r-- | libc/docs/CHANGES.TXT | 8 | ||||
-rw-r--r-- | libc/include/pthread.h | 5 |
3 files changed, 94 insertions, 4 deletions
diff --git a/libc/bionic/pthread.c b/libc/bionic/pthread.c index 127122f..4ffa9b8 100644 --- a/libc/bionic/pthread.c +++ b/libc/bionic/pthread.c @@ -1248,11 +1248,57 @@ int pthread_mutex_lock_timeout_np(pthread_mutex_t *mutex, unsigned msecs) return 0; } +int pthread_condattr_init(pthread_condattr_t *attr) +{ + if (attr == NULL) + return EINVAL; + + *attr = PTHREAD_PROCESS_PRIVATE; + return 0; +} + +int pthread_condattr_getpshared(pthread_condattr_t *attr, int *pshared) +{ + if (attr == NULL || pshared == NULL) + return EINVAL; + + *pshared = *attr; + return 0; +} + +int pthread_condattr_setpshared(pthread_condattr_t *attr, int pshared) +{ + if (attr == NULL) + return EINVAL; + + if (pshared != PTHREAD_PROCESS_SHARED && + pshared != PTHREAD_PROCESS_PRIVATE) + return EINVAL; + + *attr = pshared; + return 0; +} + +int pthread_condattr_destroy(pthread_condattr_t *attr) +{ + if (attr == NULL) + return EINVAL; + + *attr = 0xdeada11d; + return 0; +} + +/* We use one bit in condition variable values as the 'shared' flag + * The rest is a counter. + */ +#define COND_SHARING_MASK 0x0001 +#define COND_COUNTER_INCREMENT 0x0002 +#define COND_COUNTER_MASK (~COND_SHARING_MASK) /* XXX *technically* there is a race condition that could allow * XXX a signal to be missed. If thread A is preempted in _wait() * XXX after unlocking the mutex and before waiting, and if other - * XXX threads call signal or broadcast UINT_MAX times (exactly), + * XXX threads call signal or broadcast UINT_MAX/2 times (exactly), * XXX before thread A is scheduled again and calls futex_wait(), * XXX then the signal will be lost. */ @@ -1260,26 +1306,59 @@ int pthread_mutex_lock_timeout_np(pthread_mutex_t *mutex, unsigned msecs) int pthread_cond_init(pthread_cond_t *cond, const pthread_condattr_t *attr) { + if (cond == NULL) + return EINVAL; + cond->value = 0; + + if (attr != NULL && *attr == PTHREAD_PROCESS_SHARED) + cond->value |= COND_SHARING_MASK; + return 0; } int pthread_cond_destroy(pthread_cond_t *cond) { + if (cond == NULL) + return EINVAL; + cond->value = 0xdeadc04d; return 0; } +/* This function is used by pthread_cond_broadcast and + * pthread_cond_signal to atomically decrement the counter. + */ +static void +__pthread_cond_pulse(pthread_cond_t *cond) +{ + long flags = (cond->value & ~COND_COUNTER_MASK); + + for (;;) { + long oldval = cond->value; + long newval = ((oldval - COND_COUNTER_INCREMENT) & COND_COUNTER_MASK) + | flags; + if (__atomic_cmpxchg(oldval, newval, &cond->value) == 0) + break; + } +} + int pthread_cond_broadcast(pthread_cond_t *cond) { - __atomic_dec(&cond->value); + if (__unlikely(cond == NULL)) + return EINVAL; + + __pthread_cond_pulse(cond); __futex_wake(&cond->value, INT_MAX); return 0; } int pthread_cond_signal(pthread_cond_t *cond) { - __atomic_dec(&cond->value); + if (__unlikely(cond == NULL)) + return EINVAL; + + __pthread_cond_pulse(cond); __futex_wake(&cond->value, 1); return 0; } diff --git a/libc/docs/CHANGES.TXT b/libc/docs/CHANGES.TXT index 4f87547..ec147c2 100644 --- a/libc/docs/CHANGES.TXT +++ b/libc/docs/CHANGES.TXT @@ -78,7 +78,13 @@ Differences between current and Android 2.1: - DNS: get rid of spurious random DNS queries when trying to resolve an unknown domain name. Due to an initialization bug, a random DNS search - list was generated for each thread is net.dns.search is not defined. + list was generated for each thread if net.dns.search is not defined. + +- <pthread.h>: Add pthread_condattr_init/destroy/setpshared/getpshared functions + to enable proper shared conditional variable initialization. + + XXX: The implementation still always uses shared condvars, independent + of the flags being selected. This will change in a later commit. ------------------------------------------------------------------------------- Differences between Android 2.1 and 2.0.1: diff --git a/libc/include/pthread.h b/libc/include/pthread.h index 6603b3f..eb2d169 100644 --- a/libc/include/pthread.h +++ b/libc/include/pthread.h @@ -165,6 +165,11 @@ int pthread_mutex_unlock(pthread_mutex_t *mutex); int pthread_mutex_trylock(pthread_mutex_t *mutex); int pthread_mutex_timedlock(pthread_mutex_t *mutex, struct timespec* ts); +int pthread_condattr_init(pthread_condattr_t *attr); +int pthread_condattr_getpshared(pthread_condattr_t *attr, int *pshared); +int pthread_condattr_setpshared(pthread_condattr_t* attr, int pshared); +int pthread_condattr_destroy(pthread_condattr_t *attr); + int pthread_cond_init(pthread_cond_t *cond, const pthread_condattr_t *attr); int pthread_cond_destroy(pthread_cond_t *cond); |