xref: /linux/tools/testing/selftests/futex/include/futex_thread.h (revision b844715e8aca2929c0a97a32b3a5650496b5872f)
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