1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
|
/*
* Copyright (C) 2009-2012 the libgit2 contributors
*
* This file is part of libgit2, distributed under the GNU GPL v2 with
* a Linking Exception. For full terms see the included COPYING file.
*/
#include "common.h"
#include "global.h"
#include "git2/threads.h"
#include "thread-utils.h"
/**
* Handle the global state with TLS
*
* If libgit2 is built with GIT_THREADS enabled,
* the `git_threads_init()` function must be called
* before calling any other function of the library.
*
* This function allocates a TLS index (using pthreads
* or the native Win32 API) to store the global state
* on a per-thread basis.
*
* Any internal method that requires global state will
* then call `git__global_state()` which returns a pointer
* to the global state structure; this pointer is lazily
* allocated on each thread.
*
* Before shutting down the library, the
* `git_threads_shutdown` method must be called to free
* the previously reserved TLS index.
*
* If libgit2 is built without threading support, the
* `git__global_statestate()` call returns a pointer to a single,
* statically allocated global state. The `git_thread_`
* functions are not available in that case.
*/
#if defined(GIT_THREADS) && defined(GIT_WIN32)
static DWORD _tls_index;
static int _tls_init = 0;
void git_threads_init(void)
{
if (_tls_init)
return;
_tls_index = TlsAlloc();
_tls_init = 1;
}
void git_threads_shutdown(void)
{
TlsFree(_tls_index);
_tls_init = 0;
}
git_global_st *git__global_state(void)
{
void *ptr;
if ((ptr = TlsGetValue(_tls_index)) != NULL)
return ptr;
ptr = malloc(sizeof(git_global_st));
if (!ptr)
return NULL;
memset(ptr, 0x0, sizeof(git_global_st));
TlsSetValue(_tls_index, ptr);
return ptr;
}
#elif defined(GIT_THREADS) && defined(_POSIX_THREADS)
static pthread_key_t _tls_key;
static int _tls_init = 0;
static void cb__free_status(void *st)
{
free(st);
}
void git_threads_init(void)
{
if (_tls_init)
return;
pthread_key_create(&_tls_key, &cb__free_status);
_tls_init = 1;
}
void git_threads_shutdown(void)
{
pthread_key_delete(_tls_key);
_tls_init = 0;
}
git_global_st *git__global_state(void)
{
void *ptr;
if ((ptr = pthread_getspecific(_tls_key)) != NULL)
return ptr;
ptr = malloc(sizeof(git_global_st));
if (!ptr)
return NULL;
memset(ptr, 0x0, sizeof(git_global_st));
pthread_setspecific(_tls_key, ptr);
return ptr;
}
#else
static git_global_st __state;
void git_threads_init(void)
{
/* noop */
}
void git_threads_shutdown(void)
{
/* noop */
}
git_global_st *git__global_state(void)
{
return &__state;
}
#endif /* GIT_THREADS */
|