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

Line Branch Exec Source
1
/*	$OpenBSD: rthread_tls.c,v 1.4 2017/09/05 02:40:54 guenther Exp $ */
2
/*
3
 * Copyright (c) 2004,2005 Ted Unangst <tedu@openbsd.org>
4
 * All Rights Reserved.
5
 *
6
 * Permission to use, copy, modify, and distribute this software for any
7
 * purpose with or without fee is hereby granted, provided that the above
8
 * copyright notice and this permission notice appear in all copies.
9
 *
10
 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11
 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12
 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13
 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14
 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15
 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16
 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17
 */
18
/*
19
 * thread specific storage
20
 */
21
22
#include <errno.h>
23
#include <pthread.h>
24
#include <stdlib.h>
25
26
#include <pthread.h>
27
#include <stdlib.h>
28
29
#include "rthread.h"
30
31
32
struct rthread_key {
33
	int used;
34
	void (*destructor)(void *);
35
};
36
37
static struct rthread_key rkeys[PTHREAD_KEYS_MAX];
38
static _atomic_lock_t rkeyslock = _SPINLOCK_UNLOCKED;
39
40
int
41
pthread_key_create(pthread_key_t *key, void (*destructor)(void*))
42
{
43
	static int hint;
44
	int i;
45
46
	_spinlock(&rkeyslock);
47
	if (rkeys[hint].used) {
48
		for (i = 0; i < PTHREAD_KEYS_MAX; i++) {
49
			if (!rkeys[i].used)
50
				break;
51
		}
52
		if (i == PTHREAD_KEYS_MAX) {
53
			_spinunlock(&rkeyslock);
54
			return (EAGAIN);
55
		}
56
		hint = i;
57
	}
58
	rkeys[hint].used = 1;
59
	rkeys[hint].destructor = destructor;
60
61
	*key = hint++;
62
	if (hint >= PTHREAD_KEYS_MAX)
63
		hint = 0;
64
	_spinunlock(&rkeyslock);
65
66
	return (0);
67
}
68
DEF_STRONG(pthread_key_create);
69
70
int
71
pthread_key_delete(pthread_key_t key)
72
{
73
	struct rthread_storage *rs;
74
	int rv = 0;
75
76
	if (key < 0 || key >= PTHREAD_KEYS_MAX)
77
		return (EINVAL);
78
79
	_spinlock(&rkeyslock);
80
	if (!rkeys[key].used) {
81
		rv = EINVAL;
82
		goto out;
83
	}
84
85
	rkeys[key].used = 0;
86
	rkeys[key].destructor = NULL;
87
	if (_thread_cb.tc_thread_key_zero != NULL)
88
		_thread_cb.tc_thread_key_zero(key);
89
	else {
90
		for (rs = _initial_thread.local_storage; rs; rs = rs->next) {
91
			if (rs->keyid == key)
92
				rs->data = NULL;
93
		}
94
	}
95
96
out:
97
	_spinunlock(&rkeyslock);
98
	return (rv);
99
}
100
101
static struct rthread_storage *
102
_rthread_findstorage(pthread_key_t key)
103
{
104
	struct rthread_storage *rs;
105
	pthread_t self;
106
107
	if (!rkeys[key].used) {
108
		rs = NULL;
109
		goto out;
110
	}
111
112
	self = pthread_self();
113
114
	for (rs = self->local_storage; rs; rs = rs->next) {
115
		if (rs->keyid == key)
116
			break;
117
	}
118
	if (!rs) {
119
		rs = calloc(1, sizeof(*rs));
120
		if (!rs)
121
			goto out;
122
		rs->keyid = key;
123
		rs->data = NULL;
124
		rs->next = self->local_storage;
125
		self->local_storage = rs;
126
	}
127
128
out:
129
	return (rs);
130
}
131
132
void *
133
pthread_getspecific(pthread_key_t key)
134
{
135
	struct rthread_storage *rs;
136
137
	if (key < 0 || key >= PTHREAD_KEYS_MAX)
138
		return (NULL);
139
140
	rs = _rthread_findstorage(key);
141
	if (!rs)
142
		return (NULL);
143
144
	return (rs->data);
145
}
146
DEF_STRONG(pthread_getspecific);
147
148
int
149
pthread_setspecific(pthread_key_t key, const void *data)
150
{
151
	struct rthread_storage *rs;
152
153
	if (key < 0 || key >= PTHREAD_KEYS_MAX)
154
		return (EINVAL);
155
156
	rs = _rthread_findstorage(key);
157
	if (!rs)
158
		return (ENOMEM);
159
	rs->data = (void *)data;
160
161
	return (0);
162
}
163
DEF_STRONG(pthread_setspecific);
164
165
void
166
_rthread_tls_destructors(pthread_t thread)
167
{
168
	struct rthread_storage *rs;
169
	int i;
170
171
	_spinlock(&rkeyslock);
172
	for (i = 0; i < PTHREAD_DESTRUCTOR_ITERATIONS; i++) {
173
		for (rs = thread->local_storage; rs; rs = rs->next) {
174
			if (!rs->data)
175
				continue;
176
			if (rkeys[rs->keyid].destructor) {
177
				void (*destructor)(void *) =
178
				    rkeys[rs->keyid].destructor;
179
				void *data = rs->data;
180
				rs->data = NULL;
181
				_spinunlock(&rkeyslock);
182
				destructor(data);
183
				_spinlock(&rkeyslock);
184
			}
185
		}
186
	}
187
	for (rs = thread->local_storage; rs; rs = thread->local_storage) {
188
		thread->local_storage = rs->next;
189
		free(rs);
190
	}
191
	_spinunlock(&rkeyslock);
192
}