Skip to content

Commit 34e685c

Browse files
authored
Merge pull request libgit2#5747 from lhchavez/atomic-tests
Homogenize semantics for atomic-related functions
2 parents 3f8bf8b + 74708a8 commit 34e685c

File tree

5 files changed

+234
-52
lines changed

5 files changed

+234
-52
lines changed

src/attrcache.c

Lines changed: 6 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -127,7 +127,7 @@ static int attr_cache_remove(git_attr_cache *cache, git_attr_file *file)
127127
{
128128
int error = 0;
129129
git_attr_file_entry *entry;
130-
git_attr_file *old = NULL;
130+
git_attr_file *oldfile = NULL;
131131

132132
if (!file)
133133
return 0;
@@ -136,13 +136,13 @@ static int attr_cache_remove(git_attr_cache *cache, git_attr_file *file)
136136
return error;
137137

138138
if ((entry = attr_cache_lookup_entry(cache, file->entry->path)) != NULL)
139-
old = git_atomic_compare_and_swap(&entry->file[file->source.type], file, NULL);
139+
oldfile = git_atomic_compare_and_swap(&entry->file[file->source.type], file, NULL);
140140

141141
attr_cache_unlock(cache);
142142

143-
if (old) {
144-
GIT_REFCOUNT_OWN(old, NULL);
145-
git_attr_file__free(old);
143+
if (oldfile == file) {
144+
GIT_REFCOUNT_OWN(file, NULL);
145+
git_attr_file__free(file);
146146
}
147147

148148
return error;
@@ -401,8 +401,7 @@ int git_attr_cache__init(git_repository *repo)
401401
(ret = git_pool_init(&cache->pool, 1)) < 0)
402402
goto cancel;
403403

404-
cache = git_atomic_compare_and_swap(&repo->attrcache, NULL, cache);
405-
if (cache)
404+
if (git_atomic_compare_and_swap(&repo->attrcache, NULL, cache) != NULL)
406405
goto cancel; /* raced with another thread, free this but no error */
407406

408407
git_config_free(cfg);

src/diff_driver.c

Lines changed: 15 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -141,18 +141,23 @@ static int diff_driver_funcname(const git_config_entry *entry, void *payload)
141141
static git_diff_driver_registry *git_repository_driver_registry(
142142
git_repository *repo)
143143
{
144-
if (!repo->diff_drivers) {
145-
git_diff_driver_registry *reg = git_diff_driver_registry_new();
146-
reg = git_atomic_compare_and_swap(&repo->diff_drivers, NULL, reg);
144+
git_diff_driver_registry *reg = git_atomic_load(repo->diff_drivers), *newreg;
145+
if (reg)
146+
return reg;
147147

148-
if (reg != NULL) /* if we race, free losing allocation */
149-
git_diff_driver_registry_free(reg);
150-
}
151-
152-
if (!repo->diff_drivers)
148+
newreg = git_diff_driver_registry_new();
149+
if (!newreg) {
153150
git_error_set(GIT_ERROR_REPOSITORY, "unable to create diff driver registry");
154-
155-
return repo->diff_drivers;
151+
return newreg;
152+
}
153+
reg = git_atomic_compare_and_swap(&repo->diff_drivers, NULL, newreg);
154+
if (!reg) {
155+
reg = newreg;
156+
} else {
157+
/* if we race, free losing allocation */
158+
git_diff_driver_registry_free(newreg);
159+
}
160+
return reg;
156161
}
157162

158163
static int diff_driver_alloc(

src/repository.c

Lines changed: 4 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1093,8 +1093,7 @@ int git_repository_config__weakptr(git_config **out, git_repository *repo)
10931093
if (!error) {
10941094
GIT_REFCOUNT_OWN(config, repo);
10951095

1096-
config = git_atomic_compare_and_swap(&repo->_config, NULL, config);
1097-
if (config != NULL) {
1096+
if (git_atomic_compare_and_swap(&repo->_config, NULL, config) != NULL) {
10981097
GIT_REFCOUNT_OWN(config, NULL);
10991098
git_config_free(config);
11001099
}
@@ -1164,8 +1163,7 @@ int git_repository_odb__weakptr(git_odb **out, git_repository *repo)
11641163
return error;
11651164
}
11661165

1167-
odb = git_atomic_compare_and_swap(&repo->_odb, NULL, odb);
1168-
if (odb != NULL) {
1166+
if (git_atomic_compare_and_swap(&repo->_odb, NULL, odb) != NULL) {
11691167
GIT_REFCOUNT_OWN(odb, NULL);
11701168
git_odb_free(odb);
11711169
}
@@ -1209,8 +1207,7 @@ int git_repository_refdb__weakptr(git_refdb **out, git_repository *repo)
12091207
if (!error) {
12101208
GIT_REFCOUNT_OWN(refdb, repo);
12111209

1212-
refdb = git_atomic_compare_and_swap(&repo->_refdb, NULL, refdb);
1213-
if (refdb != NULL) {
1210+
if (git_atomic_compare_and_swap(&repo->_refdb, NULL, refdb) != NULL) {
12141211
GIT_REFCOUNT_OWN(refdb, NULL);
12151212
git_refdb_free(refdb);
12161213
}
@@ -1257,8 +1254,7 @@ int git_repository_index__weakptr(git_index **out, git_repository *repo)
12571254
if (!error) {
12581255
GIT_REFCOUNT_OWN(index, repo);
12591256

1260-
index = git_atomic_compare_and_swap(&repo->_index, NULL, index);
1261-
if (index != NULL) {
1257+
if (git_atomic_compare_and_swap(&repo->_index, NULL, index) != NULL) {
12621258
GIT_REFCOUNT_OWN(index, NULL);
12631259
git_index_free(index);
12641260
}

src/thread.h

Lines changed: 84 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,9 @@ typedef git_atomic32 git_atomic_ssize;
7474
# include "unix/pthread.h"
7575
#endif
7676

77+
/*
78+
* Atomically sets the contents of *a to be val.
79+
*/
7780
GIT_INLINE(void) git_atomic32_set(git_atomic32 *a, int val)
7881
{
7982
#if defined(GIT_WIN32)
@@ -87,6 +90,10 @@ GIT_INLINE(void) git_atomic32_set(git_atomic32 *a, int val)
8790
#endif
8891
}
8992

93+
/*
94+
* Atomically increments the contents of *a by 1, and stores the result back into *a.
95+
* @return the result of the operation.
96+
*/
9097
GIT_INLINE(int) git_atomic32_inc(git_atomic32 *a)
9198
{
9299
#if defined(GIT_WIN32)
@@ -100,10 +107,14 @@ GIT_INLINE(int) git_atomic32_inc(git_atomic32 *a)
100107
#endif
101108
}
102109

110+
/*
111+
* Atomically adds the contents of *a and addend, and stores the result back into *a.
112+
* @return the result of the operation.
113+
*/
103114
GIT_INLINE(int) git_atomic32_add(git_atomic32 *a, int32_t addend)
104115
{
105116
#if defined(GIT_WIN32)
106-
return InterlockedExchangeAdd(&a->val, addend);
117+
return InterlockedAdd(&a->val, addend);
107118
#elif defined(GIT_BUILTIN_ATOMIC)
108119
return __atomic_add_fetch(&a->val, addend, __ATOMIC_SEQ_CST);
109120
#elif defined(GIT_BUILTIN_SYNC)
@@ -113,6 +124,10 @@ GIT_INLINE(int) git_atomic32_add(git_atomic32 *a, int32_t addend)
113124
#endif
114125
}
115126

127+
/*
128+
* Atomically decrements the contents of *a by 1, and stores the result back into *a.
129+
* @return the result of the operation.
130+
*/
116131
GIT_INLINE(int) git_atomic32_dec(git_atomic32 *a)
117132
{
118133
#if defined(GIT_WIN32)
@@ -126,6 +141,10 @@ GIT_INLINE(int) git_atomic32_dec(git_atomic32 *a)
126141
#endif
127142
}
128143

144+
/*
145+
* Atomically gets the contents of *a.
146+
* @return the contents of *a.
147+
*/
129148
GIT_INLINE(int) git_atomic32_get(git_atomic32 *a)
130149
{
131150
#if defined(GIT_WIN32)
@@ -143,16 +162,13 @@ GIT_INLINE(void *) git_atomic__compare_and_swap(
143162
void * volatile *ptr, void *oldval, void *newval)
144163
{
145164
#if defined(GIT_WIN32)
146-
volatile void *foundval;
147-
foundval = InterlockedCompareExchangePointer((volatile PVOID *)ptr, newval, oldval);
148-
return (foundval == oldval) ? oldval : newval;
165+
return InterlockedCompareExchangePointer((volatile PVOID *)ptr, newval, oldval);
149166
#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;
167+
void *foundval = oldval;
168+
__atomic_compare_exchange(ptr, &foundval, &newval, false, __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST);
169+
return foundval;
152170
#elif defined(GIT_BUILTIN_SYNC)
153-
volatile void *foundval;
154-
foundval = __sync_val_compare_and_swap(ptr, oldval, newval);
155-
return (foundval == oldval) ? oldval : newval;
171+
return __sync_val_compare_and_swap(ptr, oldval, newval);
156172
#else
157173
# error "Unsupported architecture for atomic operations"
158174
#endif
@@ -164,11 +180,11 @@ GIT_INLINE(volatile void *) git_atomic__swap(
164180
#if defined(GIT_WIN32)
165181
return InterlockedExchangePointer(ptr, newval);
166182
#elif defined(GIT_BUILTIN_ATOMIC)
167-
void * volatile foundval;
183+
void * volatile foundval = NULL;
168184
__atomic_exchange(ptr, &newval, &foundval, __ATOMIC_SEQ_CST);
169185
return foundval;
170186
#elif defined(GIT_BUILTIN_SYNC)
171-
return __sync_lock_test_and_set(ptr, newval);
187+
return (volatile void *)__sync_lock_test_and_set(ptr, newval);
172188
#else
173189
# error "Unsupported architecture for atomic operations"
174190
#endif
@@ -178,9 +194,7 @@ GIT_INLINE(volatile void *) git_atomic__load(void * volatile *ptr)
178194
{
179195
#if defined(GIT_WIN32)
180196
void *newval = NULL, *oldval = NULL;
181-
volatile void *foundval = NULL;
182-
foundval = InterlockedCompareExchangePointer((volatile PVOID *)ptr, newval, oldval);
183-
return foundval;
197+
return (volatile void *)InterlockedCompareExchangePointer((volatile PVOID *)ptr, newval, oldval);
184198
#elif defined(GIT_BUILTIN_ATOMIC)
185199
return (volatile void *)__atomic_load_n(ptr, __ATOMIC_SEQ_CST);
186200
#elif defined(GIT_BUILTIN_SYNC)
@@ -192,10 +206,14 @@ GIT_INLINE(volatile void *) git_atomic__load(void * volatile *ptr)
192206

193207
#ifdef GIT_ARCH_64
194208

209+
/*
210+
* Atomically adds the contents of *a and addend, and stores the result back into *a.
211+
* @return the result of the operation.
212+
*/
195213
GIT_INLINE(int64_t) git_atomic64_add(git_atomic64 *a, int64_t addend)
196214
{
197215
#if defined(GIT_WIN32)
198-
return InterlockedExchangeAdd64(&a->val, addend);
216+
return InterlockedAdd64(&a->val, addend);
199217
#elif defined(GIT_BUILTIN_ATOMIC)
200218
return __atomic_add_fetch(&a->val, addend, __ATOMIC_SEQ_CST);
201219
#elif defined(GIT_BUILTIN_SYNC)
@@ -205,6 +223,9 @@ GIT_INLINE(int64_t) git_atomic64_add(git_atomic64 *a, int64_t addend)
205223
#endif
206224
}
207225

226+
/*
227+
* Atomically sets the contents of *a to be val.
228+
*/
208229
GIT_INLINE(void) git_atomic64_set(git_atomic64 *a, int64_t val)
209230
{
210231
#if defined(GIT_WIN32)
@@ -218,6 +239,10 @@ GIT_INLINE(void) git_atomic64_set(git_atomic64 *a, int64_t val)
218239
#endif
219240
}
220241

242+
/*
243+
* Atomically gets the contents of *a.
244+
* @return the contents of *a.
245+
*/
221246
GIT_INLINE(int64_t) git_atomic64_get(git_atomic64 *a)
222247
{
223248
#if defined(GIT_WIN32)
@@ -297,11 +322,10 @@ GIT_INLINE(int) git_atomic32_get(git_atomic32 *a)
297322
GIT_INLINE(void *) git_atomic__compare_and_swap(
298323
void * volatile *ptr, void *oldval, void *newval)
299324
{
300-
if (*ptr == oldval)
325+
void *foundval = *ptr;
326+
if (foundval == oldval)
301327
*ptr = newval;
302-
else
303-
oldval = newval;
304-
return oldval;
328+
return foundval;
305329
}
306330

307331
GIT_INLINE(volatile void *) git_atomic__swap(
@@ -339,17 +363,50 @@ GIT_INLINE(int64_t) git_atomic64_get(git_atomic64 *a)
339363

340364
#endif
341365

342-
/* Atomically replace oldval with newval
343-
* @return oldval if it was replaced or newval if it was not
366+
/*
367+
* Atomically replace the contents of *ptr (if they are equal to oldval) with
368+
* newval. ptr must point to a pointer or a value that is the same size as a
369+
* pointer. This is semantically compatible with:
370+
*
371+
* #define git_atomic_compare_and_swap(ptr, oldval, newval) \
372+
* ({ \
373+
* void *foundval = *ptr; \
374+
* if (foundval == oldval) \
375+
* *ptr = newval; \
376+
* foundval; \
377+
* })
378+
*
379+
* @return the original contents of *ptr.
344380
*/
345-
#define git_atomic_compare_and_swap(P,O,N) \
346-
git_atomic__compare_and_swap((void * volatile *)P, O, N)
381+
#define git_atomic_compare_and_swap(ptr, oldval, newval) \
382+
git_atomic__compare_and_swap((void * volatile *)ptr, oldval, newval)
347383

348-
#define git_atomic_swap(ptr, val) \
349-
(void *)git_atomic__swap((void * volatile *)&ptr, val)
384+
/*
385+
* Atomically replace the contents of v with newval. v must be the same size as
386+
* a pointer. This is semantically compatible with:
387+
*
388+
* #define git_atomic_swap(v, newval) \
389+
* ({ \
390+
* volatile void *old = v; \
391+
* v = newval; \
392+
* old; \
393+
* })
394+
*
395+
* @return the original contents of v.
396+
*/
397+
#define git_atomic_swap(v, newval) \
398+
(void *)git_atomic__swap((void * volatile *)&(v), newval)
350399

351-
#define git_atomic_load(ptr) \
352-
(void *)git_atomic__load((void * volatile *)&ptr)
400+
/*
401+
* Atomically reads the contents of v. v must be the same size as a pointer.
402+
* This is semantically compatible with:
403+
*
404+
* #define git_atomic_load(v) v
405+
*
406+
* @return the contents of v.
407+
*/
408+
#define git_atomic_load(v) \
409+
(void *)git_atomic__load((void * volatile *)&(v))
353410

354411
#if defined(GIT_THREADS)
355412

0 commit comments

Comments
 (0)