@@ -73,47 +73,69 @@ static void git__shutdown(void)
73
73
#if defined(GIT_THREADS ) && defined(GIT_WIN32 )
74
74
75
75
static DWORD _tls_index ;
76
- static int _tls_init = 0 ;
76
+ static DWORD _mutex = 0 ;
77
+ static DWORD _n_inits = 0 ;
77
78
78
- int git_threads_init ( void )
79
+ static int synchronized_threads_init ( )
79
80
{
80
81
int error ;
81
82
82
- if (_tls_init )
83
- return 0 ;
84
-
85
83
_tls_index = TlsAlloc ();
86
84
if (git_mutex_init (& git__mwindow_mutex ))
87
85
return -1 ;
88
86
89
87
/* Initialize any other subsystems that have global state */
90
- if ((error = git_hash_global_init ()) >= 0 &&
91
- (error = git_futils_dirs_global_init ()) >= 0 )
92
- _tls_init = 1 ;
93
-
94
- GIT_MEMORY_BARRIER ;
88
+ if ((error = git_hash_global_init ()) >= 0 )
89
+ error = git_futils_dirs_global_init ();
95
90
96
91
win32_pthread_initialize ();
97
92
98
93
return error ;
99
94
}
100
95
101
- void git_threads_shutdown (void )
96
+ int git_threads_init (void )
97
+ {
98
+ int error = 0 ;
99
+
100
+ /* Enter the lock */
101
+ while (InterlockedCompareExchange (& _mutex , 1 , 0 )) { Sleep (0 ); }
102
+
103
+ /* Only do work on a 0 -> 1 transition of the refcount */
104
+ if (1 == ++ _n_inits )
105
+ error = synchronized_threads_init ();
106
+
107
+ /* Exit the lock */
108
+ InterlockedExchange (& _mutex , 0 );
109
+
110
+ return error ;
111
+ }
112
+
113
+ static void synchronized_threads_shutdown ()
102
114
{
103
115
/* Shut down any subsystems that have global state */
104
116
git__shutdown ();
105
-
106
117
TlsFree (_tls_index );
107
- _tls_init = 0 ;
108
-
109
118
git_mutex_free (& git__mwindow_mutex );
110
119
}
111
120
121
+ void git_threads_shutdown (void )
122
+ {
123
+ /* Enter the lock */
124
+ while (InterlockedCompareExchange (& _mutex , 1 , 0 )) { Sleep (0 ); }
125
+
126
+ /* Only do work on a 1 -> 0 transition of the refcount */
127
+ if (0 == -- _n_inits )
128
+ synchronized_threads_shutdown ();
129
+
130
+ /* Exit the lock */
131
+ InterlockedExchange (& _mutex , 0 );
132
+ }
133
+
112
134
git_global_st * git__global_state (void )
113
135
{
114
136
void * ptr ;
115
137
116
- assert (_tls_init );
138
+ assert (_n_inits );
117
139
118
140
if ((ptr = TlsGetValue (_tls_index )) != NULL )
119
141
return ptr ;
@@ -130,55 +152,58 @@ git_global_st *git__global_state(void)
130
152
#elif defined(GIT_THREADS ) && defined(_POSIX_THREADS )
131
153
132
154
static pthread_key_t _tls_key ;
133
- static int _tls_init = 0 ;
155
+ static pthread_once_t _once_init = PTHREAD_ONCE_INIT ;
156
+ static git_atomic git__n_inits ;
157
+ int init_error = 0 ;
134
158
135
159
static void cb__free_status (void * st )
136
160
{
137
161
git__free (st );
138
162
}
139
163
140
- int git_threads_init (void )
164
+ static void init_once (void )
141
165
{
142
- int error = 0 ;
143
-
144
- if (_tls_init )
145
- return 0 ;
146
-
147
- if (git_mutex_init (& git__mwindow_mutex ))
148
- return -1 ;
166
+ if ((init_error = git_mutex_init (& git__mwindow_mutex )) != 0 )
167
+ return ;
149
168
pthread_key_create (& _tls_key , & cb__free_status );
150
169
151
170
/* Initialize any other subsystems that have global state */
152
- if ((error = git_hash_global_init ()) >= 0 &&
153
- (error = git_futils_dirs_global_init ()) >= 0 )
154
- _tls_init = 1 ;
171
+ if ((init_error = git_hash_global_init ()) >= 0 )
172
+ init_error = git_futils_dirs_global_init ();
155
173
156
174
GIT_MEMORY_BARRIER ;
175
+ }
157
176
158
- return error ;
177
+ int git_threads_init (void )
178
+ {
179
+ pthread_once (& _once_init , init_once );
180
+ git_atomic_inc (& git__n_inits );
181
+ return init_error ;
159
182
}
160
183
161
184
void git_threads_shutdown (void )
162
185
{
186
+ pthread_once_t new_once = PTHREAD_ONCE_INIT ;
187
+
188
+ if (git_atomic_dec (& git__n_inits ) > 0 ) return ;
189
+
163
190
/* Shut down any subsystems that have global state */
164
191
git__shutdown ();
165
192
166
- if (_tls_init ) {
167
- void * ptr = pthread_getspecific (_tls_key );
168
- pthread_setspecific (_tls_key , NULL );
169
- git__free (ptr );
170
- }
193
+ void * ptr = pthread_getspecific (_tls_key );
194
+ pthread_setspecific (_tls_key , NULL );
195
+ git__free (ptr );
171
196
172
197
pthread_key_delete (_tls_key );
173
- _tls_init = 0 ;
174
198
git_mutex_free (& git__mwindow_mutex );
199
+ _once_init = new_once ;
175
200
}
176
201
177
202
git_global_st * git__global_state (void )
178
203
{
179
204
void * ptr ;
180
205
181
- assert (_tls_init );
206
+ assert (git__n_inits . val );
182
207
183
208
if ((ptr = pthread_getspecific (_tls_key )) != NULL )
184
209
return ptr ;
0 commit comments