99#include "khash.h"
1010
1111static const char * const builtin_fsmonitor__daemon_usage [] = {
12+ N_ ("git fsmonitor--daemon start [<options>]" ),
1213 N_ ("git fsmonitor--daemon run [<options>]" ),
1314 N_ ("git fsmonitor--daemon stop" ),
1415 N_ ("git fsmonitor--daemon status" ),
@@ -22,6 +23,9 @@ static const char * const builtin_fsmonitor__daemon_usage[] = {
2223#define FSMONITOR__IPC_THREADS "fsmonitor.ipcthreads"
2324static int fsmonitor__ipc_threads = 8 ;
2425
26+ #define FSMONITOR__START_TIMEOUT "fsmonitor.starttimeout"
27+ static int fsmonitor__start_timeout_sec = 60 ;
28+
2529#define FSMONITOR__ANNOUNCE_STARTUP "fsmonitor.announcestartup"
2630static int fsmonitor__announce_startup = 0 ;
2731
@@ -36,6 +40,15 @@ static int fsmonitor_config(const char *var, const char *value, void *cb)
3640 return 0 ;
3741 }
3842
43+ if (!strcmp (var , FSMONITOR__START_TIMEOUT )) {
44+ int i = git_config_int (var , value );
45+ if (i < 0 )
46+ return error (_ ("value of '%s' out of range: %d" ),
47+ FSMONITOR__START_TIMEOUT , i );
48+ fsmonitor__start_timeout_sec = i ;
49+ return 0 ;
50+ }
51+
3952 if (!strcmp (var , FSMONITOR__ANNOUNCE_STARTUP )) {
4053 int is_bool ;
4154 int i = git_config_bool_or_int (var , value , & is_bool );
@@ -250,7 +263,7 @@ static int fsmonitor_run_daemon(void)
250263 return err ;
251264}
252265
253- static int try_to_run_foreground_daemon (void )
266+ static int try_to_run_foreground_daemon (int detach_console )
254267{
255268 /*
256269 * Technically, we don't need to probe for an existing daemon
@@ -270,17 +283,106 @@ static int try_to_run_foreground_daemon(void)
270283 fflush (stderr );
271284 }
272285
286+ #ifdef GIT_WINDOWS_NATIVE
287+ if (detach_console )
288+ FreeConsole ();
289+ #endif
290+
273291 return !!fsmonitor_run_daemon ();
274292}
275293
294+ static start_bg_wait_cb bg_wait_cb ;
295+
296+ static int bg_wait_cb (const struct child_process * cp , void * cb_data )
297+ {
298+ enum ipc_active_state s = fsmonitor_ipc__get_state ();
299+
300+ switch (s ) {
301+ case IPC_STATE__LISTENING :
302+ /* child is "ready" */
303+ return 0 ;
304+
305+ case IPC_STATE__NOT_LISTENING :
306+ case IPC_STATE__PATH_NOT_FOUND :
307+ /* give child more time */
308+ return 1 ;
309+
310+ default :
311+ case IPC_STATE__INVALID_PATH :
312+ case IPC_STATE__OTHER_ERROR :
313+ /* all the time in world won't help */
314+ return -1 ;
315+ }
316+ }
317+
318+ static int try_to_start_background_daemon (void )
319+ {
320+ struct child_process cp = CHILD_PROCESS_INIT ;
321+ enum start_bg_result sbgr ;
322+
323+ /*
324+ * Before we try to create a background daemon process, see
325+ * if a daemon process is already listening. This makes it
326+ * easier for us to report an already-listening error to the
327+ * console, since our spawn/daemon can only report the success
328+ * of creating the background process (and not whether it
329+ * immediately exited).
330+ */
331+ if (fsmonitor_ipc__get_state () == IPC_STATE__LISTENING )
332+ die (_ ("fsmonitor--daemon is already running '%s'" ),
333+ the_repository -> worktree );
334+
335+ if (fsmonitor__announce_startup ) {
336+ fprintf (stderr , _ ("starting fsmonitor-daemon in '%s'\n" ),
337+ the_repository -> worktree );
338+ fflush (stderr );
339+ }
340+
341+ cp .git_cmd = 1 ;
342+
343+ strvec_push (& cp .args , "fsmonitor--daemon" );
344+ strvec_push (& cp .args , "run" );
345+ strvec_push (& cp .args , "--detach" );
346+ strvec_pushf (& cp .args , "--ipc-threads=%d" , fsmonitor__ipc_threads );
347+
348+ cp .no_stdin = 1 ;
349+ cp .no_stdout = 1 ;
350+ cp .no_stderr = 1 ;
351+
352+ sbgr = start_bg_command (& cp , bg_wait_cb , NULL ,
353+ fsmonitor__start_timeout_sec );
354+
355+ switch (sbgr ) {
356+ case SBGR_READY :
357+ return 0 ;
358+
359+ default :
360+ case SBGR_ERROR :
361+ case SBGR_CB_ERROR :
362+ return error (_ ("daemon failed to start" ));
363+
364+ case SBGR_TIMEOUT :
365+ return error (_ ("daemon not online yet" ));
366+
367+ case SBGR_DIED :
368+ return error (_ ("daemon terminated" ));
369+ }
370+ }
371+
276372int cmd_fsmonitor__daemon (int argc , const char * * argv , const char * prefix )
277373{
278374 const char * subcmd ;
375+ int detach_console = 0 ;
279376
280377 struct option options [] = {
378+ OPT_BOOL (0 , "detach" , & detach_console , N_ ("detach from console" )),
281379 OPT_INTEGER (0 , "ipc-threads" ,
282380 & fsmonitor__ipc_threads ,
283381 N_ ("use <n> ipc worker threads" )),
382+ OPT_INTEGER (0 , "start-timeout" ,
383+ & fsmonitor__start_timeout_sec ,
384+ N_ ("max seconds to wait for background daemon startup" )),
385+
284386 OPT_END ()
285387 };
286388
@@ -296,8 +398,11 @@ int cmd_fsmonitor__daemon(int argc, const char **argv, const char *prefix)
296398 die (_ ("invalid 'ipc-threads' value (%d)" ),
297399 fsmonitor__ipc_threads );
298400
401+ if (!strcmp (subcmd , "start" ))
402+ return !!try_to_start_background_daemon ();
403+
299404 if (!strcmp (subcmd , "run" ))
300- return !!try_to_run_foreground_daemon ();
405+ return !!try_to_run_foreground_daemon (detach_console );
301406
302407 if (!strcmp (subcmd , "stop" ))
303408 return !!do_as_client__send_stop ();
0 commit comments