Skip to content

Commit 200a76b

Browse files
j6tgitster
authored andcommitted
Reimplement async procedures using pthreads
On Windows, async procedures have always been run in threads, and the implementation used Windows specific APIs. Rewrite the code to use pthreads. A new configuration option is introduced so that the threaded implementation can also be used on POSIX systems. Since this option is intended only as playground on POSIX, but is mandatory on Windows, the option is not documented. One detail is that on POSIX it is necessary to set FD_CLOEXEC on the pipe handles. On Windows, this is not needed because pipe handles are not inherited to child processes, and the new calls to set_cloexec() are effectively no-ops. Signed-off-by: Johannes Sixt <j6t@kdbg.org> Signed-off-by: Junio C Hamano <gitster@pobox.com>
1 parent 912b263 commit 200a76b

3 files changed

Lines changed: 34 additions & 20 deletions

File tree

Makefile

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -979,6 +979,7 @@ ifeq ($(uname_S),Windows)
979979
NO_CURL = YesPlease
980980
NO_PYTHON = YesPlease
981981
BLK_SHA1 = YesPlease
982+
ASYNC_AS_THREAD = YesPlease
982983

983984
CC = compat/vcbuild/scripts/clink.pl
984985
AR = compat/vcbuild/scripts/lib.pl
@@ -1030,6 +1031,7 @@ ifneq (,$(findstring MINGW,$(uname_S)))
10301031
NO_REGEX = YesPlease
10311032
NO_PYTHON = YesPlease
10321033
BLK_SHA1 = YesPlease
1034+
ASYNC_AS_THREAD = YesPlease
10331035
COMPAT_CFLAGS += -D__USE_MINGW_ACCESS -DNOGDI -Icompat -Icompat/fnmatch -Icompat/win32
10341036
COMPAT_CFLAGS += -DSTRIP_EXTENSION=\".exe\"
10351037
COMPAT_OBJS += compat/mingw.o compat/fnmatch/fnmatch.o compat/winansi.o \
@@ -1342,6 +1344,9 @@ ifdef NO_PTHREADS
13421344
else
13431345
EXTLIBS += $(PTHREAD_LIBS)
13441346
LIB_OBJS += thread-utils.o
1347+
ifdef ASYNC_AS_THREAD
1348+
BASIC_CFLAGS += -DASYNC_AS_THREAD
1349+
endif
13451350
endif
13461351

13471352
ifdef DIR_HAS_BSD_GROUP_SEMANTICS

run-command.c

Lines changed: 23 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -82,14 +82,14 @@ static NORETURN void die_child(const char *err, va_list params)
8282
write(child_err, "\n", 1);
8383
exit(128);
8484
}
85+
#endif
8586

8687
static inline void set_cloexec(int fd)
8788
{
8889
int flags = fcntl(fd, F_GETFD);
8990
if (flags >= 0)
9091
fcntl(fd, F_SETFD, flags | FD_CLOEXEC);
9192
}
92-
#endif
9393

9494
static int wait_or_whine(pid_t pid, const char *argv0, int silent_exec_failure)
9595
{
@@ -447,11 +447,12 @@ int run_command_v_opt_cd_env(const char **argv, int opt, const char *dir, const
447447
return run_command(&cmd);
448448
}
449449

450-
#ifdef WIN32
451-
static unsigned __stdcall run_thread(void *data)
450+
#ifdef ASYNC_AS_THREAD
451+
static void *run_thread(void *data)
452452
{
453453
struct async *async = data;
454-
return async->proc(async->proc_in, async->proc_out, async->data);
454+
intptr_t ret = async->proc(async->proc_in, async->proc_out, async->data);
455+
return (void *)ret;
455456
}
456457
#endif
457458

@@ -497,7 +498,7 @@ int start_async(struct async *async)
497498
else
498499
proc_out = -1;
499500

500-
#ifndef WIN32
501+
#ifndef ASYNC_AS_THREAD
501502
/* Flush stdio before fork() to avoid cloning buffers */
502503
fflush(NULL);
503504

@@ -524,12 +525,18 @@ int start_async(struct async *async)
524525
else if (async->out)
525526
close(async->out);
526527
#else
528+
if (proc_in >= 0)
529+
set_cloexec(proc_in);
530+
if (proc_out >= 0)
531+
set_cloexec(proc_out);
527532
async->proc_in = proc_in;
528533
async->proc_out = proc_out;
529-
async->tid = (HANDLE) _beginthreadex(NULL, 0, run_thread, async, 0, NULL);
530-
if (!async->tid) {
531-
error("cannot create thread: %s", strerror(errno));
532-
goto error;
534+
{
535+
int err = pthread_create(&async->tid, NULL, run_thread, async);
536+
if (err) {
537+
error("cannot create thread: %s", strerror(err));
538+
goto error;
539+
}
533540
}
534541
#endif
535542
return 0;
@@ -549,17 +556,15 @@ int start_async(struct async *async)
549556

550557
int finish_async(struct async *async)
551558
{
552-
#ifndef WIN32
553-
int ret = wait_or_whine(async->pid, "child process", 0);
559+
#ifndef ASYNC_AS_THREAD
560+
return wait_or_whine(async->pid, "child process", 0);
554561
#else
555-
DWORD ret = 0;
556-
if (WaitForSingleObject(async->tid, INFINITE) != WAIT_OBJECT_0)
557-
ret = error("waiting for thread failed: %lu", GetLastError());
558-
else if (!GetExitCodeThread(async->tid, &ret))
559-
ret = error("cannot get thread exit code: %lu", GetLastError());
560-
CloseHandle(async->tid);
562+
void *ret = (void *)(intptr_t)(-1);
563+
564+
if (pthread_join(async->tid, &ret))
565+
error("pthread_join failed");
566+
return (int)(intptr_t)ret;
561567
#endif
562-
return ret;
563568
}
564569

565570
int run_hook(const char *index_file, const char *name, ...)

run-command.h

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,10 @@
11
#ifndef RUN_COMMAND_H
22
#define RUN_COMMAND_H
33

4+
#ifdef ASYNC_AS_THREAD
5+
#include <pthread.h>
6+
#endif
7+
48
struct child_process {
59
const char **argv;
610
pid_t pid;
@@ -74,10 +78,10 @@ struct async {
7478
void *data;
7579
int in; /* caller writes here and closes it */
7680
int out; /* caller reads from here and closes it */
77-
#ifndef WIN32
81+
#ifndef ASYNC_AS_THREAD
7882
pid_t pid;
7983
#else
80-
HANDLE tid;
84+
pthread_t tid;
8185
int proc_in;
8286
int proc_out;
8387
#endif

0 commit comments

Comments
 (0)