mirror of
https://github.com/darlinghq/darling-libkqueue.git
synced 2024-11-23 11:49:50 +00:00
* 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:
parent
c9e5fa9267
commit
bab7f0f8d8
4
Makefile
4
Makefile
@ -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
|
||||
|
@ -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
85
configure
vendored
@ -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
|
||||
|
||||
|
@ -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_ */
|
||||
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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);
|
||||
|
@ -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
81
src/linux/hook.c
Normal 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);
|
||||
}
|
@ -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
97
src/solaris/hook.c
Normal 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
111
src/solaris/proc.c
Normal 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
117
src/solaris/signal.c
Normal 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
109
src/solaris/socket.c
Normal 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
125
src/solaris/timer.c
Normal 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
151
src/solaris/user.c
Normal 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
172
src/solaris/vnode.c
Normal 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,
|
||||
};
|
@ -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
|
||||
|
@ -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>
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
|
108
test/proc.c
108
test/proc.c
@ -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();
|
||||
|
@ -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();
|
||||
|
@ -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>
|
||||
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user