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()
_______________________________________________
svn-src-head@freebsd.org mailing list
http://lists.freebsd.org/mailman/listinfo/svn-src-head
To unsubscribe, send any mail to "svn-src-head-unsubscr...@freebsd.org"

Reply via email to