Port of pthreads to Windows API threads
cover Port of pthreads to Windows API threads
Here is a small patch that allows use of native Windows API threads for where git uses pthreads. I don't have full msysgit environment to test it, all I know is it compiles, so someone else could test it a little. I enabled it for MSVC only (since msysgit uses win32-pthreads and cygwin has it's own). I assume that patch could help with getting rid of that one dependency for msysgit.
PS. I'm new here (actually new for whole kernel-like-development-cycle-with- patches-flying-low-on-mailing-lists), so please be kind to my stupidity for a while... please? ;-)
Andrzej K. Haczewski (1):
MSVC: port pthread code to native Windows threads
Makefile | 2 +- builtin-pack-objects.c | 42 +++++++++- compat/winthread.h | 219 ++++++++++++++++++++++++++++++++++++++++++++++++ preload-index.c | 12 +++ 4 files changed, 272 insertions(+), 3 deletions(-) create mode 100644 compat/winthread.h
PATCH 1/1 MSVC: port pthread code to native Windows threads
--- Makefile | 2 +- builtin-pack-objects.c | 42 +++++++++- compat/winthread.h | 219 ++++++++++++++++++++++++++++++++++++++++++++++++ preload-index.c | 12 +++ 4 files changed, 272 insertions(+), 3 deletions(-) create mode 100644 compat/winthread.h
Makefile +1 -1
@@ -940,7 +940,7 @@ ifdef MSVC OBJECT_CREATION_USES_RENAMES = UnfortunatelyNeedsTo NO_REGEX = YesPlease NO_CURL = YesPlease - NO_PTHREADS = YesPlease + THREADED_DELTA_SEARCH = YesPlease BLK_SHA1 = YesPlease CC = compat/vcbuild/scripts/clink.pl
builtin-pack-objects.c +40 -2
80 lines not on this page · raw message
compat/winthread.h new file +219 -0
219 lines not on this page · raw message
preload-index.c +12 -0
@@ -10,7 +10,11 @@ static void preload_index(struct index_state *index, const char **pathspec) }#else +#ifndef _WIN32#include <pthread.h> +#else +#include <winthread.h> +#endif /* * Mostly randomly chosen maximum thread counts: we
@@ -28,7 +32,11 @@ struct thread_data {int offset, nr; }; +#ifndef _WIN32 static void *preload_thread(void *_data) +#else +static DWORD WINAPI preload_thread(LPVOID _data) +#endif {int nr;struct thread_data *p = _data;
@@ -59,7 +67,11 @@ static void *preload_thread(void *_data)continue ;ce_mark_uptodate (ce); }while (--nr >0 ); +#ifndef _WIN32return NULL ; +#else +return 0 ; +#endif }static void preload_index (struct index_state *index,const char **pathspec)
Signature · 1 line
1.6.5.2
Re: [PATCH 1/1] MSVC: port pthread code to native Windows threads
Quoted 1 line · Andrzej K. Haczewski
---
You should sign-off your patches.
builtin-pack-objects.c line 27
Quoted 10 lines
#ifdef
THREADED_DELTA_SEARCHbuiltin-pack-objects.c +6
-2-#include "thread-utils.h" -#include <pthread.h> +# include "thread-utils.h" +# ifndef _WIN32 +# include <pthread.h> +# else +# include <winthread.h> +# endif #endif
Can't you just use the pthread package that is included in msysgit?
Quoted 11 lines
builtin-pack-objects.c +8
-0+#ifndef _WIN32 static void *threaded_find_deltas(void *arg) +#else +static DWORD WINAPI threaded_find_deltas(LPVOID arg) +#endif +#ifndef _WIN32return NULL ; +#else +return 0 ; +#endif
Quoted 1 line
etc ...
You have far too many #ifdef in the generic code. There must be a better way to hide the implementation details of this emulation.
builtin-pack-objects.c int cmd_pack_objects(int argc, const char **argv, const char *prefix) · line 2352
Quoted 10 lines
builtin-pack-objects.c +10
-0+#ifdef _WIN32 +/* +* Windows require initialization of mutex (CRITICAL_SECTION) +* and conditional variable. +*/ +pthread_mutex_init (&read_mutex); +pthread_mutex_init (&cache_mutex); +pthread_mutex_init (&progress_mutex); +win32_cond_init (&progress_cond); +#endif
*If* we are going to use this minimal pthreads implementation, then I think it will be OK to call pthread_*_init even on non-Windows.
compat/winthread.h line 28
Quoted 7 lines
compat/winthread.h new file +7
-0+static __inlineint win32_cond_init (win32_cond_t *cond) +{ + cond->waiters =0 ; + +InitializeCriticalSection (&cond->waiters_lock); + + cond->sema =CreateSemaphore (NULL ,0 ,LONG_MAX ,NULL );
Wouldn't an Event object be lighter-weight? (I'm only guessing.)
Quoted 6 lines
compat/winthread.h new file +6
-0+if (NULL == cond->sema) +return -1 ; +return 0 ; +} + +static __inlineint win32_cond_destroy (win32_cond_t *cond)
compat/winthread.h line 44
Quoted 10 lines
compat/winthread.h new file +10
-0+{ +CloseHandle (cond->sema); + cond->sema =NULL ; + +DeleteCriticalSection (&cond->waiters_lock); + +return 0 ; +} + +static __inlineint win32_cond_wait (win32_cond_t *cond,CRITICAL_SECTION *mutex)
And the reason that this is not pthread_cond_wait, is...?
compat/winthread.h line 56
Quoted 12 lines
compat/winthread.h new file +12
-0+{ +DWORD result; +int ret =0 ; + +/* we're waiting... */ +EnterCriticalSection (&cond->waiters_lock); + ++cond->waiters; +LeaveCriticalSection (&cond->waiters_lock); + +/* unlock external mutex and wait for signal */ +LeaveCriticalSection (mutex); + result =WaitForSingleObject (cond->sema,INFINITE );
Releasing the mutex and entering the wait state as well as leaving the wait state and reacquiring the mutex should be atomic. Neither are in this implementation. You are not mentioning why you are implementing things like this and why this would be acceptable.
Quoted 5 lines
compat/winthread.h new file +5
-0+ +if (0 != result) + ret =-1 ; + +/* one waiter less */
compat/winthread.h line 107
Quoted 10 lines
compat/winthread.h new file +9
-0+EnterCriticalSection (&cond->waiters_lock); + --cond->waiters; +LeaveCriticalSection (&cond->waiters_lock); + +/* lock external mutex again */ +EnterCriticalSection (mutex); +/* almost copy-paste code of mingw.c */ +static int err_win_to_posix () +{
There must be a better way than to just copy & paste this huge piece of code.
-- Hannes
Re: [PATCH 1/1] MSVC: port pthread code to native Windows threads
2009/11/4 Johannes Sixt <[email protected]>:
Quoted 11 lines
compat/winthread.h line 28
Quoted 7 lines · Andrzej K. Haczewski
compat/winthread.h new file +7
-0+static __inlineint win32_cond_init (win32_cond_t *cond) +{ + cond->waiters = 0; + + InitializeCriticalSection(&cond->waiters_lock); + + cond->sema = CreateSemaphore(NULL, 0, LONG_MAX, NULL);Wouldn't an Event object be lighter-weight? (I'm only guessing.)
Both events and semaphores resolve to wait-able kernel objects; so neither is "lighter-weight" than the other.
Re: [PATCH 1/1] MSVC: port pthread code to native Windows threads
In reply to Johannes Sixt2009/11/4 Johannes Sixt <[email protected]>:
Quoted 1 line
Can't you just use the pthread package that is included in msysgit?
I don't like bloat, and msysgit is bloated. Sure, there are parts of msysgit that are even heavier (bash, perl), but this will be removed with further C'ification of scripts. I did what I thought could be sensible for my first patch. I'm newbie after all.
Quoted 9 lines
Quoted 8 lines
+ /* we're waiting... */
+EnterCriticalSection(&cond->waiters_lock);
+ ++cond->waiters;
+LeaveCriticalSection(&cond->waiters_lock); +
+ /* unlock external mutex and wait for signal */
+ LeaveCriticalSection(mutex);
+ result =WaitForSingleObject(cond->sema, INFINITE);
Quoted 4 lines
Releasing the mutex and entering the wait state as well as leaving the wait state and reacquiring the mutex should be atomic. Neither are in this implementation. You are not mentioning why you are implementing things like this and why this would be acceptable.
It's safe to do it like this here because we're serializing waiters count and when signaling we make sure we have waiters before we release semaphore. That implementation is based on ACE.
Andrew
Re: [PATCH 1/1] MSVC: port pthread code to native Windows threads
In reply to Andrzej K. HaczewskiHi,
Quoted 1 line · Andrzej K. Haczewski
---
Could you please add the reasoning from the cover letter to this commit message? And add a sign-off?
Quoted 8 lines
builtin-pack-objects.c +0
-0@@ -18,8 +18,12 @@#include "refs.h" #ifdef THREADED_DELTA_SEARCH
builtin-pack-objects.c line 28
Quoted 10 lines
builtin-pack-objects.c +6
-2-#include "thread-utils.h" -#include <pthread.h> +# include "thread-utils.h" +# ifndef _WIN32 +# include <pthread.h> +# else +# include <winthread.h> +# endif #endif
It is unlikely that an #ifdef "contamination" of this extent will go through easily, but I have a suggestion that may make your patch both easier to read and more likely to be accepted into git.git: Try to wrap the win32 calls into pthread-compatible function signatures. Then you can add a compat/win32/pthread.h and not even touch core files of git.git at all.
Oh, and you definitely do not want to copy-paste err_win_to_posix(). You definitely want to reuse the existing instance.
Ciao,
Dscho
Re: [PATCH 1/1] MSVC: port pthread code to native Windows threads
2009/11/4 Johannes Schindelin <[email protected]>:
Quoted 2 lines
Could you please add the reasoning from the cover letter to this commit message? And add a sign-off?
Sure, will do so for next submission of that patch.
Quoted 6 lines
It is unlikely that an #ifdef "contamination" of this extent will go through easily, but I have a suggestion that may make your patch both easier to read and more likely to be accepted into git.git: Try to wrap the win32 calls into pthread-compatible function signatures. Then you can add a
compat/win32/pthread.hand not even touch core files of git.git at all.
First of all I didn't want to use wrappers because (if not inlined) they introduce one additional call, that can be avoided with #defines (as you can see even pthread_init can be done with macro). Second reason is that I didn't want to create wrapping structures that would need to be initialized / allocated / tracked. That patch translates pthread calls to purely Win32 calls without anything in between.
Here are my reasoning for some of these #ifdefs and what can be done and what can't (without using wrappers):
1. Thread routine has very different signature:
void *__cdecl func(void *); /* pthreads */uint32_t __stdcall func(void *); /* Windows API */
First I thought it might be a problem to do (especially return value, which is different size for 64-bit architectures), but since Git doesn't use return value, it can be done.
2. Initialization of CRITICAL_SECTION and SEMAPHORE (used by condition variables implementation). These need explicit initialization on Windows and can't be done statically with PTHREAD_MUTEX_INITIALIZER and PTHREAD_COND_INITIALIZER. There's no easy way around that (read:
it needs wrappers).
Quoted 2 lines
Oh, and you definitely do not want to copy-paste
err_win_to_posix(). You definitely want to reuse the existing instance.
Yeah, that was lazy, mea culpa.
I'll resubmit the patch with some fixes shortly,
Andrew
Re: [PATCH 1/1] MSVC: port pthread code to native Windows threads
In reply to Johannes Schindelin----- Original Message -----
From: Johannes Schindelin
Date: 11/3/2009 4:38 PM
Quoted 10 lines
Quoted 10 lines
#ifdef THREADED_DELTA_SEARCHbuiltin-pack-objects.c +6
-2-#include "thread-utils.h" -#include <pthread.h> +# include "thread-utils.h" +# ifndef _WIN32 +# include <pthread.h> +# else +# include <winthread.h> +# endif #endif
Quoted 9 lines
Quoted 2 lines
It is unlikely that an #ifdef "contamination" of this extent will go through easily, but I have a suggestion that may make your patch both easier to read and more likely to be accepted into git.git: Try to wrap the win32 calls into pthread-compatible function signatures. Then you can add a
compat/win32/pthread.hand not even touch core files of git.git at all.
Pardon my ignorance, but is there a reason to not use Pthreads for Win32? http://sourceware.org/pthreads-win32/
Josh
Re: [PATCH 1/1] MSVC: port pthread code to native Windows threads
Quoted 4 lines
Pardon my ignorance, but is there a reason to not use Pthreads for Win32?
http://sourceware.org/pthreads-win32/
Not using pthreads on Windows makes Git:
1. faster on that platform
2. not depend on Pthreads for Win32
IMHO that makes Git one step closer to become native on Windows, and is a sensible step.
Andrew
Re: [PATCH 1/1] MSVC: port pthread code to native Windows threads
[please don't cull Cc list on this ML]
Quoted 6 lines · Andrzej K. Haczewski
Quoted 3 lines
Pardon my ignorance, but is there a reason to not use Pthreads for Win32?
http://sourceware.org/pthreads-win32/Not using pthreads on Windows makes Git:
1. faster on that platform
I believe this only if you present hard numbers. My guess is that (for example) packing objects with two threads is still faster with a slow pthreads emulation than without threading at all.
Quoted 1 line
2. not depend on Pthreads for Win32
Why is this an advantage?
Quoted 2 lines
IMHO that makes Git one step closer to become native on Windows, and is a sensible step.
Emulating pthreads on Windows with all its facets is an extremely difficult task. If exact POSIX conformance is needed, I would choose an existing package over doing it myself at any time.
Granted, we don't need the esoteric parts (cancelation points), which would simplify the emulation a lot. But, as I pointed out in my other mail, even a pthread_cond_wait() is not that trivial to implement with the Windows API.
-- Hannes
Re: [PATCH 1/1] MSVC: port pthread code to native Windows threads
In reply to Joshua JensenHi,
I do not appreciate at all that you culled me from the Cc: list.
Quoted 22 lines · Joshua Jensen
----- Original Message -----
From: Johannes Schindelin
Date: 11/3/2009 4:38 PMQuoted 10 lines
Quoted 10 lines
#ifdef THREADED_DELTA_SEARCHbuiltin-pack-objects.c +6
-2-#include "thread-utils.h" -#include <pthread.h> +# include "thread-utils.h" +# ifndef _WIN32 +# include <pthread.h> +# else +# include <winthread.h> +# endif #endif Quoted 9 lines
Quoted 2 lines
It is unlikely that an #ifdef "contamination" of this extent will go through easily, but I have a suggestion that may make your patch both easier to read and more likely to be accepted into git.git: Try to wrap the win32 calls into pthread-compatible function signatures. Then you can add a
compat/win32/pthread.hand not even touch core files of git.git at all.
Quoted 2 lines
Pardon my ignorance, but is there a reason to not use Pthreads for Win32? http://sourceware.org/pthreads-win32/
Pthreads is a rather large dependency we do not really need.
Ciao,
Dscho
PATCH 1/1 MSVC: port pthread code to native Windows threads
In reply to Andrzej K. HaczewskiHere is slightly modified patch with more comments where explanations were requested (ie. non atomic release mutex and wait).
The implementation of conditional variable is based on ACE.
The patch needs testing from someone capable of compiling Git on Windows and running it with msysgit environment. I can confirm that it compiles cleanly on both Linux and Windows. I modified Makefile only for MSVC part, so if you'd like to compile it with mingw or cygwin, proper corrections have to be made. I aim for native MSVC compilation, that's why I did it like that. That's also the reason I don't like having Pthreads for Win32 dependency - it's faster to use native calls than depend on 3rd party wrapper library to do it for you (ie. pthreads for win32 does allocations to implement POSIX standard, and full-conformance isn't required by Git, since Git uses only small subset of pthreads).
One more motivation I had for the patch: as I was reading through archives I had a feeling that Git aims to be as lightweight as possible, hence removing additional dependencies (even for Windows platform) seems sensible to me.
--- Makefile | 4 +- builtin-pack-objects.c | 29 +++++++++- compat/mingw.c | 2 +- compat/win32/pthread.h | 143 ++++++++++++++++++++++++++++++++++++++++++++++++ git-compat-util.h | 13 ++++ preload-index.c | 4 +- 6 files changed, 187 insertions(+), 8 deletions(-) create mode 100644 compat/win32/pthread.h
Makefile +2 -2
@@ -939,7 +939,7 @@ ifdef MSVC OBJECT_CREATION_USES_RENAMES = UnfortunatelyNeedsTo NO_REGEX = YesPlease NO_CURL = YesPlease - NO_PTHREADS = YesPlease + THREADED_DELTA_SEARCH = YesPlease BLK_SHA1 = YesPlease CC = compat/vcbuild/scripts/clink.pl
@@ -947,7 +947,7 @@ ifdef MSVC CFLAGS = BASIC_CFLAGS = -nologo -I. -I../zlib -Icompat/vcbuild -Icompat/vcbuild/include -DWIN32 -D_CONSOLE -DHAVE_STRING_H -D_CRT_SECURE_NO_WARNINGS -D_CRT_NONSTDC_NO_DEPRECATE COMPAT_OBJS = compat/msvc.o compat/fnmatch/fnmatch.o compat/winansi.o - COMPAT_CFLAGS = -D__USE_MINGW_ACCESS -DNOGDI -DHAVE_STRING_H -DHAVE_ALLOCA_H -Icompat -Icompat/fnmatch -Icompat/regex -Icompat/fnmatch -DSTRIP_EXTENSION=\".exe\" + COMPAT_CFLAGS = -D__USE_MINGW_ACCESS -DNOGDI -DHAVE_STRING_H -DHAVE_ALLOCA_H -Icompat -Icompat/fnmatch -Icompat/regex -Icompat/fnmatch -Icompat/win32 -DSTRIP_EXTENSION=\".exe\" BASIC_LDFLAGS = -IGNORE:4217 -IGNORE:4049 -NOLOGO -SUBSYSTEM:CONSOLE -NODEFAULTLIB:MSVCRT.lib EXTLIBS = advapi32.lib shell32.lib wininet.lib ws2_32.lib lib =
builtin-pack-objects.c +26 -3
@@ -1592,7 +1592,7 @@ struct thread_params {static pthread_cond_t progress_cond =PTHREAD_COND_INITIALIZER ; -static void *threaded_find_deltas (void *arg) +static THREAD_FUNC(threaded_find_deltas, arg) {struct thread_params *me = arg;
@@ -1620,7 +1620,7 @@ static void *threaded_find_deltas(void *arg)pthread_mutex_unlock (&me->mutex); }/* leave ->working 1 so that this doesn't get more work assigned */ -return NULL ; +THREAD_RETURN (NULL ); } static void ll_find_deltas(struct object_entry **list, unsigned list_size,
@@ -2327,6 +2327,18 @@ int cmd_pack_objects(int argc, const char **argv, const char *prefix)#ifdef THREADED_DELTA_SEARCH if (!delta_search_threads)/* --threads=0 means autodetect */ delta_search_threads =online_cpus (); + +#ifdef _WIN32 +/* +* Windows requires initialization of mutex (CRITICAL_SECTION) +* and conditional variable. +*/ +pthread_mutex_init (&read_mutex); +pthread_mutex_init (&cache_mutex); +pthread_mutex_init (&progress_mutex); +pthread_cond_init (&progress_cond,NULL ); +#endif +#endif prepare_packed_git ();
@@ -2345,7 +2357,7 @@ int cmd_pack_objects(int argc, const char **argv, const char *prefix)stop_progress (&progress_state);if (non_empty && !nr_result) -return 0 ; + goto cleanup;if (nr_result)prepare_pack (window, depth);write_pack_file ();
@@ -2353,5 +2365,16 @@ int cmd_pack_objects(int argc, const char **argv, const char *prefix)fprintf (stderr,"Total %" PRIu32" (delta %" PRIu32")," " reused %" PRIu32" (delta %" PRIu32")\n" , written, written_delta, reused, reused_delta); + +cleanup: +#if defined(THREADED_DELTA_SEARCH ) && defined(_WIN32) +/* cleanup Windows threads thingies */ +pthread_cond_destroy (&progress_cond); +pthread_mutex_destroy (&read_mutex); +pthread_mutex_destroy (&cache_mutex); +pthread_mutex_destroy (&progress_mutex); +#endif +return 0 ; } +
compat/mingw.c +1 -1
@@ -5,7 +5,7 @@#include <shellapi.h> -static int err_win_to_posix (DWORD winerr) +int err_win_to_posix (DWORD winerr) {int error =ENOSYS ;switch (winerr) {
compat/win32/pthread.h new file +143 -0
143 lines not on this page · raw message
git-compat-util.h +13 -0
@@ -464,4 +464,17 @@ void git_qsort(void *base, size_t nmemb, size_t size,*/ int unlink_or_warn (const char *path); +/* +* Properly defines thread routine for Windows and POSIX +*/ +#ifndef NO_PTHREADS +# ifndef _WIN32 +# define THREAD_FUNC (f, a) void *f(void *a) +# define THREAD_RETURN (x) return (x) +# else +# define THREAD_FUNC (f, a) DWORD __stdcall f(LPVOID a) +# define THREAD_RETURN (x) return (DWORD)(x); +# endif +#endif +#endif
preload-index.c +2 -2
@@ -28,7 +28,7 @@ struct thread_data {int offset, nr; }; -static void *preload_thread (void *_data) +static THREAD_FUNC(preload_thread, _data) {int nr;struct thread_data *p = _data;
@@ -59,7 +59,7 @@ static void *preload_thread(void *_data)continue ;ce_mark_uptodate (ce); }while (--nr >0 ); -return NULL ; +THREAD_RETURN (NULL ); }static void preload_index (struct index_state *index,const char **pathspec)
Signature · 1 line
1.6.5.2
PATCH 1/1 MSVC: Windows-native implementation for subset of Pthreads API
This patch implements native to Windows subset of pthreads API used by Git. It allows to remove Pthreads for Win32 dependency for msysgit and cygwin.
The patch modifies Makefile only for MSVC (that's the environment I'm capable of testing on), so it requires further corrections to compile with MinGW or Cygwin.
--- Makefile | 8 ++- builtin-pack-objects.c | 41 +++++++++++++- compat/mingw.c | 2 +- compat/mingw.h | 5 ++ compat/win32/pthread.h | 136 ++++++++++++++++++++++++++++++++++++++++++++++++ git-compat-util.h | 10 ++++ preload-index.c | 4 +- 7 files changed, 198 insertions(+), 8 deletions(-) create mode 100644 compat/win32/pthread.h
Makefile +6 -2
@@ -939,7 +939,8 @@ ifdef MSVC OBJECT_CREATION_USES_RENAMES = UnfortunatelyNeedsTo NO_REGEX = YesPlease NO_CURL = YesPlease - NO_PTHREADS = YesPlease + THREADED_DELTA_SEARCH = YesPlease + NO_STATIC_PTHREADS_INIT = YesPlease BLK_SHA1 = YesPlease CC = compat/vcbuild/scripts/clink.pl
@@ -947,7 +948,7 @@ ifdef MSVC CFLAGS = BASIC_CFLAGS = -nologo -I. -I../zlib -Icompat/vcbuild -Icompat/vcbuild/include -DWIN32 -D_CONSOLE -DHAVE_STRING_H -D_CRT_SECURE_NO_WARNINGS -D_CRT_NONSTDC_NO_DEPRECATE COMPAT_OBJS = compat/msvc.o compat/fnmatch/fnmatch.o compat/winansi.o - COMPAT_CFLAGS = -D__USE_MINGW_ACCESS -DNOGDI -DHAVE_STRING_H -DHAVE_ALLOCA_H -Icompat -Icompat/fnmatch -Icompat/regex -Icompat/fnmatch -DSTRIP_EXTENSION=\".exe\" + COMPAT_CFLAGS = -D__USE_MINGW_ACCESS -DNOGDI -DHAVE_STRING_H -DHAVE_ALLOCA_H -Icompat -Icompat/fnmatch -Icompat/regex -Icompat/fnmatch -Icompat/win32 -DSTRIP_EXTENSION=\".exe\" BASIC_LDFLAGS = -IGNORE:4217 -IGNORE:4049 -NOLOGO -SUBSYSTEM:CONSOLE -NODEFAULTLIB:MSVCRT.lib EXTLIBS = advapi32.lib shell32.lib wininet.lib ws2_32.lib lib =
@@ -1293,6 +1294,9 @@ ifdef THREADED_DELTA_SEARCH BASIC_CFLAGS += -DTHREADED_DELTA_SEARCH LIB_OBJS += thread-utils.o endif +ifdef NO_STATIC_PTHREADS_INIT + COMPAT_CFLAGS += -DNO_STATIC_PTHREADS_INIT +endif ifdef DIR_HAS_BSD_GROUP_SEMANTICS COMPAT_CFLAGS += -DDIR_HAS_BSD_GROUP_SEMANTICS endif
builtin-pack-objects.c +38 -3
70 lines not on this page · raw message
compat/mingw.c +1 -1
@@ -5,7 +5,7 @@#include <shellapi.h> -static int err_win_to_posix (DWORD winerr) +int err_win_to_posix (DWORD winerr) {int error =ENOSYS ;switch (winerr) {
compat/mingw.h +5 -0
@@ -294,3 +294,8 @@ struct mingw_dirent#define readdir (x) mingw_readdir(x)struct dirent *mingw_readdir (DIR *dir);#endif // !NO_MINGW_REPLACE_READDIR + +/* +* Used by Pthread API implementation for Windows +*/ +extern int err_win_to_posix (DWORD winerr);
compat/win32/pthread.h new file +136 -0
136 lines not on this page · raw message
git-compat-util.h +10 -0
@@ -464,4 +464,14 @@ void git_qsort(void *base, size_t nmemb, size_t size,*/ int unlink_or_warn (const char *path); +/* +* Define type of thread function return type to distinguish +* Windows and POSIX. +*/ +#ifndef _WIN32 +# define THREAD_RET_TYPE void * +#else +# define THREAD_RET_TYPE DWORD __stdcall +#endif +#endif
preload-index.c +2 -2
@@ -28,7 +28,7 @@ struct thread_data {int offset, nr; }; -static void *preload_thread (void *_data) +static THREAD_RET_TYPE preload_thread (void * _data) {int nr;struct thread_data *p = _data;
@@ -59,7 +59,7 @@ static void *preload_thread(void *_data)continue ;ce_mark_uptodate (ce); }while (--nr >0 ); -return NULL ; +return 0 ; }static void preload_index (struct index_state *index,const char **pathspec)
Signature · 1 line
1.6.5.2
Re: [PATCH] MSVC: Windows-native implementation for subset of Pthreads API
Makefile ifdef MSVC · line 943
Quoted 1 line · Andrzej K. Haczewski
Makefile +1
-0+ NO_STATIC_PTHREADS_INIT = YesPlease
Let's not go that route please. If Windows can't get away without runtime initializations then let's use them on all platforms. There is no gain in exploding the code path combinations here wrt testing coverage.
Quoted 1 line
+static
THREAD_RET_TYPEthreaded_find_deltas(void *arg)
Why can't you just cast the function pointer in your pthread_create wrapper instead? No one cares about the returned value anyway.
builtin-pack-objects.c int cmd_pack_objects(int argc, const char **argv, const char *prefix) · line 2358
Quoted 6 lines
builtin-pack-objects.c +2
-0@@ -2327,6 +2354,8 @@ int cmd_pack_objects(int argc, const char **argv, const char *prefix)#ifdef THREADED_DELTA_SEARCH if (!delta_search_threads)/* --threads=0 means autodetect */ delta_search_threads =online_cpus (); + +init_threaded_delta_search ();
What about doing this at the beginning of ll_find_deltas() instead? And similarly for cleanup_threaded_delta_search(): call it right before leaving ll_find_deltas(). This way thread issues would remain more localized. In fact I'd move the whole thing above in ll_find_deltas() as well (separately from this patch though).
Nicolas
Re: [PATCH] MSVC: Windows-native implementation for subset of Pthreads API
2009/11/4 Nicolas Pitre <[email protected]>:
Quoted 9 lines · Andrzej K. Haczewski
Quoted 2 lines
+
NO_STATIC_PTHREADS_INIT= YesPleaseLet's not go that route please. If Windows can't get away without runtime initializations then let's use them on all platforms. There is no gain in exploding the code path combinations here wrt testing coverage.
I don't like that approach either, but I was frighten of Junio being anal about static inits ;).
Let's make it clear: has anyone have any objections that I add explicit initialization of mutexes and condition variables for POSIX also?
Quoted 4 lines
Quoted 1 line
+static
THREAD_RET_TYPEthreaded_find_deltas(void *arg)Why can't you just cast the function pointer in your
pthread_createwrapper instead? No one cares about the returned value anyway.
Because of calling convention - I'd have to cast cdecl function as stdcall function, which would change the function call clean up (in cdecl caller is responsible for unwinding stack, stdcall callee; the effect - double stack unwinding).
Quoted 4 lines
Quoted 4 lines
builtin-pack-objects.c +0
-0@@ -2327,6 +2354,8 @@ int cmd_pack_objects(int argc, const char **argv, const char *prefix) #ifdef THREADED_DELTA_SEARCHif (!delta_search_threads) /* --threads=0 means autodetect */
delta_search_threads=online_cpus();
Quoted 8 lines
Quoted 2 lines
+
+init_threaded_delta_search();What about doing this at the beginning of
ll_find_deltas()instead? And similarly forcleanup_threaded_delta_search(): call it right before leavingll_find_deltas(). This way thread issues would remain more localized. In fact I'd move the whole thing above inll_find_deltas()as well (separately from this patch though).
Sounds sensible, but I'd wait for the NO_STATIC_PTHREADS_INIT verdict.
--
Andrzej
Re: [PATCH] MSVC: Windows-native implementation for subset of Pthreads API
Quoted 10 lines · Andrzej K. Haczewski
Quoted 4 lines
Quoted 1 line
+static
THREAD_RET_TYPEthreaded_find_deltas(void *arg)Why can't you just cast the function pointer in your
pthread_createwrapper instead? No one cares about the returned value anyway.Because of calling convention - I'd have to cast cdecl function as stdcall function, which would change the function call clean up (in cdecl caller is responsible for unwinding stack, stdcall callee; the effect - double stack unwinding).
Couldn't the windows version of pthread_create have a wrapper function, that corrected the calling convention, much like the function run_thread that start_async in run-command.c has?
Signature · 1 line
Erik "kusma" Faye-Lund
Re: [PATCH] MSVC: Windows-native implementation for subset of Pthreads API
Erik Faye-Lund pisze:
Quoted 3 lines
Couldn't the windows version of
pthread_createhave a wrapper function, that corrected the calling convention, much like the functionrun_threadthatstart_asyncinrun-command.chas?
Can't be done without allocations. I'd have to pass to that wrapping thread function an address of original function *and* an original argument, and there's no way to pack that as one void*.
--
Andrzej
Re: [PATCH] MSVC: Windows-native implementation for subset of Pthreads API
Quoted 8 lines · Andrzej K. Haczewski
Erik Faye-Lund pisze:
Quoted 3 lines
Couldn't the windows version of
pthread_createhave a wrapper function, that corrected the calling convention, much like the functionrun_threadthatstart_asyncinrun-command.chas?Can't be done without allocations. I'd have to pass to that wrapping thread function an address of original function *and* an original argument, and there's no way to pack that as one void*.
What about:
typedef struct {
HANDLE handle;
void *(*start_routine)(void *);
void *arg;
} pthread_t;DWORD __stdcall windows_thread_start(LPVOID _self)
{
pthread_t *self = _self;
void *ret = self->start_routine(self->arg);
return (DWORD)ret;
}static inline int pthread_create(pthread_t *thread, const void *unused,
void *(*start_routine)(void *), void *arg)
{
thread->handle = CreateThread(NULL, 0, windows_thread_start,
thread, 0, NULL);
[...]
}?
Sure this will use 8 to 16 more bytes per thread, but we're dealing with a rather small number of threads anyway (more threads than the number of CPU cores is useless) making this extra memory usage rather insignificant compared to the many megabytes of RAM the rest of the code is using. The advantage is full compatibility with the native pthread interface git is using at the source level while still being much lighter than a full blown pthread implementation.
And thread creation is a relatively rare event compared to e.g. mutex lock/unlock, so the indirection shouldn't be noticeable. For the same reason, I also think that you could make pthread_create() and pthread_join() into a C file instead of being inlined which would reduce the code footprint at every call site, and allow for only one instance of windows_thread_start() which could then be made static.
Nicolas
Re: [PATCH] MSVC: Windows-native implementation for subset of Pthreads API
2009/11/5 Nicolas Pitre <[email protected]>:
Quoted 17 lines · Andrzej K. Haczewski
What about:
typedef struct {
HANDLE handle;
void *(*start_routine)(void *);
void *arg;
}pthread_t;DWORD
__stdcallwindows_thread_start(LPVOID _self){
pthread_t *self =_self;
void *ret =self->start_routine(self->arg); return (DWORD)ret;
}
Quoted 7 lines
static inline int
pthread_create(pthread_t *thread, const void *unused, void *(*start_routine)(void *), void *arg){
thread->handle =CreateThread(NULL, 0, windows_thread_start, thread, 0, NULL);
[...]
}
The problem I see is not with pthread_init, but pthread_join. Here's how it looks:
int pthread_join(pthread_t thread, void **value_ptr);
If pthread_t would be a struct, then we can't call pthread_join like that... At least that's what I though yesterday, but maybe it can be done like this:
int win32_pthread_join(pthread_t *thread, void **value_ptr)
{
[...]
}#define pthread_join(a, b) win32_pthread_join(&(a), (b))
That way we don't need allocations to simulate pthread init/join API
Quoted 6 lines
And thread creation is a relatively rare event compared to e.g. mutex lock/unlock, so the indirection shouldn't be noticeable. For the same reason, I also think that you could make
pthread_create()andpthread_join()into a C file instead of being inlined which would reduce the code footprint at every call site, and allow for only one instance ofwindows_thread_start()which could then be made static.
Yeah, I'll factor that out to separate file.
--
Andrzej
PATCH 1/1 MSVC: Windows-native implementation for subset of Pthreads API
This patch implements native to Windows subset of pthreads API used by Git. It allows to remove Pthreads for Win32 dependency for msysgit and Cygwin.
The patch modifies Makefile only for MSVC (that's the environment I'm capable of testing on), so it requires further corrections to compile with MinGW or Cygwin.
--- Makefile | 7 ++- builtin-pack-objects.c | 31 ++++++++++-- compat/mingw.c | 2 +- compat/mingw.h | 5 ++ compat/win32/pthread.c | 39 +++++++++++++++ compat/win32/pthread.h | 125 ++++++++++++++++++++++++++++++++++++++++++++++++ 6 files changed, 201 insertions(+), 8 deletions(-) create mode 100644 compat/win32/pthread.c create mode 100644 compat/win32/pthread.h
Makefile +4 -3
@@ -453,6 +453,7 @@ LIB_H += commit.h LIB_H += compat/bswap.h LIB_H += compat/cygwin.h LIB_H += compat/mingw.h +LIB_H += compat/win32/pthread.h LIB_H += csum-file.h LIB_H += decorate.h LIB_H += delta.h
@@ -971,15 +972,15 @@ ifdef MSVC OBJECT_CREATION_USES_RENAMES = UnfortunatelyNeedsTo NO_REGEX = YesPlease NO_CURL = YesPlease - NO_PTHREADS = YesPlease + THREADED_DELTA_SEARCH = YesPlease BLK_SHA1 = YesPlease CC = compat/vcbuild/scripts/clink.pl AR = compat/vcbuild/scripts/lib.pl CFLAGS = BASIC_CFLAGS = -nologo -I. -I../zlib -Icompat/vcbuild -Icompat/vcbuild/include -DWIN32 -D_CONSOLE -DHAVE_STRING_H -D_CRT_SECURE_NO_WARNINGS -D_CRT_NONSTDC_NO_DEPRECATE - COMPAT_OBJS = compat/msvc.o compat/fnmatch/fnmatch.o compat/winansi.o - COMPAT_CFLAGS = -D__USE_MINGW_ACCESS -DNOGDI -DHAVE_STRING_H -DHAVE_ALLOCA_H -Icompat -Icompat/fnmatch -Icompat/regex -Icompat/fnmatch -DSTRIP_EXTENSION=\".exe\" + COMPAT_OBJS = compat/msvc.o compat/fnmatch/fnmatch.o compat/winansi.o compat/win32/pthread.o + COMPAT_CFLAGS = -D__USE_MINGW_ACCESS -DNOGDI -DHAVE_STRING_H -DHAVE_ALLOCA_H -Icompat -Icompat/fnmatch -Icompat/regex -Icompat/fnmatch -Icompat/win32 -DSTRIP_EXTENSION=\".exe\" BASIC_LDFLAGS = -IGNORE:4217 -IGNORE:4049 -NOLOGO -SUBSYSTEM:CONSOLE -NODEFAULTLIB:MSVCRT.lib EXTLIBS = advapi32.lib shell32.lib wininet.lib ws2_32.lib lib =
builtin-pack-objects.c +27 -4
@@ -1255,15 +1255,15 @@ static int delta_cacheable(unsigned long src_size, unsigned long trg_size,#ifdef THREADED_DELTA_SEARCH -static pthread_mutex_t read_mutex =PTHREAD_MUTEX_INITIALIZER ; +static pthread_mutex_t read_mutex;#define read_lock () pthread_mutex_lock(&read_mutex)#define read_unlock () pthread_mutex_unlock(&read_mutex) -static pthread_mutex_t cache_mutex =PTHREAD_MUTEX_INITIALIZER ; +static pthread_mutex_t cache_mutex;#define cache_lock () pthread_mutex_lock(&cache_mutex)#define cache_unlock () pthread_mutex_unlock(&cache_mutex) -static pthread_mutex_t progress_mutex =PTHREAD_MUTEX_INITIALIZER ; +static pthread_mutex_t progress_mutex;#define progress_lock () pthread_mutex_lock(&progress_mutex)#define progress_unlock () pthread_mutex_unlock(&progress_mutex)
@@ -1590,7 +1590,26 @@ struct thread_params {unsigned *processed; }; -static pthread_cond_t progress_cond =PTHREAD_COND_INITIALIZER ; +static pthread_cond_t progress_cond; + +/* +* Mutex and conditional variable can't be statically-initialized on Windows. +*/ +static void init_threaded_search () +{ +pthread_mutex_init (&read_mutex,NULL ); +pthread_mutex_init (&cache_mutex,NULL ); +pthread_mutex_init (&progress_mutex,NULL ); +pthread_cond_init (&progress_cond,NULL ); +} + +static void cleanup_threaded_search () +{ +pthread_cond_destroy (&progress_cond); +pthread_mutex_destroy (&read_mutex); +pthread_mutex_destroy (&cache_mutex); +pthread_mutex_destroy (&progress_mutex); +}static void *threaded_find_deltas (void *arg) {
@@ -1629,8 +1648,11 @@ static void ll_find_deltas(struct object_entry **list, unsigned list_size,struct thread_params *p;int i, ret, active_threads =0 ; +init_threaded_search (); +if (delta_search_threads <=1 ) {find_deltas (list, &list_size, window, depth, processed); +cleanup_threaded_search ();return ; }if (progress > pack_to_stdout)
@@ -1745,6 +1767,7 @@ static void ll_find_deltas(struct object_entry **list, unsigned list_size, active_threads--; } } +cleanup_threaded_search ();free (p); }
compat/mingw.c +1 -1
@@ -5,7 +5,7 @@#include <shellapi.h> -static int err_win_to_posix (DWORD winerr) +int err_win_to_posix (DWORD winerr) {int error =ENOSYS ;switch (winerr) {
compat/mingw.h +5 -0
@@ -294,3 +294,8 @@ struct mingw_dirent#define readdir (x) mingw_readdir(x)struct dirent *mingw_readdir (DIR *dir);#endif // !NO_MINGW_REPLACE_READDIR + +/* +* Used by Pthread API implementation for Windows +*/ +extern int err_win_to_posix (DWORD winerr);
compat/win32/pthread.c new file +39 -0
@@ -0,0 +1,39 @@ +/* +* Copyright (C) 2009 Andrzej K. Haczewski <[email protected]> +*/ + +#include "pthread.h" + +static DWORD __stdcallwin32_start_routine (LPVOID arg) +{ +pthread_t *thread = arg; + thread->value = thread->start_routine (thread->arg); +return 0 ; +} + +int pthread_create (pthread_t *thread,const void *unused, +void *(*start_routine)(void *),void *arg) +{ + thread->arg = arg; + thread->handle =CreateThread (NULL ,0 , win32_start_routine, thread,0 ,NULL ); + +if (!thread->handle) +return err_win_to_posix (GetLastError ()); +else +return 0 ; +} + +int win32_pthread_join (pthread_t *thread,void **value_ptr) +{ +DWORD result =WaitForSingleObject (thread->handle,INFINITE ); +switch (result) { +case WAIT_OBJECT_0 : +if (value_ptr) + *value_ptr = thread.value; +return 0 ; +case WAIT_ABANDONED : +return EINVAL ; +default : +return err_win_to_posix (GetLastError ()); + } +}
compat/win32/pthread.h new file +125 -0
125 lines not on this page · raw message
Signature · 1 line
1.6.5.2
Re: [PATCH] MSVC: Windows-native implementation for subset of Pthreads API
Quoted 21 lines · Andrzej K. Haczewski
Makefile +2
-1@@ -453,6 +453,7 @@ LIB_H += commit.h LIB_H += compat/bswap.h LIB_H += compat/cygwin.h LIB_H += compat/mingw.h +LIB_H += compat/win32/pthread.h LIB_H += csum-file.h LIB_H += decorate.h LIB_H += delta.h@@ -971,15 +972,15 @@ ifdef MSVC OBJECT_CREATION_USES_RENAMES = UnfortunatelyNeedsTo NO_REGEX = YesPlease NO_CURL = YesPlease - NO_PTHREADS = YesPlease + THREADED_DELTA_SEARCH = YesPlease BLK_SHA1 = YesPlease CC = compat/vcbuild/scripts/clink.pl
Makefile ifdef MSVC · line 986
Quoted 10 lines
Makefile +2
-2AR = compat/vcbuild/scripts/lib.pl CFLAGS = BASIC_CFLAGS = -nologo -I. -I../zlib -Icompat/vcbuild -Icompat/vcbuild/include -DWIN32 -D_CONSOLE -DHAVE_STRING_H -D_CRT_SECURE_NO_WARNINGS -D_CRT_NONSTDC_NO_DEPRECATE - COMPAT_OBJS = compat/msvc.o compat/fnmatch/fnmatch.o compat/winansi.o - COMPAT_CFLAGS = -D__USE_MINGW_ACCESS -DNOGDI -DHAVE_STRING_H -DHAVE_ALLOCA_H -Icompat -Icompat/fnmatch -Icompat/regex -Icompat/fnmatch -DSTRIP_EXTENSION=\".exe\" + COMPAT_OBJS = compat/msvc.o compat/fnmatch/fnmatch.o compat/winansi.o compat/win32/pthread.o + COMPAT_CFLAGS = -D__USE_MINGW_ACCESS -DNOGDI -DHAVE_STRING_H -DHAVE_ALLOCA_H -Icompat -Icompat/fnmatch -Icompat/regex -Icompat/fnmatch -Icompat/win32 -DSTRIP_EXTENSION=\".exe\" BASIC_LDFLAGS = -IGNORE:4217 -IGNORE:4049 -NOLOGO -SUBSYSTEM:CONSOLE -NODEFAULTLIB:MSVCRT.lib EXTLIBS = advapi32.lib shell32.lib wininet.lib ws2_32.lib lib =
What compiles compat/win32/pthread.c?
Please don't forget to add compat/win32/*.o to the clean target.
Makefile
Quoted 5 lines
Makefile +5
-0+int pthread_create(pthread_t *thread, const void *unused, + void *(*start_routine)(void*), void *arg) +{ + thread->arg = arg; + thread->handle = CreateThread(NULL, 0, win32_start_routine, thread, 0, NULL);
Elsewhere we use _beginthreadex(). What's the difference?
Quoted 59 lines
Makefile +59
-0+static inline int pthread_cond_init(pthread_cond_t *cond, const void *unused) +{ + cond->waiters = 0; + + InitializeCriticalSection(&cond->waiters_lock); + + cond->sema = CreateSemaphore(NULL, 0, LONG_MAX, NULL); + if (!cond->sema) + die(""); + return 0; +} + +static inline int pthread_cond_destroy(pthread_cond_t *cond) +{ + CloseHandle(cond->sema); + cond->sema = NULL; + + DeleteCriticalSection(&cond->waiters_lock); + + return 0; +} + +static inline int pthread_cond_wait(pthread_cond_t *cond, CRITICAL_SECTION *mutex) +{ + /* serialize access to waiters count */ + EnterCriticalSection(&cond->waiters_lock); + ++cond->waiters; + LeaveCriticalSection(&cond->waiters_lock); + + /* + * Unlock external mutex and wait for signal. + * NOTE: we've held mutex locked long enough to increment + * waiters count above, so there's no problem with + * leaving mutex unlocked before we wait on semaphore. + */ + LeaveCriticalSection(mutex); + + /* let's wait */ + WaitForSingleObject(cond->sema, INFINITE)) + + /* we're done waiting, so make sure we decrease waiters count */ + EnterCriticalSection(&cond->waiters_lock); + --cond->waiters; + LeaveCriticalSection(&cond->waiters_lock); + + /* lock external mutex again */ + EnterCriticalSection(mutex); + + return 0; +} + +static inline int pthread_cond_signal(pthread_cond_t *cond) +{ + int have_waiters; + + /* serialize access to waiters count */ + EnterCriticalSection(&cond->waiters_lock); + have_waiters = cond->waiters > 0; + LeaveCriticalSection(&cond->waiters_lock);
Makefile
Quoted 10 lines
Makefile +10
-0+ + /* + * Signal only when there are waiters + */ + if (have_waiters) + return ReleaseSemaphore(cond->sema, 1, NULL) ? + 0 : err_win_to_posix(GetLastError(); + else + return 0; +}
The pthread_cond_* functions are quite voluminous, but not performance critical. Could you please move them to pthread.c as well?
-- Hannes
Re: [PATCH] MSVC: Windows-native implementation for subset of Pthreads API
2009/11/5 Johannes Sixt <[email protected]>:
Quoted 1 line
Elsewhere we use
_beginthreadex(). What's the difference?
Oh my, I've just run through MSDN documentation and I'm wrongly using CreateThread. I should have used _beginthread from the start, because besides calling CreateThread it initializes local thread storage for global C-runtime variables (errno etc.), which CreateThread does not do. That could lead to very unpleasant consequences. I'll redo thread creation to use _beginthreadex(). Thanks for that question!
Quoted 2 lines
The pthread_cond_* functions are quite voluminous, but not performance critical. Could you please move them to
pthread.cas well?
Ok, will do.
--
Andrzej
Re: [PATCH] MSVC: Windows-native implementation for subset of Pthreads API
In reply to Andrzej K. HaczewskiQuoted 2 lines · Andrzej K. Haczewski
That way we don't need allocations to simulate pthread init/join API
Yay! By the way, I love the work you're doing here. Getting threaded delta-searching on Windows is something I'm looking forward to :)
Signature · 1 line
Erik "kusma" Faye-Lund
Re: [PATCH] MSVC: Windows-native implementation for subset of Pthreads API
In reply to Andrzej K. HaczewskiQuoted 26 lines · Andrzej K. Haczewski
2009/11/5 Nicolas Pitre <[email protected]>:
Quoted 17 lines · Andrzej K. Haczewski
What about:
typedef struct {
HANDLE handle;
void *(*start_routine)(void *);
void *arg;
}pthread_t;DWORD
__stdcallwindows_thread_start(LPVOID _self){
pthread_t *self =_self;
void *ret =self->start_routine(self->arg); return (DWORD)ret;
}Quoted 7 lines
static inline int
pthread_create(pthread_t *thread, const void *unused, void *(*start_routine)(void *), void *arg){
thread->handle =CreateThread(NULL, 0, windows_thread_start, thread, 0, NULL);
[...]
}
Quoted 7 lines
The problem I see is not with
pthread_init, butpthread_join. Here's how it looks:int
pthread_join(pthread_t thread, void **value_ptr);If
pthread_twould be a struct, then we can't callpthread_joinlike that...
Why not? At least gcc is quite happy with such a construct. It probably makes a copy of the stack before passing it though.
Quoted 11 lines
At least that's what I though yesterday, but maybe it can be done like this:
int
win32_pthread_join(pthread_t *thread, void **value_ptr){ [...] }#define
pthread_join(a, b)win32_pthread_join(&(a), (b))That way we don't need allocations to simulate pthread init/join API
Right.
Nicolas
Re: [PATCH] MSVC: Windows-native implementation for subset of Pthreads API
2009/11/5 Nicolas Pitre <[email protected]>:
Quoted 2 lines
Why not? At least gcc is quite happy with such a construct. It probably makes a copy of the stack before passing it though.
Err... my mind is rotted with all that ugly java, c#, python and ruby, even c++. I should start taking some medications I suppose... what was I thinking is that C can't copy-construct a struct. Damn, too much sun (of java fame)...
That way I rediscovered simple struct construct...man I missed C so much :)
Anyway, the solution with passing pthread_t as pointer saves some stack, so it's probably not that bad.
--
Andrzej
Re: [PATCH] MSVC: Windows-native implementation for subset of Pthreads API
Quoted 3 lines · Andrzej K. Haczewski
2009/11/5 Nicolas Pitre <[email protected]>:
Quoted 2 lines
Why not? At least gcc is quite happy with such a construct. It probably makes a copy of the stack before passing it though.
"a copy of the struct" I meant here.
Quoted 6 lines
Err... my mind is rotted with all that ugly java, c#, python and ruby, even c++. I should start taking some medications I suppose... what was I thinking is that C can't copy-construct a struct. Damn, too much sun (of java fame)...
That way I rediscovered simple struct construct...man I missed C so much :)
Welcome back ! ;-)
Quoted 2 lines
Anyway, the solution with passing
pthread_tas pointer saves some stack, so it's probably not that bad.
Yep, just what I said. Normally if you pass a structure to a function, it will be copied beforehand so modifications by the callee won't be seen by the caller. But in this case we don't care, hence passing the original structure address is more efficient.
Nicolas
PATCH 1/1 MSVC: Windows-native implementation for subset of Pthreads API
In reply to Andrzej K. HaczewskiThis patch implements native to Windows subset of pthreads API used by Git. It allows to remove Pthreads for Win32 dependency for msysgit and cygwin.
The patch modifies Makefile only for MSVC (that's the environment I'm capable of testing on), so it requires further corrections to compile with MinGW or Cygwin.
--- Makefile | 4 +- builtin-pack-objects.c | 34 ++++++++++-- compat/mingw.c | 2 +- compat/mingw.h | 5 ++ compat/win32/pthread.h | 132 ++++++++++++++++++++++++++++++++++++++++++++++++ git-compat-util.h | 10 ++++ preload-index.c | 4 +- 7 files changed, 180 insertions(+), 11 deletions(-) create mode 100644 compat/win32/pthread.h
Makefile +2 -2
@@ -975,7 +975,7 @@ ifdef MSVC OBJECT_CREATION_USES_RENAMES = UnfortunatelyNeedsTo NO_REGEX = YesPlease NO_CURL = YesPlease - NO_PTHREADS = YesPlease + THREADED_DELTA_SEARCH = YesPlease BLK_SHA1 = YesPlease CC = compat/vcbuild/scripts/clink.pl
@@ -983,7 +983,7 @@ ifdef MSVC CFLAGS = BASIC_CFLAGS = -nologo -I. -I../zlib -Icompat/vcbuild -Icompat/vcbuild/include -DWIN32 -D_CONSOLE -DHAVE_STRING_H -D_CRT_SECURE_NO_WARNINGS -D_CRT_NONSTDC_NO_DEPRECATE COMPAT_OBJS = compat/msvc.o compat/fnmatch/fnmatch.o compat/winansi.o - COMPAT_CFLAGS = -D__USE_MINGW_ACCESS -DNOGDI -DHAVE_STRING_H -DHAVE_ALLOCA_H -Icompat -Icompat/fnmatch -Icompat/regex -Icompat/fnmatch -DSTRIP_EXTENSION=\".exe\" + COMPAT_CFLAGS = -D__USE_MINGW_ACCESS -DNOGDI -DHAVE_STRING_H -DHAVE_ALLOCA_H -Icompat -Icompat/fnmatch -Icompat/regex -Icompat/fnmatch -Icompat/win32 -DSTRIP_EXTENSION=\".exe\" BASIC_LDFLAGS = -IGNORE:4217 -IGNORE:4049 -NOLOGO -SUBSYSTEM:CONSOLE -NODEFAULTLIB:MSVCRT.lib EXTLIBS = advapi32.lib shell32.lib wininet.lib ws2_32.lib lib =
builtin-pack-objects.c +28 -6
@@ -1255,15 +1255,15 @@ static int delta_cacheable(unsigned long src_size, unsigned long trg_size,#ifdef THREADED_DELTA_SEARCH -static pthread_mutex_t read_mutex =PTHREAD_MUTEX_INITIALIZER ; +static pthread_mutex_t read_mutex;#define read_lock () pthread_mutex_lock(&read_mutex)#define read_unlock () pthread_mutex_unlock(&read_mutex) -static pthread_mutex_t cache_mutex =PTHREAD_MUTEX_INITIALIZER ; +static pthread_mutex_t cache_mutex;#define cache_lock () pthread_mutex_lock(&cache_mutex)#define cache_unlock () pthread_mutex_unlock(&cache_mutex) -static pthread_mutex_t progress_mutex =PTHREAD_MUTEX_INITIALIZER ; +static pthread_mutex_t progress_mutex;#define progress_lock () pthread_mutex_lock(&progress_mutex)#define progress_unlock () pthread_mutex_unlock(&progress_mutex)
@@ -1590,9 +1590,28 @@ struct thread_params {unsigned *processed; }; -static pthread_cond_t progress_cond =PTHREAD_COND_INITIALIZER ; +static pthread_cond_t progress_cond; -static void *threaded_find_deltas (void *arg) +/* +* Mutex and conditional variable can't be statically-initialized on Windows. +*/ +static void init_threaded_search () +{ +pthread_mutex_init (&read_mutex); +pthread_mutex_init (&cache_mutex); +pthread_mutex_init (&progress_mutex); +pthread_cond_init (&progress_cond,NULL ); +} + +static void cleanup_threaded_search () +{ +pthread_cond_destroy (&progress_cond); +pthread_mutex_destroy (&read_mutex); +pthread_mutex_destroy (&cache_mutex); +pthread_mutex_destroy (&progress_mutex); +} + +static THREAD_RET_TYPE threaded_find_deltas (void *arg) {struct thread_params *me = arg;
@@ -1620,7 +1639,7 @@ static void *threaded_find_deltas(void *arg)pthread_mutex_unlock (&me->mutex); }/* leave ->working 1 so that this doesn't get more work assigned */ -return NULL ; +return 0 ; } static void ll_find_deltas(struct object_entry **list, unsigned list_size,
@@ -1638,6 +1657,8 @@ static void ll_find_deltas(struct object_entry **list, unsigned list_size, delta_search_threads); p =xcalloc (delta_search_threads,sizeof (*p)); +init_threaded_search (); +/* Partition the work amongst work threads. */ for (i =0 ; i < delta_search_threads; i++) {unsigned sub_size = list_size / (delta_search_threads - i);
@@ -1745,6 +1766,7 @@ static void ll_find_deltas(struct object_entry **list, unsigned list_size, active_threads--; } } +cleanup_threaded_search ();free (p); }
compat/mingw.c +1 -1
@@ -5,7 +5,7 @@#include <shellapi.h> -static int err_win_to_posix (DWORD winerr) +int err_win_to_posix (DWORD winerr) {int error =ENOSYS ;switch (winerr) {
compat/mingw.h +5 -0
@@ -294,3 +294,8 @@ struct mingw_dirent#define readdir (x) mingw_readdir(x)struct dirent *mingw_readdir (DIR *dir);#endif // !NO_MINGW_REPLACE_READDIR + +/* +* Used by Pthread API implementation for Windows +*/ +extern int err_win_to_posix (DWORD winerr);
compat/win32/pthread.h new file +132 -0
132 lines not on this page · raw message
git-compat-util.h +10 -0
@@ -464,4 +464,14 @@ void git_qsort(void *base, size_t nmemb, size_t size,*/ int unlink_or_warn (const char *path); +/* +* Define type of thread function return type to distinguish +* Windows and POSIX. +*/ +#ifndef _WIN32 +# define THREAD_RET_TYPE void * +#else +# define THREAD_RET_TYPE DWORD __stdcall +#endif +#endif
preload-index.c +2 -2
@@ -28,7 +28,7 @@ struct thread_data {int offset, nr; }; -static void *preload_thread (void *_data) +static THREAD_RET_TYPE preload_thread (void * _data) {int nr;struct thread_data *p = _data;
@@ -59,7 +59,7 @@ static void *preload_thread(void *_data)continue ;ce_mark_uptodate (ce); }while (--nr >0 ); -return NULL ; +return 0 ; }static void preload_index (struct index_state *index,const char **pathspec)
Signature · 1 line
1.6.5.2
PATCH 1/1 MSVC: Windows-native implementation for subset of Pthreads API
This patch implements native to Windows subset of pthreads API used by Git. It allows to remove Pthreads for Win32 dependency for msysgit and cygwin.
The patch modifies Makefile only for MSVC (that's the environment I'm capable of testing on), so it requires further corrections to compile with MinGW or Cygwin.
---
Ignore previous patch, there was a compile error for POSIX platform (pthread_mutex_init takes 2 arguments, MSVC doesn't complain if 1 argument is supplied to a macro call, but on POSIX it's function call).
I haven't integrated Nicolas patch.
Makefile | 4 +- builtin-pack-objects.c | 34 ++++++++++-- compat/mingw.c | 2 +- compat/mingw.h | 5 ++ compat/win32/pthread.h | 132 ++++++++++++++++++++++++++++++++++++++++++++++++ git-compat-util.h | 10 ++++ preload-index.c | 4 +- 7 files changed, 180 insertions(+), 11 deletions(-) create mode 100644 compat/win32/pthread.h
Makefile +2 -2
@@ -975,7 +975,7 @@ ifdef MSVC OBJECT_CREATION_USES_RENAMES = UnfortunatelyNeedsTo NO_REGEX = YesPlease NO_CURL = YesPlease - NO_PTHREADS = YesPlease + THREADED_DELTA_SEARCH = YesPlease BLK_SHA1 = YesPlease CC = compat/vcbuild/scripts/clink.pl
@@ -983,7 +983,7 @@ ifdef MSVC CFLAGS = BASIC_CFLAGS = -nologo -I. -I../zlib -Icompat/vcbuild -Icompat/vcbuild/include -DWIN32 -D_CONSOLE -DHAVE_STRING_H -D_CRT_SECURE_NO_WARNINGS -D_CRT_NONSTDC_NO_DEPRECATE COMPAT_OBJS = compat/msvc.o compat/fnmatch/fnmatch.o compat/winansi.o - COMPAT_CFLAGS = -D__USE_MINGW_ACCESS -DNOGDI -DHAVE_STRING_H -DHAVE_ALLOCA_H -Icompat -Icompat/fnmatch -Icompat/regex -Icompat/fnmatch -DSTRIP_EXTENSION=\".exe\" + COMPAT_CFLAGS = -D__USE_MINGW_ACCESS -DNOGDI -DHAVE_STRING_H -DHAVE_ALLOCA_H -Icompat -Icompat/fnmatch -Icompat/regex -Icompat/fnmatch -Icompat/win32 -DSTRIP_EXTENSION=\".exe\" BASIC_LDFLAGS = -IGNORE:4217 -IGNORE:4049 -NOLOGO -SUBSYSTEM:CONSOLE -NODEFAULTLIB:MSVCRT.lib EXTLIBS = advapi32.lib shell32.lib wininet.lib ws2_32.lib lib =
builtin-pack-objects.c +28 -6
@@ -1255,15 +1255,15 @@ static int delta_cacheable(unsigned long src_size, unsigned long trg_size,#ifdef THREADED_DELTA_SEARCH -static pthread_mutex_t read_mutex =PTHREAD_MUTEX_INITIALIZER ; +static pthread_mutex_t read_mutex;#define read_lock () pthread_mutex_lock(&read_mutex)#define read_unlock () pthread_mutex_unlock(&read_mutex) -static pthread_mutex_t cache_mutex =PTHREAD_MUTEX_INITIALIZER ; +static pthread_mutex_t cache_mutex;#define cache_lock () pthread_mutex_lock(&cache_mutex)#define cache_unlock () pthread_mutex_unlock(&cache_mutex) -static pthread_mutex_t progress_mutex =PTHREAD_MUTEX_INITIALIZER ; +static pthread_mutex_t progress_mutex;#define progress_lock () pthread_mutex_lock(&progress_mutex)#define progress_unlock () pthread_mutex_unlock(&progress_mutex)
@@ -1590,9 +1590,28 @@ struct thread_params {unsigned *processed; }; -static pthread_cond_t progress_cond =PTHREAD_COND_INITIALIZER ; +static pthread_cond_t progress_cond; -static void *threaded_find_deltas (void *arg) +/* +* Mutex and conditional variable can't be statically-initialized on Windows. +*/ +static void init_threaded_search () +{ +pthread_mutex_init (&read_mutex,NULL ); +pthread_mutex_init (&cache_mutex,NULL ); +pthread_mutex_init (&progress_mutex,NULL ); +pthread_cond_init (&progress_cond,NULL ); +} + +static void cleanup_threaded_search () +{ +pthread_cond_destroy (&progress_cond); +pthread_mutex_destroy (&read_mutex); +pthread_mutex_destroy (&cache_mutex); +pthread_mutex_destroy (&progress_mutex); +} + +static THREAD_RET_TYPE threaded_find_deltas (void *arg) {struct thread_params *me = arg;
@@ -1620,7 +1639,7 @@ static void *threaded_find_deltas(void *arg)pthread_mutex_unlock (&me->mutex); }/* leave ->working 1 so that this doesn't get more work assigned */ -return NULL ; +return 0 ; } static void ll_find_deltas(struct object_entry **list, unsigned list_size,
@@ -1638,6 +1657,8 @@ static void ll_find_deltas(struct object_entry **list, unsigned list_size, delta_search_threads); p =xcalloc (delta_search_threads,sizeof (*p)); +init_threaded_search (); +/* Partition the work amongst work threads. */ for (i =0 ; i < delta_search_threads; i++) {unsigned sub_size = list_size / (delta_search_threads - i);
@@ -1745,6 +1766,7 @@ static void ll_find_deltas(struct object_entry **list, unsigned list_size, active_threads--; } } +cleanup_threaded_search ();free (p); }
compat/mingw.c +1 -1
@@ -5,7 +5,7 @@#include <shellapi.h> -static int err_win_to_posix (DWORD winerr) +int err_win_to_posix (DWORD winerr) {int error =ENOSYS ;switch (winerr) {
compat/mingw.h +5 -0
@@ -294,3 +294,8 @@ struct mingw_dirent#define readdir (x) mingw_readdir(x)struct dirent *mingw_readdir (DIR *dir);#endif // !NO_MINGW_REPLACE_READDIR + +/* +* Used by Pthread API implementation for Windows +*/ +extern int err_win_to_posix (DWORD winerr);
compat/win32/pthread.h new file +132 -0
132 lines not on this page · raw message
git-compat-util.h +10 -0
@@ -464,4 +464,14 @@ void git_qsort(void *base, size_t nmemb, size_t size,*/ int unlink_or_warn (const char *path); +/* +* Define type of thread function return type to distinguish +* Windows and POSIX. +*/ +#ifndef _WIN32 +# define THREAD_RET_TYPE void * +#else +# define THREAD_RET_TYPE DWORD __stdcall +#endif +#endif
preload-index.c +2 -2
@@ -28,7 +28,7 @@ struct thread_data {int offset, nr; }; -static void *preload_thread (void *_data) +static THREAD_RET_TYPE preload_thread (void * _data) {int nr;struct thread_data *p = _data;
@@ -59,7 +59,7 @@ static void *preload_thread(void *_data)continue ;ce_mark_uptodate (ce); }while (--nr >0 ); -return NULL ; +return 0 ; }static void preload_index (struct index_state *index,const char **pathspec)
-- 1.6.5.2
Re: [PATCH] MSVC: Windows-native implementation for subset of Pthreads API
Quoted 6 lines · Andrzej K. Haczewski
This patch implements native to Windows subset of pthreads API used by Git. It allows to remove Pthreads for Win32 dependency for msysgit and cygwin.
The patch modifies
Makefileonly for MSVC (that's the environment I'm capable of testing on), so it requires further corrections to compile with MinGW or Cygwin.
Looks quite good already.
In the next round, please squash this in.
Makefile +1 -0
@@ -414,6 +414,7 @@ LIB_H += cache-tree.h LIB_H += commit.h LIB_H += compat/cygwin.h LIB_H += compat/mingw.h +LIB_H += compat/win32/pthread.h LIB_H += csum-file.h LIB_H += decorate.h LIB_H += delta.h
Re: [PATCH] MSVC: Windows-native implementation for subset of Pthreads API
In reply to Andrzej K. Haczewskibuiltin-pack-objects.c static void ll_find_deltas(struct object_entry **list, unsigned list_size, · line 1660
Quoted 5 lines · Andrzej K. Haczewski
builtin-pack-objects.c +1
-0@@ -1638,6 +1657,8 @@ static void ll_find_deltas(struct object_entry **list, unsigned list_size, delta_search_threads); p =xcalloc (delta_search_threads,sizeof (*p)); +init_threaded_search ();
Careful. At the beginning of the function you'll find:
if (delta_search_threads <= 1) {
find_deltas(list, &list_size, window, depth, processed);
return;
}That is, if we have thread support compiled in but we're told to use only one thread, then the bulk of the work splitting is bypassed entirely. Inside find_deltas() there will still be pthread_mutex_lock() and pthread_mutex_unlock() calls even if no threads are spawned.
Nicolas
Re: [PATCH] MSVC: Windows-native implementation for subset of Pthreads API
2009/11/5 Nicolas Pitre <[email protected]>:
Quoted 11 lines
Careful. At the beginning of the function you'll find:
if (
delta_search_threads<= 1) {
find_deltas(list,&list_size, window, depth, processed); return;
}That is, if we have thread support compiled in but we're told to use only one thread, then the bulk of the work splitting is bypassed entirely. Inside
find_deltas()there will still bepthread_mutex_lock()andpthread_mutex_unlock()calls even if no threads are spawned.
Ah, I wasn't aware of that. Actually why would find_deltas lock if no threads are used? Maybe, for non-threaded call to find_deltas, locking could be factored out?
--
Andrzej
Re: [PATCH] MSVC: Windows-native implementation for subset of Pthreads API
Quoted 8 lines · Andrzej K. Haczewski
2009/11/5 Nicolas Pitre <[email protected]>:
Quoted 7 lines
Careful. At the beginning of the function you'll find:
if (
delta_search_threads<= 1) {
find_deltas(list,&list_size, window, depth, processed); return;
}
Quoted 8 lines
Quoted 4 lines
That is, if we have thread support compiled in but we're told to use only one thread, then the bulk of the work splitting is bypassed entirely. Inside
find_deltas()there will still bepthread_mutex_lock()andpthread_mutex_unlock()calls even if no threads are spawned.Ah, I wasn't aware of that. Actually why would
find_deltaslock if no threads are used? Maybe, for non-threaded call tofind_deltas, locking could be factored out?
It is already factored out when thread support is not enabled.
When thread support is enabled but there is only one thread, there was no point duplicating the code just to have a path without any mutexes, especially on Linux where no performance difference could be measured.
Nicolas
Re: [PATCH] MSVC: Windows-native implementation for subset of Pthreads API
In reply to Andrzej K. Haczewskicompat/win32/pthread.h line 40
Quoted 11 lines · Andrzej K. Haczewski
compat/win32/pthread.h new file +11
-0+static inline int pthread_cond_init (pthread_cond_t *cond,const void *unused) +{ + cond->waiters =0 ; + +InitializeCriticalSection (&cond->waiters_lock); + + cond->sema =CreateSemaphore (NULL ,0 ,LONG_MAX ,NULL ); +if (!cond->sema) +return 0 ;/* POSIX do not allow pthread_cond_init to fail */ +return 0 ; +}
Please use die("CreateSemaphore() failed") in the failure case instead of returning success.
However, my pthread_cond_init man page says:
[[[
RETURN VALUE
If successful, the pthread_cond_destroy() and pthread_cond_init() func- tions shall return zero; otherwise, an error number shall be returned to indicate the error.
The [EBUSY] and [EINVAL] error checks, if implemented, shall act as if they were performed immediately at the beginning of processing for the function and caused an error return prior to modifying the state of the condition variable specified by cond.
ERRORS
The pthread_cond_destroy() function may fail if:
EBUSY The implementation has detected an attempt to destroy the object
referenced by cond while it is referenced (for example, while being used in a pthread_cond_wait() or pthread_cond_timedwait()) by another thread.
EINVAL The value specified by cond is invalid.
The pthread_cond_init() function shall fail if:
EAGAIN The system lacked the necessary resources (other than memory) to
initialize another condition variable.
ENOMEM Insufficient memory exists to initialize the condition variable.
The pthread_cond_init() function may fail if:
EBUSY The implementation has detected an attempt to reinitialize the
object referenced by cond, a previously initialized, but not yet destroyed, condition variable.
EINVAL The value specified by attr is invalid.
]]]
I'm not advocating that you implement detailed error codes as we don't really care about specific errors. This is just to disagree with the "POSIX do not allow pthread_cond_init to fail" assertion. In any case, using die() to keep it simple is certainly better than blindly returning 0 on failure. However you could simply return ENOMEM and use the die() in init_threaded_search() instead.
Nicolas
Re: [PATCH] MSVC: Windows-native implementation for subset of Pthreads API
2009/11/5 Nicolas Pitre <[email protected]>:
Quoted 2 lines
Please use
die("CreateSemaphore() failed")in the failure case instead of returning success.
Sure, will do.
Quoted 1 line
However, my
pthread_cond_initman page says:
And that is weird, because mine man page says:
[[[pthread_cond_init, pthread_cond_signal, pthread_cond_broadcast, and pthread_cond_wait never return an error code.
]]]
--
Andrzej
Re: [PATCH] MSVC: Windows-native implementation for subset of Pthreads API
Quoted 7 lines · Andrzej K. Haczewski
Quoted 1 line
However, my
pthread_cond_initman page says:And that is weird, because mine man page says:
[[[pthread_cond_init,pthread_cond_signal,pthread_cond_broadcast, andpthread_cond_waitnever return an error code.
]]]
Maybe that's for a particular implementation.
Nicolas
PATCH 1/1 pack-objects: move thread autodetection closer to relevant code
In reply to Andrzej K. HaczewskiLet's keep thread stuff close together if possible. And in this case, this even reduces the #ifdef noise, and allows for skipping the autodetection altogether if delta search is not needed (like with a pure clone).
---
Quoted 13 lines
2009/11/4 Nicolas Pitre <[email protected]>:
Quoted 12 lines
Quoted 6 lines
(quoted diff) +0
-0@@ -2327,6 +2354,8 @@ int cmd_pack_objects(int argc, const char **argv, const char *prefix) #ifdef THREADED_DELTA_SEARCHif (!delta_search_threads) /* --threads=0 means autodetect */
delta_search_threads=online_cpus();
+
+init_threaded_delta_search();What about doing this at the beginning of
ll_find_deltas()instead? And similarly forcleanup_threaded_delta_search(): call it right before leavingll_find_deltas(). This way thread issues would remain more localized. In fact I'd move the whole thing above inll_find_deltas()as well (separately from this patch though).
So here it is.
builtin-pack-objects.c +2 -5
@@ -1629,6 +1629,8 @@ static void ll_find_deltas(struct object_entry **list, unsigned list_size,struct thread_params *p;int i, ret, active_threads =0 ; +if (!delta_search_threads)/* --threads=0 means autodetect */ + delta_search_threads =online_cpus ();if (delta_search_threads <=1 ) {find_deltas (list, &list_size, window, depth, processed);return ;
@@ -2324,11 +2326,6 @@ int cmd_pack_objects(int argc, const char **argv, const char *prefix)if (keep_unreachable && unpack_unreachable)die ("--keep-unreachable and --unpack-unreachable are incompatible." ); -#ifdef THREADED_DELTA_SEARCH -if (!delta_search_threads)/* --threads=0 means autodetect */ - delta_search_threads =online_cpus (); -#endif -prepare_packed_git ();if (progress)
Re: [PATCH] pack-objects: move thread autodetection closer to relevant code
Quoted 4 lines · Nicolas Pitre
Let's keep thread stuff close together if possible. And in this case, this even reduces the #ifdef noise, and allows for skipping the autodetection altogether if delta search is not needed (like with a pure clone).
Nice. The ll_find_delta() function itself will disappear and becomes the single-threaded find_deltas() when THREADED_DELTA_SEARCH is not defined, and the variable in question is used only inside the function anyway, so this works beautifully.
Very nice.
Re: [PATCH] MSVC: Windows-native implementation for subset of Pthreads API
In reply to Andrzej K. HaczewskiQuoted 5 lines · Andrzej K. Haczewski
2009/11/4 Nicolas Pitre <[email protected]>:
Quoted 4 lines · Andrzej K. Haczewski
Quoted 2 lines
+
NO_STATIC_PTHREADS_INIT= YesPlease
Quoted 8 lines
Quoted 5 lines
Let's not go that route please. If Windows can't get away without runtime initializations then let's use them on all platforms. There is no gain in exploding the code path combinations here wrt testing coverage.
I don't like that approach either, but I was frighten of Junio being anal about static inits ;).
I think the alternative is much worse than loosing those static inits.
Quoted 3 lines
Let's make it clear: has anyone have any objections that I add explicit initialization of mutexes and condition variables for POSIX also?
Please do it and if anyone finds a problem with it then we'll start from there.
Nicolas
Re: [PATCH] MSVC: Windows-native implementation for subset of Pthreads API
In reply to Nicolas PitreQuoted 8 lines · Nicolas Pitre
Makefile ifdef MSVC · line 943
Quoted 1 line · Andrzej K. Haczewski
Makefile +1
-0+ NO_STATIC_PTHREADS_INIT = YesPleaseLet's not go that route please. If Windows can't get away without runtime initializations then let's use them on all platforms. There is no gain in exploding the code path combinations here wrt testing coverage.
Hear hear.
Re: [PATCH] MSVC: port pthread code to native Windows threads
In reply to Andrzej K. Haczewskigit-compat-util.h void git_qsort(void *base, size_t nmemb, size_t size, · line 479
Quoted 13 lines · Andrzej K. Haczewski
git-compat-util.h +13
-0+/* +* Properly defines thread routine for Windows and POSIX +*/ +#ifndef NO_PTHREADS +# ifndef _WIN32 +# define THREAD_FUNC(f, a) void *f(void *a) +# define THREAD_RETURN(x) return (x) +# else +# define THREAD_FUNC(f, a) DWORD __stdcall f(LPVOID a) +# define THREAD_RETURN(x) return (DWORD)(x); +# endif +#endif +
Seeing how THREAD_RETURN is only called with NULL-parameter, perhaps it would be better to do this?
+/*
+ * Properly defines thread routine for Windows and POSIX
+ */
+#ifndef NO_PTHREADS
+# ifndef _WIN32
+# define THREAD_FUNC(f, a) void *f(void *a)
+# define THREAD_RETURN() return NULL;
+# else
+# define THREAD_FUNC(f, a) DWORD __stdcall f(LPVOID a) +# define THREAD_RETURN() return 0;
+# endif
+#endif
Quoted 1 line
+
Signature · 1 line
Erik "kusma" Faye-Lund
Re: [PATCH] MSVC: port pthread code to native Windows threads
2009/11/4 Erik Faye-Lund <[email protected]>:
Quoted 6 lines
Seeing how
THREAD_RETURNis only called with NULL-parameter, perhaps it would be better to do this?git-compat-util.h +2
-0+/* +* Properly defines thread routine for Windows and POSIX
git-compat-util.h void git_qsort(void *base, size_t nmemb, size_t size, · line 478
Quoted 10 lines
git-compat-util.h +10
-0+*/ +#ifndef NO_PTHREADS +# ifndef _WIN32 +# define THREAD_FUNC(f, a) void *f(void *a) +# define THREAD_RETURN() return NULL; +# else +# define THREAD_FUNC(f, a) DWORD __stdcall f(LPVOID a) +# define THREAD_RETURN() return 0; +# endif +#endif
Good point. Should I resubmit the patch again?
Andrew
Re: [PATCH] MSVC: port pthread code to native Windows threads
In reply to Erik Faye-LundQuoted 31 lines · Erik Faye-Lund
git-compat-util.h void git_qsort(void *base, size_t nmemb, size_t size, · line 479
Quoted 13 lines · Andrzej K. Haczewski
git-compat-util.h +13
-0+/* +* Properly defines thread routine for Windows and POSIX +*/ +#ifndef NO_PTHREADS +# ifndef _WIN32 +# define THREAD_FUNC (f, a) void *f(void *a) +# define THREAD_RETURN (x) return (x) +# else +# define THREAD_FUNC (f, a) DWORD __stdcall f(LPVOID a) +# define THREAD_RETURN (x) return (DWORD)(x); +# endif +#endif +Seeing how
THREAD_RETURNis only called with NULL-parameter, perhaps it would be better to do this?git-compat-util.h +12
-0+/* +* Properly defines thread routine for Windows and POSIX +*/ +#ifndef NO_PTHREADS +# ifndef _WIN32 +# define THREAD_FUNC (f, a) void *f(void *a) +# define THREAD_RETURN () return NULL; +# else +# define THREAD_FUNC (f, a) DWORD __stdcall f(LPVOID a) +# define THREAD_RETURN () return 0; +# endif +#endif
Quoted 1 line
Quoted 1 line
+
Even better, "return 0" is good under either platform (0 converts to void *), and LPVOID is the same thing as void*, so you can just do
#ifndef _WIN32
# define THREAD_RET_TYPE DWORD __stdcall #else # define THREAD_RET_TYPE void * #endif
Paolo
Re: [PATCH] MSVC: port pthread code to native Windows threads
In reply to Andrzej K. HaczewskiPlease do not cull Cc list when you resend a patch, if possible.
After staring some time on the code, I have convinced myself that the pthread_cond_wait and pthread_cond_signal implementation will work *in our usage scenario* that has these preconditions:
- There is no more than one thread waiting on any particular condition variable instance.
- pthread_cond_signal is called while the mutex is held.
- We retest the condition after pthread_cond_wait returns.
These conditions should be attached in BIG BOLD letters to this implementation; particularly, the last one.
On to your patch...
The subject is a bit misleading, IMHO. You are not porting the (p)threading code, but you are adding pthread_* function wrappers for Windows.
Your patch adds whitespace-at-eol. Please use git show --check to see where.
Quoted 17 lines · Andrzej K. Haczewski
Here is slightly modified patch with more comments where explanations were requested (ie. non atomic release mutex and wait).
The implementation of conditional variable is based on ACE.
The patch needs testing from someone capable of compiling Git on Windows and running it with msysgit environment. I can confirm that it compiles cleanly on both Linux and Windows. I modified
Makefileonly for MSVC part, so if you'd like to compile it with mingw or cygwin, proper corrections have to be made. I aim for native MSVC compilation, that's why I did it like that. That's also the reason I don't like having Pthreads for Win32 dependency - it's faster to use native calls than depend on 3rd party wrapper library to do it for you (ie. pthreads for win32 does allocations to implement POSIX standard, and full-conformance isn't required by Git, since Git uses only small subset of pthreads).
Quoted 6 lines
One more motivation I had for the patch: as I was reading through archives I had a feeling that Git aims to be as lightweight as possible, hence removing additional dependencies (even for Windows platform) seems sensible to me.
Signed-off-by Andrzej K. Haczewski <[email protected]>
Please drop words from the commit message that do not make sense once this commit is in git's history. Look at existing commit messages to get a feeling for the style. Do write about "why" (motivation), "how" (design choices) and "how not" (dead ends that you tried).
builtin-pack-objects.c struct thread_params {
Quoted 13 lines
builtin-pack-objects.c +2
-2@@ -1592,7 +1592,7 @@ struct thread_params {static pthread_cond_t progress_cond =PTHREAD_COND_INITIALIZER ; -static void *threaded_find_deltas (void *arg) +static THREAD_FUNC(threaded_find_deltas, arg) - returnNULL ; +THREAD_RETURN (NULL);
See Erik's and Paolo's comments.
Quoted 5 lines
builtin-pack-objects.c +1
-0@@ -2327,6 +2327,18 @@ int cmd_pack_objects(int argc, const char **argv, const char *prefix)#ifdef THREADED_DELTA_SEARCH if (!delta_search_threads)/* --threads=0 means autodetect */ delta_search_threads =online_cpus (); +
builtin-pack-objects.c int cmd_pack_objects(int argc, const char **argv, const char *prefix) · line 2340
Quoted 10 lines
builtin-pack-objects.c +10
-0+#ifdef _WIN32 +/* +* Windows requires initialization of mutex (CRITICAL_SECTION) +* and conditional variable. +*/ +pthread_mutex_init (&read_mutex); +pthread_mutex_init (&cache_mutex); +pthread_mutex_init (&progress_mutex); +pthread_cond_init (&progress_cond,NULL ); +#endif
I think it would be OK to drop '= PTHREAD_{MUTEX,COND}_INITIALIZER' and use *_init function calls without the #ifdef. Likewise for *_destroy.
builtin-pack-objects.c int cmd_pack_objects(int argc, const char **argv, const char *prefix) · line 2380
Quoted 12 lines
builtin-pack-objects.c +10
-0+cleanup: +#if defined(THREADED_DELTA_SEARCH ) && defined(_WIN32) +/* cleanup Windows threads thingies */ +pthread_cond_destroy (&progress_cond); +pthread_mutex_destroy (&read_mutex); +pthread_mutex_destroy (&cache_mutex); +pthread_mutex_destroy (&progress_mutex); +#endif +return 0 ; } +
Drop this empty line at EOF.
builtin-pack-objects.c line 2
Quoted 3 lines
builtin-pack-objects.c +2
-0@@ -0,0 +1,143 @@ +/* +* Header used to "adapt" pthread-based POSIX code to Windows API threads.
I think "adapt" is the right word here. You don't need to put it in quotes. ;)
Quoted 6 lines
builtin-pack-objects.c +6
-0+* +* Copyright (C) 2009 Andrzej K. Haczewski <[email protected]> +*/ + +#ifndef PTHREAD_H +#define PTHREAD_H
builtin-pack-objects.c line 18
Quoted 10 lines
builtin-pack-objects.c +10
-0+ +#ifndef WIN32_LEAN_AND_MEAN +#define WIN32_LEAN_AND_MEAN +#endif + +#include <windows.h> + +/* +* don't include mingw.h for err_win_to_posix function - mingw.h doesn't +* have include-guards
So what? Is there an #include loop? Can't you add include guards?
builtin-pack-objects.c line 19
Quoted 1 line
builtin-pack-objects.c +1
-0+static __inlineint pthread_cond_init (pthread_cond_t *cond,const void *unused)
What's wrong with 'static inline int ...' (without the underscores)?
builtin-pack-objects.c line 28
Quoted 9 lines
builtin-pack-objects.c +9
-0+{ + cond->waiters =0 ; + +InitializeCriticalSection (&cond->waiters_lock); + + cond->sema =CreateSemaphore (NULL ,0 ,LONG_MAX ,NULL ); +if (NULL == cond->sema) +return -1 ; +return 0 ;
In case of failure, the pthread_* functions return the error number, not -1. Moreover, we write
if (!cond->sema) return err_win_to_posix(GetLastError()); or return cond->sema ? 0 : err_win_to_posix(GetLastError());
builtin-pack-objects.c
Quoted 6 lines
builtin-pack-objects.c +5
-0+static __inlineint pthread_cond_wait (pthread_cond_t *cond,CRITICAL_SECTION *mutex) +{ +/* let's wait */ +if (0 !=WaitForSingleObject (cond->sema,INFINITE )) + ret =-1 ;
Mind the return value!
builtin-pack-objects.c
Quoted 5 lines
builtin-pack-objects.c +4
-0+static __inlineint pthread_cond_signal (pthread_cond_t *cond) +{ +if (have_waiters) +return ReleaseSemaphore (cond->sema,1 ,NULL ) ?0 :-1 ;
Return value again.
builtin-pack-objects.c
Quoted 5 lines
builtin-pack-objects.c +5
-0+static __inlineint pthread_create (pthread_t *t,const void *unused,DWORD (__stdcall *start_routine)(LPVOID ),void *arg) +{ + *t =CreateThread (NULL ,0 , start_routine, arg,0 ,NULL ); + +if (NULL == *t) {
if (!*t)
builtin-pack-objects.c
Quoted 2 lines
builtin-pack-objects.c +2
-0+ errno =err_win_to_posix (GetLastError ()); +return -1 ;
Return value again. errno is not set.
builtin-pack-objects.c
Quoted 11 lines
builtin-pack-objects.c +10
-0+ }else { + errno =0 ; +return 0 ; + } +} + +static __inlineint pthread_join (pthread_t t,void **unused) +{ + errno =err_win_to_posix (GetLastError ()); +return -1 ;
And again.
-- Hannes
Re: [PATCH] MSVC: port pthread code to native Windows threads
2009/11/4 Johannes Sixt <[email protected]>:
Quoted 1 line
Please do not cull Cc list when you resend a patch, if possible.
Ok, will do. I was sending patch using git send-email and I just forgot to copy Cc there. Still trying to BTW is there a way to "reformat-patch" with new amended commit and then "resend-email"?
Quoted 3 lines
After staring some time on the code, I have convinced myself that the
pthread_cond_waitandpthread_cond_signalimplementation will work *in our usage scenario* that has these preconditions:
But it is not impossible with that implementation. I based this implementation on ACE (Adaptive Communication Environment, large C++ library) implementation of the same concepts. All I removed from their implementation is cond_broadcast, since it's not used by Git. I'm sure that ACE does the best job when it comes to threading primitives.
On resubmit I'll give more credit to ACE.
Quoted 1 line
-
pthread_cond_signalis called while the mutex is held.
AFAIK that is a requirement for condition variable to be signaled while holding the same mutex that other threads cond_wait on. I just don't check that it is true, because Git is locking mutex.
Quoted 4 lines
- We retest the condition after
pthread_cond_waitreturns.These conditions should be attached in BIG BOLD letters to this implementation; particularly, the last one.
That's also a known requirement for working with cond vars. Here's excerpt from pthread_cond_wait man page:
When using condition variables there is always a boolean predicate involving shared variables associated with each condition wait that is true if the thread should proceed. Spurious wakeups from the pthread_cond_wait() or pthread_cond_timedwait() functions may occur. Since the return from pthread_cond_wait() or pthread_cond_timedwait() does not imply anything about the value of this predicate, the predicate should be re-evaluated upon such return.
Quoted 10 lines
The subject is a bit misleading, IMHO. You are not porting the (p)threading code, but you are adding pthread_* function wrappers for Windows.
Your patch adds whitespace-at-eol. Please use git show --check to see where.
Please drop words from the commit message that do not make sense once this commit is in git's history. Look at existing commit messages to get a feeling for the style. Do write about "why" (motivation), "how" (design choices) and "how not" (dead ends that you tried).
Ok, thanks for pointing that out.
Quoted 2 lines
I think it would be OK to drop '= PTHREAD_{MUTEX,COND}_INITIALIZER' and use
*_initfunction calls without the #ifdef. Likewise for*_destroy.
Actually it won't save us many #ifdefs. There's one #ifdef for initialization that could be saved, but then comes #ifdef for cleanup:
#if defined(THREADED_DELTA_SEARCH) && defined(_WIN32)
What you propose will remove one #ifdef _WIN32 for initialization, but the cleanup will look almost the same:
#ifdef THREADED_DELTA_SEARCH
Quoted 3 lines
-- Hannes
Thanks for awesome review, I'll fix all those returns and whitespaces and resubmit.
--
Andrzej
Re: [PATCH] MSVC: port pthread code to native Windows threads
Quoted 7 lines · Andrzej K. Haczewski
2009/11/4 Johannes Sixt <[email protected]>:
Quoted 1 line
-
pthread_cond_signalis called while the mutex is held.AFAIK that is a requirement for condition variable to be signaled while holding the same mutex that other threads
cond_waiton. I just don't check that it is true, because Git is locking mutex.
There is no such requirement in POSIX:
The pthread_cond_broadcast() or pthread_cond_signal() functions may be called by a thread whether or not it currently owns the mutex that threads calling pthread_cond_wait() or pthread_cond_timedwait() have associated with the condition variable during their waits; however, if predictable scheduling behavior is required, then that mutex shall be locked by the thread calling pthread_cond_broadcast() or pthread_cond_signal().
http://www.opengroup.org/onlinepubs/009695399/functions/pthread_cond_signal.html
Dmitry
Re: [PATCH] MSVC: port pthread code to native Windows threads
In reply to Andrzej K. HaczewskiQuoted 6 lines · Andrzej K. Haczewski
2009/11/4 Johannes Sixt <[email protected]>:
Quoted 3 lines
After staring some time on the code, I have convinced myself that the
pthread_cond_waitandpthread_cond_signalimplementation will work *in our usage scenario* that has these preconditions:But it is not impossible with that implementation.
Read again what I wrote: We are in agreement.
Quoted 1 line
On resubmit I'll give more credit to ACE.
Perhaps also a link to the source and, even better, to a discussion of the implementation.
Quoted 5 lines
Quoted 1 line
-
pthread_cond_signalis called while the mutex is held.AFAIK that is a requirement for condition variable to be signaled while holding the same mutex that other threads
cond_waiton. I just don't check that it is true, because Git is locking mutex.
It is not a requirement, but, yes, we do hold the mutex.
Quoted 6 lines
Quoted 4 lines
- We retest the condition after
pthread_cond_waitreturns.These conditions should be attached in BIG BOLD letters to this implementation; particularly, the last one.
That's also a known requirement for working with cond vars.
Indeed.
Quoted 10 lines
Quoted 2 lines
I think it would be OK to drop '= PTHREAD_{MUTEX,COND}_INITIALIZER' and use
*_initfunction calls without the #ifdef. Likewise for*_destroy.Actually it won't save us many #ifdefs. There's one #ifdef for initialization that could be saved, but then comes #ifdef for cleanup:
#ifdefined(THREADED_DELTA_SEARCH)&&defined(_WIN32)What you propose will remove one #ifdef
_WIN32for initialization, but the cleanup will look almost the same:
#ifdefTHREADED_DELTA_SEARCH
You are right. But #ifdef THREADED_DELTA_SEARCH is about a "generic" property of the code and is already used elsewhere in the file, whereas #ifdef WIN32 would be new and is is about platform differences.
Anyway, we would have to see what Junio says about the new function calls, because he's usually quite anal when it comes to added code vs. static initialization. ;)
-- Hannes
Re: [PATCH] MSVC: port pthread code to native Windows threads
2009/11/4 Johannes Sixt <[email protected]>:
Quoted 8 lines
You are right. But #ifdef
THREADED_DELTA_SEARCHis about a "generic" property of the code and is already used elsewhere in the file, whereas #ifdef WIN32 would be new and is is about platform differences.Anyway, we would have to see what Junio says about the new function calls, because he's usually quite anal when it comes to added code vs. static initialization. ;)
I could do it with wrappers for pthread_mutex_lock and _unlock and lazy init there plus lazy init cond var in cond_wait and _signal, that way it could be done without any additional code in the first #ifdef. But I don't see any simple solution for working around deinitialization, that's why I'd leave non-static initialization. Let me put some touchups and resubmit for another round.
--
Andrzej
Re: [PATCH] MSVC: port pthread code to native Windows threads
Quoted 10 lines · Andrzej K. Haczewski
2009/11/4 Johannes Sixt <[email protected]>:
Quoted 8 lines
You are right. But #ifdef
THREADED_DELTA_SEARCHis about a "generic" property of the code and is already used elsewhere in the file, whereas #ifdef WIN32 would be new and is is about platform differences.Anyway, we would have to see what Junio says about the new function calls, because he's usually quite anal when it comes to added code vs. static initialization. ;)
Quoted 6 lines
I could do it with wrappers for
pthread_mutex_lockand_unlockand lazy init there plus lazy init cond var incond_waitand_signal, that way it could be done without any additional code in the first #ifdef. But I don't see any simple solution for working around deinitialization, that's why I'd leave non-static initialization. Let me put some touchups and resubmit for another round.
Is it actually necessary to deinitialize? Since the variables are static and therefore can't leak, and would presumably not need to be reinitialized differently if they were used again, I think they should be able to just stay. If Windows is unhappy about processes still having locks initialized at exit, I suppose we could go through and destroy all our mutexes and conds at cleanup time. Pthreads does have the appropriate functions, and it would be correct to use them, although unnecessary.
-Daniel
*This .sig left intentionally blank*
Re: [PATCH] MSVC: port pthread code to native Windows threads
Quoted 19 lines · Daniel Barkalow
Quoted 10 lines · Andrzej K. Haczewski
2009/11/4 Johannes Sixt <[email protected]>:
Quoted 8 lines
You are right. But #ifdef
THREADED_DELTA_SEARCHis about a "generic" property of the code and is already used elsewhere in the file, whereas #ifdef WIN32 would be new and is is about platform differences.Anyway, we would have to see what Junio says about the new function calls, because he's usually quite anal when it comes to added code vs. static initialization. ;)
Quoted 6 lines
I could do it with wrappers for
pthread_mutex_lockand_unlockand lazy init there plus lazy init cond var incond_waitand_signal, that way it could be done without any additional code in the first #ifdef. But I don't see any simple solution for working around deinitialization, that's why I'd leave non-static initialization. Let me put some touchups and resubmit for another round.
Quoted 7 lines
Is it actually necessary to deinitialize? Since the variables are static and therefore can't leak, and would presumably not need to be reinitialized differently if they were used again, I think they should be able to just stay. If Windows is unhappy about processes still having locks initialized at exit, I suppose we could go through and destroy all our mutexes and conds at cleanup time. Pthreads does have the appropriate functions, and it would be correct to use them, although unnecessary.
Lazy initialization would probably turn up to be more expensive (checking a flag on each usage) than unconditionally initializing them once. Remember that those are used at least once per object meaning a lot.
And I much prefer having runtime initialization for both Unix and Windows than having separate paths on each platform potentially hiding different bugs. And given that on Unix you can statically initialize those, then a runtime initialization is certainly not going to be _that_ costly.
And while at it, we might just deinitialize them as soon as we're done with them saving resources (on Unix that might turn up to be a no op anyway) which is why I suggested doing this within ll_find_deltas() directly.
Nicolas
Re: [PATCH] MSVC: port pthread code to native Windows threads
Quoted 29 lines · Nicolas Pitre
Quoted 19 lines · Daniel Barkalow
Quoted 10 lines · Andrzej K. Haczewski
2009/11/4 Johannes Sixt <[email protected]>:
Quoted 8 lines
You are right. But #ifdef
THREADED_DELTA_SEARCHis about a "generic" property of the code and is already used elsewhere in the file, whereas #ifdef WIN32 would be new and is is about platform differences.Anyway, we would have to see what Junio says about the new function calls, because he's usually quite anal when it comes to added code vs. static initialization. ;)
Quoted 6 lines
I could do it with wrappers for
pthread_mutex_lockand_unlockand lazy init there plus lazy init cond var incond_waitand_signal, that way it could be done without any additional code in the first #ifdef. But I don't see any simple solution for working around deinitialization, that's why I'd leave non-static initialization. Let me put some touchups and resubmit for another round.Quoted 7 lines
Is it actually necessary to deinitialize? Since the variables are static and therefore can't leak, and would presumably not need to be reinitialized differently if they were used again, I think they should be able to just stay. If Windows is unhappy about processes still having locks initialized at exit, I suppose we could go through and destroy all our mutexes and conds at cleanup time. Pthreads does have the appropriate functions, and it would be correct to use them, although unnecessary.
Quoted 4 lines
Lazy initialization would probably turn up to be more expensive (checking a flag on each usage) than unconditionally initializing them once. Remember that those are used at least once per object meaning a lot.
Meh, checking a flag on the same cache line as the lock you're about to take can't be a big incremental cost, especially if it's actually checking whether some sort of cookie is non-zero before doing something with it.
Quoted 5 lines
And I much prefer having runtime initialization for both Unix and Windows than having separate paths on each platform potentially hiding different bugs. And given that on Unix you can statically initialize those, then a runtime initialization is certainly not going to be _that_ costly.
Yeah, definitely best to have them match, whichever way we go.
I don't think it matters terribly much either way which we use, so long as its consistent. It'd be nice if the static initializers worked, just because people seem to write code with them, but we could just not do that in the future.
-Daniel
*This .sig left intentionally blank*
Re: [PATCH] MSVC: port pthread code to native Windows threads
Quoted 31 lines · Daniel Barkalow
Quoted 29 lines · Nicolas Pitre
Quoted 26 lines · Daniel Barkalow
Quoted 10 lines · Andrzej K. Haczewski
2009/11/4 Johannes Sixt <[email protected]>:
Quoted 8 lines
You are right. But #ifdef
THREADED_DELTA_SEARCHis about a "generic" property of the code and is already used elsewhere in the file, whereas #ifdef WIN32 would be new and is is about platform differences.Anyway, we would have to see what Junio says about the new function calls, because he's usually quite anal when it comes to added code vs. static initialization. ;)
Quoted 6 lines
I could do it with wrappers for
pthread_mutex_lockand_unlockand lazy init there plus lazy init cond var incond_waitand_signal, that way it could be done without any additional code in the first #ifdef. But I don't see any simple solution for working around deinitialization, that's why I'd leave non-static initialization. Let me put some touchups and resubmit for another round.Is it actually necessary to deinitialize? Since the variables are static and therefore can't leak, and would presumably not need to be reinitialized differently if they were used again, I think they should be able to just stay. If Windows is unhappy about processes still having locks initialized at exit, I suppose we could go through and destroy all our mutexes and conds at cleanup time. Pthreads does have the appropriate functions, and it would be correct to use them, although unnecessary.
Quoted 8 lines
Quoted 4 lines
Lazy initialization would probably turn up to be more expensive (checking a flag on each usage) than unconditionally initializing them once. Remember that those are used at least once per object meaning a lot.
Meh, checking a flag on the same cache line as the lock you're about to take can't be a big incremental cost, especially if it's actually checking whether some sort of cookie is non-zero before doing something with it.
This is still a bigger cost than not checking such flag at all. Especially if the check will be false on every call but the first one out of millions. I agree this is not significant, but neither is a runtime initialization vs a static one.
Quoted 4 lines
I don't think it matters terribly much either way which we use, so long as its consistent. It'd be nice if the static initializers worked, just because people seem to write code with them, but we could just not do that in the future.
Maybe the static initializer can be turned into a global constructor on Windows?
Nicolas
Re: [PATCH] MSVC: port pthread code to native Windows threads
In reply to Johannes Sixt2009/11/4 Johannes Sixt <[email protected]>:
Quoted 4 lines
Quoted 1 line
+static
__inlineintpthread_cond_init(pthread_cond_t *cond, const void *unused)What's wrong with 'static inline int ...' (without the underscores)?
Forgot to answer. 'inline' is avaliable in C++ only (on MSVC at least), while '__inline' is MS extension for C and C++.
--
Andrew
Re: [PATCH] MSVC: port pthread code to native Windows threads
Quoted 9 lines · Andrzej K. Haczewski
2009/11/4 Johannes Sixt <[email protected]>:
Quoted 4 lines
Quoted 1 line
+static
__inlineintpthread_cond_init(pthread_cond_t *cond, const void *unused)What's wrong with 'static inline int ...' (without the underscores)?
Forgot to answer. 'inline' is avaliable in C++ only (on MSVC at least), while '
__inline' is MS extension for C and C++.
You don't need it:
compat/msvc.h:9:#define inline __inline
Signature · 1 line
Erik "kusma" Faye-Lund
Re: [PATCH] MSVC: port pthread code to native Windows threads
In reply to Andrzej K. HaczewskiHi,
builtin-pack-objects.c int cmd_pack_objects(int argc, const char **argv, const char *prefix) · line 2331
Quoted 10 lines · Andrzej K. Haczewski
builtin-pack-objects.c +2
-0@@ -2327,6 +2327,18 @@ int cmd_pack_objects(int argc, const char **argv, const char *prefix)#ifdef THREADED_DELTA_SEARCH if (!delta_search_threads)/* --threads=0 means autodetect */ delta_search_threads =online_cpus (); + +#ifdef _WIN32
This flies in the face of our endeavors to enhance readability by reducing the number of #ifdef's, and at least guarding the #ifdef'ed parts behind meaningful names rather than platform specifiers.
See for example THREADED_DELTA_SEARCH: it does not read "HAS_PTHREADS" or some such.
Ciao,
Dscho
Re: [PATCH] MSVC: port pthread code to native Windows threads
In reply to Andrzej K. HaczewskiThe condition variable implementation seems more complicated than necessary. The mutex can be used to protect access to cond->waiters, so waiters_lock is not necessary. On the other hand, it seems to me that pthread_cond_signal should be the one that decrements the waiters count.
Otherwise, a loop like
while (pthread_cond_signal (cond, mutex));
will fill the semaphore with signals and the waiters will get lots of spurious accesses.
static __inline int pthread_cond_wait(pthread_cond_t *cond,
CRITICAL_SECTION *mutex)
{
int ret = 0;
/* the mutex protects access to waiters count */
++cond->waiters;
/*
* Unlock external mutex and wait for signal.
* NOTE: cond->waiters > 0 now. If pthread_cond_signal
* is called after leaving mutex unlocked before we wait on
* semaphore, it will add a signal to the semaphore,
* and we'll happily go on with the wait. This would not
* happen with an event, for example.
*/
LeaveCriticalSection(mutex);
if (0 != WaitForSingleObject(cond->sema, INFINITE))
ret = -1;
EnterCriticalSection(mutex);
return ret;
}static __inline int pthread_cond_signal(pthread_cond_t *cond)
{
/* the mutex protects access to waiters count */
if (cond->waiters > 0) {
--cond->waiters;
return ReleaseSemaphore(cond->sema, 1, NULL) ? 0 : -1;
} else
return 0;
}Paolo
PATCH 1/1 MSVC: Windows-native implementation for subset of Pthreads API
In reply to Andrzej K. HaczewskiThis patch implements native to Windows subset of pthreads API used by Git. It allows to remove Pthreads for Win32 dependency for MSVC, msysgit and Cygwin.
The patch modifies Makefile only for MSVC (that's the environment I'm capable of testing on), so it requires further corrections to compile with MinGW or Cygwin.
---
Here is another round of that patch with all comments considered. There is no workaround to make static initialization of mutexes and condition variables work for Windows, that's why there's explicit initialization added.
I hope I added to Cc all interested in this patch. Excuse me if I omitted someone.
Makefile | 7 ++- builtin-pack-objects.c | 31 +++++++++++-- compat/mingw.c | 2 +- compat/mingw.h | 5 ++ compat/win32/pthread.c | 116 ++++++++++++++++++++++++++++++++++++++++++++++++ compat/win32/pthread.h | 69 ++++++++++++++++++++++++++++ 6 files changed, 222 insertions(+), 8 deletions(-) create mode 100644 compat/win32/pthread.c create mode 100644 compat/win32/pthread.h
Makefile +4 -3
@@ -453,6 +453,7 @@ LIB_H += commit.h LIB_H += compat/bswap.h LIB_H += compat/cygwin.h LIB_H += compat/mingw.h +LIB_H += compat/win32/pthread.h LIB_H += csum-file.h LIB_H += decorate.h LIB_H += delta.h
@@ -971,15 +972,15 @@ ifdef MSVC OBJECT_CREATION_USES_RENAMES = UnfortunatelyNeedsTo NO_REGEX = YesPlease NO_CURL = YesPlease - NO_PTHREADS = YesPlease + THREADED_DELTA_SEARCH = YesPlease BLK_SHA1 = YesPlease CC = compat/vcbuild/scripts/clink.pl AR = compat/vcbuild/scripts/lib.pl CFLAGS = BASIC_CFLAGS = -nologo -I. -I../zlib -Icompat/vcbuild -Icompat/vcbuild/include -DWIN32 -D_CONSOLE -DHAVE_STRING_H -D_CRT_SECURE_NO_WARNINGS -D_CRT_NONSTDC_NO_DEPRECATE - COMPAT_OBJS = compat/msvc.o compat/fnmatch/fnmatch.o compat/winansi.o - COMPAT_CFLAGS = -D__USE_MINGW_ACCESS -DNOGDI -DHAVE_STRING_H -DHAVE_ALLOCA_H -Icompat -Icompat/fnmatch -Icompat/regex -Icompat/fnmatch -DSTRIP_EXTENSION=\".exe\" + COMPAT_OBJS = compat/msvc.o compat/fnmatch/fnmatch.o compat/winansi.o compat/win32/pthread.o + COMPAT_CFLAGS = -D__USE_MINGW_ACCESS -DNOGDI -DHAVE_STRING_H -DHAVE_ALLOCA_H -Icompat -Icompat/fnmatch -Icompat/regex -Icompat/fnmatch -Icompat/win32 -DSTRIP_EXTENSION=\".exe\" BASIC_LDFLAGS = -IGNORE:4217 -IGNORE:4049 -NOLOGO -SUBSYSTEM:CONSOLE -NODEFAULTLIB:MSVCRT.lib EXTLIBS = advapi32.lib shell32.lib wininet.lib ws2_32.lib lib =
builtin-pack-objects.c +27 -4
@@ -1255,15 +1255,15 @@ static int delta_cacheable(unsigned long src_size, unsigned long trg_size,#ifdef THREADED_DELTA_SEARCH -static pthread_mutex_t read_mutex =PTHREAD_MUTEX_INITIALIZER ; +static pthread_mutex_t read_mutex;#define read_lock () pthread_mutex_lock(&read_mutex)#define read_unlock () pthread_mutex_unlock(&read_mutex) -static pthread_mutex_t cache_mutex =PTHREAD_MUTEX_INITIALIZER ; +static pthread_mutex_t cache_mutex;#define cache_lock () pthread_mutex_lock(&cache_mutex)#define cache_unlock () pthread_mutex_unlock(&cache_mutex) -static pthread_mutex_t progress_mutex =PTHREAD_MUTEX_INITIALIZER ; +static pthread_mutex_t progress_mutex;#define progress_lock () pthread_mutex_lock(&progress_mutex)#define progress_unlock () pthread_mutex_unlock(&progress_mutex)
@@ -1590,7 +1590,26 @@ struct thread_params {unsigned *processed; }; -static pthread_cond_t progress_cond =PTHREAD_COND_INITIALIZER ; +static pthread_cond_t progress_cond; + +/* +* Mutex and conditional variable can't be statically-initialized on Windows. +*/ +static void init_threaded_search () +{ +pthread_mutex_init (&read_mutex,NULL ); +pthread_mutex_init (&cache_mutex,NULL ); +pthread_mutex_init (&progress_mutex,NULL ); +pthread_cond_init (&progress_cond,NULL ); +} + +static void cleanup_threaded_search () +{ +pthread_cond_destroy (&progress_cond); +pthread_mutex_destroy (&read_mutex); +pthread_mutex_destroy (&cache_mutex); +pthread_mutex_destroy (&progress_mutex); +}static void *threaded_find_deltas (void *arg) {
@@ -1629,8 +1648,11 @@ static void ll_find_deltas(struct object_entry **list, unsigned list_size,struct thread_params *p;int i, ret, active_threads =0 ; +init_threaded_search (); +if (delta_search_threads <=1 ) {find_deltas (list, &list_size, window, depth, processed); +cleanup_threaded_search ();return ; }if (progress > pack_to_stdout)
@@ -1745,6 +1767,7 @@ static void ll_find_deltas(struct object_entry **list, unsigned list_size, active_threads--; } } +cleanup_threaded_search ();free (p); }
compat/mingw.c +1 -1
@@ -5,7 +5,7 @@#include <shellapi.h> -static int err_win_to_posix (DWORD winerr) +int err_win_to_posix (DWORD winerr) {int error =ENOSYS ;switch (winerr) {
compat/mingw.h +5 -0
@@ -294,3 +294,8 @@ struct mingw_dirent#define readdir (x) mingw_readdir(x)struct dirent *mingw_readdir (DIR *dir);#endif // !NO_MINGW_REPLACE_READDIR + +/* +* Used by Pthread API implementation for Windows +*/ +extern int err_win_to_posix (DWORD winerr);
compat/win32/pthread.c new file +116 -0
116 lines not on this page · raw message
compat/win32/pthread.h new file +69 -0
69 lines not on this page · raw message
Signature · 1 line
1.6.5.2
Re: [PATCH] MSVC: Windows-native implementation for subset of Pthreads API
Thanks.
I pushed this to
git://repo.or.cz/git/mingw/j6t.git pthreads-for-windows
together with Nico's patch and another patch to enable pthreads on MinGW unconditionally. Feedback welcome!
Andrzej K. Haczewski (1):
MSVC: Windows-native implementation for subset of Pthreads API
Johannes Sixt (1):
MinGW: enable pthreads
Nicolas Pitre (1):
pack-objects: move thread autodetection closer to relevant code
This is my patch:
--- >8 ---
From: Johannes Sixt <[email protected]>
Subject: [PATCH] MinGW: enable pthreads
If the MinGW build was built as part of the msysgit build environment, then threading was already enabled because the pthreads package from GNU-Win32 is available in msysgit.
The previous patch added a minimal pthreads implementation for Windows. Therefore, we can now enable code that uses pthreads unconditionally.
--- Makefile | 6 +++--- 1 files changed, 3 insertions(+), 3 deletions(-)
Makefile +3 -3
@@ -986,9 +986,11 @@ ifneq (,$(findstring MINGW,$(uname_S))) UNRELIABLE_FSTAT = UnfortunatelyYes OBJECT_CREATION_USES_RENAMES = UnfortunatelyNeedsTo NO_REGEX = YesPlease + THREADED_DELTA_SEARCH = YesPlease COMPAT_CFLAGS += -D__USE_MINGW_ACCESS -DNOGDI -Icompat -Icompat/fnmatch COMPAT_CFLAGS += -DSTRIP_EXTENSION=\".exe\" - COMPAT_OBJS += compat/mingw.o compat/fnmatch/fnmatch.o compat/winansi.o + COMPAT_OBJS += compat/mingw.o compat/fnmatch/fnmatch.o compat/winansi.o \ + compat/win32/pthread.o EXTLIBS += -lws2_32 X = .exe ifneq (,$(wildcard ../THIS_IS_MSYSGIT))
@@ -998,10 +1000,8 @@ ifneq (,$(wildcard ../THIS_IS_MSYSGIT)) EXTLIBS += /mingw/lib/libz.a NO_R_TO_GCC_LINKER = YesPlease INTERNAL_QSORT = YesPlease - THREADED_DELTA_SEARCH = YesPlease else NO_CURL = YesPlease - NO_PTHREADS = YesPlease endif endif endif
Signature · 1 line
1.6.5.2.1198.ge698c
Re: [PATCH] MSVC: Windows-native implementation for subset of Pthreads API
In reply to Andrzej K. Haczewskicompat/win32/pthread.c line 16
Quoted 6 lines · Andrzej K. Haczewski
compat/win32/pthread.c new file +6
-0+static unsigned __stdcallwin32_start_routine (void *arg) +{ +pthread_t *thread = arg; + thread->value = thread->start_routine (thread->arg); +return 0 ; +}
I suppose you could reuse thread->arg for both the argument and the returned value to save a word.
compat/win32/pthread.c line 35
Quoted 3 lines
compat/win32/pthread.c new file +3
-0+int win32_pthread_join (pthread_t *thread,void **value_ptr) +{ +DWORD result =WaitForSingleObject ((HANDLE )thread->handle,INFINITE );
Why are you casting thread->handle here? Why not simply declaring it as a HANDLE?
Otherwise this looks pretty good now.
Nicolas
Re: [PATCH] MSVC: Windows-native implementation for subset of Pthreads API
2009/11/5 Nicolas Pitre <[email protected]>:
Quoted 11 lines · Andrzej K. Haczewski
compat/win32/pthread.c line 16
Quoted 7 lines
compat/win32/pthread.c new file +6
-0+static unsigned __stdcallwin32_start_routine (void *arg) +{ + pthread_t *thread = arg; + thread->value = thread->start_routine(thread->arg); + return 0; +}I suppose you could reuse
thread->argfor both the argument and the returned value to save a word.
You're right! J6t committed already, what can I do now?
Quoted 2 lines
Why are you casting
thread->handlehere? Why not simply declaring it as a HANDLE?
Just to silence MSVC warnings. WaitForSingleObject requires HANDLE, _beginthreadex() returns uintptr_t. It's just a matter of where would I put cast ;).
--
Andrzej
Re: [PATCH] MSVC: Windows-native implementation for subset of Pthreads API
Quoted 13 lines · Andrzej K. Haczewski
2009/11/5 Nicolas Pitre <[email protected]>:
Quoted 11 lines · Andrzej K. Haczewski
compat/win32/pthread.c line 16
Quoted 7 lines
compat/win32/pthread.c new file +6
-0+static unsigned __stdcallwin32_start_routine (void *arg) +{ + pthread_t *thread = arg; + thread->value = thread->start_routine(thread->arg); + return 0; +}I suppose you could reuse
thread->argfor both the argument and the returned value to save a word.
Quoted 1 line
You're right! J6t committed already, what can I do now?
Just post a replacement patch.
Quoted 6 lines
Quoted 2 lines
Why are you casting
thread->handlehere? Why not simply declaring it as a HANDLE?Just to silence MSVC warnings. WaitForSingleObject requires HANDLE,
_beginthreadex()returnsuintptr_t. It's just a matter of where would I put cast ;).
Wonderful. One could wonder why Windows can't have coherent interfaces...
Well, given that all existing usages in the tree (run-command.c and compat/mingw.c) already cast the _beginthreadex() return value instead, then that might be a good idea to follow the same model.
Nicolas
PATCH 1/1 MSVC: Windows-native implementation for subset of Pthreads API
In reply to Andrzej K. HaczewskiThis patch implements native to Windows subset of pthreads API used by Git. It allows to remove Pthreads for Win32 dependency for MSVC, msysgit and Cygwin.
The patch modifies Makefile only for MSVC (that's the environment I'm capable of testing on), so it requires further corrections to compile with MinGW or Cygwin.
---
One more round of that patch with Nicolas' comments considered, and disclamer about the implementation added.
Johannes, can you replace previous commit with that patch?
Makefile | 7 ++- builtin-pack-objects.c | 31 +++++++++++-- compat/mingw.c | 2 +- compat/mingw.h | 5 ++ compat/win32/pthread.c | 120 ++++++++++++++++++++++++++++++++++++++++++++++++ compat/win32/pthread.h | 68 +++++++++++++++++++++++++++ 6 files changed, 225 insertions(+), 8 deletions(-) create mode 100644 compat/win32/pthread.c create mode 100644 compat/win32/pthread.h
Makefile +4 -3
@@ -453,6 +453,7 @@ LIB_H += commit.h LIB_H += compat/bswap.h LIB_H += compat/cygwin.h LIB_H += compat/mingw.h +LIB_H += compat/win32/pthread.h LIB_H += csum-file.h LIB_H += decorate.h LIB_H += delta.h
@@ -971,15 +972,15 @@ ifdef MSVC OBJECT_CREATION_USES_RENAMES = UnfortunatelyNeedsTo NO_REGEX = YesPlease NO_CURL = YesPlease - NO_PTHREADS = YesPlease + THREADED_DELTA_SEARCH = YesPlease BLK_SHA1 = YesPlease CC = compat/vcbuild/scripts/clink.pl AR = compat/vcbuild/scripts/lib.pl CFLAGS = BASIC_CFLAGS = -nologo -I. -I../zlib -Icompat/vcbuild -Icompat/vcbuild/include -DWIN32 -D_CONSOLE -DHAVE_STRING_H -D_CRT_SECURE_NO_WARNINGS -D_CRT_NONSTDC_NO_DEPRECATE - COMPAT_OBJS = compat/msvc.o compat/fnmatch/fnmatch.o compat/winansi.o - COMPAT_CFLAGS = -D__USE_MINGW_ACCESS -DNOGDI -DHAVE_STRING_H -DHAVE_ALLOCA_H -Icompat -Icompat/fnmatch -Icompat/regex -Icompat/fnmatch -DSTRIP_EXTENSION=\".exe\" + COMPAT_OBJS = compat/msvc.o compat/fnmatch/fnmatch.o compat/winansi.o compat/win32/pthread.o + COMPAT_CFLAGS = -D__USE_MINGW_ACCESS -DNOGDI -DHAVE_STRING_H -DHAVE_ALLOCA_H -Icompat -Icompat/fnmatch -Icompat/regex -Icompat/fnmatch -Icompat/win32 -DSTRIP_EXTENSION=\".exe\" BASIC_LDFLAGS = -IGNORE:4217 -IGNORE:4049 -NOLOGO -SUBSYSTEM:CONSOLE -NODEFAULTLIB:MSVCRT.lib EXTLIBS = advapi32.lib shell32.lib wininet.lib ws2_32.lib lib =
builtin-pack-objects.c +27 -4
@@ -1255,15 +1255,15 @@ static int delta_cacheable(unsigned long src_size, unsigned long trg_size,#ifdef THREADED_DELTA_SEARCH -static pthread_mutex_t read_mutex =PTHREAD_MUTEX_INITIALIZER ; +static pthread_mutex_t read_mutex;#define read_lock () pthread_mutex_lock(&read_mutex)#define read_unlock () pthread_mutex_unlock(&read_mutex) -static pthread_mutex_t cache_mutex =PTHREAD_MUTEX_INITIALIZER ; +static pthread_mutex_t cache_mutex;#define cache_lock () pthread_mutex_lock(&cache_mutex)#define cache_unlock () pthread_mutex_unlock(&cache_mutex) -static pthread_mutex_t progress_mutex =PTHREAD_MUTEX_INITIALIZER ; +static pthread_mutex_t progress_mutex;#define progress_lock () pthread_mutex_lock(&progress_mutex)#define progress_unlock () pthread_mutex_unlock(&progress_mutex)
@@ -1590,7 +1590,26 @@ struct thread_params {unsigned *processed; }; -static pthread_cond_t progress_cond =PTHREAD_COND_INITIALIZER ; +static pthread_cond_t progress_cond; + +/* +* Mutex and conditional variable can't be statically-initialized on Windows. +*/ +static void init_threaded_search () +{ +pthread_mutex_init (&read_mutex,NULL ); +pthread_mutex_init (&cache_mutex,NULL ); +pthread_mutex_init (&progress_mutex,NULL ); +pthread_cond_init (&progress_cond,NULL ); +} + +static void cleanup_threaded_search () +{ +pthread_cond_destroy (&progress_cond); +pthread_mutex_destroy (&read_mutex); +pthread_mutex_destroy (&cache_mutex); +pthread_mutex_destroy (&progress_mutex); +}static void *threaded_find_deltas (void *arg) {
@@ -1629,8 +1648,11 @@ static void ll_find_deltas(struct object_entry **list, unsigned list_size,struct thread_params *p;int i, ret, active_threads =0 ; +init_threaded_search (); +if (delta_search_threads <=1 ) {find_deltas (list, &list_size, window, depth, processed); +cleanup_threaded_search ();return ; }if (progress > pack_to_stdout)
@@ -1745,6 +1767,7 @@ static void ll_find_deltas(struct object_entry **list, unsigned list_size, active_threads--; } } +cleanup_threaded_search ();free (p); }
compat/mingw.c +1 -1
@@ -5,7 +5,7 @@#include <shellapi.h> -static int err_win_to_posix (DWORD winerr) +int err_win_to_posix (DWORD winerr) {int error =ENOSYS ;switch (winerr) {
compat/mingw.h +5 -0
@@ -294,3 +294,8 @@ struct mingw_dirent#define readdir (x) mingw_readdir(x)struct dirent *mingw_readdir (DIR *dir);#endif // !NO_MINGW_REPLACE_READDIR + +/* +* Used by Pthread API implementation for Windows +*/ +extern int err_win_to_posix (DWORD winerr);
compat/win32/pthread.c new file +120 -0
120 lines not on this page · raw message
compat/win32/pthread.h new file +68 -0
68 lines not on this page · raw message
Signature · 1 line
1.6.5.2
Re: [PATCH] MSVC: Windows-native implementation for subset of Pthreads API
Quoted 4 lines · Andrzej K. Haczewski
One more round of that patch with Nicolas' comments considered, and disclamer about the implementation added.
Johannes, can you replace previous commit with that patch?
Thanks; the result is in
git://repo.or.cz/git/mingw/j6t.git pthreads-for-windows
-- Hannes