-
Notifications
You must be signed in to change notification settings - Fork 105
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add a small multithreading test case
This adds a test case that just spawns a bunch of threads quickly and calls efi_get_variable() on an empty directory. It fails pretty reliably without either of the following commits: 65a3ad0 error.c: make our 'global' state be thread local 3d19e7d efivarfs.c: Call get_efivarfs_path() from a constructor Signed-off-by: Peter Jones <pjones@redhat.com>
- Loading branch information
1 parent
766772c
commit 73fae6c
Showing
6 changed files
with
173 additions
and
7 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,2 +1,8 @@ | ||
!guids.S | ||
*.bin | ||
efivar | ||
efivar-guids.h | ||
efivar-static | ||
makeguids | ||
guid-symbols.c | ||
thread-test |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,117 @@ | ||
// SPDX-License-Identifier: LGPL-2.1-or-later | ||
/* | ||
* thread-test.c - test (some) efivar thread safety | ||
* Copyright Jonathan Marler | ||
*/ | ||
|
||
#include <alloca.h> | ||
#include <pthread.h> | ||
#include <stdlib.h> | ||
#include <stdio.h> | ||
#include <stdint.h> | ||
#include <inttypes.h> | ||
#include <sys/types.h> | ||
#include <unistd.h> | ||
|
||
// returns: the number of threads created | ||
static size_t | ||
multi_pthread_create(pthread_t * threads, unsigned count, | ||
void *(*start_routine)(void *)) | ||
{ | ||
size_t i = 0; | ||
int result; | ||
|
||
for (; i < count; i++) { | ||
result = pthread_create(&threads[i], NULL, start_routine, NULL); | ||
if (result != 0) { | ||
perror("pthread_create"); | ||
break; | ||
} | ||
} | ||
|
||
return i; | ||
} | ||
|
||
#define TEST_SUCCESS NULL | ||
#define TEST_FAIL ((void*)1) | ||
static const char *test_result_str(void *result) | ||
{ | ||
return (result == TEST_SUCCESS) ? "SUCCESS" : "FAIL"; | ||
} | ||
|
||
// returns: 0 on success | ||
static int | ||
multi_pthread_join(pthread_t * threads, unsigned count, void **worst_result) | ||
{ | ||
for (unsigned i = 0; i < count; i++) { | ||
void *result; | ||
int join_result; | ||
|
||
join_result = pthread_join(threads[i], &result); | ||
if (join_result != 0) { | ||
perror("pthread_join"); | ||
return 1; | ||
} | ||
printf("[MAIN-THREAD] child %d exited with %s\n", i, | ||
test_result_str(result)); | ||
if (result != NULL) { | ||
*worst_result = result; | ||
} | ||
} | ||
return 0; | ||
} | ||
|
||
#include <efivar.h> | ||
#define LOOP_COUNT 100 | ||
|
||
static void *loop_get_variable_size_test(void *_ __attribute__((__unused__))) | ||
{ | ||
//printf("[DEBUG] test running on new thread!\n"); | ||
for (unsigned i = 0; i < LOOP_COUNT; i++) { | ||
size_t size; | ||
efi_guid_t guid = { 0 }; | ||
int result; | ||
|
||
result = efi_get_variable_size(guid, "foo2", &size); | ||
if (result == 0 || errno != ENOENT) { | ||
printf("fail, iteration=%u, result=%d errno=%d, expected error\n", | ||
i, result, errno); | ||
return TEST_FAIL; | ||
} else { | ||
//printf("[DEBUG] iteration=%u, result=%d errno=%d\n", i, result, errno); | ||
} | ||
} | ||
return TEST_SUCCESS; | ||
} | ||
|
||
static int multithreaded_test(size_t count, void *(*test_func)(void *)) | ||
{ | ||
pthread_t *threads = alloca(sizeof(pthread_t) * count); | ||
if (count != multi_pthread_create(threads, count, test_func)) { | ||
// error already logged | ||
return 1; | ||
} | ||
void *worst_result = TEST_SUCCESS; | ||
if (multi_pthread_join(threads, count, &worst_result)) { | ||
// error already logged | ||
return 1; | ||
} | ||
printf("worst result %s\n", test_result_str(worst_result)); | ||
return (worst_result == TEST_SUCCESS) ? 0 : -1; | ||
} | ||
|
||
int main(int argc, char *argv[]) | ||
{ | ||
int thread_count; | ||
|
||
if (argc != 2) { | ||
printf("Usage: %s THREAD_COUNT\n", argv[0]); | ||
return 1; | ||
} | ||
|
||
thread_count = atoi(argv[1]); | ||
printf("thread count %d\n", thread_count); | ||
return multithreaded_test(thread_count, loop_get_variable_size_test); | ||
} | ||
|
||
// vim:fenc=utf-8:tw=75:noet |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,40 @@ | ||
#!/usr/bin/env sh | ||
# SPDX-License-Identifier: LGPL-2.1-or-later | ||
# test (some) efivar thread safety | ||
# | ||
# Copyright Jonathan Marler | ||
|
||
set -e | ||
|
||
if [ "x$TOPDIR" = "x" ] ; then | ||
TOPDIR="$(realpath "$(dirname "$0")/../")" | ||
fi | ||
|
||
rm -rf scratch | ||
mkdir scratch | ||
|
||
EFIVARFS_PATH="" | ||
LD_LIBRARY_PATH="" | ||
LIBEFIVAR_OPS="" | ||
|
||
EFIVARFS_PATH=$(realpath scratch)/ | ||
LD_LIBRARY_PATH="${TOPDIR}/src/" | ||
LIBEFIVAR_OPS=efivarfs | ||
export EFIVARFS_PATH LD_LIBRARY_PATH LIBEFIVAR_OPS | ||
|
||
test() { | ||
echo "================================================================================" | ||
echo "testing $1 thread..." | ||
echo "================================================================================" | ||
if "${TOPDIR}/src/thread-test" "$1" ; then | ||
echo "${1} thread worked" | ||
else | ||
echo "${1} thread failed" | ||
exit 1 | ||
fi | ||
} | ||
|
||
test 1 | ||
test 2 | ||
test 4 | ||
test 64 |