* Ported to Solaris 10. The port compiles but does not work yet.

* Experimental work on EVFILT_PROC, disabled by default.

  * kqueue() init hook

  * kevent() split into several hook functions.



git-svn-id: svn://svn.code.sf.net/p/libkqueue/code/trunk@106 fb4e3144-bc1c-4b72-a658-5bcd248dd7f7
This commit is contained in:
mheily 2009-11-24 03:32:59 +00:00
parent c9e5fa9267
commit bab7f0f8d8
24 changed files with 1215 additions and 156 deletions

View File

@ -21,8 +21,8 @@ include config.mk
build:
$(CC) $(CFLAGS) -c $(SOURCES)
ar rcs libkqueue.a *.o
gcc -shared -Wl,-soname,libkqueue.so -o libkqueue.so *.o
$(AR) rcs $(PROGRAM).a *.o
$(LD) $(LDFLAGS) -o $(PROGRAM).so *.o $(LDADD)
install:
$(INSTALL) -d -m 755 $(INCLUDEDIR)/kqueue/sys

View File

@ -19,6 +19,8 @@ pre_configure_hook() {
cflags="$cflags -DKQUEUE_DEBUG"
fi
optional_headers="err.h"
libdepends=" -L$libdir"
if [ $target = "linux" ] ; then
libdepends="$libdepends -lpthread -lrt"
@ -47,9 +49,8 @@ post_configure_hook() {
if [ "$have_sys_eventfd_h" != "yes" ] ; then
evfilt_user="" # TODO: "src/posix/user.c"
fi
evfilt_proc="src/posix/proc.c"
fi
sources="$sources $evfilt_signal $evfilt_proc $evfilt_socket
$evfilt_timer $evfilt_user $evfilt_vnode"
sources="$sources src/$target/hook.c $evfilt_signal $evfilt_proc
$evfilt_socket $evfilt_timer $evfilt_user $evfilt_vnode"
}

85
configure vendored
View File

@ -6,7 +6,7 @@ make_exports="program version target \
prefix libdir includedir mandir \
cflags ldflags ldadd libdepends \
sources mans headers extra_dist subdirs \
install"
cc cpp ld ar install"
required_headers=
optional_headers=
@ -19,12 +19,10 @@ post_configure_hook() {
return
}
. ./config.inc
export_to_make() {
for id in $*
do
uc_id=`echo $id | tr '[:lower:]' '[:upper:]'`;
uc_id=`echo $id | $tr '[:lower:]' '[:upper:]'`;
eval "echo \"$uc_id=\"\$$id\"\" >> config.mk"
done
}
@ -32,12 +30,13 @@ export_to_make() {
export_to_c() {
for id in $*
do
uc_id=`echo $id | tr '[:lower:]' '[:upper:]'`;
uc_id=`echo $id | $tr '[:lower:]' '[:upper:]'`;
eval "echo \"#define $uc_id \\\"\$$id\\\"\" >> config.h"
done
}
finalize() {
uc_id=`echo \"$1\" | $tr '[:lower:]' '[:upper:]'`;
eval "if [ \"\$$1\" = \"\" ] ; then $1=\"$2\" ; fi"
}
@ -51,10 +50,19 @@ process_argv() {
done
}
process_env() {
test -n "$CC" && cc="$CC"
test -n "$CPP" && cpp="$CPP"
test -n "$CPPFLAGS" && cppflags="$CPPFLAGS"
test -n "$CFLAGS" && cflags="$CFLAGS"
test -n "$LD" && ld="$LD"
test -n "$LDFLAGS" && ldflags="$LDFLAGS"
test -n "$AR" && ar="$AR"
}
check_header() {
sym=`echo "have_$1" | sed 's,[./],_,g'`
uc_sym=`echo "$sym" | tr '[:lower:]' '[:upper:]'`;
uc_sym=`echo "$sym" | $tr '[:lower:]' '[:upper:]'`;
path=$1
printf "checking for $path.. "
@ -82,8 +90,8 @@ check_symbol() {
header=$1
symbol=$2
uc_symbol=`echo "HAVE_$symbol" | tr '[:lower:]' '[:upper:]' | sed 's,[./],_,g'`
lc_symbol=`echo "have_$symbol" | tr '[:upper:]' '[:lower:]' | sed 's,[./],_,g'`
uc_symbol=`echo "HAVE_$symbol" | $tr '[:lower:]' '[:upper:]' | sed 's,[./],_,g'`
lc_symbol=`echo "have_$symbol" | $tr '[:upper:]' '[:lower:]' | sed 's,[./],_,g'`
if [ -f "$header" ] ; then
path="$header"
@ -119,6 +127,49 @@ check_install() {
echo "$install"
}
check_target() {
printf "checking operating system type.. "
default_target=`uname -s | $tr '[:upper:]' '[:lower:]'`
if [ "$default_target" = "sunos" ] ; then
default_target="solaris"
fi
finalize target "$default_target"
echo "$target"
}
check_compiler() {
printf "checking for a C compiler.. "
if [ "`uname -s`" = "SunOS" ] ; then
default_cc="/usr/sfw/bin/gcc"
else
default_cc="/usr/bin/cc"
fi
finalize cc "$default_cc"
echo "$cc"
}
check_linker() {
printf "checking for a suitable linker.. "
if [ "`uname -s`" = "SunOS" ] ; then
default_ld="/usr/sfw/bin/gld"
else
default_ld="/usr/bin/ld"
fi
ldflags="-shared -soname $program.so $ldflags"
finalize ld "$default_ld"
echo "$ld"
}
check_archiver() {
printf "checking for a suitable archiver.. "
if [ "`uname -s`" = "SunOS" ] ; then
default_ar="/usr/sfw/bin/gar"
else
default_ar="/usr/bin/ar"
fi
finalize ar "$default_ar"
echo "$ar"
}
err() {
echo "*** ERROR *** $*"
exit 1
@ -155,6 +206,12 @@ subst_vars() {
#
#######################################################################
# Workaround for Solaris "Bad string" issue when LOCALE is undefined
tr="/usr/bin/tr"
test -f /usr/xpg4/bin/tr && tr="/usr/xpg4/bin/tr"
. ./config.inc
# Initialize the output files
#
for output_file in config.mk $program.pc
@ -166,10 +223,16 @@ rm -f config.h
echo "/* AUTOMATICALLY GENERATED -- DO NOT EDIT */" > config.h
process_argv "$*"
process_env
check_target
check_compiler
check_linker
check_archiver
check_install
finalize program "$program"
finalize version "$version"
finalize target `uname -s | tr '[:upper:]' '[:lower:]'`
finalize prefix "/usr/local"
finalize libdir "${prefix}/lib"
finalize includedir "${prefix}/include"
@ -178,10 +241,6 @@ finalize cflags "$cflags"
finalize libdepends "$libdepends"
finalize ldadd ""
finalize ldflags ""
finalize cc "/usr/bin/cc"
echo "checking operating system type.. $target"
check_install
pre_configure_hook

View File

@ -33,7 +33,6 @@
#include <sys/queue.h>
#include <sys/types.h>
#include <stdint.h>
#include <sys/cdefs.h>
struct timespec;
@ -162,12 +161,17 @@ struct kevent {
#define VQ_NOTRESPLOCK 0x0080 /* server lockd down */
__BEGIN_DECLS
#ifdef __cplusplus
extern "C" {
#endif
int kqueue(void);
int kevent(int kq, const struct kevent *changelist, int nchanges,
struct kevent *eventlist, int nevents,
const struct timespec *timeout);
__END_DECLS
#ifdef __cplusplus
}
#endif
#endif /* !_SYS_EVENT_H_ */

View File

@ -49,6 +49,10 @@ filter_register(struct kqueue *kq, short filter, const struct filter *src)
pthread_mutex_init(&dst->kf_mtx, NULL);
KNOTELIST_INIT(&dst->kf_watchlist);
KNOTELIST_INIT(&dst->kf_eventlist);
if (src->kf_id == 0) {
dbg_puts("filter is not implemented");
return (0);
}
if (src->kf_init == NULL) {
dbg_puts("filter has no initializer");
return (-1);
@ -62,15 +66,12 @@ filter_register(struct kqueue *kq, short filter, const struct filter *src)
}
/* Add the filter's event descriptor to the main fdset */
if (dst->kf_pfd <= 0) {
dbg_printf("FIXME - filter %s did not return a fd to poll!",
filter_name(filter));
return (-1);
}
if (dst->kf_pfd > 0) {
FD_SET(dst->kf_pfd, &kq->kq_fds);
if (dst->kf_pfd > kq->kq_nfds)
kq->kq_nfds = dst->kf_pfd;
dbg_printf("fds: added %d (nfds=%d)", dst->kf_pfd, kq->kq_nfds);
}
dbg_printf("%s registered", filter_name(filter));
return (0);
@ -130,7 +131,7 @@ filter_socketpair(struct filter *filt)
{
int sockfd[2];
if (socketpair(AF_LOCAL, SOCK_STREAM, 0, sockfd) < 0)
if (socketpair(AF_UNIX, SOCK_STREAM, 0, sockfd) < 0)
return (-1);
fcntl(sockfd[0], F_SETFL, O_NONBLOCK);

View File

@ -143,9 +143,7 @@ kevent(int kqfd, const struct kevent *changelist, int nchanges,
const struct timespec *timeout)
{
struct kqueue *kq;
struct filter *filt;
fd_set fds;
int i, rv, n, nret;
int rv, n, nret;
errno = 0;
@ -171,52 +169,17 @@ kevent(int kqfd, const struct kevent *changelist, int nchanges,
if (nevents > MAX_KEVENT)
nevents = MAX_KEVENT;
/*
* Wait for one or more filters to have events.
*/
wait_for_events:
fds = kq->kq_fds;
n = pselect(kq->kq_nfds, &fds, NULL , NULL, timeout, NULL);
if (n < 0) {
if (errno == EINTR) {
dbg_puts("signal caught");
return (-1);
}
dbg_perror("pselect(2)");
return (-1);
}
dbg_printf("pselect(2): %d bits set", n);
if (n == 0)
return (0);
/*
* Process each event and place it on the eventlist
*/
nret = 0;
for (i = 0; (i < EVFILT_SYSCOUNT && n > 0 && nevents > 0); i++) {
dbg_printf("eventlist: n = %d nevents = %d", n, nevents);
filt = &kq->kq_filt[i];
dbg_printf("pfd[%d] = %d", i, filt->kf_pfd);
if (FD_ISSET(filt->kf_pfd, &fds)) {
dbg_printf("event(s) for filter #%d", i);
filter_lock(filt);
rv = filt->kf_copyout(filt, eventlist, nevents);
if (rv < 0) {
filter_unlock(filt);
dbg_puts("kevent_copyout failed");
return (-1);
}
nret += rv;
eventlist += rv;
nevents -= rv;
n--;
filter_unlock(filt);
}
}
/* Handle spurious wakeups where no events are generated. */
if (nret == 0)
goto wait_for_events;
for (nret = 0; nret == 0;
nret = kevent_copyout(kq, n, eventlist, nevents))
{
/* Wait for one or more events. */
n = kevent_wait(kq, timeout);
if (n < 0)
return (-1);
if (n == 0)
return (0); /* Timeout */
}
return (nret);
}

View File

@ -37,7 +37,12 @@ static pthread_rwlock_t kqlist_mtx = PTHREAD_RWLOCK_INITIALIZER;
static sigset_t saved_sigmask;
static int kqgc_pfd[2];
#ifdef SOLARIS
static pthread_once_t kqueue_init_ctl = { PTHREAD_ONCE_INIT };
#else
static pthread_once_t kqueue_init_ctl = PTHREAD_ONCE_INIT;
#endif
static pthread_cond_t kqueue_init_cond = PTHREAD_COND_INITIALIZER;
static pthread_mutex_t kqueue_init_mtx = PTHREAD_MUTEX_INITIALIZER;
static int kqueue_init_status = 0;
@ -147,7 +152,7 @@ kqueue_close_wait(void *unused)
dbg_printf("gc: waiting for events on %d kqfds", n - 1);
n = poll(&fds[0], n, -1);
n = poll(fds, n, -1);
if (n == 0)
continue; /* Spurious wakeup */
if (n < 0) {
@ -226,14 +231,29 @@ kqueue_init(void)
{
pthread_t tid;
if (socketpair(AF_LOCAL, SOCK_STREAM, 0, kqgc_pfd) < 0)
if (socketpair(AF_UNIX, SOCK_STREAM, 0, kqgc_pfd) < 0)
goto errout;
pthread_mutex_lock(&kqueue_init_mtx);
pthread_create(&tid, NULL, kqueue_close_wait, NULL);
if (pthread_create(&tid, NULL, kqueue_close_wait, NULL) != 0)
goto err1;
pthread_cond_wait(&kqueue_init_cond, &kqueue_init_mtx);
if (kqueue_init_hook() < 0)
goto err2;
pthread_mutex_unlock(&kqueue_init_mtx);
return;
err2:
pthread_cancel(tid);
err1:
pthread_mutex_unlock(&kqueue_init_mtx);
close(kqgc_pfd[0]);
close(kqgc_pfd[1]);
errout:
kqueue_init_status = -1;
}
@ -249,7 +269,10 @@ kqueue(void)
return (-1);
pthread_mutex_init(&kq->kq_mtx, NULL);
if (socketpair(AF_LOCAL, SOCK_STREAM, 0, kq->kq_sockfd) < 0)
if (kqueue_hook(kq) < 0)
goto errout;
if (socketpair(AF_UNIX, SOCK_STREAM, 0, kq->kq_sockfd) < 0)
goto errout;
(void) pthread_once(&kqueue_init_ctl, kqueue_init);

View File

@ -17,8 +17,15 @@
#ifndef _KQUEUE_PRIVATE_H
#define _KQUEUE_PRIVATE_H
#if defined (__SVR4) && defined (__sun)
#define SOLARIS
#include <port.h>
#endif
#include <errno.h>
#include <pthread.h>
#include <stdio.h>
#include <string.h>
#include <sys/select.h>
#include "sys/event.h"
@ -91,9 +98,12 @@ struct filter {
struct kqueue {
int kq_sockfd[2];
struct filter kq_filt[EVFILT_SYSCOUNT];
fd_set kq_fds;
fd_set kq_fds, kq_rfds;
int kq_nfds;
pthread_mutex_t kq_mtx;
#ifdef SOLARIS
int kq_port;
#endif
LIST_ENTRY(kqueue) entries;
};
@ -114,12 +124,12 @@ int filter_raise(struct filter *);
int kevent_init(struct kqueue *);
const char * kevent_dump(struct kevent *);
int kevent_wait(struct kqueue *kq,
struct kevent *kevent,
int nevents,
const struct timespec *timeout);
int kevent_wait(struct kqueue *, const struct timespec *);
int kevent_copyout(struct kqueue *, int, struct kevent *, int);
void kevent_free(struct kqueue *);
struct kqueue * kqueue_lookup(int kq);
int kqueue_init_hook(void);
int kqueue_hook(struct kqueue *);
#endif /* ! _KQUEUE_PRIVATE_H */

81
src/linux/hook.c Normal file
View File

@ -0,0 +1,81 @@
/*
* Copyright (c) 2009 Mark Heily <mark@heily.com>
*
* 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.
*
* 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.
*/
#include "sys/event.h"
#include "private.h"
int
kqueue_init_hook(void)
{
return (0);
}
int
kqueue_hook(struct kqueue *kq)
{
return (0);
}
int
kevent_wait(struct kqueue *kq, const struct timespec *timeout)
{
int n;
kq->kq_rfds = kq->kq_fds;
n = pselect(kq->kq_nfds, &kq->kq_rfds, NULL , NULL, timeout, NULL);
if (n < 0) {
if (errno == EINTR) {
dbg_puts("signal caught");
return (-1);
}
dbg_perror("pselect(2)");
return (-1);
}
return (n);
}
int
kevent_copyout(struct kqueue *kq, int nready,
struct kevent *eventlist, int nevents)
{
struct filter *filt;
int i, rv, nret;
nret = 0;
for (i = 0; (i < EVFILT_SYSCOUNT && nready > 0 && nevents > 0); i++) {
dbg_printf("eventlist: n = %d nevents = %d", nready, nevents);
filt = &kq->kq_filt[i];
dbg_printf("pfd[%d] = %d", i, filt->kf_pfd);
if (FD_ISSET(filt->kf_pfd, &kq->kq_rfds)) {
dbg_printf("event(s) for filter #%d", i);
filter_lock(filt);
rv = filt->kf_copyout(filt, eventlist, nevents);
if (rv < 0) {
filter_unlock(filt);
dbg_puts("kevent_copyout failed");
return (-1);
}
nret += rv;
eventlist += rv;
nevents -= rv;
nready--;
filter_unlock(filt);
}
}
return (nret);
}

View File

@ -32,6 +32,9 @@
#include "sys/event.h"
#include "private.h"
pthread_cond_t wait_cond = PTHREAD_COND_INITIALIZER;
pthread_mutex_t wait_mtx = PTHREAD_MUTEX_INITIALIZER;
struct evfilt_data {
pthread_t wthr_id;
};
@ -53,10 +56,13 @@ wait_thread(void *arg)
for (;;) {
/* Wait for a child process to exit(2) */
if ((pid = wait(&status)) < 0) {
if ((pid = waitpid(-1, &status, 0)) < 0) {
if (errno == ECHILD) {
dbg_puts("waiting for child");
pause(); /*XXX-FIXME stupid */
dbg_puts("got ECHILD, waiting for wakeup condition");
pthread_mutex_lock(&wait_mtx);
pthread_cond_wait(&wait_cond, &wait_mtx);
pthread_mutex_unlock(&wait_mtx);
dbg_puts("awoken from ECHILD-induced sleep");
continue;
}
if (errno == EINTR)
@ -127,8 +133,11 @@ int
evfilt_proc_copyin(struct filter *filt,
struct knote *dst, const struct kevent *src)
{
if (src->flags & EV_ADD && KNOTE_EMPTY(dst))
if (src->flags & EV_ADD && KNOTE_EMPTY(dst)) {
memcpy(&dst->kev, src, sizeof(*src));
/* TODO: think about locking the mutex first.. */
pthread_cond_signal(&wait_cond);
}
if (src->flags & EV_ADD || src->flags & EV_ENABLE) {
/* Nothing to do.. */

97
src/solaris/hook.c Normal file
View File

@ -0,0 +1,97 @@
/*
* Copyright (c) 2009 Mark Heily <mark@heily.com>
*
* 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.
*
* 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.
*/
#include <errno.h>
#include <string.h>
#include "sys/event.h"
#include "private.h"
#define PORTEV_DUMP(pe) dbg_printf("port_event: events=%d source=%hu", \
(pe)->portev_events, (pe)->portev_source)
int
kqueue_init_hook(void)
{
return (0);
}
int
kqueue_hook(struct kqueue *kq)
{
if ((kq->kq_port = port_create()) < 0) {
dbg_perror("port_create(2)");
return (-1);
}
return (0);
}
int
kevent_wait(struct kqueue *kq, const struct timespec *timeout)
{
port_event_t pe[1];
int rv, nget;
dbg_printf("port_get: %d %lu %lu",
kq->kq_port, timeout->tv_sec, timeout->tv_nsec);
nget = 1;
rv = port_getn(kq->kq_port, pe, 1, &nget, (struct timespec *) timeout);
if (rv < 0) {
if (errno == EINTR) {
dbg_puts("signal caught");
return (-1);
}
dbg_perror("port_getn(2)");
return (-1);
}
if (nget > 0) {
dbg_printf(" -- event(s) pending: nget = %d", nget);
PORTEV_DUMP(&pe[0]);
} else {
dbg_puts(" -- no events --");
}
return (nget);
}
int
kevent_copyout(struct kqueue *kq, int nready,
struct kevent *eventlist, int nevents)
{
return (-1);
#if TODO
struct filter *filt;
int i, rv, nret;
if (FD_ISSET(filt->kf_pfd, &kq->kq_rfds)) {
dbg_printf("event(s) for filter #%d", i);
filter_lock(filt);
rv = filt->kf_copyout(filt, eventlist, nevents);
if (rv < 0) {
filter_unlock(filt);
dbg_puts("kevent_copyout failed");
return (-1);
}
nret += rv;
eventlist += rv;
nevents -= rv;
nready--;
filter_unlock(filt);
}
return (nret);
#endif
}

111
src/solaris/proc.c Normal file
View File

@ -0,0 +1,111 @@
/*
* Copyright (c) 2009 Mark Heily <mark@heily.com>
*
* 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.
*
* 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.
*/
#include "sys/event.h"
#include "private.h"
int
evfilt_proc_init(struct filter *filt)
{
return (-1);
}
void
evfilt_proc_destroy(struct filter *filt)
{
;
}
int
evfilt_proc_copyin(struct filter *filt,
struct knote *dst, const struct kevent *src)
{
return (-1);
#if TODO
if (src->flags & EV_ADD && KNOTE_EMPTY(dst)) {
memcpy(&dst->kev, src, sizeof(*src));
/* TODO: Consider holding the mutex here.. */
pthread_cond_signal(&filt->kf_data->wait_cond);
}
if (src->flags & EV_ADD || src->flags & EV_ENABLE) {
/* Nothing to do.. */
}
return (0);
#endif
}
int
evfilt_proc_copyout(struct filter *filt,
struct kevent *dst,
int maxevents)
{
return (-1);
#if TODO
struct knote *kn, *kn_nxt;
int nevents = 0;
uint64_t cur;
/* Reset the counter */
if (read(filt->kf_pfd, &cur, sizeof(cur)) < sizeof(cur)) {
dbg_printf("read(2): %s", strerror(errno));
return (-1);
}
dbg_printf(" counter=%llu", (unsigned long long) cur);
pthread_mutex_lock(&filt->kf_mtx);
for (kn = LIST_FIRST(&filt->kf_eventlist); kn != NULL; kn = kn_nxt) {
kn_nxt = LIST_NEXT(kn, entries);
kevent_dump(&kn->kev);
memcpy(dst, &kn->kev, sizeof(*dst));
if (kn->kev.flags & EV_DISPATCH) {
KNOTE_DISABLE(kn);
}
if (kn->kev.flags & EV_ONESHOT) {
knote_free(kn);
} else {
kn->kev.data = 0;
LIST_REMOVE(kn, entries);
LIST_INSERT_HEAD(&filt->kf_watchlist, kn, entries);
}
if (++nevents > maxevents)
break;
dst++;
}
pthread_mutex_unlock(&filt->kf_mtx);
if (!LIST_EMPTY(&filt->kf_eventlist)) {
/* XXX-FIXME: If there are leftover events on the waitq,
re-arm the eventfd. list */
abort();
}
return (nevents);
#endif
}
const struct filter evfilt_proc = {
0, //EVFILT_PROC,
evfilt_proc_init,
evfilt_proc_destroy,
evfilt_proc_copyin,
evfilt_proc_copyout,
};

117
src/solaris/signal.c Normal file
View File

@ -0,0 +1,117 @@
/*
* Copyright (c) 2009 Mark Heily <mark@heily.com>
*
* 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.
*
* 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.
*/
#include "sys/event.h"
#include "private.h"
/* Highest signal number supported. POSIX standard signals are < 32 */
#define SIGNAL_MAX 32
int
evfilt_signal_init(struct filter *filt)
{
return (-1);
}
void
evfilt_signal_destroy(struct filter *filt)
{
;
}
int
evfilt_signal_copyin(struct filter *filt,
struct knote *dst, const struct kevent *src)
{
if (src->ident >= SIGNAL_MAX) {
dbg_printf("unsupported signal number %u", (u_int) src->ident);
return (-1);
}
return (-1);
#if TODO
if (src->flags & EV_ADD && KNOTE_EMPTY(dst)) {
memcpy(&dst->kev, src, sizeof(*src));
dst->kev.flags |= EV_CLEAR;
}
if (src->flags & EV_ADD || src->flags & EV_ENABLE)
sigaddset(&filt->kf_sigmask, src->ident);
if (src->flags & EV_DISABLE || src->flags & EV_DELETE)
sigdelset(&filt->kf_sigmask, src->ident);
return (update_sigmask(filt));
#endif
}
int
evfilt_signal_copyout(struct filter *filt,
struct kevent *dst,
int nevents)
{
return (-1);
#if TODO
struct knote *kn;
struct signalfd_siginfo sig[MAX_KEVENT];
int i;
ssize_t n;
n = read(filt->kf_pfd, &sig, nevents * sizeof(sig[0]));
if (n < 0 || n < sizeof(sig[0])) {
dbg_puts("invalid read from signalfd");
return (-1);
}
n /= sizeof(sig[0]);
for (i = 0, nevents = 0; i < n; i++) {
/* This is not an error because of this race condition:
* 1. Signal arrives and is queued
* 2. The kevent is deleted via kevent(..., EV_DELETE)
* 3. The event is dequeued from the signalfd
*/
kn = knote_lookup(filt, sig[i].ssi_signo);
if (kn == NULL)
continue;
dbg_printf("got signal %d", sig[i].ssi_signo);
memcpy(dst, &kn->kev, sizeof(*dst));
/* TODO: dst->data should be the number of times the signal occurred */
dst->data = 1;
if (kn->kev.flags & EV_DISPATCH || kn->kev.flags & EV_ONESHOT) {
sigdelset(&filt->kf_sigmask, dst->ident);
update_sigmask(filt); /* TODO: error checking */
}
if (kn->kev.flags & EV_DISPATCH)
KNOTE_DISABLE(kn);
if (kn->kev.flags & EV_ONESHOT)
knote_free(kn);
dst++;
nevents++;
}
return (nevents);
#endif
}
const struct filter evfilt_signal = {
0, //EVFILT_SIGNAL,
evfilt_signal_init,
evfilt_signal_destroy,
evfilt_signal_copyin,
evfilt_signal_copyout,
};

109
src/solaris/socket.c Normal file
View File

@ -0,0 +1,109 @@
/*
* Copyright (c) 2009 Mark Heily <mark@heily.com>
*
* 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.
*
* 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.
*/
#include <errno.h>
#include <fcntl.h>
#include <signal.h>
#include <stdlib.h>
#include <stdio.h>
#include <sys/queue.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <string.h>
#include <unistd.h>
#include <port.h>
#include "sys/event.h"
#include "private.h"
int
evfilt_socket_init(struct filter *filt)
{
return (0);
}
void
evfilt_socket_destroy(struct filter *filt)
{
;
}
int
evfilt_socket_copyin(struct filter *filt,
struct knote *dst, const struct kevent *src)
{
int port, events;
int rv;
port = filt->kf_kqueue->kq_port;
/* Not supported or not implemented */
if (src->flags & EV_CLEAR) {
dbg_puts("attempt to use unsupported mechanism");
return (-1);
}
if (src->flags & EV_ADD && KNOTE_EMPTY(dst)) {
memcpy(&dst->kev, src, sizeof(*src));
if (src->filter == EVFILT_READ)
events = POLLIN;
else
events = POLLOUT;
}
if (src->flags & EV_DELETE || src->flags & EV_DISABLE) {
rv = port_dissociate(port, PORT_SOURCE_FD, src->ident);
if (rv < 0) {
dbg_perror("port_disassociate(2)");
return (-1);
}
}
if (src->flags & EV_ENABLE || src->flags & EV_ADD) {
rv = port_associate(port, PORT_SOURCE_FD,
src->ident, events, src->udata);
if (rv < 0) {
dbg_perror("port_associate(2)");
return (-1);
}
}
/* XXX-TODO support modifying an existing watch */
return (0);
}
int
evfilt_socket_copyout(struct filter *filt,
struct kevent *dst,
int nevents)
{
return (-1);
}
const struct filter evfilt_read = {
EVFILT_READ,
evfilt_socket_init,
evfilt_socket_destroy,
evfilt_socket_copyin,
evfilt_socket_copyout,
};
const struct filter evfilt_write = {
EVFILT_WRITE,
evfilt_socket_init,
evfilt_socket_destroy,
evfilt_socket_copyin,
evfilt_socket_copyout,
};

125
src/solaris/timer.c Normal file
View File

@ -0,0 +1,125 @@
/*
* Copyright (c) 2009 Mark Heily <mark@heily.com>
*
* 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.
*
* 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.
*/
#include <port.h>
#include "sys/event.h"
#include "private.h"
int
evfilt_timer_init(struct filter *filt)
{
return (-1);
}
void
evfilt_timer_destroy(struct filter *filt)
{
;
}
int
evfilt_timer_copyin(struct filter *filt,
struct knote *dst, const struct kevent *src)
{
return (-1);
#if TODO
if (src->flags & EV_ADD && KNOTE_EMPTY(dst)) {
memcpy(&dst->kev, src, sizeof(*src));
dst->kev.flags |= EV_CLEAR;
}
if (src->flags & EV_ADD)
return ktimer_create(filt, dst);
if (src->flags & EV_DELETE)
return ktimer_delete(filt, dst);
if (src->flags & EV_ENABLE)
return ktimer_create(filt, dst);
if (src->flags & EV_DISABLE) {
// TODO: err checking
(void) ktimer_delete(filt, dst);
KNOTE_DISABLE(dst);
}
return (0);
#endif
}
int
evfilt_timer_copyout(struct filter *filt,
struct kevent *dst,
int nevents)
{
return (-1);
#if TODO
struct epoll_event epevt[MAX_KEVENT];
struct epoll_event *ev;
struct knote *kn;
uint64_t expired;
int i, nret;
ssize_t n;
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->kn_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);
if (kn->kev.flags & EV_ONESHOT) {
ktimer_delete(filt, kn);
knote_free(kn);
}
nevents++;
dst++;
}
return (nevents);
#endif
}
const struct filter evfilt_timer = {
0, //EVFILT_TIMER,
evfilt_timer_init,
evfilt_timer_destroy,
evfilt_timer_copyin,
evfilt_timer_copyout,
};

151
src/solaris/user.c Normal file
View File

@ -0,0 +1,151 @@
/*
* Copyright (c) 2009 Mark Heily <mark@heily.com>
*
* 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.
*
* 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.
*/
#include "sys/event.h"
#include "private.h"
int
evfilt_user_init(struct filter *filt)
{
return (-1);
}
void
evfilt_user_destroy(struct filter *filt)
{
return;
}
int
evfilt_user_copyin(struct filter *filt,
struct knote *dst, const struct kevent *src)
{
return (-1);
#if TODO
u_int ffctrl;
struct kevent *kev;
uint64_t counter;
if (src->flags & EV_ADD && KNOTE_EMPTY(dst))
memcpy(&dst->kev, src, sizeof(*src));
kev = &dst->kev;
if (src->flags & EV_ENABLE) {
dst->kev.flags &= ~EV_DISABLE;
/* FIXME: what happens if NOTE_TRIGGER is in fflags?
should the event fire? */
}
if (src->flags & EV_DISABLE)
dst->kev.flags |= EV_DISABLE;
/* FIXME: can oneshot be added after the knote is already created? */
if (src->flags & EV_ONESHOT)
dst->kev.flags |= EV_ONESHOT;
/* Excerpted from sys/kern/kern_event.c in FreeBSD HEAD */
ffctrl = kev->fflags & NOTE_FFCTRLMASK;
kev->fflags &= NOTE_FFLAGSMASK;
switch (ffctrl) {
case NOTE_FFNOP:
break;
case NOTE_FFAND:
kev->fflags &= src->fflags;
break;
case NOTE_FFOR:
kev->fflags |= src->fflags;
break;
case NOTE_FFCOPY:
kev->fflags = kev->fflags;
break;
default:
/* XXX Return error? */
break;
}
if ((!(dst->kev.flags & EV_DISABLE)) && src->fflags & NOTE_TRIGGER) {
counter = 1;
if (write(filt->kf_pfd, &counter, sizeof(counter)) < 0) {
if (errno != EAGAIN) {
dbg_printf("write(2): %s", strerror(errno));
return (-1);
}
}
dst->kev.fflags |= NOTE_TRIGGER;
dbg_puts("knote triggered");
}
#endif
return (0);
}
int
evfilt_user_copyout(struct filter *filt,
struct kevent *dst,
int maxevents)
{
return (-1);
#if TODO
struct knote *kn, *kn_next;
int nevents = 0;
uint64_t cur;
/* Reset the counter */
if (read(filt->kf_pfd, &cur, sizeof(cur)) < sizeof(cur)) {
dbg_printf("read(2): %s", strerror(errno));
return (-1);
}
dbg_printf(" counter=%llu", (unsigned long long) cur);
for (kn = LIST_FIRST(&filt->kf_watchlist); kn != NULL; kn = kn_next) {
kn_next = LIST_NEXT(kn, entries);
memcpy(dst, &kn->kev, sizeof(*dst));
dst->fflags &= ~NOTE_FFCTRLMASK; //FIXME: Not sure if needed
dst->fflags &= ~NOTE_TRIGGER;
if (kn->kev.flags & EV_DISPATCH)
KNOTE_DISABLE(kn);
if (kn->kev.flags & EV_ADD) {
/* NOTE: True on FreeBSD but not consistent behavior with
other filters. */
dst->flags &= ~EV_ADD;
}
if (kn->kev.flags & EV_ONESHOT) {
/* NOTE: True on FreeBSD but not consistent behavior with
other filters. */
dst->flags &= ~EV_ONESHOT;
knote_free(kn);
}
dst++;
if (++nevents == maxevents)
break;
}
return (nevents);
#endif
}
const struct filter evfilt_user = {
0, //EVFILT_USER,
evfilt_user_init,
evfilt_user_destroy,
evfilt_user_copyin,
evfilt_user_copyout,
};

172
src/solaris/vnode.c Normal file
View File

@ -0,0 +1,172 @@
/*
* Copyright (c) 2009 Mark Heily <mark@heily.com>
*
* 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.
*
* 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.
*/
#include "sys/event.h"
#include "private.h"
int
evfilt_vnode_init(struct filter *filt)
{
return (-1);
}
void
evfilt_vnode_destroy(struct filter *filt)
{
;
}
int
evfilt_vnode_copyin(struct filter *filt,
struct knote *dst, const struct kevent *src)
{
#if TODO
char path[PATH_MAX];
struct stat sb;
uint32_t mask;
if (src->flags & EV_DELETE || src->flags & EV_DISABLE)
return delete_watch(filt->kf_pfd, dst);
if (src->flags & EV_ADD && KNOTE_EMPTY(dst)) {
memcpy(&dst->kev, src, sizeof(*src));
if (fstat(src->ident, &sb) < 0) {
dbg_puts("fstat failed");
return (-1);
}
dst->kn_st_nlink = sb.st_nlink;
dst->kn_st_size = sb.st_size;
dst->kev.data = -1;
}
if (src->flags & EV_ADD || src->flags & EV_ENABLE) {
/* Convert the fd to a pathname */
if (fd_to_path(&path[0], sizeof(path), src->ident) < 0)
return (-1);
/* Convert the fflags to the inotify mask */
mask = 0;
if (dst->kev.fflags & NOTE_DELETE)
mask |= IN_ATTRIB | IN_DELETE_SELF;
if (dst->kev.fflags & NOTE_WRITE)
mask |= IN_MODIFY | IN_ATTRIB;
if (dst->kev.fflags & NOTE_EXTEND)
mask |= IN_MODIFY | IN_ATTRIB;
if ((dst->kev.fflags & NOTE_ATTRIB) ||
(dst->kev.fflags & NOTE_LINK))
mask |= IN_ATTRIB;
if (dst->kev.fflags & NOTE_RENAME)
mask |= IN_MOVE_SELF;
if (dst->kev.flags & EV_ONESHOT)
mask |= IN_ONESHOT;
dbg_printf("inotify_add_watch(2); inofd=%d, %s, path=%s",
filt->kf_pfd, inotify_mask_dump(mask), path);
dst->kev.data = inotify_add_watch(filt->kf_pfd, path, mask);
if (dst->kev.data < 0) {
dbg_printf("inotify_add_watch(2): %s", strerror(errno));
return (-1);
}
}
return (0);
#endif
return (-1);
}
int
evfilt_vnode_copyout(struct filter *filt,
struct kevent *dst,
int nevents)
{
#if TODO
struct inotify_event evt;
struct stat sb;
struct knote *kn;
if (get_one_event(&evt, filt->kf_pfd) < 0)
return (-1);
inotify_event_dump(&evt);
if (evt.mask & IN_IGNORED) {
/* TODO: possibly return error when fs is unmounted */
return (0);
}
kn = knote_lookup_data(filt, evt.wd);
if (kn == NULL) {
dbg_printf("no match for wd # %d", evt.wd);
return (-1);
}
memcpy(dst, &kn->kev, sizeof(*dst));
dst->data = 0;
/* No error checking because fstat(2) should rarely fail */
if ((evt.mask & IN_ATTRIB || evt.mask & IN_MODIFY)
&& fstat(kn->kev.ident, &sb) == 0) {
if (sb.st_nlink == 0 && kn->kev.fflags & NOTE_DELETE)
dst->fflags |= NOTE_DELETE;
if (sb.st_nlink != kn->kn_st_nlink && kn->kev.fflags & NOTE_LINK)
dst->fflags |= NOTE_LINK;
#if HAVE_NOTE_TRUNCATE
if (sb.st_nsize == 0 && kn->kev.fflags & NOTE_TRUNCATE)
dst->fflags |= NOTE_TRUNCATE;
#endif
if (sb.st_size > kn->kn_st_size && kn->kev.fflags & NOTE_WRITE)
dst->fflags |= NOTE_EXTEND;
kn->kn_st_nlink = sb.st_nlink;
kn->kn_st_size = sb.st_size;
}
if (evt.mask & IN_MODIFY && kn->kev.fflags & NOTE_WRITE)
dst->fflags |= NOTE_WRITE;
if (evt.mask & IN_ATTRIB && kn->kev.fflags & NOTE_ATTRIB)
dst->fflags |= NOTE_ATTRIB;
if (evt.mask & IN_MOVE_SELF && kn->kev.fflags & NOTE_RENAME)
dst->fflags |= NOTE_RENAME;
if (evt.mask & IN_DELETE_SELF && kn->kev.fflags & NOTE_DELETE)
dst->fflags |= NOTE_DELETE;
if (evt.mask & IN_MODIFY && kn->kev.fflags & NOTE_WRITE)
dst->fflags |= NOTE_WRITE;
if (evt.mask & IN_ATTRIB && kn->kev.fflags & NOTE_ATTRIB)
dst->fflags |= NOTE_ATTRIB;
if (evt.mask & IN_MOVE_SELF && kn->kev.fflags & NOTE_RENAME)
dst->fflags |= NOTE_RENAME;
if (evt.mask & IN_DELETE_SELF && kn->kev.fflags & NOTE_DELETE)
dst->fflags |= NOTE_DELETE;
if (kn->kev.flags & EV_DISPATCH) {
delete_watch(filt->kf_pfd, kn); /* TODO: error checking */
KNOTE_DISABLE(kn);
}
if (kn->kev.flags & EV_ONESHOT)
knote_free(kn);
return (1);
#endif
return (-1);
}
const struct filter evfilt_vnode = {
0, //EVFILT_VNODE,
evfilt_vnode_init,
evfilt_vnode_destroy,
evfilt_vnode_copyin,
evfilt_vnode_copyout,
};

View File

@ -16,30 +16,30 @@
include config.mk
all:
kqtest: $(SOURCES)
if [ ! -f /usr/include/sys/event.h ] ; then \
cd .. && ./configure --debug=yes && make build ; \
fi
$(CC) $(CFLAGS) $(SOURCES) $(LDADD)
$(CC) -o kqtest $(CFLAGS) $(SOURCES) $(LDADD)
check:
./a.out
check: kqtest
./kqtest
# NOTE: copy+paste of 'make check'
valgrind: all
valgrind --tool=memcheck --leak-check=full --show-reachable=yes --num-callers=20 --track-fds=yes ./a.out
valgrind: kqtest
valgrind --tool=memcheck --leak-check=full --show-reachable=yes --num-callers=20 --track-fds=yes ./kqtest
check-installed:
gcc $(CFLAGS) -I$(PREFIX)/kqueue test.c -lkqueue
./a.out
gcc $(CFLAGS) -o kqtest -I$(PREFIX)/kqueue test.c -lkqueue
./kqtest
check-libtool:
gcc $(CFLAGS) -c *.c
libtool --mode=link gcc -g -O0 -o a.out *.o $(LIBDIR)/libkqueue.la
./a.out
libtool --mode=link gcc -g -O0 -o kqtest *.o $(LIBDIR)/libkqueue.la
./kqtest
distclean: clean
rm -f config.mk config.h a.out
rm -f config.mk config.h
clean:
rm -f *.o
rm -f *.o kqtest

View File

@ -18,7 +18,12 @@
#define _COMMON_H
#include <err.h>
#if HAVE_ERR_H
# include <err.h>
#else
# define err(rc,msg,...) do { perror(msg); exit(rc); } while (0)
# define errx(rc,msg,...) do { puts(msg); exit(rc); } while (0)
#endif
#include <errno.h>
#include <fcntl.h>
#include <signal.h>

View File

@ -15,6 +15,8 @@ pre_configure_hook() {
ldadd="$ldadd ../libkqueue.a -lpthread -lrt"
}
test "$target" = "solaris" && ldadd="$ldadd -lsocket"
check_symbol $sys_event_h EV_DISPATCH
check_symbol $sys_event_h EV_RECEIPT
check_symbol $sys_event_h NOTE_TRUNCATE

View File

@ -255,9 +255,6 @@ main(int argc, char **argv)
test_kqueue();
test_kqueue_close();
if (test_proc)
test_evfilt_proc();
if (test_socket)
test_evfilt_read();
if (test_signal)
@ -270,6 +267,8 @@ main(int argc, char **argv)
#endif
if (test_timer)
test_evfilt_timer();
if (test_proc)
test_evfilt_proc();
printf("\n---\n"
"+OK All %d tests completed.\n", testnum - 1);

View File

@ -16,63 +16,82 @@
#include "common.h"
static int sigusr1_caught = 0;
int kqfd;
pid_t child;
static void
sig_handler(int signum)
{
sigusr1_caught = 1;
}
static void
add_and_delete(void)
{
const char *test_id1 = "kevent(EVFILT_PROC, EV_ADD)";
const char *test_id2 = "kevent(EVFILT_PROC, EV_ADD)";
struct kevent kev;
pid_t pid;
test_begin(test_id1);
/* Create a child that waits to be killed and then exits */
pid = fork();
if (pid == 0) {
pause();
exit(2);
}
printf(" -- child created (pid %d)\n", (int) pid);
EV_SET(&kev, child, EVFILT_PROC, EV_ADD, 0, 0, NULL);
if (kevent(kqfd, &kev, 1, NULL, 0, NULL) < 0)
err(1, "%s", test_id1);
test_begin("kevent(EVFILT_PROC, EV_ADD)");
test_no_kevents();
kevent_add(kqfd, &kev, pid, EVFILT_PROC, EV_ADD, 0, 0, NULL);
test_no_kevents();
success();
test_begin(test_id2);
test_begin("kevent(EVFILT_PROC, EV_DELETE)");
kev.flags = EV_DELETE;
if (kevent(kqfd, &kev, 1, NULL, 0, NULL) < 0)
err(1, "%s", test_id2);
success();
}
#if TODO
void
test_kevent_signal_get(void)
{
const char *test_id = "kevent(EVFILT_SIGNAL, wait)";
struct kevent kev;
test_begin(test_id);
EV_SET(&kev, SIGUSR1, EVFILT_SIGNAL, EV_ADD, 0, 0, NULL);
if (kevent(kqfd, &kev, 1, NULL, 0, NULL) < 0)
err(1, "%s", test_id);
/* Block SIGUSR1, then send it to ourselves */
sigset_t mask;
sigemptyset(&mask);
sigaddset(&mask, SIGUSR1);
if (sigprocmask(SIG_BLOCK, &mask, NULL) == -1)
err(1, "sigprocmask");
if (kill(getpid(), SIGUSR1) < 0)
test_no_kevents();
kevent_add(kqfd, &kev, pid, EVFILT_PROC, EV_DELETE, 0, 0, NULL);
if (kill(pid, SIGKILL) < 0)
err(1, "kill");
sleep(1);
test_no_kevents();
kev.flags |= EV_CLEAR;
kev.data = 1;
success();
}
static void
event_trigger(void)
{
struct kevent kev;
pid_t pid;
test_begin("kevent(EVFILT_PROC, wait)");
/* Create a child that waits to be killed and then exits */
pid = fork();
if (pid == 0) {
pause();
printf(" -- child caught signal, exiting\n");
exit(2);
}
printf(" -- child created (pid %d)\n", (int) pid);
test_no_kevents();
kevent_add(kqfd, &kev, pid, EVFILT_PROC, EV_ADD, 0, 0, NULL);
/* Cause the child to exit, then retrieve the event */
printf(" -- killing process %d\n", (int) pid);
if (kill(pid, SIGUSR1) < 0)
err(1, "kill");
kevent_cmp(&kev, kevent_get(kqfd));
test_no_kevents();
success();
}
#ifdef TODO
void
test_kevent_signal_disable(void)
{
@ -91,7 +110,7 @@ test_kevent_signal_disable(void)
sigaddset(&mask, SIGUSR1);
if (sigprocmask(SIG_BLOCK, &mask, NULL) == -1)
err(1, "sigprocmask");
if (kill(getpid(), SIGUSR1) < 0)
if (kill(getpid(), SIGKILL) < 0)
err(1, "kill");
test_no_kevents();
@ -201,14 +220,13 @@ test_evfilt_proc()
{
kqfd = kqueue();
/* Create a child that sleeps for a few seconds and then exits */
child = fork();
if (child == 0) {
sleep(3);
exit(123);
}
signal(SIGUSR1, sig_handler);
add_and_delete();
event_trigger();
signal(SIGUSR1, SIG_DFL);
#if TODO
test_kevent_signal_add();
test_kevent_signal_del();

View File

@ -304,7 +304,7 @@ void
test_evfilt_read()
{
/* Create a connected pair of full-duplex sockets for testing socket events */
if (socketpair(AF_LOCAL, SOCK_STREAM, 0, sockfd) < 0)
if (socketpair(AF_UNIX, SOCK_STREAM, 0, sockfd) < 0)
abort();
kqfd = kqueue();

View File

@ -41,7 +41,7 @@
<h1>libkqueue</h1>
libkqueue is a portable userspace implementation of the <a href="http://www.freebsd.org/cgi/man.cgi?query=kqueue&sektion=2">kqueue(2)</a> kernel event notification mechanism. Initial efforts are focused on porting the kqueue API to the Linux 2.6 kernel.
libkqueue is a portable userspace implementation of the <a href="http://www.freebsd.org/cgi/man.cgi?query=kqueue&sektion=2">kqueue(2)</a> kernel event notification mechanism. Initial efforts are focused on porting the kqueue API to the Linux 2.6 kernel. There is also an experimental Solaris port (currently broken).
<h2>Download</h2>
@ -158,6 +158,8 @@ libkqueue currently requires the following:
<li>glibc 2.8 or higher
</ul>
The Solaris port requires Solaris 10 or higher, and uses the GNU compiler and toolchain.
<h2>Usage</h2>