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: read.cancel
18*d327dbeaSPatrick Mooney * Assertion: A read is not requeued if mevent_disable() is called while it is
19*d327dbeaSPatrick Mooney * being handled.
20*d327dbeaSPatrick Mooney *
21*d327dbeaSPatrick Mooney * Strategy: 1. Create a pipe
22*d327dbeaSPatrick Mooney * 2. Call mevent_add() to be notified of writes to the pipe. The
23*d327dbeaSPatrick Mooney * callback will signal a cv.
24*d327dbeaSPatrick Mooney * 3. Write to the pipe then wait for a wakeup.
25*d327dbeaSPatrick Mooney * 4. From the read event callback, disable the event then awaken
26*d327dbeaSPatrick Mooney * the main thread.
27*d327dbeaSPatrick Mooney * 5. In the main thread, add a timer event that will awaken the
28*d327dbeaSPatrick Mooney * main thread after a short delay.
29*d327dbeaSPatrick Mooney * 5. Write to the pipe and wait to be awoken. The wakeup should
30*d327dbeaSPatrick Mooney * come from the timer event, not the read event.
31*d327dbeaSPatrick Mooney */
32*d327dbeaSPatrick Mooney
33*d327dbeaSPatrick Mooney #include <errno.h>
34*d327dbeaSPatrick Mooney #include <fcntl.h>
35*d327dbeaSPatrick Mooney #include <pthread.h>
36*d327dbeaSPatrick Mooney #include <signal.h>
37*d327dbeaSPatrick Mooney #include <stdio.h>
38*d327dbeaSPatrick Mooney #include <stdlib.h>
39*d327dbeaSPatrick Mooney #include <strings.h>
40*d327dbeaSPatrick Mooney #include <unistd.h>
41*d327dbeaSPatrick Mooney
42*d327dbeaSPatrick Mooney #include <sys/types.h>
43*d327dbeaSPatrick Mooney #include <sys/stat.h>
44*d327dbeaSPatrick Mooney
45*d327dbeaSPatrick Mooney #include "testlib.h"
46*d327dbeaSPatrick Mooney #include "mevent.h"
47*d327dbeaSPatrick Mooney
48*d327dbeaSPatrick Mooney typedef enum {
49*d327dbeaSPatrick Mooney CB_NONE,
50*d327dbeaSPatrick Mooney CB_READ,
51*d327dbeaSPatrick Mooney CB_TIMER,
52*d327dbeaSPatrick Mooney } lastwake_t;
53*d327dbeaSPatrick Mooney
54*d327dbeaSPatrick Mooney static lastwake_t lastwake = CB_NONE;
55*d327dbeaSPatrick Mooney
56*d327dbeaSPatrick Mooney static pthread_mutex_t mtx = PTHREAD_MUTEX_INITIALIZER;
57*d327dbeaSPatrick Mooney static pthread_cond_t cv = PTHREAD_COND_INITIALIZER;
58*d327dbeaSPatrick Mooney
59*d327dbeaSPatrick Mooney static struct mevent *read_event;
60*d327dbeaSPatrick Mooney
61*d327dbeaSPatrick Mooney static void
munch(int fd,enum ev_type ev,void * arg)62*d327dbeaSPatrick Mooney munch(int fd, enum ev_type ev, void *arg)
63*d327dbeaSPatrick Mooney {
64*d327dbeaSPatrick Mooney ssize_t nbytes;
65*d327dbeaSPatrick Mooney char buf[32] = { 0 };
66*d327dbeaSPatrick Mooney int err;
67*d327dbeaSPatrick Mooney
68*d327dbeaSPatrick Mooney if ((nbytes = read(fd, buf, sizeof (buf))) < 0) {
69*d327dbeaSPatrick Mooney FAIL_ERRNO("bad read");
70*d327dbeaSPatrick Mooney }
71*d327dbeaSPatrick Mooney VERBOSE(("read %ld bytes '%s'", nbytes, buf));
72*d327dbeaSPatrick Mooney
73*d327dbeaSPatrick Mooney err = mevent_disable(read_event);
74*d327dbeaSPatrick Mooney ASSERT_INT_EQ(("mevent_disable: ", strerror(err)), err, 0);
75*d327dbeaSPatrick Mooney
76*d327dbeaSPatrick Mooney pthread_mutex_lock(&mtx);
77*d327dbeaSPatrick Mooney
78*d327dbeaSPatrick Mooney ASSERT_INT_EQ(("wrong lastwake"), lastwake, CB_NONE);
79*d327dbeaSPatrick Mooney lastwake = CB_READ;
80*d327dbeaSPatrick Mooney
81*d327dbeaSPatrick Mooney pthread_cond_signal(&cv);
82*d327dbeaSPatrick Mooney VERBOSE(("wakeup"));
83*d327dbeaSPatrick Mooney
84*d327dbeaSPatrick Mooney pthread_mutex_unlock(&mtx);
85*d327dbeaSPatrick Mooney }
86*d327dbeaSPatrick Mooney
87*d327dbeaSPatrick Mooney static void
tick(int ms,enum ev_type ev,void * arg)88*d327dbeaSPatrick Mooney tick(int ms, enum ev_type ev, void *arg)
89*d327dbeaSPatrick Mooney {
90*d327dbeaSPatrick Mooney pthread_mutex_lock(&mtx);
91*d327dbeaSPatrick Mooney
92*d327dbeaSPatrick Mooney ASSERT_INT_EQ(("wrong lastwake"), lastwake, CB_READ);
93*d327dbeaSPatrick Mooney lastwake = CB_TIMER;
94*d327dbeaSPatrick Mooney
95*d327dbeaSPatrick Mooney pthread_cond_signal(&cv);
96*d327dbeaSPatrick Mooney VERBOSE(("wakeup"));
97*d327dbeaSPatrick Mooney
98*d327dbeaSPatrick Mooney pthread_mutex_unlock(&mtx);
99*d327dbeaSPatrick Mooney }
100*d327dbeaSPatrick Mooney
101*d327dbeaSPatrick Mooney int
main(int argc,const char * argv[])102*d327dbeaSPatrick Mooney main(int argc, const char *argv[])
103*d327dbeaSPatrick Mooney {
104*d327dbeaSPatrick Mooney int pipefds[2];
105*d327dbeaSPatrick Mooney struct mevent *timer;
106*d327dbeaSPatrick Mooney ssize_t written;
107*d327dbeaSPatrick Mooney char *msgs[] = { "first", "second" };
108*d327dbeaSPatrick Mooney char *msg;
109*d327dbeaSPatrick Mooney
110*d327dbeaSPatrick Mooney start_test(argv[0], 5);
111*d327dbeaSPatrick Mooney start_event_thread();
112*d327dbeaSPatrick Mooney
113*d327dbeaSPatrick Mooney if (pipe(pipefds) != 0) {
114*d327dbeaSPatrick Mooney FAIL_ERRNO("pipe");
115*d327dbeaSPatrick Mooney }
116*d327dbeaSPatrick Mooney if (fcntl(pipefds[0], F_SETFL, O_NONBLOCK) != 0) {
117*d327dbeaSPatrick Mooney FAIL_ERRNO("set pipe nonblocking");
118*d327dbeaSPatrick Mooney }
119*d327dbeaSPatrick Mooney
120*d327dbeaSPatrick Mooney /*
121*d327dbeaSPatrick Mooney * First write
122*d327dbeaSPatrick Mooney */
123*d327dbeaSPatrick Mooney msg = msgs[0];
124*d327dbeaSPatrick Mooney read_event = mevent_add(pipefds[0], EVF_READ, munch, msg);
125*d327dbeaSPatrick Mooney ASSERT_PTR_NEQ(("mevent_add pipefd"), read_event, NULL);
126*d327dbeaSPatrick Mooney
127*d327dbeaSPatrick Mooney pthread_mutex_lock(&mtx);
128*d327dbeaSPatrick Mooney written = write(pipefds[1], msg, strlen(msg));
129*d327dbeaSPatrick Mooney if (written < 0) {
130*d327dbeaSPatrick Mooney FAIL_ERRNO("bad write");
131*d327dbeaSPatrick Mooney }
132*d327dbeaSPatrick Mooney ASSERT_INT64_EQ(("write '%s' failed", msg), written, strlen(msg));
133*d327dbeaSPatrick Mooney
134*d327dbeaSPatrick Mooney /*
135*d327dbeaSPatrick Mooney * Wait for it to be read
136*d327dbeaSPatrick Mooney */
137*d327dbeaSPatrick Mooney pthread_cond_wait(&cv, &mtx);
138*d327dbeaSPatrick Mooney ASSERT_INT_EQ(("wrong lastwake"), lastwake, CB_READ);
139*d327dbeaSPatrick Mooney pthread_mutex_unlock(&mtx);
140*d327dbeaSPatrick Mooney
141*d327dbeaSPatrick Mooney /*
142*d327dbeaSPatrick Mooney * Add timer, second write.
143*d327dbeaSPatrick Mooney */
144*d327dbeaSPatrick Mooney msg = msgs[1];
145*d327dbeaSPatrick Mooney timer = mevent_add(50, EVF_TIMER, tick, msg);
146*d327dbeaSPatrick Mooney ASSERT_PTR_NEQ(("mevent_add timer"), timer, NULL);
147*d327dbeaSPatrick Mooney
148*d327dbeaSPatrick Mooney pthread_mutex_lock(&mtx);
149*d327dbeaSPatrick Mooney written = write(pipefds[1], msg, strlen(msg));
150*d327dbeaSPatrick Mooney if (written < 0) {
151*d327dbeaSPatrick Mooney FAIL_ERRNO("bad write");
152*d327dbeaSPatrick Mooney }
153*d327dbeaSPatrick Mooney ASSERT_INT64_EQ(("write '%s' failed", msg), written, strlen(msg));
154*d327dbeaSPatrick Mooney
155*d327dbeaSPatrick Mooney /*
156*d327dbeaSPatrick Mooney * Wait for timer to expire
157*d327dbeaSPatrick Mooney */
158*d327dbeaSPatrick Mooney pthread_cond_wait(&cv, &mtx);
159*d327dbeaSPatrick Mooney ASSERT_INT_EQ(("wrong lastwake"), lastwake, CB_TIMER);
160*d327dbeaSPatrick Mooney pthread_mutex_unlock(&mtx);
161*d327dbeaSPatrick Mooney
162*d327dbeaSPatrick Mooney PASS();
163*d327dbeaSPatrick Mooney }
164