/*
* Copyright (c) 2001 Daniel Eischen <deischen@FreeBSD.org>.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY DANIEL EISCHEN AND CONTRIBUTORS ``AS IS''
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* $FreeBSD: /tmp/pcvs/ports/devel/linuxthreads/files/wraputhread.c,v 1.3 2003-06-09 03:48:31 tegge Exp $
*/
#ifdef LINUXTHREADS_WRAP_API
#define COMPILING_WRAPUTHREAD
#endif
#include <pthread.h>
#include <stdlib.h>
#include <sys/errno.h>
#ifdef LINUXTHREADS_WRAP_API
#define __pthread_attr_destroy linuxthreads_pthread_attr_destroy
#define __pthread_attr_getdetachstate linuxthreads_pthread_attr_getdetachstate
#define __pthread_attr_getinheritsched linuxthreads_pthread_attr_getinheritsched
#define __pthread_attr_getschedparam linuxthreads_pthread_attr_getschedparam
#define __pthread_attr_getschedpolicy linuxthreads_pthread_attr_getschedpolicy
#define __pthread_attr_getscope linuxthreads_pthread_attr_getscope
#define __pthread_attr_init linuxthreads_pthread_attr_init
#define __pthread_attr_setdetachstate linuxthreads_pthread_attr_setdetachstate
#define __pthread_attr_setinheritsched linuxthreads_pthread_attr_setinheritsched
#define __pthread_attr_setschedparam linuxthreads_pthread_attr_setschedparam
#define __pthread_attr_setschedpolicy linuxthreads_pthread_attr_setschedpolicy
#define __pthread_attr_setscope linuxthreads_pthread_attr_setscope
#define __pthread_barrier_destroy linuxthreads_pthread_barrier_destroy
#define __pthread_barrier_init linuxthreads_pthread_barrier_init
#define __pthread_barrier_wait linuxthreads_pthread_barrier_wait
#define __pthread_barrierattr_destroy linuxthreads_pthread_barrierattr_destroy
#define __pthread_barrierattr_init linuxthreads_pthread_barrierattr_init
#define __pthread_barrierattr_setpshared linuxthreads_pthread_barrierattr_setpshared
#define __pthread_cancel linuxthreads_pthread_cancel
#define __pthread_condattr_destroy linuxthreads_pthread_condattr_destroy
#define __pthread_condattr_getpshared linuxthreads_pthread_condattr_getpshared
#define __pthread_condattr_init linuxthreads_pthread_condattr_init
#define __pthread_condattr_setpshared linuxthreads_pthread_condattr_setpshared
#define __pthread_cond_broadcast linuxthreads_pthread_cond_broadcast
#define __pthread_cond_destroy linuxthreads_pthread_cond_destroy
#define __pthread_cond_init linuxthreads_pthread_cond_init
#define __pthread_cond_signal linuxthreads_pthread_cond_signal
#define __pthread_cond_timedwait linuxthreads_pthread_cond_timedwait
#define __pthread_cond_wait linuxthreads_pthread_cond_wait
#define __pthread_create linuxthreads_pthread_create
#define __pthread_detach linuxthreads_pthread_detach
#define __pthread_equal linuxthreads_pthread_equal
#define __pthread_exit linuxthreads_pthread_exit
#define __pthread_getcpuclockid linuxthreads_pthread_getcpuclockid
#define __pthread_getschedparam linuxthreads_pthread_getschedparam
#define __pthread_join linuxthreads_pthread_join
#define __pthread_key_delete linuxthreads_pthread_key_delete
#define __pthread_kill linuxthreads_pthread_kill
#define __pthread_rwlockattr_init linuxthreads_pthread_rwlockattr_init
#define __pthread_rwlockattr_getpshared linuxthreads_pthread_rwlockattr_getpshared
#define __pthread_rwlockattr_setpshared linuxthreads_pthread_rwlockattr_setpshared
#define __pthread_rwlockattr_destroy linuxthreads_pthread_rwlockattr_destroy
#define __pthread_self linuxthreads_pthread_self
#define __pthread_setcanceltype linuxthreads_pthread_setcanceltype
#define __pthread_setcancelstate linuxthreads_pthread_setcancelstate
#define __pthread_setschedparam linuxthreads_pthread_setschedparam
#define __pthread_sigmask linuxthreads_pthread_sigmask
#define __pthread_testcancel linuxthreads_pthread_testcancel
#else
#define __pthread_attr_destroy pthread_attr_destroy
#define __pthread_attr_getdetachstate pthread_attr_getdetachstate
#define __pthread_attr_getinheritsched pthread_attr_getinheritsched
#define __pthread_attr_getschedparam pthread_attr_getschedparam
#define __pthread_attr_getschedpolicy pthread_attr_getschedpolicy
#define __pthread_attr_getscope pthread_attr_getscope
#define __pthread_attr_init pthread_attr_init
#define __pthread_attr_setdetachstate pthread_attr_setdetachstate
#define __pthread_attr_setinheritsched pthread_attr_setinheritsched
#define __pthread_attr_setschedparam pthread_attr_setschedparam
#define __pthread_attr_setschedpolicy pthread_attr_setschedpolicy
#define __pthread_attr_setscope pthread_attr_setscope
#define __pthread_barrier_destroy pthread_barrier_destroy
#define __pthread_barrier_init pthread_barrier_init
#define __pthread_barrier_wait pthread_barrier_wait
#define __pthread_barrierattr_destroy pthread_barrierattr_destroy
#define __pthread_barrierattr_init pthread_barrierattr_init
#define __pthread_barrierattr_setpshared pthread_barrierattr_setpshared
#define __pthread_cancel pthread_cancel
#define __pthread_condattr_destroy pthread_condattr_destroy
#define __pthread_condattr_getpshared pthread_condattr_getpshared
#define __pthread_condattr_init pthread_condattr_init
#define __pthread_condattr_setpshared pthread_condattr_setpshared
#define __pthread_cond_broadcast pthread_cond_broadcast
#define __pthread_cond_destroy pthread_cond_destroy
#define __pthread_cond_init pthread_cond_init
#define __pthread_cond_signal pthread_cond_signal
#define __pthread_cond_timedwait pthread_cond_timedwait
#define __pthread_cond_wait pthread_cond_wait
#define __pthread_create pthread_create
#define __pthread_detach pthread_detach
#define __pthread_equal pthread_equal
#define __pthread_exit pthread_exit
#define __pthread_getschedparam pthread_getschedparam
#define __pthread_join pthread_join
#define __pthread_key_delete pthread_key_delete
#define __pthread_kill pthread_kill
#define __pthread_rwlockattr_init pthread_rwlockattr_init
#define __pthread_rwlockattr_getpshared pthread_rwlockattr_getpshared
#define __pthread_rwlockattr_setpshared pthread_rwlockattr_setpshared
#define __pthread_rwlockattr_destroy pthread_rwlockattr_destroy
#define __pthread_self pthread_self
#define __pthread_setcanceltype pthread_setcanceltype
#define __pthread_setcancelstate pthread_setcancelstate
#define __pthread_setschedparam pthread_setschedparam
#define __pthread_sigmask pthread_sigmask
#define __pthread_testcancel pthread_testcancel
#endif
int __pthread_atfork(void (*)(void), void (*)(void), void (*)(void));
int __pthread_attr_destroy(pthread_attr_t *);
int __pthread_attr_getdetachstate(const pthread_attr_t *, int *);
int __pthread_attr_getguardsize(const pthread_attr_t *, size_t *);
int __pthread_attr_getinheritsched(const pthread_attr_t *, int *);
int __pthread_attr_getschedparam(const pthread_attr_t *,
struct sched_param *);
int __pthread_attr_getschedpolicy(const pthread_attr_t *, int *);
int __pthread_attr_getscope(const pthread_attr_t *, int *);
int __pthread_attr_getstack(const pthread_attr_t *, void **, size_t *);
int __pthread_attr_getstackaddr(const pthread_attr_t *, void **);
int __pthread_attr_getstacksize(const pthread_attr_t *, size_t *);
int __pthread_attr_init(pthread_attr_t *);
int __pthread_attr_setdetachstate(pthread_attr_t *, int);
int __pthread_attr_setguardsize(pthread_attr_t *, size_t);
int __pthread_attr_setinheritsched(pthread_attr_t *, int);
int __pthread_attr_setschedparam(pthread_attr_t *,
const struct sched_param *);
int __pthread_attr_setschedpolicy(pthread_attr_t *, int);
int __pthread_attr_setscope(pthread_attr_t *, int);
int __pthread_attr_setstack(pthread_attr_t *, void *, size_t);
int __pthread_attr_setstackaddr(pthread_attr_t *, void *);
int __pthread_attr_setstacksize(pthread_attr_t *, size_t);
int __pthread_barrier_destroy(pthread_barrier_t *);
int __pthread_barrier_init(pthread_barrier_t *,
const pthread_barrierattr_t *,
unsigned int);
int __pthread_barrier_wait(pthread_barrier_t *);
int __pthread_barrierattr_destroy(pthread_barrierattr_t *);
int __pthread_barrierattr_getpshared(const pthread_barrierattr_t *, int *);
int __pthread_barrierattr_init(pthread_barrierattr_t *);
int __pthread_barrierattr_setpshared(pthread_barrierattr_t *, int);
int __pthread_cancel(pthread_t);
int __pthread_cond_broadcast(pthread_cond_t *);
int __pthread_cond_destroy(pthread_cond_t *);
int __pthread_cond_init(pthread_cond_t *, const pthread_condattr_t *);
int __pthread_cond_signal(pthread_cond_t *);
int __pthread_cond_timedwait(pthread_cond_t *,
pthread_mutex_t *,
const struct timespec *);
int __pthread_cond_wait(pthread_cond_t *, pthread_mutex_t *);
int __pthread_condattr_destroy(pthread_condattr_t *);
int __pthread_condattr_getpshared(const pthread_condattr_t *, int *);
int __pthread_condattr_init(pthread_condattr_t *);
int __pthread_condattr_setpshared(pthread_condattr_t *, int);
int __pthread_create(pthread_t *,
const pthread_attr_t *,
void *(*)(void *),
void *);
int __pthread_detach(pthread_t);
int __pthread_equal(pthread_t, pthread_t);
void __pthread_exit(void *);
int __pthread_getconcurrency(void);
int __pthread_getschedparam(pthread_t, int *, struct sched_param *);
void *__pthread_getspecific(pthread_key_t);
int __pthread_join(pthread_t, void **);
int __pthread_key_create(pthread_key_t *, void (*) (void *));
int __pthread_key_delete(pthread_key_t);
int __pthread_kill(pthread_t, int);
int __pthread_mutex_destroy(pthread_mutex_t *);
int __pthread_mutex_init(pthread_mutex_t *, const pthread_mutexattr_t *);
int __pthread_mutex_lock(pthread_mutex_t *);
int __pthread_mutex_timedlock(pthread_mutex_t *, const struct timespec *);
int __pthread_mutex_trylock(pthread_mutex_t *);
int __pthread_mutex_unlock(pthread_mutex_t *);
int __pthread_mutexattr_destroy(pthread_mutexattr_t *);
int __pthread_mutexattr_getpshared(const pthread_mutexattr_t *, int *);
int __pthread_mutexattr_gettype(const pthread_mutexattr_t *, int *);
int __pthread_mutexattr_init(pthread_mutexattr_t *);
int __pthread_mutexattr_setpshared(pthread_mutexattr_t *, int);
int __pthread_mutexattr_settype(pthread_mutexattr_t *, int);
int __pthread_rwlock_destroy(pthread_rwlock_t *);
int __pthread_rwlock_init(pthread_rwlock_t *,
const pthread_rwlockattr_t *);
int __pthread_rwlock_rdlock(pthread_rwlock_t *);
int __pthread_rwlock_timedrdlock(pthread_rwlock_t *,
const struct timespec *);
int __pthread_rwlock_timedwrlock(pthread_rwlock_t *,
const struct timespec *);
int __pthread_rwlock_tryrdlock(pthread_rwlock_t *);
int __pthread_rwlock_trywrlock(pthread_rwlock_t *);
int __pthread_rwlock_unlock(pthread_rwlock_t *);
int __pthread_rwlock_wrlock(pthread_rwlock_t *);
int __pthread_rwlockattr_destroy(pthread_rwlockattr_t *);
int __pthread_rwlockattr_init(pthread_rwlockattr_t *);
int __pthread_rwlockattr_getpshared(const pthread_rwlockattr_t *, int *);
int __pthread_rwlockattr_setpshared(pthread_rwlockattr_t *, int);
pthread_t __pthread_self(void);
int __pthread_setcancelstate(int, int *);
int __pthread_setcanceltype(int, int *);
int __pthread_setconcurrency(int);
int __pthread_setschedparam(pthread_t, int, const struct sched_param *);
int __pthread_setspecific(pthread_key_t, const void *);
int __pthread_sigmask(int, const sigset_t *, sigset_t *);
void __pthread_testcancel(void);
static pthread_mutex_t allocmutexlock = PTHREAD_MUTEX_INITIALIZER;
enum uthread_mutextype {
UTHREAD_PTHREAD_MUTEX_ERRORCHECK = 1, /* Default POSIX mutex */
UTHREAD_PTHREAD_MUTEX_RECURSIVE = 2, /* Recursive mutex */
UTHREAD_PTHREAD_MUTEX_NORMAL = 3, /* No error checking */
MUTEX_TYPE_MAX
};
enum {
UTHREAD_PTHREAD_CREATE_JOINABLE = 0,
UTHREAD_PTHREAD_CREATE_DETACHED = 1
};
enum {
UTHREAD_PTHREAD_INHERIT_SCHED = 0,
UTHREAD_PTHREAD_EXPLICIT_SCHED = 1
};
enum {
UTHREAD_PTHREAD_SCOPE_SYSTEM = 0,
UTHREAD_PTHREAD_SCOPE_PROCESS = 1
};
enum {
UTHREAD_PTHREAD_PROCESS_PRIVATE = 0,
UTHREAD_PTHREAD_PROCESS_SHARED = 1
};
enum {
UTHREAD_PTHREAD_CANCEL_ENABLE = 0,
UTHREAD_PTHREAD_CANCEL_DISABLE = 1,
UTHREAD_PTHREAD_CANCEL_DEFERRED = 0,
UTHREAD_PTHREAD_CANCEL_ASYNCHRONOUS = 2
};
#define UTHREAD_PTHREAD_CANCELED ((void *) 1)
enum {
UTHREAD_PTHREAD_PRIO_NONE = 0,
UTHREAD_PTHREAD_PRIO_INHERIT = 1,
UTHREAD_PTHREAD_PRIO_PROTECT = 2
};
struct uthread_pthread_once {
int state;
pthread_mutex_t *mutex;
};
typedef struct uthread_pthread_once uthread_pthread_once_t;
/*
* Flags for once initialization.
*/
#define UTHREAD_PTHREAD_NEEDS_INIT 0
#define UTHREAD_PTHREAD_DONE_INIT 1
static int allocbarrier(pthread_barrier_t **barrier);
static int alloccond(pthread_cond_t **cond);
static int allocmutex(pthread_mutex_t **mutex);
static int allocrwlock(pthread_rwlock_t **rwlock);
static int
allocbarrier(pthread_barrier_t **barrier)
{
pthread_barrier_t *b;
int ret;
b = malloc(sizeof(pthread_barrier_t));
if (b == NULL)
return ENOMEM;
ret = __pthread_barrier_init(b, NULL, 1);
if (ret != 0) {
free(b);
return ret;
}
__pthread_mutex_lock(&allocmutexlock);
if (*barrier != NULL) {
__pthread_mutex_unlock(&allocmutexlock);
__pthread_barrier_destroy(b);
free(b);
return 0;
}
*barrier = b;
__pthread_mutex_unlock(&allocmutexlock);
return 0;
}
static int
alloccond(pthread_cond_t **cond)
{
pthread_cond_t *c;
int ret;
c = malloc(sizeof(pthread_cond_t));
if (c == NULL)
return ENOMEM;
ret = __pthread_cond_init(c, NULL);
if (ret != 0) {
free(c);
return ret;
}
__pthread_mutex_lock(&allocmutexlock);
if (*cond != NULL) {
__pthread_mutex_unlock(&allocmutexlock);
__pthread_cond_destroy(c);
free(c);
return 0;
}
*cond = c;
__pthread_mutex_unlock(&allocmutexlock);
return 0;
}
static int
allocmutex(pthread_mutex_t **mutex)
{
pthread_mutex_t *m;
int ret;
m = malloc(sizeof(pthread_mutex_t));
if (m == NULL)
return ENOMEM;
ret = __pthread_mutex_init(m, NULL);
if (ret != 0) {
free(m);
return ret;
}
__pthread_mutex_lock(&allocmutexlock);
if (*mutex != NULL) {
__pthread_mutex_unlock(&allocmutexlock);
__pthread_mutex_destroy(m);
free(m);
return 0;
}
*mutex = m;
__pthread_mutex_unlock(&allocmutexlock);
return 0;
}
static int
allocrwlock(pthread_rwlock_t **rwlock)
{
pthread_rwlock_t *rw;
int ret;
rw = malloc(sizeof(pthread_rwlock_t));
if (rw == NULL)
return ENOMEM;
ret = __pthread_rwlock_init(rw, NULL);
if (ret != 0) {
free(rw);
return ret;
}
__pthread_mutex_lock(&allocmutexlock);
if (*rwlock != NULL) {
__pthread_mutex_unlock(&allocmutexlock);
__pthread_rwlock_destroy(rw);
free(rw);
return 0;
}
*rwlock = rw;
__pthread_mutex_unlock(&allocmutexlock);
return 0;
}
int
_pthread_atfork(void (*prepare)(void),
void (*parent)(void),
void (*child)(void))
{
return __pthread_atfork(prepare, parent, child);
}
int
_pthread_attr_destroy(pthread_attr_t **attr)
{
int ret;
if (attr == NULL || *attr == NULL)
return EINVAL;
ret = __pthread_attr_destroy(*attr);
if (ret == 0) {
free(*attr);
*attr = NULL;
}
return ret;
}
int
_pthread_attr_getdetachstate(const pthread_attr_t **attr, int *detachstate)
{
int ret;
int lstate;
if (attr == NULL || *attr == NULL || detachstate == NULL)
return EINVAL;
ret = __pthread_attr_getdetachstate(*attr, &lstate);
if (ret == 0) {
switch (lstate) {
case PTHREAD_CREATE_JOINABLE:
*detachstate = UTHREAD_PTHREAD_CREATE_JOINABLE;
break;
case PTHREAD_CREATE_DETACHED:
*detachstate = UTHREAD_PTHREAD_CREATE_DETACHED;
break;
default:
ret = EINVAL;
}
}
return ret;
}
int
_pthread_attr_getguardsize(const pthread_attr_t **attr, size_t *guardsize)
{
if (attr == NULL || *attr == NULL)
return EINVAL;
return __pthread_attr_getguardsize(*attr, guardsize);
}
int
_pthread_attr_getinheritsched(const pthread_attr_t **attr, int *inherit)
{
int ret;
int linherit;
if (attr == NULL || *attr == NULL || inherit == NULL)
return EINVAL;
ret = __pthread_attr_getinheritsched(*attr, &linherit);
if (ret == 0) {
switch (linherit) {
case PTHREAD_EXPLICIT_SCHED:
*inherit = UTHREAD_PTHREAD_EXPLICIT_SCHED;
break;
case PTHREAD_INHERIT_SCHED:
*inherit = UTHREAD_PTHREAD_INHERIT_SCHED;
break;
default:
ret = EINVAL;
}
}
return ret;
}
int
_pthread_attr_getschedparam(const pthread_attr_t **attr,
struct sched_param *sparam)
{
if (attr == NULL || *attr == NULL || sparam == NULL)
return EINVAL;
return __pthread_attr_getschedparam(*attr, sparam);
}
int
_pthread_attr_getschedpolicy(const pthread_attr_t **attr,
int *policy)
{
if (attr == NULL || *attr == NULL || policy == NULL)
return EINVAL;
return __pthread_attr_getschedpolicy(*attr, policy);
}
int
_pthread_attr_getscope(const pthread_attr_t **attr,
int *scope)
{
int ret;
int lscope;
if (attr == NULL || *attr == NULL || scope == NULL)
return EINVAL;
ret = __pthread_attr_getscope(*attr, &lscope);
if (ret == 0) {
switch (lscope) {
case PTHREAD_SCOPE_SYSTEM:
*scope = UTHREAD_PTHREAD_SCOPE_SYSTEM;
break;
case PTHREAD_SCOPE_PROCESS:
*scope = UTHREAD_PTHREAD_SCOPE_PROCESS;
break;
default:
ret = EINVAL;
}
}
return ret;
}
int
_pthread_attr_getstack(const pthread_attr_t **attr,
void **stackaddr,
size_t *stacksize)
{
if (attr == NULL || *attr == NULL ||
stackaddr == NULL || stacksize == NULL)
return EINVAL;
return __pthread_attr_getstack(*attr, stackaddr, stacksize);
}
int
_pthread_attr_getstackaddr(const pthread_attr_t **attr,
void **stackaddr)
{
if (attr == NULL || *attr == NULL || stackaddr == NULL)
return EINVAL;
return __pthread_attr_getstackaddr(*attr, stackaddr);
}
int
_pthread_attr_getstacksize(const pthread_attr_t **attr,
size_t *stacksize)
{
if (attr == NULL || *attr == NULL || stacksize == NULL)
return EINVAL;
return __pthread_attr_getstacksize(*attr, stacksize);
}
int
_pthread_attr_init(pthread_attr_t **attr)
{
int ret;
pthread_attr_t *res;
if (attr == NULL)
return EINVAL;
res = malloc(sizeof(pthread_attr_t));
if (res == NULL)
return ENOMEM;
ret = __pthread_attr_init(res);
if (ret == 0)
*attr = res;
else
free(res);
return ret;
}
int
_pthread_attr_setdetachstate(pthread_attr_t **attr, int detachstate)
{
if (attr == NULL || *attr == NULL)
return EINVAL;
switch (detachstate) {
case UTHREAD_PTHREAD_CREATE_JOINABLE:
return __pthread_attr_setdetachstate(*attr,
PTHREAD_CREATE_JOINABLE);
case UTHREAD_PTHREAD_CREATE_DETACHED:
return __pthread_attr_setdetachstate(*attr,
PTHREAD_CREATE_DETACHED);
default:
return EINVAL;
}
}
int
_pthread_attr_setguardsize(pthread_attr_t **attr, size_t guardsize)
{
if (attr == NULL || *attr == NULL)
return EINVAL;
return __pthread_attr_setguardsize(*attr, guardsize);
}
int
_pthread_attr_setinheritsched(pthread_attr_t **attr, int inherit)
{
if (attr == NULL || *attr == NULL)
return EINVAL;
switch (inherit) {
case UTHREAD_PTHREAD_EXPLICIT_SCHED:
return __pthread_attr_setinheritsched(*attr,
PTHREAD_EXPLICIT_SCHED);
case UTHREAD_PTHREAD_INHERIT_SCHED:
return __pthread_attr_setinheritsched(*attr,
PTHREAD_INHERIT_SCHED);
default:
return EINVAL;
}
}
int
_pthread_attr_setschedparam(pthread_attr_t **attr,
struct sched_param *sparam)
{
if (attr == NULL || *attr == NULL || sparam == NULL)
return EINVAL;
return __pthread_attr_setschedparam(*attr, sparam);
}
int
_pthread_attr_setschedpolicy(pthread_attr_t **attr,
int policy)
{
if (attr == NULL || *attr == NULL)
return EINVAL;
return __pthread_attr_setschedpolicy(*attr, policy);
}
int
_pthread_attr_setscope(pthread_attr_t **attr,
int scope)
{
if (attr == NULL || *attr == NULL)
return EINVAL;
switch (scope) {
case UTHREAD_PTHREAD_SCOPE_SYSTEM:
return __pthread_attr_setscope(*attr, PTHREAD_SCOPE_SYSTEM);
case UTHREAD_PTHREAD_SCOPE_PROCESS:
return __pthread_attr_setscope(*attr, PTHREAD_SCOPE_PROCESS);
default:
return EINVAL;
}
}
int
_pthread_attr_setstack(pthread_attr_t **attr,
void *stackaddr,
size_t stacksize)
{
if (attr == NULL || *attr == NULL)
return EINVAL;
return __pthread_attr_setstack(*attr, stackaddr, stacksize);
}
int
_pthread_attr_setstackaddr(pthread_attr_t **attr,
void *stackaddr)
{
if (attr == NULL || *attr == NULL)
return EINVAL;
return __pthread_attr_setstackaddr(*attr, stackaddr);
}
int
_pthread_attr_setstacksize(pthread_attr_t **attr,
size_t stacksize)
{
if (attr == NULL || *attr == NULL)
return EINVAL;
return __pthread_attr_setstacksize(*attr, stacksize);
}
int
_pthread_barrier_destroy(pthread_barrier_t **barrier)
{
int ret;
if (barrier == NULL || *barrier == NULL)
return EINVAL;
ret = __pthread_barrier_destroy(*barrier);
if (ret == 0) {
free(*barrier);
*barrier = NULL;
}
return ret;
}
int
_pthread_barrier_init(pthread_barrier_t **barrier,
pthread_barrierattr_t **battr,
unsigned int count)
{
int ret;
pthread_barrier_t *res;
if (barrier == NULL)
return EINVAL;
res = malloc(sizeof(pthread_barrier_t));
if (res == NULL)
return ENOMEM;
ret = __pthread_barrier_init(res, battr != NULL ? *battr : NULL,
count);
if (ret == 0)
*barrier = res;
else
free(res);
return ret;
}
int
_pthread_barrier_wait(pthread_barrier_t **barrier)
{
int ret;
if (barrier == NULL)
return EINVAL;
if (*barrier == NULL) {
ret = allocbarrier(barrier);
if (ret != 0)
return ret;
}
return __pthread_barrier_wait(*barrier);
}
int
_pthread_barrierattr_destroy(pthread_barrierattr_t **battr)
{
int ret;
if (battr == NULL || *battr == NULL)
return EINVAL;
ret = __pthread_barrierattr_destroy(*battr);
if (ret == 0) {
free(*battr);
*battr = NULL;
}
return ret;
}
int
_pthread_barrierattr_getpshared(const pthread_barrierattr_t **battr,
int *pshared)
{
int ret;
int lshared;
if (battr == NULL || *battr == NULL || pshared == NULL)
return EINVAL;
ret = __pthread_barrierattr_getpshared(*battr, &lshared);
if (ret == 0) {
switch (lshared) {
case PTHREAD_PROCESS_PRIVATE:
*pshared = UTHREAD_PTHREAD_PROCESS_PRIVATE;
break;
case PTHREAD_PROCESS_SHARED:
*pshared = UTHREAD_PTHREAD_PROCESS_SHARED;
break;
default:
ret = EINVAL;
}
}
return ret;
}
int
_pthread_barrierattr_init(pthread_barrierattr_t **battr)
{
int ret;
pthread_barrierattr_t *res;
if (battr == NULL)
return EINVAL;
res = malloc(sizeof(pthread_barrierattr_t));
if (res == NULL)
return ENOMEM;
ret = __pthread_barrierattr_init(res);
if (ret == 0)
*battr = res;
else
free(res);
return ret;
}
int
_pthread_barrierattr_setpshared(pthread_barrierattr_t **battr,
int pshared)
{
if (battr == NULL || *battr == NULL)
return EINVAL;
switch (pshared) {
case UTHREAD_PTHREAD_PROCESS_PRIVATE:
return __pthread_barrierattr_setpshared(*battr,
PTHREAD_PROCESS_PRIVATE);
case UTHREAD_PTHREAD_PROCESS_SHARED:
return __pthread_barrierattr_setpshared(*battr,
PTHREAD_PROCESS_SHARED);
default:
return EINVAL;
}
}
int
_pthread_cancel(pthread_t tid)
{
return __pthread_cancel(tid);
}
int
_pthread_cond_broadcast(pthread_cond_t **cond)
{
int ret;
if (cond == NULL)
return EINVAL;
if (*cond == NULL) {
ret = alloccond(cond);
if (ret != 0)
return ret;
}
return __pthread_cond_broadcast(*cond);
}
int
_pthread_cond_destroy(pthread_cond_t **cond)
{
int ret;
if (cond == NULL || *cond == NULL)
return EINVAL;
ret = __pthread_cond_destroy(*cond);
if (ret == 0) {
free(*cond);
*cond = NULL;
}
return ret;
}
int
_pthread_cond_init(pthread_cond_t **cond,
pthread_condattr_t **cattr)
{
int ret;
pthread_cond_t *res;
if (cond == NULL)
return EINVAL;
res = malloc(sizeof(pthread_cond_t));
if (res == NULL)
return ENOMEM;
ret = __pthread_cond_init(res, cattr != NULL ? *cattr : NULL);
if (ret == 0)
*cond = res;
else
free(res);
return ret;
}
int
_pthread_cond_signal(pthread_cond_t **cond)
{
int ret;
if (cond == NULL)
return EINVAL;
if (*cond == NULL) {
ret = alloccond(cond);
if (ret != 0)
return ret;
}
return __pthread_cond_signal(*cond);
}
int
_pthread_cond_timedwait(pthread_cond_t **cond,
pthread_mutex_t **mutex,
const struct timespec *timespec)
{
int ret;
if (cond == NULL || mutex == NULL)
return EINVAL;
if (*cond == NULL) {
ret = alloccond(cond);
if (ret != 0)
return ret;
}
if (*mutex == NULL) {
ret = allocmutex(mutex);
if (ret != 0)
return ret;
}
return __pthread_cond_timedwait(*cond, *mutex, timespec);
}
int
_pthread_cond_wait(pthread_cond_t **cond,
pthread_mutex_t **mutex)
{
int ret;
if (cond == NULL || mutex == NULL)
return EINVAL;
if (*cond == NULL) {
ret = alloccond(cond);
if (ret != 0)
return ret;
}
if (*mutex == NULL) {
ret = allocmutex(mutex);
if (ret != 0)
return ret;
}
return __pthread_cond_wait(*cond, *mutex);
}
int
_pthread_condattr_destroy(pthread_condattr_t **cattr)
{
int ret;
if (cattr == NULL || *cattr == NULL)
return EINVAL;
ret = __pthread_condattr_destroy(*cattr);
if (ret == 0) {
free(*cattr);
*cattr = NULL;
}
return ret;
}
int
_pthread_condattr_getpshared(const pthread_condattr_t **rwattr,
int *pshared)
{
int ret;
int lshared;
if (rwattr == NULL || *rwattr == NULL || pshared == NULL)
return EINVAL;
ret = __pthread_condattr_getpshared(*rwattr, &lshared);
if (ret == 0) {
switch (lshared) {
case PTHREAD_PROCESS_PRIVATE:
*pshared = UTHREAD_PTHREAD_PROCESS_PRIVATE;
break;
case PTHREAD_PROCESS_SHARED:
*pshared = UTHREAD_PTHREAD_PROCESS_SHARED;
break;
default:
ret = EINVAL;
}
}
return ret;
}
int
_pthread_condattr_init(pthread_condattr_t **cattr)
{
pthread_condattr_t *res;
int ret;
if (cattr == NULL)
return EINVAL;
res = malloc(sizeof(pthread_condattr_t));
if (res == NULL)
return ENOMEM;
ret = __pthread_condattr_init(res);
if (ret == 0)
*cattr = res;
else
free(res);
return ret;
}
int
_pthread_condattr_setpshared(pthread_condattr_t **cattr,
int pshared)
{
if (cattr == NULL || *cattr == NULL)
return EINVAL;
switch (pshared) {
case UTHREAD_PTHREAD_PROCESS_PRIVATE:
return __pthread_condattr_setpshared(*cattr,
PTHREAD_PROCESS_PRIVATE);
case UTHREAD_PTHREAD_PROCESS_SHARED:
return __pthread_condattr_setpshared(*cattr,
PTHREAD_PROCESS_SHARED);
default:
return EINVAL;
}
}
int
_pthread_create(pthread_t *tid,
const pthread_attr_t **attr,
void *(*startfunc)(void *),
void *arg)
{
return __pthread_create(tid,
attr != NULL ? *attr : NULL,
startfunc,
arg);
}
int
_pthread_detach(pthread_t tid)
{
return __pthread_detach(tid);
}
int
_pthread_equal(pthread_t tid1, pthread_t tid2)
{
return __pthread_equal(tid1, tid2);
}
void
_pthread_exit(void *retval)
{
__pthread_exit(retval);
}
int
_pthread_getconcurrency(void)
{
return __pthread_getconcurrency();
}
int
_pthread_getcpuclockid(pthread_t tid, clockid_t *clockid)
{
return EINVAL;
}
int
_pthread_getschedparam(pthread_t tid, int *policy, struct sched_param *sparam)
{
if (sparam == NULL || policy == NULL)
return EINVAL;
return __pthread_getschedparam(tid, policy, sparam);
}
void *
_pthread_getspecific(pthread_key_t key)
{
return __pthread_getspecific(key);
}
int
_pthread_join(pthread_t tid, void **treturn)
{
if (treturn == NULL)
return EINVAL;
return __pthread_join(tid, treturn);
}
int
_pthread_key_create(pthread_key_t *key, void (*destructor) (void *))
{
return __pthread_key_create(key, destructor);
}
int
_pthread_key_delete(pthread_key_t key)
{
return __pthread_key_delete(key);
}
int
_pthread_kill(pthread_t tid, int signo)
{
return __pthread_kill(tid, signo);
}
int
_pthread_mutex_destroy(pthread_mutex_t **mutex)
{
int ret;
if (mutex == NULL || *mutex == NULL)
return EINVAL;
ret = __pthread_mutex_destroy(*mutex);
if (ret == 0) {
free(*mutex);
*mutex = NULL;
}
return ret;
}
int
_pthread_mutex_init(pthread_mutex_t **mutex, const pthread_mutexattr_t **mattr)
{
int ret;
pthread_mutex_t *res;
if (mutex == NULL)
return EINVAL;
res = malloc(sizeof(pthread_mutex_t));
if (res == NULL)
return ENOMEM;
ret = __pthread_mutex_init(res, mattr != NULL ? *mattr : NULL);
if (ret == 0)
*mutex = res;
else
free(res);
return ret;
}
int
_pthread_mutex_lock(pthread_mutex_t **mutex)
{
int ret;
if (mutex == NULL)
return EINVAL;
if (*mutex == NULL) {
ret = allocmutex(mutex);
if (ret != 0)
return ret;
}
return __pthread_mutex_lock(*mutex);
}
int
_pthread_mutex_timedlock(pthread_mutex_t **mutex,
const struct timespec *abstime)
{
int ret;
if (mutex == NULL)
return EINVAL;
if (*mutex == NULL) {
ret = allocmutex(mutex);
if (ret != 0)
return ret;
}
return __pthread_mutex_timedlock(*mutex, abstime);
}
int
_pthread_mutex_trylock(pthread_mutex_t **mutex)
{
int ret;
if (mutex == NULL)
return EINVAL;
if (*mutex == NULL) {
ret = allocmutex(mutex);
if (ret != 0)
return ret;
}
return __pthread_mutex_trylock(*mutex);
}
int
_pthread_mutex_unlock(pthread_mutex_t **mutex)
{
if (mutex == NULL || *mutex == NULL)
return EINVAL;
return __pthread_mutex_unlock(*mutex);
}
int
_pthread_mutexattr_destroy(pthread_mutexattr_t **mattr)
{
int ret;
if (mattr == NULL || *mattr == NULL)
return EINVAL;
ret = __pthread_mutexattr_destroy(*mattr);
if (ret == 0) {
free(*mattr);
*mattr = NULL;
}
return ret;
}
int
_pthread_mutexattr_getpshared(const pthread_mutexattr_t **mattr, int *pshared)
{
int ret;
int lshared;
if (mattr == NULL || *mattr == NULL || pshared == NULL)
return EINVAL;
ret = __pthread_mutexattr_getpshared(*mattr, &lshared);
if (ret == 0) {
switch (lshared) {
case PTHREAD_PROCESS_PRIVATE:
*pshared = UTHREAD_PTHREAD_PROCESS_PRIVATE;
break;
case PTHREAD_PROCESS_SHARED:
*pshared = UTHREAD_PTHREAD_PROCESS_SHARED;
break;
default:
ret = EINVAL;
}
}
return ret;
}
int
_pthread_mutexattr_gettype(const pthread_mutexattr_t **mattr, int *type)
{
int ret;
int ltype;
if (mattr == NULL || *mattr == NULL || type == NULL)
return EINVAL;
ret = __pthread_mutexattr_gettype(*mattr, <ype);
if (ret == 0) {
switch (ltype) {
case PTHREAD_MUTEX_ERRORCHECK:
*type = UTHREAD_PTHREAD_MUTEX_ERRORCHECK;
break;
case PTHREAD_MUTEX_RECURSIVE:
*type = UTHREAD_PTHREAD_MUTEX_RECURSIVE;
break;
case PTHREAD_MUTEX_NORMAL:
*type = UTHREAD_PTHREAD_MUTEX_NORMAL;
break;
default:
return EINVAL;
}
}
return ret;
}
int
_pthread_mutexattr_init(pthread_mutexattr_t **mattr)
{
pthread_mutexattr_t *res;
int ret;
if (mattr == NULL)
return EINVAL;
res = malloc(sizeof(pthread_mutexattr_t));
if (res == NULL)
return ENOMEM;
ret = __pthread_mutexattr_init(res);
if (ret == 0)
*mattr = res;
else
free(res);
return ret;
}
int
_pthread_mutexattr_setpshared(pthread_mutexattr_t **mattr,
int pshared)
{
if (mattr == NULL || *mattr == NULL)
return EINVAL;
switch (pshared) {
case UTHREAD_PTHREAD_PROCESS_PRIVATE:
return __pthread_mutexattr_setpshared(*mattr,
PTHREAD_PROCESS_PRIVATE);
case UTHREAD_PTHREAD_PROCESS_SHARED:
return __pthread_mutexattr_setpshared(*mattr,
PTHREAD_PROCESS_SHARED);
default:
return EINVAL;
}
}
int
_pthread_mutexattr_settype(pthread_mutexattr_t **mattr, int type)
{
if (mattr == NULL || *mattr == NULL)
return EINVAL;
switch (type) {
case UTHREAD_PTHREAD_MUTEX_ERRORCHECK:
return __pthread_mutexattr_settype(*mattr,
PTHREAD_MUTEX_ERRORCHECK);
case UTHREAD_PTHREAD_MUTEX_RECURSIVE:
return __pthread_mutexattr_settype(*mattr,
PTHREAD_MUTEX_ERRORCHECK);
case UTHREAD_PTHREAD_MUTEX_NORMAL:
return __pthread_mutexattr_settype(*mattr,
PTHREAD_MUTEX_NORMAL);
default:
return EINVAL;
}
}
int
_pthread_once(uthread_pthread_once_t *once_control,
void (*init_routine) (void))
{
if (once_control->state == UTHREAD_PTHREAD_NEEDS_INIT) {
_pthread_mutex_lock(&(once_control->mutex));
if (once_control->state == UTHREAD_PTHREAD_NEEDS_INIT) {
init_routine();
once_control->state = UTHREAD_PTHREAD_DONE_INIT;
}
_pthread_mutex_unlock(&(once_control->mutex));
}
return (0);
}
int
_pthread_rwlock_destroy(pthread_rwlock_t **rwlock)
{
int ret;
if (rwlock == NULL || *rwlock == NULL)
return EINVAL;
ret = __pthread_rwlock_destroy(*rwlock);
if (ret == 0) {
free(*rwlock);
*rwlock = NULL;
}
return ret;
}
int
_pthread_rwlock_init(pthread_rwlock_t **rwlock,
const pthread_rwlockattr_t **rwlockattr)
{
pthread_rwlock_t *res;
int ret;
if (rwlock == NULL)
return EINVAL;
res = malloc(sizeof(pthread_rwlock_t));
if (res == NULL)
return ENOMEM;
ret = __pthread_rwlock_init(res,
rwlockattr != NULL ? *rwlockattr : NULL);
if (ret == 0)
*rwlock = res;
else
free(res);
return ret;
}
int
_pthread_rwlock_rdlock(pthread_rwlock_t **rwlock)
{
int ret;
if (rwlock == NULL)
return EINVAL;
if (*rwlock == NULL) {
ret = allocrwlock(rwlock);
if (ret != 0)
return ret;
}
return __pthread_rwlock_rdlock(*rwlock);
}
int
_pthread_rwlock_timedrdlock(pthread_rwlock_t **rwlock,
const struct timespec *abstime)
{
int ret;
if (rwlock == NULL)
return EINVAL;
if (*rwlock == NULL) {
ret = allocrwlock(rwlock);
if (ret != 0)
return ret;
}
return __pthread_rwlock_timedrdlock(*rwlock, abstime);
}
int
_pthread_rwlock_timedwrlock(pthread_rwlock_t **rwlock,
const struct timespec *abstime)
{
int ret;
if (rwlock == NULL)
return EINVAL;
if (*rwlock == NULL) {
ret = allocrwlock(rwlock);
if (ret != 0)
return ret;
}
return __pthread_rwlock_timedwrlock(*rwlock, abstime);
}
int
_pthread_rwlock_tryrdlock(pthread_rwlock_t **rwlock)
{
int ret;
if (rwlock == NULL)
return EINVAL;
if (*rwlock == NULL) {
ret = allocrwlock(rwlock);
if (ret != 0)
return ret;
}
return __pthread_rwlock_tryrdlock(*rwlock);
}
int
_pthread_rwlock_trywrlock(pthread_rwlock_t **rwlock)
{
int ret;
if (rwlock == NULL)
return EINVAL;
if (*rwlock == NULL) {
ret = allocrwlock(rwlock);
if (ret != 0)
return ret;
}
return __pthread_rwlock_trywrlock(*rwlock);
}
int
_pthread_rwlock_unlock(pthread_rwlock_t **rwlock)
{
if (rwlock == NULL || *rwlock == NULL)
return EINVAL;
return __pthread_rwlock_unlock(*rwlock);
}
int
_pthread_rwlock_wrlock(pthread_rwlock_t **rwlock)
{
int ret;
if (rwlock == NULL)
return EINVAL;
if (*rwlock == NULL) {
ret = allocrwlock(rwlock);
if (ret != 0)
return ret;
}
return __pthread_rwlock_wrlock(*rwlock);
}
int
_pthread_rwlockattr_destroy(pthread_rwlockattr_t **rwattr)
{
int ret;
if (rwattr == NULL || *rwattr == NULL)
return EINVAL;
ret = __pthread_rwlockattr_destroy(*rwattr);
if (ret == 0) {
free(*rwattr);
*rwattr = NULL;
}
return ret;
}
int
_pthread_rwlockattr_getpshared(const pthread_rwlockattr_t **rwattr,
int *pshared)
{
int ret;
int lshared;
if (rwattr == NULL || *rwattr == NULL || pshared == NULL)
return EINVAL;
ret = __pthread_rwlockattr_getpshared(*rwattr, &lshared);
if (ret == 0) {
switch (lshared) {
case PTHREAD_PROCESS_PRIVATE:
*pshared = UTHREAD_PTHREAD_PROCESS_PRIVATE;
break;
case PTHREAD_PROCESS_SHARED:
*pshared = UTHREAD_PTHREAD_PROCESS_SHARED;
break;
default:
ret = EINVAL;
}
}
return ret;
}
int
_pthread_rwlockattr_init(pthread_rwlockattr_t **rwattr)
{
pthread_rwlockattr_t *res;
int ret;
if (rwattr == NULL)
return EINVAL;
res = malloc(sizeof(pthread_rwlockattr_t));
if (res == NULL)
return ENOMEM;
ret = __pthread_rwlockattr_init(res);
if (ret == 0)
*rwattr = res;
else
free(res);
return ret;
}
int
_pthread_rwlockattr_setpshared(pthread_rwlockattr_t **rwattr,
int pshared)
{
if (rwattr == NULL || *rwattr == NULL)
return EINVAL;
switch (pshared) {
case UTHREAD_PTHREAD_PROCESS_PRIVATE:
return __pthread_rwlockattr_setpshared(*rwattr,
PTHREAD_PROCESS_PRIVATE);
case UTHREAD_PTHREAD_PROCESS_SHARED:
return __pthread_rwlockattr_setpshared(*rwattr,
PTHREAD_PROCESS_SHARED);
default:
return EINVAL;
}
}
pthread_t
_pthread_self(void)
{
return __pthread_self();
}
int
_pthread_setcancelstate(int newstate, int *oldstate)
{
int ret;
int lold;
switch (newstate) {
case UTHREAD_PTHREAD_CANCEL_ENABLE:
ret = __pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, &lold);
break;
case UTHREAD_PTHREAD_CANCEL_DISABLE:
ret = __pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &lold);
break;
default:
ret = EINVAL;
}
if (ret == 0 && oldstate != NULL) {
switch (lold) {
case PTHREAD_CANCEL_ENABLE:
*oldstate = UTHREAD_PTHREAD_CANCEL_ENABLE;
break;
case PTHREAD_CANCEL_DISABLE:
*oldstate = UTHREAD_PTHREAD_CANCEL_DISABLE;
break;
default:
ret = EINVAL;
}
}
return ret;
}
int
_pthread_setcanceltype(int newtype, int *oldtype)
{
int ret;
int lold;
switch (newtype) {
case UTHREAD_PTHREAD_CANCEL_DEFERRED:
ret = __pthread_setcanceltype(PTHREAD_CANCEL_DEFERRED, &lold);
break;
case UTHREAD_PTHREAD_CANCEL_ASYNCHRONOUS:
ret = __pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, &lold);
break;
default:
ret = EINVAL;
}
if (ret == 0 && oldtype != NULL) {
switch (lold) {
case PTHREAD_CANCEL_DEFERRED:
*oldtype = UTHREAD_PTHREAD_CANCEL_DEFERRED;
break;
case PTHREAD_CANCEL_ASYNCHRONOUS:
*oldtype = UTHREAD_PTHREAD_CANCEL_ASYNCHRONOUS;
break;
default:
ret = EINVAL;
}
}
return ret;
}
int
_pthread_setconcurrency(int level)
{
return __pthread_setconcurrency(level);
}
int
_pthread_setschedparam(pthread_t tid, int policy,
const struct sched_param *sparam)
{
return __pthread_setschedparam(tid, policy, sparam);
}
int
_pthread_setspecific(pthread_key_t key, const void *value)
{
return __pthread_setspecific(key, value);
}
int
_pthread_sigmask(int how, const sigset_t *set, sigset_t *oset)
{
return __pthread_sigmask(how, set, oset);
}
void
_pthread_testcancel(void)
{
__pthread_testcancel();
}
#ifdef LINUXTHREADS_WRAP_API
#include "internals.h"
void linuxthreads__pthread_cleanup_pop(struct _pthread_cleanup_buffer *buf,
int execute);
void linuxthreads__pthread_cleanup_push(struct _pthread_cleanup_buffer *buf,
void (*)(void *),
void *);
void wrap_pthread_cleanup_pop(int) __asm__("_pthread_cleanup_pop");
void wrap_pthread_cleanup_push(void (*)(void *), void *) __asm__("_pthread_cleanup_push");
#undef pthread_cleanup_pop
#undef pthread_cleanup_push
extern int pthread_cleanup_pop(int) __attribute__ ((weak, alias("_pthread_cleanup_pop")));
extern int pthread_cleanup_push(void (*)(void *), void *) __attribute__ ((weak, alias("_pthread_cleanup_push")));
struct wrap_pthread_cleanup_buffer {
struct _pthread_cleanup_buffer _buf;
void (*func)(void *);
void *arg;
void *nextfree;
};
static pthread_mutex_t cleanup_mutex = PTHREAD_MUTEX_INITIALIZER;
static pthread_key_t cleanup_key = (pthread_key_t) -1;
static void free_cleanup_buffers(void *arg);
static struct wrap_pthread_cleanup_buffer *
alloc_cleanup_buffer(void)
{
struct wrap_pthread_cleanup_buffer *buf;
if (cleanup_key == (pthread_key_t) -1) {
__pthread_mutex_lock(&cleanup_mutex);
if (cleanup_key == (pthread_key_t) -1) {
if (__pthread_key_create(&cleanup_key,
free_cleanup_buffers) < 0) {
__pthread_mutex_unlock(&cleanup_mutex);
abort();
}
}
__pthread_mutex_unlock(&cleanup_mutex);
}
buf = __pthread_getspecific(cleanup_key);
if (buf == NULL) {
buf = (struct wrap_pthread_cleanup_buffer *)
malloc(sizeof(struct wrap_pthread_cleanup_buffer));
} else {
__pthread_setspecific(cleanup_key, buf->nextfree);
}
if (buf != NULL) {
buf->nextfree = NULL;
}
return buf;
}
static void
stash_cleanup_buffer(struct wrap_pthread_cleanup_buffer *buf)
{
buf->nextfree = __pthread_getspecific(cleanup_key);
__pthread_setspecific(cleanup_key, buf);
}
static void
free_cleanup_buffers(void *arg)
{
struct wrap_pthread_cleanup_buffer *buf;
struct wrap_pthread_cleanup_buffer *nbuf;
buf = (struct wrap_pthread_cleanup_buffer *) arg;
while (buf != NULL) {
nbuf = buf->nextfree;
free(buf);
buf = nbuf;
}
}
static void
wrap_cleanup(void *arg)
{
struct wrap_pthread_cleanup_buffer *buf;
buf = (struct wrap_pthread_cleanup_buffer *) arg;
buf->func(buf->arg);
/* Cannot free buffer yet ==> stash it on a thread specific freelist */
stash_cleanup_buffer(buf);
}
void
wrap_pthread_cleanup_pop(int execute)
{
pthread_descr self;
struct _pthread_cleanup_buffer *buf;
self = thread_self();
buf = THREAD_GETMEM(self, p_cleanup);
linuxthreads__pthread_cleanup_pop(buf, execute);
}
void
wrap_pthread_cleanup_push(void (*func)(void *),
void *arg)
{
struct wrap_pthread_cleanup_buffer *buf;
buf = alloc_cleanup_buffer();
buf->func = func;
buf->arg = arg;
linuxthreads__pthread_cleanup_push(&buf->_buf,
wrap_cleanup,
buf);
}
#endif