1 /* SPDX-License-Identifier: GPL-2.0-or-later */ 2 3 #ifndef _FUTEX_THREAD_H 4 #define _FUTEX_THREAD_H 5 #include <errno.h> 6 #include <pthread.h> 7 #include <stdio.h> 8 #include <string.h> 9 #include <unistd.h> 10 11 #include "kselftest_harness.h" 12 13 #define USEC_PER_SEC 1000000L 14 #define WAIT_FOR_THREAD_SECS 1 15 #define WAIT_FOR_THREAD_USECS (WAIT_FOR_THREAD_SECS * USEC_PER_SEC) 16 #define WAIT_THREAD_RETRIES 100 17 18 struct futex_thread { 19 pthread_t thread; 20 pthread_barrier_t barrier; 21 pid_t tid; 22 int (*threadfn)(void *arg); 23 void *arg; 24 int retval; 25 }; 26 27 static inline int __wait_for_thread(FILE *fp, struct __test_metadata *_metadata) 28 { 29 unsigned int sleep_time_us = WAIT_FOR_THREAD_USECS / WAIT_THREAD_RETRIES; 30 char buf[80] = ""; 31 32 for (int i = 0; i < WAIT_THREAD_RETRIES; i++) { 33 if (!fgets(buf, sizeof(buf), fp)) 34 return EIO; 35 if (!strncmp(buf, "futex", 5)) 36 return 0; 37 usleep(sleep_time_us); 38 rewind(fp); 39 } 40 41 TH_LOG("/proc/$PID/wchan contains \"%s\". Trying to continue.", buf); 42 return 0; 43 } 44 45 static void *__futex_thread_fn(void *arg) 46 { 47 struct futex_thread *t = arg; 48 49 t->tid = gettid(); 50 pthread_barrier_wait(&t->barrier); 51 t->retval = t->threadfn(t->arg); 52 return NULL; 53 } 54 55 /** 56 * futex_wait_for_thread - Wait for the child thread to sleep in the futex context 57 * @t: Thread handle. 58 * @_metadata: Test metadata for TH_LOG() context 59 */ 60 static inline int futex_wait_for_thread(struct futex_thread *t, struct __test_metadata *_metadata) 61 { 62 char fname[80]; 63 FILE *fp; 64 int res; 65 66 snprintf(fname, sizeof(fname), "/proc/%d/wchan", t->tid); 67 fp = fopen(fname, "r"); 68 if (!fp) { 69 /* If /proc/... is not available, sleep */ 70 if (errno != ENOENT) 71 return errno; 72 TH_LOG("/proc/$PID/wchan not accessible, continue with sleep()"); 73 sleep(WAIT_FOR_THREAD_SECS); 74 return 0; 75 } 76 77 res = __wait_for_thread(fp, _metadata); 78 fclose(fp); 79 return res; 80 } 81 82 /** 83 * futex_thread_create - Create a new thread for testing. 84 * @t: The handle of the newly created thread. 85 * @threadfn: The new thread starts execution by invoking threadfn 86 * @arg: The parameters passed to threadfn. 87 */ 88 static inline int futex_thread_create(struct futex_thread *t, int (*threadfn)(void *), void *arg) 89 { 90 pthread_barrier_init(&t->barrier, NULL, 2); 91 92 t->tid = 0; 93 t->threadfn = threadfn; 94 t->arg = arg; 95 96 if (pthread_create(&t->thread, NULL, __futex_thread_fn, t) < 0) { 97 int ret = errno; 98 pthread_barrier_destroy(&t->barrier); 99 return ret; 100 } 101 102 pthread_barrier_wait(&t->barrier); 103 return 0; 104 } 105 106 /** 107 * futex_thread_destroy - Wait for and reclaim the resources of the thread. 108 * @t: Thread handle. 109 */ 110 static inline int futex_thread_destroy(struct futex_thread *t) 111 { 112 pthread_join(t->thread, NULL); 113 pthread_barrier_destroy(&t->barrier); 114 return t->retval; 115 } 116 117 #endif 118