Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0
0002 #include <inttypes.h>
0003 #include <unistd.h>
0004 #include <sys/syscall.h>
0005 #include <sys/types.h>
0006 #include <sys/mman.h>
0007 #include <pthread.h>
0008 #include <stdlib.h>
0009 #include <stdio.h>
0010 #include "debug.h"
0011 #include "event.h"
0012 #include "tests.h"
0013 #include "machine.h"
0014 #include "thread_map.h"
0015 #include "map.h"
0016 #include "symbol.h"
0017 #include "util/synthetic-events.h"
0018 #include "thread.h"
0019 #include <internal/lib.h> // page_size
0020 
0021 #define THREADS 4
0022 
0023 static int go_away;
0024 
0025 struct thread_data {
0026     pthread_t   pt;
0027     pid_t       tid;
0028     void        *map;
0029     int     ready[2];
0030 };
0031 
0032 static struct thread_data threads[THREADS];
0033 
0034 static int thread_init(struct thread_data *td)
0035 {
0036     void *map;
0037 
0038     map = mmap(NULL, page_size,
0039            PROT_READ|PROT_WRITE|PROT_EXEC,
0040            MAP_SHARED|MAP_ANONYMOUS, -1, 0);
0041 
0042     if (map == MAP_FAILED) {
0043         perror("mmap failed");
0044         return -1;
0045     }
0046 
0047     td->map = map;
0048     td->tid = syscall(SYS_gettid);
0049 
0050     pr_debug("tid = %d, map = %p\n", td->tid, map);
0051     return 0;
0052 }
0053 
0054 static void *thread_fn(void *arg)
0055 {
0056     struct thread_data *td = arg;
0057     ssize_t ret;
0058     int go = 0;
0059 
0060     if (thread_init(td))
0061         return NULL;
0062 
0063     /* Signal thread_create thread is initialized. */
0064     ret = write(td->ready[1], &go, sizeof(int));
0065     if (ret != sizeof(int)) {
0066         pr_err("failed to notify\n");
0067         return NULL;
0068     }
0069 
0070     while (!go_away) {
0071         /* Waiting for main thread to kill us. */
0072         usleep(100);
0073     }
0074 
0075     munmap(td->map, page_size);
0076     return NULL;
0077 }
0078 
0079 static int thread_create(int i)
0080 {
0081     struct thread_data *td = &threads[i];
0082     int err, go;
0083 
0084     if (pipe(td->ready))
0085         return -1;
0086 
0087     err = pthread_create(&td->pt, NULL, thread_fn, td);
0088     if (!err) {
0089         /* Wait for thread initialization. */
0090         ssize_t ret = read(td->ready[0], &go, sizeof(int));
0091         err = ret != sizeof(int);
0092     }
0093 
0094     close(td->ready[0]);
0095     close(td->ready[1]);
0096     return err;
0097 }
0098 
0099 static int threads_create(void)
0100 {
0101     struct thread_data *td0 = &threads[0];
0102     int i, err = 0;
0103 
0104     go_away = 0;
0105 
0106     /* 0 is main thread */
0107     if (thread_init(td0))
0108         return -1;
0109 
0110     for (i = 1; !err && i < THREADS; i++)
0111         err = thread_create(i);
0112 
0113     return err;
0114 }
0115 
0116 static int threads_destroy(void)
0117 {
0118     struct thread_data *td0 = &threads[0];
0119     int i, err = 0;
0120 
0121     /* cleanup the main thread */
0122     munmap(td0->map, page_size);
0123 
0124     go_away = 1;
0125 
0126     for (i = 1; !err && i < THREADS; i++)
0127         err = pthread_join(threads[i].pt, NULL);
0128 
0129     return err;
0130 }
0131 
0132 typedef int (*synth_cb)(struct machine *machine);
0133 
0134 static int synth_all(struct machine *machine)
0135 {
0136     return perf_event__synthesize_threads(NULL,
0137                           perf_event__process,
0138                           machine, 1, 0, 1);
0139 }
0140 
0141 static int synth_process(struct machine *machine)
0142 {
0143     struct perf_thread_map *map;
0144     int err;
0145 
0146     map = thread_map__new_by_pid(getpid());
0147 
0148     err = perf_event__synthesize_thread_map(NULL, map,
0149                         perf_event__process,
0150                         machine, 1, 0);
0151 
0152     perf_thread_map__put(map);
0153     return err;
0154 }
0155 
0156 static int mmap_events(synth_cb synth)
0157 {
0158     struct machine *machine;
0159     int err, i;
0160 
0161     /*
0162      * The threads_create will not return before all threads
0163      * are spawned and all created memory map.
0164      *
0165      * They will loop until threads_destroy is called, so we
0166      * can safely run synthesizing function.
0167      */
0168     TEST_ASSERT_VAL("failed to create threads", !threads_create());
0169 
0170     machine = machine__new_host();
0171 
0172     dump_trace = verbose > 1 ? 1 : 0;
0173 
0174     err = synth(machine);
0175 
0176     dump_trace = 0;
0177 
0178     TEST_ASSERT_VAL("failed to destroy threads", !threads_destroy());
0179     TEST_ASSERT_VAL("failed to synthesize maps", !err);
0180 
0181     /*
0182      * All data is synthesized, try to find map for each
0183      * thread object.
0184      */
0185     for (i = 0; i < THREADS; i++) {
0186         struct thread_data *td = &threads[i];
0187         struct addr_location al;
0188         struct thread *thread;
0189 
0190         thread = machine__findnew_thread(machine, getpid(), td->tid);
0191 
0192         pr_debug("looking for map %p\n", td->map);
0193 
0194         thread__find_map(thread, PERF_RECORD_MISC_USER,
0195                  (unsigned long) (td->map + 1), &al);
0196 
0197         thread__put(thread);
0198 
0199         if (!al.map) {
0200             pr_debug("failed, couldn't find map\n");
0201             err = -1;
0202             break;
0203         }
0204 
0205         pr_debug("map %p, addr %" PRIx64 "\n", al.map, al.map->start);
0206     }
0207 
0208     machine__delete_threads(machine);
0209     machine__delete(machine);
0210     return err;
0211 }
0212 
0213 /*
0214  * This test creates 'THREADS' number of threads (including
0215  * main thread) and each thread creates memory map.
0216  *
0217  * When threads are created, we synthesize them with both
0218  * (separate tests):
0219  *   perf_event__synthesize_thread_map (process based)
0220  *   perf_event__synthesize_threads    (global)
0221  *
0222  * We test we can find all memory maps via:
0223  *   thread__find_map
0224  *
0225  * by using all thread objects.
0226  */
0227 static int test__mmap_thread_lookup(struct test_suite *test __maybe_unused, int subtest __maybe_unused)
0228 {
0229     /* perf_event__synthesize_threads synthesize */
0230     TEST_ASSERT_VAL("failed with sythesizing all",
0231             !mmap_events(synth_all));
0232 
0233     /* perf_event__synthesize_thread_map synthesize */
0234     TEST_ASSERT_VAL("failed with sythesizing process",
0235             !mmap_events(synth_process));
0236 
0237     return 0;
0238 }
0239 
0240 DEFINE_SUITE("Lookup mmap thread", mmap_thread_lookup);