1*4c87aefeSPatrick Mooney /*
2*4c87aefeSPatrick Mooney  * This file and its contents are supplied under the terms of the
3*4c87aefeSPatrick Mooney  * Common Development and Distribution License ("CDDL"), version 1.0.
4*4c87aefeSPatrick Mooney  * You may only use this file in accordance with the terms of version
5*4c87aefeSPatrick Mooney  * 1.0 of the CDDL.
6*4c87aefeSPatrick Mooney  *
7*4c87aefeSPatrick Mooney  * A full copy of the text of the CDDL should have accompanied this
8*4c87aefeSPatrick Mooney  * source.  A copy of the CDDL is also available via the Internet at
9*4c87aefeSPatrick Mooney  * http://www.illumos.org/license/CDDL.
10*4c87aefeSPatrick Mooney  */
11*4c87aefeSPatrick Mooney 
12*4c87aefeSPatrick Mooney /*
13*4c87aefeSPatrick Mooney  * Copyright 2018 Joyent, Inc.
14*4c87aefeSPatrick Mooney  */
15*4c87aefeSPatrick Mooney 
16*4c87aefeSPatrick Mooney /*
17*4c87aefeSPatrick Mooney  *        Test:	lists.delete
18*4c87aefeSPatrick Mooney  *   Assertion: mevent_delete() causes the total number of events to decrease
19*4c87aefeSPatrick Mooney  *
20*4c87aefeSPatrick Mooney  *    Strategy: 1. Create a pipe.
21*4c87aefeSPatrick Mooney  *		2. Call mevent_add() to be notified of writes to the pipe.  The
22*4c87aefeSPatrick Mooney  *		   callback will do nothing other than generate an error if it
23*4c87aefeSPatrick Mooney  *		   is called.
24*4c87aefeSPatrick Mooney  *		3. Create another pipe and add a read event watcher to it.  The
25*4c87aefeSPatrick Mooney  *		   callback will signal a cv when called.  A write to the pipe
26*4c87aefeSPatrick Mooney  *		   followed by a wait on the cv will ensure that async
27*4c87aefeSPatrick Mooney  *		   operations in mevent.c are complete.  See flush_and_wait().
28*4c87aefeSPatrick Mooney  *		4. Call flush_and_wait(), then get event count.
29*4c87aefeSPatrick Mooney  *		5. Delete the event created in step 2.
30*4c87aefeSPatrick Mooney  *		6. Call flush_and_wait(), then get event count.
31*4c87aefeSPatrick Mooney  *		7. Verify result in step 6 is one less than result in step 4.
32*4c87aefeSPatrick Mooney  */
33*4c87aefeSPatrick Mooney 
34*4c87aefeSPatrick Mooney #include <errno.h>
35*4c87aefeSPatrick Mooney #include <fcntl.h>
36*4c87aefeSPatrick Mooney #include <pthread.h>
37*4c87aefeSPatrick Mooney #include <signal.h>
38*4c87aefeSPatrick Mooney #include <stdio.h>
39*4c87aefeSPatrick Mooney #include <stdlib.h>
40*4c87aefeSPatrick Mooney #include <strings.h>
41*4c87aefeSPatrick Mooney #include <unistd.h>
42*4c87aefeSPatrick Mooney 
43*4c87aefeSPatrick Mooney #include <sys/types.h>
44*4c87aefeSPatrick Mooney #include <sys/stat.h>
45*4c87aefeSPatrick Mooney 
46*4c87aefeSPatrick Mooney #include "testlib.h"
47*4c87aefeSPatrick Mooney #include "mevent.h"
48*4c87aefeSPatrick Mooney 
49*4c87aefeSPatrick Mooney static pthread_mutex_t mtx = PTHREAD_MUTEX_INITIALIZER;
50*4c87aefeSPatrick Mooney static pthread_cond_t cv = PTHREAD_COND_INITIALIZER;
51*4c87aefeSPatrick Mooney 
52*4c87aefeSPatrick Mooney static int
get_count(void)53*4c87aefeSPatrick Mooney get_count(void)
54*4c87aefeSPatrick Mooney {
55*4c87aefeSPatrick Mooney 	int global = -1, change = -1, del_pending = -1;
56*4c87aefeSPatrick Mooney 	int total;
57*4c87aefeSPatrick Mooney 
58*4c87aefeSPatrick Mooney 	test_mevent_count_lists(&global, &change, &del_pending);
59*4c87aefeSPatrick Mooney 	ASSERT_INT_NEQ(("count not set"), global, -1);
60*4c87aefeSPatrick Mooney 	ASSERT_INT_NEQ(("count not set"), change, -1);
61*4c87aefeSPatrick Mooney 	ASSERT_INT_NEQ(("count not set"), change, -1);
62*4c87aefeSPatrick Mooney 	ASSERT_INT_EQ(("pending delete not processed"), del_pending, 0);
63*4c87aefeSPatrick Mooney 
64*4c87aefeSPatrick Mooney 	total = global + change + del_pending;
65*4c87aefeSPatrick Mooney 
66*4c87aefeSPatrick Mooney 	VERBOSE(("count = %d (%d + %d + %d)", total, global, change,
67*4c87aefeSPatrick Mooney 	    del_pending));
68*4c87aefeSPatrick Mooney 
69*4c87aefeSPatrick Mooney 	return (total);
70*4c87aefeSPatrick Mooney }
71*4c87aefeSPatrick Mooney 
72*4c87aefeSPatrick Mooney static void
not_called_cb(int fd,enum ev_type ev,void * arg)73*4c87aefeSPatrick Mooney not_called_cb(int fd, enum ev_type ev, void *arg)
74*4c87aefeSPatrick Mooney {
75*4c87aefeSPatrick Mooney 	FAIL(("this callback should never be called"));
76*4c87aefeSPatrick Mooney }
77*4c87aefeSPatrick Mooney 
78*4c87aefeSPatrick Mooney static void
flush_cb(int fd,enum ev_type ev,void * arg)79*4c87aefeSPatrick Mooney flush_cb(int fd, enum ev_type ev, void *arg)
80*4c87aefeSPatrick Mooney {
81*4c87aefeSPatrick Mooney 	char buf[32];
82*4c87aefeSPatrick Mooney 
83*4c87aefeSPatrick Mooney 	/* Drain the pipe */
84*4c87aefeSPatrick Mooney 	while (read(fd, buf, sizeof (buf)) > 0)
85*4c87aefeSPatrick Mooney 		;
86*4c87aefeSPatrick Mooney 
87*4c87aefeSPatrick Mooney 	pthread_mutex_lock(&mtx);
88*4c87aefeSPatrick Mooney 	pthread_cond_signal(&cv);
89*4c87aefeSPatrick Mooney 	pthread_mutex_unlock(&mtx);
90*4c87aefeSPatrick Mooney }
91*4c87aefeSPatrick Mooney 
92*4c87aefeSPatrick Mooney void
flush_and_wait(int fd)93*4c87aefeSPatrick Mooney flush_and_wait(int fd)
94*4c87aefeSPatrick Mooney {
95*4c87aefeSPatrick Mooney 	uint8_t msg = 42;
96*4c87aefeSPatrick Mooney 
97*4c87aefeSPatrick Mooney 	/*
98*4c87aefeSPatrick Mooney 	 * Lock taken ahead of waking flush_cb so this thread doesn't race
99*4c87aefeSPatrick Mooney 	 * with the event thread.
100*4c87aefeSPatrick Mooney 	 */
101*4c87aefeSPatrick Mooney 	pthread_mutex_lock(&mtx);
102*4c87aefeSPatrick Mooney 	if (write(fd, &msg, sizeof (msg)) != sizeof (msg)) {
103*4c87aefeSPatrick Mooney 		FAIL(("bad write"));
104*4c87aefeSPatrick Mooney 	}
105*4c87aefeSPatrick Mooney 
106*4c87aefeSPatrick Mooney 	/* Wait for it to be read */
107*4c87aefeSPatrick Mooney 	pthread_cond_wait(&cv, &mtx);
108*4c87aefeSPatrick Mooney 	pthread_mutex_unlock(&mtx);
109*4c87aefeSPatrick Mooney }
110*4c87aefeSPatrick Mooney 
111*4c87aefeSPatrick Mooney int
main(int argc,const char * argv[])112*4c87aefeSPatrick Mooney main(int argc, const char *argv[])
113*4c87aefeSPatrick Mooney {
114*4c87aefeSPatrick Mooney 	int unused_pipe[2];
115*4c87aefeSPatrick Mooney 	int flush_pipe[2];
116*4c87aefeSPatrick Mooney 	struct mevent *unused_evp, *flush_evp;
117*4c87aefeSPatrick Mooney 	int count1, count2;
118*4c87aefeSPatrick Mooney 
119*4c87aefeSPatrick Mooney 	start_test(argv[0], 5);
120*4c87aefeSPatrick Mooney 	start_event_thread();
121*4c87aefeSPatrick Mooney 
122*4c87aefeSPatrick Mooney 	/*
123*4c87aefeSPatrick Mooney 	 * Create first pipe and related event
124*4c87aefeSPatrick Mooney 	 */
125*4c87aefeSPatrick Mooney 	if (pipe(unused_pipe) != 0) {
126*4c87aefeSPatrick Mooney 		FAIL_ERRNO("pipe");
127*4c87aefeSPatrick Mooney 	}
128*4c87aefeSPatrick Mooney 	VERBOSE(("unused_pipe[] = { %d, %d }", unused_pipe[0], unused_pipe[1]));
129*4c87aefeSPatrick Mooney 	if (fcntl(unused_pipe[0], F_SETFL, O_NONBLOCK) != 0) {
130*4c87aefeSPatrick Mooney 		FAIL_ERRNO("set pipe nonblocking");
131*4c87aefeSPatrick Mooney 	}
132*4c87aefeSPatrick Mooney 	unused_evp = mevent_add(unused_pipe[0], EVF_READ, not_called_cb, NULL);
133*4c87aefeSPatrick Mooney 	ASSERT_PTR_NEQ(("mevent_add"), unused_evp, NULL);
134*4c87aefeSPatrick Mooney 
135*4c87aefeSPatrick Mooney 	/*
136*4c87aefeSPatrick Mooney 	 * Create flush pipe and related event
137*4c87aefeSPatrick Mooney 	 */
138*4c87aefeSPatrick Mooney 	if (pipe(flush_pipe) != 0) {
139*4c87aefeSPatrick Mooney 		FAIL_ERRNO("pipe");
140*4c87aefeSPatrick Mooney 	}
141*4c87aefeSPatrick Mooney 	VERBOSE(("flush_pipe[] = { %d, %d }", flush_pipe[0],
142*4c87aefeSPatrick Mooney 	    flush_pipe[1]));
143*4c87aefeSPatrick Mooney 	if (fcntl(flush_pipe[0], F_SETFL, O_NONBLOCK) != 0) {
144*4c87aefeSPatrick Mooney 		FAIL_ERRNO("set pipe nonblocking");
145*4c87aefeSPatrick Mooney 	}
146*4c87aefeSPatrick Mooney 	flush_evp = mevent_add(flush_pipe[0], EVF_READ, flush_cb, NULL);
147*4c87aefeSPatrick Mooney 	ASSERT_PTR_NEQ(("mevent_add"), flush_evp, NULL);
148*4c87aefeSPatrick Mooney 
149*4c87aefeSPatrick Mooney 	/* Get count before delete. */
150*4c87aefeSPatrick Mooney 	flush_and_wait(flush_pipe[1]);
151*4c87aefeSPatrick Mooney 	count1 = get_count();
152*4c87aefeSPatrick Mooney 
153*4c87aefeSPatrick Mooney 	/*
154*4c87aefeSPatrick Mooney 	 * Delete the first event and flush a read after the delete is
155*4c87aefeSPatrick Mooney 	 * complete.
156*4c87aefeSPatrick Mooney 	 */
157*4c87aefeSPatrick Mooney 	if (mevent_delete(unused_evp) != 0) {
158*4c87aefeSPatrick Mooney 		FAIL_ERRNO("mevent_delete");
159*4c87aefeSPatrick Mooney 	}
160*4c87aefeSPatrick Mooney 
161*4c87aefeSPatrick Mooney 	/*
162*4c87aefeSPatrick Mooney 	 * Verify count decreased.
163*4c87aefeSPatrick Mooney 	 */
164*4c87aefeSPatrick Mooney 	flush_and_wait(flush_pipe[1]);
165*4c87aefeSPatrick Mooney 	count2 = get_count();
166*4c87aefeSPatrick Mooney 	if (count1 - 1 != count2) {
167*4c87aefeSPatrick Mooney 		FAIL(("mevent_delete() did not decrease count by 1: "
168*4c87aefeSPatrick Mooney 		    "was %d, now %d", count1, count2));
169*4c87aefeSPatrick Mooney 	}
170*4c87aefeSPatrick Mooney 
171*4c87aefeSPatrick Mooney 	PASS();
172*4c87aefeSPatrick Mooney }