xref: /openbsd-src/regress/sys/kern/futex/futex.c (revision ebff625aa633eab5297dfbeb558c0dc36347c511)
1*ebff625aSkettenis /*	$OpenBSD: futex.c,v 1.5 2021/11/22 18:42:16 kettenis Exp $ */
22b5b01cfSmpi /*
32b5b01cfSmpi  * Copyright (c) 2017 Martin Pieuchot
42b5b01cfSmpi  *
52b5b01cfSmpi  * Permission to use, copy, modify, and distribute this software for any
62b5b01cfSmpi  * purpose with or without fee is hereby granted, provided that the above
72b5b01cfSmpi  * copyright notice and this permission notice appear in all copies.
82b5b01cfSmpi  *
92b5b01cfSmpi  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
102b5b01cfSmpi  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
112b5b01cfSmpi  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
122b5b01cfSmpi  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
132b5b01cfSmpi  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
142b5b01cfSmpi  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
152b5b01cfSmpi  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
162b5b01cfSmpi  */
172b5b01cfSmpi 
182b5b01cfSmpi #include <sys/time.h>
192b5b01cfSmpi #include <sys/futex.h>
20116b6a5eSvisa #include <sys/mman.h>
21116b6a5eSvisa #include <sys/wait.h>
222b5b01cfSmpi 
232b5b01cfSmpi #include <assert.h>
242b5b01cfSmpi #include <errno.h>
252b5b01cfSmpi #include <pthread.h>
262b5b01cfSmpi #include <signal.h>
27116b6a5eSvisa #include <stdlib.h>
282b5b01cfSmpi #include <string.h>
292b5b01cfSmpi #include <unistd.h>
302b5b01cfSmpi 
312b5b01cfSmpi #include "futex.h"
322b5b01cfSmpi 
332b5b01cfSmpi uint32_t lock = 0;
34116b6a5eSvisa uint32_t *shlock;
352b5b01cfSmpi 
362b5b01cfSmpi void handler(int);
372b5b01cfSmpi void *signaled(void *);
382b5b01cfSmpi void *awakener(void *);
392b5b01cfSmpi 
402b5b01cfSmpi int
main(int argc,char * argv[])412b5b01cfSmpi main(int argc, char *argv[])
422b5b01cfSmpi {
43116b6a5eSvisa 	char filename[] = "/tmp/futex.XXXXXXXX";
442b5b01cfSmpi 	struct sigaction sa;
45116b6a5eSvisa 	struct timespec tmo = { 0, 5000 };
462b5b01cfSmpi 	pthread_t thread;
47116b6a5eSvisa 	pid_t pid;
48116b6a5eSvisa 	int fd, i, status;
492b5b01cfSmpi 
505b1e7562Smpi 	/* Invalid operation */
51f18e4490Skettenis 	assert(futex(&lock, 0xFFFF, 0, 0, NULL) == -1);
52f18e4490Skettenis 	assert(errno == ENOSYS);
535b1e7562Smpi 
542b5b01cfSmpi 	/* Incorrect pointer */
55f18e4490Skettenis 	assert(futex_twait((void *)0xdeadbeef, 1, 0, NULL, 0) == -1);
56f18e4490Skettenis 	assert(errno == EFAULT);
572b5b01cfSmpi 
582b5b01cfSmpi 	/* If (lock != 1) return EAGAIN */
59f18e4490Skettenis 	assert(futex_twait(&lock, 1, 0, NULL, 0) == -1);
60f18e4490Skettenis 	assert(errno == EAGAIN);
612b5b01cfSmpi 
622b5b01cfSmpi 	/* Deadlock for 5000ns */
63f18e4490Skettenis 	assert(futex_twait(&lock, 0, CLOCK_REALTIME, &tmo, 0) == -1);
64f18e4490Skettenis 	assert(errno == ETIMEDOUT);
652b5b01cfSmpi 
662b5b01cfSmpi 	/* Interrupt a thread waiting on a futex. */
672b5b01cfSmpi 	memset(&sa, 0, sizeof(sa));
682b5b01cfSmpi 	sa.sa_handler = handler;
692b5b01cfSmpi 	assert(sigaction(SIGUSR1, &sa, NULL) == 0);
702b5b01cfSmpi 	assert(pthread_create(&thread, NULL, signaled, NULL) == 0);
712b5b01cfSmpi 	usleep(100);
722b5b01cfSmpi 	assert(pthread_kill(thread, SIGUSR1) == 0);
732b5b01cfSmpi 	assert(pthread_join(thread, NULL) == 0);
742b5b01cfSmpi 
752b5b01cfSmpi 	/* Wait until another thread awakes us. */
762b5b01cfSmpi 	assert(pthread_create(&thread, NULL, awakener, NULL) == 0);
77116b6a5eSvisa 	assert(futex_twait(&lock, 0, 0, NULL, 0) == 0);
782b5b01cfSmpi 	assert(pthread_join(thread, NULL) == 0);
792b5b01cfSmpi 
80116b6a5eSvisa 	/* Create a uvm object for sharing a lock. */
81116b6a5eSvisa 	fd = mkstemp(filename);
82116b6a5eSvisa 	assert(fd != -1);
83116b6a5eSvisa 	unlink(filename);
84116b6a5eSvisa 	assert(ftruncate(fd, 65536) == 0);
85116b6a5eSvisa 	shlock = mmap(NULL, sizeof(*shlock), PROT_READ | PROT_WRITE,
86116b6a5eSvisa 	    MAP_SHARED, fd, 0);
87116b6a5eSvisa 	assert(shlock != MAP_FAILED);
88116b6a5eSvisa 	close(fd);
89116b6a5eSvisa 
90116b6a5eSvisa 	/* Wake another process. */
91116b6a5eSvisa 	pid = fork();
92116b6a5eSvisa 	assert(pid != -1);
93116b6a5eSvisa 	if (pid == 0) {
94116b6a5eSvisa 		usleep(50000);
95116b6a5eSvisa 		futex_wake(shlock, -1, 0);
96116b6a5eSvisa 		_exit(0);
97116b6a5eSvisa 	} else {
98116b6a5eSvisa 		assert(futex_twait(shlock, 0, 0, NULL, 0) == 0);
99116b6a5eSvisa 		assert(waitpid(pid, &status, 0) == pid);
100116b6a5eSvisa 		assert(WIFEXITED(status));
101116b6a5eSvisa 		assert(WEXITSTATUS(status) == 0);
102116b6a5eSvisa 	}
103116b6a5eSvisa 
104116b6a5eSvisa 	/* Cannot wake another process using a private futex. */
105116b6a5eSvisa 	for (i = 1; i < 4; i++) {
106116b6a5eSvisa 		pid = fork();
107116b6a5eSvisa 		assert(pid != -1);
108116b6a5eSvisa 		if (pid == 0) {
109116b6a5eSvisa 			usleep(50000);
110116b6a5eSvisa 			futex_wake(shlock, -1,
111116b6a5eSvisa 			    (i & 1) ? FUTEX_PRIVATE_FLAG : 0);
112116b6a5eSvisa 			_exit(0);
113116b6a5eSvisa 		} else {
114116b6a5eSvisa 			tmo.tv_sec = 0;
115116b6a5eSvisa 			tmo.tv_nsec = 200000000;
116116b6a5eSvisa 			assert(futex_twait(shlock, 0, CLOCK_REALTIME, &tmo,
117f18e4490Skettenis 			    (i & 2) ? FUTEX_PRIVATE_FLAG : 0) == -1);
118f18e4490Skettenis 			assert(errno == ETIMEDOUT);
119116b6a5eSvisa 			assert(waitpid(pid, &status, 0) == pid);
120116b6a5eSvisa 			assert(WIFEXITED(status));
121116b6a5eSvisa 			assert(WEXITSTATUS(status) == 0);
122116b6a5eSvisa 		}
123116b6a5eSvisa 	}
124116b6a5eSvisa 
125116b6a5eSvisa 	assert(munmap(shlock, sizeof(*shlock)) == 0);
126116b6a5eSvisa 
127*ebff625aSkettenis 	/* Create anonymous memory for sharing a lock. */
128*ebff625aSkettenis 	shlock = mmap(NULL, sizeof(*shlock), PROT_READ | PROT_WRITE,
129*ebff625aSkettenis 	    MAP_ANON | MAP_SHARED, -1, 0);
130*ebff625aSkettenis 	assert(shlock != MAP_FAILED);
131*ebff625aSkettenis 
132*ebff625aSkettenis 	/* Wake another process. */
133*ebff625aSkettenis 	pid = fork();
134*ebff625aSkettenis 	assert(pid != -1);
135*ebff625aSkettenis 	if (pid == 0) {
136*ebff625aSkettenis 		usleep(50000);
137*ebff625aSkettenis 		futex_wake(shlock, -1, 0);
138*ebff625aSkettenis 		_exit(0);
139*ebff625aSkettenis 	} else {
140*ebff625aSkettenis 		assert(futex_twait(shlock, 0, 0, NULL, 0) == 0);
141*ebff625aSkettenis 		assert(waitpid(pid, &status, 0) == pid);
142*ebff625aSkettenis 		assert(WIFEXITED(status));
143*ebff625aSkettenis 		assert(WEXITSTATUS(status) == 0);
144*ebff625aSkettenis 	}
145*ebff625aSkettenis 
146*ebff625aSkettenis 	/* Cannot wake another process using a private futex. */
147*ebff625aSkettenis 	for (i = 1; i < 4; i++) {
148*ebff625aSkettenis 		pid = fork();
149*ebff625aSkettenis 		assert(pid != -1);
150*ebff625aSkettenis 		if (pid == 0) {
151*ebff625aSkettenis 			usleep(50000);
152*ebff625aSkettenis 			futex_wake(shlock, -1,
153*ebff625aSkettenis 			    (i & 1) ? FUTEX_PRIVATE_FLAG : 0);
154*ebff625aSkettenis 			_exit(0);
155*ebff625aSkettenis 		} else {
156*ebff625aSkettenis 			tmo.tv_sec = 0;
157*ebff625aSkettenis 			tmo.tv_nsec = 200000000;
158*ebff625aSkettenis 			assert(futex_twait(shlock, 0, CLOCK_REALTIME, &tmo,
159*ebff625aSkettenis 			    (i & 2) ? FUTEX_PRIVATE_FLAG : 0) == -1);
160*ebff625aSkettenis 			assert(errno == ETIMEDOUT);
161*ebff625aSkettenis 			assert(waitpid(pid, &status, 0) == pid);
162*ebff625aSkettenis 			assert(WIFEXITED(status));
163*ebff625aSkettenis 			assert(WEXITSTATUS(status) == 0);
164*ebff625aSkettenis 		}
165*ebff625aSkettenis 	}
166*ebff625aSkettenis 
167*ebff625aSkettenis 	assert(munmap(shlock, sizeof(*shlock)) == 0);
168*ebff625aSkettenis 
1692b5b01cfSmpi 	return 0;
1702b5b01cfSmpi }
1712b5b01cfSmpi 
1722b5b01cfSmpi void
handler(int sig)1732b5b01cfSmpi handler(int sig)
1742b5b01cfSmpi {
1752b5b01cfSmpi }
1762b5b01cfSmpi 
1772b5b01cfSmpi void *
signaled(void * arg)1782b5b01cfSmpi signaled(void *arg)
1792b5b01cfSmpi {
1802b5b01cfSmpi 	/* Wait until receiving a signal. */
181f18e4490Skettenis 	assert(futex_twait(&lock, 0, 0, NULL, 0) == -1);
182f18e4490Skettenis 	assert(errno == EINTR);
183116b6a5eSvisa 	return NULL;
1842b5b01cfSmpi }
1852b5b01cfSmpi 
1862b5b01cfSmpi void *
awakener(void * arg)1872b5b01cfSmpi awakener(void *arg)
1882b5b01cfSmpi {
1892b5b01cfSmpi 	usleep(100);
190116b6a5eSvisa 	assert(futex_wake(&lock, -1, 0) == 1);
191116b6a5eSvisa 	return NULL;
1922b5b01cfSmpi }
193