summaryrefslogtreecommitdiff
path: root/lib/libc/include/thread_private.h
blob: 723bed5f51857ace965770c7551aea06db9fbbaf (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
/* $OpenBSD: thread_private.h,v 1.10 2001/09/04 22:17:45 fgsch Exp $ */

#ifndef _THREAD_PRIVATE_H_
#define _THREAD_PRIVATE_H_

#include <pthread.h>

/*
 * This variable is initially 0 when there is exactly one thread.
 * It should never decrease.
 */
extern int __isthreaded;

/*
 * 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 _NO_WEAK_ALIASES
#ifdef _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_ALIASES */
#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 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 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)

struct _thread_private_key_struct {
	pthread_once_t		once;
	void			(*cleanfn)__P((void *));
	pthread_key_t		key;
};

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 pthread_mutex_t __THREAD_MUTEX_NAME(name) = 		\
		PTHREAD_MUTEX_INITIALIZER			
		
/* Lock a module mutex against use by any other threads. */
#define _THREAD_PRIVATE_MUTEX_LOCK(name) 				\
	_libc_private_storage_lock(&__THREAD_MUTEX_NAME(name))
		
/* Unlock a module mutex. */
#define _THREAD_PRIVATE_MUTEX_UNLOCK(name) 				\
	_libc_private_storage_unlock(&__THREAD_MUTEX_NAME(name))

/* Declare a thread-private storage key. */
#define _THREAD_PRIVATE_KEY(name)					\
	static volatile struct _thread_private_key_struct		\
	__THREAD_KEY_NAME(name) = {					\
		PTHREAD_ONCE_INIT, 					\
		0							\
	}

/*
 * 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, 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.
 */
#ifdef	_FLOCK_DEBUG
#define FLOCKFILE(fp)		_flockfile_debug(fp, __FILE__, __LINE__)
#else
#define FLOCKFILE(fp)		flockfile(fp)
#endif
#define	FUNLOCKFILE(fp)		funlockfile(fp)

/*
 * File descriptor locking definitions.
 */
#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 *, char *, int);
void	_thread_fd_unlock(int, int);
void	_thread_fd_unlock_debug(int, int, char *, int);

#endif /* _THREAD_PRIVATE_H_ */