Remove "weak" attribute from symbols
[librseq.git] / src / rseq.c
1 // SPDX-License-Identifier: LGPL-2.1-only
2 /*
3 * rseq.c
4 *
5 * Copyright (C) 2016 Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
6 *
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Lesser General Public
9 * License as published by the Free Software Foundation; only
10 * version 2.1 of the License.
11 *
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
16 */
17 #ifndef _GNU_SOURCE
18 #define _GNU_SOURCE
19 #endif
20 #include <errno.h>
21 #include <sched.h>
22 #include <stdio.h>
23 #include <stdlib.h>
24 #include <string.h>
25 #include <unistd.h>
26 #include <syscall.h>
27 #include <assert.h>
28 #include <signal.h>
29 #include <limits.h>
30
31 #include <rseq/rseq.h>
32
33 #define ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0]))
34
35 __thread
36 volatile struct rseq __rseq_abi = {
37 .cpu_id = RSEQ_CPU_ID_UNINITIALIZED,
38 };
39
40 __thread
41 volatile uint32_t __rseq_refcount;
42
43 static int sys_rseq(volatile struct rseq *rseq_abi, uint32_t rseq_len,
44 int flags, uint32_t sig)
45 {
46 return syscall(__NR_rseq, rseq_abi, rseq_len, flags, sig);
47 }
48
49 int rseq_available(void)
50 {
51 int rc;
52
53 rc = sys_rseq(NULL, 0, 0, 0);
54 if (rc != -1)
55 abort();
56 switch (errno) {
57 case ENOSYS:
58 return 0;
59 case EINVAL:
60 return 1;
61 default:
62 abort();
63 }
64 }
65
66 static void signal_off_save(sigset_t *oldset)
67 {
68 sigset_t set;
69 int ret;
70
71 sigfillset(&set);
72 ret = pthread_sigmask(SIG_BLOCK, &set, oldset);
73 if (ret)
74 abort();
75 }
76
77 static void signal_restore(sigset_t oldset)
78 {
79 int ret;
80
81 ret = pthread_sigmask(SIG_SETMASK, &oldset, NULL);
82 if (ret)
83 abort();
84 }
85
86 int rseq_register_current_thread(void)
87 {
88 int rc, ret = 0;
89 sigset_t oldset;
90
91 signal_off_save(&oldset);
92 if (__rseq_refcount == UINT_MAX) {
93 ret = -1;
94 goto end;
95 }
96 if (__rseq_refcount++)
97 goto end;
98 rc = sys_rseq(&__rseq_abi, sizeof(struct rseq), 0, RSEQ_SIG);
99 if (!rc) {
100 assert(rseq_current_cpu_raw() >= 0);
101 goto end;
102 }
103 if (errno != EBUSY)
104 __rseq_abi.cpu_id = RSEQ_CPU_ID_REGISTRATION_FAILED;
105 ret = -1;
106 __rseq_refcount--;
107 end:
108 signal_restore(oldset);
109 return ret;
110 }
111
112 int rseq_unregister_current_thread(void)
113 {
114 int rc, ret = 0;
115 sigset_t oldset;
116
117 signal_off_save(&oldset);
118 if (!__rseq_refcount) {
119 ret = -1;
120 goto end;
121 }
122 if (--__rseq_refcount)
123 goto end;
124 rc = sys_rseq(&__rseq_abi, sizeof(struct rseq),
125 RSEQ_FLAG_UNREGISTER, RSEQ_SIG);
126 if (!rc)
127 goto end;
128 ret = -1;
129 end:
130 signal_restore(oldset);
131 return ret;
132 }
133
134 int32_t rseq_fallback_current_cpu(void)
135 {
136 int32_t cpu;
137
138 cpu = sched_getcpu();
139 if (cpu < 0) {
140 perror("sched_getcpu()");
141 abort();
142 }
143 return cpu;
144 }
This page took 0.03388 seconds and 4 git commands to generate.