From: Junio C Hamano Date: Sun, 18 Nov 2018 09:23:52 +0000 (+0900) Subject: Merge branch 'nd/pthreads' X-Git-Tag: v2.20.0-rc0~26 X-Git-Url: https://git.lorimer.id.au/gitweb.git/diff_plain/26b80a841ad6f2ddff855aa9bd0000a4ba81f6ff?ds=inline;hp=-c Merge branch 'nd/pthreads' The codebase has been cleaned up to reduce "#ifndef NO_PTHREADS". * nd/pthreads: Clean up pthread_create() error handling read-cache.c: initialize copy_len to shut up gcc 8 read-cache.c: reduce branching based on HAVE_THREADS read-cache.c: remove #ifdef NO_PTHREADS pack-objects: remove #ifdef NO_PTHREADS preload-index.c: remove #ifdef NO_PTHREADS grep: clean up num_threads handling grep: remove #ifdef NO_PTHREADS attr.c: remove #ifdef NO_PTHREADS name-hash.c: remove #ifdef NO_PTHREADS index-pack: remove #ifdef NO_PTHREADS send-pack.c: move async's #ifdef NO_PTHREADS back to run-command.c run-command.h: include thread-utils.h instead of pthread.h thread-utils: macros to unconditionally compile pthreads API --- 26b80a841ad6f2ddff855aa9bd0000a4ba81f6ff diff --combined Makefile index 016fdcdb81,321540a736..3b48e86e8b --- a/Makefile +++ b/Makefile @@@ -616,7 -616,7 +616,7 @@@ SCRIPT_SH += git-merge-one-file.s SCRIPT_SH += git-merge-resolve.sh SCRIPT_SH += git-mergetool.sh SCRIPT_SH += git-quiltimport.sh -SCRIPT_SH += git-rebase.sh +SCRIPT_SH += git-legacy-rebase.sh SCRIPT_SH += git-remote-testgit.sh SCRIPT_SH += git-request-pull.sh SCRIPT_SH += git-stash.sh @@@ -626,7 -626,7 +626,7 @@@ SCRIPT_SH += git-web--browse.s SCRIPT_LIB += git-mergetool--lib SCRIPT_LIB += git-parse-remote SCRIPT_LIB += git-rebase--am -SCRIPT_LIB += git-rebase--interactive +SCRIPT_LIB += git-rebase--common SCRIPT_LIB += git-rebase--preserve-merges SCRIPT_LIB += git-rebase--merge SCRIPT_LIB += git-sh-setup @@@ -751,7 -751,6 +751,7 @@@ TEST_BUILTINS_OBJS += test-sigchain. TEST_BUILTINS_OBJS += test-strcmp-offset.o TEST_BUILTINS_OBJS += test-string-list.o TEST_BUILTINS_OBJS += test-submodule-config.o +TEST_BUILTINS_OBJS += test-submodule-nested-repo-config.o TEST_BUILTINS_OBJS += test-subprocess.o TEST_BUILTINS_OBJS += test-urlmatch-normalization.o TEST_BUILTINS_OBJS += test-wildmatch.o @@@ -955,7 -954,6 +955,7 @@@ LIB_OBJS += quote. LIB_OBJS += range-diff.o LIB_OBJS += reachable.o LIB_OBJS += read-cache.o +LIB_OBJS += rebase-interactive.o LIB_OBJS += reflog-walk.o LIB_OBJS += refs.o LIB_OBJS += refs/files-backend.o @@@ -993,6 -991,7 +993,7 @@@ LIB_OBJS += sub-process. 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 @@@ -1095,8 -1094,7 +1096,8 @@@ BUILTIN_OBJS += builtin/pull. BUILTIN_OBJS += builtin/push.o BUILTIN_OBJS += builtin/range-diff.o BUILTIN_OBJS += builtin/read-tree.o -BUILTIN_OBJS += builtin/rebase--helper.o +BUILTIN_OBJS += builtin/rebase.o +BUILTIN_OBJS += builtin/rebase--interactive.o BUILTIN_OBJS += builtin/receive-pack.o BUILTIN_OBJS += builtin/reflog.o BUILTIN_OBJS += builtin/remote.o @@@ -1677,7 -1675,6 +1678,6 @@@ ifdef NO_PTHREAD else BASIC_CFLAGS += $(PTHREAD_CFLAGS) EXTLIBS += $(PTHREAD_LIBS) - LIB_OBJS += thread-utils.o endif ifdef HAVE_PATHS_H @@@ -2071,7 -2068,7 +2071,7 @@@ $(BUILT_INS): git$ command-list.h: generate-cmdlist.sh command-list.txt -command-list.h: $(wildcard Documentation/git*.txt) Documentation/*config.txt +command-list.h: $(wildcard Documentation/git*.txt) Documentation/*config.txt Documentation/config/*.txt $(QUIET_GEN)$(SHELL_PATH) ./generate-cmdlist.sh command-list.txt >$@+ && mv $@+ $@ SCRIPT_DEFINES = $(SHELL_PATH_SQ):$(DIFF_SQ):$(GIT_VERSION):\ @@@ -2437,6 -2434,7 +2437,6 @@@ XGETTEXT_FLAGS_PERL = $(XGETTEXT_FLAGS LOCALIZED_C = $(C_OBJ:o=c) $(LIB_H) $(GENERATED_H) LOCALIZED_SH = $(SCRIPT_SH) LOCALIZED_SH += git-parse-remote.sh -LOCALIZED_SH += git-rebase--interactive.sh LOCALIZED_SH += git-rebase--preserve-merges.sh LOCALIZED_SH += git-sh-setup.sh LOCALIZED_PERL = $(SCRIPT_PERL) diff --combined builtin/grep.c index 56e4a11052,de3f568cee..cca87cf870 --- a/builtin/grep.c +++ b/builtin/grep.c @@@ -34,7 -34,6 +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 @@@ -70,13 -69,11 +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,6 -231,9 +231,9 @@@ static int wait_all(void int hit = 0; int i; + if (!HAVE_THREADS) + BUG("Never call this function unless you have started threads"); + grep_lock(); all_work_added = 1; @@@ -265,13 -265,6 +265,6 @@@ 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,17 -277,15 +277,15 @@@ 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 > 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; } - #endif } if (!strcmp(var, "submodule.recurse")) @@@ -330,17 -321,14 +321,14 @@@ static int grep_oid(struct grep_opt *op grep_source_init(&gs, GREP_SOURCE_OID, pathbuf.buf, path, oid); strbuf_release(&pathbuf); - #ifndef NO_PTHREADS - if (num_threads) { + if (num_threads > 1) { /* * 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 -351,14 +351,14 @@@ static int grep_file(struct grep_opt *o grep_source_init(&gs, GREP_SOURCE_FILE, buf.buf, filename, filename); strbuf_release(&buf); - #ifndef NO_PTHREADS - if (num_threads) { + if (num_threads > 1) { /* * 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); @@@ -422,23 -407,11 +407,23 @@@ static int grep_submodule(struct grep_o struct repository submodule; int hit; - if (!is_submodule_active(superproject, path)) + /* + * NEEDSWORK: submodules functions need to be protected because they + * access the object store via config_from_gitmodules(): the latter + * uses get_oid() which, for now, relies on the global the_repository + * object. + */ + grep_read_lock(); + + if (!is_submodule_active(superproject, path)) { + grep_read_unlock(); return 0; + } - if (repo_submodule_init(&submodule, superproject, path)) + if (repo_submodule_init(&submodule, superproject, path)) { + grep_read_unlock(); return 0; + } repo_read_gitmodules(&submodule); @@@ -452,6 -425,7 +437,6 @@@ * store is no longer global and instead is a member of the repository * object. */ - grep_read_lock(); add_to_alternates_memory(submodule.objects->objectdir); grep_read_unlock(); @@@ -1049,39 -1023,35 +1034,35 @@@ int cmd_grep(int argc, const char **arg pathspec.recursive = 1; pathspec.recurse_submodules = !!recurse_submodules; - #ifndef NO_PTHREADS - 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) + 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 = 0; - #endif + 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) + 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() below calls compile_grep_patterns() + * start_threads() above calls compile_grep_patterns() * for each thread. */ compile_grep_patterns(&opt); - - #ifndef NO_PTHREADS - if (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")); @@@ -1132,7 -1102,7 +1113,7 @@@ 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); diff --combined builtin/pack-objects.c index c99ee79c31,12edd6da16..2193054d27 --- a/builtin/pack-objects.c +++ b/builtin/pack-objects.c @@@ -1953,8 -1953,6 +1953,6 @@@ static int delta_cacheable(unsigned lon 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 +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 +2335,6 @@@ static void find_deltas(struct object_e free(array); } - #ifndef NO_PTHREADS - static void try_to_free_from_threads(size_t size) { read_lock(); @@@ -2399,6 -2385,7 +2385,6 @@@ static void init_threaded_search(void pthread_mutex_init(&cache_mutex, NULL); pthread_mutex_init(&progress_mutex, NULL); pthread_cond_init(&progress_cond, NULL); - pthread_mutex_init(&to_pack.lock, NULL); old_try_to_free_routine = set_try_to_free_routine(try_to_free_from_threads); } @@@ -2577,10 -2564,6 +2563,6 @@@ static void ll_find_deltas(struct objec 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; @@@ -2733,12 -2716,10 +2715,10 @@@ static int git_pack_config(const char * 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")) { @@@ -3107,7 -3088,6 +3087,7 @@@ static void get_object_list(int ac, con repo_init_revisions(the_repository, &revs, NULL); save_commit_buffer = 0; + revs.allow_exclude_promisor_objects_opt = 1; setup_revisions(ac, av, &revs, NULL); /* make sure shallows are read */ @@@ -3402,10 -3382,8 +3382,8 @@@ int cmd_pack_objects(int argc, const ch 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 --combined pack-objects.h index 86ee93feb4,3a42727c7d..feb6a6a05e --- a/pack-objects.h +++ b/pack-objects.h @@@ -145,9 -145,7 +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 +167,11 @@@ void prepare_packing_data(struct packin 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, @@@ -377,7 -371,7 +371,7 @@@ static inline unsigned long oe_delta_si return e->delta_size_; /* - * pack->detla_size[] can't be NULL because oe_set_delta_size() + * pack->delta_size[] can't be NULL because oe_set_delta_size() * must have been called when a new delta is saved with * oe_set_delta(). * If oe_delta() returns NULL (i.e. default state, which means diff --combined preload-index.c index 222792ccbc,ddca1c216e..c7dc3f2b9f --- a/preload-index.c +++ b/preload-index.c @@@ -7,17 -7,7 +7,7 @@@ #include "fsmonitor.h" #include "config.h" #include "progress.h" - - #ifdef NO_PTHREADS - 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 @@@ -100,15 -90,15 +90,15 @@@ static void *preload_thread(void *_data return NULL; } -static void preload_index(struct index_state *index, - const struct pathspec *pathspec, - unsigned int refresh_flags) +void preload_index(struct index_state *index, + const struct pathspec *pathspec, + unsigned int refresh_flags) { int threads, i, work, offset; 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; @@@ -131,6 -121,8 +121,8 @@@ for (i = 0; i < threads; i++) { struct thread_data *p = data+i; + int err; + p->index = index; if (pathspec) copy_pathspec(&p->pathspec, pathspec); @@@ -139,8 -131,10 +131,10 @@@ 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; @@@ -151,7 -145,6 +145,6 @@@ trace_performance_leave("preload index"); } - #endif int read_index_preload(struct index_state *index, const struct pathspec *pathspec, diff --combined read-cache.c index 8c924506dd,c510f598b1..4ca81286c0 --- a/read-cache.c +++ b/read-cache.c @@@ -1496,12 -1496,6 +1496,12 @@@ int refresh_index(struct index_state *i typechange_fmt = (in_porcelain ? "T\t%s\n" : "%s needs update\n"); added_fmt = (in_porcelain ? "A\t%s\n" : "%s needs update\n"); unmerged_fmt = (in_porcelain ? "U\t%s\n" : "%s: needs merge\n"); + /* + * Use the multi-threaded preload_index() to refresh most of the + * cache entries quickly then in the single threaded loop below, + * we only have to do the special cases that are left. + */ + preload_index(istate, pathspec, 0); for (i = 0; i < istate->cache_nr; i++) { struct cache_entry *ce, *new_entry; int cache_errno = 0; @@@ -1752,7 -1746,7 +1752,7 @@@ static struct cache_entry *create_from_ 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 @@@ -1792,8 -1786,6 +1792,6 @@@ 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; } @@@ -1926,19 -1918,15 +1924,15 @@@ struct index_entry_offset_tabl 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; @@@ -2016,8 -2004,6 +2010,6 @@@ static unsigned long load_all_cache_ent return consumed; } - #ifndef NO_PTHREADS - /* * Mostly randomly chosen maximum thread counts: we * cap the parallelism to online_cpus() threads, and we want @@@ -2128,7 -2114,6 +2120,6 @@@ static unsigned long load_cache_entries 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) @@@ -2141,10 -2126,8 +2132,8 @@@ 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; @@@ -2187,7 -2170,6 +2176,6 @@@ src_offset = sizeof(*hdr); - #ifndef NO_PTHREADS nr_threads = git_config_get_index_threads(); /* TODO: does creating more threads than cores help? */ @@@ -2198,6 -2180,9 +2186,9 @@@ nr_threads = cpus; } + if (!HAVE_THREADS) + nr_threads = 1; + if (nr_threads > 1) { extension_offset = read_eoie_extension(mmap, mmap_size); if (extension_offset) { @@@ -2225,22 -2210,16 +2216,16 @@@ } 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 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) { int ret = pthread_join(p.pthread, NULL); if (ret) die(_("unable to join load_index_extensions thread: %s"), strerror(ret)); - } - #endif - if (!extension_offset) { + } else { p.src_offset = src_offset; load_index_extensions(&p); } @@@ -2303,8 -2282,8 +2288,8 @@@ int read_index_from(struct index_state freshen_shared_index(base_path, 0); merge_base_index(istate); post_read_index_from(istate); - free(base_path); trace_performance_leave("read cache %s", base_path); + free(base_path); return ret; } @@@ -2762,8 -2741,11 +2747,11 @@@ static int do_write_index(struct index_ 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(); + else + nr_threads = 1; + if (nr_threads != 1) { int ieot_blocks, cpus; @@@ -2793,7 -2775,6 +2781,6 @@@ ieot_entries = DIV_ROUND_UP(entries, ieot_blocks); } } - #endif offset = lseek(newfd, 0, SEEK_CUR); if (offset < 0) { @@@ -2877,7 -2858,6 +2864,6 @@@ * strip_extensions parameter as we need it when loading the shared * index. */ - #ifndef NO_PTHREADS if (ieot) { struct strbuf sb = STRBUF_INIT; @@@ -2889,7 -2869,6 +2875,6 @@@ if (err) return -1; } - #endif if (!strip_extensions && istate->split_index) { struct strbuf sb = STRBUF_INIT; @@@ -3475,7 -3454,6 +3460,6 @@@ static void write_eoie_extension(struc 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) @@@ -3548,4 -3526,3 +3532,3 @@@ static void write_ieot_extension(struc strbuf_add(sb, &buffer, sizeof(uint32_t)); } } - #endif diff --combined run-command.c index d679cc267c,decf3239bd..c11ff80674 --- a/run-command.c +++ b/run-command.c @@@ -380,7 -380,7 +380,7 @@@ static void child_err_spew(struct child set_error_routine(old_errfn); } -static void prepare_cmd(struct argv_array *out, const struct child_process *cmd) +static int prepare_cmd(struct argv_array *out, const struct child_process *cmd) { if (!cmd->argv[0]) BUG("command is empty"); @@@ -403,22 -403,16 +403,22 @@@ /* * If there are no '/' characters in the command then perform a path * lookup and use the resolved path as the command to exec. If there - * are no '/' characters or if the command wasn't found in the path, - * have exec attempt to invoke the command directly. + * are '/' characters, we have exec attempt to invoke the command + * directly. */ if (!strchr(out->argv[1], '/')) { char *program = locate_in_PATH(out->argv[1]); if (program) { free((char *)out->argv[1]); out->argv[1] = program; + } else { + argv_array_clear(out); + errno = ENOENT; + return -1; } } + + return 0; } static char **prep_childenv(const char *const *deltaenv) @@@ -725,12 -719,6 +725,12 @@@ fail_pipe struct child_err cerr; struct atfork_state as; + if (prepare_cmd(&argv, cmd) < 0) { + failed_errno = errno; + cmd->pid = -1; + goto end_of_spawn; + } + if (pipe(notify_pipe)) notify_pipe[0] = notify_pipe[1] = -1; @@@ -741,6 -729,7 +741,6 @@@ set_cloexec(null_fd); } - prepare_cmd(&argv, cmd); childenv = prep_childenv(cmd->env); atfork_prepare(&as); @@@ -868,8 -857,6 +868,8 @@@ argv_array_clear(&argv); free(childenv); } +end_of_spawn: + #else { int fhin = 0, fhout = 1, fherr = 2; @@@ -1226,7 -1213,7 +1226,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; } } @@@ -1259,6 -1246,15 +1259,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;