Skip to content

Commit 2d4828e

Browse files
jeffhostetlerGit for Windows Build Agent
authored and
Git for Windows Build Agent
committed
Merge branch 'try-v4-fsmonitor-part4' into try-v4-fsmonitor
2 parents 59b39ec + a3963b0 commit 2d4828e

21 files changed

+1560
-137
lines changed

Makefile

Lines changed: 17 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -469,8 +469,14 @@ all::
469469
#
470470
# If your platform supports a built-in fsmonitor backend, set
471471
# FSMONITOR_DAEMON_BACKEND to the "<name>" of the corresponding
472-
# `compat/fsmonitor/fsm-listen-<name>.c` that implements the
473-
# `fsm_listen__*()` routines.
472+
# `compat/fsmonitor/fsm-listen-<name>.c` and
473+
# `compat/fsmonitor/fsm-health-<name>.c` files
474+
# that implement the `fsm_listen__*()` and `fsm_health__*()` routines.
475+
#
476+
# If your platform has os-specific ways to tell if a repo is incompatible with
477+
# fsmonitor (whether the hook or ipc daemon version), set FSMONITOR_OS_SETTINGS
478+
# to the "<name>" of the corresponding `compat/fsmonitor/fsm-settings-<name>.c`
479+
# that implements the `fsm_os_settings__*()` routines.
474480
#
475481
# Define DEVELOPER to enable more compiler warnings. Compiler version
476482
# and family are auto detected, but could be overridden by defining
@@ -1947,6 +1953,12 @@ endif
19471953
ifdef FSMONITOR_DAEMON_BACKEND
19481954
COMPAT_CFLAGS += -DHAVE_FSMONITOR_DAEMON_BACKEND
19491955
COMPAT_OBJS += compat/fsmonitor/fsm-listen-$(FSMONITOR_DAEMON_BACKEND).o
1956+
COMPAT_OBJS += compat/fsmonitor/fsm-health-$(FSMONITOR_DAEMON_BACKEND).o
1957+
endif
1958+
1959+
ifdef FSMONITOR_OS_SETTINGS
1960+
COMPAT_CFLAGS += -DHAVE_FSMONITOR_OS_SETTINGS
1961+
COMPAT_OBJS += compat/fsmonitor/fsm-settings-$(FSMONITOR_OS_SETTINGS).o
19501962
endif
19511963

19521964
ifeq ($(TCLTK_PATH),)
@@ -2834,6 +2846,9 @@ GIT-BUILD-OPTIONS: FORCE
28342846
ifdef FSMONITOR_DAEMON_BACKEND
28352847
@echo FSMONITOR_DAEMON_BACKEND=\''$(subst ','\'',$(subst ','\'',$(FSMONITOR_DAEMON_BACKEND)))'\' >>$@+
28362848
endif
2849+
ifdef FSMONITOR_OS_SETTINGS
2850+
@echo FSMONITOR_OS_SETTINGS=\''$(subst ','\'',$(subst ','\'',$(FSMONITOR_OS_SETTINGS)))'\' >>$@+
2851+
endif
28372852
ifdef TEST_OUTPUT_DIRECTORY
28382853
@echo TEST_OUTPUT_DIRECTORY=\''$(subst ','\'',$(subst ','\'',$(TEST_OUTPUT_DIRECTORY)))'\' >>$@+
28392854
endif

builtin/fsmonitor--daemon.c

Lines changed: 123 additions & 15 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"
@@ -27,6 +28,9 @@ static int fsmonitor__ipc_threads = 8;
2728
#define FSMONITOR__START_TIMEOUT "fsmonitor.starttimeout"
2829
static int fsmonitor__start_timeout_sec = 60;
2930

31+
#define FSMONITOR__ANNOUNCE_STARTUP "fsmonitor.announcestartup"
32+
static int fsmonitor__announce_startup = 0;
33+
3034
static int fsmonitor_config(const char *var, const char *value, void *cb)
3135
{
3236
if (!strcmp(var, FSMONITOR__IPC_THREADS)) {
@@ -47,6 +51,16 @@ static int fsmonitor_config(const char *var, const char *value, void *cb)
4751
return 0;
4852
}
4953

54+
if (!strcmp(var, FSMONITOR__ANNOUNCE_STARTUP)) {
55+
int is_bool;
56+
int i = git_config_bool_or_int(var, value, &is_bool);
57+
if (i < 0)
58+
return error(_("value of '%s' not bool or int: %d"),
59+
var, i);
60+
fsmonitor__announce_startup = i;
61+
return 0;
62+
}
63+
5064
return git_default_config(var, value, cb);
5165
}
5266

@@ -1111,6 +1125,18 @@ void fsmonitor_publish(struct fsmonitor_daemon_state *state,
11111125
pthread_mutex_unlock(&state->main_lock);
11121126
}
11131127

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+
11141140
static void *fsm_listen__thread_proc(void *_state)
11151141
{
11161142
struct fsmonitor_daemon_state *state = _state;
@@ -1149,18 +1175,21 @@ static int fsmonitor_run_daemon_1(struct fsmonitor_daemon_state *state)
11491175
*/
11501176
.uds_disallow_chdir = 0
11511177
};
1178+
int health_started = 0;
1179+
int listener_started = 0;
1180+
int err = 0;
11521181

11531182
/*
11541183
* Start the IPC thread pool before the we've started the file
11551184
* system event listener thread so that we have the IPC handle
11561185
* before we need it.
11571186
*/
11581187
if (ipc_server_run_async(&state->ipc_server_data,
1159-
fsmonitor_ipc__get_path(), &ipc_opts,
1188+
state->path_ipc.buf, &ipc_opts,
11601189
handle_client, state))
11611190
return error_errno(
11621191
_("could not start IPC thread pool on '%s'"),
1163-
fsmonitor_ipc__get_path());
1192+
state->path_ipc.buf);
11641193

11651194
/*
11661195
* Start the fsmonitor listener thread to collect filesystem
@@ -1169,15 +1198,31 @@ static int fsmonitor_run_daemon_1(struct fsmonitor_daemon_state *state)
11691198
if (pthread_create(&state->listener_thread, NULL,
11701199
fsm_listen__thread_proc, state) < 0) {
11711200
ipc_server_stop_async(state->ipc_server_data);
1172-
ipc_server_await(state->ipc_server_data);
1201+
err = error(_("could not start fsmonitor listener thread"));
1202+
goto cleanup;
1203+
}
1204+
listener_started = 1;
11731205

1174-
return error(_("could not start fsmonitor listener thread"));
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;
11751214
}
1215+
health_started = 1;
11761216

11771217
/*
11781218
* The daemon is now fully functional in background threads.
1219+
* Our primary thread should now just wait while the threads
1220+
* do all the work.
1221+
*/
1222+
cleanup:
1223+
/*
11791224
* Wait for the IPC thread pool to shutdown (whether by client
1180-
* request or from filesystem activity).
1225+
* request, from filesystem activity, or an error).
11811226
*/
11821227
ipc_server_await(state->ipc_server_data);
11831228

@@ -1186,23 +1231,38 @@ static int fsmonitor_run_daemon_1(struct fsmonitor_daemon_state *state)
11861231
* event from the IPC thread pool, but it doesn't hurt to tell
11871232
* it again. And wait for it to shutdown.
11881233
*/
1189-
fsm_listen__stop_async(state);
1190-
pthread_join(state->listener_thread, NULL);
1234+
if (listener_started) {
1235+
fsm_listen__stop_async(state);
1236+
pthread_join(state->listener_thread, NULL);
1237+
}
11911238

1192-
return state->error_code;
1239+
if (health_started) {
1240+
fsm_health__stop_async(state);
1241+
pthread_join(state->health_thread, NULL);
1242+
}
1243+
1244+
if (err)
1245+
return err;
1246+
if (state->listen_error_code)
1247+
return state->listen_error_code;
1248+
if (state->health_error_code)
1249+
return state->health_error_code;
1250+
return 0;
11931251
}
11941252

11951253
static int fsmonitor_run_daemon(void)
11961254
{
11971255
struct fsmonitor_daemon_state state;
1256+
const char *home;
11981257
int err;
11991258

12001259
memset(&state, 0, sizeof(state));
12011260

12021261
hashmap_init(&state.cookies, cookies_cmp, NULL, 0);
12031262
pthread_mutex_init(&state.main_lock, NULL);
12041263
pthread_cond_init(&state.cookies_cond, NULL);
1205-
state.error_code = 0;
1264+
state.listen_error_code = 0;
1265+
state.health_error_code = 0;
12061266
state.current_token_data = fsmonitor_new_token_data();
12071267

12081268
/* Prepare to (recursively) watch the <worktree-root> directory. */
@@ -1264,6 +1324,15 @@ static int fsmonitor_run_daemon(void)
12641324

12651325
strbuf_addch(&state.path_cookie_prefix, '/');
12661326

1327+
/*
1328+
* We create a named-pipe or unix domain socket inside of the
1329+
* ".git" directory. (Well, on Windows, we base our named
1330+
* pipe in the NPFS on the absolute path of the git
1331+
* directory.)
1332+
*/
1333+
strbuf_init(&state.path_ipc, 0);
1334+
strbuf_addstr(&state.path_ipc, absolute_path(fsmonitor_ipc__get_path()));
1335+
12671336
/*
12681337
* Confirm that we can create platform-specific resources for the
12691338
* filesystem listener before we bother starting all the threads.
@@ -1273,18 +1342,42 @@ static int fsmonitor_run_daemon(void)
12731342
goto done;
12741343
}
12751344

1345+
if (fsm_health__ctor(&state)) {
1346+
err = error(_("could not initialize health thread"));
1347+
goto done;
1348+
}
1349+
1350+
/*
1351+
* CD out of the worktree root directory.
1352+
*
1353+
* The common Git startup mechanism causes our CWD to be the
1354+
* root of the worktree. On Windows, this causes our process
1355+
* to hold a locked handle on the CWD. This prevents the
1356+
* worktree from being moved or deleted while the daemon is
1357+
* running.
1358+
*
1359+
* We assume that our FS and IPC listener threads have either
1360+
* opened all of the handles that they need or will do
1361+
* everything using absolute paths.
1362+
*/
1363+
home = getenv("HOME");
1364+
if (home && *home && chdir(home))
1365+
die_errno("could not cd home '%s'", home);
1366+
12761367
err = fsmonitor_run_daemon_1(&state);
12771368

12781369
done:
12791370
pthread_cond_destroy(&state.cookies_cond);
12801371
pthread_mutex_destroy(&state.main_lock);
12811372
fsm_listen__dtor(&state);
1373+
fsm_health__dtor(&state);
12821374

12831375
ipc_server_free(state.ipc_server_data);
12841376

12851377
strbuf_release(&state.path_worktree_watch);
12861378
strbuf_release(&state.path_gitdir_watch);
12871379
strbuf_release(&state.path_cookie_prefix);
1380+
strbuf_release(&state.path_ipc);
12881381

12891382
/*
12901383
* NEEDSWORK: Consider "rm -rf <gitdir>/<fsmonitor-dir>"
@@ -1307,9 +1400,11 @@ static int try_to_run_foreground_daemon(int free_console)
13071400
die("fsmonitor--daemon is already running '%s'",
13081401
the_repository->worktree);
13091402

1310-
printf(_("running fsmonitor-daemon in '%s'\n"),
1311-
the_repository->worktree);
1312-
fflush(stdout);
1403+
if (fsmonitor__announce_startup) {
1404+
fprintf(stderr, _("running fsmonitor-daemon in '%s'\n"),
1405+
the_repository->worktree);
1406+
fflush(stderr);
1407+
}
13131408

13141409
#ifdef GIT_WINDOWS_NATIVE
13151410
if (free_console)
@@ -1360,9 +1455,11 @@ static int try_to_start_background_daemon(void)
13601455
die("fsmonitor--daemon is already running '%s'",
13611456
the_repository->worktree);
13621457

1363-
printf(_("starting fsmonitor-daemon in '%s'\n"),
1364-
the_repository->worktree);
1365-
fflush(stdout);
1458+
if (fsmonitor__announce_startup) {
1459+
fprintf(stderr, _("starting fsmonitor-daemon in '%s'\n"),
1460+
the_repository->worktree);
1461+
fflush(stderr);
1462+
}
13661463

13671464
cp.git_cmd = 1;
13681465

@@ -1424,6 +1521,17 @@ int cmd_fsmonitor__daemon(int argc, const char **argv, const char *prefix)
14241521
die(_("invalid 'ipc-threads' value (%d)"),
14251522
fsmonitor__ipc_threads);
14261523

1524+
prepare_repo_settings(the_repository);
1525+
fsm_settings__set_ipc(the_repository);
1526+
1527+
if (fsm_settings__get_mode(the_repository) == FSMONITOR_MODE_INCOMPATIBLE) {
1528+
struct strbuf buf_reason = STRBUF_INIT;
1529+
fsm_settings__get_reason(the_repository, &buf_reason);
1530+
error("%s '%s'", buf_reason.buf, xgetcwd());
1531+
strbuf_release(&buf_reason);
1532+
return -1;
1533+
}
1534+
14271535
if (!strcmp(subcmd, "start"))
14281536
return !!try_to_start_background_daemon();
14291537

builtin/update-index.c

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1222,6 +1222,14 @@ int cmd_update_index(int argc, const char **argv, const char *prefix)
12221222
if (fsmonitor > 0) {
12231223
enum fsmonitor_mode fsm_mode = fsm_settings__get_mode(r);
12241224

1225+
if (fsm_mode == FSMONITOR_MODE_INCOMPATIBLE) {
1226+
struct strbuf buf_reason = STRBUF_INIT;
1227+
fsm_settings__get_reason(r, &buf_reason);
1228+
error("%s", buf_reason.buf);
1229+
strbuf_release(&buf_reason);
1230+
return -1;
1231+
}
1232+
12251233
if (fsm_mode == FSMONITOR_MODE_DISABLED) {
12261234
warning(_("core.useBuiltinFSMonitor is unset; "
12271235
"set it if you really want to enable the "

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+
}

0 commit comments

Comments
 (0)