3
3
#include "parse-options.h"
4
4
#include "fsmonitor.h"
5
5
#include "fsmonitor-ipc.h"
6
+ #include "compat/fsmonitor/fsm-health.h"
6
7
#include "compat/fsmonitor/fsm-listen.h"
7
8
#include "fsmonitor--daemon.h"
8
9
#include "simple-ipc.h"
@@ -27,6 +28,9 @@ static int fsmonitor__ipc_threads = 8;
27
28
#define FSMONITOR__START_TIMEOUT "fsmonitor.starttimeout"
28
29
static int fsmonitor__start_timeout_sec = 60 ;
29
30
31
+ #define FSMONITOR__ANNOUNCE_STARTUP "fsmonitor.announcestartup"
32
+ static int fsmonitor__announce_startup = 0 ;
33
+
30
34
static int fsmonitor_config (const char * var , const char * value , void * cb )
31
35
{
32
36
if (!strcmp (var , FSMONITOR__IPC_THREADS )) {
@@ -47,6 +51,16 @@ static int fsmonitor_config(const char *var, const char *value, void *cb)
47
51
return 0 ;
48
52
}
49
53
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
+
50
64
return git_default_config (var , value , cb );
51
65
}
52
66
@@ -1111,6 +1125,18 @@ void fsmonitor_publish(struct fsmonitor_daemon_state *state,
1111
1125
pthread_mutex_unlock (& state -> main_lock );
1112
1126
}
1113
1127
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
+
1114
1140
static void * fsm_listen__thread_proc (void * _state )
1115
1141
{
1116
1142
struct fsmonitor_daemon_state * state = _state ;
@@ -1149,18 +1175,21 @@ static int fsmonitor_run_daemon_1(struct fsmonitor_daemon_state *state)
1149
1175
*/
1150
1176
.uds_disallow_chdir = 0
1151
1177
};
1178
+ int health_started = 0 ;
1179
+ int listener_started = 0 ;
1180
+ int err = 0 ;
1152
1181
1153
1182
/*
1154
1183
* Start the IPC thread pool before the we've started the file
1155
1184
* system event listener thread so that we have the IPC handle
1156
1185
* before we need it.
1157
1186
*/
1158
1187
if (ipc_server_run_async (& state -> ipc_server_data ,
1159
- fsmonitor_ipc__get_path () , & ipc_opts ,
1188
+ state -> path_ipc . buf , & ipc_opts ,
1160
1189
handle_client , state ))
1161
1190
return error_errno (
1162
1191
_ ("could not start IPC thread pool on '%s'" ),
1163
- fsmonitor_ipc__get_path () );
1192
+ state -> path_ipc . buf );
1164
1193
1165
1194
/*
1166
1195
* Start the fsmonitor listener thread to collect filesystem
@@ -1169,15 +1198,31 @@ static int fsmonitor_run_daemon_1(struct fsmonitor_daemon_state *state)
1169
1198
if (pthread_create (& state -> listener_thread , NULL ,
1170
1199
fsm_listen__thread_proc , state ) < 0 ) {
1171
1200
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 ;
1173
1205
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 ;
1175
1214
}
1215
+ health_started = 1 ;
1176
1216
1177
1217
/*
1178
1218
* 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
+ /*
1179
1224
* 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 ).
1181
1226
*/
1182
1227
ipc_server_await (state -> ipc_server_data );
1183
1228
@@ -1186,23 +1231,38 @@ static int fsmonitor_run_daemon_1(struct fsmonitor_daemon_state *state)
1186
1231
* event from the IPC thread pool, but it doesn't hurt to tell
1187
1232
* it again. And wait for it to shutdown.
1188
1233
*/
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
+ }
1191
1238
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 ;
1193
1251
}
1194
1252
1195
1253
static int fsmonitor_run_daemon (void )
1196
1254
{
1197
1255
struct fsmonitor_daemon_state state ;
1256
+ const char * home ;
1198
1257
int err ;
1199
1258
1200
1259
memset (& state , 0 , sizeof (state ));
1201
1260
1202
1261
hashmap_init (& state .cookies , cookies_cmp , NULL , 0 );
1203
1262
pthread_mutex_init (& state .main_lock , NULL );
1204
1263
pthread_cond_init (& state .cookies_cond , NULL );
1205
- state .error_code = 0 ;
1264
+ state .listen_error_code = 0 ;
1265
+ state .health_error_code = 0 ;
1206
1266
state .current_token_data = fsmonitor_new_token_data ();
1207
1267
1208
1268
/* Prepare to (recursively) watch the <worktree-root> directory. */
@@ -1264,6 +1324,15 @@ static int fsmonitor_run_daemon(void)
1264
1324
1265
1325
strbuf_addch (& state .path_cookie_prefix , '/' );
1266
1326
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
+
1267
1336
/*
1268
1337
* Confirm that we can create platform-specific resources for the
1269
1338
* filesystem listener before we bother starting all the threads.
@@ -1273,18 +1342,42 @@ static int fsmonitor_run_daemon(void)
1273
1342
goto done ;
1274
1343
}
1275
1344
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
+
1276
1367
err = fsmonitor_run_daemon_1 (& state );
1277
1368
1278
1369
done :
1279
1370
pthread_cond_destroy (& state .cookies_cond );
1280
1371
pthread_mutex_destroy (& state .main_lock );
1281
1372
fsm_listen__dtor (& state );
1373
+ fsm_health__dtor (& state );
1282
1374
1283
1375
ipc_server_free (state .ipc_server_data );
1284
1376
1285
1377
strbuf_release (& state .path_worktree_watch );
1286
1378
strbuf_release (& state .path_gitdir_watch );
1287
1379
strbuf_release (& state .path_cookie_prefix );
1380
+ strbuf_release (& state .path_ipc );
1288
1381
1289
1382
/*
1290
1383
* NEEDSWORK: Consider "rm -rf <gitdir>/<fsmonitor-dir>"
@@ -1307,9 +1400,11 @@ static int try_to_run_foreground_daemon(int free_console)
1307
1400
die ("fsmonitor--daemon is already running '%s'" ,
1308
1401
the_repository -> worktree );
1309
1402
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
+ }
1313
1408
1314
1409
#ifdef GIT_WINDOWS_NATIVE
1315
1410
if (free_console )
@@ -1360,9 +1455,11 @@ static int try_to_start_background_daemon(void)
1360
1455
die ("fsmonitor--daemon is already running '%s'" ,
1361
1456
the_repository -> worktree );
1362
1457
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
+ }
1366
1463
1367
1464
cp .git_cmd = 1 ;
1368
1465
@@ -1424,6 +1521,17 @@ int cmd_fsmonitor__daemon(int argc, const char **argv, const char *prefix)
1424
1521
die (_ ("invalid 'ipc-threads' value (%d)" ),
1425
1522
fsmonitor__ipc_threads );
1426
1523
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
+
1427
1535
if (!strcmp (subcmd , "start" ))
1428
1536
return !!try_to_start_background_daemon ();
1429
1537
0 commit comments