Skip to content

Commit fd2d475

Browse files
committed
threads: git_tls_data to git_tlsdata
Use a no-allocation approach to the TLS data abstraction.
1 parent 42d5f11 commit fd2d475

File tree

3 files changed

+164
-168
lines changed

3 files changed

+164
-168
lines changed

src/thread.c

Lines changed: 67 additions & 140 deletions
Original file line numberDiff line numberDiff line change
@@ -7,207 +7,134 @@
77

88
#include "common.h"
99

10-
#ifndef GIT_THREADS
10+
#if !defined(GIT_THREADS)
1111

12-
struct git_tls_data {
13-
void GIT_CALLBACK(free_fn)(void *payload);
14-
void *storage;
15-
};
12+
#define TLSDATA_MAX 16
1613

17-
int git_tls_data__init(git_tls_data **out,
18-
void GIT_CALLBACK(free_fn)(void *storage))
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+
22+
int git_tlsdata_init(git_tlsdata_key *key, void (GIT_SYSTEM_CALL *destroy_fn)(void *))
1923
{
20-
struct git_tls_data *tls = git__malloc(sizeof(struct git_tls_data));
21-
GIT_ERROR_CHECK_ALLOC(tls);
24+
if (tlsdata_cnt >= TLSDATA_MAX)
25+
return -1;
2226

23-
tls->storage = NULL;
24-
tls->free_fn = free_fn;
25-
*out = tls;
27+
tlsdata_values[tlsdata_cnt].value = NULL;
28+
tlsdata_values[tlsdata_cnt].destroy_fn = destroy_fn;
29+
30+
*key = tlsdata_cnt;
31+
tlsdata_cnt++;
2632

2733
return 0;
2834
}
2935

30-
int git_tls_data__set(git_tls_data *tls, void *payload)
36+
int git_tlsdata_set(git_tlsdata_key key, void *value)
3137
{
32-
tls->storage = payload;
38+
if (key < 0 || key > tlsdata_cnt)
39+
return -1;
40+
41+
tlsdata_values[key].value = value;
3342
return 0;
3443
}
3544

36-
void *git_tls_data__get(git_tls_data *tls)
45+
void *git_tlsdata_get(git_tlsdata_key key)
3746
{
38-
return tls->storage;
47+
if (key < 0 || key > tlsdata_cnt)
48+
return NULL;
49+
50+
return tlsdata_values[key].value;
3951
}
4052

41-
void git_tls_data__free(git_tls_data *tls)
53+
int git_tlsdata_dispose(git_tlsdata_key key)
4254
{
43-
tls->free_fn(tls->storage);
44-
git__free(tls);
45-
}
55+
void *value;
56+
void (*destroy_fn)(void *) = NULL;
4657

47-
#elif defined(GIT_WIN32)
58+
if (key < 0 || key > tlsdata_cnt)
59+
return -1;
4860

49-
struct git_tls_data {
50-
void GIT_CALLBACK(free_fn)(void *payload);
51-
DWORD fls_index;
52-
};
61+
value = tlsdata_values[key].value;
62+
destroy_fn = tlsdata_values[key].destroy_fn;
5363

54-
struct git_tls_cell {
55-
void GIT_CALLBACK(free_fn)(void *storage);
56-
void *storage;
57-
};
64+
tlsdata_values[key].value = NULL;
65+
tlsdata_values[key].destroy_fn = NULL;
5866

59-
static void WINAPI git_tls_cell__free(void *sc)
60-
{
61-
struct git_tls_cell *storage_cell = sc;
62-
if (storage_cell == NULL) {
63-
return;
64-
}
67+
if (value && destroy_fn)
68+
destroy_fn(value);
6569

66-
storage_cell->free_fn(storage_cell->storage);
67-
git__free(storage_cell);
70+
return 0;
6871
}
6972

70-
int git_tls_data__init(git_tls_data **out,
71-
void GIT_CALLBACK(free_fn)(void *payload))
73+
#elif defined(GIT_WIN32)
74+
75+
int git_tlsdata_init(git_tlsdata_key *key, void (GIT_SYSTEM_CALL *destroy_fn)(void *))
7276
{
73-
struct git_tls_data *tls = git__malloc(sizeof(struct git_tls_data));
74-
GIT_ERROR_CHECK_ALLOC(tls);
77+
DWORD fls_index = FlsAlloc(destroy_fn);
7578

76-
if ((tls->fls_index = FlsAlloc(git_tls_cell__free)) == FLS_OUT_OF_INDEXES) {
77-
git__free(tls);
79+
if (fls_index == FLS_OUT_OF_INDEXES)
7880
return -1;
79-
}
80-
81-
tls->free_fn = free_fn;
82-
*out = tls;
8381

82+
*key = fls_index;
8483
return 0;
8584
}
8685

87-
int git_tls_data__set(git_tls_data *tls, void *payload)
86+
int git_tlsdata_set(git_tlsdata_key key, void *value)
8887
{
89-
struct git_tls_cell *storage_cell;
90-
91-
if (payload == NULL) {
92-
if ((storage_cell = FlsGetValue(tls->fls_index)) != NULL)
93-
git_tls_cell__free(storage_cell);
94-
95-
if (FlsSetValue(tls->fls_index, NULL) == 0)
96-
return -1;
97-
98-
return 0;
99-
}
100-
101-
storage_cell = git__malloc(sizeof(struct git_tls_cell));
102-
GIT_ERROR_CHECK_ALLOC(storage_cell);
103-
104-
storage_cell->free_fn = tls->free_fn;
105-
storage_cell->storage = payload;
106-
107-
if (FlsSetValue(tls->fls_index, storage_cell) == 0) {
108-
git__free(storage_cell);
88+
if (!FlsSetValue(key, value))
10989
return -1;
110-
}
11190

11291
return 0;
11392
}
11493

115-
void *git_tls_data__get(git_tls_data *tls)
94+
void *git_tlsdata_get(git_tlsdata_key key)
11695
{
117-
struct git_tls_cell *storage_cell = FlsGetValue(tls->fls_index);
118-
if (storage_cell == NULL)
119-
return NULL;
120-
121-
return storage_cell->storage;
96+
return FlsGetValue(key);
12297
}
12398

124-
void git_tls_data__free(git_tls_data *tls)
99+
int git_tlsdata_dispose(git_tlsdata_key key)
125100
{
126-
FlsFree(tls->fls_index);
127-
tls->free_fn = NULL;
128-
git__free(tls);
101+
if (!FlsFree(key))
102+
return -1;
103+
104+
return 0;
129105
}
130106

131107
#elif defined(_POSIX_THREADS)
132108

133-
struct git_tls_data {
134-
void GIT_CALLBACK(free_fn)(void *payload);
135-
pthread_key_t tls_key;
136-
};
137-
138-
struct git_tls_cell {
139-
void GIT_CALLBACK(free_fn)(void *storage);
140-
void *storage;
141-
};
142-
143-
static void git_tls_cell__free(void *sc)
109+
int git_tlsdata_init(git_tlsdata_key *key, void (GIT_SYSTEM_CALL *destroy_fn)(void *))
144110
{
145-
struct git_tls_cell *storage_cell = sc;
146-
storage_cell->free_fn(storage_cell->storage);
147-
git__free(storage_cell);
148-
}
149-
150-
int git_tls_data__init(git_tls_data **out,
151-
void GIT_CALLBACK(free_fn)(void *payload))
152-
{
153-
struct git_tls_data *tls = git__malloc(sizeof(struct git_tls_data));
154-
GIT_ERROR_CHECK_ALLOC(tls);
155-
156-
if (pthread_key_create(&tls->tls_key, git_tls_cell__free) != 0) {
157-
git__free(tls);
111+
if (pthread_key_create(key, destroy_fn) != 0)
158112
return -1;
159-
}
160-
161-
tls->free_fn = free_fn;
162-
*out = tls;
163113

164114
return 0;
165115
}
166116

167-
int git_tls_data__set(git_tls_data *tls, void *payload)
117+
int git_tlsdata_set(git_tlsdata_key key, void *value)
168118
{
169-
struct git_tls_cell *storage_cell;
170-
171-
if (payload == NULL) {
172-
if ((storage_cell = pthread_getspecific(tls->tls_key)) != NULL)
173-
git_tls_cell__free(storage_cell);
174-
175-
if (pthread_setspecific(tls->tls_key, NULL) != 0)
176-
return -1;
177-
178-
return 0;
179-
}
180-
181-
storage_cell = git__malloc(sizeof(struct git_tls_cell));
182-
GIT_ERROR_CHECK_ALLOC(storage_cell);
183-
184-
storage_cell->free_fn = tls->free_fn;
185-
storage_cell->storage = payload;
186-
187-
if (pthread_setspecific(tls->tls_key, storage_cell) != 0) {
188-
git__free(storage_cell);
119+
if (pthread_setspecific(key, value) != 0)
189120
return -1;
190-
}
191121

192122
return 0;
193123
}
194124

195-
void *git_tls_data__get(git_tls_data *tls)
125+
void *git_tlsdata_get(git_tlsdata_key key)
196126
{
197-
struct git_tls_cell *storage_cell = pthread_getspecific(tls->tls_key);
198-
if (storage_cell == NULL)
199-
return NULL;
200-
201-
return storage_cell->storage;
127+
return pthread_getspecific(key);
202128
}
203129

204-
void git_tls_data__free(git_tls_data *tls)
130+
int git_tlsdata_dispose(git_tlsdata_key key)
205131
{
206-
git_tls_data__set(tls, NULL);
207-
pthread_key_delete(tls->tls_key);
208-
git__free(tls);
132+
if (pthread_key_delete(key) != 0)
133+
return -1;
134+
135+
return 0;
209136
}
210137

211138
#else
212-
# error unknown threading model
139+
# error unknown threading model
213140
#endif

src/thread.h

Lines changed: 32 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -367,52 +367,56 @@ GIT_INLINE(int64_t) git_atomic64_get(git_atomic64 *a)
367367

368368
#endif
369369

370-
/**
371-
* An opaque structure for managing TLS in the library
372-
*/
373-
typedef struct git_tls_data git_tls_data;
370+
/* Thread-local data */
371+
372+
#if !defined(GIT_THREADS)
373+
# define git_tlsdata_key int
374+
#elif defined(GIT_WIN32)
375+
# define git_tlsdata_key DWORD
376+
#elif defined(_POSIX_THREADS)
377+
# define git_tlsdata_key pthread_key_t
378+
#else
379+
# error unknown threading model
380+
#endif
374381

375382
/**
376-
* Initializes a thread local storage container.
377-
* This has an implementation even without GIT_THREADS
378-
* which just serves to encourage use of this where TLS
379-
* is necessary.
383+
* Create a thread-local data key. The destroy function will be
384+
* called upon thread exit. On some platforms, it may be called
385+
* when all threads have deleted their keys.
380386
*
381-
* Do not call this before the allocator has been initialized.
387+
* Note that the tlsdata functions do not set an error message on
388+
* failure; this is because the error handling in libgit2 is itself
389+
* handled by thread-local data storage.
382390
*
383-
* @param out a pointer to store the TLS container in
384-
* @param free_fn the method that should be called when
385-
* deleting something in the TLS. Will be
386-
* registered as the clean up callback for
387-
* the OS specific TLS construct.
391+
* @param key the tlsdata key
392+
* @param destroy_fn function pointer called upon thread exit
388393
* @return 0 on success, non-zero on failure
389394
*/
390-
int git_tls_data__init(git_tls_data **out,
391-
void GIT_CALLBACK(free_fn)(void *payload));
395+
int git_tlsdata_init(git_tlsdata_key *key, void (GIT_SYSTEM_CALL *destroy_fn)(void *));
392396

393397
/**
394-
* Will set a thread specific value on the TLS. Passing NULL will free the
395-
* currently held thread specific value.
398+
* Set a the thread-local value for the given key.
396399
*
397-
* @param tls the TLS instance to store data on
398-
* @param payload the pointer to store
400+
* @param key the tlsdata key to store data on
401+
* @param value the pointer to store
399402
* @return 0 on success, non-zero on failure
400403
*/
401-
int git_tls_data__set(git_tls_data *tls, void *payload);
404+
int git_tlsdata_set(git_tlsdata_key key, void *value);
402405

403406
/**
404-
* Will get the thread specific value stored in TLS.
407+
* Get the thread-local value for the given key.
405408
*
406-
* @param tls the TLS instance to retrieve data from
409+
* @param key the tlsdata key to retrieve the value of
410+
* @return the pointer stored with git_tlsdata_set
407411
*/
408-
void *git_tls_data__get(git_tls_data *tls);
412+
void *git_tlsdata_get(git_tlsdata_key key);
409413

410414
/**
411-
* Must call this to clean up the TLS when no longer in use.
412-
* The TLS pointer is unusable after a call to this.
415+
* Delete the given thread-local key.
413416
*
414-
* @param tls the TLS to free
417+
* @param key the tlsdata key to dispose
418+
* @return 0 on success, non-zero on failure
415419
*/
416-
void git_tls_data__free(git_tls_data *tls);
420+
int git_tlsdata_dispose(git_tlsdata_key key);
417421

418422
#endif

0 commit comments

Comments
 (0)