Merge branch 'nd/pthreads'
authorJunio C Hamano <gitster@pobox.com>
Sun, 18 Nov 2018 09:23:52 +0000 (18:23 +0900)
committerJunio C Hamano <gitster@pobox.com>
Sun, 18 Nov 2018 09:23:52 +0000 (18:23 +0900)
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

1  2 
Makefile
builtin/grep.c
builtin/pack-objects.c
pack-objects.h
preload-index.c
read-cache.c
run-command.c

diff --combined 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
@@@ -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;
  
  
        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)
  {
                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);
  
         * 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"));
                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
@@@ -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
@@@ -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
@@@ -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 <pthread.h>
+ #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;
  
        for (i = 0; i < threads; i++) {
                struct thread_data *p = data+i;
+               int err;
                p->index = index;
                if (pathspec)
                        copy_pathspec(&p->pathspec, pathspec);
                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;
  
        trace_performance_leave("preload index");
  }
- #endif
  
  int read_index_preload(struct index_state *index,
                       const struct pathspec *pathspec,
diff --combined 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
                                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)
        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;
  
        src_offset = sizeof(*hdr);
  
- #ifndef NO_PTHREADS
        nr_threads = git_config_get_index_threads();
  
        /* TODO: does creating more threads than cores help? */
                        nr_threads = cpus;
        }
  
+       if (!HAVE_THREADS)
+               nr_threads = 1;
        if (nr_threads > 1) {
                extension_offset = read_eoie_extension(mmap, mmap_size);
                if (extension_offset) {
        } 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;
  
                        ieot_entries = DIV_ROUND_UP(entries, ieot_blocks);
                }
        }
- #endif
  
        offset = lseek(newfd, 0, SEEK_CUR);
        if (offset < 0) {
         * strip_extensions parameter as we need it when loading the shared
         * index.
         */
- #ifndef NO_PTHREADS
        if (ieot) {
                struct strbuf sb = STRBUF_INIT;
  
                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
@@@ -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");
        /*
         * 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;
  
                set_cloexec(null_fd);
        }
  
 -      prepare_cmd(&argv, cmd);
        childenv = prep_childenv(cmd->env);
        atfork_prepare(&as);
  
        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;