1 /* SPDX-License-Identifier: GPL-2.0 */ 2 #include <pthread.h> 3 #include <stdlib.h> 4 #include <signal.h> 5 #include <unistd.h> 6 #include <linux/compiler.h> 7 #include "../tests.h" 8 9 static volatile sig_atomic_t done; 10 11 /* We want to check this symbol in perf report */ 12 noinline void test_loop(void); 13 14 static void sighandler(int sig __maybe_unused) 15 { 16 done = 1; 17 } 18 19 noinline void test_loop(void) 20 { 21 while (!done); 22 } 23 24 static void *thfunc(void *arg) 25 { 26 void (*loop_fn)(void) = arg; 27 28 loop_fn(); 29 return NULL; 30 } 31 32 static int thloop(int argc, const char **argv) 33 { 34 int nt = 2, err = 1; 35 double sec = 1.0; 36 pthread_t *thread_list = NULL; 37 38 if (argc > 0) 39 sec = atof(argv[0]); 40 41 if (!(sec > 0.0)) { 42 fprintf(stderr, "Error: seconds (%f) must be > 0\n", sec); 43 return 1; 44 } 45 46 if (argc > 1) 47 nt = atoi(argv[1]); 48 49 if (nt <= 0) { 50 fprintf(stderr, "Error: thread count (%d) must be >= 1\n", nt); 51 return 1; 52 } 53 54 signal(SIGINT, sighandler); 55 signal(SIGALRM, sighandler); 56 57 thread_list = calloc(nt, sizeof(pthread_t)); 58 if (thread_list == NULL) { 59 fprintf(stderr, "Error: malloc failed for %d threads\n", nt); 60 goto out; 61 } 62 for (int i = 1; i < nt; i++) { 63 int ret = pthread_create(&thread_list[i], NULL, thfunc, test_loop); 64 65 if (ret) { 66 fprintf(stderr, "Error: failed to create thread %d\n", i); 67 done = 1; // Ensure started threads terminate. 68 goto out; 69 } 70 } 71 if (sec < 1.0) { 72 useconds_t usecs = (useconds_t)(sec * 1000000.0); 73 74 ualarm(usecs > 0 ? usecs : 1, 0); 75 } else 76 alarm((unsigned int)sec); 77 test_loop(); 78 err = 0; 79 out: 80 for (int i = 1; i < nt; i++) { 81 if (thread_list && thread_list[i]) 82 pthread_join(thread_list[i], /*retval=*/NULL); 83 } 84 free(thread_list); 85 return err; 86 } 87 88 DEFINE_WORKLOAD(thloop); 89