Skip to content

Commit b47c32c

Browse files
mjcheethamgitster
authored andcommitted
trace2: add macOS process ancestry tracing
In 353d3d7 (trace2: collect Windows-specific process information) Windows-specific process ancestry information was added as a data_json event to TRACE2. Furthermore in 2f732bf (tr2: log parent process name) similar functionality was added for Linux-based systems, using procfs. Teach Git to also log process ancestry on macOS using the sysctl with KERN_PROC to get process information (PPID and process name). Like the Linux implementation, we use the cmd_ancestry TRACE2 event rather than using a data_json event and creating another custom data point. Signed-off-by: Matthew John Cheetham <mjcheetham@outlook.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>
1 parent 9a2fb14 commit b47c32c

1 file changed

Lines changed: 99 additions & 0 deletions

File tree

compat/darwin/procinfo.c

Lines changed: 99 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,99 @@
1+
#define USE_THE_REPOSITORY_VARIABLE
2+
3+
#include "git-compat-util.h"
4+
#include "strbuf.h"
5+
#include "strvec.h"
6+
#include "trace2.h"
7+
#include <sys/sysctl.h>
8+
9+
/*
10+
* An arbitrarily chosen value to limit the depth of the ancestor chain.
11+
*/
12+
#define NR_PIDS_LIMIT 10
13+
14+
/*
15+
* Get the process name and parent PID for a given PID using sysctl().
16+
* Returns 0 on success, -1 on failure.
17+
*/
18+
static int get_proc_info(pid_t pid, struct strbuf *name, pid_t *ppid)
19+
{
20+
int mib[4];
21+
struct kinfo_proc proc;
22+
size_t size = sizeof(proc);
23+
24+
mib[0] = CTL_KERN;
25+
mib[1] = KERN_PROC;
26+
mib[2] = KERN_PROC_PID;
27+
mib[3] = pid;
28+
29+
if (sysctl(mib, 4, &proc, &size, NULL, 0) < 0)
30+
return -1;
31+
32+
if (size == 0)
33+
return -1;
34+
35+
strbuf_addstr(name, proc.kp_proc.p_comm);
36+
*ppid = proc.kp_eproc.e_ppid;
37+
38+
return 0;
39+
}
40+
41+
/*
42+
* Recursively push process names onto the ancestry array.
43+
* We guard against cycles by limiting the depth to NR_PIDS_LIMIT.
44+
*/
45+
static void push_ancestry_name(struct strvec *names, pid_t pid, int depth)
46+
{
47+
struct strbuf name = STRBUF_INIT;
48+
pid_t ppid;
49+
50+
if (depth >= NR_PIDS_LIMIT)
51+
return;
52+
53+
if (pid <= 0)
54+
return;
55+
56+
if (get_proc_info(pid, &name, &ppid) < 0)
57+
goto cleanup;
58+
59+
strvec_push(names, name.buf);
60+
61+
/*
62+
* Recurse to the parent process. Stop if ppid is 0 or 1
63+
* (init/launchd) or if we've reached ourselves (cycle).
64+
*/
65+
if (ppid > 1 && ppid != pid)
66+
push_ancestry_name(names, ppid, depth + 1);
67+
68+
cleanup:
69+
strbuf_release(&name);
70+
}
71+
72+
void trace2_collect_process_info(enum trace2_process_info_reason reason)
73+
{
74+
struct strvec names = STRVEC_INIT;
75+
76+
if (!trace2_is_enabled())
77+
return;
78+
79+
switch (reason) {
80+
case TRACE2_PROCESS_INFO_STARTUP:
81+
push_ancestry_name(&names, getppid(), 0);
82+
if (names.nr)
83+
trace2_cmd_ancestry(names.v);
84+
85+
strvec_clear(&names);
86+
break;
87+
88+
case TRACE2_PROCESS_INFO_EXIT:
89+
/*
90+
* The Windows version of this calls its
91+
* get_peak_memory_info() here. We may want to insert
92+
* similar process-end statistics here in the future.
93+
*/
94+
break;
95+
96+
default:
97+
BUG("trace2_collect_process_info: unknown reason '%d'", reason);
98+
}
99+
}

0 commit comments

Comments
 (0)