11590Srgrimes/*-
21590Srgrimes * SPDX-License-Identifier: BSD-2-Clause
31590Srgrimes *
41590Srgrimes * Copyright (c) 2011 NetApp, Inc.
51590Srgrimes * All rights reserved.
61590Srgrimes *
71590Srgrimes * Redistribution and use in source and binary forms, with or without
81590Srgrimes * modification, are permitted provided that the following conditions
91590Srgrimes * are met:
101590Srgrimes * 1. Redistributions of source code must retain the above copyright
111590Srgrimes *    notice, this list of conditions and the following disclaimer.
121590Srgrimes * 2. Redistributions in binary form must reproduce the above copyright
131590Srgrimes *    notice, this list of conditions and the following disclaimer in the
141590Srgrimes *    documentation and/or other materials provided with the distribution.
151590Srgrimes *
161590Srgrimes * THIS SOFTWARE IS PROVIDED BY NETAPP, INC ``AS IS'' AND
171590Srgrimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
181590Srgrimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
191590Srgrimes * ARE DISCLAIMED.  IN NO EVENT SHALL NETAPP, INC OR CONTRIBUTORS BE LIABLE
201590Srgrimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
211590Srgrimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
221590Srgrimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
231590Srgrimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
241590Srgrimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
251590Srgrimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
261590Srgrimes * SUCH DAMAGE.
271590Srgrimes */
281590Srgrimes
291590Srgrimes/*
301590Srgrimes * Test program for the micro event library. Set up a simple TCP echo
311590Srgrimes * service.
321590Srgrimes *
331590Srgrimes *  cc mevent_test.c mevent.c -lpthread
341590Srgrimes */
351590Srgrimes
361590Srgrimes#include <sys/types.h>
371590Srgrimes#include <sys/stdint.h>
3827169Scharnier#include <sys/sysctl.h>
3923693Speter#include <sys/socket.h>
4027169Scharnier#include <netinet/in.h>
4127169Scharnier#include <machine/cpufunc.h>
4250127Simp
4327169Scharnier#include <stdio.h>
441590Srgrimes#include <stdlib.h>
451590Srgrimes#include <pthread.h>
461590Srgrimes#include <unistd.h>
471590Srgrimes
481590Srgrimes#include "mevent.h"
491590Srgrimes
5023693Speter#define TEST_PORT	4321
511590Srgrimes
521590Srgrimesstatic pthread_mutex_t accept_mutex = PTHREAD_MUTEX_INITIALIZER;
531590Srgrimesstatic pthread_cond_t accept_condvar = PTHREAD_COND_INITIALIZER;
541590Srgrimes
551590Srgrimesstatic struct mevent *tevp;
561590Srgrimes
571590Srgrimes
581590Srgrimes#define MEVENT_ECHO
591590Srgrimes
602537Spst/* Number of timer events to capture */
611590Srgrimes#define TEVSZ	4096
621590Srgrimesuint64_t tevbuf[TEVSZ];
631590Srgrimes
641590Srgrimesstatic void
651590Srgrimestimer_print(void)
661590Srgrimes{
671590Srgrimes	uint64_t min, max, diff, sum, tsc_freq;
681590Srgrimes	size_t len;
691590Srgrimes	int j;
701590Srgrimes
711590Srgrimes	min = UINT64_MAX;
721590Srgrimes	max = 0;
731590Srgrimes	sum = 0;
741590Srgrimes
751590Srgrimes	len = sizeof(tsc_freq);
761590Srgrimes	sysctlbyname("machdep.tsc_freq", &tsc_freq, &len, NULL, 0);
771590Srgrimes
781590Srgrimes	for (j = 1; j < TEVSZ; j++) {
791590Srgrimes		/* Convert a tsc diff into microseconds */
801590Srgrimes		diff = (tevbuf[j] - tevbuf[j-1]) * 1000000 / tsc_freq;
811590Srgrimes		sum += diff;
8250127Simp		if (min > diff)
8350127Simp			min = diff;
841590Srgrimes		if (max < diff)
851590Srgrimes			max = diff;
861590Srgrimes	}
871590Srgrimes
881590Srgrimes	printf("timers done: usecs, min %ld, max %ld, mean %ld\n", min, max,
891590Srgrimes	    sum/(TEVSZ - 1));
901590Srgrimes}
9150127Simp
9250127Simpstatic void
9350127Simptimer_callback(int fd, enum ev_type type, void *param)
9450127Simp{
9550127Simp	static int i;
961590Srgrimes
9750127Simp	if (i >= TEVSZ)
9850127Simp		abort();
991590Srgrimes
10050127Simp	tevbuf[i++] = rdtsc();
10150127Simp
10223693Speter	if (i == TEVSZ) {
1031590Srgrimes		mevent_delete(tevp);
1041590Srgrimes		timer_print();
1051590Srgrimes	}
1061590Srgrimes}
1071590Srgrimes
1081590Srgrimes
1091590Srgrimes#ifdef MEVENT_ECHO
1101590Srgrimesstruct esync {
1111590Srgrimes	pthread_mutex_t	e_mt;
1121590Srgrimes	pthread_cond_t	e_cond;
1131590Srgrimes};
1141590Srgrimes
1151590Srgrimesstatic void
1161590Srgrimesechoer_callback(int fd, enum ev_type type, void *param)
1171590Srgrimes{
1181590Srgrimes	struct esync *sync = param;
1191590Srgrimes
1201590Srgrimes	pthread_mutex_lock(&sync->e_mt);
1211590Srgrimes	pthread_cond_signal(&sync->e_cond);
1221590Srgrimes	pthread_mutex_unlock(&sync->e_mt);
1231590Srgrimes}
1241590Srgrimes
1251590Srgrimesstatic void *
1261590Srgrimesechoer(void *param)
12727169Scharnier{
1281590Srgrimes	struct esync sync;
1291590Srgrimes	struct mevent *mev;
1301590Srgrimes	char buf[128];
1311590Srgrimes	int fd = (int)(uintptr_t) param;
1321590Srgrimes	int len;
1331590Srgrimes
1341590Srgrimes	pthread_mutex_init(&sync.e_mt, NULL);
1351590Srgrimes	pthread_cond_init(&sync.e_cond, NULL);
1361590Srgrimes
1371590Srgrimes	pthread_mutex_lock(&sync.e_mt);
1381590Srgrimes
1391590Srgrimes	mev = mevent_add(fd, EVF_READ, echoer_callback, &sync);
1401590Srgrimes	if (mev == NULL) {
1411590Srgrimes		printf("Could not allocate echoer event\n");
1421590Srgrimes		exit(4);
1431590Srgrimes	}
1441590Srgrimes
1451590Srgrimes	while (!pthread_cond_wait(&sync.e_cond, &sync.e_mt)) {
1461590Srgrimes		len = read(fd, buf, sizeof(buf));
1471590Srgrimes		if (len > 0) {
1481590Srgrimes			write(fd, buf, len);
1491590Srgrimes			write(0, buf, len);
1501590Srgrimes		} else {
1511590Srgrimes			break;
1521590Srgrimes		}
1531590Srgrimes	}
1541590Srgrimes
1551590Srgrimes	mevent_delete_close(mev);
1561590Srgrimes
1571590Srgrimes	pthread_mutex_unlock(&sync.e_mt);
1581590Srgrimes	pthread_mutex_destroy(&sync.e_mt);
1591590Srgrimes	pthread_cond_destroy(&sync.e_cond);
1601590Srgrimes
1611590Srgrimes	return (NULL);
1621590Srgrimes}
1631590Srgrimes
1641590Srgrimes#else
1651590Srgrimes
1661590Srgrimesstatic void *
1671590Srgrimesechoer(void *param)
1681590Srgrimes{
1691590Srgrimes	char buf[128];
1701590Srgrimes	int fd = (int)(uintptr_t) param;
1711590Srgrimes	int len;
1721590Srgrimes
1731590Srgrimes	while ((len = read(fd, buf, sizeof(buf))) > 0) {
1741590Srgrimes		write(1, buf, len);
1751590Srgrimes	}
1761590Srgrimes
1771590Srgrimes	return (NULL);
1781590Srgrimes}
1791590Srgrimes#endif /* MEVENT_ECHO */
1801590Srgrimes
1811590Srgrimesstatic void
1821590Srgrimesacceptor_callback(int fd, enum ev_type type, void *param)
1831590Srgrimes{
18423693Speter	pthread_mutex_lock(&accept_mutex);
1851590Srgrimes	pthread_cond_signal(&accept_condvar);
1861590Srgrimes	pthread_mutex_unlock(&accept_mutex);
1871590Srgrimes}
1881590Srgrimes
18923693Speterstatic void *
1901590Srgrimesacceptor(void *param)
19123693Speter{
19223693Speter	struct sockaddr_in sin;
1931590Srgrimes	pthread_t tid;
1941590Srgrimes	int news;
19523693Speter	int s;
1961590Srgrimes	static int first;
1971590Srgrimes
1981590Srgrimes	if ((s = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
1991590Srgrimes		perror("cannot create socket");
2001590Srgrimes		exit(4);
2011590Srgrimes	}
2021590Srgrimes
2031590Srgrimes	sin.sin_len = sizeof(sin);
2041590Srgrimes	sin.sin_family = AF_INET;
2051590Srgrimes	sin.sin_addr.s_addr = htonl(INADDR_ANY);
20623693Speter	sin.sin_port = htons(TEST_PORT);
20723693Speter
2081590Srgrimes	if (bind(s, (struct sockaddr *)&sin, sizeof(sin)) < 0) {
2091590Srgrimes		perror("cannot bind socket");
2101590Srgrimes		exit(4);
2111590Srgrimes	}
2121590Srgrimes
2131590Srgrimes	if (listen(s, 1) < 0) {
2141590Srgrimes		perror("cannot listen socket");
2155369Sjkh		exit(4);
2165369Sjkh	}
2171590Srgrimes
2181590Srgrimes	(void) mevent_add(s, EVF_READ, acceptor_callback, NULL);
21923693Speter
2201590Srgrimes	pthread_mutex_lock(&accept_mutex);
2211590Srgrimes
2221590Srgrimes	while (!pthread_cond_wait(&accept_condvar, &accept_mutex)) {
2231590Srgrimes		news = accept(s, NULL, NULL);
2241590Srgrimes		if (news < 0) {
2255369Sjkh			perror("accept error");
2265369Sjkh		} else {
2275369Sjkh			static int first = 1;
2281590Srgrimes
2291590Srgrimes			if (first) {
2301590Srgrimes				/*
2311590Srgrimes				 * Start a timer
2321590Srgrimes				 */
2331590Srgrimes				first = 0;
2341590Srgrimes				tevp = mevent_add(1, EVF_TIMER, timer_callback,
23523693Speter						  NULL);
23623693Speter			}
23723693Speter
23823693Speter			printf("incoming connection, spawning thread\n");
2391590Srgrimes			pthread_create(&tid, NULL, echoer,
2401590Srgrimes				       (void *)(uintptr_t)news);
2411590Srgrimes		}
2421590Srgrimes	}
2431590Srgrimes
2441590Srgrimes	return (NULL);
2451590Srgrimes}
2461590Srgrimes
24723693Spetermain()
2481590Srgrimes{
2491590Srgrimes	pthread_t tid;
2501590Srgrimes
2511590Srgrimes	pthread_create(&tid, NULL, acceptor, NULL);
2521590Srgrimes
2531590Srgrimes	mevent_dispatch();
2541590Srgrimes}
2551590Srgrimes