win32 timer filter mostly done, improved windows_kevent_wait()

git-svn-id: svn://svn.code.sf.net/p/libkqueue/code/trunk@404 fb4e3144-bc1c-4b72-a658-5bcd248dd7f7
This commit is contained in:
mheily 2011-01-21 03:30:35 +00:00
parent 29a754d3f8
commit e814dc5c6d
8 changed files with 113 additions and 91 deletions

29
libkqueue.sln Normal file
View File

@ -0,0 +1,29 @@

Microsoft Visual Studio Solution File, Format Version 11.00
# Visual C++ Express 2010
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libkqueue", "libkqueue.vcxproj", "{A29A2A03-DD72-6A48-80FB-43EE0B1A16E7}"
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "kqtest", "test\kqtest.vcxproj", "{7578F752-17DD-C6A5-C895-A00098131EEA}"
ProjectSection(ProjectDependencies) = postProject
{A29A2A03-DD72-6A48-80FB-43EE0B1A16E7} = {A29A2A03-DD72-6A48-80FB-43EE0B1A16E7}
EndProjectSection
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Win32 = Debug|Win32
Release|Win32 = Release|Win32
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{A29A2A03-DD72-6A48-80FB-43EE0B1A16E7}.Debug|Win32.ActiveCfg = Debug|Win32
{A29A2A03-DD72-6A48-80FB-43EE0B1A16E7}.Debug|Win32.Build.0 = Debug|Win32
{A29A2A03-DD72-6A48-80FB-43EE0B1A16E7}.Release|Win32.ActiveCfg = Release|Win32
{A29A2A03-DD72-6A48-80FB-43EE0B1A16E7}.Release|Win32.Build.0 = Release|Win32
{7578F752-17DD-C6A5-C895-A00098131EEA}.Debug|Win32.ActiveCfg = Debug|Win32
{7578F752-17DD-C6A5-C895-A00098131EEA}.Debug|Win32.Build.0 = Debug|Win32
{7578F752-17DD-C6A5-C895-A00098131EEA}.Release|Win32.ActiveCfg = Release|Win32
{7578F752-17DD-C6A5-C895-A00098131EEA}.Release|Win32.Build.0 = Release|Win32
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
EndGlobal

View File

@ -73,6 +73,7 @@
<ClCompile Include="src\common\knote.c" />
<ClCompile Include="src\common\kqueue.c" />
<ClCompile Include="src\windows\platform.c" />
<ClCompile Include="src\windows\timer.c" />
</ItemGroup>
<ItemGroup>
<ClInclude Include="include\kqueue.h" />

View File

@ -98,6 +98,7 @@ struct knote {
} vnode;
timer_t timerid;
pthread_t tid; /* Used by posix/timer.c */
void *handle; /* Used by win32 filters */
} data;
TAILQ_ENTRY(knote) event_ent; /* Used by filter->kf_event */
RB_ENTRY(knote) kntree_ent; /* Used by filter->kntree */

View File

@ -22,7 +22,6 @@ const struct filter evfilt_vnode = EVFILT_NOTIMPL;
const struct filter evfilt_signal = EVFILT_NOTIMPL;
const struct filter evfilt_write = EVFILT_NOTIMPL;
const struct filter evfilt_read = EVFILT_NOTIMPL;
const struct filter evfilt_timer = EVFILT_NOTIMPL;
const struct filter evfilt_user = EVFILT_NOTIMPL;
const struct kqueue_vtable kqops = {
@ -96,8 +95,9 @@ windows_kevent_wait(struct kqueue *kq, const struct timespec *timeout)
timeout_ms += timeout->tv_nsec / 1000000;
}
#if DEADWOOD
/* Wait for an event */
dbg_printf("waiting for events (timeout=%u ms)", timeout_ms);
dbg_printf("waiting for %u events (timeout=%u ms)", kq->kq_filt_count, timeout_ms);
rv = WaitForMultipleObjects(kq->kq_filt_count, kq->kq_filt_handle, FALSE, timeout_ms);
switch (rv) {
case WAIT_TIMEOUT:
@ -106,15 +106,24 @@ windows_kevent_wait(struct kqueue *kq, const struct timespec *timeout)
break;
case WAIT_FAILED:
dbg_perror("WaitForMultipleEvents()");
/* TODO: Use GetLastError() for details */
dbg_lasterror("WaitForMultipleEvents()");
retval = -1;
default:
kq->kq_filt_signalled = rv;
retval = 1;
}
#endif
rv = SleepEx(timeout_ms, TRUE);
if (rv == 0) {
dbg_puts("timeout reached");
retval = 0;
} else {
dbg_lasterror("SleepEx()");
retval = -1;
}
return (retval);
}
@ -143,6 +152,8 @@ windows_kevent_copyout(struct kqueue *kq, int nready,
int
windows_filter_init(struct kqueue *kq, struct filter *kf)
{
return (0); //XXX-FIXME TESTING
kf->kf_event_handle = CreateEvent(NULL, FALSE, FALSE, NULL);
if (kf->kf_event_handle == NULL) {
dbg_perror("CreateEvent()");

View File

@ -36,6 +36,19 @@
#include "../../include/sys/event.h"
/*
* Debugging macros
*/
#ifndef NDEBUG
#define dbg_lasterror(str) do { \
if (KQUEUE_DEBUG) \
fprintf(stderr, "KQ: [%d] %s(): %s: (LastError=%d)\n", \
THREAD_ID, __func__, str, GetLastError()); \
} while (0)
#endif
/*
* Atomic integer operations
*/

View File

@ -16,97 +16,49 @@
#include "../common/private.h"
#ifndef NDEBUG
static char *
itimerspec_dump(struct itimerspec *ts)
{
static char __thread buf[1024];
snprintf(buf, sizeof(buf),
"itimer: [ interval=%lu s %lu ns, next expire=%lu s %lu ns ]",
ts->it_interval.tv_sec,
ts->it_interval.tv_nsec,
ts->it_value.tv_sec,
ts->it_value.tv_nsec
);
return (buf);
}
#endif
/* Convert milliseconds into seconds+nanoseconds */
/* Convert milliseconds into negative increments of 100-nanoseconds */
static void
convert_msec_to_itimerspec(struct itimerspec *dst, int src, int oneshot)
convert_msec_to_filetime(LARGE_INTEGER *dst, int src)
{
time_t sec, nsec;
sec = src / 1000;
nsec = (src % 1000) * 1000000;
/* Set the interval */
if (oneshot) {
dst->it_interval.tv_sec = 0;
dst->it_interval.tv_nsec = 0;
} else {
dst->it_interval.tv_sec = sec;
dst->it_interval.tv_nsec = nsec;
}
/* Set the initial expiration */
dst->it_value.tv_sec = sec;
dst->it_value.tv_nsec = nsec;
dbg_printf("%s", itimerspec_dump(dst));
dst->QuadPart = -((int64_t) src * 1000 * 10);
}
static int
ktimer_delete(struct filter *filt, struct knote *kn)
{
int rv = 0;
if (kn->data.pfd == -1)
if (kn->data.handle == NULL)
return (0);
dbg_printf("removing timerfd %d from %d", kn->data.pfd, filt->kf_pfd);
if (epoll_ctl(filt->kf_pfd, EPOLL_CTL_DEL, kn->data.pfd, NULL) < 0) {
dbg_printf("epoll_ctl(2): %s", strerror(errno));
rv = -1;
}
if (close(kn->data.pfd) < 0) {
dbg_printf("close(2): %s", strerror(errno));
rv = -1;
}
if (!CancelWaitableTimer(kn->data.handle)) {
dbg_lasterror("CancelWaitableTimer()");
return (-1);
}
if (!CloseHandle(kn->data.handle)) {
dbg_lasterror("CloseHandle()");
return (-1);
}
kn->data.pfd = -1;
return (rv);
kn->data.handle = NULL;
return (0);
}
int
evfilt_timer_init(struct filter *filt)
{
filt->kf_pfd = epoll_create(1);
if (filt->kf_pfd < 0)
return (-1);
dbg_printf("timer epollfd = %d", filt->kf_pfd);
return (0);
}
void
evfilt_timer_destroy(struct filter *filt)
{
close (filt->kf_pfd);//LAME
}
/* TODO: This entire function is copy+pasted from socket.c
with minor changes for timerfds.
Perhaps it could be refactored into a generic epoll_copyout()
that calls custom per-filter actions.
*/
int
evfilt_timer_copyout(struct filter *filt,
struct kevent *dst,
int nevents)
{
#if FIXME
struct epoll_event epevt[MAX_KEVENT];
struct epoll_event *ev;
struct knote *kn;
@ -157,41 +109,35 @@ evfilt_timer_copyout(struct filter *filt,
}
return (nevents);
#endif
return (0);
}
int
evfilt_timer_knote_create(struct filter *filt, struct knote *kn)
{
struct epoll_event ev;
struct itimerspec ts;
int tfd;
HANDLE th;
LARGE_INTEGER liDueTime;
kn->kev.flags |= EV_CLEAR;
tfd = timerfd_create(CLOCK_MONOTONIC, 0);
if (tfd < 0) {
dbg_printf("timerfd_create(2): %s", strerror(errno));
th = CreateWaitableTimer(NULL, FALSE, NULL);
if (th == NULL) {
dbg_lasterror("CreateWaitableTimer()");
return (-1);
}
dbg_printf("created timerfd %d", tfd);
dbg_printf("created timer handle %p", th);
convert_msec_to_itimerspec(&ts, kn->kev.data, kn->kev.flags & EV_ONESHOT);
if (timerfd_settime(tfd, 0, &ts, NULL) < 0) {
dbg_printf("timerfd_settime(2): %s", strerror(errno));
close(tfd);
convert_msec_to_filetime(&liDueTime, kn->kev.data);
// XXX-FIXME add completion routine to this call
if (!SetWaitableTimer(th, &liDueTime, (kn->kev.flags & EV_ONESHOT), NULL, NULL, FALSE)) {
dbg_lasterror("SetWaitableTimer()");
CloseHandle(th);
return (-1);
}
memset(&ev, 0, sizeof(ev));
ev.events = EPOLLIN;
ev.data.ptr = kn;
if (epoll_ctl(filt->kf_pfd, EPOLL_CTL_ADD, tfd, &ev) < 0) {
dbg_printf("epoll_ctl(2): %d", errno);
close(tfd);
return (-1);
}
kn->data.pfd = tfd;
kn->data.handle = th;
return (0);
}

20
test/kqtest.sln Normal file
View File

@ -0,0 +1,20 @@

Microsoft Visual Studio Solution File, Format Version 11.00
# Visual C++ Express 2010
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "kqtest", "kqtest.vcxproj", "{7578F752-17DD-C6A5-C895-A00098131EEA}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Win32 = Debug|Win32
Release|Win32 = Release|Win32
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{7578F752-17DD-C6A5-C895-A00098131EEA}.Debug|Win32.ActiveCfg = Debug|Win32
{7578F752-17DD-C6A5-C895-A00098131EEA}.Debug|Win32.Build.0 = Debug|Win32
{7578F752-17DD-C6A5-C895-A00098131EEA}.Release|Win32.ActiveCfg = Release|Win32
{7578F752-17DD-C6A5-C895-A00098131EEA}.Release|Win32.Build.0 = Release|Win32
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
EndGlobal

View File

@ -144,15 +144,16 @@ int
main(int argc, char **argv)
{
struct unit_test tests[] = {
{ "socket", 1, test_evfilt_read },
#ifndef _WIN32
{ "socket", 1, test_evfilt_read },
{ "signal", 1, test_evfilt_signal },
#endif
#if FIXME
{ "proc", 1, test_evfilt_proc },
#endif
{ "vnode", 1, test_evfilt_vnode },
{ "timer", 1, test_evfilt_timer },
{ "timer", 1, test_evfilt_timer },
{ "vnode", 1, test_evfilt_vnode },
#if HAVE_EVFILT_USER
{ "user", 1, test_evfilt_user },
#endif