diff --git a/libkqueue.vcxproj b/libkqueue.vcxproj index 752b198..092e51d 100644 --- a/libkqueue.vcxproj +++ b/libkqueue.vcxproj @@ -50,6 +50,7 @@ MachineX86 true Windows + msvcrtd.lib;Libcmtd.lib;%(AdditionalDependencies) @@ -72,12 +73,14 @@ + + diff --git a/src/common/alloc.h b/src/common/alloc.h index 56c3900..f82628c 100644 --- a/src/common/alloc.h +++ b/src/common/alloc.h @@ -34,7 +34,10 @@ */ #include -#include + +#ifndef _WIN32 +# include +#endif static __thread struct { void **ac_cache; /* An array of reusable memory objects */ diff --git a/src/common/debug.h b/src/common/debug.h index 00db529..983a907 100644 --- a/src/common/debug.h +++ b/src/common/debug.h @@ -19,7 +19,7 @@ #include -extern int DEBUG; +extern int DEBUG_ACTIVE; extern char *DEBUG_IDENT; #if defined(__linux__) @@ -27,7 +27,7 @@ extern char *DEBUG_IDENT; #elif defined(__sun) # define THREAD_ID (pthread_self()) #elif defined(_WIN32) -# define THREAD_ID (GetCurrentThreadId()) +# define THREAD_ID (int)(GetCurrentThreadId()) #else # error Unsupported platform #endif @@ -35,19 +35,19 @@ extern char *DEBUG_IDENT; #ifndef NDEBUG #define dbg_puts(str) do { \ - if (DEBUG) \ + if (DEBUG_ACTIVE) \ fprintf(stderr, "%s [%d]: %s(): %s\n", \ DEBUG_IDENT, THREAD_ID, __func__, str); \ } while (0) #define dbg_printf(fmt,...) do { \ - if (DEBUG) \ + if (DEBUG_ACTIVE) \ fprintf(stderr, "%s [%d]: %s(): "fmt"\n", \ DEBUG_IDENT, THREAD_ID, __func__, __VA_ARGS__); \ } while (0) #define dbg_perror(str) do { \ - if (DEBUG) \ + if (DEBUG_ACTIVE) \ fprintf(stderr, "%s [%d]: %s(): %s: %s (errno=%d)\n", \ DEBUG_IDENT, THREAD_ID, __func__, str, \ strerror(errno), errno); \ @@ -57,9 +57,9 @@ extern char *DEBUG_IDENT; # if defined(_WIN32) # define dbg_lasterror(str) do { \ - if (DEBUG) \ + if (DEBUG_ACTIVE) \ fprintf(stderr, "%s: [%d] %s(): %s: (LastError=%d)\n", \ - THREAD_ID, __func__, str, GetLastError()); \ + DEBUG_IDENT, THREAD_ID, __func__, str, (int)GetLastError()); \ } while (0) # else # define dbg_lasterror(str) ; diff --git a/src/common/kevent.c b/src/common/kevent.c index b207697..9e063d2 100644 --- a/src/common/kevent.c +++ b/src/common/kevent.c @@ -250,7 +250,7 @@ kevent(int kqfd, const struct kevent *changelist, int nchanges, return (-1); } - if (DEBUG) { + if (DEBUG_ACTIVE) { myid = atomic_inc(&_kevent_counter); dbg_printf("--- kevent %u --- (nchanges = %d, nevents = %d)", myid, nchanges, nevents); } else { @@ -291,7 +291,7 @@ kevent(int kqfd, const struct kevent *changelist, int nchanges, } } - if (DEBUG) { + if (DEBUG_ACTIVE) { int n; dbg_printf("(%u) returning %d events", myid, rv); diff --git a/src/common/knote.c b/src/common/knote.c index e8f8746..a43d2d4 100644 --- a/src/common/knote.c +++ b/src/common/knote.c @@ -19,6 +19,7 @@ #include #include "private.h" + #include "alloc.h" static void knote_free(struct filter *, struct knote *); @@ -45,11 +46,15 @@ knote_new(void) struct knote* res = malloc(sizeof(struct knote)); if(!res) return NULL; +#ifdef _WIN32 + pthread_mutex_init(&res->mtx, NULL); +#else if(pthread_mutex_init(&res->mtx, NULL)){ dbg_perror("pthread_mutex_init"); free(res); return NULL; } +#endif return res; } diff --git a/src/common/kqueue.c b/src/common/kqueue.c index be6b91f..9c1c029 100644 --- a/src/common/kqueue.c +++ b/src/common/kqueue.c @@ -24,12 +24,20 @@ #include "private.h" -int DEBUG = 0; +int DEBUG_ACTIVE = 0; char *DEBUG_IDENT = "KQ"; static unsigned int get_fd_limit(void) { +#ifdef _WIN32 + /* actually windows should be able to hold + way more, as they use HANDLEs for everything. + Still this number should still be sufficient for + the provided number of kqueue fds. + */ + return 65536; +#else struct rlimit rlim; if (getrlimit(RLIMIT_NOFILE, &rlim) < 0) { @@ -38,6 +46,7 @@ get_fd_limit(void) } else { return (rlim.rlim_max); } +#endif } static struct map *kqmap; @@ -46,14 +55,22 @@ int CONSTRUCTOR _libkqueue_init(void) { #ifdef NDEBUG - DEBUG = 0; + DEBUG_ACTIVE = 0; #elif _WIN32 /* Experimental port, always debug */ - DEBUG = 1; + DEBUG_ACTIVE = 1; +# ifndef __GNUC__ + /* Enable heap surveillance */ + { + int tmpFlag = _CrtSetDbgFlag( _CRTDBG_REPORT_FLAG ); + tmpFlag |= _CRTDBG_CHECK_ALWAYS_DF; + _CrtSetDbgFlag(tmpFlag); + } +# endif #else char *s = getenv("KQUEUE_DEBUG"); if (s != NULL && strlen(s) > 0) - DEBUG = 1; + DEBUG_ACTIVE = 1; #endif kqmap = map_new(get_fd_limit()); // INT_MAX diff --git a/src/common/map.c b/src/common/map.c index 98e9360..50ba0cf 100644 --- a/src/common/map.c +++ b/src/common/map.c @@ -26,9 +26,18 @@ map_new(size_t len) { struct map *dst; - dst = calloc(1, sizeof(*dst)); + dst = calloc(1, sizeof(struct map)); if (dst == NULL) return (NULL); +#ifdef _WIN32 + dst->data = calloc(len, sizeof(void*)); + if(dst->data == NULL) { + dbg_perror("calloc()"); + free(dst); + return NULL; + } + dst->len = len; +#else dst->data = mmap(NULL, len * sizeof(void *), PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_NORESERVE | MAP_ANON, -1, 0); if (dst->data == MAP_FAILED) { @@ -37,6 +46,7 @@ map_new(size_t len) return (NULL); } dst->len = len; +#endif return (dst); } @@ -44,10 +54,10 @@ map_new(size_t len) int map_insert(struct map *m, int idx, void *ptr) { - if (slowpath(idx < 0 || idx > m->len)) + if (slowpath(idx < 0 || idx > (int)m->len)) return (-1); - if (atomic_cas(&(m->data[idx]), 0, ptr) == NULL) { + if (atomic_ptr_cas(&(m->data[idx]), 0, ptr) == NULL) { dbg_printf("inserted %p in location %d", ptr, idx); return (0); } else { @@ -61,10 +71,10 @@ map_insert(struct map *m, int idx, void *ptr) int map_remove(struct map *m, int idx, void *ptr) { - if (slowpath(idx < 0 || idx > m->len)) + if (slowpath(idx < 0 || idx > (int)m->len)) return (-1); - if (atomic_cas(&(m->data[idx]), ptr, 0) == NULL) { + if (atomic_ptr_cas(&(m->data[idx]), ptr, 0) == NULL) { dbg_printf("removed %p from location %d", ptr, idx); return (0); } else { @@ -78,10 +88,10 @@ map_replace(struct map *m, int idx, void *oldp, void *newp) { void *tmp; - if (slowpath(idx < 0 || idx > m->len)) + if (slowpath(idx < 0 || idx > (int)m->len)) return (-1); - tmp = atomic_cas(&(m->data[idx]), oldp, newp); + tmp = atomic_ptr_cas(&(m->data[idx]), oldp, newp); if (tmp == oldp) { dbg_printf("replaced value %p in location %d with value %p", oldp, idx, newp); @@ -96,7 +106,7 @@ map_replace(struct map *m, int idx, void *oldp, void *newp) void * map_lookup(struct map *m, int idx) { - if (slowpath(idx < 0 || idx > m->len)) + if (slowpath(idx < 0 || idx > (int)m->len)) return (NULL); return m->data[idx]; @@ -108,13 +118,13 @@ map_delete(struct map *m, int idx) void *oval; void *nval; - if (slowpath(idx < 0 || idx > m->len)) + if (slowpath(idx < 0 || idx > (int)m->len)) return ((void *)-1); /* Hopefully we aren't racing with another thread, but you never know.. */ do { oval = m->data[idx]; - nval = atomic_cas(&(m->data[idx]), oval, NULL); + nval = atomic_ptr_cas(&(m->data[idx]), oval, NULL); } while (nval != oval); m->data[idx] = NULL; diff --git a/src/common/private.h b/src/common/private.h index 9de0f6f..c35cea6 100644 --- a/src/common/private.h +++ b/src/common/private.h @@ -35,6 +35,9 @@ struct evfilt_data; #if defined(_WIN32) # include "../windows/platform.h" # include "../common/queue.h" +# if !defined(NDEBUG) && !defined(__GNUC__) +# include +# endif #elif defined(__linux__) # include "../posix/platform.h" # include "../linux/platform.h" @@ -141,7 +144,15 @@ struct kqueue { struct kqueue_vtable { int (*kqueue_init)(struct kqueue *); void (*kqueue_free)(struct kqueue *); + // @param timespec can be given as timeout + // @param int the number of events to wait for + // @param kqueue the queue to wait on int (*kevent_wait)(struct kqueue *, int, const struct timespec *); + // @param kqueue the queue to look at + // @param int The number of events that should be ready + // @param kevent the structure to copy the events into + // @param int The number of events to copy + // @return the actual number of events copied int (*kevent_copyout)(struct kqueue *, int, struct kevent *, int); int (*filter_init)(struct kqueue *, struct filter *); void (*filter_free)(struct kqueue *, struct filter *); diff --git a/src/windows/platform.c b/src/windows/platform.c index 3a95c33..a775e37 100644 --- a/src/windows/platform.c +++ b/src/windows/platform.c @@ -51,7 +51,9 @@ BOOL WINAPI DllMain( break; case DLL_PROCESS_DETACH: +#if XXX WSACleanup(); +#endif break; } @@ -67,6 +69,11 @@ windows_kqueue_init(struct kqueue *kq) return (-1); } + if(filter_register_all(kq) < 0) { + CloseHandle(kq->kq_handle); + return (-1); + } + return (0); } @@ -78,7 +85,7 @@ windows_kqueue_free(struct kqueue *kq) } int -windows_kevent_wait(struct kqueue *kq, const struct timespec *timeout) +windows_kevent_wait(struct kqueue *kq, int no, const struct timespec *timeout) { int retval; DWORD rv, timeout_ms; @@ -96,7 +103,7 @@ windows_kevent_wait(struct kqueue *kq, const struct timespec *timeout) } /* Wait for an event */ - dbg_printf("waiting for %u events (timeout=%u ms)", kq->kq_filt_count, timeout_ms); + dbg_printf("waiting for %u events (timeout=%u ms)", kq->kq_filt_count, (unsigned int)timeout_ms); rv = WaitForMultipleObjectsEx(kq->kq_filt_count, kq->kq_filt_handle, FALSE, timeout_ms, TRUE); switch (rv) { case WAIT_TIMEOUT: @@ -121,6 +128,7 @@ windows_kevent_copyout(struct kqueue *kq, int nready, struct kevent *eventlist, int nevents) { struct filter *filt; + struct knote* kn; int rv; /* KLUDGE: We are abusing the WAIT_FAILED constant to mean @@ -129,8 +137,13 @@ windows_kevent_copyout(struct kqueue *kq, int nready, if (kq->kq_filt_signalled == WAIT_FAILED) return (0); filt = kq->kq_filt_ref[kq->kq_filt_signalled]; + kn = knote_lookup(filt, eventlist->ident); + if(kn == NULL) { + dbg_puts("knote_lookup failed"); + return (-1); + } kq->kq_filt_signalled = WAIT_FAILED; - rv = filt->kf_copyout(filt, eventlist, nevents); + rv = filt->kf_copyout(eventlist, kn, filt); if (rv < 0) { dbg_puts("kevent_copyout failed"); return (-1); diff --git a/src/windows/platform.h b/src/windows/platform.h index 7af7739..18ee425 100644 --- a/src/windows/platform.h +++ b/src/windows/platform.h @@ -27,12 +27,12 @@ #include #include #include - -#pragma comment(lib, "Ws2_32.lib") -/* The #define doesn't seem to work, but the #pragma does.. */ #define _CRT_SECURE_NO_WARNINGS 1 -#pragma warning( disable : 4996 ) +/* The #define doesn't seem to work, but the #pragma does.. */ +#ifdef _MSC_VER +# pragma warning( disable : 4996 ) +#endif #include "../../include/sys/event.h" @@ -40,8 +40,17 @@ /* * Atomic integer operations */ -#define atomic_inc InterlockedIncrement -#define atomic_dec InterlockedDecrement +#ifdef __GNUC__ +# define atomic_inc(p) __sync_add_and_fetch((p), 1) +# define atomic_dec(p) __sync_sub_and_fetch((p), 1) +# define atomic_cas(p, oval, nval) __sync_val_compare_and_swap(p, oval, nval) +# define atomic_ptr_cas(p, oval, nval) __sync_val_compare_and_swap(p, oval, nval) +#else +# define atomic_inc InterlockedIncrement +# define atomic_dec InterlockedDecrement +# define atomic_cas(p, oval, nval) InterlockedCompareExchange(p, nval, oval) +# define atomic_ptr_cas(p, oval, nval) InterlockedCompareExchangePointer(p, nval, oval) +#endif /* * Additional members of struct kqueue @@ -62,12 +71,18 @@ #define FILTER_PLATFORM_SPECIFIC \ HANDLE kf_event_handle +/* + * Some datatype forward declarations + */ +struct filter; +struct kqueue; + /* * Hooks and prototypes */ int windows_kqueue_init(struct kqueue *); void windows_kqueue_free(struct kqueue *); -int windows_kevent_wait(struct kqueue *, const struct timespec *); +int windows_kevent_wait(struct kqueue *, int, const struct timespec *); int windows_kevent_copyout(struct kqueue *, int, struct kevent *, int); int windows_filter_init(struct kqueue *, struct filter *); void windows_filter_free(struct kqueue *, struct filter *); @@ -78,17 +93,29 @@ void windows_filter_free(struct kqueue *, struct filter *); */ #define CONSTRUCTOR +/* + * GCC-compatible branch prediction macros + */ +#ifdef __GNUC__ +# define fastpath(x) __builtin_expect((x), 1) +# define slowpath(x) __builtin_expect((x), 0) +#else +# define fastpath(x) (x) +# define slowpath(x) (x) +#endif + /* Function visibility macros */ #define VISIBLE __declspec(dllexport) #define HIDDEN -#ifndef __func__ +#if !defined(__func__) && !defined(__GNUC__) #define __func__ __FUNCDNAME__ #endif #define snprintf _snprintf #define ssize_t SSIZE_T #define sleep(x) Sleep((x) * 1000) +#define inline __inline /* For POSIX compatibility when compiling, not for actual use */ typedef int socklen_t; @@ -98,7 +125,9 @@ typedef int pthread_t; typedef int sigset_t; typedef int pid_t; -#define __thread __declspec(thread) +#ifndef __GNUC__ +# define __thread __declspec(thread) +#endif /* Emulation of pthreads mutex functionality */ #define PTHREAD_PROCESS_SHARED 1 @@ -116,6 +145,7 @@ typedef CRITICAL_SECTION pthread_rwlock_t; #define pthread_spin_unlock _cs_unlock #define pthread_spin_init(x,y) _cs_init((x)) #define pthread_mutex_init(x,y) _cs_init((x)) +#define pthread_mutex_destroy(x) #define pthread_rwlock_rdlock _cs_lock #define pthread_rwlock_wrlock _cs_lock #define pthread_rwlock_unlock _cs_unlock diff --git a/src/windows/timer.c b/src/windows/timer.c index 39a5df9..d06266d 100644 --- a/src/windows/timer.c +++ b/src/windows/timer.c @@ -54,62 +54,16 @@ evfilt_timer_destroy(struct filter *filt) } int -evfilt_timer_copyout(struct filter *filt, - struct kevent *dst, - int nevents) +evfilt_timer_copyout(struct kevent* dst, struct knote* src, void* ptr) { -#if FIXME - struct epoll_event epevt[MAX_KEVENT]; - struct epoll_event *ev; - struct knote *kn; - uint64_t expired; - int i, nret; - ssize_t n; + memcpy(dst, &src->kev, sizeof(struct kevent*)); + // TODO: Timer error handling + + /* We have no way to determine the number of times + the timer triggered, thus we assume it was only once + */ + dst->data = 1; - for (;;) { - nret = epoll_wait(filt->kf_pfd, &epevt[0], nevents, 0); - if (nret < 0) { - if (errno == EINTR) - continue; - dbg_perror("epoll_wait"); - return (-1); - } else { - break; - } - } - - for (i = 0, nevents = 0; i < nret; i++) { - ev = &epevt[i]; - /* TODO: put in generic debug.c: epoll_event_dump(ev); */ - kn = ev->data.ptr; - memcpy(dst, &kn->kev, sizeof(*dst)); - if (ev->events & EPOLLERR) - dst->fflags = 1; /* FIXME: Return the actual timer error */ - - /* On return, data contains the number of times the - timer has been trigered. - */ - n = read(kn->data.pfd, &expired, sizeof(expired)); - if (n < 0 || n < sizeof(expired)) { - dbg_puts("invalid read from timerfd"); - expired = 1; /* Fail gracefully */ - } - dst->data = expired; - - if (kn->kev.flags & EV_DISPATCH) { - KNOTE_DISABLE(kn); - ktimer_delete(filt, kn); - } else if (kn->kev.flags & EV_ONESHOT) { - ktimer_delete(filt, kn); - knote_free(filt, kn); - } - - nevents++; - dst++; - } - - return (nevents); -#endif return (0); } diff --git a/test/common.h b/test/common.h index 720cc58..6405269 100644 --- a/test/common.h +++ b/test/common.h @@ -49,9 +49,8 @@ #include #include "config.h" #else -#include "../include/sys/event.h" -#include "../src/windows/platform.h" -#pragma comment(lib, "../Debug/libkqueue.lib") +# include "../include/sys/event.h" +# include "../src/windows/platform.h" #endif diff --git a/test/kqtest.vcxproj b/test/kqtest.vcxproj index 876aac8..30043fe 100644 --- a/test/kqtest.vcxproj +++ b/test/kqtest.vcxproj @@ -50,6 +50,7 @@ MachineX86 true Console + wsock32.lib;%(AdditionalDependencies) @@ -82,6 +83,11 @@ + + + {74c1eceb-1d2b-2740-8a0b-9ec65aa06eab} + + diff --git a/test/main.c b/test/main.c index e8078f0..ac5dc3a 100644 --- a/test/main.c +++ b/test/main.c @@ -14,9 +14,6 @@ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ -#include - - #include "common.h" struct unit_test { diff --git a/test/read.c b/test/read.c index 0ff3cf1..2566a17 100644 --- a/test/read.c +++ b/test/read.c @@ -340,7 +340,7 @@ test_kevent_regular_file(void) /* Set file position to EOF-1 */ kev2->data--; if ((curpos = lseek(fd, kev2->data, SEEK_SET)) != kev2->data) { - printf("seek to %zu failed with rv=%zu\n", kev2->data, curpos); + printf("seek to %u failed with rv=%lu\n", kev2->data, curpos); abort(); } @@ -348,7 +348,7 @@ test_kevent_regular_file(void) (void) kevent_get(kqfd); kev2->data = curpos + 1; if ((curpos = lseek(fd, kev2->data, SEEK_SET)) != kev2->data) { - printf("seek to %zu failed with rv=%zu\n", kev2->data, curpos); + printf("seek to %u failed with rv=%lu\n", kev2->data, curpos); abort(); }