at v5.0-rc7 117 lines 2.4 kB view raw
1// SPDX-License-Identifier: LGPL-2.1 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 18#define _GNU_SOURCE 19#include <errno.h> 20#include <sched.h> 21#include <stdio.h> 22#include <stdlib.h> 23#include <string.h> 24#include <unistd.h> 25#include <syscall.h> 26#include <assert.h> 27#include <signal.h> 28 29#include "rseq.h" 30 31#define ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0])) 32 33__attribute__((tls_model("initial-exec"))) __thread 34volatile struct rseq __rseq_abi = { 35 .cpu_id = RSEQ_CPU_ID_UNINITIALIZED, 36}; 37 38static __attribute__((tls_model("initial-exec"))) __thread 39volatile int refcount; 40 41static void signal_off_save(sigset_t *oldset) 42{ 43 sigset_t set; 44 int ret; 45 46 sigfillset(&set); 47 ret = pthread_sigmask(SIG_BLOCK, &set, oldset); 48 if (ret) 49 abort(); 50} 51 52static void signal_restore(sigset_t oldset) 53{ 54 int ret; 55 56 ret = pthread_sigmask(SIG_SETMASK, &oldset, NULL); 57 if (ret) 58 abort(); 59} 60 61static int sys_rseq(volatile struct rseq *rseq_abi, uint32_t rseq_len, 62 int flags, uint32_t sig) 63{ 64 return syscall(__NR_rseq, rseq_abi, rseq_len, flags, sig); 65} 66 67int rseq_register_current_thread(void) 68{ 69 int rc, ret = 0; 70 sigset_t oldset; 71 72 signal_off_save(&oldset); 73 if (refcount++) 74 goto end; 75 rc = sys_rseq(&__rseq_abi, sizeof(struct rseq), 0, RSEQ_SIG); 76 if (!rc) { 77 assert(rseq_current_cpu_raw() >= 0); 78 goto end; 79 } 80 if (errno != EBUSY) 81 __rseq_abi.cpu_id = -2; 82 ret = -1; 83 refcount--; 84end: 85 signal_restore(oldset); 86 return ret; 87} 88 89int rseq_unregister_current_thread(void) 90{ 91 int rc, ret = 0; 92 sigset_t oldset; 93 94 signal_off_save(&oldset); 95 if (--refcount) 96 goto end; 97 rc = sys_rseq(&__rseq_abi, sizeof(struct rseq), 98 RSEQ_FLAG_UNREGISTER, RSEQ_SIG); 99 if (!rc) 100 goto end; 101 ret = -1; 102end: 103 signal_restore(oldset); 104 return ret; 105} 106 107int32_t rseq_fallback_current_cpu(void) 108{ 109 int32_t cpu; 110 111 cpu = sched_getcpu(); 112 if (cpu < 0) { 113 perror("sched_getcpu()"); 114 abort(); 115 } 116 return cpu; 117}