Linux Audio

Check our new training course

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