Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

selftests: vDSO: simplify getrandom thread local storage and structs

Rather than using pthread_get/set_specific, just use gcc's __thread
annotation, which is noticeably faster and makes the code more obvious.

Also, just have one simplified struct called vgrnd, instead of trying to
split things up semantically. Those divisions were useful when this code
was split across several commit *messages*, but doesn't make as much
sense within a single file. This should make the code more clear and
provide a better example for implementers.

Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>

+27 -40
+27 -40
tools/testing/selftests/vDSO/vdso_test_getrandom.c
··· 38 38 pthread_mutex_t lock; 39 39 void **states; 40 40 size_t len, cap; 41 - } grnd_allocator = { 42 - .lock = PTHREAD_MUTEX_INITIALIZER 43 - }; 44 - 45 - static struct { 46 41 ssize_t(*fn)(void *, size_t, unsigned long, void *, size_t); 47 - pthread_key_t key; 48 - pthread_once_t initialized; 49 42 struct vgetrandom_opaque_params params; 50 - } grnd_ctx = { 51 - .initialized = PTHREAD_ONCE_INIT 43 + } vgrnd = { 44 + .lock = PTHREAD_MUTEX_INITIALIZER 52 45 }; 53 46 54 47 static void *vgetrandom_get_state(void) 55 48 { 56 49 void *state = NULL; 57 50 58 - pthread_mutex_lock(&grnd_allocator.lock); 59 - if (!grnd_allocator.len) { 51 + pthread_mutex_lock(&vgrnd.lock); 52 + if (!vgrnd.len) { 60 53 size_t page_size = getpagesize(); 61 54 size_t new_cap; 62 55 size_t alloc_size, num = sysconf(_SC_NPROCESSORS_ONLN); /* Just a decent heuristic. */ 63 56 void *new_block, *new_states; 64 57 65 - alloc_size = (num * grnd_ctx.params.size_of_opaque_state + page_size - 1) & (~(page_size - 1)); 66 - num = (page_size / grnd_ctx.params.size_of_opaque_state) * (alloc_size / page_size); 67 - new_block = mmap(0, alloc_size, grnd_ctx.params.mmap_prot, grnd_ctx.params.mmap_flags, -1, 0); 58 + alloc_size = (num * vgrnd.params.size_of_opaque_state + page_size - 1) & (~(page_size - 1)); 59 + num = (page_size / vgrnd.params.size_of_opaque_state) * (alloc_size / page_size); 60 + new_block = mmap(0, alloc_size, vgrnd.params.mmap_prot, vgrnd.params.mmap_flags, -1, 0); 68 61 if (new_block == MAP_FAILED) 69 62 goto out; 70 63 71 - new_cap = grnd_allocator.cap + num; 72 - new_states = reallocarray(grnd_allocator.states, new_cap, sizeof(*grnd_allocator.states)); 64 + new_cap = vgrnd.cap + num; 65 + new_states = reallocarray(vgrnd.states, new_cap, sizeof(*vgrnd.states)); 73 66 if (!new_states) 74 67 goto unmap; 75 - grnd_allocator.cap = new_cap; 76 - grnd_allocator.states = new_states; 68 + vgrnd.cap = new_cap; 69 + vgrnd.states = new_states; 77 70 78 71 for (size_t i = 0; i < num; ++i) { 79 - if (((uintptr_t)new_block & (page_size - 1)) + grnd_ctx.params.size_of_opaque_state > page_size) 72 + if (((uintptr_t)new_block & (page_size - 1)) + vgrnd.params.size_of_opaque_state > page_size) 80 73 new_block = (void *)(((uintptr_t)new_block + page_size - 1) & (~(page_size - 1))); 81 - grnd_allocator.states[i] = new_block; 82 - new_block += grnd_ctx.params.size_of_opaque_state; 74 + vgrnd.states[i] = new_block; 75 + new_block += vgrnd.params.size_of_opaque_state; 83 76 } 84 - grnd_allocator.len = num; 77 + vgrnd.len = num; 85 78 goto success; 86 79 87 80 unmap: ··· 82 89 goto out; 83 90 } 84 91 success: 85 - state = grnd_allocator.states[--grnd_allocator.len]; 92 + state = vgrnd.states[--vgrnd.len]; 86 93 87 94 out: 88 - pthread_mutex_unlock(&grnd_allocator.lock); 95 + pthread_mutex_unlock(&vgrnd.lock); 89 96 return state; 90 97 } 91 98 ··· 93 100 { 94 101 if (!state) 95 102 return; 96 - pthread_mutex_lock(&grnd_allocator.lock); 97 - grnd_allocator.states[grnd_allocator.len++] = state; 98 - pthread_mutex_unlock(&grnd_allocator.lock); 103 + pthread_mutex_lock(&vgrnd.lock); 104 + vgrnd.states[vgrnd.len++] = state; 105 + pthread_mutex_unlock(&vgrnd.lock); 99 106 } 100 107 101 108 static void vgetrandom_init(void) 102 109 { 103 - if (pthread_key_create(&grnd_ctx.key, vgetrandom_put_state) != 0) 104 - return; 105 110 unsigned long sysinfo_ehdr = getauxval(AT_SYSINFO_EHDR); 106 111 if (!sysinfo_ehdr) { 107 112 printf("AT_SYSINFO_EHDR is not present!\n"); 108 113 exit(KSFT_SKIP); 109 114 } 110 115 vdso_init_from_sysinfo_ehdr(sysinfo_ehdr); 111 - grnd_ctx.fn = (__typeof__(grnd_ctx.fn))vdso_sym("LINUX_2.6", "__vdso_getrandom"); 112 - if (!grnd_ctx.fn) { 116 + vgrnd.fn = (__typeof__(vgrnd.fn))vdso_sym("LINUX_2.6", "__vdso_getrandom"); 117 + if (!vgrnd.fn) { 113 118 printf("__vdso_getrandom is missing!\n"); 114 119 exit(KSFT_FAIL); 115 120 } 116 - if (grnd_ctx.fn(NULL, 0, 0, &grnd_ctx.params, ~0UL) != 0) { 121 + if (vgrnd.fn(NULL, 0, 0, &vgrnd.params, ~0UL) != 0) { 117 122 printf("failed to fetch vgetrandom params!\n"); 118 123 exit(KSFT_FAIL); 119 124 } ··· 119 128 120 129 static ssize_t vgetrandom(void *buf, size_t len, unsigned long flags) 121 130 { 122 - void *state; 131 + static __thread void *state; 123 132 124 - pthread_once(&grnd_ctx.initialized, vgetrandom_init); 125 - state = pthread_getspecific(grnd_ctx.key); 126 133 if (!state) { 127 134 state = vgetrandom_get_state(); 128 - if (pthread_setspecific(grnd_ctx.key, state) != 0) { 129 - vgetrandom_put_state(state); 130 - state = NULL; 131 - } 132 135 if (!state) { 133 136 printf("vgetrandom_get_state failed!\n"); 134 137 exit(KSFT_FAIL); 135 138 } 136 139 } 137 - return grnd_ctx.fn(buf, len, flags, state, grnd_ctx.params.size_of_opaque_state); 140 + return vgrnd.fn(buf, len, flags, state, vgrnd.params.size_of_opaque_state); 138 141 } 139 142 140 143 enum { TRIALS = 25000000, THREADS = 256 }; ··· 250 265 251 266 int main(int argc, char *argv[]) 252 267 { 268 + vgetrandom_init(); 269 + 253 270 if (argc == 1) { 254 271 kselftest(); 255 272 return 0;