diff --git a/libkqueue.sln b/libkqueue.sln
new file mode 100644
index 0000000..57f8dd0
--- /dev/null
+++ b/libkqueue.sln
@@ -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
diff --git a/libkqueue.vcxproj b/libkqueue.vcxproj
index 9da03dd..752b198 100644
--- a/libkqueue.vcxproj
+++ b/libkqueue.vcxproj
@@ -73,6 +73,7 @@
+
diff --git a/src/common/private.h b/src/common/private.h
index 21255d9..0b8b515 100644
--- a/src/common/private.h
+++ b/src/common/private.h
@@ -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 */
diff --git a/src/windows/platform.c b/src/windows/platform.c
index df7fb2e..888b50a 100644
--- a/src/windows/platform.c
+++ b/src/windows/platform.c
@@ -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()");
diff --git a/src/windows/platform.h b/src/windows/platform.h
index 597044c..b6bb51d 100644
--- a/src/windows/platform.h
+++ b/src/windows/platform.h
@@ -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
*/
diff --git a/src/windows/timer.c b/src/windows/timer.c
index 0563cf5..39a5df9 100644
--- a/src/windows/timer.c
+++ b/src/windows/timer.c
@@ -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);
}
diff --git a/test/kqtest.sln b/test/kqtest.sln
new file mode 100644
index 0000000..ef1f169
--- /dev/null
+++ b/test/kqtest.sln
@@ -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
diff --git a/test/main.c b/test/main.c
index 28e86ad..2794d0f 100644
--- a/test/main.c
+++ b/test/main.c
@@ -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