Line data Source code
1 : #define _GNU_SOURCE 2 : #include "fd_tile.h" 3 : 4 : #include <errno.h> 5 : #include <unistd.h> 6 : #include <sys/syscall.h> 7 : 8 : /* glibc>=2.35 (and RHEL 9's 2.34 backport) registers rseq on every 9 : thread and exports the area through <sys/rseq.h>. Older glibc and 10 : musl register nothing, so there is nothing to unregister. */ 11 : #if defined(__has_include) 12 : #if __has_include(<sys/rseq.h>) 13 : #include <sys/rseq.h> 14 : #define FD_TILE_HAS_GLIBC_RSEQ 1 15 : #endif 16 : #endif 17 : #ifndef FD_TILE_HAS_GLIBC_RSEQ 18 : #define FD_TILE_HAS_GLIBC_RSEQ 0 19 : #endif 20 : 21 : int 22 0 : fd_tile_rseq_unregister( void ) { 23 0 : #if FD_HAS_X86 && FD_TILE_HAS_GLIBC_RSEQ 24 0 : if( FD_UNLIKELY( !__rseq_size ) ) return 0; /* glibc did not register rseq */ 25 : 26 0 : ulong tp; __asm__( "mov %%fs:0, %0" : "=r"(tp) ); /* x86-64 thread pointer */ 27 0 : struct rseq * rs = (struct rseq *)( tp + (ulong)__rseq_offset ); 28 0 : if( FD_UNLIKELY( (int)FD_VOLATILE_CONST( rs->cpu_id )<0 ) ) return 0; /* unregistered or registration failed */ 29 : 30 : /* The kernel requires the exact registered length to unregister. 31 : glibc registers max(__rseq_size,32) bytes, where __rseq_size is the 32 : used feature size (32 or 20 for glibc<2.41; AT_RSEQ_FEATURE_SIZE for 33 : glibc>=2.41, e.g. 28, or 33 on Linux>=7.0). The length is not 34 : rounded up to the area alignment. */ 35 0 : uint len = fd_uint_max( __rseq_size, 32U ); 36 0 : if( FD_UNLIKELY( syscall( SYS_rseq, rs, len, RSEQ_FLAG_UNREGISTER, 0x53053053U /* x86 RSEQ_SIG */ ) ) ) { 37 0 : FD_LOG_WARNING(( "rseq(RSEQ_FLAG_UNREGISTER) failed (%i-%s)", errno, fd_io_strerror( errno ) )); 38 0 : return 0; 39 0 : } 40 0 : return 1; 41 : #else 42 : return 0; /* no glibc rseq area, or not x86-64 */ 43 : #endif 44 0 : }