Skip to content

Commit 66ad532

Browse files
jeffhostetlerdscho
authored andcommitted
fsmonitor--daemon: stub in health thread
Create another thread to watch over the daemon process and automatically shut it down if necessary. This commit creates the basic framework for a "health" thread to monitor the daemon and/or the file system. Later commits will add platform-specific code to do the actual work. The "health" thread is intended to monitor conditions that would be difficult to track inside the IPC thread pool and/or the file system listener threads. For example, when there are file system events outside of the watched worktree root or if we want to have an idle-timeout auto-shutdown feature. Signed-off-by: Jeff Hostetler <[email protected]>
1 parent 11f9e05 commit 66ad532

File tree

7 files changed

+192
-2
lines changed

7 files changed

+192
-2
lines changed

Makefile

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -473,8 +473,9 @@ all::
473473
#
474474
# If your platform supports a built-in fsmonitor backend, set
475475
# FSMONITOR_DAEMON_BACKEND to the "<name>" of the corresponding
476-
# `compat/fsmonitor/fsm-listen-<name>.c` that implements the
477-
# `fsm_listen__*()` routines.
476+
# `compat/fsmonitor/fsm-listen-<name>.c` and
477+
# `compat/fsmonitor/fsm-health-<name>.c` files
478+
# that implement the `fsm_listen__*()` and `fsm_health__*()` routines.
478479
#
479480
# If your platform has os-specific ways to tell if a repo is incompatible with
480481
# fsmonitor (whether the hook or ipc daemon version), set FSMONITOR_OS_SETTINGS
@@ -1954,6 +1955,7 @@ endif
19541955
ifdef FSMONITOR_DAEMON_BACKEND
19551956
COMPAT_CFLAGS += -DHAVE_FSMONITOR_DAEMON_BACKEND
19561957
COMPAT_OBJS += compat/fsmonitor/fsm-listen-$(FSMONITOR_DAEMON_BACKEND).o
1958+
COMPAT_OBJS += compat/fsmonitor/fsm-health-$(FSMONITOR_DAEMON_BACKEND).o
19571959
endif
19581960

19591961
ifdef FSMONITOR_OS_SETTINGS

builtin/fsmonitor--daemon.c

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
#include "parse-options.h"
44
#include "fsmonitor.h"
55
#include "fsmonitor-ipc.h"
6+
#include "compat/fsmonitor/fsm-health.h"
67
#include "compat/fsmonitor/fsm-listen.h"
78
#include "fsmonitor--daemon.h"
89
#include "simple-ipc.h"
@@ -1124,6 +1125,18 @@ void fsmonitor_publish(struct fsmonitor_daemon_state *state,
11241125
pthread_mutex_unlock(&state->main_lock);
11251126
}
11261127

1128+
static void *fsm_health__thread_proc(void *_state)
1129+
{
1130+
struct fsmonitor_daemon_state *state = _state;
1131+
1132+
trace2_thread_start("fsm-health");
1133+
1134+
fsm_health__loop(state);
1135+
1136+
trace2_thread_exit();
1137+
return NULL;
1138+
}
1139+
11271140
static void *fsm_listen__thread_proc(void *_state)
11281141
{
11291142
struct fsmonitor_daemon_state *state = _state;
@@ -1162,6 +1175,7 @@ static int fsmonitor_run_daemon_1(struct fsmonitor_daemon_state *state)
11621175
*/
11631176
.uds_disallow_chdir = 0
11641177
};
1178+
int health_started = 0;
11651179
int listener_started = 0;
11661180
int err = 0;
11671181

@@ -1189,6 +1203,17 @@ static int fsmonitor_run_daemon_1(struct fsmonitor_daemon_state *state)
11891203
}
11901204
listener_started = 1;
11911205

1206+
/*
1207+
* Start the health thread to watch over our process.
1208+
*/
1209+
if (pthread_create(&state->health_thread, NULL,
1210+
fsm_health__thread_proc, state) < 0) {
1211+
ipc_server_stop_async(state->ipc_server_data);
1212+
err = error(_("could not start fsmonitor health thread"));
1213+
goto cleanup;
1214+
}
1215+
health_started = 1;
1216+
11921217
/*
11931218
* The daemon is now fully functional in background threads.
11941219
* Our primary thread should now just wait while the threads
@@ -1211,10 +1236,17 @@ static int fsmonitor_run_daemon_1(struct fsmonitor_daemon_state *state)
12111236
pthread_join(state->listener_thread, NULL);
12121237
}
12131238

1239+
if (health_started) {
1240+
fsm_health__stop_async(state);
1241+
pthread_join(state->health_thread, NULL);
1242+
}
1243+
12141244
if (err)
12151245
return err;
12161246
if (state->listen_error_code)
12171247
return state->listen_error_code;
1248+
if (state->health_error_code)
1249+
return state->health_error_code;
12181250
return 0;
12191251
}
12201252

@@ -1230,6 +1262,7 @@ static int fsmonitor_run_daemon(void)
12301262
pthread_mutex_init(&state.main_lock, NULL);
12311263
pthread_cond_init(&state.cookies_cond, NULL);
12321264
state.listen_error_code = 0;
1265+
state.health_error_code = 0;
12331266
state.current_token_data = fsmonitor_new_token_data();
12341267

12351268
/* Prepare to (recursively) watch the <worktree-root> directory. */
@@ -1309,6 +1342,11 @@ static int fsmonitor_run_daemon(void)
13091342
goto done;
13101343
}
13111344

1345+
if (fsm_health__ctor(&state)) {
1346+
err = error(_("could not initialize health thread"));
1347+
goto done;
1348+
}
1349+
13121350
/*
13131351
* CD out of the worktree root directory.
13141352
*
@@ -1332,6 +1370,7 @@ static int fsmonitor_run_daemon(void)
13321370
pthread_cond_destroy(&state.cookies_cond);
13331371
pthread_mutex_destroy(&state.main_lock);
13341372
fsm_listen__dtor(&state);
1373+
fsm_health__dtor(&state);
13351374

13361375
ipc_server_free(state.ipc_server_data);
13371376

compat/fsmonitor/fsm-health-darwin.c

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
#include "cache.h"
2+
#include "config.h"
3+
#include "fsmonitor.h"
4+
#include "fsm-health.h"
5+
#include "fsmonitor--daemon.h"
6+
7+
int fsm_health__ctor(struct fsmonitor_daemon_state *state)
8+
{
9+
return 0;
10+
}
11+
12+
void fsm_health__dtor(struct fsmonitor_daemon_state *state)
13+
{
14+
return;
15+
}
16+
17+
void fsm_health__loop(struct fsmonitor_daemon_state *state)
18+
{
19+
return;
20+
}
21+
22+
void fsm_health__stop_async(struct fsmonitor_daemon_state *state)
23+
{
24+
}

compat/fsmonitor/fsm-health-win32.c

Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
#include "cache.h"
2+
#include "config.h"
3+
#include "fsmonitor.h"
4+
#include "fsm-health.h"
5+
#include "fsmonitor--daemon.h"
6+
7+
struct fsm_health_data
8+
{
9+
HANDLE hEventShutdown;
10+
11+
HANDLE hHandles[1]; /* the array does not own these handles */
12+
#define HEALTH_SHUTDOWN 0
13+
int nr_handles; /* number of active event handles */
14+
};
15+
16+
int fsm_health__ctor(struct fsmonitor_daemon_state *state)
17+
{
18+
struct fsm_health_data *data;
19+
20+
CALLOC_ARRAY(data, 1);
21+
22+
data->hEventShutdown = CreateEvent(NULL, TRUE, FALSE, NULL);
23+
24+
data->hHandles[HEALTH_SHUTDOWN] = data->hEventShutdown;
25+
data->nr_handles++;
26+
27+
state->health_data = data;
28+
return 0;
29+
}
30+
31+
void fsm_health__dtor(struct fsmonitor_daemon_state *state)
32+
{
33+
struct fsm_health_data *data;
34+
35+
if (!state || !state->health_data)
36+
return;
37+
38+
data = state->health_data;
39+
40+
CloseHandle(data->hEventShutdown);
41+
42+
FREE_AND_NULL(state->health_data);
43+
}
44+
45+
void fsm_health__loop(struct fsmonitor_daemon_state *state)
46+
{
47+
struct fsm_health_data *data = state->health_data;
48+
49+
for (;;) {
50+
DWORD dwWait = WaitForMultipleObjects(data->nr_handles,
51+
data->hHandles,
52+
FALSE, INFINITE);
53+
54+
if (dwWait == WAIT_OBJECT_0 + HEALTH_SHUTDOWN)
55+
goto clean_shutdown;
56+
57+
error(_("health thread wait failed [GLE %ld]"),
58+
GetLastError());
59+
goto force_error_stop;
60+
}
61+
62+
force_error_stop:
63+
state->health_error_code = -1;
64+
ipc_server_stop_async(state->ipc_server_data);
65+
clean_shutdown:
66+
return;
67+
}
68+
69+
void fsm_health__stop_async(struct fsmonitor_daemon_state *state)
70+
{
71+
SetEvent(state->health_data->hHandles[HEALTH_SHUTDOWN]);
72+
}

compat/fsmonitor/fsm-health.h

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
#ifndef FSM_HEALTH_H
2+
#define FSM_HEALTH_H
3+
4+
/* This needs to be implemented by each backend */
5+
6+
#ifdef HAVE_FSMONITOR_DAEMON_BACKEND
7+
8+
struct fsmonitor_daemon_state;
9+
10+
/*
11+
* Initialize platform-specific data for the fsmonitor health thread.
12+
* This will be called from the main thread PRIOR to staring the
13+
* thread.
14+
*
15+
* Returns 0 if successful.
16+
* Returns -1 otherwise.
17+
*/
18+
int fsm_health__ctor(struct fsmonitor_daemon_state *state);
19+
20+
/*
21+
* Cleanup platform-specific data for the health thread.
22+
* This will be called from the main thread AFTER joining the thread.
23+
*/
24+
void fsm_health__dtor(struct fsmonitor_daemon_state *state);
25+
26+
/*
27+
* The main body of the platform-specific event loop to monitor the
28+
* health of the daemon process. This will run in the health thread.
29+
*
30+
* The health thread should call `ipc_server_stop_async()` if it needs
31+
* to cause a shutdown. (It should NOT do so if it receives a shutdown
32+
* shutdown signal.)
33+
*
34+
* It should set `state->health_error_code` to -1 if the daemon should exit
35+
* with an error.
36+
*/
37+
void fsm_health__loop(struct fsmonitor_daemon_state *state);
38+
39+
/*
40+
* Gently request that the health thread shutdown.
41+
* It does not wait for it to stop. The caller should do a JOIN
42+
* to wait for it.
43+
*/
44+
void fsm_health__stop_async(struct fsmonitor_daemon_state *state);
45+
46+
#endif /* HAVE_FSMONITOR_DAEMON_BACKEND */
47+
#endif /* FSM_HEALTH_H */

contrib/buildsystems/CMakeLists.txt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -314,12 +314,14 @@ if(SUPPORTS_SIMPLE_IPC)
314314
if(CMAKE_SYSTEM_NAME STREQUAL "Windows")
315315
add_compile_definitions(HAVE_FSMONITOR_DAEMON_BACKEND)
316316
list(APPEND compat_SOURCES compat/fsmonitor/fsm-listen-win32.c)
317+
list(APPEND compat_SOURCES compat/fsmonitor/fsm-health-win32.c)
317318

318319
add_compile_definitions(HAVE_FSMONITOR_OS_SETTINGS)
319320
list(APPEND compat_SOURCES compat/fsmonitor/fsm-settings-win32.c)
320321
elseif(CMAKE_SYSTEM_NAME STREQUAL "Darwin")
321322
add_compile_definitions(HAVE_FSMONITOR_DAEMON_BACKEND)
322323
list(APPEND compat_SOURCES compat/fsmonitor/fsm-listen-darwin.c)
324+
list(APPEND compat_SOURCES compat/fsmonitor/fsm-health-darwin.c)
323325

324326
add_compile_definitions(HAVE_FSMONITOR_OS_SETTINGS)
325327
list(APPEND compat_SOURCES compat/fsmonitor/fsm-settings-darwin.c)

fsmonitor--daemon.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,9 +34,11 @@ void fsmonitor_batch__free_list(struct fsmonitor_batch *batch);
3434
void fsmonitor_batch__add_path(struct fsmonitor_batch *batch, const char *path);
3535

3636
struct fsm_listen_data; /* opaque platform-specific data for listener thread */
37+
struct fsm_health_data; /* opaque platform-specific data for health thread */
3738

3839
struct fsmonitor_daemon_state {
3940
pthread_t listener_thread;
41+
pthread_t health_thread;
4042
pthread_mutex_t main_lock;
4143

4244
struct strbuf path_worktree_watch;
@@ -51,7 +53,9 @@ struct fsmonitor_daemon_state {
5153
struct hashmap cookies;
5254

5355
int listen_error_code;
56+
int health_error_code;
5457
struct fsm_listen_data *listen_data;
58+
struct fsm_health_data *health_data;
5559

5660
struct ipc_server_data *ipc_server_data;
5761
struct strbuf path_ipc;

0 commit comments

Comments
 (0)