mirror of
https://github.com/darlinghq/darling-libkqueue.git
synced 2024-11-23 03:39:51 +00:00
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:
parent
29a754d3f8
commit
e814dc5c6d
29
libkqueue.sln
Normal file
29
libkqueue.sln
Normal 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
|
@ -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" />
|
||||
|
@ -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 */
|
||||
|
@ -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,14 +106,23 @@ 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()");
|
||||
|
@ -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
|
||||
*/
|
||||
|
@ -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 (!CancelWaitableTimer(kn->data.handle)) {
|
||||
dbg_lasterror("CancelWaitableTimer()");
|
||||
return (-1);
|
||||
}
|
||||
if (close(kn->data.pfd) < 0) {
|
||||
dbg_printf("close(2): %s", strerror(errno));
|
||||
rv = -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
20
test/kqtest.sln
Normal 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
|
@ -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 },
|
||||
{ "vnode", 1, test_evfilt_vnode },
|
||||
#if HAVE_EVFILT_USER
|
||||
{ "user", 1, test_evfilt_user },
|
||||
#endif
|
||||
|
Loading…
Reference in New Issue
Block a user