123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234 |
- #include <unistd.h>
- #include <sys/syscall.h>
- #include <sys/types.h>
- #include <sys/mman.h>
- #include <pthread.h>
- #include <stdlib.h>
- #include <stdio.h>
- #include "debug.h"
- #include "tests.h"
- #include "machine.h"
- #include "thread_map.h"
- #include "symbol.h"
- #include "thread.h"
- #define THREADS 4
- static int go_away;
- struct thread_data {
- pthread_t pt;
- pid_t tid;
- void *map;
- int ready[2];
- };
- static struct thread_data threads[THREADS];
- static int thread_init(struct thread_data *td)
- {
- void *map;
- map = mmap(NULL, page_size,
- PROT_READ|PROT_WRITE|PROT_EXEC,
- MAP_SHARED|MAP_ANONYMOUS, -1, 0);
- if (map == MAP_FAILED) {
- perror("mmap failed");
- return -1;
- }
- td->map = map;
- td->tid = syscall(SYS_gettid);
- pr_debug("tid = %d, map = %p\n", td->tid, map);
- return 0;
- }
- static void *thread_fn(void *arg)
- {
- struct thread_data *td = arg;
- ssize_t ret;
- int go;
- if (thread_init(td))
- return NULL;
- /* Signal thread_create thread is initialized. */
- ret = write(td->ready[1], &go, sizeof(int));
- if (ret != sizeof(int)) {
- pr_err("failed to notify\n");
- return NULL;
- }
- while (!go_away) {
- /* Waiting for main thread to kill us. */
- usleep(100);
- }
- munmap(td->map, page_size);
- return NULL;
- }
- static int thread_create(int i)
- {
- struct thread_data *td = &threads[i];
- int err, go;
- if (pipe(td->ready))
- return -1;
- err = pthread_create(&td->pt, NULL, thread_fn, td);
- if (!err) {
- /* Wait for thread initialization. */
- ssize_t ret = read(td->ready[0], &go, sizeof(int));
- err = ret != sizeof(int);
- }
- close(td->ready[0]);
- close(td->ready[1]);
- return err;
- }
- static int threads_create(void)
- {
- struct thread_data *td0 = &threads[0];
- int i, err = 0;
- go_away = 0;
- /* 0 is main thread */
- if (thread_init(td0))
- return -1;
- for (i = 1; !err && i < THREADS; i++)
- err = thread_create(i);
- return err;
- }
- static int threads_destroy(void)
- {
- struct thread_data *td0 = &threads[0];
- int i, err = 0;
- /* cleanup the main thread */
- munmap(td0->map, page_size);
- go_away = 1;
- for (i = 1; !err && i < THREADS; i++)
- err = pthread_join(threads[i].pt, NULL);
- return err;
- }
- typedef int (*synth_cb)(struct machine *machine);
- static int synth_all(struct machine *machine)
- {
- return perf_event__synthesize_threads(NULL,
- perf_event__process,
- machine, 0, 500);
- }
- static int synth_process(struct machine *machine)
- {
- struct thread_map *map;
- int err;
- map = thread_map__new_by_pid(getpid());
- err = perf_event__synthesize_thread_map(NULL, map,
- perf_event__process,
- machine, 0, 500);
- thread_map__put(map);
- return err;
- }
- static int mmap_events(synth_cb synth)
- {
- struct machine *machine;
- int err, i;
- /*
- * The threads_create will not return before all threads
- * are spawned and all created memory map.
- *
- * They will loop until threads_destroy is called, so we
- * can safely run synthesizing function.
- */
- TEST_ASSERT_VAL("failed to create threads", !threads_create());
- machine = machine__new_host();
- dump_trace = verbose > 1 ? 1 : 0;
- err = synth(machine);
- dump_trace = 0;
- TEST_ASSERT_VAL("failed to destroy threads", !threads_destroy());
- TEST_ASSERT_VAL("failed to synthesize maps", !err);
- /*
- * All data is synthesized, try to find map for each
- * thread object.
- */
- for (i = 0; i < THREADS; i++) {
- struct thread_data *td = &threads[i];
- struct addr_location al;
- struct thread *thread;
- thread = machine__findnew_thread(machine, getpid(), td->tid);
- pr_debug("looking for map %p\n", td->map);
- thread__find_addr_map(thread,
- PERF_RECORD_MISC_USER, MAP__FUNCTION,
- (unsigned long) (td->map + 1), &al);
- thread__put(thread);
- if (!al.map) {
- pr_debug("failed, couldn't find map\n");
- err = -1;
- break;
- }
- pr_debug("map %p, addr %" PRIx64 "\n", al.map, al.map->start);
- }
- machine__delete_threads(machine);
- machine__delete(machine);
- return err;
- }
- /*
- * This test creates 'THREADS' number of threads (including
- * main thread) and each thread creates memory map.
- *
- * When threads are created, we synthesize them with both
- * (separate tests):
- * perf_event__synthesize_thread_map (process based)
- * perf_event__synthesize_threads (global)
- *
- * We test we can find all memory maps via:
- * thread__find_addr_map
- *
- * by using all thread objects.
- */
- int test__mmap_thread_lookup(int subtest __maybe_unused)
- {
- /* perf_event__synthesize_threads synthesize */
- TEST_ASSERT_VAL("failed with sythesizing all",
- !mmap_events(synth_all));
- /* perf_event__synthesize_thread_map synthesize */
- TEST_ASSERT_VAL("failed with sythesizing process",
- !mmap_events(synth_process));
- return 0;
- }
|