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.pause
18*d327dbeaSPatrick Mooney  *   Assertion: mevent_disable() can be used to pause reads.
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 signal a cv.
23*d327dbeaSPatrick Mooney  *		3. In a loop, write to the pipe then wait on the cv.
24*d327dbeaSPatrick Mooney  */
25*d327dbeaSPatrick Mooney 
26*d327dbeaSPatrick Mooney #include <errno.h>
27*d327dbeaSPatrick Mooney #include <fcntl.h>
28*d327dbeaSPatrick Mooney #include <pthread.h>
29*d327dbeaSPatrick Mooney #include <signal.h>
30*d327dbeaSPatrick Mooney #include <stdio.h>
31*d327dbeaSPatrick Mooney #include <stdlib.h>
32*d327dbeaSPatrick Mooney #include <strings.h>
33*d327dbeaSPatrick Mooney #include <unistd.h>
34*d327dbeaSPatrick Mooney 
35*d327dbeaSPatrick Mooney #include <sys/types.h>
36*d327dbeaSPatrick Mooney #include <sys/stat.h>
37*d327dbeaSPatrick Mooney 
38*d327dbeaSPatrick Mooney #include "testlib.h"
39*d327dbeaSPatrick Mooney #include "mevent.h"
40*d327dbeaSPatrick Mooney 
41*d327dbeaSPatrick Mooney static pthread_mutex_t mtx = PTHREAD_MUTEX_INITIALIZER;
42*d327dbeaSPatrick Mooney static pthread_cond_t cv = PTHREAD_COND_INITIALIZER;
43*d327dbeaSPatrick Mooney 
44*d327dbeaSPatrick Mooney static char cookie[] = "Chocolate chip with fudge stripes";
45*d327dbeaSPatrick Mooney 
46*d327dbeaSPatrick Mooney /*
47*d327dbeaSPatrick Mooney  * After this many bytes are sent, writes will get batched up, progress will be
48*d327dbeaSPatrick Mooney  * made on the write side via an interval timer
49*d327dbeaSPatrick Mooney  */
50*d327dbeaSPatrick Mooney const int pauseat = 8;
51*d327dbeaSPatrick Mooney 
52*d327dbeaSPatrick Mooney static void
munch(int fd,enum ev_type ev,void * arg)53*d327dbeaSPatrick Mooney munch(int fd, enum ev_type ev, void *arg)
54*d327dbeaSPatrick Mooney {
55*d327dbeaSPatrick Mooney 	static int i = 0;
56*d327dbeaSPatrick Mooney 	char buf[sizeof (cookie)] = { 0 };
57*d327dbeaSPatrick Mooney 	ssize_t nbytes;
58*d327dbeaSPatrick Mooney 	ssize_t expected;
59*d327dbeaSPatrick Mooney 
60*d327dbeaSPatrick Mooney 	ASSERT_INT_EQ(("bad event"), ev, EVF_READ);
61*d327dbeaSPatrick Mooney 	ASSERT_PTR_EQ(("bad cookie"), arg, cookie);
62*d327dbeaSPatrick Mooney 
63*d327dbeaSPatrick Mooney 	/*
64*d327dbeaSPatrick Mooney 	 * For the first while, expect data to come a byte at a time.  After the
65*d327dbeaSPatrick Mooney 	 * pause, we should get a burst with the rest of the data.
66*d327dbeaSPatrick Mooney 	 */
67*d327dbeaSPatrick Mooney 	if (i > pauseat) {
68*d327dbeaSPatrick Mooney 		expected = strlen(cookie) - pauseat - 1;
69*d327dbeaSPatrick Mooney 	} else {
70*d327dbeaSPatrick Mooney 		expected = 1;
71*d327dbeaSPatrick Mooney 	}
72*d327dbeaSPatrick Mooney 
73*d327dbeaSPatrick Mooney 	if ((nbytes = read(fd, buf, sizeof (buf))) < 0) {
74*d327dbeaSPatrick Mooney 		FAIL_ERRNO("bad read");
75*d327dbeaSPatrick Mooney 	}
76*d327dbeaSPatrick Mooney 	VERBOSE(("read %ld bytes '%s'", nbytes, buf));
77*d327dbeaSPatrick Mooney 
78*d327dbeaSPatrick Mooney 	ASSERT_INT64_EQ(("wanted a byte of cookie"), nbytes, expected);
79*d327dbeaSPatrick Mooney 
80*d327dbeaSPatrick Mooney 	if (expected == 1) {
81*d327dbeaSPatrick Mooney 		ASSERT_CHAR_EQ(("bad byte %d of cookie", i), buf[0], cookie[i]);
82*d327dbeaSPatrick Mooney 	} else {
83*d327dbeaSPatrick Mooney 		ASSERT_STR_EQ(("bad last half of cookie"), buf, &cookie[i]);
84*d327dbeaSPatrick Mooney 	}
85*d327dbeaSPatrick Mooney 
86*d327dbeaSPatrick Mooney 	pthread_mutex_lock(&mtx);
87*d327dbeaSPatrick Mooney 	pthread_cond_signal(&cv);
88*d327dbeaSPatrick Mooney 	VERBOSE(("wakeup"));
89*d327dbeaSPatrick Mooney 	pthread_mutex_unlock(&mtx);
90*d327dbeaSPatrick Mooney 
91*d327dbeaSPatrick Mooney 	i++;
92*d327dbeaSPatrick Mooney }
93*d327dbeaSPatrick Mooney 
94*d327dbeaSPatrick Mooney static void
tick(int ms,enum ev_type ev,void * arg)95*d327dbeaSPatrick Mooney tick(int ms, enum ev_type ev, void *arg)
96*d327dbeaSPatrick Mooney {
97*d327dbeaSPatrick Mooney 	pthread_mutex_lock(&mtx);
98*d327dbeaSPatrick Mooney 	pthread_cond_signal(&cv);
99*d327dbeaSPatrick Mooney 	VERBOSE(("wakeup"));
100*d327dbeaSPatrick Mooney 	pthread_mutex_unlock(&mtx);
101*d327dbeaSPatrick Mooney }
102*d327dbeaSPatrick Mooney 
103*d327dbeaSPatrick Mooney int
main(int argc,const char * argv[])104*d327dbeaSPatrick Mooney main(int argc, const char *argv[])
105*d327dbeaSPatrick Mooney {
106*d327dbeaSPatrick Mooney 	int pipefds[2];
107*d327dbeaSPatrick Mooney 	struct mevent *evp, *timer;
108*d327dbeaSPatrick Mooney 	ssize_t written;
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 	evp = mevent_add(pipefds[0], EVF_READ, munch, cookie);
121*d327dbeaSPatrick Mooney 	ASSERT_PTR_NEQ(("mevent_add pipefd"), evp, NULL);
122*d327dbeaSPatrick Mooney 
123*d327dbeaSPatrick Mooney 	for (int i = 0; cookie[i] != 0; i++) {
124*d327dbeaSPatrick Mooney 		pthread_mutex_lock(&mtx);
125*d327dbeaSPatrick Mooney 		written = write(pipefds[1], cookie + i, 1);
126*d327dbeaSPatrick Mooney 		if (written < 0) {
127*d327dbeaSPatrick Mooney 			FAIL_ERRNO("bad write");
128*d327dbeaSPatrick Mooney 		}
129*d327dbeaSPatrick Mooney 		ASSERT_INT64_EQ(("write byte %d of cookie", i), written, 1);
130*d327dbeaSPatrick Mooney 
131*d327dbeaSPatrick Mooney 		/* Wait for it to be read */
132*d327dbeaSPatrick Mooney 		pthread_cond_wait(&cv, &mtx);
133*d327dbeaSPatrick Mooney 		pthread_mutex_unlock(&mtx);
134*d327dbeaSPatrick Mooney 
135*d327dbeaSPatrick Mooney 		if (i == pauseat) {
136*d327dbeaSPatrick Mooney 			timer = mevent_add(10, EVF_TIMER, tick,
137*d327dbeaSPatrick Mooney 			    &cookie[pauseat]);
138*d327dbeaSPatrick Mooney 			ASSERT_PTR_NEQ(("mevent_add timer"), timer, NULL);
139*d327dbeaSPatrick Mooney 			VERBOSE(("disable munch"));
140*d327dbeaSPatrick Mooney 			mevent_disable(evp);
141*d327dbeaSPatrick Mooney 		}
142*d327dbeaSPatrick Mooney 	}
143*d327dbeaSPatrick Mooney 
144*d327dbeaSPatrick Mooney 	pthread_mutex_lock(&mtx);
145*d327dbeaSPatrick Mooney 
146*d327dbeaSPatrick Mooney 	mevent_enable(evp);
147*d327dbeaSPatrick Mooney 
148*d327dbeaSPatrick Mooney 	pthread_cond_wait(&cv, &mtx);
149*d327dbeaSPatrick Mooney 	pthread_mutex_unlock(&mtx);
150*d327dbeaSPatrick Mooney 
151*d327dbeaSPatrick Mooney 	PASS();
152*d327dbeaSPatrick Mooney }
153