Skip to content

Commit d2bd862

Browse files
jeffhostetlergitster
authored andcommitted
fsmonitor-ipc: create client routines for git-fsmonitor--daemon
Create fsmonitor_ipc__*() client routines to spawn the built-in file system monitor daemon and send it an IPC request using the `Simple IPC` API. Stub in empty fsmonitor_ipc__*() functions for unsupported platforms. Signed-off-by: Jeff Hostetler <[email protected]> Signed-off-by: Junio C Hamano <[email protected]>
1 parent 974c1b3 commit d2bd862

File tree

3 files changed

+220
-0
lines changed

3 files changed

+220
-0
lines changed

Makefile

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -907,6 +907,7 @@ LIB_OBJS += fetch-pack.o
907907
LIB_OBJS += fmt-merge-msg.o
908908
LIB_OBJS += fsck.o
909909
LIB_OBJS += fsmonitor.o
910+
LIB_OBJS += fsmonitor-ipc.o
910911
LIB_OBJS += gettext.o
911912
LIB_OBJS += gpg-interface.o
912913
LIB_OBJS += graph.o

fsmonitor-ipc.c

Lines changed: 171 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,171 @@
1+
#include "cache.h"
2+
#include "fsmonitor.h"
3+
#include "simple-ipc.h"
4+
#include "fsmonitor-ipc.h"
5+
#include "run-command.h"
6+
#include "strbuf.h"
7+
#include "trace2.h"
8+
9+
#ifndef HAVE_FSMONITOR_DAEMON_BACKEND
10+
11+
/*
12+
* A trivial implementation of the fsmonitor_ipc__ API for unsupported
13+
* platforms.
14+
*/
15+
16+
int fsmonitor_ipc__is_supported(void)
17+
{
18+
return 0;
19+
}
20+
21+
const char *fsmonitor_ipc__get_path(void)
22+
{
23+
return NULL;
24+
}
25+
26+
enum ipc_active_state fsmonitor_ipc__get_state(void)
27+
{
28+
return IPC_STATE__OTHER_ERROR;
29+
}
30+
31+
int fsmonitor_ipc__send_query(const char *since_token,
32+
struct strbuf *answer)
33+
{
34+
return -1;
35+
}
36+
37+
int fsmonitor_ipc__send_command(const char *command,
38+
struct strbuf *answer)
39+
{
40+
return -1;
41+
}
42+
43+
#else
44+
45+
int fsmonitor_ipc__is_supported(void)
46+
{
47+
return 1;
48+
}
49+
50+
GIT_PATH_FUNC(fsmonitor_ipc__get_path, "fsmonitor--daemon.ipc")
51+
52+
enum ipc_active_state fsmonitor_ipc__get_state(void)
53+
{
54+
return ipc_get_active_state(fsmonitor_ipc__get_path());
55+
}
56+
57+
static int spawn_daemon(void)
58+
{
59+
const char *args[] = { "fsmonitor--daemon", "start", NULL };
60+
61+
return run_command_v_opt_tr2(args, RUN_COMMAND_NO_STDIN | RUN_GIT_CMD,
62+
"fsmonitor");
63+
}
64+
65+
int fsmonitor_ipc__send_query(const char *since_token,
66+
struct strbuf *answer)
67+
{
68+
int ret = -1;
69+
int tried_to_spawn = 0;
70+
enum ipc_active_state state = IPC_STATE__OTHER_ERROR;
71+
struct ipc_client_connection *connection = NULL;
72+
struct ipc_client_connect_options options
73+
= IPC_CLIENT_CONNECT_OPTIONS_INIT;
74+
const char *tok = since_token ? since_token : "";
75+
size_t tok_len = since_token ? strlen(since_token) : 0;
76+
77+
options.wait_if_busy = 1;
78+
options.wait_if_not_found = 0;
79+
80+
trace2_region_enter("fsm_client", "query", NULL);
81+
trace2_data_string("fsm_client", NULL, "query/command", tok);
82+
83+
try_again:
84+
state = ipc_client_try_connect(fsmonitor_ipc__get_path(), &options,
85+
&connection);
86+
87+
switch (state) {
88+
case IPC_STATE__LISTENING:
89+
ret = ipc_client_send_command_to_connection(
90+
connection, tok, tok_len, answer);
91+
ipc_client_close_connection(connection);
92+
93+
trace2_data_intmax("fsm_client", NULL,
94+
"query/response-length", answer->len);
95+
goto done;
96+
97+
case IPC_STATE__NOT_LISTENING:
98+
case IPC_STATE__PATH_NOT_FOUND:
99+
if (tried_to_spawn)
100+
goto done;
101+
102+
tried_to_spawn++;
103+
if (spawn_daemon())
104+
goto done;
105+
106+
/*
107+
* Try again, but this time give the daemon a chance to
108+
* actually create the pipe/socket.
109+
*
110+
* Granted, the daemon just started so it can't possibly have
111+
* any FS cached yet, so we'll always get a trivial answer.
112+
* BUT the answer should include a new token that can serve
113+
* as the basis for subsequent requests.
114+
*/
115+
options.wait_if_not_found = 1;
116+
goto try_again;
117+
118+
case IPC_STATE__INVALID_PATH:
119+
ret = error(_("fsmonitor_ipc__send_query: invalid path '%s'"),
120+
fsmonitor_ipc__get_path());
121+
goto done;
122+
123+
case IPC_STATE__OTHER_ERROR:
124+
default:
125+
ret = error(_("fsmonitor_ipc__send_query: unspecified error on '%s'"),
126+
fsmonitor_ipc__get_path());
127+
goto done;
128+
}
129+
130+
done:
131+
trace2_region_leave("fsm_client", "query", NULL);
132+
133+
return ret;
134+
}
135+
136+
int fsmonitor_ipc__send_command(const char *command,
137+
struct strbuf *answer)
138+
{
139+
struct ipc_client_connection *connection = NULL;
140+
struct ipc_client_connect_options options
141+
= IPC_CLIENT_CONNECT_OPTIONS_INIT;
142+
int ret;
143+
enum ipc_active_state state;
144+
const char *c = command ? command : "";
145+
size_t c_len = command ? strlen(command) : 0;
146+
147+
strbuf_reset(answer);
148+
149+
options.wait_if_busy = 1;
150+
options.wait_if_not_found = 0;
151+
152+
state = ipc_client_try_connect(fsmonitor_ipc__get_path(), &options,
153+
&connection);
154+
if (state != IPC_STATE__LISTENING) {
155+
die(_("fsmonitor--daemon is not running"));
156+
return -1;
157+
}
158+
159+
ret = ipc_client_send_command_to_connection(connection, c, c_len,
160+
answer);
161+
ipc_client_close_connection(connection);
162+
163+
if (ret == -1) {
164+
die(_("could not send '%s' command to fsmonitor--daemon"), c);
165+
return -1;
166+
}
167+
168+
return 0;
169+
}
170+
171+
#endif

fsmonitor-ipc.h

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
#ifndef FSMONITOR_IPC_H
2+
#define FSMONITOR_IPC_H
3+
4+
#include "simple-ipc.h"
5+
6+
/*
7+
* Returns true if built-in file system monitor daemon is defined
8+
* for this platform.
9+
*/
10+
int fsmonitor_ipc__is_supported(void);
11+
12+
/*
13+
* Returns the pathname to the IPC named pipe or Unix domain socket
14+
* where a `git-fsmonitor--daemon` process will listen. This is a
15+
* per-worktree value.
16+
*
17+
* Returns NULL if the daemon is not supported on this platform.
18+
*/
19+
const char *fsmonitor_ipc__get_path(void);
20+
21+
/*
22+
* Try to determine whether there is a `git-fsmonitor--daemon` process
23+
* listening on the IPC pipe/socket.
24+
*/
25+
enum ipc_active_state fsmonitor_ipc__get_state(void);
26+
27+
/*
28+
* Connect to a `git-fsmonitor--daemon` process via simple-ipc
29+
* and ask for the set of changed files since the given token.
30+
*
31+
* Spawn a daemon process in the background if necessary.
32+
*
33+
* Returns -1 on error; 0 on success.
34+
*/
35+
int fsmonitor_ipc__send_query(const char *since_token,
36+
struct strbuf *answer);
37+
38+
/*
39+
* Connect to a `git-fsmonitor--daemon` process via simple-ipc and
40+
* send a command verb. If no daemon is available, we DO NOT try to
41+
* start one.
42+
*
43+
* Returns -1 on error; 0 on success.
44+
*/
45+
int fsmonitor_ipc__send_command(const char *command,
46+
struct strbuf *answer);
47+
48+
#endif /* FSMONITOR_IPC_H */

0 commit comments

Comments
 (0)