1//------------------------------------------------------------------------------
2// Copyright (c) 2016 by Lukasz Janyst <lukasz@jany.st>
3//------------------------------------------------------------------------------
4// This file is part of thread-bites.
5//
6// thread-bites is free software: you can redistribute it and/or modify
7// it under the terms of the GNU General Public License as published by
8// the Free Software Foundation, either version 3 of the License, or
9// (at your option) any later version.
10//
11// thread-bites is distributed in the hope that it will be useful,
12// but WITHOUT ANY WARRANTY; without even the implied warranty of
13// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14// GNU General Public License for more details.
15//
16// You should have received a copy of the GNU General Public License
17// along with thread-bites. If not, see <http://www.gnu.org/licenses/>.
18//------------------------------------------------------------------------------
19
20#include "tb.h"
21
22//------------------------------------------------------------------------------
23// Get the pointer of the currently running thread
24//------------------------------------------------------------------------------
25tbthread_t tbthread_self()
26{
27 tbthread_t self;
28 asm("movq %%fs:0, %0\n\t" : "=r" (self));
29 return self;
30}
31
32//------------------------------------------------------------------------------
33// The keys and helpers
34//------------------------------------------------------------------------------
35static struct
36{
37 uint64_t seq;
38 void (*destructor)(void *);
39} keys[TBTHREAD_MAX_KEYS];
40
41#define KEY_UNUSED(k) ((keys[k].seq&1) == 0)
42#define KEY_ACQUIRE(k) (__sync_bool_compare_and_swap(&(keys[k].seq), keys[k].seq, keys[k].seq+1))
43#define KEY_RELEASE(k) (__sync_bool_compare_and_swap(&(keys[k].seq), keys[k].seq, keys[k].seq+1))
44
45//------------------------------------------------------------------------------
46// Create a key
47//------------------------------------------------------------------------------
48int tbthread_key_create(tbthread_key_t *key, void (*destructor)(void *))
49{
50 for(tbthread_key_t i = 0; i < TBTHREAD_MAX_KEYS; ++i) {
51 if(KEY_UNUSED(i) && KEY_ACQUIRE(i)) {
52 *key = i;
53 keys[i].destructor = destructor;
54 return 0;
55 }
56 }
57 return -ENOMEM;
58}
59
60//------------------------------------------------------------------------------
61// Delete the key
62//------------------------------------------------------------------------------
63int tbthread_key_delete(tbthread_key_t key)
64{
65 if(key >= TBTHREAD_MAX_KEYS)
66 return -EINVAL;
67
68 if(!KEY_UNUSED(key) && KEY_RELEASE(key))
69 return 0;
70
71 return -EINVAL;
72}
73
74//------------------------------------------------------------------------------
75// Get the thread specific data associated with the key
76//------------------------------------------------------------------------------
77void *tbthread_getspecific(tbthread_key_t key)
78{
79 if(key >= TBTHREAD_MAX_KEYS || KEY_UNUSED(key))
80 return 0;
81
82 tbthread_t self = tbthread_self();
83 if(self->tls[key].seq == keys[key].seq)
84 return self->tls[key].data;
85 return 0;
86}
87
88//------------------------------------------------------------------------------
89// Associate thread specific data with the key
90//------------------------------------------------------------------------------
91int tbthread_setspecific(tbthread_key_t key, void *value)
92{
93 if(key >= TBTHREAD_MAX_KEYS || KEY_UNUSED(key))
94 return -EINVAL;
95
96 tbthread_t self = tbthread_self();
97 self->tls[key].seq = keys[key].seq;
98 self->tls[key].data = value;
99 return 0;
100}
101
102//------------------------------------------------------------------------------
103// Call the destructors of all the non-null values
104//------------------------------------------------------------------------------
105void tb_tls_call_destructors()
106{
107 tbthread_t self = tbthread_self();
108 for(tbthread_key_t i = 0; i < TBTHREAD_MAX_KEYS; ++i) {
109 if(!KEY_UNUSED(i) && self->tls[i].seq == keys[i].seq &&
110 self->tls[i].data && keys[i].destructor) {
111 void *data = self->tls[i].data;
112 self->tls[i].data = 0;
113 keys[i].destructor(data);
114 }
115 }
116}
117