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