Merge branch 'sb/submodule-parallel-fetch' into maint
authorJunio C Hamano <gitster@pobox.com>
Thu, 28 Jul 2016 18:26:02 +0000 (11:26 -0700)
committerJunio C Hamano <gitster@pobox.com>
Thu, 28 Jul 2016 18:26:02 +0000 (11:26 -0700)
Fix recently introduced codepaths that are involved in parallel
submodule operations, which gave up on reading too early, and
could have wasted CPU while attempting to write under a corner
case condition.

* sb/submodule-parallel-fetch:
hoist out handle_nonblock function for xread and xwrite
xwrite: poll on non-blocking FDs
xread: retry after poll on EAGAIN/EWOULDBLOCK

1  2 
wrapper.c
diff --combined wrapper.c
index 5dc4e15aa9bf73bb2ce0a7af1837e092e0cab585,a774ab7d80737d0caa6a753fa51c220816e817be..26db215f0c2f38e426d76e41fb16b7cb8deadeb3
+++ b/wrapper.c
@@@ -152,9 -152,6 +152,9 @@@ void *xcalloc(size_t nmemb, size_t size
  {
        void *ret;
  
 +      if (unsigned_mult_overflows(nmemb, size))
 +              die("data too large to fit into virtual memory space");
 +
        memory_limit_check(size * nmemb, 0);
        ret = calloc(nmemb, size);
        if (!ret && (!nmemb || !size))
@@@ -227,6 -224,24 +227,24 @@@ int xopen(const char *path, int oflag, 
        }
  }
  
+ static int handle_nonblock(int fd, short poll_events, int err)
+ {
+       struct pollfd pfd;
+       if (err != EAGAIN && err != EWOULDBLOCK)
+               return 0;
+       pfd.fd = fd;
+       pfd.events = poll_events;
+       /*
+        * no need to check for errors, here;
+        * a subsequent read/write will detect unrecoverable errors
+        */
+       poll(&pfd, 1, -1);
+       return 1;
+ }
  /*
   * xread() is the same a read(), but it automatically restarts read()
   * operations with a recoverable error (EAGAIN and EINTR). xread()
@@@ -242,20 -257,8 +260,8 @@@ ssize_t xread(int fd, void *buf, size_
                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);
-                       }
+                       if (handle_nonblock(fd, POLLIN, errno))
+                               continue;
                }
                return nr;
        }
@@@ -273,8 -276,13 +279,13 @@@ ssize_t xwrite(int fd, const void *buf
            len = MAX_IO_SIZE;
        while (1) {
                nr = write(fd, buf, len);
-               if ((nr < 0) && (errno == EAGAIN || errno == EINTR))
-                       continue;
+               if (nr < 0) {
+                       if (errno == EINTR)
+                               continue;
+                       if (handle_nonblock(fd, POLLOUT, errno))
+                               continue;
+               }
                return nr;
        }
  }
@@@ -394,19 -402,6 +405,19 @@@ FILE *xfdopen(int fd, const char *mode
        return stream;
  }
  
 +FILE *fopen_for_writing(const char *path)
 +{
 +      FILE *ret = fopen(path, "w");
 +
 +      if (!ret && errno == EPERM) {
 +              if (!unlink(path))
 +                      ret = fopen(path, "w");
 +              else
 +                      errno = EPERM;
 +      }
 +      return ret;
 +}
 +
  int xmkstemp(char *template)
  {
        int fd;
@@@ -446,6 -441,23 +457,6 @@@ int git_mkstemp(char *path, size_t len
        return mkstemp(path);
  }
  
 -/* git_mkstemps() - create tmp file with suffix honoring TMPDIR variable. */
 -int git_mkstemps(char *path, size_t len, const char *template, int suffix_len)
 -{
 -      const char *tmp;
 -      size_t n;
 -
 -      tmp = getenv("TMPDIR");
 -      if (!tmp)
 -              tmp = "/tmp";
 -      n = snprintf(path, len, "%s/%s", tmp, template);
 -      if (len <= n) {
 -              errno = ENAMETOOLONG;
 -              return -1;
 -      }
 -      return mkstemps(path, suffix_len);
 -}
 -
  /* Adapted from libiberty's mkstemp.c. */
  
  #undef TMP_MAX
@@@ -555,7 -567,7 +566,7 @@@ static int warn_if_unremovable(const ch
        if (!rc || errno == ENOENT)
                return 0;
        err = errno;
 -      warning("unable to %s %s: %s", op, file, strerror(errno));
 +      warning_errno("unable to %s %s", op, file);
        errno = err;
        return rc;
  }
@@@ -591,7 -603,7 +602,7 @@@ int remove_or_warn(unsigned int mode, c
  
  void warn_on_inaccessible(const char *path)
  {
 -      warning(_("unable to access '%s': %s"), path, strerror(errno));
 +      warning_errno(_("unable to access '%s'"), path);
  }
  
  static int access_error_is_ok(int err, unsigned flag)
@@@ -616,6 -628,18 +627,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;