diff options
author | David Leonard <d@cvs.openbsd.org> | 2000-01-06 07:47:10 +0000 |
---|---|---|
committer | David Leonard <d@cvs.openbsd.org> | 2000-01-06 07:47:10 +0000 |
commit | 0336fa3e2a09f916f18448ea7e1e7746b23409ec (patch) | |
tree | 490c5775934fd5fb0d41d7fa831aaf5feb3c7467 /lib/libc | |
parent | 465358cdc102ac7b0791790eb5ff8decc50e7025 (diff) |
rewrite to use the helpers in the thread/ directory and to define weak alias macros
Diffstat (limited to 'lib/libc')
-rw-r--r-- | lib/libc/include/thread_private.h | 226 |
1 files changed, 91 insertions, 135 deletions
diff --git a/lib/libc/include/thread_private.h b/lib/libc/include/thread_private.h index 0027468269b..b2677fad0e0 100644 --- a/lib/libc/include/thread_private.h +++ b/lib/libc/include/thread_private.h @@ -1,179 +1,135 @@ -/* - * - * Support for thread-safety in libc and libc_r common code using macros - * to declare thread-safe data structures. - * - * $OpenBSD: thread_private.h,v 1.2 1999/01/06 05:19:32 d Exp $ - */ +/* $OpenBSD: thread_private.h,v 1.3 2000/01/06 07:47:09 d Exp $ */ #ifndef _THREAD_PRIVATE_H_ #define _THREAD_PRIVATE_H_ -/* - * Parts of this file are - * Copyright (c) 1998 John Birrell <jb@cimlogic.com.au>. - * All rights reserved. - * - * $Id: thread_private.h,v 1.2 1999/01/06 05:19:32 d Exp $ - * $OpenBSD: thread_private.h,v 1.2 1999/01/06 05:19:32 d Exp $ - */ +#include <pthread.h> /* - * This global flag is non-zero when a process has created one - * or more threads. It is used to avoid calling locking functions - * when they are not required. In libc, this is always assumed - * to be zero. + * This variable is initally 0 when there is exactly one thread. + * It should never decrease. */ - -extern volatile int __isthreaded; - -#ifdef _THREAD_SAFE - -#include <pthread.h> -#include "pthread_private.h" +extern int __isthreaded; /* - * File lock contention is difficult to diagnose without knowing - * where locks were set. Allow a debug library to be built which - * records the source file and line number of each lock call. + * Weak symbols are used in libc so that the thread library can + * efficiently wrap libc functions. + * + * Use WEAK_NAME(n) to get a libc-private name for n (_weak_n), + * WEAK_ALIAS(n) to generate the weak symbol n pointing to _weak_n, + * WEAK_PROTOTYPE(n) to generate a prototype for _weak_n (based on n). + * + * If the symbol _NO_WEAK_ALIASES is defined, then symbols will be */ -#ifdef _FLOCK_DEBUG -#define _FLOCKFILE(x) _flockfile_debug(x, __FILE__, __LINE__) + +#ifdef _NO_WEAK_ALIASES +#defined _THREAD_SAFE +#define WEAK_NAME(name) __CONCAT(_weak,name) +#else +#define WEAK_NAME(name) name +#endif +#define WEAK_ALIAS(name) /* unavailable */ +#define WEAK_PROTOTYPE(name) /* unnecessary */ +#else /* !_NO_WEAK_AILASES */ +#define WEAK_NAME(name) __CONCAT(_weak_,name) +#define WEAK_ALIAS(name) __weak_alias(name, WEAK_NAME(name)) +#ifdef __GNUC__ +#define WEAK_PROTOTYPE(name) __typeof__(name) WEAK_NAME(name) #else -#define _FLOCKFILE(x) flockfile(x) +#define WEAK_PROTOTYPE(name) /* typeof() only in gcc */ #endif +#endif /* !_NO_WEAK_ALIASES */ /* * These macros help in making persistent storage thread-specific. * Libc makes extensive use of private static data structures * that hold state across function invocation, and these macros - * are no-ops when _THREAD_SAFE is not defined. - * In a thread-safe library, the static variables are used only for - * initialising the per-thread instances of the state variables. + * are no-ops when running single-threaded. + * + * Linking against the user-thread library causes these macros to + * allocate storage on a per-thread basis. */ + +#define __THREAD_MUTEX_NAME(name) __CONCAT(_libc_storage_mutex_,name) +#define __THREAD_KEY_NAME(name) __CONCAT(_libc_storage_key_,name) -/* - * Give names to the private variables used to hold per-thread - * data structures. - */ -#ifdef __STDC__ -#define __THREAD_MUTEXP_NAME(name) _thread_mutexp_inst__ ## name -#define __THREAD_MUTEX_NAME(name) _thread_mutex_inst__ ## name -#define __THREAD_KEY_NAME(name) _thread_key_inst__ ## name -#else -#define __THREAD_MUTEXP_NAME(name) _thread_mutexp_inst__/**/name -#define __THREAD_MUTEX_NAME(name) _thread_mutex_inst__/**/name -#define __THREAD_KEY_NAME(name) _thread_key_inst__/**/name -#endif +struct _thread_private_key_struct { + pthread_once_t once; + void (*cleanfn)__P((void *)); + pthread_key_t key; +}; -/* - * Mutex declare, lock and unlock macros. - */ +void _libc_private_storage_lock(pthread_mutex_t *); +void _libc_private_storage_unlock(pthread_mutex_t *); +void * _libc_private_storage(volatile struct _thread_private_key_struct *, + void *, size_t, void *); + +/* Declare a module mutex. */ #define _THREAD_PRIVATE_MUTEX(name) \ - static struct pthread_mutex __THREAD_MUTEXP_NAME(name) = \ - PTHREAD_MUTEX_STATIC_INITIALIZER; \ static pthread_mutex_t __THREAD_MUTEX_NAME(name) = \ - &__THREAD_MUTEXP_NAME(name); + PTHREAD_MUTEX_INITIALIZER +/* Lock a module mutex against use by any other threads. */ #define _THREAD_PRIVATE_MUTEX_LOCK(name) \ - pthread_mutex_lock(&__THREAD_MUTEX_NAME(name)) + _libc_private_storage_lock(&__THREAD_MUTEX_NAME(name)) +/* Unlock a module mutex. */ #define _THREAD_PRIVATE_MUTEX_UNLOCK(name) \ - pthread_mutex_unlock(&__THREAD_MUTEX_NAME(name)) + _libc_private_storage_unlock(&__THREAD_MUTEX_NAME(name)) -/* - * A mutexed data structure used to hold the persistent state's key. - */ -struct _thread_private_key_struct { - struct pthread_mutex lockd; - pthread_mutex_t lock; - int init; - pthread_key_t key; -}; - -/* - * Declaration of a per-thread state key. - */ +/* Declare a thread-private storage key. */ #define _THREAD_PRIVATE_KEY(name) \ static volatile struct _thread_private_key_struct \ __THREAD_KEY_NAME(name) = { \ - PTHREAD_MUTEX_STATIC_INITIALIZER, \ - &__THREAD_KEY_NAME(name).lockd, \ + PTHREAD_ONCE_INIT, \ 0 \ - }; + } /* - * Initialisation of storage space for a per-thread state variable. - * A pointer to a per-thread *copy* of the _initv parameter is returned. - * It calls malloc the first time and the space is automatically free'd - * when the thread dies. If you need something a bit more complicated - * than free() you will need to roll-your-own. + * In threaded mode, return a pointer to thread-private memory of + * the same size as, and (initially) with the same contents as 'storage'. If + * an error occurs, the 'error' parameter is returned. + * In single-threaded mode, no storage is allocated. Instead, a pointer + * to storage is always returned. + * The 'cleanfn' function of the key structure is called to free the storage. + * If 'cleanfn' is NULL, then free() is used. This hook can be useful for + * getting rid of memory leaks. */ -#define _THREAD_PRIVATE(keyname, _initv, _errv) \ - ({ \ - struct _thread_private_key_struct * __k = \ - &__THREAD_KEY_NAME(keyname); \ - void* __p; \ - extern void free __P((void*)); \ - extern void* malloc __P((size_t)); \ - \ - if (!__isthreaded) { \ - /* non-threaded behaviour */ \ - __p = &(_initv); \ - goto _ok; \ - } \ - \ - /* create key for first thread */ \ - pthread_mutex_lock(&__k->lock); \ - if (__k->init == 0) { \ - if (pthread_key_create(&__k->key, free)) { \ - pthread_mutex_unlock(&__k->lock); \ - goto _err; \ - } \ - __k->init = 1; \ - } \ - pthread_mutex_unlock(&__k->lock); \ - \ - if ((__p = pthread_getspecific(__k->key)) == NULL) { \ - /* alloc space on 1st call in this thread */ \ - if ((__p = malloc(sizeof(_initv))) == NULL) \ - goto _err; \ - if (pthread_setspecific(__k->key, __p) != 0) { \ - free(__p); \ - goto _err; \ - } \ - /* initialise with _initv */ \ - memcpy(__p, &_initv, sizeof(_initv)); \ - } \ - goto _ok; \ - _err: \ - __p = (_errv); \ - _ok: \ - __p; \ - }) +#define _THREAD_PRIVATE(keyname, storage, error) \ + _libc_private_storage(&__THREAD_KEY_NAME(keyname), \ + &(storage), sizeof (storage), error) /* * Macros for locking and unlocking FILEs. These test if the * process is threaded to avoid locking when not required. */ -#define FLOCKFILE(fp) if (__isthreaded) _FLOCKFILE(fp) -#define FUNLOCKFILE(fp) if (__isthreaded) funlockfile(fp) - -#else /* !_THREAD_SAFE */ +#ifdef _FLOCK_DEBUG +#define FLOCKFILE(fp) _flockfile_debug(fp, __FILE__, __LINE__) +#else +#define FLOCKFILE(fp) flockfile(fp) +#endif +#define FUNLOCKFILE(fp) funlockfile(fp) /* - * Do-nothing macros for single-threaded case. + * File descriptor locking definitions. */ -#define _FD_LOCK(f,o,p) (0) -#define _FD_UNLOCK(f,o) /* nothing */ -#define _THREAD_PRIVATE_KEY(_key) /* nothing */ -#define _THREAD_PRIVATE(keyname, _initv, _errv) (&(_initv)) -#define _THREAD_PRIVATE_MUTEX(_name) /* nothing */ -#define _THREAD_PRIVATE_MUTEX_LOCK(_name) /* nothing */ -#define _THREAD_PRIVATE_MUTEX_UNLOCK(_name) /* nothing */ -#define FLOCKFILE(fp) /* nothing */ -#define FUNLOCKFILE(fp) /* nothing */ - -#endif /* !_THREAD_SAFE */ +#define FD_READ 0x1 +#define FD_WRITE 0x2 +#define FD_RDWR (FD_READ | FD_WRITE) + +#ifdef _LOCK_DEBUG +#define _FD_LOCK(_fd,_type,_ts) _thread_fd_lock_debug(_fd, _type, \ + _ts, __FILE__, __LINE__) +#define _FD_UNLOCK(_fd,_type) _thread_fd_unlock_debug(_fd, _type, \ + __FILE__, __LINE__) +#else +#define _FD_LOCK(_fd,_type,_ts) _thread_fd_lock(_fd, _type, _ts) +#define _FD_UNLOCK(_fd,_type) _thread_fd_unlock(_fd, _type) +#endif + +int _thread_fd_lock(int, int, struct timespec *); +int _thread_fd_lock_debug(int, int, struct timespec *, const char *, int); +void _thread_fd_unlock(int, int); +void _thread_fd_unlock_debug(int, int, const char *, int); #endif _THREAD_PRIVATE_H_ |