mirror of
https://github.com/darlinghq/darling-libkqueue.git
synced 2024-11-26 21:20:38 +00:00
More work on kqlite
git-svn-id: svn://svn.code.sf.net/p/libkqueue/code/trunk@658 fb4e3144-bc1c-4b72-a658-5bcd248dd7f7
This commit is contained in:
parent
f09868e45b
commit
74c794d2b9
26
kqlite/README
Normal file
26
kqlite/README
Normal file
@ -0,0 +1,26 @@
|
||||
kqlite has the following goals:
|
||||
|
||||
* be lightweight and efficient
|
||||
* provide a strict subset of the functionality of kqueue(2) and kevent(2)
|
||||
* closely resemble the kqueue API, but not guarantee 100% compatibility
|
||||
* support modern POSIX operating systems
|
||||
|
||||
It should be possible to switch between kqlite and the full libkqueue
|
||||
using a few preprocessor macros:
|
||||
|
||||
#if LIBKQUEUE
|
||||
#define kqueue_t int
|
||||
#define kq_init kqueue
|
||||
#define kq_event kevent
|
||||
#define kq_free close
|
||||
#endif
|
||||
|
||||
Here are the differences between kqlite and kqueue:
|
||||
|
||||
* Function names are different:
|
||||
|
||||
kqueue() == kq_init()
|
||||
kevent() == kq_event()
|
||||
close() == kq_free()
|
||||
|
||||
* kqueue() returns an int, while kq_init returns an opaque kqueue_t type.
|
166
kqlite/kqlite.c
166
kqlite/kqlite.c
@ -16,9 +16,12 @@
|
||||
|
||||
#include "./lite.h"
|
||||
|
||||
#include <unistd.h>
|
||||
|
||||
/* Determine what type of kernel event system to use. */
|
||||
#if defined(__FreeBSD__) || defined(__APPLE__) || defined(__OpenBSD__) || defined(__NetBSD__)
|
||||
#define USE_KQUEUE
|
||||
#include <sys/event.h>
|
||||
#elif defined(__linux__)
|
||||
#define USE_EPOLL
|
||||
#include <pthread.h>
|
||||
@ -31,47 +34,88 @@
|
||||
#error Unsupported operating system type
|
||||
#endif
|
||||
|
||||
#if defined(USE_KQUEUE)
|
||||
typedef int kqueue_t;
|
||||
#elif defined(USE_EPOLL)
|
||||
struct kqueue {
|
||||
int epfd; /* epoll */
|
||||
int inofd; /* inotify */
|
||||
int timefd; /* timerfd */
|
||||
int sigfd; /* signalfd */
|
||||
sigset_t sigmask;
|
||||
pthread_mutex_t kq_mtx;
|
||||
};
|
||||
|
||||
/* Linux supports a subset of these filters. */
|
||||
#if defined(USE_EPOLL)
|
||||
#define EVFILT_READ (0)
|
||||
#define EVFILT_WRITE (1)
|
||||
#define EVFILT_VNODE (2)
|
||||
#define EVFILT_SIGNAL (3)
|
||||
#define EVFILT_TIMER (4)
|
||||
#define EVFILT_SYSCOUNT (5)
|
||||
#endif
|
||||
|
||||
/* Initialize the event descriptor */
|
||||
int
|
||||
kq_init(kqueue_t kq)
|
||||
{
|
||||
struct kqueue {
|
||||
#if defined(USE_KQUEUE)
|
||||
kq = kqueue();
|
||||
int kqfd; /* kqueue(2) descriptor */
|
||||
#elif defined(USE_EPOLL)
|
||||
int epfd; /* epoll */
|
||||
int wfd[EVFILT_SYSCOUNT]; /* an event wait descriptor for each EVFILT_* */
|
||||
sigset_t sigmask;
|
||||
pthread_mutex_t kq_mtx;
|
||||
#else
|
||||
#error Undefined event system
|
||||
#endif
|
||||
};
|
||||
|
||||
return (kq);
|
||||
/* Initialize the event descriptor */
|
||||
kqueue_t
|
||||
kq_init(void)
|
||||
{
|
||||
struct kqueue *kq;
|
||||
|
||||
if ((kq = malloc(sizeof(*kq))) == NULL)
|
||||
return (NULL);
|
||||
|
||||
#if defined(USE_KQUEUE)
|
||||
kq->kqfd = kqueue();
|
||||
if (kq->kqfd < 0) {
|
||||
free(kq);
|
||||
return (NULL);
|
||||
}
|
||||
|
||||
#elif defined(USE_EPOLL)
|
||||
if (pthread_mutex_init(&kq->kq_mtx, NULL) != 0)
|
||||
return (-1);
|
||||
goto errout;
|
||||
kq->epfd = epoll_create(10);
|
||||
if (kq->epfd < 0)
|
||||
goto errout;
|
||||
sigemptyset(&kq->sigmask);
|
||||
kq->wfd[EVFILT_SIGNAL] = signalfd(-1, &kq->sigmask, 0);
|
||||
|
||||
return (kq->epfd);
|
||||
// FIXME: check that all members of kq->wfd are valid
|
||||
|
||||
return (kq);
|
||||
|
||||
errout:
|
||||
free(kq);
|
||||
if (kq->epfd >= 0) close(kq->epfd);
|
||||
//FIXME: something like: if (kq->wfd[EVFILT_SIGNAL] >= 0) free(kq->epfd);
|
||||
return (NULL);
|
||||
#endif
|
||||
}
|
||||
|
||||
void
|
||||
kq_free(kqueue_t kq)
|
||||
{
|
||||
#if defined(USE_KQUEUE)
|
||||
close(kq.kqfd);
|
||||
|
||||
#elif defined(USE_EPOLL)
|
||||
close(kq->epfd);
|
||||
#endif
|
||||
free(kq);
|
||||
}
|
||||
|
||||
#if defined(USE_EPOLL)
|
||||
|
||||
/* Add a new item to the list of events to be monitored */
|
||||
int
|
||||
kq_add(kqueue_t kq, const kevent_t *ev)
|
||||
static inline int
|
||||
kq_add(kqueue_t kq, const struct kevent *ev)
|
||||
{
|
||||
int rv = 0;
|
||||
#if defined(USE_KQUEUE)
|
||||
//TODO
|
||||
#elif defined(USE_EPOLL)
|
||||
struct epoll_event epev;
|
||||
kevent_t *evcopy;
|
||||
struct kevent *evcopy;
|
||||
int sigfd;
|
||||
|
||||
/* Save a copy of the kevent so kq_wait() can use it later */
|
||||
@ -81,25 +125,25 @@ kq_add(kqueue_t kq, const kevent_t *ev)
|
||||
memcpy (evcopy, ev, sizeof(*evcopy));
|
||||
|
||||
switch (ev->ident) {
|
||||
case SOURCE_READ:
|
||||
case EVFILT_READ:
|
||||
epev.events = EPOLLIN;
|
||||
epev.data.ptr = evcopy;
|
||||
rv = epoll_ctl(kq->epfd, EPOLL_CTL_ADD, ev->ident, &epev);
|
||||
|
||||
case SOURCE_WRITE:
|
||||
case EVFILT_WRITE:
|
||||
epev.events = EPOLLOUT;
|
||||
epev.data.ptr = evcopy;
|
||||
rv = epoll_ctl(kq->epfd, EPOLL_CTL_ADD, ev->ident, &epev);
|
||||
|
||||
case SOURCE_VNODE:
|
||||
case EVFILT_VNODE:
|
||||
//TODO: create an inotifyfd, create an epollfd, add the inotifyfd to the epollfd, set epollfd.data.ptr = evcopy, add epollfd to kq->epfd.
|
||||
rv = -1;
|
||||
break;
|
||||
|
||||
case SOURCE_SIGNAL:
|
||||
case EVFILT_SIGNAL:
|
||||
pthread_mutex_lock(&kq->kq_mtx);
|
||||
sigaddset(&kq->sigmask, ev->ident);
|
||||
sigfd = signalfd(kq->sigfd, &kq->sigmask, 0);
|
||||
sigfd = signalfd(kq->wfd[EVFILT_SIGNAL], &kq->sigmask, 0);
|
||||
pthread_mutex_unlock(&kq->kq_mtx);
|
||||
if (sigfd < 0) {
|
||||
rv = -1;
|
||||
@ -108,7 +152,7 @@ kq_add(kqueue_t kq, const kevent_t *ev)
|
||||
}
|
||||
break;
|
||||
|
||||
case SOURCE_TIMER:
|
||||
case EVFILT_TIMER:
|
||||
//TODO
|
||||
rv = -1;
|
||||
break;
|
||||
@ -120,35 +164,31 @@ kq_add(kqueue_t kq, const kevent_t *ev)
|
||||
|
||||
// if (rv < 0)
|
||||
// free(evcopy);
|
||||
#endif
|
||||
return (rv);
|
||||
}
|
||||
|
||||
/* Delete an item from the list of events to be monitored */
|
||||
int
|
||||
kq_remove(kqueue_t kq, const kevent_t *ev)
|
||||
static int
|
||||
kq_delete(kqueue_t kq, const struct kevent *ev)
|
||||
{
|
||||
int rv = 0;
|
||||
int sigfd;
|
||||
#if defined(USE_KQUEUE)
|
||||
//TODO
|
||||
#elif defined(USE_EPOLL)
|
||||
struct epoll_event epev;
|
||||
|
||||
switch (ev->ident) {
|
||||
case SOURCE_READ:
|
||||
case SOURCE_WRITE:
|
||||
case EVFILT_READ:
|
||||
case EVFILT_WRITE:
|
||||
rv = epoll_ctl(kq->epfd, EPOLL_CTL_DEL, ev->ident, &epev);
|
||||
break;
|
||||
|
||||
case SOURCE_VNODE:
|
||||
case EVFILT_VNODE:
|
||||
//TODO
|
||||
break;
|
||||
|
||||
case SOURCE_SIGNAL:
|
||||
case EVFILT_SIGNAL:
|
||||
pthread_mutex_lock(&kq->kq_mtx);
|
||||
sigdelset(&kq->sigmask, ev->ident);
|
||||
sigfd = signalfd(kq->sigfd, &kq->sigmask, 0);
|
||||
sigfd = signalfd(kq->wfd[EVFILT_SIGNAL], &kq->sigmask, 0);
|
||||
pthread_mutex_unlock(&kq->kq_mtx);
|
||||
if (sigfd < 0) {
|
||||
rv = -1;
|
||||
@ -157,7 +197,7 @@ kq_remove(kqueue_t kq, const kevent_t *ev)
|
||||
}
|
||||
break;
|
||||
|
||||
case SOURCE_TIMER:
|
||||
case EVFILT_TIMER:
|
||||
//TODO
|
||||
break;
|
||||
|
||||
@ -165,20 +205,37 @@ kq_remove(kqueue_t kq, const kevent_t *ev)
|
||||
rv = 0;
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
return (rv);
|
||||
}
|
||||
|
||||
/* Wait for an event */
|
||||
int
|
||||
kq_wait(kqueue_t kq, kevent_t *ev, const struct timespec *timeout)
|
||||
#endif /* defined(USE_EPOLL) */
|
||||
|
||||
/* Equivalent to kevent() */
|
||||
int kq_event(kqueue_t kq, const struct kevent *changelist, int nchanges,
|
||||
struct kevent *eventlist, int nevents,
|
||||
const struct timespec *timeout)
|
||||
{
|
||||
int rv = 0;
|
||||
|
||||
#if defined(USE_KQUEUE)
|
||||
//TODO
|
||||
return kevent(kq->kqfd, changelist, nchanges, eventlist, nevents, timeout);
|
||||
|
||||
#elif defined(USE_EPOLL)
|
||||
struct epoll_event epev;
|
||||
int eptimeout;
|
||||
int i, eptimeout;
|
||||
|
||||
/* Process each item on the changelist */
|
||||
for (i = 0; i < nchanges; i++) {
|
||||
if (changelist[i].flags & EV_ADD) {
|
||||
rv = kq_add(kq, &changelist[i]);
|
||||
} else if (changelist[i].flags & EV_DELETE) {
|
||||
rv = kq_delete(kq, &changelist[i]);
|
||||
} else {
|
||||
rv = -1;
|
||||
}
|
||||
if (rv < 0)
|
||||
return (-1);
|
||||
}
|
||||
|
||||
/* Convert timeout to the format used by epoll_wait() */
|
||||
if (timeout == NULL)
|
||||
@ -189,15 +246,16 @@ kq_wait(kqueue_t kq, kevent_t *ev, const struct timespec *timeout)
|
||||
rv = epoll_wait(kq->epfd, &epev, 1, eptimeout);
|
||||
//FIXME: handle timeout
|
||||
if (rv > 0) {
|
||||
if (epev.data.fd == kq->sigfd) {
|
||||
//if (epev.data.fd == kq->sigfd) {
|
||||
// FIXME: data.fd isn't actually set :(
|
||||
// Special case: a signal was received
|
||||
// ...
|
||||
} else {
|
||||
// Normal case: data.ptr is a kevent_t (see evcopy from above)
|
||||
//} else {
|
||||
// Normal case: data.ptr is a struct kevent (see evcopy from above)
|
||||
// ...
|
||||
}
|
||||
//}
|
||||
}
|
||||
#endif
|
||||
|
||||
return (rv == 1 ? 0 : -1);
|
||||
#endif
|
||||
}
|
||||
|
170
kqlite/lite.h
170
kqlite/lite.h
@ -1,57 +1,153 @@
|
||||
/*
|
||||
/*-
|
||||
* Copyright (c) 2013 Mark Heily <mark@heily.com>
|
||||
* Copyright (c) 1999,2000,2001 Jonathan Lemon <jlemon@FreeBSD.org>
|
||||
* All rights reserved.
|
||||
*
|
||||
* Permission to use, copy, modify, and distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
* copyright notice and this permission notice appear in all copies.
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*
|
||||
* $FreeBSD SVN Revision 197533$
|
||||
*/
|
||||
|
||||
#ifndef _KQUEUE_LITE_H
|
||||
#define _KQUEUE_LITE_H
|
||||
|
||||
#include <stdint.h>
|
||||
#if defined(__FreeBSD__) || defined(__APPLE__) || defined(__OpenBSD__) || defined(__NetBSD__)
|
||||
#include <sys/event.h>
|
||||
#else
|
||||
|
||||
#include <sys/time.h>
|
||||
#include <sys/types.h>
|
||||
#include <stdint.h>
|
||||
|
||||
/* Equilavent to the list of kevent filters */
|
||||
typedef enum {
|
||||
SOURCE_READ,
|
||||
SOURCE_WRITE,
|
||||
SOURCE_VNODE,
|
||||
SOURCE_SIGNAL,
|
||||
SOURCE_TIMER
|
||||
} kevent_source_t;
|
||||
#define EV_SET(kevp_, a, b, c, d, e, f) do { \
|
||||
struct kevent *kevp = (kevp_); \
|
||||
(kevp)->ident = (a); \
|
||||
(kevp)->filter = (b); \
|
||||
(kevp)->flags = (c); \
|
||||
(kevp)->fflags = (d); \
|
||||
(kevp)->data = (e); \
|
||||
(kevp)->udata = (f); \
|
||||
} while(0)
|
||||
|
||||
/* Equivalent to 'struct kevent' */
|
||||
typedef struct {
|
||||
uintptr_t ident; /* identifier for this event */
|
||||
short filter; /* filter for event */
|
||||
unsigned short flags;
|
||||
unsigned int fflags;
|
||||
intptr_t data;
|
||||
void *udata; /* opaque user data identifier */
|
||||
} kevent_t;
|
||||
struct kevent {
|
||||
uintptr_t ident; /* identifier for this event */
|
||||
short filter; /* filter for event */
|
||||
unsigned short flags;
|
||||
unsigned int fflags;
|
||||
intptr_t data;
|
||||
void *udata; /* opaque user data identifier */
|
||||
};
|
||||
|
||||
/* actions */
|
||||
#define EV_ADD 0x0001 /* add event to kq (implies enable) */
|
||||
#define EV_DELETE 0x0002 /* delete event from kq */
|
||||
#define EV_ENABLE 0x0004 /* enable event */
|
||||
#define EV_DISABLE 0x0008 /* disable event (not reported) */
|
||||
|
||||
/* flags */
|
||||
#define EV_ONESHOT 0x0010 /* only report one occurrence */
|
||||
#define EV_CLEAR 0x0020 /* clear event state after reporting */
|
||||
#define EV_RECEIPT 0x0040 /* force EV_ERROR on success, data=0 */
|
||||
#define EV_DISPATCH 0x0080 /* disable event after reporting */
|
||||
|
||||
#define EV_SYSFLAGS 0xF000 /* reserved by system */
|
||||
#define EV_FLAG1 0x2000 /* filter-specific flag */
|
||||
|
||||
/* returned values */
|
||||
#define EV_EOF 0x8000 /* EOF detected */
|
||||
#define EV_ERROR 0x4000 /* error, data contains errno */
|
||||
|
||||
/*
|
||||
* data/hint flags/masks for EVFILT_USER
|
||||
*
|
||||
* On input, the top two bits of fflags specifies how the lower twenty four
|
||||
* bits should be applied to the stored value of fflags.
|
||||
*
|
||||
* On output, the top two bits will always be set to NOTE_FFNOP and the
|
||||
* remaining twenty four bits will contain the stored fflags value.
|
||||
*/
|
||||
#define NOTE_FFNOP 0x00000000 /* ignore input fflags */
|
||||
#define NOTE_FFAND 0x40000000 /* AND fflags */
|
||||
#define NOTE_FFOR 0x80000000 /* OR fflags */
|
||||
#define NOTE_FFCOPY 0xc0000000 /* copy fflags */
|
||||
#define NOTE_FFCTRLMASK 0xc0000000 /* masks for operations */
|
||||
#define NOTE_FFLAGSMASK 0x00ffffff
|
||||
|
||||
#define NOTE_TRIGGER 0x01000000 /* Cause the event to be
|
||||
triggered for output. */
|
||||
|
||||
/*
|
||||
* data/hint flags for EVFILT_{READ|WRITE}
|
||||
*/
|
||||
#define NOTE_LOWAT 0x0001 /* low water mark */
|
||||
#undef NOTE_LOWAT /* Not supported on Linux */
|
||||
|
||||
/*
|
||||
* data/hint flags for EVFILT_VNODE
|
||||
*/
|
||||
#define NOTE_DELETE 0x0001 /* vnode was removed */
|
||||
#define NOTE_WRITE 0x0002 /* data contents changed */
|
||||
#define NOTE_EXTEND 0x0004 /* size increased */
|
||||
#define NOTE_ATTRIB 0x0008 /* attributes changed */
|
||||
#define NOTE_LINK 0x0010 /* link count changed */
|
||||
#define NOTE_RENAME 0x0020 /* vnode was renamed */
|
||||
#define NOTE_REVOKE 0x0040 /* vnode access was revoked */
|
||||
#undef NOTE_REVOKE /* Not supported on Linux */
|
||||
|
||||
/*
|
||||
* data/hint flags for EVFILT_PROC
|
||||
*/
|
||||
#define NOTE_EXIT 0x80000000 /* process exited */
|
||||
#define NOTE_FORK 0x40000000 /* process forked */
|
||||
#define NOTE_EXEC 0x20000000 /* process exec'd */
|
||||
#define NOTE_PCTRLMASK 0xf0000000 /* mask for hint bits */
|
||||
#define NOTE_PDATAMASK 0x000fffff /* mask for pid */
|
||||
|
||||
/* additional flags for EVFILT_PROC */
|
||||
#define NOTE_TRACK 0x00000001 /* follow across forks */
|
||||
#define NOTE_TRACKERR 0x00000002 /* could not track child */
|
||||
#define NOTE_CHILD 0x00000004 /* am a child process */
|
||||
|
||||
/*
|
||||
* data/hint flags for EVFILT_NETDEV
|
||||
*/
|
||||
#define NOTE_LINKUP 0x0001 /* link is up */
|
||||
#define NOTE_LINKDOWN 0x0002 /* link is down */
|
||||
#define NOTE_LINKINV 0x0004 /* link state is invalid */
|
||||
|
||||
#endif /* defined(__FreeBSD__) etc.. */
|
||||
|
||||
/* kqueue_t - the event descriptor */
|
||||
typedef struct kqueue *kqueue_t;
|
||||
|
||||
/* Initialize the event descriptor */
|
||||
int kq_init(kqueue_t kq);
|
||||
kqueue_t kq_init();
|
||||
|
||||
/* Add a new item to the list of events to be monitored */
|
||||
int kq_add(kqueue_t kq, const kevent_t *ev);
|
||||
/* Free the event descriptor */
|
||||
void kq_free(kqueue_t kq);
|
||||
|
||||
/* Delete an item from the list of events to be monitored */
|
||||
int kq_remove(kqueue_t kq, const kevent_t *ev);
|
||||
|
||||
/* Wait for an event */
|
||||
int kq_wait(kqueue_t kq, kevent_t *ev, const struct timespec *timeout);
|
||||
/* Equivalent to kevent() */
|
||||
int kq_event(kqueue_t kq, const struct kevent *changelist, int nchanges,
|
||||
struct kevent *eventlist, int nevents,
|
||||
const struct timespec *timeout);
|
||||
|
||||
#endif /* ! _KQUEUE_LITE_H */
|
||||
|
@ -5,6 +5,11 @@
|
||||
#include <unistd.h>
|
||||
|
||||
int main() {
|
||||
kqueue_t kq;
|
||||
|
||||
kq = kq_init();
|
||||
kq_free(kq);
|
||||
|
||||
puts("ok");
|
||||
exit(0);
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user