14c87aefeSPatrick Mooney /*
24c87aefeSPatrick Mooney  * This file and its contents are supplied under the terms of the
34c87aefeSPatrick Mooney  * Common Development and Distribution License ("CDDL"), version 1.0.
44c87aefeSPatrick Mooney  * You may only use this file in accordance with the terms of version
54c87aefeSPatrick Mooney  * 1.0 of the CDDL.
64c87aefeSPatrick Mooney  *
74c87aefeSPatrick Mooney  * A full copy of the text of the CDDL should have accompanied this
84c87aefeSPatrick Mooney  * source.  A copy of the CDDL is also available via the Internet at
94c87aefeSPatrick Mooney  * http://www.illumos.org/license/CDDL.
104c87aefeSPatrick Mooney  */
114c87aefeSPatrick Mooney 
124c87aefeSPatrick Mooney /*
134c87aefeSPatrick Mooney  * Copyright 2018 Joyent, Inc.
144c87aefeSPatrick Mooney  */
154c87aefeSPatrick Mooney 
164c87aefeSPatrick Mooney /*
174c87aefeSPatrick Mooney  *        Test:	read.cancel
184c87aefeSPatrick Mooney  *   Assertion: A read is not requeued if mevent_disable() is called while it is
194c87aefeSPatrick Mooney  *		being handled.
204c87aefeSPatrick Mooney  *
214c87aefeSPatrick Mooney  *    Strategy: 1. Create a pipe
224c87aefeSPatrick Mooney  *		2. Call mevent_add() to be notified of writes to the pipe.  The
234c87aefeSPatrick Mooney  *		   callback will signal a cv.
244c87aefeSPatrick Mooney  *		3. Write to the pipe then wait for a wakeup.
254c87aefeSPatrick Mooney  *		4. From the read event callback, disable the event then awaken
264c87aefeSPatrick Mooney  *		   the main thread.
274c87aefeSPatrick Mooney  *		5. In the main thread, add a timer event that will awaken the
284c87aefeSPatrick Mooney  *		   main thread after a short delay.
294c87aefeSPatrick Mooney  *		5. Write to the pipe and wait to be awoken.  The wakeup should
304c87aefeSPatrick Mooney  *		   come from the timer event, not the read event.
314c87aefeSPatrick Mooney  */
324c87aefeSPatrick Mooney 
334c87aefeSPatrick Mooney #include <errno.h>
344c87aefeSPatrick Mooney #include <fcntl.h>
354c87aefeSPatrick Mooney #include <pthread.h>
364c87aefeSPatrick Mooney #include <signal.h>
374c87aefeSPatrick Mooney #include <stdio.h>
384c87aefeSPatrick Mooney #include <stdlib.h>
394c87aefeSPatrick Mooney #include <strings.h>
404c87aefeSPatrick Mooney #include <unistd.h>
414c87aefeSPatrick Mooney 
424c87aefeSPatrick Mooney #include <sys/types.h>
434c87aefeSPatrick Mooney #include <sys/stat.h>
444c87aefeSPatrick Mooney 
454c87aefeSPatrick Mooney #include "testlib.h"
464c87aefeSPatrick Mooney #include "mevent.h"
474c87aefeSPatrick Mooney 
484c87aefeSPatrick Mooney typedef enum {
494c87aefeSPatrick Mooney 	CB_NONE,
504c87aefeSPatrick Mooney 	CB_READ,
514c87aefeSPatrick Mooney 	CB_TIMER,
524c87aefeSPatrick Mooney } lastwake_t;
534c87aefeSPatrick Mooney 
544c87aefeSPatrick Mooney static lastwake_t lastwake = CB_NONE;
554c87aefeSPatrick Mooney 
564c87aefeSPatrick Mooney static pthread_mutex_t mtx = PTHREAD_MUTEX_INITIALIZER;
574c87aefeSPatrick Mooney static pthread_cond_t cv = PTHREAD_COND_INITIALIZER;
584c87aefeSPatrick Mooney 
594c87aefeSPatrick Mooney static struct mevent *read_event;
604c87aefeSPatrick Mooney 
614c87aefeSPatrick Mooney static void
munch(int fd,enum ev_type ev,void * arg)624c87aefeSPatrick Mooney munch(int fd, enum ev_type ev, void *arg)
634c87aefeSPatrick Mooney {
644c87aefeSPatrick Mooney 	ssize_t nbytes;
654c87aefeSPatrick Mooney 	char buf[32] = { 0 };
664c87aefeSPatrick Mooney 	int err;
674c87aefeSPatrick Mooney 
684c87aefeSPatrick Mooney 	if ((nbytes = read(fd, buf, sizeof (buf))) < 0) {
694c87aefeSPatrick Mooney 		FAIL_ERRNO("bad read");
704c87aefeSPatrick Mooney 	}
714c87aefeSPatrick Mooney 	VERBOSE(("read %ld bytes '%s'", nbytes, buf));
724c87aefeSPatrick Mooney 
734c87aefeSPatrick Mooney 	err = mevent_disable(read_event);
744c87aefeSPatrick Mooney 	ASSERT_INT_EQ(("mevent_disable: ", strerror(err)), err, 0);
754c87aefeSPatrick Mooney 
764c87aefeSPatrick Mooney 	pthread_mutex_lock(&mtx);
774c87aefeSPatrick Mooney 
784c87aefeSPatrick Mooney 	ASSERT_INT_EQ(("wrong lastwake"), lastwake, CB_NONE);
794c87aefeSPatrick Mooney 	lastwake = CB_READ;
804c87aefeSPatrick Mooney 
814c87aefeSPatrick Mooney 	pthread_cond_signal(&cv);
824c87aefeSPatrick Mooney 	VERBOSE(("wakeup"));
834c87aefeSPatrick Mooney 
844c87aefeSPatrick Mooney 	pthread_mutex_unlock(&mtx);
854c87aefeSPatrick Mooney }
864c87aefeSPatrick Mooney 
874c87aefeSPatrick Mooney static void
tick(int ms,enum ev_type ev,void * arg)884c87aefeSPatrick Mooney tick(int ms, enum ev_type ev, void *arg)
894c87aefeSPatrick Mooney {
904c87aefeSPatrick Mooney 	pthread_mutex_lock(&mtx);
914c87aefeSPatrick Mooney 
924c87aefeSPatrick Mooney 	ASSERT_INT_EQ(("wrong lastwake"), lastwake, CB_READ);
934c87aefeSPatrick Mooney 	lastwake = CB_TIMER;
944c87aefeSPatrick Mooney 
954c87aefeSPatrick Mooney 	pthread_cond_signal(&cv);
964c87aefeSPatrick Mooney 	VERBOSE(("wakeup"));
974c87aefeSPatrick Mooney 
984c87aefeSPatrick Mooney 	pthread_mutex_unlock(&mtx);
994c87aefeSPatrick Mooney }
1004c87aefeSPatrick Mooney 
1014c87aefeSPatrick Mooney int
main(int argc,const char * argv[])1024c87aefeSPatrick Mooney main(int argc, const char *argv[])
1034c87aefeSPatrick Mooney {
1044c87aefeSPatrick Mooney 	int pipefds[2];
1054c87aefeSPatrick Mooney 	struct mevent *timer;
1064c87aefeSPatrick Mooney 	ssize_t written;
1074c87aefeSPatrick Mooney 	char *msgs[] = { "first", "second" };
1084c87aefeSPatrick Mooney 	char *msg;
1094c87aefeSPatrick Mooney 
1104c87aefeSPatrick Mooney 	start_test(argv[0], 5);
1114c87aefeSPatrick Mooney 	start_event_thread();
1124c87aefeSPatrick Mooney 
1134c87aefeSPatrick Mooney 	if (pipe(pipefds) != 0) {
1144c87aefeSPatrick Mooney 		FAIL_ERRNO("pipe");
1154c87aefeSPatrick Mooney 	}
1164c87aefeSPatrick Mooney 	if (fcntl(pipefds[0], F_SETFL, O_NONBLOCK) != 0) {
1174c87aefeSPatrick Mooney 		FAIL_ERRNO("set pipe nonblocking");
1184c87aefeSPatrick Mooney 	}
1194c87aefeSPatrick Mooney 
1204c87aefeSPatrick Mooney 	/*
1214c87aefeSPatrick Mooney 	 * First write
1224c87aefeSPatrick Mooney 	 */
1234c87aefeSPatrick Mooney 	msg = msgs[0];
1244c87aefeSPatrick Mooney 	read_event = mevent_add(pipefds[0], EVF_READ, munch, msg);
1254c87aefeSPatrick Mooney 	ASSERT_PTR_NEQ(("mevent_add pipefd"), read_event, NULL);
1264c87aefeSPatrick Mooney 
1274c87aefeSPatrick Mooney 	pthread_mutex_lock(&mtx);
1284c87aefeSPatrick Mooney 	written = write(pipefds[1], msg, strlen(msg));
1294c87aefeSPatrick Mooney 	if (written < 0) {
1304c87aefeSPatrick Mooney 		FAIL_ERRNO("bad write");
1314c87aefeSPatrick Mooney 	}
1324c87aefeSPatrick Mooney 	ASSERT_INT64_EQ(("write '%s' failed", msg), written, strlen(msg));
1334c87aefeSPatrick Mooney 
1344c87aefeSPatrick Mooney 	/*
1354c87aefeSPatrick Mooney 	 * Wait for it to be read
1364c87aefeSPatrick Mooney 	 */
1374c87aefeSPatrick Mooney 	pthread_cond_wait(&cv, &mtx);
1384c87aefeSPatrick Mooney 	ASSERT_INT_EQ(("wrong lastwake"), lastwake, CB_READ);
1394c87aefeSPatrick Mooney 	pthread_mutex_unlock(&mtx);
1404c87aefeSPatrick Mooney 
1414c87aefeSPatrick Mooney 	/*
1424c87aefeSPatrick Mooney 	 * Add timer, second write.
1434c87aefeSPatrick Mooney 	 */
1444c87aefeSPatrick Mooney 	msg = msgs[1];
1454c87aefeSPatrick Mooney 	timer = mevent_add(50, EVF_TIMER, tick, msg);
1464c87aefeSPatrick Mooney 	ASSERT_PTR_NEQ(("mevent_add timer"), timer, NULL);
1474c87aefeSPatrick Mooney 
1484c87aefeSPatrick Mooney 	pthread_mutex_lock(&mtx);
1494c87aefeSPatrick Mooney 	written = write(pipefds[1], msg, strlen(msg));
1504c87aefeSPatrick Mooney 	if (written < 0) {
1514c87aefeSPatrick Mooney 		FAIL_ERRNO("bad write");
1524c87aefeSPatrick Mooney 	}
1534c87aefeSPatrick Mooney 	ASSERT_INT64_EQ(("write '%s' failed", msg), written, strlen(msg));
1544c87aefeSPatrick Mooney 
1554c87aefeSPatrick Mooney 	/*
1564c87aefeSPatrick Mooney 	 * Wait for timer to expire
1574c87aefeSPatrick Mooney 	 */
1584c87aefeSPatrick Mooney 	pthread_cond_wait(&cv, &mtx);
1594c87aefeSPatrick Mooney 	ASSERT_INT_EQ(("wrong lastwake"), lastwake, CB_TIMER);
1604c87aefeSPatrick Mooney 	pthread_mutex_unlock(&mtx);
1614c87aefeSPatrick Mooney 
1624c87aefeSPatrick Mooney 	PASS();
1634c87aefeSPatrick Mooney }
164