rseq: output whether configure finds rseq syscall
[lttng-ust.git] / libringbuffer / rseq.c
1 /*
2 * rseq.c
3 *
4 * Copyright (C) 2016 Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
5 *
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; only
9 * version 2.1 of the License.
10 *
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
15 */
16
17 #define _GNU_SOURCE
18 #include <errno.h>
19 #include <sched.h>
20 #include <stdio.h>
21 #include <stdlib.h>
22 #include <string.h>
23 #include <unistd.h>
24 #include <syscall.h>
25 #include <assert.h>
26 #include <signal.h>
27
28 #include <rseq.h>
29
30 __attribute__((weak)) __thread volatile struct rseq __rseq_abi = {
31 .u.e.cpu_id = -1,
32 };
33
34 /* Own state, not shared with other libs. */
35 static __thread int rseq_registered;
36
37 static pthread_key_t rseq_key;
38
39
40 #ifdef __NR_rseq
41 static int sys_rseq(volatile struct rseq *rseq_abi, int flags)
42 {
43 return syscall(__NR_rseq, rseq_abi, flags);
44 }
45 #else
46 static int sys_rseq(volatile struct rseq *rseq_abi, int flags)
47 {
48 errno = ENOSYS;
49 return -1;
50 }
51 #endif
52
53 static void signal_off_save(sigset_t *oldset)
54 {
55 sigset_t set;
56 int ret;
57
58 sigfillset(&set);
59 ret = pthread_sigmask(SIG_BLOCK, &set, oldset);
60 if (ret)
61 abort();
62 }
63
64 static void signal_restore(sigset_t oldset)
65 {
66 int ret;
67
68 ret = pthread_sigmask(SIG_SETMASK, &oldset, NULL);
69 if (ret)
70 abort();
71 }
72
73 int rseq_unregister_current_thread(void)
74 {
75 sigset_t oldset;
76 int rc, ret = 0;
77
78 signal_off_save(&oldset);
79 if (rseq_registered) {
80 rc = sys_rseq(NULL, 0);
81 if (rc) {
82 fprintf(stderr, "Error: sys_rseq(...) failed(%d): %s\n",
83 errno, strerror(errno));
84 ret = -1;
85 goto end;
86 }
87 rseq_registered = 0;
88 }
89 end:
90 signal_restore(oldset);
91 return ret;
92 }
93
94 static void destroy_rseq_key(void *key)
95 {
96 if (rseq_unregister_current_thread())
97 abort();
98 }
99
100 int rseq_register_current_thread(void)
101 {
102 sigset_t oldset;
103 int rc, ret = 0;
104
105 signal_off_save(&oldset);
106 if (caa_likely(!rseq_registered)) {
107 rc = sys_rseq(&__rseq_abi, 0);
108 if (rc) {
109 fprintf(stderr, "Error: sys_rseq(...) failed(%d): %s\n",
110 errno, strerror(errno));
111 __rseq_abi.u.e.cpu_id = -2;
112 ret = -1;
113 goto end;
114 }
115 rseq_registered = 1;
116 assert(rseq_current_cpu_raw() >= 0);
117 /*
118 * Register destroy notifier. Pointer needs to
119 * be non-NULL.
120 */
121 if (pthread_setspecific(rseq_key, (void *)0x1))
122 abort();
123 }
124 end:
125 signal_restore(oldset);
126 return ret;
127 }
128
129 void rseq_init(void)
130 {
131 int ret;
132
133 ret = pthread_key_create(&rseq_key, destroy_rseq_key);
134 if (ret) {
135 errno = -ret;
136 perror("pthread_key_create");
137 abort();
138 }
139 }
140
141 void rseq_destroy(void)
142 {
143 int ret;
144
145 ret = pthread_key_delete(rseq_key);
146 if (ret) {
147 errno = -ret;
148 perror("pthread_key_delete");
149 abort();
150 }
151 }
This page took 0.055978 seconds and 5 git commands to generate.