Merge branch 'sb/submodule-parallel-fetch'
authorJunio C Hamano <gitster@pobox.com>
Tue, 12 Jan 2016 23:16:54 +0000 (15:16 -0800)
committerJunio C Hamano <gitster@pobox.com>
Tue, 12 Jan 2016 23:16:54 +0000 (15:16 -0800)
Add a framework to spawn a group of processes in parallel, and use
it to run "git fetch --recurse-submodules" in parallel.

Rerolled and this seems to be a lot cleaner. The merge of the
earlier one to 'next' has been reverted.

* sb/submodule-parallel-fetch:
submodules: allow parallel fetching, add tests and documentation
fetch_populated_submodules: use new parallel job processing
run-command: add an asynchronous parallel child processor
sigchain: add command to pop all common signals
strbuf: add strbuf_read_once to read without blocking
xread: poll on non blocking fds
submodule.c: write "Fetching submodule <foo>" to stderr

1  2 
submodule.h
wrapper.c
diff --combined submodule.h
index ddff512109cbf24f0ead87676f1fc8e6cb92f897,cbc000304eacbe318e1950572a19b164a897ce41..e06eaa5ebb30e825fd0721c76e7d194b0b854706
@@@ -5,7 -5,6 +5,7 @@@ struct diff_options
  struct argv_array;
  
  enum {
 +      RECURSE_SUBMODULES_CHECK = -4,
        RECURSE_SUBMODULES_ERROR = -3,
        RECURSE_SUBMODULES_NONE = -2,
        RECURSE_SUBMODULES_ON_DEMAND = -1,
@@@ -32,7 -31,7 +32,7 @@@ void set_config_fetch_recurse_submodule
  void check_for_new_submodule_commits(unsigned char new_sha1[20]);
  int fetch_populated_submodules(const struct argv_array *options,
                               const char *prefix, int command_line_option,
-                              int quiet);
+                              int quiet, int max_parallel_jobs);
  unsigned is_submodule_modified(const char *path, int ignore_untracked);
  int submodule_uses_gitfile(const char *path);
  int ok_to_remove_submodule(const char *path);
diff --combined wrapper.c
index c95e2906b850749cbeb109050359b671979969f2,1770efac8e02836c5596527be4dc30413968a858..b43d437630c9245a6a48a0940df1607e21357362
+++ b/wrapper.c
@@@ -236,8 -236,24 +236,24 @@@ ssize_t xread(int fd, void *buf, size_
            len = MAX_IO_SIZE;
        while (1) {
                nr = read(fd, buf, len);
-               if ((nr < 0) && (errno == EAGAIN || errno == EINTR))
-                       continue;
+               if (nr < 0) {
+                       if (errno == EINTR)
+                               continue;
+                       if (errno == EAGAIN || errno == EWOULDBLOCK) {
+                               struct pollfd pfd;
+                               pfd.events = POLLIN;
+                               pfd.fd = fd;
+                               /*
+                                * it is OK if this poll() failed; we
+                                * want to leave this infinite loop
+                                * only when read() returns with
+                                * success, or an expected failure,
+                                * which would be checked by the next
+                                * call to read(2).
+                                */
+                               poll(&pfd, 1, -1);
+                       }
+               }
                return nr;
        }
  }
@@@ -601,6 -617,18 +617,6 @@@ int access_or_die(const char *path, in
        return ret;
  }
  
 -struct passwd *xgetpwuid_self(void)
 -{
 -      struct passwd *pw;
 -
 -      errno = 0;
 -      pw = getpwuid(getuid());
 -      if (!pw)
 -              die(_("unable to look up current user in the passwd file: %s"),
 -                  errno ? strerror(errno) : _("no such user"));
 -      return pw;
 -}
 -
  char *xgetcwd(void)
  {
        struct strbuf sb = STRBUF_INIT;