* [PATCH] builtin/index-pack.c: Fix some pthread_t misuse
@ 2012-03-07 19:00 Ramsay Jones
2012-03-07 19:15 ` Junio C Hamano
0 siblings, 1 reply; 4+ messages in thread
From: Ramsay Jones @ 2012-03-07 19:00 UTC (permalink / raw)
To: Nguyen Thai Ngoc Duy; +Cc: Junio C Hamano, GIT Mailing-list
On cygwin, sparse complains as follows:
SP builtin/index-pack.c
builtin/index-pack.c:892:49: warning: Using plain integer as \
NULL pointer
The warning refers to code which assigns zero to a pthread_t thread
handle. In this case, the pthread_t handle type is a pointer type,
which results in the above warning. On Linux a pthread_t is defined
as an integer type (unsigned long int for me) and so sparse does not
issue any such warning.
However, pthread_t is intended to be an opaque (implementation defined)
type. For example, an implementation may choose to use a structure to
implement the type. Therefore, assigning zero (or any other constant)
to a pthread_t is not supported in general.
As a case in point, the pthread emulation code on MinGW defines the
pthread_t type using a structure (see compat/win32/pthread.h:57), which
results in gcc complaining as follows:
CC builtin/index-pack.o
builtin/index-pack.c: In function 'get_thread_data':
builtin/index-pack.c:290: error: invalid operands to binary == \
(have 'pthread_t' and 'pthread_t')
builtin/index-pack.c: In function 'resolve_one_delta':
builtin/index-pack.c:302: error: invalid operands to binary == \
(have 'pthread_t' and 'pthread_t')
builtin/index-pack.c: In function 'parse_pack_objects':
builtin/index-pack.c:892: error: incompatible types when assigning \
to type 'pthread_t' from type 'int'
make: *** [builtin/index-pack.o] Error 1
Note that, for the same reason given above, you can not, in general,
directly compare pthread_t handles with the built-in equality operator.
In order to compare pthread_t's for equality, the POSIX standard requires
the use of pthread_equal().
In order to fix the warnings and errors, we replace the use of the
'==' operator with corresponding calls to pthread_equal() and remove
the statement which assigns zero to the thread handle.
Signed-off-by: Ramsay Jones <ramsay@ramsay1.demon.co.uk>
---
Hi Nguyen,
commit ee66dabd ("index-pack: support multithreaded delta resolving",
02-03-2012) causes a build failure on MinGW. This patch makes a small
improvement - it at least builds.
The only testing I have done is to run the testsuite on Linux (it passes)
and tests t5300-pack-object.sh, t5302-pack-index.sh, t5510-fetch.sh and
t6050-replace.sh on cygwin (running the full testsuite on cygwin takes
*hours*) and again it passes.
On MinGW, however, the above tests all fail miserably! (They crash with
that irritating 'git.exe failed do you want to send error report to
Microsoft' dialog). I noticed that the 'counter_mutex' is not initialised
or destroyed, and have (literally) just tested a patch which does this
and ... it made no difference! :(
So, more debugging needs to be done on windows ...
ATB,
Ramsay Jones
builtin/index-pack.c | 8 +++-----
1 files changed, 3 insertions(+), 5 deletions(-)
diff --git a/builtin/index-pack.c b/builtin/index-pack.c
index edd7cbd..f8d93b8 100644
--- a/builtin/index-pack.c
+++ b/builtin/index-pack.c
@@ -287,7 +287,7 @@ static struct thread_local *get_thread_data(void)
int i;
pthread_t self = pthread_self();
for (i = 1; i < nr_threads; i++)
- if (self == thread_data[i].thread)
+ if (pthread_equal(self, thread_data[i].thread))
return &thread_data[i];
#endif
return &thread_data[0];
@@ -299,7 +299,7 @@ static void resolve_one_delta(void)
int i;
pthread_t self = pthread_self();
for (i = 1; i < nr_threads; i++)
- if (self == thread_data[i].thread) {
+ if (pthread_equal(self, thread_data[i].thread)) {
counter_lock();
nr_resolved_deltas++;
counter_unlock();
@@ -887,10 +887,8 @@ static void parse_pack_objects(unsigned char *sha1)
if (ret)
die("unable to create thread: %s", strerror(ret));
}
- for (i = 1; i < nr_threads; i++) {
+ for (i = 1; i < nr_threads; i++)
pthread_join(thread_data[i].thread, NULL);
- thread_data[i].thread = 0;
- }
cleanup_thread();
/* stop get_thread_data() from looking up beyond the
--
1.7.9
^ permalink raw reply related [flat|nested] 4+ messages in thread* Re: [PATCH] builtin/index-pack.c: Fix some pthread_t misuse 2012-03-07 19:00 [PATCH] builtin/index-pack.c: Fix some pthread_t misuse Ramsay Jones @ 2012-03-07 19:15 ` Junio C Hamano 2012-03-08 1:29 ` Nguyen Thai Ngoc Duy 0 siblings, 1 reply; 4+ messages in thread From: Junio C Hamano @ 2012-03-07 19:15 UTC (permalink / raw) To: Ramsay Jones; +Cc: Nguyen Thai Ngoc Duy, GIT Mailing-list Ramsay Jones <ramsay@ramsay1.demon.co.uk> writes: > However, pthread_t is intended to be an opaque (implementation defined) > type. For example, an implementation may choose to use a structure to > implement the type. Therefore, assigning zero (or any other constant) > to a pthread_t is not supported in general. > ... > Note that, for the same reason given above, you can not, in general, > directly compare pthread_t handles with the built-in equality operator. > In order to compare pthread_t's for equality, the POSIX standard requires > the use of pthread_equal(). Thanks, the above analysis all sound sensible. I do not think it matters in *this* case, but if a loop iterates over an array of things with a field of type pthread_t in it, whose element may or may not be valid, and wants to mark the validity of an element with the value of its pthread_t field, what is the proper way to do so? I.e. for (i = 0; i < ARRAY_SIZE(thread_data); i++) { if (pthread_invalid(thread_data[i].thread) continue; /* not used */ if (!pthread_equal(self, thread_data[i].thread)) continue; /* not me */ /* ah, this is mine! */ ... } Perhaps the answer is "Don't do it" and that is perfectly fine, but does Nguyen's code rely on the final clean-up (assignment with 0 you are removing with this patch) to mark that these elements are no longer relevant? ^ permalink raw reply [flat|nested] 4+ messages in thread
* Re: [PATCH] builtin/index-pack.c: Fix some pthread_t misuse 2012-03-07 19:15 ` Junio C Hamano @ 2012-03-08 1:29 ` Nguyen Thai Ngoc Duy 2012-03-10 21:20 ` Ramsay Jones 0 siblings, 1 reply; 4+ messages in thread From: Nguyen Thai Ngoc Duy @ 2012-03-08 1:29 UTC (permalink / raw) To: Junio C Hamano, Ramsay Jones; +Cc: GIT Mailing-list On Wed, Mar 07, 2012 at 11:15:00AM -0800, Junio C Hamano wrote: > Ramsay Jones <ramsay@ramsay1.demon.co.uk> writes: > > > However, pthread_t is intended to be an opaque (implementation defined) > > type. For example, an implementation may choose to use a structure to > > implement the type. Therefore, assigning zero (or any other constant) > > to a pthread_t is not supported in general. > > ... > > Note that, for the same reason given above, you can not, in general, > > directly compare pthread_t handles with the built-in equality operator. > > In order to compare pthread_t's for equality, the POSIX standard requires > > the use of pthread_equal(). > > Thanks, the above analysis all sound sensible. > > I do not think it matters in *this* case, but if a loop iterates > over an array of things with a field of type pthread_t in it, whose > element may or may not be valid, and wants to mark the validity of > an element with the value of its pthread_t field, what is the proper > way to do so? I.e. > > for (i = 0; i < ARRAY_SIZE(thread_data); i++) { > if (pthread_invalid(thread_data[i].thread) > continue; /* not used */ > if (!pthread_equal(self, thread_data[i].thread)) > continue; /* not me */ > /* ah, this is mine! */ > ... > } > > Perhaps the answer is "Don't do it" and that is perfectly fine, but > does Nguyen's code rely on the final clean-up (assignment with 0 you > are removing with this patch) to mark that these elements are no > longer relevant? The 0 assignment is not strictly needed. Shortly after that, nr_threads is set back to 1, which makes thread_data[1..] inaccessible, and thread_data[0] is dedicated for the main thread already. We can get rid of pthread_t comparison by using TLS (I avoided this because this would be the first time pthread_getspecific is used in git). Does this help your crash Ramsay? It also moves down cleanup_thread() so counter_mutex is always valid when it's used. Seems to work with linux-2.6.git. -- 8< -- diff --git a/builtin/index-pack.c b/builtin/index-pack.c index edd7cbd..098f350 100644 --- a/builtin/index-pack.c +++ b/builtin/index-pack.c @@ -104,6 +104,8 @@ static pthread_mutex_t work_mutex; #define work_lock() pthread_mutex_lock(&work_mutex) #define work_unlock() pthread_mutex_unlock(&work_mutex) +static pthread_key_t key; + /* * Mutex and conditional variable can't be statically-initialized on Windows. */ @@ -111,6 +113,7 @@ static void init_thread(void) { init_recursive_mutex(&read_mutex); pthread_mutex_init(&work_mutex, NULL); + pthread_key_create(&key, NULL); } static void cleanup_thread(void) @@ -284,31 +287,19 @@ static NORETURN void bad_object(unsigned long offset, const char *format, ...) static struct thread_local *get_thread_data(void) { #ifndef NO_PTHREADS - int i; - pthread_t self = pthread_self(); - for (i = 1; i < nr_threads; i++) - if (self == thread_data[i].thread) - return &thread_data[i]; + if (nr_threads > 1) + return pthread_getspecific(key); #endif + assert(nr_threads == 1 && + "This should only be reached when all threads are gone"); return &thread_data[0]; } static void resolve_one_delta(void) { -#ifndef NO_PTHREADS - int i; - pthread_t self = pthread_self(); - for (i = 1; i < nr_threads; i++) - if (self == thread_data[i].thread) { - counter_lock(); - nr_resolved_deltas++; - counter_unlock(); - return; - } -#endif - assert(nr_threads == 1 && - "This should only be reached when all threads are gone"); + counter_lock(); nr_resolved_deltas++; + counter_unlock(); } static struct base_data *alloc_base_data(void) @@ -796,6 +787,7 @@ static void second_pass(struct object_entry *obj) static void *threaded_second_pass(void *arg) { + pthread_setspecific(key, arg); for (;;) { int i, nr = 16; work_lock(); @@ -883,15 +875,12 @@ static void parse_pack_objects(unsigned char *sha1) init_thread(); for (i = 1; i < nr_threads; i++) { int ret = pthread_create(&thread_data[i].thread, NULL, - threaded_second_pass, NULL); + threaded_second_pass, thread_data + i); if (ret) die("unable to create thread: %s", strerror(ret)); } - for (i = 1; i < nr_threads; i++) { + for (i = 1; i < nr_threads; i++) pthread_join(thread_data[i].thread, NULL); - thread_data[i].thread = 0; - } - cleanup_thread(); /* stop get_thread_data() from looking up beyond the first item, when fix_unresolved_deltas() runs */ @@ -1411,6 +1400,9 @@ int cmd_index_pack(int argc, const char **argv, const char *prefix) die("pack has %d unresolved deltas", nr_deltas - nr_resolved_deltas); } +#ifndef NO_PTHREADS + cleanup_thread(); +#endif free(deltas); if (strict) check_objects(); -- 8< -- ^ permalink raw reply related [flat|nested] 4+ messages in thread
* Re: [PATCH] builtin/index-pack.c: Fix some pthread_t misuse 2012-03-08 1:29 ` Nguyen Thai Ngoc Duy @ 2012-03-10 21:20 ` Ramsay Jones 0 siblings, 0 replies; 4+ messages in thread From: Ramsay Jones @ 2012-03-10 21:20 UTC (permalink / raw) To: Nguyen Thai Ngoc Duy; +Cc: Junio C Hamano, GIT Mailing-list Nguyen Thai Ngoc Duy wrote: > Does this help your crash Ramsay? It also moves down cleanup_thread() > so counter_mutex is always valid when it's used. Seems to work with > linux-2.6.git. [ patch snipped ] No this does not help, because it doesn't address the fundamental problem. The problem is simply that mutex variables are being used when they are not in a usable state; either they are not initialised at all (counter_mutex), or they are being used *before* they are initialised (in init_thread()) or *after* they are destroyed (in cleanup_thread()). If I apply the patch below on top of your patch (it should look familiar!), then everything works fine. (This time I only tested on MinGW and cygwin). Also, I would move the call to cleanup_thread() back up to it's original location, since the move down serves no useful purpose. I don't know that using TLS here is an improvement or not (it's probably a wash). ;-) [BTW, using an uninitialised mutex on cygwin and Linux *seems* to work without problem, but I can't be sure that's true (I haven't looked at the code). :-P ] ATB, Ramsay Jones -- 8< -- diff --git a/builtin/index-pack.c b/builtin/index-pack.c index 098f350..31f923c 100644 --- a/builtin/index-pack.c +++ b/builtin/index-pack.c @@ -74,6 +74,7 @@ static int nr_processed; static int nr_deltas; static int nr_resolved_deltas; static int nr_threads; +static int threads_active; static int from_stdin; static int strict; @@ -93,16 +94,16 @@ static int input_fd, output_fd, pack_fd; #ifndef NO_PTHREADS static pthread_mutex_t read_mutex; -#define read_lock() pthread_mutex_lock(&read_mutex) -#define read_unlock() pthread_mutex_unlock(&read_mutex) +#define read_lock() if (threads_active) pthread_mutex_lock(&read_mutex) +#define read_unlock() if (threads_active) pthread_mutex_unlock(&read_mutex) static pthread_mutex_t counter_mutex; -#define counter_lock() pthread_mutex_lock(&counter_mutex) -#define counter_unlock() pthread_mutex_unlock(&counter_mutex) +#define counter_lock() if (threads_active) pthread_mutex_lock(&counter_mutex) +#define counter_unlock() if (threads_active) pthread_mutex_unlock(&counter_mutex) static pthread_mutex_t work_mutex; -#define work_lock() pthread_mutex_lock(&work_mutex) -#define work_unlock() pthread_mutex_unlock(&work_mutex) +#define work_lock() if (threads_active) pthread_mutex_lock(&work_mutex) +#define work_unlock() if (threads_active) pthread_mutex_unlock(&work_mutex) static pthread_key_t key; @@ -112,13 +113,17 @@ static pthread_key_t key; static void init_thread(void) { init_recursive_mutex(&read_mutex); + pthread_mutex_init(&counter_mutex, NULL); pthread_mutex_init(&work_mutex, NULL); pthread_key_create(&key, NULL); + threads_active = 1; } static void cleanup_thread(void) { + threads_active = 0; pthread_mutex_destroy(&read_mutex); + pthread_mutex_destroy(&counter_mutex); pthread_mutex_destroy(&work_mutex); } -- 8< -- ^ permalink raw reply related [flat|nested] 4+ messages in thread
end of thread, other threads:[~2012-03-11 18:33 UTC | newest] Thread overview: 4+ messages (download: mbox.gz follow: Atom feed -- links below jump to the message on this page -- 2012-03-07 19:00 [PATCH] builtin/index-pack.c: Fix some pthread_t misuse Ramsay Jones 2012-03-07 19:15 ` Junio C Hamano 2012-03-08 1:29 ` Nguyen Thai Ngoc Duy 2012-03-10 21:20 ` Ramsay Jones
This is a public inbox, see mirroring instructions for how to clone and mirror all data and code used for this inbox; as well as URLs for NNTP newsgroup(s).