1366f6083SPeter Grehan /*-
2*4d846d26SWarner Losh * SPDX-License-Identifier: BSD-2-Clause
31de7b4b8SPedro F. Giffuni *
4366f6083SPeter Grehan * Copyright (c) 2011 NetApp, Inc.
5366f6083SPeter Grehan * All rights reserved.
6366f6083SPeter Grehan *
7366f6083SPeter Grehan * Redistribution and use in source and binary forms, with or without
8366f6083SPeter Grehan * modification, are permitted provided that the following conditions
9366f6083SPeter Grehan * are met:
10366f6083SPeter Grehan * 1. Redistributions of source code must retain the above copyright
11366f6083SPeter Grehan * notice, this list of conditions and the following disclaimer.
12366f6083SPeter Grehan * 2. Redistributions in binary form must reproduce the above copyright
13366f6083SPeter Grehan * notice, this list of conditions and the following disclaimer in the
14366f6083SPeter Grehan * documentation and/or other materials provided with the distribution.
15366f6083SPeter Grehan *
16366f6083SPeter Grehan * THIS SOFTWARE IS PROVIDED BY NETAPP, INC ``AS IS'' AND
17366f6083SPeter Grehan * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18366f6083SPeter Grehan * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19366f6083SPeter Grehan * ARE DISCLAIMED. IN NO EVENT SHALL NETAPP, INC OR CONTRIBUTORS BE LIABLE
20366f6083SPeter Grehan * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21366f6083SPeter Grehan * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22366f6083SPeter Grehan * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23366f6083SPeter Grehan * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24366f6083SPeter Grehan * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25366f6083SPeter Grehan * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26366f6083SPeter Grehan * SUCH DAMAGE.
27366f6083SPeter Grehan */
28366f6083SPeter Grehan
29366f6083SPeter Grehan /*
30366f6083SPeter Grehan * Test program for the micro event library. Set up a simple TCP echo
31366f6083SPeter Grehan * service.
32366f6083SPeter Grehan *
33366f6083SPeter Grehan * cc mevent_test.c mevent.c -lpthread
34366f6083SPeter Grehan */
35366f6083SPeter Grehan
36366f6083SPeter Grehan #include <sys/types.h>
37151dba4aSPeter Grehan #include <sys/stdint.h>
38151dba4aSPeter Grehan #include <sys/sysctl.h>
39366f6083SPeter Grehan #include <sys/socket.h>
40366f6083SPeter Grehan #include <netinet/in.h>
41151dba4aSPeter Grehan #include <machine/cpufunc.h>
42366f6083SPeter Grehan
43366f6083SPeter Grehan #include <stdio.h>
44366f6083SPeter Grehan #include <stdlib.h>
45366f6083SPeter Grehan #include <pthread.h>
46151dba4aSPeter Grehan #include <unistd.h>
47366f6083SPeter Grehan
48366f6083SPeter Grehan #include "mevent.h"
49366f6083SPeter Grehan
50366f6083SPeter Grehan #define TEST_PORT 4321
51366f6083SPeter Grehan
52366f6083SPeter Grehan static pthread_mutex_t accept_mutex = PTHREAD_MUTEX_INITIALIZER;
53366f6083SPeter Grehan static pthread_cond_t accept_condvar = PTHREAD_COND_INITIALIZER;
54366f6083SPeter Grehan
55151dba4aSPeter Grehan static struct mevent *tevp;
56151dba4aSPeter Grehan
57151dba4aSPeter Grehan
58366f6083SPeter Grehan #define MEVENT_ECHO
59366f6083SPeter Grehan
60151dba4aSPeter Grehan /* Number of timer events to capture */
61151dba4aSPeter Grehan #define TEVSZ 4096
62151dba4aSPeter Grehan uint64_t tevbuf[TEVSZ];
63151dba4aSPeter Grehan
64151dba4aSPeter Grehan static void
timer_print(void)65151dba4aSPeter Grehan timer_print(void)
66151dba4aSPeter Grehan {
67151dba4aSPeter Grehan uint64_t min, max, diff, sum, tsc_freq;
68151dba4aSPeter Grehan size_t len;
69151dba4aSPeter Grehan int j;
70151dba4aSPeter Grehan
71151dba4aSPeter Grehan min = UINT64_MAX;
72151dba4aSPeter Grehan max = 0;
73151dba4aSPeter Grehan sum = 0;
74151dba4aSPeter Grehan
75151dba4aSPeter Grehan len = sizeof(tsc_freq);
76151dba4aSPeter Grehan sysctlbyname("machdep.tsc_freq", &tsc_freq, &len, NULL, 0);
77151dba4aSPeter Grehan
78151dba4aSPeter Grehan for (j = 1; j < TEVSZ; j++) {
79151dba4aSPeter Grehan /* Convert a tsc diff into microseconds */
80151dba4aSPeter Grehan diff = (tevbuf[j] - tevbuf[j-1]) * 1000000 / tsc_freq;
81151dba4aSPeter Grehan sum += diff;
82151dba4aSPeter Grehan if (min > diff)
83151dba4aSPeter Grehan min = diff;
84151dba4aSPeter Grehan if (max < diff)
85151dba4aSPeter Grehan max = diff;
86151dba4aSPeter Grehan }
87151dba4aSPeter Grehan
88151dba4aSPeter Grehan printf("timers done: usecs, min %ld, max %ld, mean %ld\n", min, max,
89151dba4aSPeter Grehan sum/(TEVSZ - 1));
90151dba4aSPeter Grehan }
91151dba4aSPeter Grehan
92151dba4aSPeter Grehan static void
timer_callback(int fd,enum ev_type type,void * param)93151dba4aSPeter Grehan timer_callback(int fd, enum ev_type type, void *param)
94151dba4aSPeter Grehan {
95151dba4aSPeter Grehan static int i;
96151dba4aSPeter Grehan
97151dba4aSPeter Grehan if (i >= TEVSZ)
98151dba4aSPeter Grehan abort();
99151dba4aSPeter Grehan
100151dba4aSPeter Grehan tevbuf[i++] = rdtsc();
101151dba4aSPeter Grehan
102151dba4aSPeter Grehan if (i == TEVSZ) {
103151dba4aSPeter Grehan mevent_delete(tevp);
104151dba4aSPeter Grehan timer_print();
105151dba4aSPeter Grehan }
106151dba4aSPeter Grehan }
107151dba4aSPeter Grehan
108151dba4aSPeter Grehan
109366f6083SPeter Grehan #ifdef MEVENT_ECHO
110366f6083SPeter Grehan struct esync {
111366f6083SPeter Grehan pthread_mutex_t e_mt;
112366f6083SPeter Grehan pthread_cond_t e_cond;
113366f6083SPeter Grehan };
114366f6083SPeter Grehan
115366f6083SPeter Grehan static void
echoer_callback(int fd,enum ev_type type,void * param)116366f6083SPeter Grehan echoer_callback(int fd, enum ev_type type, void *param)
117366f6083SPeter Grehan {
118366f6083SPeter Grehan struct esync *sync = param;
119366f6083SPeter Grehan
120366f6083SPeter Grehan pthread_mutex_lock(&sync->e_mt);
121366f6083SPeter Grehan pthread_cond_signal(&sync->e_cond);
122366f6083SPeter Grehan pthread_mutex_unlock(&sync->e_mt);
123366f6083SPeter Grehan }
124366f6083SPeter Grehan
125366f6083SPeter Grehan static void *
echoer(void * param)126366f6083SPeter Grehan echoer(void *param)
127366f6083SPeter Grehan {
128366f6083SPeter Grehan struct esync sync;
129366f6083SPeter Grehan struct mevent *mev;
130366f6083SPeter Grehan char buf[128];
131366f6083SPeter Grehan int fd = (int)(uintptr_t) param;
132366f6083SPeter Grehan int len;
133366f6083SPeter Grehan
134366f6083SPeter Grehan pthread_mutex_init(&sync.e_mt, NULL);
135366f6083SPeter Grehan pthread_cond_init(&sync.e_cond, NULL);
136366f6083SPeter Grehan
137366f6083SPeter Grehan pthread_mutex_lock(&sync.e_mt);
138366f6083SPeter Grehan
139366f6083SPeter Grehan mev = mevent_add(fd, EVF_READ, echoer_callback, &sync);
140366f6083SPeter Grehan if (mev == NULL) {
141366f6083SPeter Grehan printf("Could not allocate echoer event\n");
142989e062bSMarcelo Araujo exit(4);
143366f6083SPeter Grehan }
144366f6083SPeter Grehan
145366f6083SPeter Grehan while (!pthread_cond_wait(&sync.e_cond, &sync.e_mt)) {
146366f6083SPeter Grehan len = read(fd, buf, sizeof(buf));
147366f6083SPeter Grehan if (len > 0) {
148366f6083SPeter Grehan write(fd, buf, len);
149366f6083SPeter Grehan write(0, buf, len);
150366f6083SPeter Grehan } else {
151366f6083SPeter Grehan break;
152366f6083SPeter Grehan }
153366f6083SPeter Grehan }
154366f6083SPeter Grehan
155366f6083SPeter Grehan mevent_delete_close(mev);
156366f6083SPeter Grehan
157366f6083SPeter Grehan pthread_mutex_unlock(&sync.e_mt);
158366f6083SPeter Grehan pthread_mutex_destroy(&sync.e_mt);
159366f6083SPeter Grehan pthread_cond_destroy(&sync.e_cond);
160151dba4aSPeter Grehan
161151dba4aSPeter Grehan return (NULL);
162366f6083SPeter Grehan }
163366f6083SPeter Grehan
164366f6083SPeter Grehan #else
165366f6083SPeter Grehan
166366f6083SPeter Grehan static void *
echoer(void * param)167366f6083SPeter Grehan echoer(void *param)
168366f6083SPeter Grehan {
169366f6083SPeter Grehan char buf[128];
170366f6083SPeter Grehan int fd = (int)(uintptr_t) param;
171366f6083SPeter Grehan int len;
172366f6083SPeter Grehan
173366f6083SPeter Grehan while ((len = read(fd, buf, sizeof(buf))) > 0) {
174366f6083SPeter Grehan write(1, buf, len);
175366f6083SPeter Grehan }
176151dba4aSPeter Grehan
177151dba4aSPeter Grehan return (NULL);
178366f6083SPeter Grehan }
179366f6083SPeter Grehan #endif /* MEVENT_ECHO */
180366f6083SPeter Grehan
181366f6083SPeter Grehan static void
acceptor_callback(int fd,enum ev_type type,void * param)182366f6083SPeter Grehan acceptor_callback(int fd, enum ev_type type, void *param)
183366f6083SPeter Grehan {
184366f6083SPeter Grehan pthread_mutex_lock(&accept_mutex);
185366f6083SPeter Grehan pthread_cond_signal(&accept_condvar);
186366f6083SPeter Grehan pthread_mutex_unlock(&accept_mutex);
187366f6083SPeter Grehan }
188366f6083SPeter Grehan
189366f6083SPeter Grehan static void *
acceptor(void * param)190366f6083SPeter Grehan acceptor(void *param)
191366f6083SPeter Grehan {
192366f6083SPeter Grehan struct sockaddr_in sin;
193366f6083SPeter Grehan pthread_t tid;
194366f6083SPeter Grehan int news;
195366f6083SPeter Grehan int s;
196151dba4aSPeter Grehan static int first;
197366f6083SPeter Grehan
198366f6083SPeter Grehan if ((s = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
199989e062bSMarcelo Araujo perror("cannot create socket");
200989e062bSMarcelo Araujo exit(4);
201366f6083SPeter Grehan }
202366f6083SPeter Grehan
203366f6083SPeter Grehan sin.sin_len = sizeof(sin);
204366f6083SPeter Grehan sin.sin_family = AF_INET;
205366f6083SPeter Grehan sin.sin_addr.s_addr = htonl(INADDR_ANY);
206366f6083SPeter Grehan sin.sin_port = htons(TEST_PORT);
207366f6083SPeter Grehan
208366f6083SPeter Grehan if (bind(s, (struct sockaddr *)&sin, sizeof(sin)) < 0) {
209989e062bSMarcelo Araujo perror("cannot bind socket");
210989e062bSMarcelo Araujo exit(4);
211366f6083SPeter Grehan }
212366f6083SPeter Grehan
213366f6083SPeter Grehan if (listen(s, 1) < 0) {
214989e062bSMarcelo Araujo perror("cannot listen socket");
215989e062bSMarcelo Araujo exit(4);
216366f6083SPeter Grehan }
217366f6083SPeter Grehan
218366f6083SPeter Grehan (void) mevent_add(s, EVF_READ, acceptor_callback, NULL);
219366f6083SPeter Grehan
220366f6083SPeter Grehan pthread_mutex_lock(&accept_mutex);
221366f6083SPeter Grehan
222366f6083SPeter Grehan while (!pthread_cond_wait(&accept_condvar, &accept_mutex)) {
223366f6083SPeter Grehan news = accept(s, NULL, NULL);
224366f6083SPeter Grehan if (news < 0) {
225366f6083SPeter Grehan perror("accept error");
226366f6083SPeter Grehan } else {
227151dba4aSPeter Grehan static int first = 1;
228151dba4aSPeter Grehan
229151dba4aSPeter Grehan if (first) {
230151dba4aSPeter Grehan /*
231151dba4aSPeter Grehan * Start a timer
232151dba4aSPeter Grehan */
233151dba4aSPeter Grehan first = 0;
234151dba4aSPeter Grehan tevp = mevent_add(1, EVF_TIMER, timer_callback,
235151dba4aSPeter Grehan NULL);
236151dba4aSPeter Grehan }
237151dba4aSPeter Grehan
238366f6083SPeter Grehan printf("incoming connection, spawning thread\n");
239366f6083SPeter Grehan pthread_create(&tid, NULL, echoer,
240366f6083SPeter Grehan (void *)(uintptr_t)news);
241366f6083SPeter Grehan }
242366f6083SPeter Grehan }
243151dba4aSPeter Grehan
244151dba4aSPeter Grehan return (NULL);
245366f6083SPeter Grehan }
246366f6083SPeter Grehan
main()247366f6083SPeter Grehan main()
248366f6083SPeter Grehan {
249366f6083SPeter Grehan pthread_t tid;
250366f6083SPeter Grehan
251366f6083SPeter Grehan pthread_create(&tid, NULL, acceptor, NULL);
252366f6083SPeter Grehan
253366f6083SPeter Grehan mevent_dispatch();
254366f6083SPeter Grehan }
255