From c1f295aa8666eb1c08a1edf944ac5617659a066c Mon Sep 17 00:00:00 2001 From: d <> Date: Fri, 20 Nov 1998 11:18:51 +0000 Subject: Add thread-safety to libc, so that libc_r will build (on i386 at least). All POSIX libc api now there (to P1003.1c/D10) (more md stuff is needed for other libc/arch/*) (setlogin is no longer a special syscall) Add -pthread option to gcc (that makes it use -lc_r and -D_POSIX_THREADS). Doc some re-entrant routines Add libc_r to intro(3) dig() uses some libc srcs and an extra -I was needed there. Add more md stuff to libc_r. Update includes for the pthreads api Update libc_r TODO --- src/lib/libc/include/thread_private.h | 175 ++++++++++++++++++++++++++++++++++ 1 file changed, 175 insertions(+) create mode 100644 src/lib/libc/include/thread_private.h (limited to 'src/lib/libc/include/thread_private.h') diff --git a/src/lib/libc/include/thread_private.h b/src/lib/libc/include/thread_private.h new file mode 100644 index 0000000000..a7f7749078 --- /dev/null +++ b/src/lib/libc/include/thread_private.h @@ -0,0 +1,175 @@ +/* + * + * 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.1 1998/11/20 11:18:41 d Exp $ + */ + +#ifndef _THREAD_PRIVATE_H_ +#define _THREAD_PRIVATE_H_ + +/* + * Parts of this file are + * Copyright (c) 1998 John Birrell . + * All rights reserved. + * + * $Id: thread_private.h,v 1.1 1998/11/20 11:18:41 d Exp $ + * $OpenBSD: thread_private.h,v 1.1 1998/11/20 11:18:41 d Exp $ + */ + +/* + * 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. + */ + +extern volatile int __isthreaded; + +#ifdef _THREAD_SAFE + +#include +#include "pthread_private.h" + +#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 + +/* + * Mutex declare, lock and unlock macros. + */ + +#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); + +#define _THREAD_PRIVATE_MUTEX_LOCK(name) \ + pthread_mutex_lock(&__THREAD_MUTEX_NAME(name)) + +#define _THREAD_PRIVATE_MUTEX_UNLOCK(name) \ + pthread_mutex_unlock(&__THREAD_MUTEX_NAME(name)) + +/* + * 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. + */ + +/* + * 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. + */ +#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, \ + 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. + */ +#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; \ + }) + +#else + + +/* + * do-nothing macros for single-threaded case + */ +#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 */ + +#endif + +/* + * 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. + */ +#ifdef _FLOCK_DEBUG +#define _FLOCKFILE(x) _flockfile_debug(x, __FILE__, __LINE__) +#else +#define _FLOCKFILE(x) flockfile(x) +#endif + +/* + * 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) + +#endif _THREAD_PRIVATE_H_ -- cgit v1.2.3-55-g6feb