GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: lib/libc/thread/rthread_libc.c Lines: 0 68 0.0 %
Date: 2017-11-13 Branches: 0 42 0.0 %

Line Branch Exec Source
1
/* $OpenBSD: rthread_libc.c,v 1.2 2017/09/05 02:40:54 guenther Exp $ */
2
3
/* PUBLIC DOMAIN: No Rights Reserved. Marco S Hyman <marc@snafu.org> */
4
5
#include <pthread.h>
6
#include <stdlib.h>
7
#include <string.h>
8
9
#include "rthread.h"
10
#include "rthread_cb.h"
11
12
/*
13
 * A thread tag is a pointer to a structure of this type.  An opaque
14
 * tag is used to decouple libc from the thread library.
15
 */
16
struct _thread_tag {
17
	pthread_mutex_t	m;	/* the tag's mutex */
18
	pthread_key_t	k;	/* a key for private data */
19
};
20
21
/*
22
 * local mutex to protect against tag creation races.
23
 */
24
static pthread_mutex_t	_thread_tag_mutex = PTHREAD_MUTEX_INITIALIZER;
25
26
/*
27
 * Initialize a thread tag structure once.   This function is called
28
 * if the tag is null.  Allocation and initialization are controlled
29
 * by a mutex.   If the tag is not null when the mutex is obtained
30
 * the caller lost a race -- some other thread initialized the tag.
31
 * This function will never return NULL.
32
 */
33
static void
34
_thread_tag_init(void **tag)
35
{
36
	struct _thread_tag *tt;
37
	int result;
38
39
	result = pthread_mutex_lock(&_thread_tag_mutex);
40
	if (result == 0) {
41
		if (*tag == NULL) {
42
			tt = malloc(sizeof *tt);
43
			if (tt != NULL) {
44
				result = pthread_mutex_init(&tt->m, NULL);
45
				result |= pthread_key_create(&tt->k, free);
46
				*tag = tt;
47
			}
48
		}
49
		result |= pthread_mutex_unlock(&_thread_tag_mutex);
50
	}
51
	if (result != 0)
52
		_rthread_debug(1, "tag init failure");
53
}
54
55
/*
56
 * lock the mutex associated with the given tag
57
 */
58
void
59
_thread_tag_lock(void **tag)
60
{
61
	struct _thread_tag *tt;
62
63
	if (__isthreaded) {
64
		if (*tag == NULL)
65
			_thread_tag_init(tag);
66
		tt = *tag;
67
		if (pthread_mutex_lock(&tt->m) != 0)
68
			_rthread_debug(1, "tag mutex lock failure");
69
	}
70
}
71
72
/*
73
 * unlock the mutex associated with the given tag
74
 */
75
void
76
_thread_tag_unlock(void **tag)
77
{
78
	struct _thread_tag *tt;
79
80
	if (__isthreaded) {
81
		if (*tag == NULL)
82
			_thread_tag_init(tag);
83
		tt = *tag;
84
		if (pthread_mutex_unlock(&tt->m) != 0)
85
			_rthread_debug(1, "tag mutex unlock failure");
86
	}
87
}
88
89
/*
90
 * return the thread specific data for the given tag.   If there
91
 * is no data for this thread initialize it from 'storage'.
92
 * On any error return 'err'.
93
 */
94
void *
95
_thread_tag_storage(void **tag, void *storage, size_t sz, void *err)
96
{
97
	struct _thread_tag *tt;
98
	void *ret;
99
100
	if (*tag == NULL)
101
		_thread_tag_init(tag);
102
	tt = *tag;
103
104
	ret = pthread_getspecific(tt->k);
105
	if (ret == NULL) {
106
		ret = malloc(sz);
107
		if (ret == NULL)
108
			ret = err;
109
		else {
110
			if (pthread_setspecific(tt->k, ret) == 0)
111
				memcpy(ret, storage, sz);
112
			else {
113
				free(ret);
114
				ret = err;
115
			}
116
		}
117
	}
118
	return ret;
119
}
120
121
void
122
_thread_mutex_lock(void **mutex)
123
{
124
	pthread_mutex_t	*pmutex = (pthread_mutex_t *)mutex;
125
126
	if (pthread_mutex_lock(pmutex) != 0)
127
		_rthread_debug(1, "mutex lock failure");
128
}
129
130
void
131
_thread_mutex_unlock(void **mutex)
132
{
133
	pthread_mutex_t	*pmutex = (pthread_mutex_t *)mutex;
134
135
	if (pthread_mutex_unlock(pmutex) != 0)
136
		_rthread_debug(1, "mutex unlock failure");
137
}
138
139
void
140
_thread_mutex_destroy(void **mutex)
141
{
142
	pthread_mutex_t	*pmutex = (pthread_mutex_t *)mutex;
143
144
	if (pthread_mutex_destroy(pmutex) != 0)
145
		_rthread_debug(1, "mutex destroy failure");
146
}
147
148
/*
149
 * the malloc lock
150
 */
151
#ifndef FUTEX
152
#define MALLOC_LOCK_INITIALIZER(n) { \
153
	_SPINLOCK_UNLOCKED,	\
154
	TAILQ_HEAD_INITIALIZER(malloc_lock[n].lockers), \
155
	PTHREAD_MUTEX_DEFAULT,	\
156
	NULL,			\
157
	0,			\
158
	-1 }
159
#else
160
#define MALLOC_LOCK_INITIALIZER(n) { \
161
	_SPINLOCK_UNLOCKED,	\
162
	PTHREAD_MUTEX_DEFAULT,	\
163
	NULL,			\
164
	0,			\
165
	-1 }
166
#endif
167
168
static struct pthread_mutex malloc_lock[_MALLOC_MUTEXES] = {
169
	MALLOC_LOCK_INITIALIZER(0),
170
	MALLOC_LOCK_INITIALIZER(1),
171
	MALLOC_LOCK_INITIALIZER(2),
172
	MALLOC_LOCK_INITIALIZER(3)
173
};
174
175
static pthread_mutex_t malloc_mutex[_MALLOC_MUTEXES] = {
176
	&malloc_lock[0],
177
	&malloc_lock[1],
178
	&malloc_lock[2],
179
	&malloc_lock[3]
180
};
181
182
void
183
_thread_malloc_lock(int i)
184
{
185
	pthread_mutex_lock(&malloc_mutex[i]);
186
}
187
188
void
189
_thread_malloc_unlock(int i)
190
{
191
	pthread_mutex_unlock(&malloc_mutex[i]);
192
}
193
194
static void
195
_thread_malloc_reinit(void)
196
{
197
	int i;
198
199
	for (i = 0; i < _MALLOC_MUTEXES; i++) {
200
		malloc_lock[i].lock = _SPINLOCK_UNLOCKED;
201
#ifndef FUTEX
202
		TAILQ_INIT(&malloc_lock[i].lockers);
203
#endif
204
		malloc_lock[i].owner = NULL;
205
		malloc_lock[i].count = 0;
206
	}
207
}
208
209
/*
210
 * atexit lock
211
 */
212
static _atomic_lock_t atexit_lock = _SPINLOCK_UNLOCKED;
213
214
void
215
_thread_atexit_lock(void)
216
{
217
	_spinlock(&atexit_lock);
218
}
219
220
void
221
_thread_atexit_unlock(void)
222
{
223
	_spinunlock(&atexit_lock);
224
}
225
226
/*
227
 * atfork lock
228
 */
229
static _atomic_lock_t atfork_lock = _SPINLOCK_UNLOCKED;
230
231
void
232
_thread_atfork_lock(void)
233
{
234
	_spinlock(&atfork_lock);
235
}
236
237
void
238
_thread_atfork_unlock(void)
239
{
240
	_spinunlock(&atfork_lock);
241
}
242
243
/*
244
 * arc4random lock
245
 */
246
static _atomic_lock_t arc4_lock = _SPINLOCK_UNLOCKED;
247
248
void
249
_thread_arc4_lock(void)
250
{
251
	_spinlock(&arc4_lock);
252
}
253
254
void
255
_thread_arc4_unlock(void)
256
{
257
	_spinunlock(&arc4_lock);
258
}
259
260
pid_t
261
_thread_dofork(pid_t (*sys_fork)(void))
262
{
263
	int i;
264
	pid_t newid;
265
266
	_thread_atexit_lock();
267
	for (i = 0; i < _MALLOC_MUTEXES; i++)
268
		_thread_malloc_lock(i);
269
	_thread_arc4_lock();
270
271
	newid = sys_fork();
272
273
	_thread_arc4_unlock();
274
	if (newid == 0)
275
		_thread_malloc_reinit();
276
	else
277
		for (i = 0; i < _MALLOC_MUTEXES; i++)
278
			_thread_malloc_unlock(i);
279
	_thread_atexit_unlock();
280
281
	return newid;
282
}
283