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"
@@ -1136,6 +1137,18 @@ void fsmonitor_publish(struct fsmonitor_daemon_state *state,
1136
1137
pthread_mutex_unlock (& state -> main_lock );
1137
1138
}
1138
1139
1140
+ static void * fsm_health__thread_proc (void * _state )
1141
+ {
1142
+ struct fsmonitor_daemon_state * state = _state ;
1143
+
1144
+ trace2_thread_start ("fsm-health" );
1145
+
1146
+ fsm_health__loop (state );
1147
+
1148
+ trace2_thread_exit ();
1149
+ return NULL ;
1150
+ }
1151
+
1139
1152
static void * fsm_listen__thread_proc (void * _state )
1140
1153
{
1141
1154
struct fsmonitor_daemon_state * state = _state ;
@@ -1174,18 +1187,21 @@ static int fsmonitor_run_daemon_1(struct fsmonitor_daemon_state *state)
1174
1187
*/
1175
1188
.uds_disallow_chdir = 0
1176
1189
};
1190
+ int health_started = 0 ;
1191
+ int listener_started = 0 ;
1192
+ int err = 0 ;
1177
1193
1178
1194
/*
1179
1195
* Start the IPC thread pool before the we've started the file
1180
1196
* system event listener thread so that we have the IPC handle
1181
1197
* before we need it.
1182
1198
*/
1183
1199
if (ipc_server_run_async (& state -> ipc_server_data ,
1184
- fsmonitor_ipc__get_path () , & ipc_opts ,
1200
+ state -> path_ipc . buf , & ipc_opts ,
1185
1201
handle_client , state ))
1186
1202
return error_errno (
1187
1203
_ ("could not start IPC thread pool on '%s'" ),
1188
- fsmonitor_ipc__get_path () );
1204
+ state -> path_ipc . buf );
1189
1205
1190
1206
/*
1191
1207
* Start the fsmonitor listener thread to collect filesystem
@@ -1194,15 +1210,31 @@ static int fsmonitor_run_daemon_1(struct fsmonitor_daemon_state *state)
1194
1210
if (pthread_create (& state -> listener_thread , NULL ,
1195
1211
fsm_listen__thread_proc , state ) < 0 ) {
1196
1212
ipc_server_stop_async (state -> ipc_server_data );
1197
- ipc_server_await (state -> ipc_server_data );
1213
+ err = error (_ ("could not start fsmonitor listener thread" ));
1214
+ goto cleanup ;
1215
+ }
1216
+ listener_started = 1 ;
1198
1217
1199
- return error (_ ("could not start fsmonitor listener thread" ));
1218
+ /*
1219
+ * Start the health thread to watch over our process.
1220
+ */
1221
+ if (pthread_create (& state -> health_thread , NULL ,
1222
+ fsm_health__thread_proc , state ) < 0 ) {
1223
+ ipc_server_stop_async (state -> ipc_server_data );
1224
+ err = error (_ ("could not start fsmonitor health thread" ));
1225
+ goto cleanup ;
1200
1226
}
1227
+ health_started = 1 ;
1201
1228
1202
1229
/*
1203
1230
* The daemon is now fully functional in background threads.
1231
+ * Our primary thread should now just wait while the threads
1232
+ * do all the work.
1233
+ */
1234
+ cleanup :
1235
+ /*
1204
1236
* Wait for the IPC thread pool to shutdown (whether by client
1205
- * request or from filesystem activity).
1237
+ * request, from filesystem activity, or an error ).
1206
1238
*/
1207
1239
ipc_server_await (state -> ipc_server_data );
1208
1240
@@ -1211,23 +1243,38 @@ static int fsmonitor_run_daemon_1(struct fsmonitor_daemon_state *state)
1211
1243
* event from the IPC thread pool, but it doesn't hurt to tell
1212
1244
* it again. And wait for it to shutdown.
1213
1245
*/
1214
- fsm_listen__stop_async (state );
1215
- pthread_join (state -> listener_thread , NULL );
1246
+ if (listener_started ) {
1247
+ fsm_listen__stop_async (state );
1248
+ pthread_join (state -> listener_thread , NULL );
1249
+ }
1250
+
1251
+ if (health_started ) {
1252
+ fsm_health__stop_async (state );
1253
+ pthread_join (state -> health_thread , NULL );
1254
+ }
1216
1255
1217
- return state -> error_code ;
1256
+ if (err )
1257
+ return err ;
1258
+ if (state -> listen_error_code )
1259
+ return state -> listen_error_code ;
1260
+ if (state -> health_error_code )
1261
+ return state -> health_error_code ;
1262
+ return 0 ;
1218
1263
}
1219
1264
1220
1265
static int fsmonitor_run_daemon (void )
1221
1266
{
1222
1267
struct fsmonitor_daemon_state state ;
1268
+ const char * home ;
1223
1269
int err ;
1224
1270
1225
1271
memset (& state , 0 , sizeof (state ));
1226
1272
1227
1273
hashmap_init (& state .cookies , cookies_cmp , NULL , 0 );
1228
1274
pthread_mutex_init (& state .main_lock , NULL );
1229
1275
pthread_cond_init (& state .cookies_cond , NULL );
1230
- state .error_code = 0 ;
1276
+ state .listen_error_code = 0 ;
1277
+ state .health_error_code = 0 ;
1231
1278
state .current_token_data = fsmonitor_new_token_data ();
1232
1279
1233
1280
/* Prepare to (recursively) watch the <worktree-root> directory. */
@@ -1289,6 +1336,15 @@ static int fsmonitor_run_daemon(void)
1289
1336
1290
1337
strbuf_addch (& state .path_cookie_prefix , '/' );
1291
1338
1339
+ /*
1340
+ * We create a named-pipe or unix domain socket inside of the
1341
+ * ".git" directory. (Well, on Windows, we base our named
1342
+ * pipe in the NPFS on the absolute path of the git
1343
+ * directory.)
1344
+ */
1345
+ strbuf_init (& state .path_ipc , 0 );
1346
+ strbuf_addstr (& state .path_ipc , absolute_path (fsmonitor_ipc__get_path ()));
1347
+
1292
1348
/*
1293
1349
* Confirm that we can create platform-specific resources for the
1294
1350
* filesystem listener before we bother starting all the threads.
@@ -1298,18 +1354,42 @@ static int fsmonitor_run_daemon(void)
1298
1354
goto done ;
1299
1355
}
1300
1356
1357
+ if (fsm_health__ctor (& state )) {
1358
+ err = error (_ ("could not initialize health thread" ));
1359
+ goto done ;
1360
+ }
1361
+
1362
+ /*
1363
+ * CD out of the worktree root directory.
1364
+ *
1365
+ * The common Git startup mechanism causes our CWD to be the
1366
+ * root of the worktree. On Windows, this causes our process
1367
+ * to hold a locked handle on the CWD. This prevents the
1368
+ * worktree from being moved or deleted while the daemon is
1369
+ * running.
1370
+ *
1371
+ * We assume that our FS and IPC listener threads have either
1372
+ * opened all of the handles that they need or will do
1373
+ * everything using absolute paths.
1374
+ */
1375
+ home = getenv ("HOME" );
1376
+ if (home && * home && chdir (home ))
1377
+ die_errno (_ ("could not cd home '%s'" ), home );
1378
+
1301
1379
err = fsmonitor_run_daemon_1 (& state );
1302
1380
1303
1381
done :
1304
1382
pthread_cond_destroy (& state .cookies_cond );
1305
1383
pthread_mutex_destroy (& state .main_lock );
1306
1384
fsm_listen__dtor (& state );
1385
+ fsm_health__dtor (& state );
1307
1386
1308
1387
ipc_server_free (state .ipc_server_data );
1309
1388
1310
1389
strbuf_release (& state .path_worktree_watch );
1311
1390
strbuf_release (& state .path_gitdir_watch );
1312
1391
strbuf_release (& state .path_cookie_prefix );
1392
+ strbuf_release (& state .path_ipc );
1313
1393
1314
1394
return err ;
1315
1395
}
@@ -1449,6 +1529,12 @@ int cmd_fsmonitor__daemon(int argc, const char **argv, const char *prefix)
1449
1529
die (_ ("invalid 'ipc-threads' value (%d)" ),
1450
1530
fsmonitor__ipc_threads );
1451
1531
1532
+ prepare_repo_settings (the_repository );
1533
+ fsm_settings__set_ipc (the_repository );
1534
+
1535
+ if (fsm_settings__error_if_incompatible (the_repository ))
1536
+ return 1 ;
1537
+
1452
1538
if (!strcmp (subcmd , "start" ))
1453
1539
return !!try_to_start_background_daemon ();
1454
1540
0 commit comments