1
1
// SPDX-License-Identifier: GPL-2.0
2
2
3
3
#include <unistd.h>
4
+ #include <pthread.h>
4
5
#include <test_progs.h>
5
6
#include "uprobe_multi.skel.h"
6
7
#include "uprobe_multi_bench.skel.h"
@@ -27,7 +28,10 @@ noinline void uprobe_multi_func_3(void)
27
28
28
29
struct child {
29
30
int go [2 ];
31
+ int c2p [2 ]; /* child -> parent channel */
30
32
int pid ;
33
+ int tid ;
34
+ pthread_t thread ;
31
35
};
32
36
33
37
static void release_child (struct child * child )
@@ -38,6 +42,10 @@ static void release_child(struct child *child)
38
42
return ;
39
43
close (child -> go [1 ]);
40
44
close (child -> go [0 ]);
45
+ if (child -> thread )
46
+ pthread_join (child -> thread , NULL );
47
+ close (child -> c2p [0 ]);
48
+ close (child -> c2p [1 ]);
41
49
if (child -> pid > 0 )
42
50
waitpid (child -> pid , & child_status , 0 );
43
51
}
@@ -63,7 +71,7 @@ static struct child *spawn_child(void)
63
71
if (pipe (child .go ))
64
72
return NULL ;
65
73
66
- child .pid = fork ();
74
+ child .pid = child . tid = fork ();
67
75
if (child .pid < 0 ) {
68
76
release_child (& child );
69
77
errno = EINVAL ;
@@ -89,6 +97,66 @@ static struct child *spawn_child(void)
89
97
return & child ;
90
98
}
91
99
100
+ static void * child_thread (void * ctx )
101
+ {
102
+ struct child * child = ctx ;
103
+ int c = 0 , err ;
104
+
105
+ child -> tid = syscall (SYS_gettid );
106
+
107
+ /* let parent know we are ready */
108
+ err = write (child -> c2p [1 ], & c , 1 );
109
+ if (err != 1 )
110
+ pthread_exit (& err );
111
+
112
+ /* wait for parent's kick */
113
+ err = read (child -> go [0 ], & c , 1 );
114
+ if (err != 1 )
115
+ pthread_exit (& err );
116
+
117
+ uprobe_multi_func_1 ();
118
+ uprobe_multi_func_2 ();
119
+ uprobe_multi_func_3 ();
120
+
121
+ err = 0 ;
122
+ pthread_exit (& err );
123
+ }
124
+
125
+ static struct child * spawn_thread (void )
126
+ {
127
+ static struct child child ;
128
+ int c , err ;
129
+
130
+ /* pipe to notify child to execute the trigger functions */
131
+ if (pipe (child .go ))
132
+ return NULL ;
133
+ /* pipe to notify parent that child thread is ready */
134
+ if (pipe (child .c2p )) {
135
+ close (child .go [0 ]);
136
+ close (child .go [1 ]);
137
+ return NULL ;
138
+ }
139
+
140
+ child .pid = getpid ();
141
+
142
+ err = pthread_create (& child .thread , NULL , child_thread , & child );
143
+ if (err ) {
144
+ err = - errno ;
145
+ close (child .go [0 ]);
146
+ close (child .go [1 ]);
147
+ close (child .c2p [0 ]);
148
+ close (child .c2p [1 ]);
149
+ errno = - err ;
150
+ return NULL ;
151
+ }
152
+
153
+ err = read (child .c2p [0 ], & c , 1 );
154
+ if (!ASSERT_EQ (err , 1 , "child_thread_ready" ))
155
+ return NULL ;
156
+
157
+ return & child ;
158
+ }
159
+
92
160
static void uprobe_multi_test_run (struct uprobe_multi * skel , struct child * child )
93
161
{
94
162
skel -> bss -> uprobe_multi_func_1_addr = (__u64 ) uprobe_multi_func_1 ;
@@ -103,15 +171,22 @@ static void uprobe_multi_test_run(struct uprobe_multi *skel, struct child *child
103
171
* passed at the probe attach.
104
172
*/
105
173
skel -> bss -> pid = child ? 0 : getpid ();
174
+ skel -> bss -> expect_pid = child ? child -> pid : 0 ;
175
+
176
+ /* trigger all probes, if we are testing child *process*, just to make
177
+ * sure that PID filtering doesn't let through activations from wrong
178
+ * PIDs; when we test child *thread*, we don't want to do this to
179
+ * avoid double counting number of triggering events
180
+ */
181
+ if (!child || !child -> thread ) {
182
+ uprobe_multi_func_1 ();
183
+ uprobe_multi_func_2 ();
184
+ uprobe_multi_func_3 ();
185
+ }
106
186
107
187
if (child )
108
188
kick_child (child );
109
189
110
- /* trigger all probes */
111
- uprobe_multi_func_1 ();
112
- uprobe_multi_func_2 ();
113
- uprobe_multi_func_3 ();
114
-
115
190
/*
116
191
* There are 2 entry and 2 exit probe called for each uprobe_multi_func_[123]
117
192
* function and each slepable probe (6) increments uprobe_multi_sleep_result.
@@ -126,8 +201,12 @@ static void uprobe_multi_test_run(struct uprobe_multi *skel, struct child *child
126
201
127
202
ASSERT_EQ (skel -> bss -> uprobe_multi_sleep_result , 6 , "uprobe_multi_sleep_result" );
128
203
129
- if (child )
204
+ ASSERT_FALSE (skel -> bss -> bad_pid_seen , "bad_pid_seen" );
205
+
206
+ if (child ) {
130
207
ASSERT_EQ (skel -> bss -> child_pid , child -> pid , "uprobe_multi_child_pid" );
208
+ ASSERT_EQ (skel -> bss -> child_tid , child -> tid , "uprobe_multi_child_tid" );
209
+ }
131
210
}
132
211
133
212
static void test_skel_api (void )
@@ -210,6 +289,13 @@ test_attach_api(const char *binary, const char *pattern, struct bpf_uprobe_multi
210
289
return ;
211
290
212
291
__test_attach_api (binary , pattern , opts , child );
292
+
293
+ /* pid filter (thread) */
294
+ child = spawn_thread ();
295
+ if (!ASSERT_OK_PTR (child , "spawn_thread" ))
296
+ return ;
297
+
298
+ __test_attach_api (binary , pattern , opts , child );
213
299
}
214
300
215
301
static void test_attach_api_pattern (void )
@@ -495,6 +581,13 @@ static void test_link_api(void)
495
581
return ;
496
582
497
583
__test_link_api (child );
584
+
585
+ /* pid filter (thread) */
586
+ child = spawn_thread ();
587
+ if (!ASSERT_OK_PTR (child , "spawn_thread" ))
588
+ return ;
589
+
590
+ __test_link_api (child );
498
591
}
499
592
500
593
static void test_bench_attach_uprobe (void )
0 commit comments