projects/linux·blob master · refs

117 lines · 2.7 KiB

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
18struct 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
27static 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
45static 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 */
60static 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 */
88static 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 */
110static 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