Browse Source

Introduce an API for handling spawned auxiliary children

One of gdbserver backend features is to spawn a GDB server. The handling
of this child process is more or less similar to strace_popen'ed child,
so let's generalise it.

* aux_children.c: New file.
* aux_children.h: Likewise.
* Makefile.am (strace_SOURCES): Add them.
Eugene Syromiatnikov 2 years ago
parent
commit
6a4fc3ada3
3 changed files with 274 additions and 0 deletions
  1. 2
    0
      Makefile.am
  2. 173
    0
      aux_children.c
  3. 99
    0
      aux_children.h

+ 2
- 0
Makefile.am View File

@@ -73,6 +73,8 @@ strace_SOURCES =	\
73 73
 	aio.c		\
74 74
 	alpha.c		\
75 75
 	arch_defs.h	\
76
+	aux_children.c	\
77
+	aux_children.h	\
76 78
 	basic_filters.c	\
77 79
 	bind.c		\
78 80
 	bjm.c		\

+ 173
- 0
aux_children.c View File

@@ -0,0 +1,173 @@
1
+/*
2
+ * Auxiliary children support implementation.
3
+ *
4
+ * Copyright (c) 2017 The strace developers.
5
+ * All rights reserved.
6
+ *
7
+ * Redistribution and use in source and binary forms, with or without
8
+ * modification, are permitted provided that the following conditions
9
+ * are met:
10
+ * 1. Redistributions of source code must retain the above copyright
11
+ *    notice, this list of conditions and the following disclaimer.
12
+ * 2. Redistributions in binary form must reproduce the above copyright
13
+ *    notice, this list of conditions and the following disclaimer in the
14
+ *    documentation and/or other materials provided with the distribution.
15
+ * 3. The name of the author may not be used to endorse or promote products
16
+ *    derived from this software without specific prior written permission.
17
+ *
18
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
19
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
20
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
21
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
22
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
23
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
24
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
25
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
27
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28
+ */
29
+
30
+#include "defs.h"
31
+
32
+#include <sys/types.h>
33
+#include <sys/wait.h>
34
+
35
+#include "list.h"
36
+
37
+#include "aux_children.h"
38
+
39
+/* We store children as a linked list since there is not a lot of them and in
40
+ * order to ease removal */
41
+
42
+struct aux_child {
43
+	pid_t pid;
44
+	const struct aux_child_handlers *handlers;
45
+	void *signal_fn_data;
46
+	void *exit_notify_fn_data;
47
+	void *exit_wait_fn_data;
48
+	struct list_item list;
49
+};
50
+
51
+static EMPTY_LIST(children);
52
+
53
+
54
+void
55
+register_aux_child_ex(pid_t pid, const struct aux_child_handlers *h,
56
+		      void *signal_fn_data, void *exit_notify_fn_data,
57
+		       void *exit_wait_fn_data)
58
+{
59
+	static const struct aux_child_handlers default_handlers;
60
+
61
+	struct aux_child *child;
62
+
63
+	list_foreach(child, &children, list) {
64
+		if (child->pid == pid)
65
+			error_func_msg_and_die("Duplicate auxiliary child pid");
66
+	}
67
+
68
+	child = xcalloc(1, sizeof(*child));
69
+
70
+	child->pid = pid;
71
+	child->handlers = h ?: &default_handlers;
72
+	child->signal_fn_data = signal_fn_data;
73
+	child->exit_notify_fn_data = exit_notify_fn_data;
74
+	child->exit_wait_fn_data = exit_wait_fn_data;
75
+
76
+	list_append(&children, &child->list);
77
+}
78
+
79
+void
80
+remove_aux_child(pid_t pid)
81
+{
82
+	struct aux_child *child;
83
+
84
+	list_foreach(child, &children, list) {
85
+		if (child->pid == pid) {
86
+			list_remove(&child->list);
87
+			free(child);
88
+		}
89
+	}
90
+}
91
+
92
+bool
93
+have_aux_children(void)
94
+{
95
+	return !list_is_empty(&children);
96
+}
97
+
98
+enum aux_child_sig
99
+aux_children_signal(pid_t pid, int status)
100
+{
101
+	struct aux_child *child;
102
+
103
+	list_foreach(child, &children, list) {
104
+		if (child->pid == pid) {
105
+			aux_child_signal_fn sig_handler =
106
+				child->handlers->signal_fn;
107
+
108
+			if (!sig_handler)
109
+				sig_handler = aux_child_sig_handler;
110
+
111
+			return sig_handler(pid, status, child->signal_fn_data);
112
+		}
113
+	}
114
+
115
+	return ACS_NONE;
116
+}
117
+
118
+void
119
+aux_children_exit_notify(int exit_code)
120
+{
121
+	struct aux_child *cur;
122
+	struct aux_child *tmp;
123
+
124
+	list_foreach_safe(cur, &children, list, tmp) {
125
+		if (cur->handlers->exit_notify_fn)
126
+			cur->handlers->exit_notify_fn(cur->pid, exit_code,
127
+						      cur->exit_notify_fn_data);
128
+	}
129
+}
130
+
131
+int
132
+aux_children_exit_wait(int exit_code)
133
+{
134
+	int cnt = 0;
135
+	struct aux_child *cur;
136
+	struct aux_child *tmp;
137
+
138
+	list_foreach_safe(cur, &children, list, tmp) {
139
+		aux_child_exit_fn wait_handler = cur->handlers->exit_wait_fn;
140
+
141
+
142
+		if (!wait_handler)
143
+			wait_handler = aux_child_wait_handler;
144
+
145
+		if (wait_handler(cur->pid, exit_code, cur->exit_wait_fn_data)
146
+		    == ACR_REMOVE_ME) {
147
+			list_remove(&cur->list);
148
+			free(cur);
149
+		} else {
150
+			cnt++;
151
+		}
152
+	}
153
+
154
+	return cnt;
155
+}
156
+
157
+enum aux_child_sig
158
+aux_child_sig_handler(pid_t pid, int status, void *data)
159
+{
160
+	if (!WIFSTOPPED(status))
161
+		remove_aux_child(pid);
162
+
163
+	return ACS_CONTINUE;
164
+}
165
+
166
+enum aux_child_ret
167
+aux_child_wait_handler(pid_t pid, int exit_code, void *data)
168
+{
169
+	while (waitpid(pid, NULL, 0) < 0 && errno == EINTR)
170
+		;
171
+
172
+	return ACR_REMOVE_ME;
173
+}

+ 99
- 0
aux_children.h View File

@@ -0,0 +1,99 @@
1
+/*
2
+ * Auxiliary children infrastructure support header.
3
+ *
4
+ * Copyright (c) 2017-2019 The strace developers.
5
+ * All rights reserved.
6
+ *
7
+ * SPDX-License-Identifier: LGPL-2.1-or-later
8
+ */
9
+
10
+#ifndef STRACE_AUX_CHILDREN_H
11
+#define STRACE_AUX_CHILDREN_H
12
+
13
+#include <stdbool.h>
14
+
15
+enum aux_child_ret {
16
+	ACR_NO_ACTION,
17
+	ACR_REMOVE_ME,
18
+};
19
+
20
+enum aux_child_sig {
21
+	ACS_NONE,
22
+	ACS_CONTINUE,
23
+	ACS_TERMINATE,
24
+};
25
+
26
+typedef enum aux_child_sig (*aux_child_signal_fn)(pid_t pid, int status,
27
+						  void *data);
28
+typedef enum aux_child_ret (*aux_child_exit_fn)(pid_t pid, int exit_code,
29
+						void *data);
30
+
31
+/**
32
+ * Structure containing handler functions that are called for an auxiliary
33
+ * child process.
34
+ */
35
+struct aux_child_handlers {
36
+	/**
37
+	 * Callback that is called when an auxiliary child is signalled.
38
+	 *
39
+	 * It accepts pid of the auxiliary child that was signalled, status,
40
+	 * as returned by the wait4() function, and data that is supplied in
41
+	 * signal_fn_data argument of register_aux_child_ex function (or NULL,
42
+	 * if the auxiliary child was registered with register_aux_child.
43
+	 * It has to return one of the entities defined in enum aux_child_sig
44
+	 * enumeration:
45
+	 *  - ACR_NO_ACTION, if no action has to be performed.
46
+	 *  - ACR_REMOVE_ME, if the auxiliary child has to be removed
47
+	 *                   from the auxiliary children list.
48
+	 *
49
+	 * The default callback (that is, the function which is called when this
50
+	 * field is set to NULL) is aux_child_sig_handler.
51
+	 */
52
+	aux_child_signal_fn signal_fn;
53
+	/**
54
+	 * Callback that is called when an auxiliary child has to be notified
55
+	 * about strace's termination.
56
+	 */
57
+	aux_child_exit_fn exit_notify_fn;
58
+	/**
59
+	 * A callback that is used for waiting for an auxiliary child.
60
+	 */
61
+	aux_child_exit_fn exit_wait_fn;
62
+};
63
+
64
+
65
+/**
66
+ * Register an auxiliary child process (that is, not a tracee).
67
+ */
68
+extern void register_aux_child_ex(pid_t pid, const struct aux_child_handlers *h,
69
+				  void *signal_fn_data,
70
+				  void *exit_notify_fn_data,
71
+				  void *exit_wait_fn_data);
72
+/* Do not remove other children from the aux_child handlers.  */
73
+extern void remove_aux_child(pid_t pid);
74
+
75
+/**
76
+ * A shorthand for registering an aux child with default handlers.
77
+ *
78
+ * @param pid Child's pid.
79
+ */
80
+static inline void
81
+register_aux_child(pid_t pid)
82
+{
83
+	register_aux_child_ex(pid, NULL, NULL, NULL, NULL);
84
+}
85
+
86
+extern bool have_aux_children(void);
87
+
88
+extern enum aux_child_sig aux_children_signal(pid_t pid, int status);
89
+extern void aux_children_exit_notify(int exit_code);
90
+extern int aux_children_exit_wait(int exit_code);
91
+
92
+/** Default signal handler, removes child from list */
93
+extern enum aux_child_sig aux_child_sig_handler(pid_t pid, int status,
94
+						void *data);
95
+/** Default wait handler, waits for the child and then returns ACR_REMOVE_ME */
96
+extern enum aux_child_ret aux_child_wait_handler(pid_t pid, int exit_code,
97
+						 void *data);
98
+
99
+#endif /* !STRACE_AUX_CHILDREN_H */

Loading…
Cancel
Save