diff options
Diffstat (limited to 'tools/testing/selftests/rseq/rseq.c')
| -rw-r--r-- | tools/testing/selftests/rseq/rseq.c | 55 | 
1 files changed, 47 insertions, 8 deletions
| diff --git a/tools/testing/selftests/rseq/rseq.c b/tools/testing/selftests/rseq/rseq.c index 4847e97ed049..7159eb777fd3 100644 --- a/tools/testing/selftests/rseq/rseq.c +++ b/tools/testing/selftests/rseq/rseq.c @@ -25,18 +25,27 @@  #include <syscall.h>  #include <assert.h>  #include <signal.h> +#include <limits.h>  #include "rseq.h"  #define ARRAY_SIZE(arr)	(sizeof(arr) / sizeof((arr)[0])) -__attribute__((tls_model("initial-exec"))) __thread -volatile struct rseq __rseq_abi = { +__thread volatile struct rseq __rseq_abi = {  	.cpu_id = RSEQ_CPU_ID_UNINITIALIZED,  }; -static __attribute__((tls_model("initial-exec"))) __thread -volatile int refcount; +/* + * Shared with other libraries. This library may take rseq ownership if it is + * still 0 when executing the library constructor. Set to 1 by library + * constructor when handling rseq. Set to 0 in destructor if handling rseq. + */ +int __rseq_handled; + +/* Whether this library have ownership of rseq registration. */ +static int rseq_ownership; + +static __thread volatile uint32_t __rseq_refcount;  static void signal_off_save(sigset_t *oldset)  { @@ -69,8 +78,14 @@ int rseq_register_current_thread(void)  	int rc, ret = 0;  	sigset_t oldset; +	if (!rseq_ownership) +		return 0;  	signal_off_save(&oldset); -	if (refcount++) +	if (__rseq_refcount == UINT_MAX) { +		ret = -1; +		goto end; +	} +	if (__rseq_refcount++)  		goto end;  	rc = sys_rseq(&__rseq_abi, sizeof(struct rseq), 0, RSEQ_SIG);  	if (!rc) { @@ -78,9 +93,9 @@ int rseq_register_current_thread(void)  		goto end;  	}  	if (errno != EBUSY) -		__rseq_abi.cpu_id = -2; +		__rseq_abi.cpu_id = RSEQ_CPU_ID_REGISTRATION_FAILED;  	ret = -1; -	refcount--; +	__rseq_refcount--;  end:  	signal_restore(oldset);  	return ret; @@ -91,13 +106,20 @@ int rseq_unregister_current_thread(void)  	int rc, ret = 0;  	sigset_t oldset; +	if (!rseq_ownership) +		return 0;  	signal_off_save(&oldset); -	if (--refcount) +	if (!__rseq_refcount) { +		ret = -1; +		goto end; +	} +	if (--__rseq_refcount)  		goto end;  	rc = sys_rseq(&__rseq_abi, sizeof(struct rseq),  		      RSEQ_FLAG_UNREGISTER, RSEQ_SIG);  	if (!rc)  		goto end; +	__rseq_refcount = 1;  	ret = -1;  end:  	signal_restore(oldset); @@ -115,3 +137,20 @@ int32_t rseq_fallback_current_cpu(void)  	}  	return cpu;  } + +void __attribute__((constructor)) rseq_init(void) +{ +	/* Check whether rseq is handled by another library. */ +	if (__rseq_handled) +		return; +	__rseq_handled = 1; +	rseq_ownership = 1; +} + +void __attribute__((destructor)) rseq_fini(void) +{ +	if (!rseq_ownership) +		return; +	__rseq_handled = 0; +	rseq_ownership = 0; +} |