Skip to content

Commit 2b08101

Browse files
peffgitster
authored andcommitted
Makefile: add OPEN_RETURNS_EINTR knob
On some platforms, open() reportedly returns EINTR when opening regular files and we receive a signal (usually SIGALRM from our progress meter). This shouldn't happen, as open() should be a restartable syscall, and we specify SA_RESTART when setting up the alarm handler. So it may actually be a kernel or libc bug for this to happen. But it has been reported on at least one version of Linux (on a network filesystem): https://lore.kernel.org/git/[email protected]/ as well as on macOS starting with Big Sur even on a regular filesystem. We can work around it by retrying open() calls that get EINTR, just as we do for read(), etc. Since we don't ever _want_ to interrupt an open() call, we can get away with just redefining open, rather than insisting all callsites use xopen(). We actually do have an xopen() wrapper already (and it even does this retry, though there's no indication of it being an observed problem back then; it seems simply to have been lifted from xread(), etc). But it is used hardly anywhere, and isn't suitable for general use because it will die() on error. In theory we could combine the two, but it's awkward to do so because of the variable-args interface of open(). This patch adds a Makefile knob for enabling the workaround. It's not enabled by default for any platforms in config.mak.uname yet, as we don't have enough data to decide how common this is (I have not been able to reproduce on either Linux or Big Sur myself). It may be worth enabling preemptively anyway, since the cost is pretty low (if we don't see an EINTR, it's just an extra conditional). However, note that we must not enable this on Windows. It doesn't do anything there, and the macro overrides the existing mingw_open() redirection. I've added a preemptive #undef here in the mingw header (which is processed first) to just quietly disable it (we could also make it an #error, but there is little point in being so aggressive). Reported-by: Aleksey Kliger <[email protected]> Signed-off-by: Jeff King <[email protected]> Signed-off-by: Junio C Hamano <[email protected]>
1 parent 59ec224 commit 2b08101

File tree

4 files changed

+39
-0
lines changed

4 files changed

+39
-0
lines changed

Makefile

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,9 @@ all::
2222
# when attempting to read from an fopen'ed directory (or even to fopen
2323
# it at all).
2424
#
25+
# Define OPEN_RETURNS_EINTR if your open() system call may return EINTR
26+
# when a signal is received (as opposed to restarting).
27+
#
2528
# Define NO_OPENSSL environment variable if you do not have OpenSSL.
2629
#
2730
# Define USE_LIBPCRE if you have and want to use libpcre. Various
@@ -1551,6 +1554,10 @@ ifdef FREAD_READS_DIRECTORIES
15511554
COMPAT_CFLAGS += -DFREAD_READS_DIRECTORIES
15521555
COMPAT_OBJS += compat/fopen.o
15531556
endif
1557+
ifdef OPEN_RETURNS_EINTR
1558+
COMPAT_CFLAGS += -DOPEN_RETURNS_EINTR
1559+
COMPAT_OBJS += compat/open.o
1560+
endif
15541561
ifdef NO_SYMLINK_HEAD
15551562
BASIC_CFLAGS += -DNO_SYMLINK_HEAD
15561563
endif

compat/mingw.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -227,6 +227,7 @@ int mingw_rmdir(const char *path);
227227

228228
int mingw_open (const char *filename, int oflags, ...);
229229
#define open mingw_open
230+
#undef OPEN_RETURNS_EINTR
230231

231232
int mingw_fgetc(FILE *stream);
232233
#define fgetc mingw_fgetc

compat/open.c

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
#include "git-compat-util.h"
2+
3+
#undef open
4+
int git_open_with_retry(const char *path, int flags, ...)
5+
{
6+
mode_t mode = 0;
7+
int ret;
8+
9+
/*
10+
* Also O_TMPFILE would take a mode, but it isn't defined everywhere.
11+
* And anyway, we don't use it in our code base.
12+
*/
13+
if (flags & O_CREAT) {
14+
va_list ap;
15+
va_start(ap, flags);
16+
mode = va_arg(ap, int);
17+
va_end(ap);
18+
}
19+
20+
do {
21+
ret = open(path, flags, mode);
22+
} while (ret < 0 && errno == EINTR);
23+
24+
return ret;
25+
}

git-compat-util.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -788,6 +788,12 @@ int git_vsnprintf(char *str, size_t maxsize,
788788
const char *format, va_list ap);
789789
#endif
790790

791+
#ifdef OPEN_RETURNS_EINTR
792+
#undef open
793+
#define open git_open_with_retry
794+
int git_open_with_retry(const char *path, int flag, ...);
795+
#endif
796+
791797
#ifdef __GLIBC_PREREQ
792798
#if __GLIBC_PREREQ(2, 1)
793799
#define HAVE_STRCHRNUL

0 commit comments

Comments
 (0)