rseq: output whether configure finds rseq syscall
[lttng-ust.git] / libringbuffer / rseq.c
CommitLineData
b76e5200
MD
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>
b76e5200
MD
27
28#include <rseq.h>
29
b76e5200
MD
30__attribute__((weak)) __thread volatile struct rseq __rseq_abi = {
31 .u.e.cpu_id = -1,
32};
33
26cc635c
MD
34/* Own state, not shared with other libs. */
35static __thread int rseq_registered;
36
37static pthread_key_t rseq_key;
38
39
40#ifdef __NR_rseq
b76e5200
MD
41static int sys_rseq(volatile struct rseq *rseq_abi, int flags)
42{
43 return syscall(__NR_rseq, rseq_abi, flags);
44}
26cc635c
MD
45#else
46static int sys_rseq(volatile struct rseq *rseq_abi, int flags)
47{
48 errno = ENOSYS;
49 return -1;
50}
51#endif
b76e5200 52
b76e5200
MD
53static 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
64static 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
26cc635c
MD
73int 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 }
89end:
90 signal_restore(oldset);
91 return ret;
92}
93
94static void destroy_rseq_key(void *key)
95{
96 if (rseq_unregister_current_thread())
97 abort();
98}
99
38bfb073 100int rseq_register_current_thread(void)
b76e5200 101{
26cc635c
MD
102 sigset_t oldset;
103 int rc, ret = 0;
b76e5200 104
26cc635c
MD
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();
b76e5200 123 }
26cc635c
MD
124end:
125 signal_restore(oldset);
126 return ret;
b76e5200
MD
127}
128
26cc635c 129void rseq_init(void)
b76e5200 130{
26cc635c 131 int ret;
b76e5200 132
26cc635c
MD
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
141void 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();
b76e5200 150 }
b76e5200 151}
This page took 0.03249 seconds and 5 git commands to generate.