summaryrefslogtreecommitdiff
path: root/lib/libc/include/thread_private.h
blob: 5fbbf592a41c20675a1f9980a5de343fabf2e57c (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
136
137
138
/* $OpenBSD: thread_private.h,v 1.18 2006/02/22 07:16:31 otto Exp $ */

/* PUBLIC DOMAIN: No Rights Reserved. Marco S Hyman <marc@snafu.org> */

#ifndef _THREAD_PRIVATE_H_
#define _THREAD_PRIVATE_H_

/*
 * This file defines the thread library interface to libc.  Thread
 * libraries must implement the functions described here for proper
 * inter-operation with libc.   libc contains weak versions of the
 * described functions for operation in a non-threaded environment.
 */

/*
 * This variable is 0 until a second thread is created.
 */
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).
 */
#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

/*
 * helper macro to make unique names in the thread namespace
 */
#define __THREAD_NAME(name)	__CONCAT(_thread_tagname_,name)

/*
 * helper functions that exist as (weak) null functions in libc and
 * (strong) functions in the thread library.   These functions:
 *
 * _thread_tag_lock:
 *	lock the mutex associated with the given tag.   If the given
 *	tag is NULL a tag is first allocated.
 *
 * _thread_tag_unlock:
 *	unlock the mutex associated with the given tag.   If the given
 *	tag is NULL a tag is first allocated.
 *
 * _thread_tag_storage:
 *	return a pointer to per thread instance of data associated
 *	with the given tag.  If the given tag is NULL a tag is first
 *	allocated.
 */
void	_thread_tag_lock(void **);
void	_thread_tag_unlock(void **);
void   *_thread_tag_storage(void **, void *, size_t, void *);

/*
 * Macros used in libc to access thread mutex, keys, and per thread storage.
 * _THREAD_PRIVATE_KEY and _THREAD_PRIVATE_MUTEX are different macros for
 * historical reasons.   They do the same thing, define a static variable
 * keyed by 'name' that identifies a mutex and a key to identify per thread
 * data.
 */
#define _THREAD_PRIVATE_KEY(name)					\
	static void *__THREAD_NAME(name)
#define _THREAD_PRIVATE_MUTEX(name)					\
	static void *__THREAD_NAME(name)
#define _THREAD_PRIVATE_MUTEX_LOCK(name)				\
	_thread_tag_lock(&(__THREAD_NAME(name)))
#define _THREAD_PRIVATE_MUTEX_UNLOCK(name)				\
	_thread_tag_unlock(&(__THREAD_NAME(name)))
#define _THREAD_PRIVATE(keyname, storage, error)			\
	_thread_tag_storage(&(__THREAD_NAME(keyname)), &(storage),	\
			    sizeof (storage), error)
/*
 * Resolver code is special cased in that it uses global keys.
 */
extern void *__THREAD_NAME(_res);
extern void *__THREAD_NAME(_res_ext);
extern void *__THREAD_NAME(serv_mutex);

/*
 * File descriptor locking definitions.
 */
#define FD_READ		0x1
#define FD_WRITE	0x2
#define FD_RDWR		(FD_READ | FD_WRITE)

struct timespec;
int	_thread_fd_lock(int, int, struct timespec *);
void	_thread_fd_unlock(int, int);

/*
 * Macros are used in libc code for historical (debug) reasons.
 * Define them here.
 */
#define _FD_LOCK(_fd,_type,_ts)	_thread_fd_lock(_fd, _type, _ts)
#define _FD_UNLOCK(_fd,_type)	_thread_fd_unlock(_fd, _type)


/*
 * malloc lock/unlock prototypes and definitions
 */
void	_thread_malloc_init(void);
void	_thread_malloc_lock(void);
void	_thread_malloc_unlock(void);

#define _MALLOC_LOCK()		do {					\
					if (__isthreaded)		\
						_thread_malloc_lock();	\
				} while (0)
#define _MALLOC_UNLOCK()	do {					\
					if (__isthreaded)		\
						_thread_malloc_unlock();\
				} while (0)
#define _MALLOC_LOCK_INIT()	do {					\
					if (__isthreaded)		\
						_thread_malloc_init();\
				} while (0)

void	_thread_atexit_lock(void);
void	_thread_atexit_unlock(void);

#define _ATEXIT_LOCK()		do {					\
					if (__isthreaded)		\
						_thread_atexit_lock();	\
				} while (0)
#define _ATEXIT_UNLOCK()	do {					\
					if (__isthreaded)		\
						_thread_atexit_unlock();\
				} while (0)

#endif /* _THREAD_PRIVATE_H_ */