add ppid to end event to improve fork() support
Stefan Schuermans

Stefan Schuermans commited on 2021-03-09 20:37:39
Showing 4 changed files, with 26 additions and 21 deletions.


A child process of fork() does not have a begin event and thus, nothing was
known about its parent. Adding the ppid to the end event establishes the
relationship to its parent process.
... ...
@@ -34,6 +34,10 @@ int uptev_proc_end(void **data, size_t *size) {
34 34
 
35 35
   struct _Uproctrace__ProcEnd proc_end = UPROCTRACE__PROC_END__INIT;
36 36
   proc_end.pid = getpid();
37
+  // ppid also in end event because child of fork() has no begin event
38
+  proc_end.has_ppid = 1;
39
+  proc_end.ppid = getppid();
40
+
37 41
   proc_end.cpu_time = &cpu_time;
38 42
 
39 43
   struct rusage usage;
... ...
@@ -82,6 +82,7 @@ class ProcBeginOrEnd(BaseEvent):
82 82
         super().__init__(pb2_ev)
83 83
         self._process = None
84 84
         self._pid = None
85
+        self._ppid = None
85 86
 
86 87
     @property
87 88
     def pid(self) -> int:
... ...
@@ -90,6 +91,13 @@ class ProcBeginOrEnd(BaseEvent):
90 91
         """
91 92
         return self._pid
92 93
 
94
+    @property
95
+    def ppid(self) -> int:
96
+        """
97
+        ID of parent process.
98
+        """
99
+        return self._ppid
100
+
93 101
     @property
94 102
     def process(self):
95 103
         """
... ...
@@ -123,13 +131,6 @@ class ProcBegin(ProcBeginOrEnd):
123 131
         self._environ = self._pb2GetStringList(
124 132
             p_b.environ) if p_b.HasField('environ') else None
125 133
 
126
-    @property
127
-    def ppid(self) -> int:
128
-        """
129
-        ID of parent process.
130
-        """
131
-        return self._ppid
132
-
133 134
     @property
134 135
     def exe(self) -> str:
135 136
         """
... ...
@@ -173,6 +174,7 @@ class ProcEnd(ProcBeginOrEnd):
173 174
         super().__init__(pb2_ev)
174 175
         p_e = pb2_ev.proc_end
175 176
         self._pid = p_e.pid
177
+        self._ppid = p_e.ppid if p_e.HasField('ppid') else None
176 178
         self._cpu_time = self._pb2GetTimespec(
177 179
             p_e.cpu_time) if p_e.HasField('cpu_time') else None
178 180
         self._user_time = self._pb2GetTimespec(
... ...
@@ -188,13 +190,6 @@ class ProcEnd(ProcBeginOrEnd):
188 190
         self._n_v_csw = p_e.n_v_csw if p_e.HasField('n_v_csw') else None
189 191
         self._n_iv_csw = p_e.n_iv_csw if p_e.HasField('n_iv_csw') else None
190 192
 
191
-    @property
192
-    def pid(self) -> int:
193
-        """
194
-        ID of process.
195
-        """
196
-        return self._pid
197
-
198 193
     @property
199 194
     def cpu_time(self) -> float:
200 195
         """
... ...
@@ -171,20 +171,20 @@ class Process():
171 171
         """
172 172
         Linux process ID.
173 173
         """
174
-        if self._begin is not None:
175
-            return self._begin.pid
176
-        if self._end is not None:
177
-            return self._end.pid
178
-        return None
174
+        return self._pid
179 175
 
180 176
     @property
181 177
     def ppid(self):
182 178
         """
183 179
         Linux process ID of parent process.
184 180
         """
185
-        if self._begin is None:
186
-            return None
181
+        if self._begin is not None:
182
+            if self._begin.ppid is not None:
187 183
                 return self._begin.ppid
184
+        if self._end is not None:
185
+            if self._end.ppid:
186
+                return self._end.ppid
187
+        return None
188 188
 
189 189
     @property
190 190
     def proc_id(self):
... ...
@@ -355,6 +355,10 @@ class Processes(uproctrace.parse.Visitor):
355 355
         # set end event of process and process of end event
356 356
         proc.setEnd(proc_end)
357 357
         proc_end.setProcess(proc)
358
+        # add process to parent if available
359
+        if proc_end.ppid is not None:
360
+            parent = self._getProcess(proc_end.ppid)
361
+            self._parentChild(parent, proc)
358 362
         # remove process from dict of current processes (it ended)
359 363
         #   - it is guaranteed to be in it, because it came from _getProcess()
360 364
         del self._current_processes[proc_end.pid]
... ...
@@ -22,6 +22,8 @@ message proc_begin {
22 22
 
23 23
 message proc_end {
24 24
   required int32 pid = 1;
25
+  optional int32 ppid = 12; ///< pid of parent process (important for fork(),
26
+                            ///< because child of fork has no proc_begin event)
25 27
   /// fields from clock_gettime
26 28
   //@{
27 29
   optional timespec cpu_time = 2; ///< CPU time usage
28 30