Commit | Line | Data |
---|---|---|
b54c5158 MD |
1 | /* |
2 | * Basic test coverage for critical regions and rseq_current_cpu(). | |
3 | */ | |
4 | ||
5 | #define _GNU_SOURCE | |
6 | #include <assert.h> | |
7 | #include <sched.h> | |
8 | #include <signal.h> | |
9 | #include <stdio.h> | |
10 | #include <string.h> | |
11 | #include <sys/time.h> | |
12 | ||
13 | #include <rseq.h> | |
14 | ||
15 | volatile int signals_delivered; | |
16 | volatile __thread struct rseq_state sigtest_start; | |
17 | static struct rseq_lock rseq_lock; | |
18 | ||
19 | void test_cpu_pointer(void) | |
20 | { | |
21 | cpu_set_t affinity, test_affinity; | |
22 | int i; | |
23 | ||
24 | sched_getaffinity(0, sizeof(affinity), &affinity); | |
25 | CPU_ZERO(&test_affinity); | |
26 | for (i = 0; i < CPU_SETSIZE; i++) { | |
27 | if (CPU_ISSET(i, &affinity)) { | |
28 | CPU_SET(i, &test_affinity); | |
29 | sched_setaffinity(0, sizeof(test_affinity), | |
30 | &test_affinity); | |
31 | assert(rseq_current_cpu() == sched_getcpu()); | |
32 | assert(rseq_current_cpu() == i); | |
33 | CPU_CLR(i, &test_affinity); | |
34 | } | |
35 | } | |
36 | sched_setaffinity(0, sizeof(affinity), &affinity); | |
37 | } | |
38 | ||
39 | /* | |
40 | * This depends solely on some environmental event triggering a counter | |
41 | * increase. | |
42 | */ | |
43 | void test_critical_section(void) | |
44 | { | |
45 | struct rseq_state start; | |
46 | uint32_t event_counter; | |
47 | ||
a2ac5f39 | 48 | start = rseq_start_rlock(&rseq_lock); |
b54c5158 MD |
49 | event_counter = start.event_counter; |
50 | do { | |
a2ac5f39 | 51 | start = rseq_start_rlock(&rseq_lock); |
b54c5158 MD |
52 | } while (start.event_counter == event_counter); |
53 | } | |
54 | ||
55 | void test_signal_interrupt_handler(int signo) | |
56 | { | |
57 | struct rseq_state current; | |
58 | ||
a2ac5f39 | 59 | current = rseq_start_rlock(&rseq_lock); |
b54c5158 MD |
60 | /* |
61 | * The potential critical section bordered by 'start' must be | |
62 | * invalid. | |
63 | */ | |
64 | assert(current.event_counter != sigtest_start.event_counter); | |
65 | signals_delivered++; | |
66 | } | |
67 | ||
68 | void test_signal_interrupts(void) | |
69 | { | |
70 | struct itimerval it = { { 0, 1 }, { 0, 1 } }; | |
71 | ||
72 | setitimer(ITIMER_PROF, &it, NULL); | |
73 | signal(SIGPROF, test_signal_interrupt_handler); | |
74 | ||
75 | do { | |
a2ac5f39 | 76 | sigtest_start = rseq_start_rlock(&rseq_lock); |
b54c5158 MD |
77 | } while (signals_delivered < 10); |
78 | setitimer(ITIMER_PROF, NULL, NULL); | |
79 | } | |
80 | ||
81 | int main(int argc, char **argv) | |
82 | { | |
83 | if (rseq_init_lock(&rseq_lock)) { | |
84 | perror("rseq_init_lock"); | |
85 | return -1; | |
86 | } | |
87 | if (rseq_register_current_thread()) | |
88 | goto init_thread_error; | |
89 | printf("testing current cpu\n"); | |
90 | test_cpu_pointer(); | |
91 | printf("testing critical section\n"); | |
92 | test_critical_section(); | |
93 | printf("testing critical section is interrupted by signal\n"); | |
94 | test_signal_interrupts(); | |
95 | if (rseq_unregister_current_thread()) | |
96 | goto init_thread_error; | |
97 | if (rseq_destroy_lock(&rseq_lock)) { | |
98 | perror("rseq_destroy_lock"); | |
99 | return -1; | |
100 | } | |
101 | return 0; | |
102 | ||
103 | init_thread_error: | |
104 | if (rseq_destroy_lock(&rseq_lock)) | |
105 | perror("rseq_destroy_lock"); | |
106 | return -1; | |
107 | } |