Don't start index-helper when it is already running for a repository. Keep the index-helper pid file's mtime up-to-date. Before starting index-helper, check that (a) the pid file's mtime is recent and (b) there is some process with that pid. Of course, it's possible that the mtime is recent but the index-helper has died anyway (and some other process has taken its pid), but that's pretty unlikely. Provide index-helper --kill (to kill the running index-helper) and index-helper --ignore-existing (to start up a new index-helper even if we believe that there's one already running). Add a test for index-helper's pid-file writing and for --kill. Signed-off-by: David Turner <dturner@xxxxxxxxxxxxxxxx> --- index-helper.c | 95 +++++++++++++++++++++++++++++++++++++++++++++---- t/t7900-index-helper.sh | 23 ++++++++++++ 2 files changed, 111 insertions(+), 7 deletions(-) create mode 100755 t/t7900-index-helper.sh diff --git a/index-helper.c b/index-helper.c index dc03e1e..a75da60 100644 --- a/index-helper.c +++ b/index-helper.c @@ -152,6 +152,17 @@ static void refresh(int sig) #ifdef HAVE_SHM +static void touch_pid_file(void) +{ + /* + * If we fail to update the times on index-helper.pid, we've + * probably had the repo deleted out from under us or otherwise + * lost access; might as well give up. + */ + if (utimes(git_path("index-helper.pid"), NULL)) + exit(0); +} + #ifdef USE_WATCHMAN static void share_watchman(struct index_state *istate, struct shm *is, pid_t pid) @@ -211,9 +222,10 @@ static void prepare_index(int sig, siginfo_t *si, void *context) #endif -static void loop(const char *pid_file, int idle_in_seconds) +static void loop(const char *pid_file, int idle_in_minutes) { struct sigaction sa; + int timeout_count = 0; sigchain_pop(SIGHUP); /* pushed by sigchain_push_common */ sigchain_push(SIGHUP, refresh); @@ -225,19 +237,25 @@ static void loop(const char *pid_file, int idle_in_seconds) sigaction(SIGUSR1, &sa, NULL); refresh(0); - while (sleep(idle_in_seconds)) - ; /* do nothing, all is handled by signal handlers already */ + while (timeout_count < idle_in_minutes) { + if (sleep(60) == EINTR) + timeout_count = 0; + else + timeout_count ++; + touch_pid_file(); + } } #elif defined(GIT_WINDOWS_NATIVE) -static void loop(const char *pid_file, int idle_in_seconds) +static void loop(const char *pid_file, int idle_in_minutes) { HWND hwnd; UINT_PTR timer = 0; MSG msg; HINSTANCE hinst = GetModuleHandle(NULL); WNDCLASS wc; + int timeout_count = 0; /* * Emulate UNIX signals by sending WM_USER+x to a @@ -258,11 +276,18 @@ static void loop(const char *pid_file, int idle_in_seconds) refresh(0); while (1) { - timer = SetTimer(hwnd, timer, idle_in_seconds * 1000, NULL); + timer = SetTimer(hwnd, timer, 60 * 1000, NULL); if (!timer) die(_("no timer!")); - if (!GetMessage(&msg, hwnd, 0, 0) || msg.message == WM_TIMER) + if (!GetMessage(&msg, hwnd, 0, 0)) break; + if (msg.message == WM_TIMER) { + timeout_count ++; + if (timeout_count == idle_in_minutes) + break; + } + timeout_count = 0; + touch_pid_file(); switch (msg.message) { case WM_USER: refresh(0); @@ -288,6 +313,44 @@ static const char * const usage_text[] = { NULL }; +static int already_running(void) +{ + char contents[20] = {0}; + char *end; + int fd, dead, i = 0; + time_t now; + pid_t pid; + struct stat st; + + fd = open(git_path("index-helper.pid"), O_RDONLY); + if (fd < 0) + return 0; + + if (fstat(fd, &st) < 0) + return 0; + + now = time(&now); + + /* + * We touch the pid file every minute, so if a pid file hasn't + * been updated in two minutes, it's out-of-date. + */ + if (st.st_mtime + 120 < now) + return 0; + + read_in_full(fd, &contents, sizeof(contents)); + + while (!isdigit(contents[i]) && contents[i]) + i++; + pid = strtoll(contents + i, &end, 10); + if (contents == end) + return 0; + dead = kill(pid, 0); + if (!dead) + return pid; + return 0; +} + static const char *write_pid(void) { static struct strbuf sb = STRBUF_INIT; @@ -314,6 +377,8 @@ int main(int argc, char **argv) { const char *prefix; int idle_in_minutes = 10, detach = 0; + int ignore_existing = 0; + int kill_existing = 0; const char *pid_file; struct option options[] = { OPT_INTEGER(0, "exit-after", &idle_in_minutes, @@ -321,6 +386,8 @@ int main(int argc, char **argv) OPT_BOOL(0, "strict", &to_verify, "verify shared memory after creating"), OPT_BOOL(0, "detach", &detach, "detach the process"), + OPT_BOOL(0, "ignore-existing", &ignore_existing, "run even if another index-helper seems to be running for this repo"), + OPT_BOOL(0, "kill", &kill_existing, "kill any running index-helper for this repo"), OPT_END() }; @@ -335,6 +402,20 @@ int main(int argc, char **argv) options, usage_text, 0)) die(_("too many arguments")); + if (ignore_existing && kill_existing) + die(_("--ignore-existing and --kill don't make sense together")); + + if (!ignore_existing) { + pid_t pid = already_running(); + if (pid) { + if (kill_existing) + exit(kill(pid, SIGKILL)); + else if (!detach) + warning("index-helper is apparently already running with pid %d", (int)pid); + exit(0); + } + } + write_pid(); atexit(cleanup); @@ -351,6 +432,6 @@ int main(int argc, char **argv) if (!idle_in_minutes) idle_in_minutes = 0xffffffff / 60; - loop(pid_file, idle_in_minutes * 60); + loop(pid_file, idle_in_minutes); return 0; } diff --git a/t/t7900-index-helper.sh b/t/t7900-index-helper.sh new file mode 100755 index 0000000..6708180 --- /dev/null +++ b/t/t7900-index-helper.sh @@ -0,0 +1,23 @@ +#!/bin/sh +# +# Copyright (c) 2016, Twitter, Inc +# + +test_description='git-index-helper + +Testing git index-helper +' + +. ./test-lib.sh + +test_expect_success 'index-helper creates usable pid file and can be killed' ' + test_path_is_missing .git/index-helper.pid && + git index-helper --detach && + test_path_is_file .git/index-helper.pid && + pid=$(sed s/[^0-9]//g .git/index-helper.pid) && + kill -0 $pid && + git index-helper --kill && + ! kill -0 $pid +' + +test_done -- 2.4.2.767.g62658d5-twtrsrc -- To unsubscribe from this list: send the line "unsubscribe git" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html