File: [local] / src / lib / librthread / Attic / rthread_libc.c (download)
Revision 1.6, Wed Jan 23 02:20:24 2008 UTC (16 years, 4 months ago) by kurt
Branch: MAIN
CVS Tags: OPENBSD_4_3_BASE, OPENBSD_4_3 Changes since 1.5: +18 -1 lines
- add missing libc locking functions for _thread_atexit_lock() and
_thread_atexit_unlock(). okay tedu@
|
/* $OpenBSD: rthread_libc.c,v 1.6 2008/01/23 02:20:24 kurt Exp $ */
/* $snafu: libc_tag.c,v 1.4 2004/11/30 07:00:06 marc Exp $ */
/* PUBLIC DOMAIN: No Rights Reserved. Marco S Hyman <marc@snafu.org> */
#define _POSIX_THREADS
#include <sys/time.h>
#include <machine/spinlock.h>
#include <pthread.h>
#include <stdlib.h>
#include <string.h>
#include "thread_private.h" /* in libc/include */
#include "rthread.h"
/*
* A thread tag is a pointer to a structure of this type. An opaque
* tag is used to decouple libc from the thread library.
*/
struct _thread_tag {
pthread_mutex_t m; /* the tag's mutex */
pthread_key_t k; /* a key for private data */
};
/*
* local mutex to protect against tag creation races.
*/
static pthread_mutex_t _thread_tag_mutex = PTHREAD_MUTEX_INITIALIZER;
/*
* Initialize a thread tag structure once. This function is called
* if the tag is null. Allocation and initialization are controlled
* by a mutex. If the tag is not null when the mutex is obtained
* the caller lost a race -- some other thread initialized the tag.
* This function will never return NULL.
*/
static void
_thread_tag_init(void **tag)
{
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, free);
*tag = tt;
}
}
result |= pthread_mutex_unlock(&_thread_tag_mutex);
}
if (result != 0)
_rthread_debug(1, "tag init failure");
}
/*
* lock the mutex associated with the given tag
*/
void
_thread_tag_lock(void **tag)
{
struct _thread_tag *tt;
if (__isthreaded) {
if (*tag == NULL)
_thread_tag_init(tag);
tt = *tag;
if (pthread_mutex_lock(&tt->m) != 0)
_rthread_debug(1, "tag mutex lock failure");
}
}
/*
* unlock the mutex associated with the given tag
*/
void
_thread_tag_unlock(void **tag)
{
struct _thread_tag *tt;
if (__isthreaded) {
if (*tag == NULL)
_thread_tag_init(tag);
tt = *tag;
if (pthread_mutex_unlock(&tt->m) != 0)
_rthread_debug(1, "tag mutex unlock failure");
}
}
/*
* return the thread specific data for the given tag. If there
* is no data for this thread initialize it from 'storage'.
* On any error return 'err'.
*/
void *
_thread_tag_storage(void **tag, void *storage, size_t sz, void *err)
{
struct _thread_tag *tt;
void *ret;
if (*tag == NULL)
_thread_tag_init(tag);
tt = *tag;
ret = pthread_getspecific(tt->k);
if (ret == NULL) {
ret = malloc(sz);
if (ret == NULL)
ret = err;
else {
if (pthread_setspecific(tt->k, ret) == 0)
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");
}
/*
* the malloc lock
*/
static _spinlock_lock_t malloc_lock = _SPINLOCK_UNLOCKED;
void
_thread_malloc_lock(void)
{
_spinlock(&malloc_lock);
}
void
_thread_malloc_unlock(void)
{
_spinunlock(&malloc_lock);
}
void
_thread_malloc_init(void)
{
}
/*
* atexit lock
*/
static _spinlock_lock_t atexit_lock = _SPINLOCK_UNLOCKED;
void
_thread_atexit_lock(void)
{
_spinlock(&atexit_lock);
}
void
_thread_atexit_unlock(void)
{
_spinunlock(&atexit_lock);
}
/*
* arc4random lock
*/
static _spinlock_lock_t arc4_lock = _SPINLOCK_UNLOCKED;
void
_thread_arc4_lock(void)
{
_spinlock(&arc4_lock);
}
void
_thread_arc4_unlock(void)
{
_spinunlock(&arc4_lock);
}
#if 0
/*
* miscellaneous libc exported symbols we want to override
*/
int
close(int fd)
{
int rv;
pthread_testcancel();
rv = _thread_sys_close(fd);
pthread_testcancel();
return (rv);
}
#if 0
/* libc calls open */
int
creat(const char *path, mode_t mode)
{
}
#endif
#if 0
int
fcntl(int fd, int cmd, ...)
{
va_list ap;
int rv;
pthread_testcancel();
va_start(ap, cmd);
rv = _thread_sys_fcntl(fd, cmd, va_arg(cmd, void *));
va_end(ap);
pthread_testcancel();
return (rv);
}
#endif
int
fsync(int fd)
{
int rv;
pthread_testcancel();
rv = _thread_sys_fsync(fd);
pthread_testcancel();
return (rv);
}
int
msync(void *addr, size_t len, int flags)
{
int rv;
pthread_testcancel();
rv = _thread_sys_msync(addr, len, flags);
pthread_testcancel();
return (rv);
}
int
nanosleep(const struct timespec *rqtp, struct timespec *rmtp)
{
int rv;
pthread_testcancel();
rv = _thread_sys_nanosleep(rqtp, rmtp);
pthread_testcancel();
return (rv);
}
#if 0
int
open(const char *path, int flags, ...)
{
va_list ap;
int rv;
pthread_testcancel();
va_start(ap, cmd);
rv = _thread_sys_open(fd, cmd, va_arg(cmd, mode_t));
va_end(ap);
pthread_testcancel();
return (rv);
}
#endif
#if 0
int
pause(void)
{
}
#endif
ssize_t
read(int fd, void *buf, size_t nbytes)
{
ssize_t rv;
pthread_testcancel();
rv = read(fd, buf, nbytes);
pthread_testcancel();
return (rv);
}
#if 0
int
sigwaitinfo()
{
}
#endif
int
sigsuspend(const sigset_t *sigmask)
{
int rv;
pthread_testcancel();
rv = sigsuspend(sigmask);
pthread_testcancel();
return (rv);
}
#if 0
/* libc sleep(3) calls nanosleep(2), so we'll catch it there */
unsigned int
sleep(unsigned int seconds)
{
}
#endif
#if 0
int system(const char *string)
{
}
#endif
#if 0
int
tcdrain(int fd)
{
}
#endif
#if 0
/* wait and waitpid will be handled by libc calling wait4 */
pid_t
wait(int *status)
{
}
pid_t
waitpid(pid_t wpid, int *status, int options)
{
}
#endif
pid_t
wait4(pid_t wpid, int *status, int options, struct rusage *rusage)
{
pid_t rv;
pthread_testcancel();
rv = _thread_sys_wait4(wpid, status, options, rusage);
pthread_testcancel();
return (rv);
}
ssize_t
write(int fd, const void *buf, size_t nbytes)
{
ssize_t rv;
pthread_testcancel();
rv = _thread_sys_write(fd, buf, nbytes);
pthread_testcancel();
return (rv);
}
#endif