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)
This commit is contained in:
Peter Grehan 2013-09-19 04:48:26 +00:00
parent 4458253e97
commit 151dba4a87
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/head/; revision=255690
3 changed files with 104 additions and 8 deletions

View File

@ -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 numev)
}
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;

View File

@ -31,7 +31,8 @@
enum ev_type {
EVF_READ,
EVF_WRITE
EVF_WRITE,
EVF_TIMER
};
struct mevent;

View File

@ -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()