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