@matheusbsbs / matheus-bagliano / commits / 0ea1c89ba6
Fork 0

Dying in an async procedure should only exit the thread, not the process.

Async procedures are intended as helpers that perform a very restricted task, and the caller usually has to manage them in a larger context. Conceptually, the async procedure is not concerned with the "bigger picture" in whose context it is run. When it dies, it is not supposed to destroy this "bigger picture", but rather only its own limit view of the world. On POSIX, the async procedure is run in its own process, and exiting this process naturally had only these limited effects. On Windows (or when ASYNC_AS_THREAD is set), calling die() exited the whole process, destroying the caller (the "big picture") as well. This fixes it to exit only the thread. Without ASYNC_AS_THREAD, one particular effect of exiting the async procedure process is that it automatically closes file descriptors, most notably the writable end of the pipe that the async procedure writes to. The async API already requires that the async procedure closes the pipe ends when it exits normally. But for calls to die() no requirements are imposed. In the non-threaded case the pipe ends are closed implicitly by the exiting process, but in the threaded case, the die routine must take care of closing them. Now t5530-upload-pack-error.sh passes on Windows. 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 0ea1c89ba616397ef7e5f6f601ef7a24d2c27b8e
1 file changed +34
run-command.c
+34
@@ -448,12 +448,35 @@ int run_command_v_opt_cd_env(const char **argv, int opt, const char *dir, const
448 }
449
450 #ifdef ASYNC_AS_THREAD
451 +static pthread_t main_thread;
452 +static int main_thread_set;
453 +static pthread_key_t async_key;
454 +
455 static void *run_thread(void *data)
456 {
457 struct async *async = data;
458 +
459 + pthread_setspecific(async_key, async);
460 +
461 intptr_t ret = async->proc(async->proc_in, async->proc_out, async->data);
462 return (void *)ret;
463 }
464 +
465 +static NORETURN void die_async(const char *err, va_list params)
466 +{
467 + vreportf("fatal: ", err, params);
468 +
469 + if (!pthread_equal(main_thread, pthread_self())) {
470 + struct async *async = pthread_getspecific(async_key);
471 + if (async->proc_in >= 0)
472 + close(async->proc_in);
473 + if (async->proc_out >= 0)
474 + close(async->proc_out);
475 + pthread_exit((void *)128);
476 + }
477 +
478 + exit(128);
479 +}
480 #endif
481
482 int start_async(struct async *async)
@@ -525,6 +548,17 @@ int start_async(struct async *async)
548 else if (async->out)
549 close(async->out);
550 #else
551 + if (!main_thread_set) {
552 + /*
553 + * We assume that the first time that start_async is called
554 + * it is from the main thread.
555 + */
556 + main_thread_set = 1;
557 + main_thread = pthread_self();
558 + pthread_key_create(&async_key, NULL);
559 + set_die_routine(die_async);
560 + }
561 +
562 if (proc_in >= 0)
563 set_cloexec(proc_in);
564 if (proc_out >= 0)