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:
parent
4458253e97
commit
151dba4a87
Notes:
svn2git
2020-12-20 02:59:44 +00:00
svn path=/head/; revision=255690
@ -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;
|
||||
|
@ -31,7 +31,8 @@
|
||||
|
||||
enum ev_type {
|
||||
EVF_READ,
|
||||
EVF_WRITE
|
||||
EVF_WRITE,
|
||||
EVF_TIMER
|
||||
};
|
||||
|
||||
struct mevent;
|
||||
|
@ -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()
|
||||
|
Loading…
Reference in New Issue
Block a user