diff --git a/README.md b/README.md
index c9eb6dc25..05378685b 100644
--- a/README.md
+++ b/README.md
@@ -34,15 +34,17 @@ libgit2 is already very usable.
Building libgit2 - External dependencies
========================================
-libgit2 builds cleanly on most platforms without any external dependencies. However, the following libraries
-may be used on some platforms.
+libgit2 builds cleanly on most platforms without any external dependencies.
+Under Unix-like systems, like Linux, *BSD and Mac OS X, libgit2 expects `pthreads` to be available;
+they should be installed by default on all systems. Under Windows, libgit2 uses the native Windows API
+for threading.
+
+Additionally, he following libraries may be used as replacement for built-in functionality:
* LibSSL **(optional)**
libgit2 can be built using the SHA1 implementation of LibSSL-Crypto, instead of the built-in custom implementations. Performance wise, they are quite similar.
-* pthreads-w32 **(required for MinGW)**
-
Building libgit2 - Using waf
======================
diff --git a/include/git2/thread-utils.h b/include/git2/thread-utils.h
index c45a76e95..ecb09bb53 100644
--- a/include/git2/thread-utils.h
+++ b/include/git2/thread-utils.h
@@ -32,7 +32,6 @@
*/
#define GIT_HAS_TLS 1
-#define GIT_HAS_PTHREAD 1
#if defined(__APPLE__) && defined(__MACH__)
# undef GIT_TLS
@@ -47,7 +46,6 @@
#elif defined(__INTEL_COMPILER)
# if defined(_WIN32) || defined(_WIN32_CE)
# define GIT_TLS __declspec(thread)
-# undef GIT_HAS_PTHREAD
# else
# define GIT_TLS __thread
# endif
@@ -56,11 +54,9 @@
defined(_WIN32_CE) || \
defined(__BORLANDC__)
# define GIT_TLS __declspec(thread)
-# undef GIT_HAS_PTHREAD
#else
# undef GIT_HAS_TLS
-# undef GIT_HAS_PTHREAD
# define GIT_TLS /* nothing: tls vars are thread-global */
#endif
@@ -71,10 +67,6 @@
# define GIT_TLS
#endif
-#ifdef GIT_HAS_PTHREAD
-# define GIT_THREADS 1
-#else
-# undef GIT_THREADS
-#endif
+#define GIT_THREADS 1
#endif /* INCLUDE_git_thread_utils_h__ */
diff --git a/src/common.h b/src/common.h
index 1ca00471b..723085a2b 100644
--- a/src/common.h
+++ b/src/common.h
@@ -11,9 +11,6 @@
#include "git2/thread-utils.h"
#include "cc-compat.h"
-#ifdef GIT_HAS_PTHREAD
-# include
-#endif
#ifdef GIT_HAVE_INTTYPES_H
# include
#endif
@@ -34,6 +31,7 @@
# include
# include "msvc-compat.h"
# include "mingw-compat.h"
+# include "win32/pthread.h"
# define snprintf _snprintf
@@ -43,6 +41,7 @@ typedef SSIZE_T ssize_t;
# include
# include
+# include
#endif
diff --git a/src/thread-utils.h b/src/thread-utils.h
index 0029e4bc1..e8372e731 100644
--- a/src/thread-utils.h
+++ b/src/thread-utils.h
@@ -1,108 +1,27 @@
#ifndef INCLUDE_thread_utils_h__
#define INCLUDE_thread_utils_h__
-#if defined(GIT_HAS_PTHREAD)
- typedef pthread_t git_thread;
-# define git_thread_create(thread, attr, start_routine, arg) pthread_create(thread, attr, start_routine, arg)
-# define git_thread_kill(thread) pthread_cancel(thread)
-# define git_thread_exit(status) pthread_exit(status)
-# define git_thread_join(id, status) pthread_join(id, status)
- /* Pthreads Mutex */
- 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)
+#define git_thread pthread_t
+#define git_thread_create(thread, attr, start_routine, arg) pthread_create(thread, attr, start_routine, arg)
+#define git_thread_kill(thread) pthread_cancel(thread)
+#define git_thread_exit(status) pthread_exit(status)
+#define git_thread_join(id, status) pthread_join(id, status)
- /* Pthreads condition vars */
- typedef pthread_cond_t git_cnd;
-# define GITCND_INIT PTHREAD_COND_INITIALIZER
-# define gitcnd_init(c, a) pthread_cond_init(c, a)
-# define gitcnd_free(c) pthread_cond_destroy(c)
-# define gitcnd_wait(c, l) pthread_cond_wait(c, l)
-# define gitcnd_signal(c) pthread_cond_signal(c)
-# define gitcnd_broadcast(c) pthread_cond_broadcast(c)
+/* Pthreads Mutex */
+#define git_mutex pthread_mutex_t
+#define git_mutex_init(a) pthread_mutex_init(a, NULL)
+#define git_mutex_lock(a) pthread_mutex_lock(a)
+#define git_mutex_unlock(a) pthread_mutex_unlock(a)
+#define git_mutex_free(a) pthread_mutex_destroy(a)
-# if defined(GIT_HAS_ASM_ATOMIC)
-# include
- typedef atomic_t git_refcnt;
-# define gitrc_init(a, v) atomic_set(a, v)
-# define gitrc_inc(a) atomic_inc_return(a)
-# define gitrc_dec(a) atomic_dec_and_test(a)
-# define gitrc_free(a) (void)0
-# elif defined(GIT_WIN32)
- typedef long git_refcnt;
-# define gitrc_init(a, v) (*a = v)
-# define gitrc_inc(a) (InterlockedIncrement(a))
-# define gitrc_dec(a) (!InterlockedDecrement(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, int value)
- {
- gitlck_init(&p->lock);
- p->counter = value;
- }
-
- /**
- * 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
- /* no threads support */
- typedef struct { int dummy; } 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,v) ((a)->counter = v)
-# define gitrc_inc(a) ((a)->counter++)
-# define gitrc_dec(a) (--(a)->counter == 0)
-# define gitrc_free(a) (void)0
-#endif
+/* Pthreads condition vars */
+#define git_cond pthread_cond_t
+#define git_cond_init(c, a) pthread_cond_init(c, a)
+#define git_cond_free(c) pthread_cond_destroy(c)
+#define git_cond_wait(c, l) pthread_cond_wait(c, l)
+#define git_cond_signal(c) pthread_cond_signal(c)
+#define git_cond_broadcast(c) pthread_cond_broadcast(c)
extern int git_online_cpus(void);
diff --git a/src/win32/pthread.c b/src/win32/pthread.c
new file mode 100644
index 000000000..fffff81df
--- /dev/null
+++ b/src/win32/pthread.c
@@ -0,0 +1,120 @@
+/*
+ * This file is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License, version 2,
+ * as published by the Free Software Foundation.
+ *
+ * In addition to the permissions in the GNU General Public License,
+ * the authors give you unlimited permission to link the compiled
+ * version of this file into combinations with other programs,
+ * and to distribute those combinations without any restriction
+ * coming from the use of this file. (The General Public License
+ * restrictions do apply in other respects; for example, they cover
+ * modification of the file, and distribution when not linked into
+ * a combined executable.)
+ *
+ * This file is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; see the file COPYING. If not, write to
+ * the Free Software Foundation, 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ *
+ * Original code by Ramiro Polla (Public Domain)
+ */
+
+#include "pthread.h"
+
+int pthread_create(pthread_t *GIT_RESTRICT thread,
+ const pthread_attr_t *GIT_RESTRICT GIT_UNUSED(attr),
+ void *(*start_routine)(void*), void *GIT_RESTRICT arg)
+{
+ GIT_UNUSED_ARG(attr);
+ *thread = (pthread_t) CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)start_routine, arg, 0, NULL);
+ return *thread ? GIT_SUCCESS : GIT_EOSERR;
+}
+
+int pthread_cond_signal(pthread_cond_t *cond)
+{
+ WakeConditionVariable(cond);
+ return 0;
+}
+
+int pthread_cond_wait(pthread_cond_t *GIT_RESTRICT cond,
+ pthread_mutex_t *GIT_RESTRICT mutex)
+{
+ int ret;
+ ret = SleepConditionVariableCS(cond, mutex, INFINITE);
+ return -(!ret);
+}
+
+int pthread_mutex_lock(pthread_mutex_t *mutex)
+{
+ EnterCriticalSection(mutex);
+ return 0;
+}
+
+int pthread_mutex_unlock(pthread_mutex_t *mutex)
+{
+ LeaveCriticalSection(mutex);
+ return 0;
+}
+
+int pthread_join(pthread_t thread, void **value_ptr)
+{
+ int ret;
+ ret = WaitForSingleObject(thread, INFINITE);
+ if (ret && value_ptr)
+ GetExitCodeThread(thread, (void*) value_ptr);
+ return -(!!ret);
+}
+
+int pthread_cond_broadcast(pthread_cond_t *cond)
+{
+ WakeAllConditionVariable(cond);
+ return 0;
+}
+
+int pthread_mutex_destroy(pthread_mutex_t *mutex)
+{
+ int ret;
+ ret = CloseHandle(mutex);
+ return -(!ret);
+}
+
+int pthread_cond_destroy(pthread_cond_t *GIT_UNUSED(cond))
+{
+ GIT_UNUSED_ARG(cond);
+ return 0;
+}
+
+int pthread_cond_init(pthread_cond_t *GIT_RESTRICT cond,
+ const pthread_condattr_t *GIT_RESTRICT GIT_UNUSED(condattr))
+{
+ GIT_UNUSED_ARG(condattr);
+ InitializeConditionVariable(cond);
+ return 0;
+}
+
+int pthread_mutex_init(pthread_mutex_t *GIT_RESTRICT mutex,
+ const pthread_mutexattr_t *GIT_RESTRICT GIT_UNUSED(mutexattr))
+{
+ GIT_UNUSED_ARG(mutexattr);
+ InitializeCriticalSection(mutex);
+ return 0;
+}
+
+int pthread_num_processors_np(void)
+{
+ DWORD_PTR p, s;
+ int n = 0;
+
+ if (GetProcessAffinityMask(GetCurrentProcess(), &p, &s))
+ for (; p; p >>= 1)
+ n += p&1;
+
+ return n ? n : 1;
+}
+
diff --git a/src/win32/pthread.h b/src/win32/pthread.h
new file mode 100644
index 000000000..ff694e303
--- /dev/null
+++ b/src/win32/pthread.h
@@ -0,0 +1,67 @@
+/*
+ * This file is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License, version 2,
+ * as published by the Free Software Foundation.
+ *
+ * In addition to the permissions in the GNU General Public License,
+ * the authors give you unlimited permission to link the compiled
+ * version of this file into combinations with other programs,
+ * and to distribute those combinations without any restriction
+ * coming from the use of this file. (The General Public License
+ * restrictions do apply in other respects; for example, they cover
+ * modification of the file, and distribution when not linked into
+ * a combined executable.)
+ *
+ * This file is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; see the file COPYING. If not, write to
+ * the Free Software Foundation, 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ *
+ * Original code by Ramiro Polla (Public Domain)
+ */
+
+#ifndef GIT_PTHREAD_H
+#define GIT_PTHREAD_H
+
+#include "../common.h"
+
+#if defined (_MSC_VER)
+# define GIT_RESTRICT __restrict
+#else
+# define GIT_RESTRICT __restrict__
+#endif
+
+typedef int pthread_mutexattr_t;
+typedef int pthread_condattr_t;
+typedef int pthread_attr_t;
+typedef CRITICAL_SECTION pthread_mutex_t;
+typedef CONDITION_VARIABLE pthread_cond_t;
+typedef HANDLE pthread_t;
+
+#define PTHREAD_MUTEX_INITIALIZER {(void*)-1};
+
+int pthread_create(pthread_t *GIT_RESTRICT,
+ const pthread_attr_t *GIT_RESTRICT,
+ void *(*start_routine)(void*), void *__restrict);
+
+int pthread_join(pthread_t, void **);
+
+int pthread_mutex_init(pthread_mutex_t *GIT_RESTRICT, const pthread_mutexattr_t *GIT_RESTRICT);
+int pthread_mutex_destroy(pthread_mutex_t *);
+int pthread_mutex_lock(pthread_mutex_t *);
+int pthread_mutex_unlock(pthread_mutex_t *);
+
+int pthread_cond_init(pthread_cond_t *GIT_RESTRICT, const pthread_condattr_t *GIT_RESTRICT);
+int pthread_cond_destroy(pthread_cond_t *);
+int pthread_cond_broadcast(pthread_cond_t *);
+int pthread_cond_signal(pthread_cond_t *);
+int pthread_cond_wait(pthread_cond_t *GIT_RESTRICT, pthread_mutex_t *GIT_RESTRICT);
+
+int pthread_num_processors_np(void);
+
+#endif
\ No newline at end of file
diff --git a/tests/t00-core.c b/tests/t00-core.c
index 1f6c06a95..08e42ecf4 100644
--- a/tests/t00-core.c
+++ b/tests/t00-core.c
@@ -27,17 +27,6 @@
#include "vector.h"
#include "fileops.h"
-BEGIN_TEST(refcnt0, "increment refcount twice, decrement twice")
- git_refcnt p;
-
- gitrc_init(&p, 0);
- gitrc_inc(&p);
- gitrc_inc(&p);
- must_be_true(!gitrc_dec(&p));
- must_be_true(gitrc_dec(&p));
- gitrc_free(&p);
-END_TEST
-
BEGIN_TEST(string0, "compare prefixes")
must_be_true(git__prefixcmp("", "") == 0);
must_be_true(git__prefixcmp("a", "") == 0);
@@ -626,8 +615,6 @@ END_TEST
BEGIN_SUITE(core)
- ADD_TEST(refcnt0);
-
ADD_TEST(string0);
ADD_TEST(string1);
diff --git a/wscript b/wscript
index d791d932d..198b4760b 100644
--- a/wscript
+++ b/wscript
@@ -5,10 +5,12 @@ from waflib.Build import BuildContext, CleanContext, \
# Unix flags
CFLAGS_UNIX = ["-O2", "-Wall", "-Wextra"]
CFLAGS_UNIX_DBG = ['-g']
+CFLAGS_UNIX_PED = ['-pedantic', '-Werror']
# Windows MSVC flags
-CFLAGS_WIN32_COMMON = ['/TC', '/W4', '/WX', '/nologo', '/Zi']
+CFLAGS_WIN32_COMMON = ['/TC', '/W4', '/nologo', '/Zi']
CFLAGS_WIN32_RELEASE = ['/O2', '/MD']
+CFLAGS_WIN32_PED = ['/Wx']
# Note: /RTC* cannot be used with optimization on.
CFLAGS_WIN32_DBG = ['/Od', '/RTC1', '/RTCc', '/DEBUG', '/MDd']
@@ -31,9 +33,10 @@ PPC optimized version (ppc) or the SHA1 functions from OpenSSL (openssl)")
help='Select target architecture (ia64, x64, x86, x86_amd64, x86_ia64)')
opt.add_option('--without-sqlite', action='store_false', default=True,
dest='use_sqlite', help='Disable sqlite support')
+ opt.add_option('--strict', action='store_true', default=False,
+ help='Max warning level; treat warnings as errors')
def configure(conf):
-
# load the MSVC configuration flags
if conf.options.msvc:
conf.env['MSVC_VERSIONS'] = ['msvc ' + conf.options.msvc]
@@ -43,25 +46,38 @@ def configure(conf):
# default configuration for C programs
conf.load('compiler_c')
- dbg = conf.options.debug
+ debug = conf.options.debug
+ pedantic = conf.options.strict
- conf.env.CFLAGS = CFLAGS_UNIX + (CFLAGS_UNIX_DBG if dbg else [])
+ if conf.env.CC_NAME == 'msvc':
+ conf.env.CFLAGS = CFLAGS_WIN32_COMMON
+ conf.env.LINKFLAGS = CFLAGS_WIN32_L
+ if debug:
+ conf.env.CFLAGS += CFLAGS_WIN32_DEBUG
+ conf.env.LINKFLAGS += CFLAGS_WIN32_L_DBG
+ else:
+ conf.env.CFLAGS += CFLAGS_WIN32_RELEASE
+ if pedantic:
+ conf.ENV.CFLAGS += CFLAGS_WIN32_PED
+
+ elif conf.env.CC_NAME == 'gcc':
+ conf.env.CFLAGS = CFLAGS_UNIX
+ if debug:
+ conf.env.CFLAGS += CFLAGS_UNIX_DBG
+ if pedantic:
+ conf.env.CFLAGS += CFLAGS_UNIX_PED
+
+
+ # Win32 Platform: MinGW and MSVC
if conf.env.DEST_OS == 'win32':
conf.env.PLATFORM = 'win32'
+ conf.env.DEFINES += ['WIN32', '_DEBUG', '_LIB']
- if conf.env.CC_NAME == 'msvc':
- conf.env.CFLAGS = CFLAGS_WIN32_COMMON + \
- (CFLAGS_WIN32_DBG if dbg else CFLAGS_WIN32_RELEASE)
- conf.env.LINKFLAGS += CFLAGS_WIN32_L + \
- (CFLAGS_WIN32_L_DBG if dbg else [])
- conf.env.DEFINES += ['WIN32', '_DEBUG', '_LIB']
-
- elif conf.env.CC_NAME == 'gcc':
- conf.check_cc(lib='pthread', uselib_store='pthread')
-
+ # Unix-like platforms: Linux, Darwin, Cygwin, *BSD, etc
else:
conf.env.PLATFORM = 'unix'
+ conf.check_cc(lib='pthread', uselib_store='pthread')
# Do not build ZLib with GZIP support
conf.env.DEFINES += ['NO_GZIP']