@matheusbsbs / matheus-bagliano / commits / 200a76b74d
Fork 0

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>

Johannes Sixt committed Mar 6, 2010 at 16:40 UTC 200a76b74db5c2c75bcf73773cb85c5603ec038e
3 files changed +34 -20
Makefile
+5
@@ -979,6 +979,7 @@ ifeq ($(uname_S),Windows)
979 NO_CURL = YesPlease
980 NO_PYTHON = YesPlease
981 BLK_SHA1 = YesPlease
982 + ASYNC_AS_THREAD = YesPlease
983
984 CC = compat/vcbuild/scripts/clink.pl
985 AR = compat/vcbuild/scripts/lib.pl
@@ -1030,6 +1031,7 @@ ifneq (,$(findstring MINGW,$(uname_S)))
1031 NO_REGEX = YesPlease
1032 NO_PYTHON = YesPlease
1033 BLK_SHA1 = YesPlease
1034 + ASYNC_AS_THREAD = YesPlease
1035 COMPAT_CFLAGS += -D__USE_MINGW_ACCESS -DNOGDI -Icompat -Icompat/fnmatch -Icompat/win32
1036 COMPAT_CFLAGS += -DSTRIP_EXTENSION=\".exe\"
1037 COMPAT_OBJS += compat/mingw.o compat/fnmatch/fnmatch.o compat/winansi.o \
@@ -1342,6 +1344,9 @@ ifdef NO_PTHREADS
1344 else
1345 EXTLIBS += $(PTHREAD_LIBS)
1346 LIB_OBJS += thread-utils.o
1347 +ifdef ASYNC_AS_THREAD
1348 + BASIC_CFLAGS += -DASYNC_AS_THREAD
1349 +endif
1350 endif
1351
1352 ifdef DIR_HAS_BSD_GROUP_SEMANTICS
run-command.c
+23 -18
@@ -82,6 +82,7 @@ static NORETURN void die_child(const char *err, va_list params)
82 write(child_err, "\n", 1);
83 exit(128);
84 }
85 +#endif
86
87 static inline void set_cloexec(int fd)
88 {
@@ -89,7 +90,6 @@ static inline void set_cloexec(int fd)
90 if (flags >= 0)
91 fcntl(fd, F_SETFD, flags | FD_CLOEXEC);
92 }
92 -#endif
93
94 static int wait_or_whine(pid_t pid, const char *argv0, int silent_exec_failure)
95 {
@@ -447,11 +447,12 @@ int run_command_v_opt_cd_env(const char **argv, int opt, const char *dir, const
447 return run_command(&cmd);
448 }
449
450 -#ifdef WIN32
451 -static unsigned __stdcall run_thread(void *data)
450 +#ifdef ASYNC_AS_THREAD
451 +static void *run_thread(void *data)
452 {
453 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;
456 }
457 #endif
458
@@ -497,7 +498,7 @@ int start_async(struct async *async)
498 else
499 proc_out = -1;
500
500 -#ifndef WIN32
501 +#ifndef ASYNC_AS_THREAD
502 /* Flush stdio before fork() to avoid cloning buffers */
503 fflush(NULL);
504
@@ -524,12 +525,18 @@ int start_async(struct async *async)
525 else if (async->out)
526 close(async->out);
527 #else
528 + if (proc_in >= 0)
529 + set_cloexec(proc_in);
530 + if (proc_out >= 0)
531 + set_cloexec(proc_out);
532 async->proc_in = proc_in;
533 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 + }
540 }
541 #endif
542 return 0;
@@ -549,17 +556,15 @@ error:
556
557 int finish_async(struct async *async)
558 {
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);
561 #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;
567 #endif
562 - return ret;
568 }
569
570 int run_hook(const char *index_file, const char *name, ...)
run-command.h
+6 -2
@@ -1,6 +1,10 @@
1 #ifndef RUN_COMMAND_H
2 #define RUN_COMMAND_H
3
4 +#ifdef ASYNC_AS_THREAD
5 +#include <pthread.h>
6 +#endif
7 +
8 struct child_process {
9 const char **argv;
10 pid_t pid;
@@ -74,10 +78,10 @@ struct async {
78 void *data;
79 int in; /* caller writes here and closes it */
80 int out; /* caller reads from here and closes it */
77 -#ifndef WIN32
81 +#ifndef ASYNC_AS_THREAD
82 pid_t pid;
83 #else
80 - HANDLE tid;
84 + pthread_t tid;
85 int proc_in;
86 int proc_out;
87 #endif