Skip to content

Commit 6244791

Browse files
authored
Merge pull request libgit2#5594 from lhchavez/git-atomics
Improve the support of atomics
2 parents 2307a22 + 03c0938 commit 6244791

File tree

7 files changed

+171
-41
lines changed

7 files changed

+171
-41
lines changed

src/cache.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -168,7 +168,7 @@ static void *cache_store(git_cache *cache, git_cached_obj *entry)
168168
return entry;
169169

170170
/* soften the load on the cache */
171-
if (git_cache__current_storage.val > git_cache__max_storage)
171+
if (git_atomic_ssize_get(&git_cache__current_storage) > git_cache__max_storage)
172172
cache_evict_entries(cache);
173173

174174
/* not found */

src/global.c

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
#include "sysdir.h"
1313
#include "filter.h"
1414
#include "merge_driver.h"
15+
#include "pool.h"
1516
#include "streams/registry.h"
1617
#include "streams/mbedtls.h"
1718
#include "streams/openssl.h"
@@ -38,7 +39,8 @@ static git_global_init_fn git__init_callbacks[] = {
3839
git_stream_registry_global_init,
3940
git_openssl_stream_global_init,
4041
git_mbedtls_stream_global_init,
41-
git_mwindow_global_init
42+
git_mwindow_global_init,
43+
git_pool_global_init
4244
};
4345

4446
static git_global_shutdown_fn git__shutdown_callbacks[ARRAY_SIZE(git__init_callbacks)];

src/odb.c

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -44,8 +44,8 @@ typedef struct
4444

4545
static git_cache *odb_cache(git_odb *odb)
4646
{
47-
if (odb->rc.owner != NULL) {
48-
git_repository *owner = odb->rc.owner;
47+
git_repository *owner = GIT_REFCOUNT_OWNER(odb);
48+
if (owner != NULL) {
4949
return &owner->objects;
5050
}
5151

@@ -664,7 +664,7 @@ int git_odb_open(git_odb **out, const char *objects_dir)
664664
int git_odb__set_caps(git_odb *odb, int caps)
665665
{
666666
if (caps == GIT_ODB_CAP_FROM_OWNER) {
667-
git_repository *repo = odb->rc.owner;
667+
git_repository *repo = GIT_REFCOUNT_OWNER(odb);
668668
int val;
669669

670670
if (!repo) {

src/pool.c

Lines changed: 15 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -21,30 +21,27 @@ struct git_pool_page {
2121

2222
static void *pool_alloc_page(git_pool *pool, size_t size);
2323

24-
static size_t pool_system_page_size(void)
25-
{
26-
static size_t size = 0;
24+
#ifndef GIT_DEBUG_POOL
2725

28-
if (!size) {
29-
size_t page_size;
30-
if (git__page_size(&page_size) < 0)
31-
page_size = 4096;
32-
/* allow space for malloc overhead */
33-
size = (page_size - (2 * sizeof(void *)) - sizeof(git_pool_page));
34-
}
26+
static size_t system_page_size = 0;
3527

36-
return size;
28+
int git_pool_global_init(void)
29+
{
30+
if (git__page_size(&system_page_size) < 0)
31+
system_page_size = 4096;
32+
/* allow space for malloc overhead */
33+
system_page_size -= (2 * sizeof(void *)) + sizeof(git_pool_page);
34+
return 0;
3735
}
3836

39-
#ifndef GIT_DEBUG_POOL
4037
int git_pool_init(git_pool *pool, size_t item_size)
4138
{
4239
assert(pool);
4340
assert(item_size >= 1);
4441

4542
memset(pool, 0, sizeof(git_pool));
4643
pool->item_size = item_size;
47-
pool->page_size = pool_system_page_size();
44+
pool->page_size = system_page_size;
4845

4946
return 0;
5047
}
@@ -114,6 +111,11 @@ bool git_pool__ptr_in_pool(git_pool *pool, void *ptr)
114111

115112
#else
116113

114+
int git_pool_global_init(void)
115+
{
116+
return 0;
117+
}
118+
117119
static int git_pool__ptr_cmp(const void * a, const void * b)
118120
{
119121
if(a > b) {

src/pool.h

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -135,4 +135,12 @@ extern uint32_t git_pool__open_pages(git_pool *pool);
135135
#endif
136136
extern bool git_pool__ptr_in_pool(git_pool *pool, void *ptr);
137137

138+
/**
139+
* This function is being called by our global setup routines to
140+
* initialize the system pool size.
141+
*
142+
* @return 0 on success, <0 on failure
143+
*/
144+
extern int git_pool_global_init(void);
145+
138146
#endif

src/thread-utils.h

Lines changed: 139 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -7,12 +7,30 @@
77
#ifndef INCLUDE_thread_utils_h__
88
#define INCLUDE_thread_utils_h__
99

10-
#if defined(__GNUC__) && defined(GIT_THREADS)
10+
#if defined(GIT_THREADS)
11+
12+
#if defined(__clang__)
13+
14+
# if (__clang_major__ < 3 || (__clang_major__ == 3 && __clang_minor__ < 1))
15+
# error Atomic primitives do not exist on this version of clang; configure libgit2 with -DTHREADSAFE=OFF
16+
# else
17+
# define GIT_BUILTIN_ATOMIC
18+
# endif
19+
20+
#elif defined(__GNUC__)
21+
1122
# if (__GNUC__ < 4 || (__GNUC__ == 4 && __GNUC_MINOR__ < 1))
1223
# error Atomic primitives do not exist on this version of gcc; configure libgit2 with -DTHREADSAFE=OFF
24+
# elif (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 7))
25+
# define GIT_BUILTIN_ATOMIC
26+
# else
27+
# define GIT_BUILTIN_SYNC
1328
# endif
29+
1430
#endif
1531

32+
#endif /* GIT_THREADS */
33+
1634
/* Common operations even if threading has been disabled */
1735
typedef struct {
1836
#if defined(GIT_WIN32)
@@ -26,21 +44,25 @@ typedef struct {
2644

2745
typedef struct {
2846
#if defined(GIT_WIN32)
29-
__int64 val;
47+
volatile __int64 val;
3048
#else
31-
int64_t val;
49+
volatile int64_t val;
3250
#endif
3351
} git_atomic64;
3452

3553
typedef git_atomic64 git_atomic_ssize;
3654

55+
#define git_atomic_ssize_set git_atomic64_set
3756
#define git_atomic_ssize_add git_atomic64_add
57+
#define git_atomic_ssize_get git_atomic64_get
3858

3959
#else
4060

4161
typedef git_atomic git_atomic_ssize;
4262

63+
#define git_atomic_ssize_set git_atomic_set
4364
#define git_atomic_ssize_add git_atomic_add
65+
#define git_atomic_ssize_get git_atomic_get
4466

4567
#endif
4668

@@ -56,7 +78,9 @@ GIT_INLINE(void) git_atomic_set(git_atomic *a, int val)
5678
{
5779
#if defined(GIT_WIN32)
5880
InterlockedExchange(&a->val, (LONG)val);
59-
#elif defined(__GNUC__)
81+
#elif defined(GIT_BUILTIN_ATOMIC)
82+
__atomic_store_n(&a->val, val, __ATOMIC_SEQ_CST);
83+
#elif defined(GIT_BUILTIN_SYNC)
6084
__sync_lock_test_and_set(&a->val, val);
6185
#else
6286
# error "Unsupported architecture for atomic operations"
@@ -67,7 +91,9 @@ GIT_INLINE(int) git_atomic_inc(git_atomic *a)
6791
{
6892
#if defined(GIT_WIN32)
6993
return InterlockedIncrement(&a->val);
70-
#elif defined(__GNUC__)
94+
#elif defined(GIT_BUILTIN_ATOMIC)
95+
return __atomic_add_fetch(&a->val, 1, __ATOMIC_SEQ_CST);
96+
#elif defined(GIT_BUILTIN_SYNC)
7197
return __sync_add_and_fetch(&a->val, 1);
7298
#else
7399
# error "Unsupported architecture for atomic operations"
@@ -78,7 +104,9 @@ GIT_INLINE(int) git_atomic_add(git_atomic *a, int32_t addend)
78104
{
79105
#if defined(GIT_WIN32)
80106
return InterlockedExchangeAdd(&a->val, addend);
81-
#elif defined(__GNUC__)
107+
#elif defined(GIT_BUILTIN_ATOMIC)
108+
return __atomic_add_fetch(&a->val, addend, __ATOMIC_SEQ_CST);
109+
#elif defined(GIT_BUILTIN_SYNC)
82110
return __sync_add_and_fetch(&a->val, addend);
83111
#else
84112
# error "Unsupported architecture for atomic operations"
@@ -89,34 +117,76 @@ GIT_INLINE(int) git_atomic_dec(git_atomic *a)
89117
{
90118
#if defined(GIT_WIN32)
91119
return InterlockedDecrement(&a->val);
92-
#elif defined(__GNUC__)
120+
#elif defined(GIT_BUILTIN_ATOMIC)
121+
return __atomic_sub_fetch(&a->val, 1, __ATOMIC_SEQ_CST);
122+
#elif defined(GIT_BUILTIN_SYNC)
93123
return __sync_sub_and_fetch(&a->val, 1);
94124
#else
95125
# error "Unsupported architecture for atomic operations"
96126
#endif
97127
}
98128

129+
GIT_INLINE(int) git_atomic_get(git_atomic *a)
130+
{
131+
#if defined(GIT_WIN32)
132+
return (int)InterlockedCompareExchange(&a->val, 0, 0);
133+
#elif defined(GIT_BUILTIN_ATOMIC)
134+
return __atomic_load_n(&a->val, __ATOMIC_SEQ_CST);
135+
#elif defined(GIT_BUILTIN_SYNC)
136+
return __sync_val_compare_and_swap(&a->val, 0, 0);
137+
#else
138+
# error "Unsupported architecture for atomic operations"
139+
#endif
140+
}
141+
99142
GIT_INLINE(void *) git___compare_and_swap(
100143
void * volatile *ptr, void *oldval, void *newval)
101144
{
102-
volatile void *foundval;
103145
#if defined(GIT_WIN32)
146+
volatile void *foundval;
104147
foundval = InterlockedCompareExchangePointer((volatile PVOID *)ptr, newval, oldval);
105-
#elif defined(__GNUC__)
148+
return (foundval == oldval) ? oldval : newval;
149+
#elif defined(GIT_BUILTIN_ATOMIC)
150+
bool success = __atomic_compare_exchange(ptr, &oldval, &newval, false, __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST);
151+
return success ? oldval : newval;
152+
#elif defined(GIT_BUILTIN_SYNC)
153+
volatile void *foundval;
106154
foundval = __sync_val_compare_and_swap(ptr, oldval, newval);
155+
return (foundval == oldval) ? oldval : newval;
107156
#else
108157
# error "Unsupported architecture for atomic operations"
109158
#endif
110-
return (foundval == oldval) ? oldval : newval;
111159
}
112160

113161
GIT_INLINE(volatile void *) git___swap(
114162
void * volatile *ptr, void *newval)
115163
{
116164
#if defined(GIT_WIN32)
117165
return InterlockedExchangePointer(ptr, newval);
118-
#else
166+
#elif defined(GIT_BUILTIN_ATOMIC)
167+
void * volatile foundval;
168+
__atomic_exchange(ptr, &newval, &foundval, __ATOMIC_SEQ_CST);
169+
return foundval;
170+
#elif defined(GIT_BUILTIN_SYNC)
119171
return __sync_lock_test_and_set(ptr, newval);
172+
#else
173+
# error "Unsupported architecture for atomic operations"
174+
#endif
175+
}
176+
177+
GIT_INLINE(volatile void *) git___load(void * volatile *ptr)
178+
{
179+
#if defined(GIT_WIN32)
180+
void *newval = NULL, *oldval = NULL;
181+
volatile void *foundval = NULL;
182+
foundval = InterlockedCompareExchangePointer((volatile PVOID *)ptr, newval, oldval);
183+
return foundval;
184+
#elif defined(GIT_BUILTIN_ATOMIC)
185+
return (volatile void *)__atomic_load_n(ptr, __ATOMIC_SEQ_CST);
186+
#elif defined(GIT_BUILTIN_SYNC)
187+
return (volatile void *)__sync_val_compare_and_swap(ptr, 0, 0);
188+
#else
189+
# error "Unsupported architecture for atomic operations"
120190
#endif
121191
}
122192

@@ -126,13 +196,41 @@ GIT_INLINE(int64_t) git_atomic64_add(git_atomic64 *a, int64_t addend)
126196
{
127197
#if defined(GIT_WIN32)
128198
return InterlockedExchangeAdd64(&a->val, addend);
129-
#elif defined(__GNUC__)
199+
#elif defined(GIT_BUILTIN_ATOMIC)
200+
return __atomic_add_fetch(&a->val, addend, __ATOMIC_SEQ_CST);
201+
#elif defined(GIT_BUILTIN_SYNC)
130202
return __sync_add_and_fetch(&a->val, addend);
131203
#else
132204
# error "Unsupported architecture for atomic operations"
133205
#endif
134206
}
135207

208+
GIT_INLINE(void) git_atomic64_set(git_atomic64 *a, int64_t val)
209+
{
210+
#if defined(GIT_WIN32)
211+
InterlockedExchange64(&a->val, val);
212+
#elif defined(GIT_BUILTIN_ATOMIC)
213+
__atomic_store_n(&a->val, val, __ATOMIC_SEQ_CST);
214+
#elif defined(GIT_BUILTIN_SYNC)
215+
__sync_lock_test_and_set(&a->val, val);
216+
#else
217+
# error "Unsupported architecture for atomic operations"
218+
#endif
219+
}
220+
221+
GIT_INLINE(int64_t) git_atomic64_get(git_atomic64 *a)
222+
{
223+
#if defined(GIT_WIN32)
224+
return (int64_t)InterlockedCompareExchange64(&a->val, 0, 0);
225+
#elif defined(GIT_BUILTIN_ATOMIC)
226+
return __atomic_load_n(&a->val, __ATOMIC_SEQ_CST);
227+
#elif defined(GIT_BUILTIN_SYNC)
228+
return __sync_val_compare_and_swap(&a->val, 0, 0);
229+
#else
230+
# error "Unsupported architecture for atomic operations"
231+
#endif
232+
}
233+
136234
#endif
137235

138236
#else
@@ -190,6 +288,11 @@ GIT_INLINE(int) git_atomic_dec(git_atomic *a)
190288
return --a->val;
191289
}
192290

291+
GIT_INLINE(int) git_atomic_get(git_atomic *a)
292+
{
293+
return (int)a->val;
294+
}
295+
193296
GIT_INLINE(void *) git___compare_and_swap(
194297
void * volatile *ptr, void *oldval, void *newval)
195298
{
@@ -216,15 +319,20 @@ GIT_INLINE(int64_t) git_atomic64_add(git_atomic64 *a, int64_t addend)
216319
return a->val;
217320
}
218321

219-
#endif
220-
221-
#endif
322+
GIT_INLINE(void) git_atomic64_set(git_atomic64 *a, int64_t val)
323+
{
324+
a->val = val;
325+
}
222326

223-
GIT_INLINE(int) git_atomic_get(git_atomic *a)
327+
GIT_INLINE(int64_t) git_atomic64_get(git_atomic64 *a)
224328
{
225-
return (int)a->val;
329+
return (int64_t)a->val;
226330
}
227331

332+
#endif
333+
334+
#endif
335+
228336
/* Atomically replace oldval with newval
229337
* @return oldval if it was replaced or newval if it was not
230338
*/
@@ -233,14 +341,24 @@ GIT_INLINE(int) git_atomic_get(git_atomic *a)
233341

234342
#define git__swap(ptr, val) (void *)git___swap((void * volatile *)&ptr, val)
235343

344+
#define git__load(ptr) (void *)git___load((void * volatile *)&ptr)
345+
236346
extern int git_online_cpus(void);
237347

238-
#if defined(GIT_THREADS) && defined(_MSC_VER)
239-
# define GIT_MEMORY_BARRIER MemoryBarrier()
240-
#elif defined(GIT_THREADS)
241-
# define GIT_MEMORY_BARRIER __sync_synchronize()
348+
#if defined(GIT_THREADS)
349+
350+
# if defined(GIT_WIN32)
351+
# define GIT_MEMORY_BARRIER MemoryBarrier()
352+
# elif defined(GIT_BUILTIN_ATOMIC)
353+
# define GIT_MEMORY_BARRIER __atomic_thread_fence(__ATOMIC_SEQ_CST)
354+
# elif defined(GIT_BUILTIN_SYNC)
355+
# define GIT_MEMORY_BARRIER __sync_synchronize()
356+
# endif
357+
242358
#else
359+
243360
# define GIT_MEMORY_BARRIER /* noop */
361+
244362
#endif
245363

246364
#endif

0 commit comments

Comments
 (0)