#include <pthread.h>
#include <stdlib.h>
#include <string.h>
#include "rthread.h"
#include "rthread_cb.h"
struct _thread_tag {
pthread_mutex_t m;
pthread_key_t k;
};
static pthread_mutex_t _thread_tag_mutex = PTHREAD_MUTEX_INITIALIZER;
static void
_thread_tag_init(void **tag, void (*dt)(void *))
{
struct _thread_tag *tt;
int result;
result = pthread_mutex_lock(&_thread_tag_mutex);
if (result == 0) {
if (*tag == NULL) {
tt = malloc(sizeof *tt);
if (tt != NULL) {
result = pthread_mutex_init(&tt->m, NULL);
result |= pthread_key_create(&tt->k, dt ? dt :
free);
*tag = tt;
}
}
result |= pthread_mutex_unlock(&_thread_tag_mutex);
}
if (result != 0)
_rthread_debug(1, "tag init failure");
}
void
_thread_tag_lock(void **tag)
{
struct _thread_tag *tt;
if (__isthreaded) {
if (*tag == NULL)
_thread_tag_init(tag, NULL);
tt = *tag;
if (pthread_mutex_lock(&tt->m) != 0)
_rthread_debug(1, "tag mutex lock failure");
}
}
void
_thread_tag_unlock(void **tag)
{
struct _thread_tag *tt;
if (__isthreaded) {
if (*tag == NULL)
_thread_tag_init(tag, NULL);
tt = *tag;
if (pthread_mutex_unlock(&tt->m) != 0)
_rthread_debug(1, "tag mutex unlock failure");
}
}
void *
_thread_tag_storage(void **tag, void *storage, size_t sz, void (*dt)(void *),
void *err)
{
struct _thread_tag *tt;
void *ret;
if (*tag == NULL)
_thread_tag_init(tag, dt);
tt = *tag;
ret = pthread_getspecific(tt->k);
if (ret == NULL) {
ret = calloc(1, sz);
if (ret == NULL)
ret = err;
else {
if (pthread_setspecific(tt->k, ret) == 0) {
if (pthread_self() == &_initial_thread)
memcpy(ret, storage, sz);
} else {
free(ret);
ret = err;
}
}
}
return ret;
}
void
_thread_mutex_lock(void **mutex)
{
pthread_mutex_t *pmutex = (pthread_mutex_t *)mutex;
if (pthread_mutex_lock(pmutex) != 0)
_rthread_debug(1, "mutex lock failure");
}
void
_thread_mutex_unlock(void **mutex)
{
pthread_mutex_t *pmutex = (pthread_mutex_t *)mutex;
if (pthread_mutex_unlock(pmutex) != 0)
_rthread_debug(1, "mutex unlock failure");
}
void
_thread_mutex_destroy(void **mutex)
{
pthread_mutex_t *pmutex = (pthread_mutex_t *)mutex;
if (pthread_mutex_destroy(pmutex) != 0)
_rthread_debug(1, "mutex destroy failure");
}
#ifndef FUTEX
#define MALLOC_LOCK_INITIALIZER(n) { \
_SPINLOCK_UNLOCKED, \
TAILQ_HEAD_INITIALIZER(malloc_lock[n].lockers), \
PTHREAD_MUTEX_DEFAULT, \
NULL, \
0, \
-1 }
#else
#define MALLOC_LOCK_INITIALIZER(n) { \
_SPINLOCK_UNLOCKED, \
PTHREAD_MUTEX_DEFAULT, \
NULL, \
0, \
-1 }
#endif
static struct pthread_mutex malloc_lock[_MALLOC_MUTEXES] = {
MALLOC_LOCK_INITIALIZER(0),
MALLOC_LOCK_INITIALIZER(1),
MALLOC_LOCK_INITIALIZER(2),
MALLOC_LOCK_INITIALIZER(3),
MALLOC_LOCK_INITIALIZER(4),
MALLOC_LOCK_INITIALIZER(5),
MALLOC_LOCK_INITIALIZER(6),
MALLOC_LOCK_INITIALIZER(7),
MALLOC_LOCK_INITIALIZER(8),
MALLOC_LOCK_INITIALIZER(9),
MALLOC_LOCK_INITIALIZER(10),
MALLOC_LOCK_INITIALIZER(11),
MALLOC_LOCK_INITIALIZER(12),
MALLOC_LOCK_INITIALIZER(13),
MALLOC_LOCK_INITIALIZER(14),
MALLOC_LOCK_INITIALIZER(15),
MALLOC_LOCK_INITIALIZER(16),
MALLOC_LOCK_INITIALIZER(17),
MALLOC_LOCK_INITIALIZER(18),
MALLOC_LOCK_INITIALIZER(19),
MALLOC_LOCK_INITIALIZER(20),
MALLOC_LOCK_INITIALIZER(21),
MALLOC_LOCK_INITIALIZER(22),
MALLOC_LOCK_INITIALIZER(23),
MALLOC_LOCK_INITIALIZER(24),
MALLOC_LOCK_INITIALIZER(25),
MALLOC_LOCK_INITIALIZER(26),
MALLOC_LOCK_INITIALIZER(27),
MALLOC_LOCK_INITIALIZER(28),
MALLOC_LOCK_INITIALIZER(29),
MALLOC_LOCK_INITIALIZER(30),
MALLOC_LOCK_INITIALIZER(31)
};
static pthread_mutex_t malloc_mutex[_MALLOC_MUTEXES] = {
&malloc_lock[0],
&malloc_lock[1],
&malloc_lock[2],
&malloc_lock[3],
&malloc_lock[4],
&malloc_lock[5],
&malloc_lock[6],
&malloc_lock[7],
&malloc_lock[8],
&malloc_lock[9],
&malloc_lock[10],
&malloc_lock[11],
&malloc_lock[12],
&malloc_lock[13],
&malloc_lock[14],
&malloc_lock[15],
&malloc_lock[16],
&malloc_lock[17],
&malloc_lock[18],
&malloc_lock[19],
&malloc_lock[20],
&malloc_lock[21],
&malloc_lock[22],
&malloc_lock[23],
&malloc_lock[24],
&malloc_lock[25],
&malloc_lock[26],
&malloc_lock[27],
&malloc_lock[28],
&malloc_lock[29],
&malloc_lock[30],
&malloc_lock[31]
};
void
_thread_malloc_lock(int i)
{
pthread_mutex_lock(&malloc_mutex[i]);
}
void
_thread_malloc_unlock(int i)
{
pthread_mutex_unlock(&malloc_mutex[i]);
}
static void
_thread_malloc_reinit(void)
{
int i;
for (i = 0; i < _MALLOC_MUTEXES; i++) {
malloc_lock[i].lock = _SPINLOCK_UNLOCKED;
#ifndef FUTEX
TAILQ_INIT(&malloc_lock[i].lockers);
#endif
malloc_lock[i].owner = NULL;
malloc_lock[i].count = 0;
}
}
static struct __cmtx atexit_lock = __CMTX_INITIALIZER();
void
_thread_atexit_lock(void)
{
__cmtx_enter(&atexit_lock);
}
void
_thread_atexit_unlock(void)
{
__cmtx_leave(&atexit_lock);
}
static struct __cmtx atfork_lock = __CMTX_INITIALIZER();
void
_thread_atfork_lock(void)
{
__cmtx_enter(&atfork_lock);
}
void
_thread_atfork_unlock(void)
{
__cmtx_leave(&atfork_lock);
}
static struct __cmtx arc4_lock = __CMTX_INITIALIZER();
void
_thread_arc4_lock(void)
{
__cmtx_enter(&arc4_lock);
}
void
_thread_arc4_unlock(void)
{
__cmtx_leave(&arc4_lock);
}
pid_t
_thread_dofork(pid_t (*sys_fork)(void))
{
int i;
pid_t newid;
_thread_atexit_lock();
for (i = 0; i < _MALLOC_MUTEXES; i++)
_thread_malloc_lock(i);
_thread_arc4_lock();
newid = sys_fork();
_thread_arc4_unlock();
if (newid == 0)
_thread_malloc_reinit();
else
for (i = 0; i < _MALLOC_MUTEXES; i++)
_thread_malloc_unlock(i);
_thread_atexit_unlock();
return newid;
}