From e814dc5c6d342fdbab990b460cb3982e202a4da7 Mon Sep 17 00:00:00 2001 From: mheily Date: Fri, 21 Jan 2011 03:30:35 +0000 Subject: [PATCH] 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 --- libkqueue.sln | 29 +++++++++++ libkqueue.vcxproj | 1 + src/common/private.h | 1 + src/windows/platform.c | 19 +++++-- src/windows/platform.h | 13 +++++ src/windows/timer.c | 114 +++++++++++------------------------------ test/kqtest.sln | 20 ++++++++ test/main.c | 7 +-- 8 files changed, 113 insertions(+), 91 deletions(-) create mode 100644 libkqueue.sln create mode 100644 test/kqtest.sln 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