summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/common.h2
-rw-r--r--src/thread-utils.h83
-rw-r--r--tests/t0002-refcnt.c13
3 files changed, 97 insertions, 1 deletions
diff --git a/src/common.h b/src/common.h
index 89b6f61f7..61950787a 100644
--- a/src/common.h
+++ b/src/common.h
@@ -9,6 +9,7 @@
#include <inttypes.h>
#include <assert.h>
#include <errno.h>
+#include <limits.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
@@ -19,6 +20,7 @@
#include "cc-compat.h"
#include "util.h"
+#include "thread-utils.h"
#include "errors.h"
#define GIT_PATH_MAX 4096
diff --git a/src/thread-utils.h b/src/thread-utils.h
index 199447c2a..f5a98ad91 100644
--- a/src/thread-utils.h
+++ b/src/thread-utils.h
@@ -1,7 +1,88 @@
#ifndef INCLUDE_thread_utils_h__
#define INCLUDE_thread_utils_h__
-#include "git/thread-utils.h"
+#if defined(GIT_HAS_PTHREAD)
+typedef pthread_mutex_t git_lck;
+# define GITLCK_INIT PTHREAD_MUTEX_INITIALIZER
+# define gitlck_init(a) pthread_mutex_init(a, NULL)
+# define gitlck_lock(a) pthread_mutex_lock(a)
+# define gitlck_unlock(a) pthread_mutex_unlock(a)
+# define gitlck_free(a) pthread_mutex_destroy(a)
+
+# if defined(__GLIBC__)
+# include <asm/atomic.h>
+typedef atomic_t git_refcnt;
+# define gitrc_init(a) atomic_set(a, 0)
+# define gitrc_inc(a) atomic_inc_return(a)
+# define gitrc_dec(a) atomic_dec_and_test(a)
+# define gitrc_free(a) (void)0
+
+# else
+typedef struct { git_lck lock; int counter; } git_refcnt;
+
+/** Initialize to 0. No memory barrier is issued. */
+GIT_INLINE(void) gitrc_init(git_refcnt *p)
+{
+ gitlck_init(&p->lock);
+ p->counter = 0;
+}
+
+/**
+ * Increment.
+ *
+ * Atomically increments @p by 1. A memory barrier is also
+ * issued before and after the operation.
+ *
+ * @param p pointer of type git_refcnt
+ */
+GIT_INLINE(void) gitrc_inc(git_refcnt *p)
+{
+ gitlck_lock(&p->lock);
+ p->counter++;
+ gitlck_unlock(&p->lock);
+}
+
+/**
+ * Decrement and test.
+ *
+ * Atomically decrements @p by 1 and returns true if the
+ * result is 0, or false for all other cases. A memory
+ * barrier is also issued before and after the operation.
+ *
+ * @param p pointer of type git_refcnt
+ */
+GIT_INLINE(int) gitrc_dec(git_refcnt *p)
+{
+ int c;
+ gitlck_lock(&p->lock);
+ c = --p->counter;
+ gitlck_unlock(&p->lock);
+ return !!c;
+}
+
+/** Free any resources associated with the counter. */
+# define gitrc_free(p) gitlck_free(&(p)->lock)
+
+# endif
+
+#elif defined(GIT_THREADS)
+# error GIT_THREADS but no git_lck implementation
+
+#else
+typedef struct {} git_lck;
+# define GIT_MUTEX_INIT {}
+# define gitlck_init(a) (void)0
+# define gitlck_lock(a) (void)0
+# define gitlck_unlock(a) (void)0
+# define gitlck_free(a) (void)0
+
+typedef struct { int counter; } git_refcnt;
+# define gitrc_init(a) ((a)->counter = 0)
+# define gitrc_inc(a) ((a)->counter++)
+# define gitrc_dec(a) (--(a)->counter == 0)
+# define gitrc_free(a) (void)0
+
+#endif
extern int git_online_cpus(void);
diff --git a/tests/t0002-refcnt.c b/tests/t0002-refcnt.c
new file mode 100644
index 000000000..efa59b726
--- /dev/null
+++ b/tests/t0002-refcnt.c
@@ -0,0 +1,13 @@
+#include "test_lib.h"
+#include "common.h"
+
+BEGIN_TEST(init_inc2_dec2_free)
+ git_refcnt p;
+
+ gitrc_init(&p);
+ gitrc_inc(&p);
+ gitrc_inc(&p);
+ must_be_true(!gitrc_dec(&p));
+ must_be_true(gitrc_dec(&p));
+ gitrc_free(&p);
+END_TEST