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