Skip site navigation (1)Skip section navigation (2)
Date:      Thu, 19 Sep 2013 04:48:26 +0000 (UTC)
From:      Peter Grehan <grehan@FreeBSD.org>
To:        src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org
Subject:   svn commit: r255690 - head/usr.sbin/bhyve
Message-ID:  <201309190448.r8J4mQP8003412@svn.freebsd.org>

next in thread | raw e-mail | index | archive | help
Author: grehan
Date: Thu Sep 19 04:48:26 2013
New Revision: 255690
URL: http://svnweb.freebsd.org/changeset/base/255690

Log:
  Add simplistic periodic timer support to mevent using kqueue's
  timer support. This should be enough for the emulation of
  h/w periodic timers (and no more) e.g. some of the 8254's
  more esoteric modes that happen to be used by non-FreeBSD o/s's.
  
  Approved by:	re@ (blanket)

Modified:
  head/usr.sbin/bhyve/mevent.c
  head/usr.sbin/bhyve/mevent.h
  head/usr.sbin/bhyve/mevent_test.c

Modified: head/usr.sbin/bhyve/mevent.c
==============================================================================
--- head/usr.sbin/bhyve/mevent.c	Thu Sep 19 04:29:03 2013	(r255689)
+++ head/usr.sbin/bhyve/mevent.c	Thu Sep 19 04:48:26 2013	(r255690)
@@ -59,12 +59,15 @@ __FBSDID("$FreeBSD$");
 extern char *vmname;
 
 static pthread_t mevent_tid;
+static int mevent_timid = 43;
 static int mevent_pipefd[2];
 static pthread_mutex_t mevent_lmutex = PTHREAD_MUTEX_INITIALIZER;
 
 struct mevent {	
 	void	(*me_func)(int, enum ev_type, void *);
+#define me_msecs me_fd
 	int	me_fd;
+	int	me_timid;
 	enum ev_type me_type;
 	void    *me_param;
 	int	me_cq;
@@ -129,6 +132,9 @@ mevent_kq_filter(struct mevent *mevp)
 	if (mevp->me_type == EVF_WRITE)
 		retval = EVFILT_WRITE;
 
+	if (mevp->me_type == EVF_TIMER)
+		retval = EVFILT_TIMER;
+
 	return (retval);
 }
 
@@ -140,6 +146,8 @@ mevent_kq_flags(struct mevent *mevp)
 	switch (mevp->me_state) {
 	case MEV_ENABLE:
 		ret = EV_ADD;
+		if (mevp->me_type == EVF_TIMER)
+			ret |= EV_ENABLE;
 		break;
 	case MEV_DISABLE:
 		ret = EV_DISABLE;
@@ -177,11 +185,16 @@ mevent_build(int mfd, struct kevent *kev
 			 */
 			close(mevp->me_fd);
 		} else {
-			kev[i].ident = mevp->me_fd;
+			if (mevp->me_type == EVF_TIMER) {
+				kev[i].ident = mevp->me_timid;
+				kev[i].data = mevp->me_msecs;
+			} else {
+				kev[i].ident = mevp->me_fd;
+				kev[i].data = 0;
+			}
 			kev[i].filter = mevent_kq_filter(mevp);
 			kev[i].flags = mevent_kq_flags(mevp);
 			kev[i].fflags = mevent_kq_fflags(mevp);
-			kev[i].data = 0;
 			kev[i].udata = mevp;
 			i++;
 		}
@@ -219,12 +232,12 @@ mevent_handle(struct kevent *kev, int nu
 }
 
 struct mevent *
-mevent_add(int fd, enum ev_type type,
+mevent_add(int tfd, enum ev_type type,
 	   void (*func)(int, enum ev_type, void *), void *param)
 {
 	struct mevent *lp, *mevp;
 
-	if (fd < 0 || func == NULL) {
+	if (tfd < 0 || func == NULL) {
 		return (NULL);
 	}
 
@@ -236,13 +249,15 @@ mevent_add(int fd, enum ev_type type,
 	 * Verify that the fd/type tuple is not present in any list
 	 */
 	LIST_FOREACH(lp, &global_head, me_list) {
-		if (lp->me_fd == fd && lp->me_type == type) {
+		if (type != EVF_TIMER && lp->me_fd == tfd &&
+		    lp->me_type == type) {
 			goto exit;
 		}
 	}
 
 	LIST_FOREACH(lp, &change_head, me_list) {
-		if (lp->me_fd == fd && lp->me_type == type) {
+		if (type != EVF_TIMER && lp->me_fd == tfd &&
+		    lp->me_type == type) {
 			goto exit;
 		}
 	}
@@ -256,7 +271,11 @@ mevent_add(int fd, enum ev_type type,
 	}
 
 	memset(mevp, 0, sizeof(struct mevent));
-	mevp->me_fd = fd;
+	if (type == EVF_TIMER) {
+		mevp->me_msecs = tfd;
+		mevp->me_timid = mevent_timid++;
+	} else
+		mevp->me_fd = tfd;
 	mevp->me_type = type;
 	mevp->me_func = func;
 	mevp->me_param = param;

Modified: head/usr.sbin/bhyve/mevent.h
==============================================================================
--- head/usr.sbin/bhyve/mevent.h	Thu Sep 19 04:29:03 2013	(r255689)
+++ head/usr.sbin/bhyve/mevent.h	Thu Sep 19 04:48:26 2013	(r255690)
@@ -31,7 +31,8 @@
 
 enum ev_type {
 	EVF_READ,
-	EVF_WRITE
+	EVF_WRITE,
+	EVF_TIMER
 };
 
 struct mevent;

Modified: head/usr.sbin/bhyve/mevent_test.c
==============================================================================
--- head/usr.sbin/bhyve/mevent_test.c	Thu Sep 19 04:29:03 2013	(r255689)
+++ head/usr.sbin/bhyve/mevent_test.c	Thu Sep 19 04:48:26 2013	(r255690)
@@ -34,12 +34,16 @@
  */
 
 #include <sys/types.h>
+#include <sys/stdint.h>
+#include <sys/sysctl.h>
 #include <sys/socket.h>
 #include <netinet/in.h>
+#include <machine/cpufunc.h>
 
 #include <stdio.h>
 #include <stdlib.h>
 #include <pthread.h>
+#include <unistd.h>
 
 #include "mevent.h"
 
@@ -48,8 +52,62 @@
 static pthread_mutex_t accept_mutex = PTHREAD_MUTEX_INITIALIZER;
 static pthread_cond_t accept_condvar = PTHREAD_COND_INITIALIZER;
 
+static struct mevent *tevp;
+
+char *vmname = "test vm";
+
+
 #define MEVENT_ECHO
 
+/* Number of timer events to capture */
+#define TEVSZ	4096
+uint64_t tevbuf[TEVSZ];
+
+static void
+timer_print(void)
+{
+	uint64_t min, max, diff, sum, tsc_freq;
+	size_t len;
+	int j;
+
+	min = UINT64_MAX;
+	max = 0;
+	sum = 0;
+
+	len = sizeof(tsc_freq);
+	sysctlbyname("machdep.tsc_freq", &tsc_freq, &len, NULL, 0);
+
+	for (j = 1; j < TEVSZ; j++) {
+		/* Convert a tsc diff into microseconds */
+		diff = (tevbuf[j] - tevbuf[j-1]) * 1000000 / tsc_freq;
+		sum += diff;
+		if (min > diff)
+			min = diff;
+		if (max < diff)
+			max = diff;
+	}
+
+	printf("timers done: usecs, min %ld, max %ld, mean %ld\n", min, max,
+	    sum/(TEVSZ - 1));
+}
+
+static void
+timer_callback(int fd, enum ev_type type, void *param)
+{
+	static int i;
+
+	if (i >= TEVSZ)
+		abort();
+
+	tevbuf[i++] = rdtsc();
+
+	if (i == TEVSZ) {
+		mevent_delete(tevp);
+		timer_print();
+	}
+}
+
+
 #ifdef MEVENT_ECHO
 struct esync {
 	pthread_mutex_t	e_mt;
@@ -101,6 +159,8 @@ echoer(void *param)
 	pthread_mutex_unlock(&sync.e_mt);
 	pthread_mutex_destroy(&sync.e_mt);
 	pthread_cond_destroy(&sync.e_cond);
+
+	return (NULL);
 }
 
 #else
@@ -115,6 +175,8 @@ echoer(void *param)
 	while ((len = read(fd, buf, sizeof(buf))) > 0) {
 		write(1, buf, len);
 	}
+
+	return (NULL);
 }
 #endif /* MEVENT_ECHO */
 
@@ -133,6 +195,7 @@ acceptor(void *param)
 	pthread_t tid;
 	int news;
 	int s;
+	static int first;
 
         if ((s = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
                 perror("socket");
@@ -163,11 +226,24 @@ acceptor(void *param)
 		if (news < 0) {
 			perror("accept error");
 		} else {
+			static int first = 1;
+
+			if (first) {
+				/*
+				 * Start a timer
+				 */
+				first = 0;
+				tevp = mevent_add(1, EVF_TIMER, timer_callback,
+						  NULL);
+			}
+
 			printf("incoming connection, spawning thread\n");
 			pthread_create(&tid, NULL, echoer,
 				       (void *)(uintptr_t)news);
 		}
 	}
+
+	return (NULL);
 }
 
 main()



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201309190448.r8J4mQP8003412>