From 0ec79358d07db38e5d9e9e8a7c0d78f455763844 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nguy=E1=BB=85n=20Th=C3=A1i=20Ng=E1=BB=8Dc=20Duy?= Date: Sat, 27 Oct 2018 19:29:59 +0200 Subject: [PATCH 01/14] thread-utils: macros to unconditionally compile pthreads API MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit When built with NO_PTHREADS, the macros are used make the code build even though pthreads header and library may be missing. The code can still have different code paths for no threads support with HAVE_THREADS variable. There are of course impacts on no-pthreads builds: - data structure may get slightly bigger because all the mutexes and pthread_t are present (as an int) - code execution is not impacted much. Locking (in hot path) is no-op. Other wrapper function calls really should not matter much. - the binary size grows bigger because of threaded code. But at least on Linux this does not matter, if some code is not executed, it's not mapped in memory. This is a preparation step to remove "#ifdef NO_PTHREADS" in the code mostly because of maintainability. As Jeff put it > it's probably OK to stop thinking of it as "non-threaded platforms > are the default and must pay zero cost" and more as "threaded > platforms are the default, and non-threaded ones are OK to pay a > small cost as long as they still work". Signed-off-by: Nguyễn Thái Ngọc Duy Signed-off-by: Junio C Hamano --- Makefile | 2 +- thread-utils.c | 48 ++++++++++++++++++++++++++++++++++++++++++++++++ thread-utils.h | 48 +++++++++++++++++++++++++++++++++++++++++++++--- 3 files changed, 94 insertions(+), 4 deletions(-) diff --git a/Makefile b/Makefile index b08d5ea258..321540a736 100644 --- a/Makefile +++ b/Makefile @@ -991,6 +991,7 @@ LIB_OBJS += sub-process.o LIB_OBJS += symlinks.o LIB_OBJS += tag.o LIB_OBJS += tempfile.o +LIB_OBJS += thread-utils.o LIB_OBJS += tmp-objdir.o LIB_OBJS += trace.o LIB_OBJS += trailer.o @@ -1674,7 +1675,6 @@ ifdef NO_PTHREADS else BASIC_CFLAGS += $(PTHREAD_CFLAGS) EXTLIBS += $(PTHREAD_LIBS) - LIB_OBJS += thread-utils.o endif ifdef HAVE_PATHS_H diff --git a/thread-utils.c b/thread-utils.c index a2135e0743..5329845691 100644 --- a/thread-utils.c +++ b/thread-utils.c @@ -20,6 +20,9 @@ int online_cpus(void) { +#ifdef NO_PTHREADS + return 1; +#else #ifdef _SC_NPROCESSORS_ONLN long ncpus; #endif @@ -59,10 +62,12 @@ int online_cpus(void) #endif return 1; +#endif } int init_recursive_mutex(pthread_mutex_t *m) { +#ifndef NO_PTHREADS pthread_mutexattr_t a; int ret; @@ -74,4 +79,47 @@ int init_recursive_mutex(pthread_mutex_t *m) pthread_mutexattr_destroy(&a); } return ret; +#else + return 0; +#endif } + +#ifdef NO_PTHREADS +int dummy_pthread_create(pthread_t *pthread, const void *attr, + void *(*fn)(void *), void *data) +{ + /* + * Do nothing. + * + * The main purpose of this function is to break compiler's + * flow analysis and avoid -Wunused-variable false warnings. + */ + return ENOSYS; +} + +int dummy_pthread_init(void *data) +{ + /* + * Do nothing. + * + * The main purpose of this function is to break compiler's + * flow analysis or it may realize that functions like + * pthread_mutex_init() is no-op, which means the (static) + * variable is not used/initialized at all and trigger + * -Wunused-variable + */ + return ENOSYS; +} + +int dummy_pthread_join(pthread_t pthread, void **retval) +{ + /* + * Do nothing. + * + * The main purpose of this function is to break compiler's + * flow analysis and avoid -Wunused-variable false warnings. + */ + return ENOSYS; +} + +#endif diff --git a/thread-utils.h b/thread-utils.h index d9a769d190..4961487ed9 100644 --- a/thread-utils.h +++ b/thread-utils.h @@ -4,12 +4,54 @@ #ifndef NO_PTHREADS #include -extern int online_cpus(void); -extern int init_recursive_mutex(pthread_mutex_t*); +#define HAVE_THREADS 1 #else -#define online_cpus() 1 +#define HAVE_THREADS 0 + +/* + * macros instead of typedefs because pthread definitions may have + * been pulled in by some system dependencies even though the user + * wants to disable pthread. + */ +#define pthread_t int +#define pthread_mutex_t int +#define pthread_cond_t int +#define pthread_key_t int + +#define pthread_mutex_init(mutex, attr) dummy_pthread_init(mutex) +#define pthread_mutex_lock(mutex) +#define pthread_mutex_unlock(mutex) +#define pthread_mutex_destroy(mutex) + +#define pthread_cond_init(cond, attr) dummy_pthread_init(cond) +#define pthread_cond_wait(cond, mutex) +#define pthread_cond_signal(cond) +#define pthread_cond_broadcast(cond) +#define pthread_cond_destroy(cond) + +#define pthread_key_create(key, attr) dummy_pthread_init(key) +#define pthread_key_delete(key) + +#define pthread_create(thread, attr, fn, data) \ + dummy_pthread_create(thread, attr, fn, data) +#define pthread_join(thread, retval) \ + dummy_pthread_join(thread, retval) + +#define pthread_setspecific(key, data) +#define pthread_getspecific(key) NULL + +int dummy_pthread_create(pthread_t *pthread, const void *attr, + void *(*fn)(void *), void *data); +int dummy_pthread_join(pthread_t pthread, void **retval); + +int dummy_pthread_init(void *); #endif + +int online_cpus(void); +int init_recursive_mutex(pthread_mutex_t*); + + #endif /* THREAD_COMPAT_H */ From 10bc232d0f93957c42b2167f00fc3437b30b08b3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nguy=E1=BB=85n=20Th=C3=A1i=20Ng=E1=BB=8Dc=20Duy?= Date: Sat, 3 Nov 2018 09:48:38 +0100 Subject: [PATCH 02/14] run-command.h: include thread-utils.h instead of pthread.h MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit run-command.c may use threads for its async support. But instead of including pthread.h directly, let's include thread-utils.h. run-command.c probably never needs the dummy bits in thread-utils.h when NO_PTHREADS is defined. But this makes sure we have consistent HAVE_THREADS behavior everywhere. From now on outside compat/, thread-utils.h is the only place that includes pthread.h Signed-off-by: Nguyễn Thái Ngọc Duy Signed-off-by: Junio C Hamano --- run-command.h | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/run-command.h b/run-command.h index 3932420ec8..9b7f38202c 100644 --- a/run-command.h +++ b/run-command.h @@ -1,9 +1,7 @@ #ifndef RUN_COMMAND_H #define RUN_COMMAND_H -#ifndef NO_PTHREADS -#include -#endif +#include "thread-utils.h" #include "argv-array.h" From c0e40a2d66e3b95d13bbc2e6e58d7b5c029d94ab Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nguy=E1=BB=85n=20Th=C3=A1i=20Ng=E1=BB=8Dc=20Duy?= Date: Sat, 3 Nov 2018 09:48:39 +0100 Subject: [PATCH 03/14] send-pack.c: move async's #ifdef NO_PTHREADS back to run-command.c MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit On systems that do not support multithread, start_async() is implemented with fork(). This implementation details unfortunately leak out at least in send-pack.c [1]. To keep the code base clean of NO_PTHREADS, move the this #ifdef back to run-command.c. The new wrapper function async_with_fork() at least helps suggest that this special "close()" is related to async in fork mode. [1] 09c9957cf7 (send-pack: avoid deadlock when pack-object dies early - 2011-04-25) Signed-off-by: Nguyễn Thái Ngọc Duy Signed-off-by: Junio C Hamano --- run-command.c | 9 +++++++++ run-command.h | 1 + send-pack.c | 5 ++--- 3 files changed, 12 insertions(+), 3 deletions(-) diff --git a/run-command.c b/run-command.c index 84b883c213..3c3b8814df 100644 --- a/run-command.c +++ b/run-command.c @@ -1246,6 +1246,15 @@ int finish_async(struct async *async) #endif } +int async_with_fork(void) +{ +#ifdef NO_PTHREADS + return 1; +#else + return 0; +#endif +} + const char *find_hook(const char *name) { static struct strbuf path = STRBUF_INIT; diff --git a/run-command.h b/run-command.h index 9b7f38202c..68f5369fc2 100644 --- a/run-command.h +++ b/run-command.h @@ -141,6 +141,7 @@ struct async { int start_async(struct async *async); int finish_async(struct async *async); int in_async(void); +int async_with_fork(void); void check_pipe(int err); /** diff --git a/send-pack.c b/send-pack.c index e920ca57df..f692686770 100644 --- a/send-pack.c +++ b/send-pack.c @@ -203,9 +203,8 @@ static int receive_status(int in, struct ref *refs) static int sideband_demux(int in, int out, void *data) { int *fd = data, ret; -#ifdef NO_PTHREADS - close(fd[1]); -#endif + if (async_with_fork()) + close(fd[1]); ret = recv_sideband("send-pack", fd[0], out); close(out); return ret; From 2094c5e582507c6bb03d4489ba4a603e3f5fc57e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nguy=E1=BB=85n=20Th=C3=A1i=20Ng=E1=BB=8Dc=20Duy?= Date: Sat, 3 Nov 2018 09:48:40 +0100 Subject: [PATCH 04/14] index-pack: remove #ifdef NO_PTHREADS MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Nguyễn Thái Ngọc Duy Signed-off-by: Junio C Hamano --- builtin/index-pack.c | 63 ++++++++++---------------------------------- 1 file changed, 14 insertions(+), 49 deletions(-) diff --git a/builtin/index-pack.c b/builtin/index-pack.c index 2004e25da2..682042579b 100644 --- a/builtin/index-pack.c +++ b/builtin/index-pack.c @@ -42,9 +42,7 @@ struct base_data { }; struct thread_local { -#ifndef NO_PTHREADS pthread_t thread; -#endif struct base_data *base_cache; size_t base_cache_used; int pack_fd; @@ -98,8 +96,6 @@ static uint32_t input_crc32; static int input_fd, output_fd; static const char *curr_pack; -#ifndef NO_PTHREADS - static struct thread_local *thread_data; static int nr_dispatched; static int threads_active; @@ -179,26 +175,6 @@ static void cleanup_thread(void) free(thread_data); } -#else - -#define read_lock() -#define read_unlock() - -#define counter_lock() -#define counter_unlock() - -#define work_lock() -#define work_unlock() - -#define deepest_delta_lock() -#define deepest_delta_unlock() - -#define type_cas_lock() -#define type_cas_unlock() - -#endif - - static int mark_link(struct object *obj, int type, void *data, struct fsck_options *options) { if (!obj) @@ -364,22 +340,20 @@ static NORETURN void bad_object(off_t offset, const char *format, ...) static inline struct thread_local *get_thread_data(void) { -#ifndef NO_PTHREADS - if (threads_active) - return pthread_getspecific(key); - assert(!threads_active && - "This should only be reached when all threads are gone"); -#endif + if (HAVE_THREADS) { + if (threads_active) + return pthread_getspecific(key); + assert(!threads_active && + "This should only be reached when all threads are gone"); + } return ¬hread_data; } -#ifndef NO_PTHREADS static void set_thread_data(struct thread_local *data) { if (threads_active) pthread_setspecific(key, data); } -#endif static struct base_data *alloc_base_data(void) { @@ -1092,7 +1066,6 @@ static void resolve_base(struct object_entry *obj) find_unresolved_deltas(base_obj); } -#ifndef NO_PTHREADS static void *threaded_second_pass(void *data) { set_thread_data(data); @@ -1116,7 +1089,6 @@ static void *threaded_second_pass(void *data) } return NULL; } -#endif /* * First pass: @@ -1213,7 +1185,6 @@ static void resolve_deltas(void) progress = start_progress(_("Resolving deltas"), nr_ref_deltas + nr_ofs_deltas); -#ifndef NO_PTHREADS nr_dispatched = 0; if (nr_threads > 1 || getenv("GIT_FORCE_THREADS")) { init_thread(); @@ -1229,7 +1200,6 @@ static void resolve_deltas(void) cleanup_thread(); return; } -#endif for (i = 0; i < nr_objects; i++) { struct object_entry *obj = &objects[i]; @@ -1531,11 +1501,10 @@ static int git_index_pack_config(const char *k, const char *v, void *cb) if (nr_threads < 0) die(_("invalid number of threads specified (%d)"), nr_threads); -#ifdef NO_PTHREADS - if (nr_threads != 1) + if (!HAVE_THREADS && nr_threads != 1) { warning(_("no threads support, ignoring %s"), k); - nr_threads = 1; -#endif + nr_threads = 1; + } return 0; } return git_default_config(k, v, cb); @@ -1723,12 +1692,10 @@ int cmd_index_pack(int argc, const char **argv, const char *prefix) nr_threads = strtoul(arg+10, &end, 0); if (!arg[10] || *end || nr_threads < 0) usage(index_pack_usage); -#ifdef NO_PTHREADS - if (nr_threads != 1) - warning(_("no threads support, " - "ignoring %s"), arg); - nr_threads = 1; -#endif + if (!HAVE_THREADS && nr_threads != 1) { + warning(_("no threads support, ignoring %s"), arg); + nr_threads = 1; + } } else if (starts_with(arg, "--pack_header=")) { struct pack_header *hdr; char *c; @@ -1791,14 +1758,12 @@ int cmd_index_pack(int argc, const char **argv, const char *prefix) if (strict) opts.flags |= WRITE_IDX_STRICT; -#ifndef NO_PTHREADS - if (!nr_threads) { + if (HAVE_THREADS && !nr_threads) { nr_threads = online_cpus(); /* An experiment showed that more threads does not mean faster */ if (nr_threads > 3) nr_threads = 3; } -#endif curr_pack = open_pack_file(pack_name); parse_pack_header(); From 07642942aa02f20623191207dd0a2730752c9533 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nguy=E1=BB=85n=20Th=C3=A1i=20Ng=E1=BB=8Dc=20Duy?= Date: Sat, 3 Nov 2018 09:48:41 +0100 Subject: [PATCH 05/14] name-hash.c: remove #ifdef NO_PTHREADS MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Nguyễn Thái Ngọc Duy Signed-off-by: Junio C Hamano --- name-hash.c | 22 ++++------------------ 1 file changed, 4 insertions(+), 18 deletions(-) diff --git a/name-hash.c b/name-hash.c index 1fcda73cb3..b3c9ac791d 100644 --- a/name-hash.c +++ b/name-hash.c @@ -7,6 +7,7 @@ */ #define NO_THE_INDEX_COMPATIBILITY_MACROS #include "cache.h" +#include "thread-utils.h" struct dir_entry { struct hashmap_entry ent; @@ -131,22 +132,6 @@ static int cache_entry_cmp(const void *unused_cmp_data, static int lazy_try_threaded = 1; static int lazy_nr_dir_threads; -#ifdef NO_PTHREADS - -static inline int lookup_lazy_params(struct index_state *istate) -{ - return 0; -} - -static inline void threaded_lazy_init_name_hash( - struct index_state *istate) -{ -} - -#else - -#include "thread-utils.h" - /* * Set a minimum number of cache_entries that we will handle per * thread and use that to decide how many threads to run (upto @@ -516,6 +501,9 @@ static void threaded_lazy_init_name_hash( struct lazy_dir_thread_data *td_dir; struct lazy_name_thread_data *td_name; + if (!HAVE_THREADS) + return; + k_start = 0; nr_each = DIV_ROUND_UP(istate->cache_nr, lazy_nr_dir_threads); @@ -574,8 +562,6 @@ static void threaded_lazy_init_name_hash( free(lazy_entries); } -#endif - static void lazy_init_name_hash(struct index_state *istate) { From 2e1b141a0132ad3afe2c81e43c4d2c9d394f5b1a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nguy=E1=BB=85n=20Th=C3=A1i=20Ng=E1=BB=8Dc=20Duy?= Date: Sat, 3 Nov 2018 09:48:42 +0100 Subject: [PATCH 06/14] attr.c: remove #ifdef NO_PTHREADS MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Nguyễn Thái Ngọc Duy Signed-off-by: Junio C Hamano --- attr.c | 14 -------------- 1 file changed, 14 deletions(-) diff --git a/attr.c b/attr.c index 60d284796d..eaece6658d 100644 --- a/attr.c +++ b/attr.c @@ -41,23 +41,17 @@ const char *git_attr_name(const struct git_attr *attr) struct attr_hashmap { struct hashmap map; -#ifndef NO_PTHREADS pthread_mutex_t mutex; -#endif }; static inline void hashmap_lock(struct attr_hashmap *map) { -#ifndef NO_PTHREADS pthread_mutex_lock(&map->mutex); -#endif } static inline void hashmap_unlock(struct attr_hashmap *map) { -#ifndef NO_PTHREADS pthread_mutex_unlock(&map->mutex); -#endif } /* @@ -498,23 +492,17 @@ static struct check_vector { size_t nr; size_t alloc; struct attr_check **checks; -#ifndef NO_PTHREADS pthread_mutex_t mutex; -#endif } check_vector; static inline void vector_lock(void) { -#ifndef NO_PTHREADS pthread_mutex_lock(&check_vector.mutex); -#endif } static inline void vector_unlock(void) { -#ifndef NO_PTHREADS pthread_mutex_unlock(&check_vector.mutex); -#endif } static void check_vector_add(struct attr_check *c) @@ -1181,8 +1169,6 @@ void git_all_attrs(const struct index_state *istate, void attr_start(void) { -#ifndef NO_PTHREADS pthread_mutex_init(&g_attr_hashmap.mutex, NULL); pthread_mutex_init(&check_vector.mutex, NULL); -#endif } From 4002e87cb254298fa2f44b98ee1b618bda0e8b59 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nguy=E1=BB=85n=20Th=C3=A1i=20Ng=E1=BB=8Dc=20Duy?= Date: Sat, 3 Nov 2018 09:48:43 +0100 Subject: [PATCH 07/14] grep: remove #ifdef NO_PTHREADS MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This is a faithful conversion without attempting to improve anything. That comes later. Signed-off-by: Nguyễn Thái Ngọc Duy Signed-off-by: Junio C Hamano --- builtin/grep.c | 59 +++++++++++++++++++------------------------------- grep.c | 6 ----- grep.h | 6 ----- 3 files changed, 22 insertions(+), 49 deletions(-) diff --git a/builtin/grep.c b/builtin/grep.c index d8508ddf79..6dd15dbaa2 100644 --- a/builtin/grep.c +++ b/builtin/grep.c @@ -34,7 +34,6 @@ static int recurse_submodules; #define GREP_NUM_THREADS_DEFAULT 8 static int num_threads; -#ifndef NO_PTHREADS static pthread_t *threads; /* We use one producer thread and THREADS consumer @@ -234,6 +233,9 @@ static int wait_all(void) int hit = 0; int i; + if (!HAVE_THREADS) + return 0; + grep_lock(); all_work_added = 1; @@ -265,13 +267,6 @@ static int wait_all(void) return hit; } -#else /* !NO_PTHREADS */ - -static int wait_all(void) -{ - return 0; -} -#endif static int grep_cmd_config(const char *var, const char *value, void *cb) { @@ -284,8 +279,7 @@ static int grep_cmd_config(const char *var, const char *value, void *cb) if (num_threads < 0) die(_("invalid number of threads specified (%d) for %s"), num_threads, var); -#ifdef NO_PTHREADS - else if (num_threads && num_threads != 1) { + else if (!HAVE_THREADS && num_threads && num_threads != 1) { /* * TRANSLATORS: %s is the configuration * variable for tweaking threads, currently @@ -294,7 +288,6 @@ static int grep_cmd_config(const char *var, const char *value, void *cb) warning(_("no threads support, ignoring %s"), var); num_threads = 0; } -#endif } if (!strcmp(var, "submodule.recurse")) @@ -330,17 +323,14 @@ static int grep_oid(struct grep_opt *opt, const struct object_id *oid, grep_source_init(&gs, GREP_SOURCE_OID, pathbuf.buf, path, oid); strbuf_release(&pathbuf); -#ifndef NO_PTHREADS - if (num_threads) { + if (HAVE_THREADS && num_threads) { /* * add_work() copies gs and thus assumes ownership of * its fields, so do not call grep_source_clear() */ add_work(opt, &gs); return 0; - } else -#endif - { + } else { int hit; hit = grep_source(opt, &gs); @@ -363,17 +353,14 @@ static int grep_file(struct grep_opt *opt, const char *filename) grep_source_init(&gs, GREP_SOURCE_FILE, buf.buf, filename, filename); strbuf_release(&buf); -#ifndef NO_PTHREADS - if (num_threads) { + if (HAVE_THREADS && num_threads) { /* * add_work() copies gs and thus assumes ownership of * its fields, so do not call grep_source_clear() */ add_work(opt, &gs); return 0; - } else -#endif - { + } else { int hit; hit = grep_source(opt, &gs); @@ -1038,20 +1025,20 @@ int cmd_grep(int argc, const char **argv, const char *prefix) pathspec.recursive = 1; pathspec.recurse_submodules = !!recurse_submodules; -#ifndef NO_PTHREADS - if (list.nr || cached || show_in_pager) + if (HAVE_THREADS) { + if (list.nr || cached || show_in_pager) + num_threads = 0; + else if (num_threads == 0) + num_threads = GREP_NUM_THREADS_DEFAULT; + else if (num_threads < 0) + die(_("invalid number of threads specified (%d)"), num_threads); + if (num_threads == 1) + num_threads = 0; + } else { + if (num_threads) + warning(_("no threads support, ignoring --threads")); num_threads = 0; - else if (num_threads == 0) - num_threads = GREP_NUM_THREADS_DEFAULT; - else if (num_threads < 0) - die(_("invalid number of threads specified (%d)"), num_threads); - if (num_threads == 1) - num_threads = 0; -#else - if (num_threads) - warning(_("no threads support, ignoring --threads")); - num_threads = 0; -#endif + } if (!num_threads) /* @@ -1062,15 +1049,13 @@ int cmd_grep(int argc, const char **argv, const char *prefix) */ compile_grep_patterns(&opt); -#ifndef NO_PTHREADS - if (num_threads) { + if (HAVE_THREADS && num_threads) { if (!(opt.name_only || opt.unmatch_name_only || opt.count) && (opt.pre_context || opt.post_context || opt.file_break || opt.funcbody)) skip_first_line = 1; start_threads(&opt); } -#endif if (show_in_pager && (cached || list.nr)) die(_("--open-files-in-pager only works on the worktree")); diff --git a/grep.c b/grep.c index f6bd89e40b..4db1510d16 100644 --- a/grep.c +++ b/grep.c @@ -1513,7 +1513,6 @@ static void show_line(struct grep_opt *opt, char *bol, char *eol, } } -#ifndef NO_PTHREADS int grep_use_locks; /* @@ -1539,11 +1538,6 @@ static inline void grep_attr_unlock(void) */ pthread_mutex_t grep_read_mutex; -#else -#define grep_attr_lock() -#define grep_attr_unlock() -#endif - static int match_funcname(struct grep_opt *opt, struct grep_source *gs, char *bol, char *eol) { xdemitconf_t *xecfg = opt->priv; diff --git a/grep.h b/grep.h index 1a57d12b90..fb04893721 100644 --- a/grep.h +++ b/grep.h @@ -229,7 +229,6 @@ int grep_source(struct grep_opt *opt, struct grep_source *gs); extern struct grep_opt *grep_opt_dup(const struct grep_opt *opt); extern int grep_threads_ok(const struct grep_opt *opt); -#ifndef NO_PTHREADS /* * Mutex used around access to the attributes machinery if * opt->use_threads. Must be initialized/destroyed by callers! @@ -250,9 +249,4 @@ static inline void grep_read_unlock(void) pthread_mutex_unlock(&grep_read_mutex); } -#else -#define grep_read_lock() -#define grep_read_unlock() -#endif - #endif From fd6263fb733e50cfbcf857136388bf47d9c5151f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nguy=E1=BB=85n=20Th=C3=A1i=20Ng=E1=BB=8Dc=20Duy?= Date: Sat, 3 Nov 2018 09:48:44 +0100 Subject: [PATCH 08/14] grep: clean up num_threads handling MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit When NO_PTHREADS is still used in this file, we have two separate code paths for thread and no thread support. The latter will always have num_threads remain zero while the former uses num_threads zero as "default number of threads". With recent changes blur the line between thread and no-thread support, this num_threads handling becomes a bit strange so let's redefine it like this: - num_threads == 0 means default number of threads and should become positive after all configuration and option parsing is done if multithread is supported. - num_threads <= 1 runs no threads. It does not matter if the platform supports threading or not. - num_threads > 1 will run multiple threads and is invalid if HAVE_THREADS is false. pthread API is only used in this case. PS. a new warning is also added when num_threads is forced back to one because a thread-incompatible option is specified. Signed-off-by: Nguyễn Thái Ngọc Duy Signed-off-by: Junio C Hamano --- builtin/grep.c | 60 +++++++++++++++++++++++--------------------------- 1 file changed, 28 insertions(+), 32 deletions(-) diff --git a/builtin/grep.c b/builtin/grep.c index 6dd15dbaa2..de3f568cee 100644 --- a/builtin/grep.c +++ b/builtin/grep.c @@ -69,13 +69,11 @@ static pthread_mutex_t grep_mutex; static inline void grep_lock(void) { - assert(num_threads); pthread_mutex_lock(&grep_mutex); } static inline void grep_unlock(void) { - assert(num_threads); pthread_mutex_unlock(&grep_mutex); } @@ -234,7 +232,7 @@ static int wait_all(void) int i; if (!HAVE_THREADS) - return 0; + BUG("Never call this function unless you have started threads"); grep_lock(); all_work_added = 1; @@ -279,14 +277,14 @@ static int grep_cmd_config(const char *var, const char *value, void *cb) if (num_threads < 0) die(_("invalid number of threads specified (%d) for %s"), num_threads, var); - else if (!HAVE_THREADS && num_threads && num_threads != 1) { + else if (!HAVE_THREADS && num_threads > 1) { /* * TRANSLATORS: %s is the configuration * variable for tweaking threads, currently * grep.threads */ warning(_("no threads support, ignoring %s"), var); - num_threads = 0; + num_threads = 1; } } @@ -323,7 +321,7 @@ static int grep_oid(struct grep_opt *opt, const struct object_id *oid, grep_source_init(&gs, GREP_SOURCE_OID, pathbuf.buf, path, oid); strbuf_release(&pathbuf); - if (HAVE_THREADS && num_threads) { + if (num_threads > 1) { /* * add_work() copies gs and thus assumes ownership of * its fields, so do not call grep_source_clear() @@ -353,7 +351,7 @@ static int grep_file(struct grep_opt *opt, const char *filename) grep_source_init(&gs, GREP_SOURCE_FILE, buf.buf, filename, filename); strbuf_release(&buf); - if (HAVE_THREADS && num_threads) { + if (num_threads > 1) { /* * add_work() copies gs and thus assumes ownership of * its fields, so do not call grep_source_clear() @@ -1025,36 +1023,34 @@ int cmd_grep(int argc, const char **argv, const char *prefix) pathspec.recursive = 1; pathspec.recurse_submodules = !!recurse_submodules; - if (HAVE_THREADS) { - if (list.nr || cached || show_in_pager) - num_threads = 0; - else if (num_threads == 0) - num_threads = GREP_NUM_THREADS_DEFAULT; - else if (num_threads < 0) - die(_("invalid number of threads specified (%d)"), num_threads); - if (num_threads == 1) - num_threads = 0; - } else { - if (num_threads) - warning(_("no threads support, ignoring --threads")); - num_threads = 0; - } + if (list.nr || cached || show_in_pager) { + if (num_threads > 1) + warning(_("invalid option combination, ignoring --threads")); + num_threads = 1; + } else if (!HAVE_THREADS && num_threads > 1) { + warning(_("no threads support, ignoring --threads")); + num_threads = 1; + } else if (num_threads < 0) + die(_("invalid number of threads specified (%d)"), num_threads); + else if (num_threads == 0) + num_threads = HAVE_THREADS ? GREP_NUM_THREADS_DEFAULT : 1; - if (!num_threads) - /* - * The compiled patterns on the main path are only - * used when not using threading. Otherwise - * start_threads() below calls compile_grep_patterns() - * for each thread. - */ - compile_grep_patterns(&opt); - - if (HAVE_THREADS && num_threads) { + if (num_threads > 1) { + if (!HAVE_THREADS) + BUG("Somebody got num_threads calculation wrong!"); if (!(opt.name_only || opt.unmatch_name_only || opt.count) && (opt.pre_context || opt.post_context || opt.file_break || opt.funcbody)) skip_first_line = 1; start_threads(&opt); + } else { + /* + * The compiled patterns on the main path are only + * used when not using threading. Otherwise + * start_threads() above calls compile_grep_patterns() + * for each thread. + */ + compile_grep_patterns(&opt); } if (show_in_pager && (cached || list.nr)) @@ -1106,7 +1102,7 @@ int cmd_grep(int argc, const char **argv, const char *prefix) hit = grep_objects(&opt, &pathspec, &list); } - if (num_threads) + if (num_threads > 1) hit |= wait_all(); if (hit && show_in_pager) run_pager(&opt, prefix); From e8d405662fa2e89b850ec79573953e17fea83ed1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nguy=E1=BB=85n=20Th=C3=A1i=20Ng=E1=BB=8Dc=20Duy?= Date: Sat, 3 Nov 2018 09:48:45 +0100 Subject: [PATCH 09/14] preload-index.c: remove #ifdef NO_PTHREADS MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Nguyễn Thái Ngọc Duy Signed-off-by: Junio C Hamano --- preload-index.c | 15 ++------------- 1 file changed, 2 insertions(+), 13 deletions(-) diff --git a/preload-index.c b/preload-index.c index 9e7152ab14..0e24886aca 100644 --- a/preload-index.c +++ b/preload-index.c @@ -7,17 +7,7 @@ #include "fsmonitor.h" #include "config.h" #include "progress.h" - -#ifdef NO_PTHREADS -static void preload_index(struct index_state *index, - const struct pathspec *pathspec, - unsigned int refresh_flags) -{ - ; /* nothing */ -} -#else - -#include +#include "thread-utils.h" /* * Mostly randomly chosen maximum thread counts: we @@ -108,7 +98,7 @@ static void preload_index(struct index_state *index, struct thread_data data[MAX_PARALLEL]; struct progress_data pd; - if (!core_preload_index) + if (!HAVE_THREADS || !core_preload_index) return; threads = index->cache_nr / THREAD_COST; @@ -151,7 +141,6 @@ static void preload_index(struct index_state *index, trace_performance_leave("preload index"); } -#endif int read_index_preload(struct index_state *index, const struct pathspec *pathspec, From 9c897c5c2ad27d82b47472c967f675cad122aed3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nguy=E1=BB=85n=20Th=C3=A1i=20Ng=E1=BB=8Dc=20Duy?= Date: Sat, 3 Nov 2018 09:48:46 +0100 Subject: [PATCH 10/14] pack-objects: remove #ifdef NO_PTHREADS MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Nguyễn Thái Ngọc Duy Signed-off-by: Junio C Hamano --- builtin/pack-objects.c | 26 ++------------------------ pack-objects.h | 6 ------ 2 files changed, 2 insertions(+), 30 deletions(-) diff --git a/builtin/pack-objects.c b/builtin/pack-objects.c index b059b86aee..12edd6da16 100644 --- a/builtin/pack-objects.c +++ b/builtin/pack-objects.c @@ -1953,8 +1953,6 @@ static int delta_cacheable(unsigned long src_size, unsigned long trg_size, return 0; } -#ifndef NO_PTHREADS - /* Protect access to object database */ static pthread_mutex_t read_mutex; #define read_lock() pthread_mutex_lock(&read_mutex) @@ -1979,16 +1977,6 @@ static pthread_mutex_t progress_mutex; * ahead in the list because they can be stolen and would need * progress_mutex for protection. */ -#else - -#define read_lock() (void)0 -#define read_unlock() (void)0 -#define cache_lock() (void)0 -#define cache_unlock() (void)0 -#define progress_lock() (void)0 -#define progress_unlock() (void)0 - -#endif /* * Return the size of the object without doing any delta @@ -2347,8 +2335,6 @@ static void find_deltas(struct object_entry **list, unsigned *list_size, free(array); } -#ifndef NO_PTHREADS - static void try_to_free_from_threads(size_t size) { read_lock(); @@ -2578,10 +2564,6 @@ static void ll_find_deltas(struct object_entry **list, unsigned list_size, free(p); } -#else -#define ll_find_deltas(l, s, w, d, p) find_deltas(l, &s, w, d, p) -#endif - static void add_tag_chain(const struct object_id *oid) { struct tag *tag; @@ -2734,12 +2716,10 @@ static int git_pack_config(const char *k, const char *v, void *cb) if (delta_search_threads < 0) die(_("invalid number of threads specified (%d)"), delta_search_threads); -#ifdef NO_PTHREADS - if (delta_search_threads != 1) { + if (!HAVE_THREADS && delta_search_threads != 1) { warning(_("no threads support, ignoring %s"), k); delta_search_threads = 0; } -#endif return 0; } if (!strcmp(k, "pack.indexversion")) { @@ -3402,10 +3382,8 @@ int cmd_pack_objects(int argc, const char **argv, const char *prefix) if (!delta_search_threads) /* --threads=0 means autodetect */ delta_search_threads = online_cpus(); -#ifdef NO_PTHREADS - if (delta_search_threads != 1) + if (!HAVE_THREADS && delta_search_threads != 1) warning(_("no threads support, ignoring --threads")); -#endif if (!pack_to_stdout && !pack_size_limit) pack_size_limit = pack_size_limit_cfg; if (pack_to_stdout && pack_size_limit) diff --git a/pack-objects.h b/pack-objects.h index 2ca39cfcfe..3a42727c7d 100644 --- a/pack-objects.h +++ b/pack-objects.h @@ -145,9 +145,7 @@ struct packing_data { struct packed_git **in_pack_by_idx; struct packed_git **in_pack; -#ifndef NO_PTHREADS pthread_mutex_t lock; -#endif /* * This list contains entries for bases which we know the other side @@ -169,15 +167,11 @@ void prepare_packing_data(struct packing_data *pdata); static inline void packing_data_lock(struct packing_data *pdata) { -#ifndef NO_PTHREADS pthread_mutex_lock(&pdata->lock); -#endif } static inline void packing_data_unlock(struct packing_data *pdata) { -#ifndef NO_PTHREADS pthread_mutex_unlock(&pdata->lock); -#endif } struct object_entry *packlist_alloc(struct packing_data *pdata, From 62e5ee81a39dff5d69992b669f7896b6dc31bfd5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nguy=E1=BB=85n=20Th=C3=A1i=20Ng=E1=BB=8Dc=20Duy?= Date: Sat, 3 Nov 2018 09:48:47 +0100 Subject: [PATCH 11/14] read-cache.c: remove #ifdef NO_PTHREADS MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This is a faithful conversion with no attempt to clean up whatsoever. Code indentation is left broken. There will be another commit to clean it up and un-indent if we just indent now. It's just more code noise. Signed-off-by: Nguyễn Thái Ngọc Duy Signed-off-by: Junio C Hamano --- read-cache.c | 34 ++++++++++------------------------ 1 file changed, 10 insertions(+), 24 deletions(-) diff --git a/read-cache.c b/read-cache.c index d57958233e..40fc0cb65f 100644 --- a/read-cache.c +++ b/read-cache.c @@ -1920,19 +1920,15 @@ struct index_entry_offset_table struct index_entry_offset entries[FLEX_ARRAY]; }; -#ifndef NO_PTHREADS static struct index_entry_offset_table *read_ieot_extension(const char *mmap, size_t mmap_size, size_t offset); static void write_ieot_extension(struct strbuf *sb, struct index_entry_offset_table *ieot); -#endif static size_t read_eoie_extension(const char *mmap, size_t mmap_size); static void write_eoie_extension(struct strbuf *sb, git_hash_ctx *eoie_context, size_t offset); struct load_index_extensions { -#ifndef NO_PTHREADS pthread_t pthread; -#endif struct index_state *istate; const char *mmap; size_t mmap_size; @@ -2010,8 +2006,6 @@ static unsigned long load_all_cache_entries(struct index_state *istate, return consumed; } -#ifndef NO_PTHREADS - /* * Mostly randomly chosen maximum thread counts: we * cap the parallelism to online_cpus() threads, and we want @@ -2122,7 +2116,6 @@ static unsigned long load_cache_entries_threaded(struct index_state *istate, con return consumed; } -#endif /* remember to discard_cache() before reading a different cache! */ int do_read_index(struct index_state *istate, const char *path, int must_exist) @@ -2135,10 +2128,8 @@ int do_read_index(struct index_state *istate, const char *path, int must_exist) size_t mmap_size; struct load_index_extensions p; size_t extension_offset = 0; -#ifndef NO_PTHREADS int nr_threads, cpus; struct index_entry_offset_table *ieot = NULL; -#endif if (istate->initialized) return istate->cache_nr; @@ -2181,7 +2172,7 @@ int do_read_index(struct index_state *istate, const char *path, int must_exist) src_offset = sizeof(*hdr); -#ifndef NO_PTHREADS + if (HAVE_THREADS) { nr_threads = git_config_get_index_threads(); /* TODO: does creating more threads than cores help? */ @@ -2219,21 +2210,19 @@ int do_read_index(struct index_state *istate, const char *path, int must_exist) } else { src_offset += load_all_cache_entries(istate, mmap, mmap_size, src_offset); } -#else - src_offset += load_all_cache_entries(istate, mmap, mmap_size, src_offset); -#endif + } else { + src_offset += load_all_cache_entries(istate, mmap, mmap_size, src_offset); + } istate->timestamp.sec = st.st_mtime; istate->timestamp.nsec = ST_MTIME_NSEC(st); /* if we created a thread, join it otherwise load the extensions on the primary thread */ -#ifndef NO_PTHREADS - if (extension_offset) { + if (HAVE_THREADS && extension_offset) { int ret = pthread_join(p.pthread, NULL); if (ret) die(_("unable to join load_index_extensions thread: %s"), strerror(ret)); } -#endif if (!extension_offset) { p.src_offset = src_offset; load_index_extensions(&p); @@ -2756,8 +2745,9 @@ static int do_write_index(struct index_state *istate, struct tempfile *tempfile, if (ce_write(&c, newfd, &hdr, sizeof(hdr)) < 0) return -1; -#ifndef NO_PTHREADS - nr_threads = git_config_get_index_threads(); + if (HAVE_THREADS) { + nr_threads = git_config_get_index_threads(); + if (nr_threads != 1) { int ieot_blocks, cpus; @@ -2787,7 +2777,7 @@ static int do_write_index(struct index_state *istate, struct tempfile *tempfile, ieot_entries = DIV_ROUND_UP(entries, ieot_blocks); } } -#endif + } offset = lseek(newfd, 0, SEEK_CUR); if (offset < 0) { @@ -2871,8 +2861,7 @@ static int do_write_index(struct index_state *istate, struct tempfile *tempfile, * strip_extensions parameter as we need it when loading the shared * index. */ -#ifndef NO_PTHREADS - if (ieot) { + if (HAVE_THREADS && ieot) { struct strbuf sb = STRBUF_INIT; write_ieot_extension(&sb, ieot); @@ -2883,7 +2872,6 @@ static int do_write_index(struct index_state *istate, struct tempfile *tempfile, if (err) return -1; } -#endif if (!strip_extensions && istate->split_index) { struct strbuf sb = STRBUF_INIT; @@ -3469,7 +3457,6 @@ static void write_eoie_extension(struct strbuf *sb, git_hash_ctx *eoie_context, strbuf_add(sb, hash, the_hash_algo->rawsz); } -#ifndef NO_PTHREADS #define IEOT_VERSION (1) static struct index_entry_offset_table *read_ieot_extension(const char *mmap, size_t mmap_size, size_t offset) @@ -3542,4 +3529,3 @@ static void write_ieot_extension(struct strbuf *sb, struct index_entry_offset_ta strbuf_add(sb, &buffer, sizeof(uint32_t)); } } -#endif From 88168b9b43a17d5f7712d15cf5ccfed517eb4470 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nguy=E1=BB=85n=20Th=C3=A1i=20Ng=E1=BB=8Dc=20Duy?= Date: Sat, 3 Nov 2018 09:48:48 +0100 Subject: [PATCH 12/14] read-cache.c: reduce branching based on HAVE_THREADS MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Nguyễn Thái Ngọc Duy Signed-off-by: Junio C Hamano --- read-cache.c | 19 +++++++++---------- 1 file changed, 9 insertions(+), 10 deletions(-) diff --git a/read-cache.c b/read-cache.c index 40fc0cb65f..00cd416816 100644 --- a/read-cache.c +++ b/read-cache.c @@ -2172,7 +2172,6 @@ int do_read_index(struct index_state *istate, const char *path, int must_exist) src_offset = sizeof(*hdr); - if (HAVE_THREADS) { nr_threads = git_config_get_index_threads(); /* TODO: does creating more threads than cores help? */ @@ -2183,6 +2182,9 @@ int do_read_index(struct index_state *istate, const char *path, int must_exist) nr_threads = cpus; } + if (!HAVE_THREADS) + nr_threads = 1; + if (nr_threads > 1) { extension_offset = read_eoie_extension(mmap, mmap_size); if (extension_offset) { @@ -2210,20 +2212,16 @@ int do_read_index(struct index_state *istate, const char *path, int must_exist) } else { src_offset += load_all_cache_entries(istate, mmap, mmap_size, src_offset); } - } else { - src_offset += load_all_cache_entries(istate, mmap, mmap_size, src_offset); - } istate->timestamp.sec = st.st_mtime; istate->timestamp.nsec = ST_MTIME_NSEC(st); /* if we created a thread, join it otherwise load the extensions on the primary thread */ - if (HAVE_THREADS && extension_offset) { + if (extension_offset) { int ret = pthread_join(p.pthread, NULL); if (ret) die(_("unable to join load_index_extensions thread: %s"), strerror(ret)); - } - if (!extension_offset) { + } else { p.src_offset = src_offset; load_index_extensions(&p); } @@ -2745,8 +2743,10 @@ static int do_write_index(struct index_state *istate, struct tempfile *tempfile, if (ce_write(&c, newfd, &hdr, sizeof(hdr)) < 0) return -1; - if (HAVE_THREADS) { + if (HAVE_THREADS) nr_threads = git_config_get_index_threads(); + else + nr_threads = 1; if (nr_threads != 1) { int ieot_blocks, cpus; @@ -2777,7 +2777,6 @@ static int do_write_index(struct index_state *istate, struct tempfile *tempfile, ieot_entries = DIV_ROUND_UP(entries, ieot_blocks); } } - } offset = lseek(newfd, 0, SEEK_CUR); if (offset < 0) { @@ -2861,7 +2860,7 @@ static int do_write_index(struct index_state *istate, struct tempfile *tempfile, * strip_extensions parameter as we need it when loading the shared * index. */ - if (HAVE_THREADS && ieot) { + if (ieot) { struct strbuf sb = STRBUF_INIT; write_ieot_extension(&sb, ieot); From f5c4a9af45fa47130c730a5da87e030d040f000b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nguy=E1=BB=85n=20Th=C3=A1i=20Ng=E1=BB=8Dc=20Duy?= Date: Sat, 3 Nov 2018 09:48:49 +0100 Subject: [PATCH 13/14] read-cache.c: initialize copy_len to shut up gcc 8 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit It was reported that when building with NO_PTHREADS=1, -Wmaybe-uninitialized is triggered. Just initialize the variable from the beginning to shut the compiler up (because this warning is enabled in config.dev) Signed-off-by: Nguyễn Thái Ngọc Duy Signed-off-by: Junio C Hamano --- read-cache.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/read-cache.c b/read-cache.c index 00cd416816..c510f598b1 100644 --- a/read-cache.c +++ b/read-cache.c @@ -1746,7 +1746,7 @@ static struct cache_entry *create_from_disk(struct mem_pool *ce_mem_pool, size_t len; const char *name; unsigned int flags; - size_t copy_len; + size_t copy_len = 0; /* * Adjacent cache entries tend to share the leading paths, so it makes * sense to only store the differences in later entries. In the v4 @@ -1786,8 +1786,6 @@ static struct cache_entry *create_from_disk(struct mem_pool *ce_mem_pool, die(_("malformed name field in the index, near path '%s'"), previous_ce->name); copy_len = previous_len - strip_len; - } else { - copy_len = 0; } name = (const char *)cp; } From 2179045fd02acca83127f8d15ccd0eeb70b17400 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nguy=E1=BB=85n=20Th=C3=A1i=20Ng=E1=BB=8Dc=20Duy?= Date: Sat, 3 Nov 2018 09:48:50 +0100 Subject: [PATCH 14/14] Clean up pthread_create() error handling MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Normally pthread_create() rarely fails. But with new pthreads wrapper, pthread_create() will return ENOSYS on a system without thread support. Threaded code _is_ protected by HAVE_THREADS and pthread_create() should never run in the first place. But the situation could change in the future and bugs may sneak in. Make sure that all pthread_create() reports the error cause. While at there, mark these strings for translation if they aren't. Signed-off-by: Nguyễn Thái Ngọc Duy Signed-off-by: Junio C Hamano --- name-hash.c | 16 ++++++++++------ preload-index.c | 8 ++++++-- run-command.c | 2 +- 3 files changed, 17 insertions(+), 9 deletions(-) diff --git a/name-hash.c b/name-hash.c index b3c9ac791d..623ca6923a 100644 --- a/name-hash.c +++ b/name-hash.c @@ -494,6 +494,7 @@ static inline void lazy_update_dir_ref_counts( static void threaded_lazy_init_name_hash( struct index_state *istate) { + int err; int nr_each; int k_start; int t; @@ -526,8 +527,9 @@ static void threaded_lazy_init_name_hash( if (k_start > istate->cache_nr) k_start = istate->cache_nr; td_dir_t->k_end = k_start; - if (pthread_create(&td_dir_t->pthread, NULL, lazy_dir_thread_proc, td_dir_t)) - die("unable to create lazy_dir_thread"); + err = pthread_create(&td_dir_t->pthread, NULL, lazy_dir_thread_proc, td_dir_t); + if (err) + die(_("unable to create lazy_dir thread: %s"), strerror(err)); } for (t = 0; t < lazy_nr_dir_threads; t++) { struct lazy_dir_thread_data *td_dir_t = td_dir + t; @@ -547,13 +549,15 @@ static void threaded_lazy_init_name_hash( */ td_name->istate = istate; td_name->lazy_entries = lazy_entries; - if (pthread_create(&td_name->pthread, NULL, lazy_name_thread_proc, td_name)) - die("unable to create lazy_name_thread"); + err = pthread_create(&td_name->pthread, NULL, lazy_name_thread_proc, td_name); + if (err) + die(_("unable to create lazy_name thread: %s"), strerror(err)); lazy_update_dir_ref_counts(istate, lazy_entries); - if (pthread_join(td_name->pthread, NULL)) - die("unable to join lazy_name_thread"); + err = pthread_join(td_name->pthread, NULL); + if (err) + die(_("unable to join lazy_name thread: %s"), strerror(err)); cleanup_dir_mutex(); diff --git a/preload-index.c b/preload-index.c index 0e24886aca..ddca1c216e 100644 --- a/preload-index.c +++ b/preload-index.c @@ -121,6 +121,8 @@ static void preload_index(struct index_state *index, for (i = 0; i < threads; i++) { struct thread_data *p = data+i; + int err; + p->index = index; if (pathspec) copy_pathspec(&p->pathspec, pathspec); @@ -129,8 +131,10 @@ static void preload_index(struct index_state *index, if (pd.progress) p->progress = &pd; offset += work; - if (pthread_create(&p->pthread, NULL, preload_thread, p)) - die("unable to create threaded lstat"); + err = pthread_create(&p->pthread, NULL, preload_thread, p); + + if (err) + die(_("unable to create threaded lstat: %s"), strerror(err)); } for (i = 0; i < threads; i++) { struct thread_data *p = data+i; diff --git a/run-command.c b/run-command.c index 3c3b8814df..decf3239bd 100644 --- a/run-command.c +++ b/run-command.c @@ -1213,7 +1213,7 @@ int start_async(struct async *async) { int err = pthread_create(&async->tid, NULL, run_thread, async); if (err) { - error_errno("cannot create thread"); + error(_("cannot create async thread: %s"), strerror(err)); goto error; } }