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']