Handle atexit list internaly for unthreaded builds

Wrap atexit()s calls on unthreaded builds to handle callback list internally. This is needed because on unthreaded builds, asyncs inherits parent's atexit() list, that gets run as soon as the async exit()s (and again at the end of async's parent process). That led to remove temporary files too early. Also remove a by-atexit-callback guard against this kind of issue in clone.c, as this patch makes it redundant. Fixes test 5537 (temporary shallow file vanished before unpack-objects could open it) BTW remove an unused variable in shallow.c. Helped-by: Duy Nguyen <pclouds@gmail.com> Helped-by: Andreas Schwab <schwab@linux-m68k.org> Helped-by: Junio C Hamano <gitster@pobox.com> Signed-off-by: Etienne Buira <etienne.buira@gmail.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>

Etienne Buira committed Oct 18, 2014 at 14:31 UTC 0f4b6db3baeff8de53769b38f439408abd5a42f7
4 files changed +47 -10
builtin/clone.c
-5
@@ -390,7 +390,6 @@ static void clone_local(const char *src_repo, const char *dest_repo)
390
391 static const char *junk_work_tree;
392 static const char *junk_git_dir;
393 -static pid_t junk_pid;
393 static enum {
394 JUNK_LEAVE_NONE,
395 JUNK_LEAVE_REPO,
@@ -417,8 +416,6 @@ static void remove_junk(void)
416 break;
417 }
418
420 - if (getpid() != junk_pid)
421 - return;
419 if (junk_git_dir) {
420 strbuf_addstr(&sb, junk_git_dir);
421 remove_dir_recursively(&sb, 0);
@@ -759,8 +756,6 @@ int cmd_clone(int argc, const char **argv, const char *prefix)
756 struct refspec *refspec;
757 const char *fetch_pattern;
758
762 - junk_pid = getpid();
763 -
759 packet_trace_identity("clone");
760 argc = parse_options(argc, argv, prefix, builtin_clone_options,
761 builtin_clone_usage, 0);
git-compat-util.h
+5
@@ -594,6 +594,11 @@ int inet_pton(int af, const char *src, void *dst);
594 const char *inet_ntop(int af, const void *src, char *dst, size_t size);
595 #endif
596
597 +#ifdef NO_PTHREADS
598 +#define atexit git_atexit
599 +extern int git_atexit(void (*handler)(void));
600 +#endif
601 +
602 extern void release_pack_memory(size_t);
603
604 typedef void (*try_to_free_t)(size_t);
run-command.c
+40
@@ -620,6 +620,45 @@ static int async_die_is_recursing(void)
620 return ret != NULL;
621 }
622
623 +#else
624 +
625 +static struct {
626 + void (**handlers)(void);
627 + size_t nr;
628 + size_t alloc;
629 +} git_atexit_hdlrs;
630 +
631 +static int git_atexit_installed;
632 +
633 +static void git_atexit_dispatch()
634 +{
635 + size_t i;
636 +
637 + for (i=git_atexit_hdlrs.nr ; i ; i--)
638 + git_atexit_hdlrs.handlers[i-1]();
639 +}
640 +
641 +static void git_atexit_clear()
642 +{
643 + free(git_atexit_hdlrs.handlers);
644 + memset(&git_atexit_hdlrs, 0, sizeof(git_atexit_hdlrs));
645 + git_atexit_installed = 0;
646 +}
647 +
648 +#undef atexit
649 +int git_atexit(void (*handler)(void))
650 +{
651 + ALLOC_GROW(git_atexit_hdlrs.handlers, git_atexit_hdlrs.nr + 1, git_atexit_hdlrs.alloc);
652 + git_atexit_hdlrs.handlers[git_atexit_hdlrs.nr++] = handler;
653 + if (!git_atexit_installed) {
654 + if (atexit(&git_atexit_dispatch))
655 + return -1;
656 + git_atexit_installed = 1;
657 + }
658 + return 0;
659 +}
660 +#define atexit git_atexit
661 +
662 #endif
663
664 int start_async(struct async *async)
@@ -678,6 +717,7 @@ int start_async(struct async *async)
717 close(fdin[1]);
718 if (need_out)
719 close(fdout[0]);
720 + git_atexit_clear();
721 exit(!!async->proc(proc_in, proc_out, async->data));
722 }
723
shallow.c
+2 -5
@@ -226,7 +226,6 @@ static void remove_temporary_shallow_on_signal(int signo)
226
227 const char *setup_temporary_shallow(const struct sha1_array *extra)
228 {
229 - static int installed_handler;
229 struct strbuf sb = STRBUF_INIT;
230 int fd;
231
@@ -237,10 +236,8 @@ const char *setup_temporary_shallow(const struct sha1_array *extra)
236 strbuf_addstr(&temporary_shallow, git_path("shallow_XXXXXX"));
237 fd = xmkstemp(temporary_shallow.buf);
238
240 - if (!installed_handler) {
241 - atexit(remove_temporary_shallow);
242 - sigchain_push_common(remove_temporary_shallow_on_signal);
243 - }
239 + atexit(remove_temporary_shallow);
240 + sigchain_push_common(remove_temporary_shallow_on_signal);
241
242 if (write_in_full(fd, sb.buf, sb.len) != sb.len)
243 die_errno("failed to write to %s",