summaryrefslogtreecommitdiff
path: root/lib/libc
diff options
context:
space:
mode:
authorDavid Leonard <d@cvs.openbsd.org>2000-01-06 07:47:10 +0000
committerDavid Leonard <d@cvs.openbsd.org>2000-01-06 07:47:10 +0000
commit0336fa3e2a09f916f18448ea7e1e7746b23409ec (patch)
tree490c5775934fd5fb0d41d7fa831aaf5feb3c7467 /lib/libc
parent465358cdc102ac7b0791790eb5ff8decc50e7025 (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.h226
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_