rthread_tls.c revision 1.1
1/*	$OpenBSD: rthread_tls.c,v 1.1 2017/08/15 06:13:24 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 <stdlib.h>
23#include <errno.h>
24
25#include <pthread.h>
26
27#include "rthread.h"
28
29static struct rthread_key rkeys[PTHREAD_KEYS_MAX];
30static _atomic_lock_t rkeyslock = _SPINLOCK_UNLOCKED;
31
32int
33pthread_key_create(pthread_key_t *key, void (*destructor)(void*))
34{
35	static int hint;
36	int i;
37
38	_spinlock(&rkeyslock);
39	if (rkeys[hint].used) {
40		for (i = 0; i < PTHREAD_KEYS_MAX; i++) {
41			if (!rkeys[i].used)
42				break;
43		}
44		if (i == PTHREAD_KEYS_MAX) {
45			_spinunlock(&rkeyslock);
46			return (EAGAIN);
47		}
48		hint = i;
49	}
50	rkeys[hint].used = 1;
51	rkeys[hint].destructor = destructor;
52
53	*key = hint++;
54	if (hint >= PTHREAD_KEYS_MAX)
55		hint = 0;
56	_spinunlock(&rkeyslock);
57
58	return (0);
59}
60DEF_STD(pthread_key_create);
61
62int
63pthread_key_delete(pthread_key_t key)
64{
65	pthread_t thread;
66	struct rthread_storage *rs;
67	int rv = 0;
68
69	if (key < 0 || key >= PTHREAD_KEYS_MAX)
70		return (EINVAL);
71
72	_spinlock(&rkeyslock);
73	if (!rkeys[key].used) {
74		rv = EINVAL;
75		goto out;
76	}
77
78	rkeys[key].used = 0;
79	rkeys[key].destructor = NULL;
80	_spinlock(&_thread_lock);
81	LIST_FOREACH(thread, &_thread_list, threads) {
82		for (rs = thread->local_storage; rs; rs = rs->next) {
83			if (rs->keyid == key)
84				rs->data = NULL;
85		}
86	}
87	_spinunlock(&_thread_lock);
88
89out:
90	_spinunlock(&rkeyslock);
91	return (rv);
92}
93
94static struct rthread_storage *
95_rthread_findstorage(pthread_key_t key)
96{
97	struct rthread_storage *rs;
98	pthread_t self;
99
100	if (!rkeys[key].used) {
101		rs = NULL;
102		goto out;
103	}
104
105	self = pthread_self();
106
107	for (rs = self->local_storage; rs; rs = rs->next) {
108		if (rs->keyid == key)
109			break;
110	}
111	if (!rs) {
112		rs = calloc(1, sizeof(*rs));
113		if (!rs)
114			goto out;
115		rs->keyid = key;
116		rs->data = NULL;
117		rs->next = self->local_storage;
118		self->local_storage = rs;
119	}
120
121out:
122	return (rs);
123}
124
125void *
126pthread_getspecific(pthread_key_t key)
127{
128	struct rthread_storage *rs;
129
130	if (key < 0 || key >= PTHREAD_KEYS_MAX)
131		return (NULL);
132
133	rs = _rthread_findstorage(key);
134	if (!rs)
135		return (NULL);
136
137	return (rs->data);
138}
139DEF_STD(pthread_getspecific);
140
141int
142pthread_setspecific(pthread_key_t key, const void *data)
143{
144	struct rthread_storage *rs;
145
146	if (key < 0 || key >= PTHREAD_KEYS_MAX)
147		return (EINVAL);
148
149	rs = _rthread_findstorage(key);
150	if (!rs)
151		return (ENOMEM);
152	rs->data = (void *)data;
153
154	return (0);
155}
156DEF_STD(pthread_setspecific);
157
158void
159_rthread_tls_destructors(pthread_t thread)
160{
161	struct rthread_storage *rs;
162	int i;
163
164	_spinlock(&rkeyslock);
165	for (i = 0; i < PTHREAD_DESTRUCTOR_ITERATIONS; i++) {
166		for (rs = thread->local_storage; rs; rs = rs->next) {
167			if (!rs->data)
168				continue;
169			if (rkeys[rs->keyid].destructor) {
170				void (*destructor)(void *) =
171				    rkeys[rs->keyid].destructor;
172				void *data = rs->data;
173				rs->data = NULL;
174				_spinunlock(&rkeyslock);
175				destructor(data);
176				_spinlock(&rkeyslock);
177			}
178		}
179	}
180	for (rs = thread->local_storage; rs; rs = thread->local_storage) {
181		thread->local_storage = rs->next;
182		free(rs);
183	}
184	_spinunlock(&rkeyslock);
185}
186