1
2#include <inttypes.h>
3#include <unistd.h>
4#include <sys/syscall.h>
5#include <sys/types.h>
6#include <sys/mman.h>
7#include <pthread.h>
8#include <stdlib.h>
9#include <stdio.h>
10#include "debug.h"
11#include "tests.h"
12#include "machine.h"
13#include "thread_map.h"
14#include "map.h"
15#include "symbol.h"
16#include "thread.h"
17#include "util.h"
18
19#define THREADS 4
20
21static int go_away;
22
23struct thread_data {
24 pthread_t pt;
25 pid_t tid;
26 void *map;
27 int ready[2];
28};
29
30static struct thread_data threads[THREADS];
31
32static int thread_init(struct thread_data *td)
33{
34 void *map;
35
36 map = mmap(NULL, page_size,
37 PROT_READ|PROT_WRITE|PROT_EXEC,
38 MAP_SHARED|MAP_ANONYMOUS, -1, 0);
39
40 if (map == MAP_FAILED) {
41 perror("mmap failed");
42 return -1;
43 }
44
45 td->map = map;
46 td->tid = syscall(SYS_gettid);
47
48 pr_debug("tid = %d, map = %p\n", td->tid, map);
49 return 0;
50}
51
52static void *thread_fn(void *arg)
53{
54 struct thread_data *td = arg;
55 ssize_t ret;
56 int go = 0;
57
58 if (thread_init(td))
59 return NULL;
60
61
62 ret = write(td->ready[1], &go, sizeof(int));
63 if (ret != sizeof(int)) {
64 pr_err("failed to notify\n");
65 return NULL;
66 }
67
68 while (!go_away) {
69
70 usleep(100);
71 }
72
73 munmap(td->map, page_size);
74 return NULL;
75}
76
77static int thread_create(int i)
78{
79 struct thread_data *td = &threads[i];
80 int err, go;
81
82 if (pipe(td->ready))
83 return -1;
84
85 err = pthread_create(&td->pt, NULL, thread_fn, td);
86 if (!err) {
87
88 ssize_t ret = read(td->ready[0], &go, sizeof(int));
89 err = ret != sizeof(int);
90 }
91
92 close(td->ready[0]);
93 close(td->ready[1]);
94 return err;
95}
96
97static int threads_create(void)
98{
99 struct thread_data *td0 = &threads[0];
100 int i, err = 0;
101
102 go_away = 0;
103
104
105 if (thread_init(td0))
106 return -1;
107
108 for (i = 1; !err && i < THREADS; i++)
109 err = thread_create(i);
110
111 return err;
112}
113
114static int threads_destroy(void)
115{
116 struct thread_data *td0 = &threads[0];
117 int i, err = 0;
118
119
120 munmap(td0->map, page_size);
121
122 go_away = 1;
123
124 for (i = 1; !err && i < THREADS; i++)
125 err = pthread_join(threads[i].pt, NULL);
126
127 return err;
128}
129
130typedef int (*synth_cb)(struct machine *machine);
131
132static int synth_all(struct machine *machine)
133{
134 return perf_event__synthesize_threads(NULL,
135 perf_event__process,
136 machine, 0, 1);
137}
138
139static int synth_process(struct machine *machine)
140{
141 struct thread_map *map;
142 int err;
143
144 map = thread_map__new_by_pid(getpid());
145
146 err = perf_event__synthesize_thread_map(NULL, map,
147 perf_event__process,
148 machine, 0);
149
150 thread_map__put(map);
151 return err;
152}
153
154static int mmap_events(synth_cb synth)
155{
156 struct machine *machine;
157 int err, i;
158
159
160
161
162
163
164
165
166 TEST_ASSERT_VAL("failed to create threads", !threads_create());
167
168 machine = machine__new_host();
169
170 dump_trace = verbose > 1 ? 1 : 0;
171
172 err = synth(machine);
173
174 dump_trace = 0;
175
176 TEST_ASSERT_VAL("failed to destroy threads", !threads_destroy());
177 TEST_ASSERT_VAL("failed to synthesize maps", !err);
178
179
180
181
182
183 for (i = 0; i < THREADS; i++) {
184 struct thread_data *td = &threads[i];
185 struct addr_location al;
186 struct thread *thread;
187
188 thread = machine__findnew_thread(machine, getpid(), td->tid);
189
190 pr_debug("looking for map %p\n", td->map);
191
192 thread__find_map(thread, PERF_RECORD_MISC_USER,
193 (unsigned long) (td->map + 1), &al);
194
195 thread__put(thread);
196
197 if (!al.map) {
198 pr_debug("failed, couldn't find map\n");
199 err = -1;
200 break;
201 }
202
203 pr_debug("map %p, addr %" PRIx64 "\n", al.map, al.map->start);
204 }
205
206 machine__delete_threads(machine);
207 machine__delete(machine);
208 return err;
209}
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225int test__mmap_thread_lookup(struct test *test __maybe_unused, int subtest __maybe_unused)
226{
227
228 TEST_ASSERT_VAL("failed with sythesizing all",
229 !mmap_events(synth_all));
230
231
232 TEST_ASSERT_VAL("failed with sythesizing process",
233 !mmap_events(synth_process));
234
235 return 0;
236}
237