summaryrefslogtreecommitdiff
path: root/src/thread-utils.h
diff options
context:
space:
mode:
authorRussell Belfer <rb@github.com>2013-04-15 14:27:53 -0700
committerVicent Marti <tanoku@gmail.com>2013-04-22 16:52:07 +0200
commite976b56dda6ae3d7d81bd114b61750e97cc918d3 (patch)
treeaa06f2e71988f294a5465911009f223a9886eea0 /src/thread-utils.h
parent536078688549ac3d50483eecdec5a8169d921927 (diff)
downloadlibgit2-e976b56dda6ae3d7d81bd114b61750e97cc918d3.tar.gz
Add git__compare_and_swap and use it
This removes the lock from the repository object and changes the internals to use the new atomic git__compare_and_swap to update the _odb, _config, _index, and _refdb variables in a threadsafe manner.
Diffstat (limited to 'src/thread-utils.h')
-rw-r--r--src/thread-utils.h41
1 files changed, 41 insertions, 0 deletions
diff --git a/src/thread-utils.h b/src/thread-utils.h
index 2ca290adf..7b663182d 100644
--- a/src/thread-utils.h
+++ b/src/thread-utils.h
@@ -68,6 +68,21 @@ GIT_INLINE(int) git_atomic_dec(git_atomic *a)
#endif
}
+GIT_INLINE(void *) git___compare_and_swap(
+ volatile void **ptr, void *oldval, void *newval)
+{
+ bool swapped;
+#if defined(GIT_WIN32)
+ swapped = ((LONGLONG)oldval == InterlockedCompareExchange64(
+ (LONGLONG volatile *)ptr, (LONGLONG)newval, (LONGLONG)oldval));
+#elif defined(__GNUC__)
+ swapped = (__sync_val_compare_and_swap(ptr, oldval, newval) == oldval);
+#else
+# error "Unsupported architecture for atomic operations"
+#endif
+ return swapped ? oldval : newval;
+}
+
#else
#define git_thread unsigned int
@@ -101,8 +116,34 @@ GIT_INLINE(int) git_atomic_dec(git_atomic *a)
return --a->val;
}
+GIT_INLINE(void *) git___compare_and_swap(
+ volatile void **ptr, void *oldval, void *newval)
+{
+ if (*ptr == oldval)
+ *ptr = newval;
+ else
+ oldval = newval;
+ return oldval;
+}
+
#endif
+/* Atomically replace oldval with newval
+ * @return oldval if it was replaced or newval if it was not
+ */
+#define git__compare_and_swap(P,O,N) \
+ git___compare_and_swap((volatile void **)P, O, N)
+
+#define git__swap(ptr, val) git__compare_and_swap(&ptr, ptr, val)
+
extern int git_online_cpus(void);
+#if defined(GIT_THREADS) && defined(GIT_WIN32)
+# define GIT_MEMORY_BARRIER MemoryBarrier()
+#elif defined(GIT_THREADS)
+# define GIT_MEMORY_BARRIER __sync_synchronize()
+#else
+# define GIT_MEMORY_BARRIER /* noop */
+#endif
+
#endif /* INCLUDE_thread_utils_h__ */