1 /*
2  * Copyright (C) the libgit2 contributors. All rights reserved.
3  *
4  * This file is part of libgit2, distributed under the GNU GPL v2 with
5  * a Linking Exception. For full terms see the included COPYING file.
6  */
7 
8 #include "common.h"
9 
10 #if !defined(GIT_THREADS)
11 
12 #define TLSDATA_MAX 16
13 
14 typedef struct {
15 	void *value;
16 	void (GIT_SYSTEM_CALL *destroy_fn)(void *);
17 } tlsdata_value;
18 
19 static tlsdata_value tlsdata_values[TLSDATA_MAX];
20 static int tlsdata_cnt = 0;
21 
git_tlsdata_init(git_tlsdata_key * key,void (GIT_SYSTEM_CALL * destroy_fn)(void *))22 int git_tlsdata_init(git_tlsdata_key *key, void (GIT_SYSTEM_CALL *destroy_fn)(void *))
23 {
24 	if (tlsdata_cnt >= TLSDATA_MAX)
25 		return -1;
26 
27 	tlsdata_values[tlsdata_cnt].value = NULL;
28 	tlsdata_values[tlsdata_cnt].destroy_fn = destroy_fn;
29 
30 	*key = tlsdata_cnt;
31 	tlsdata_cnt++;
32 
33 	return 0;
34 }
35 
git_tlsdata_set(git_tlsdata_key key,void * value)36 int git_tlsdata_set(git_tlsdata_key key, void *value)
37 {
38 	if (key < 0 || key > tlsdata_cnt)
39 		return -1;
40 
41 	tlsdata_values[key].value = value;
42 	return 0;
43 }
44 
git_tlsdata_get(git_tlsdata_key key)45 void *git_tlsdata_get(git_tlsdata_key key)
46 {
47 	if (key < 0 || key > tlsdata_cnt)
48 		return NULL;
49 
50 	return tlsdata_values[key].value;
51 }
52 
git_tlsdata_dispose(git_tlsdata_key key)53 int git_tlsdata_dispose(git_tlsdata_key key)
54 {
55 	void *value;
56 	void (*destroy_fn)(void *) = NULL;
57 
58 	if (key < 0 || key > tlsdata_cnt)
59 		return -1;
60 
61 	value = tlsdata_values[key].value;
62 	destroy_fn = tlsdata_values[key].destroy_fn;
63 
64 	tlsdata_values[key].value = NULL;
65 	tlsdata_values[key].destroy_fn = NULL;
66 
67 	if (value && destroy_fn)
68 		destroy_fn(value);
69 
70 	return 0;
71 }
72 
73 #elif defined(GIT_WIN32)
74 
git_tlsdata_init(git_tlsdata_key * key,void (GIT_SYSTEM_CALL * destroy_fn)(void *))75 int git_tlsdata_init(git_tlsdata_key *key, void (GIT_SYSTEM_CALL *destroy_fn)(void *))
76 {
77 	DWORD fls_index = FlsAlloc(destroy_fn);
78 
79 	if (fls_index == FLS_OUT_OF_INDEXES)
80 		return -1;
81 
82 	*key = fls_index;
83 	return 0;
84 }
85 
git_tlsdata_set(git_tlsdata_key key,void * value)86 int git_tlsdata_set(git_tlsdata_key key, void *value)
87 {
88 	if (!FlsSetValue(key, value))
89 		return -1;
90 
91 	return 0;
92 }
93 
git_tlsdata_get(git_tlsdata_key key)94 void *git_tlsdata_get(git_tlsdata_key key)
95 {
96 	return FlsGetValue(key);
97 }
98 
git_tlsdata_dispose(git_tlsdata_key key)99 int git_tlsdata_dispose(git_tlsdata_key key)
100 {
101 	if (!FlsFree(key))
102 		return -1;
103 
104 	return 0;
105 }
106 
107 #elif defined(_POSIX_THREADS)
108 
git_tlsdata_init(git_tlsdata_key * key,void (GIT_SYSTEM_CALL * destroy_fn)(void *))109 int git_tlsdata_init(git_tlsdata_key *key, void (GIT_SYSTEM_CALL *destroy_fn)(void *))
110 {
111 	if (pthread_key_create(key, destroy_fn) != 0)
112 		return -1;
113 
114 	return 0;
115 }
116 
git_tlsdata_set(git_tlsdata_key key,void * value)117 int git_tlsdata_set(git_tlsdata_key key, void *value)
118 {
119 	if (pthread_setspecific(key, value) != 0)
120 		return -1;
121 
122 	return 0;
123 }
124 
git_tlsdata_get(git_tlsdata_key key)125 void *git_tlsdata_get(git_tlsdata_key key)
126 {
127 	return pthread_getspecific(key);
128 }
129 
git_tlsdata_dispose(git_tlsdata_key key)130 int git_tlsdata_dispose(git_tlsdata_key key)
131 {
132 	if (pthread_key_delete(key) != 0)
133 		return -1;
134 
135 	return 0;
136 }
137 
138 #else
139 # error unknown threading model
140 #endif
141