rseq.c 2.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117
  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. #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. #include "rseq.h"
  28. #define ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0]))
  29. __attribute__((tls_model("initial-exec"))) __thread
  30. volatile struct rseq __rseq_abi = {
  31. .cpu_id = RSEQ_CPU_ID_UNINITIALIZED,
  32. };
  33. static __attribute__((tls_model("initial-exec"))) __thread
  34. volatile int refcount;
  35. static void signal_off_save(sigset_t *oldset)
  36. {
  37. sigset_t set;
  38. int ret;
  39. sigfillset(&set);
  40. ret = pthread_sigmask(SIG_BLOCK, &set, oldset);
  41. if (ret)
  42. abort();
  43. }
  44. static void signal_restore(sigset_t oldset)
  45. {
  46. int ret;
  47. ret = pthread_sigmask(SIG_SETMASK, &oldset, NULL);
  48. if (ret)
  49. abort();
  50. }
  51. static int sys_rseq(volatile struct rseq *rseq_abi, uint32_t rseq_len,
  52. int flags, uint32_t sig)
  53. {
  54. return syscall(__NR_rseq, rseq_abi, rseq_len, flags, sig);
  55. }
  56. int rseq_register_current_thread(void)
  57. {
  58. int rc, ret = 0;
  59. sigset_t oldset;
  60. signal_off_save(&oldset);
  61. if (refcount++)
  62. goto end;
  63. rc = sys_rseq(&__rseq_abi, sizeof(struct rseq), 0, RSEQ_SIG);
  64. if (!rc) {
  65. assert(rseq_current_cpu_raw() >= 0);
  66. goto end;
  67. }
  68. if (errno != EBUSY)
  69. __rseq_abi.cpu_id = -2;
  70. ret = -1;
  71. refcount--;
  72. end:
  73. signal_restore(oldset);
  74. return ret;
  75. }
  76. int rseq_unregister_current_thread(void)
  77. {
  78. int rc, ret = 0;
  79. sigset_t oldset;
  80. signal_off_save(&oldset);
  81. if (--refcount)
  82. goto end;
  83. rc = sys_rseq(&__rseq_abi, sizeof(struct rseq),
  84. RSEQ_FLAG_UNREGISTER, RSEQ_SIG);
  85. if (!rc)
  86. goto end;
  87. ret = -1;
  88. end:
  89. signal_restore(oldset);
  90. return ret;
  91. }
  92. int32_t rseq_fallback_current_cpu(void)
  93. {
  94. int32_t cpu;
  95. cpu = sched_getcpu();
  96. if (cpu < 0) {
  97. perror("sched_getcpu()");
  98. abort();
  99. }
  100. return cpu;
  101. }