@@ -1901,3 +1901,132 @@ void prepare_other_repo_env(struct strvec *env_array, const char *new_git_dir)
19011901 }
19021902 strvec_pushf (env_array , "%s=%s" , GIT_DIR_ENVIRONMENT , new_git_dir );
19031903}
1904+
1905+ enum start_bg_result start_bg_command (struct child_process * cmd ,
1906+ start_bg_wait_cb * wait_cb ,
1907+ void * cb_data ,
1908+ unsigned int timeout_sec )
1909+ {
1910+ enum start_bg_result sbgr = SBGR_ERROR ;
1911+ int ret ;
1912+ int wait_status ;
1913+ pid_t pid_seen ;
1914+ time_t time_limit ;
1915+
1916+ /*
1917+ * We do not allow clean-on-exit because the child process
1918+ * should persist in the background and possibly/probably
1919+ * after this process exits. So we don't want to kill the
1920+ * child during our atexit routine.
1921+ */
1922+ if (cmd -> clean_on_exit )
1923+ BUG ("start_bg_command() does not allow non-zero clean_on_exit" );
1924+
1925+ if (!cmd -> trace2_child_class )
1926+ cmd -> trace2_child_class = "background" ;
1927+
1928+ ret = start_command (cmd );
1929+ if (ret ) {
1930+ /*
1931+ * We assume that if `start_command()` fails, we
1932+ * either get a complete `trace2_child_start() /
1933+ * trace2_child_exit()` pair or it fails before the
1934+ * `trace2_child_start()` is emitted, so we do not
1935+ * need to worry about it here.
1936+ *
1937+ * We also assume that `start_command()` does not add
1938+ * us to the cleanup list. And that it calls
1939+ * calls `child_process_clear()`.
1940+ */
1941+ sbgr = SBGR_ERROR ;
1942+ goto done ;
1943+ }
1944+
1945+ time (& time_limit );
1946+ time_limit += timeout_sec ;
1947+
1948+ wait :
1949+ pid_seen = waitpid (cmd -> pid , & wait_status , WNOHANG );
1950+
1951+ if (!pid_seen ) {
1952+ /*
1953+ * The child is currently running. Ask the callback
1954+ * if the child is ready to do work or whether we
1955+ * should keep waiting for it to boot up.
1956+ */
1957+ ret = (* wait_cb )(cmd , cb_data );
1958+ if (!ret ) {
1959+ /*
1960+ * The child is running and "ready".
1961+ */
1962+ trace2_child_ready (cmd , "ready" );
1963+ sbgr = SBGR_READY ;
1964+ goto done ;
1965+ } else if (ret > 0 ) {
1966+ /*
1967+ * The callback said to give it more time to boot up
1968+ * (subject to our timeout limit).
1969+ */
1970+ time_t now ;
1971+
1972+ time (& now );
1973+ if (now < time_limit )
1974+ goto wait ;
1975+
1976+ /*
1977+ * Our timeout has expired. We don't try to
1978+ * kill the child, but rather let it continue
1979+ * (hopefully) trying to startup.
1980+ */
1981+ trace2_child_ready (cmd , "timeout" );
1982+ sbgr = SBGR_TIMEOUT ;
1983+ goto done ;
1984+ } else {
1985+ /*
1986+ * The cb gave up on this child. It is still running,
1987+ * but our cb got an error trying to probe it.
1988+ */
1989+ trace2_child_ready (cmd , "error" );
1990+ sbgr = SBGR_CB_ERROR ;
1991+ goto done ;
1992+ }
1993+ }
1994+
1995+ else if (pid_seen == cmd -> pid ) {
1996+ int child_code = -1 ;
1997+
1998+ /*
1999+ * The child started, but exited or was terminated
2000+ * before becoming "ready".
2001+ *
2002+ * We try to match the behavior of `wait_or_whine()`
2003+ * WRT the handling of WIFSIGNALED() and WIFEXITED()
2004+ * and convert the child's status to a return code for
2005+ * tracing purposes and emit the `trace2_child_exit()`
2006+ * event.
2007+ *
2008+ * We do not want the wait_or_whine() error message
2009+ * because we will be called by client-side library
2010+ * routines.
2011+ */
2012+ if (WIFEXITED (wait_status ))
2013+ child_code = WEXITSTATUS (wait_status );
2014+ else if (WIFSIGNALED (wait_status ))
2015+ child_code = WTERMSIG (wait_status ) + 128 ;
2016+ trace2_child_exit (cmd , child_code );
2017+
2018+ sbgr = SBGR_DIED ;
2019+ goto done ;
2020+ }
2021+
2022+ else if (pid_seen < 0 && errno == EINTR )
2023+ goto wait ;
2024+
2025+ trace2_child_exit (cmd , -1 );
2026+ sbgr = SBGR_ERROR ;
2027+
2028+ done :
2029+ child_process_clear (cmd );
2030+ invalidate_lstat_cache ();
2031+ return sbgr ;
2032+ }
0 commit comments