···11+== all source ==
22+33+Copyright (c) 2009 Mark Heily <mark@heily.com>
44+55+Permission to use, copy, modify, and distribute this software for any
66+purpose with or without fee is hereby granted, provided that the above
77+copyright notice and this permission notice appear in all copies.
88+99+THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
1010+WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
1111+MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
1212+ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
1313+WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
1414+ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
1515+OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
1616+1717+== event.h ==
1818+1919+Copyright (c) 1999,2000,2001 Jonathan Lemon <jlemon@FreeBSD.org>
2020+All rights reserved.
2121+2222+Redistribution and use in source and binary forms, with or without
2323+modification, are permitted provided that the following conditions
2424+are met:
2525+1. Redistributions of source code must retain the above copyright
2626+ notice, this list of conditions and the following disclaimer.
2727+2. Redistributions in binary form must reproduce the above copyright
2828+ notice, this list of conditions and the following disclaimer in the
2929+ documentation and/or other materials provided with the distribution.
3030+3131+THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
3232+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
3333+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
3434+ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
3535+FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
3636+DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
3737+OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
3838+HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
3939+LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
4040+OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
4141+SUCH DAMAGE.
4242+
···11+#!/bin/sh
22+#
33+# Copyright (c) 2013 Mark Heily <mark@heily.com>
44+#
55+# Permission to use, copy, modify, and distribute this software for any
66+# purpose with or without fee is hereby granted, provided that the above
77+# copyright notice and this permission notice appear in all copies.
88+#
99+# THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
1010+# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
1111+# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
1212+# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
1313+# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
1414+# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
1515+# OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
1616+#
1717+1818+usage() {
1919+cat << "EOF"
2020+Usage: configure [options]
2121+2222+Installation options:
2323+ --bindir [DIRECTORY] TODO describe this [$(EPREFIX)/bin]
2424+ --datadir [DIRECTORY] TODO describe this [$(DATAROOTDIR)]
2525+ --datarootdir [DIRECTORY] TODO describe this [$(PREFIX)/share]
2626+ --docdir [DIRECTORY] TODO describe this [$(DATAROOTDIR)/doc/$(PACKAGE)]
2727+ --eprefix [DIRECTORY] TODO describe this [$(PREFIX)]
2828+ --includedir [DIRECTORY] TODO describe this [$(PREFIX)/include]
2929+ --infodir [DIRECTORY] TODO describe this [$(DATAROOTDIR)/info]
3030+ --libdir [DIRECTORY] TODO describe this [$(EPREFIX)/lib]
3131+ --libexecdir [DIRECTORY] TODO describe this [$(EPREFIX)/libexec]
3232+ --localedir [DIRECTORY] TODO describe this [$(DATAROOTDIR)/locale]
3333+ --localstatedir [DIRECTORY] TODO describe this [$(PREFIX)/var]
3434+ --mandir [DIRECTORY] TODO describe this [$(DATAROOTDIR)/man]
3535+ --oldincludedir [DIRECTORY] TODO describe this [/usr/include]
3636+ --pkgconfigdir [DIRECTORY] where to install pkg-config files [$(LIBDIR)/pkgconfig]
3737+ --pkgdatadir [DIRECTORY] TODO describe this [$(DATADIR)/$(PACKAGE)]
3838+ --pkgincludedir [DIRECTORY] TODO describe this [$(INCLUDEDIR)/$(PACKAGE)]
3939+ --pkglibdir [DIRECTORY] TODO describe this [$(LIBDIR)/$(PACKAGE)]
4040+ --prefix [DIRECTORY] TODO describe this [/usr/local]
4141+ --sbindir [DIRECTORY] TODO describe this [$(EPREFIX)/sbin]
4242+ --sharedstatedir [DIRECTORY] TODO describe this [$(PREFIX)/com]
4343+ --sysconfdir [DIRECTORY] TODO describe this [$(PREFIX)/etc]
4444+4545+Project options:
4646+4747+System types:
4848+ --build BUILD set the system type for building
4949+ --host HOST cross-compile programs to run on a different system type
5050+ --target TARGET build a compiler for cross-compiling
5151+5252+Optional Features:
5353+5454+Common options:
5555+ --disable-static Disable generation of static libraries
5656+ --disable-option-checking
5757+ -h, --help Show this message
5858+ -V, --version Display version information and exit
5959+EOF
6060+}
6161+6262+err() {
6363+ echo "*** ERROR *** $*"
6464+ exit 1
6565+}
6666+6767+require_var() {
6868+ key=$1
6969+ eval "val=\$$key"
7070+ if [ "$val" = "" ] ; then
7171+ echo "ERROR: you must provide --$2 as a command line option"
7272+ exit 1
7373+ fi
7474+}
7575+7676+7777+echo "# Automatically generated by ./configure -- do not edit" > config.mk
7878+for arg in $*
7979+do
8080+ if [ `echo "$arg" | grep "^--"` = "$arg" ] ; then
8181+ key=`echo $arg | sed "s/^--//; s/=.*//; s/^with-//;"`
8282+ val=`echo $arg | sed "s/.*=//"`
8383+ uc_key=`echo "$key" | tr "a-z" "A-Z" | tr "-" "_"`
8484+ case $key in
8585+ "help")
8686+ usage
8787+ exit 1
8888+ ;;
8989+ bindir|datadir|datarootdir|docdir|includedir|infodir|libdir|libexecdir|localedir|localstatedir|mandir|pkgconfigdir|pkgdatadir|pkgincludedir|pkglibdir|prefix|sbindir|sharedstatedir|sysconfdir)
9090+ echo "$uc_key=$val" >> config.mk
9191+ ;;
9292+ exec-prefix)
9393+ echo "EPREFIX=$val" >> config.mk
9494+ ;;
9595+ program-prefix)
9696+ if [ "$val" != "" ] ; then err "FIXME - not implemented" ; fi
9797+ ;;
9898+ disable-static)
9999+ echo "$uc_key=1" >> config.mk
100100+ ;;
101101+ build|host)
102102+ # TODO: we should split this up, and override the other Makeconf
103103+ # variables like *_VENDOR, *_ARCH, *_CPU, *_KERNEL, *_SYSTEM
104104+ echo "$uc_key=$val" >> config.mk
105105+ eval "${key}_system_type=\"$val\""
106106+ ;;
107107+ disable-option-checking)
108108+ # Not implemented, this behavior is the default (for now)
109109+ ;;
110110+ disable-dependency-tracking)
111111+ # Not implemented, dependency tracking is done in Ruby (for now)
112112+ ;;
113113+ # Android-specific variables
114114+ ndk|sdk)
115115+ echo "$uc_key=$val" >> config.mk
116116+ eval "$key=\"$val\""
117117+ ;;
118118+ *)
119119+ echo "Warning: unrecognized option: $arg"
120120+ ;;
121121+ esac
122122+ fi
123123+done
124124+125125+# Android-specific options
126126+if [ "`echo ${host_system_type} | grep androideabi`" != "" ] ; then
127127+ exec ./configure.rb $*
128128+# require_var ndk with-ndk
129129+# require_var sdk with-sdk
130130+fi
131131+132132+printf "checking for a C compiler... "
133133+for cmd in ${host_system_type}-cc cc gcc gcc4 clang
134134+do
135135+ $cmd --version >/dev/null 2>&1
136136+ if [ $? -eq 0 ] ; then cc="$cmd" ; break ; fi
137137+done
138138+if [ -n "$CC" ] ; then cc="$CC" ; fi
139139+if [ -n "$cc" ] ; then
140140+ echo "$cc"
141141+ echo "CC=$cc" >> config.mk
142142+ if [ "$cc" != "cc" ] ; then echo "LD=$cc" >> config.mk ; fi
143143+ if [ -n "$CFLAGS" ] ; then echo "CFLAGS=$CFLAGS" >> config.mk ; fi
144144+else
145145+ echo "not found"
146146+ err "Please install a compiler and add it to your PATH"
147147+fi
148148+149149+printf "checking for ar.. "
150150+for ar in ${host_system_type}-ar ar gar
151151+do
152152+ $ar --version >/dev/null 2>&1
153153+ if [ $? -eq 0 ] ; then ar="$ar" ; break ; fi
154154+done
155155+if [ -n "$ar" ] ; then
156156+ echo "$ar"
157157+ echo "AR=$ar" >> config.mk
158158+else
159159+ echo "not found"
160160+ err "Please install an archiver and add it to your PATH"
161161+fi
162162+163163+printf "checking for ranlib.. "
164164+for ranlib in ${host_system_type}-ranlib ranlib
165165+do
166166+ $ar --version >/dev/null 2>&1
167167+ if [ $? -eq 0 ] ; then ranlib="$ranlib" ; break ; fi
168168+done
169169+if [ -n "$ranlib" ] ; then
170170+ echo "$ranlib"
171171+ echo "RANLIB=$ranlib" >> config.mk
172172+else
173173+ echo "not found"
174174+ err "Please install ranlib and add it to your PATH"
175175+fi
176176+177177+printf "checking for a usable make command... "
178178+for cmd in make gmake
179179+do
180180+ $cmd --version >/dev/null 2>&1
181181+ if [ $? -eq 0 ] ; then make="$cmd" ; break ; fi
182182+done
183183+if [ -n "$make" ] ; then
184184+ echo "yes"
185185+ echo "MAKE=$make" >> config.mk
186186+else
187187+ echo "not found"
188188+ err "Please install GNU Make and add it to your PATH as either make or gmake"
189189+fi
190190+191191+# Allow additional variables from the environment to override the defaults
192192+#
193193+test -n "$LD" && echo "LD=$LD" >> config.mk
194194+test -n "$LDFLAGS" && echo "LDFLAGS=$LDFLAGS" >> config.mk
195195+# TODO: need to add Makefile support for: LIBS, CPP, CPPFLAGS
196196+197197+rm -f config.h
198198+$make config.h
+320
external/libkqueue-2.0.1/configure.rb
···11+#!/usr/bin/env ruby
22+#
33+# Copyright (c) 2012 Mark Heily <mark@heily.com>
44+#
55+# Permission to use, copy, modify, and distribute this software for any
66+# purpose with or without fee is hereby granted, provided that the above
77+# copyright notice and this permission notice appear in all copies.
88+#
99+# THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
1010+# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
1111+# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
1212+# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
1313+# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
1414+# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
1515+# OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
1616+#
1717+1818+begin
1919+require 'makeconf'
2020+rescue LoadError
2121+ $LOAD_PATH << "makeconf"
2222+ require 'makeconf'
2323+end
2424+2525+# Determine the list of compiler flags
2626+def get_cflags
2727+ cflags='-I./src/common -I./include -Wall -Wextra -Wno-missing-field-initializers -Werror -g -O2 -std=c99 -D_XOPEN_SOURCE=600'.split(/ /)
2828+2929+ if Platform.is_linux?
3030+ # TODO - note this as a GCC 4.X dependency
3131+ cflags.push ' -fvisibility=hidden'
3232+ end
3333+ if Platform.is_solaris?
3434+ cflags.push "-D__EXTENSIONS__"
3535+ end
3636+ cflags
3737+end
3838+3939+# Determine the list of source code files for libkqueue
4040+def get_source_list(project)
4141+ src = %w{
4242+ src/common/filter.c
4343+ src/common/knote.c
4444+ src/common/map.c
4545+ src/common/kevent.c
4646+ src/common/kqueue.c
4747+ }
4848+4949+ if Platform.is_solaris?
5050+ src.push 'src/solaris/signal.c',
5151+ 'src/solaris/timer.c',
5252+ 'src/solaris/platform.c',
5353+ 'src/solaris/user.c'
5454+ end
5555+5656+ if Platform.is_linux? or Platform.is_solaris?
5757+ src.push 'src/posix/platform.c'
5858+ end
5959+6060+ if Platform.is_linux?
6161+ src.push 'src/linux/platform.c',
6262+ 'src/linux/read.c',
6363+ 'src/linux/write.c',
6464+ 'src/linux/user.c',
6565+ 'src/linux/vnode.c'
6666+6767+ # FIXME: needed for RHEL5
6868+ #src.push 'src/posix/user.c'
6969+7070+ if project.check_header('sys/signalfd.h')
7171+ src.push 'src/linux/signal.c'
7272+ else
7373+ src.push 'src/posix/signal.c'
7474+ end
7575+7676+ src.push 'src/linux/timer.c'
7777+ end
7878+7979+ if Platform.is_windows?
8080+ src.push 'src/windows/timer.c',
8181+ 'src/windows/platform.c',
8282+ 'src/windows/read.c',
8383+ 'src/windows/user.c'
8484+ end
8585+8686+ src
8787+end
8888+8989+# Generate the linker flags
9090+def get_ldadd
9191+ ldadd = ''
9292+9393+ if Platform.is_linux? or Platform.is_solaris?
9494+ ldadd += ' -lpthread'
9595+ end
9696+9797+ if Platform.is_linux?
9898+ ldadd += ' -lrt'
9999+ end
100100+101101+ if Platform.is_windows?
102102+ ldadd += ' ws2_32.lib'
103103+ end
104104+105105+ ldadd
106106+end
107107+108108+#
109109+# MAIN()
110110+#
111111+112112+project = Project.new \
113113+ :id => 'libkqueue',
114114+ :version => '2.0.1'
115115+116116+kq = Library.new(
117117+ :id => 'libkqueue',
118118+ :cflags => get_cflags(),
119119+ :ldadd => get_ldadd(),
120120+ :sources => get_source_list(project)
121121+ )
122122+123123+124124+project.check_header 'sys/event.h'
125125+if Platform.is_linux?
126126+ project.check_decl 'EPOLLRDHUP', :include => 'sys/epoll.h'
127127+ project.check_decl 'ppoll', :cflags => '#define _GNU_SOURCE', :include => 'poll.h'
128128+129129+130130+ project.check_header('sys/epoll.h') or throw 'epoll is required'
131131+ project.check_header('sys/inotify.h') or throw 'inotify is required'
132132+ project.check_header %w{ sys/signalfd.h sys/timerfd.h sys/eventfd.h }
133133+end
134134+135135+project.add(kq)
136136+137137+project.add(Header.new(
138138+ :id => 'event.h',
139139+ :sources => 'include/sys/event.h',
140140+ :namespace => 'kqueue/sys'
141141+ ))
142142+143143+project.add(Manual.new('kqueue.2', :alias => 'kevent.2'))
144144+145145+test_ldadd = get_ldadd()
146146+test_ldadd += ' libkqueue.a'
147147+if Platform.is_windows?
148148+ project.add(
149149+ Test.new(
150150+ :id => 'kqtest',
151151+ :cflags => '-g -O0 -Wall -Werror -Iinclude -Itest',
152152+ :sources => %w{
153153+ test/main.c
154154+ test/kevent.c
155155+ test/test.c
156156+ test/read.c
157157+ test/timer.c
158158+ test/vnode.c
159159+ test/user.c
160160+ }, # NOTE: signal.c and proc.c are removed
161161+ :ldadd => test_ldadd.split(' ')
162162+ )
163163+ )
164164+else
165165+ project.add(
166166+ Test.new(
167167+ :id => 'kqtest',
168168+ :cflags => '-g -O0 -Wall -Werror -I./include -I./test',
169169+ :sources => %w{
170170+ test/main.c
171171+ test/kevent.c
172172+ test/test.c
173173+ test/proc.c
174174+ test/read.c
175175+ test/signal.c
176176+ test/timer.c
177177+ test/vnode.c
178178+ test/user.c
179179+ },
180180+ :ldadd => test_ldadd.split(' ')
181181+ )
182182+ )
183183+end
184184+185185+186186+project.add(PkgConfig.new(
187187+ :name => 'libkqueue',
188188+ :description => 'Emulates FreeBSD kqueue(2) on other platforms',
189189+ :requires => '',
190190+ :libs => '-lkqueue',
191191+ :libs_private => '-lpthread',
192192+ :export_cflags => '-I${includedir}/kqueue'
193193+ ))
194194+195195+project.packager.add 'libkqueue.spec'
196196+197197+mc = Makeconf.new()
198198+mc.configure(project)
199199+200200+__END__
201201+#
202202+# BEGIN: old config.inc contents
203203+#
204204+program="libkqueue"
205205+version="2.0a"
206206+abi_major="0"
207207+abi_minor="0"
208208+abi_version="$abi_major.$abi_minor"
209209+cflags="-Wall -Wextra -Wno-missing-field-initializers -Werror -g -O2 -std=c99 -D_XOPEN_SOURCE=600"
210210+ldflags=""
211211+sources="src/common/filter.c src/common/knote.c src/common/map.c
212212+ src/common/kevent.c src/common/kqueue.c"
213213+libdepends=""
214214+deps="src/common/private.h src/common/debug.h"
215215+mans="kqueue.2"
216216+headers="src/common/private.h"
217217+extra_dist="*.in"
218218+subdirs="src include test"
219219+220220+# Package metadata
221221+pkg_summary="Emulates the kqueue and kevent system calls"
222222+pkg_description="Emulates the kqueue and kevent system calls"
223223+license="BSD"
224224+author="Mark Heily"
225225+226226+pre_configure_hook() {
227227+ if [ "$debug" = "yes" ] ; then
228228+ cflags="$cflags -g3 -O0 -rdynamic"
229229+ fi
230230+231231+ if [ "$target" != "windows" ] ; then
232232+ cflags="$cflags -fpic"
233233+ fi
234234+235235+ optional_headers="err.h"
236236+237237+ libdepends=" -L$libdir"
238238+ if [ $target = "linux" ] ; then
239239+240240+ check_symbol sys/epoll.h EPOLLRDHUP
241241+242242+ # TODO - note this as a GCC 4.X dependency
243243+ cflags="$cflags -fvisibility=hidden"
244244+245245+ libdepends="$libdepends -lpthread -lrt"
246246+ required_headers="sys/epoll.h sys/inotify.h"
247247+ optional_headers="sys/signalfd.h sys/timerfd.h sys/eventfd.h"
248248+ fi
249249+250250+ if [ $target = "solaris" ] ; then
251251+ cflags="$cflags -m64"
252252+ ldflags="$ldflags -m64"
253253+ libdepends="$libdepends -lsocket -lnsl"
254254+ fi
255255+}
256256+257257+post_configure_hook() {
258258+ finalize target "$target"
259259+260260+ platform="src/posix/platform.c"
261261+ evfilt_signal="src/posix/signal.c"
262262+ evfilt_proc="src/$target/proc.c"
263263+ evfilt_socket="src/$target/socket.c"
264264+ evfilt_timer="src/posix/timer.c"
265265+ evfilt_user="src/posix/user.c"
266266+ evfilt_vnode="src/$target/vnode.c"
267267+268268+ if [ $target = "linux" ] ; then
269269+ evfilt_user="src/linux/user.c"
270270+ evfilt_socket="src/linux/read.c src/linux/write.c"
271271+272272+ #XXX-FIXME disabled
273273+ evfilt_proc=""
274274+275275+ if [ "$have_sys_signalfd_h" = "yes" ] ; then
276276+ evfilt_signal="src/linux/signal.c"
277277+ fi
278278+ if [ "$have_sys_timerfd_h" = "yes" ] ; then
279279+ evfilt_timer="src/linux/timer.c"
280280+ fi
281281+ platform="$platform src/linux/platform.c"
282282+ fi
283283+284284+ if [ $target = "solaris" ] ; then
285285+ cflags="$cflags -D__EXTENSIONS__"
286286+ platform="$platform src/solaris/platform.c"
287287+ evfilt_timer="src/solaris/timer.c"
288288+ evfilt_user="src/solaris/user.c"
289289+ evfilt_signal="src/solaris/signal.c"
290290+ evfilt_proc=""
291291+ evfilt_vnode=""
292292+ fi
293293+294294+ # FIXME: This will compile but not actually work
295295+ if [ $target = "freebsd" ] ; then
296296+ evfilt_signal="src/posix/signal.c"
297297+ evfilt_proc=""
298298+ evfilt_socket=""
299299+ evfilt_timer=""
300300+ evfilt_vnode=""
301301+ fi
302302+303303+ if [ $target = "windows" ] ; then
304304+ platform="src/windows/platform.c"
305305+ cflags="$cflags -march=i686 -lws2_32"
306306+ ldflags="$ldflags -march=i686"
307307+ ldadd="-lws2_32"
308308+ evfilt_proc=""
309309+ evfilt_signal=""
310310+ #evfilt_socket="src/windows/read.c src/linux/write.c"
311311+ evfilt_socket="src/windows/read.c"
312312+ evfilt_timer="src/windows/timer.c"
313313+ evfilt_user="src/windows/user.c"
314314+ evfilt_vnode=""
315315+ fi
316316+317317+ sources="$sources $platform
318318+ $evfilt_signal $evfilt_proc
319319+ $evfilt_socket $evfilt_timer $evfilt_user $evfilt_vnode"
320320+}
+212
external/libkqueue-2.0.1/include/sys/event.h
···11+/*-
22+ * Copyright (c) 2009 Mark Heily <mark@heily.com>
33+ * Copyright (c) 1999,2000,2001 Jonathan Lemon <jlemon@FreeBSD.org>
44+ * All rights reserved.
55+ *
66+ * Redistribution and use in source and binary forms, with or without
77+ * modification, are permitted provided that the following conditions
88+ * are met:
99+ * 1. Redistributions of source code must retain the above copyright
1010+ * notice, this list of conditions and the following disclaimer.
1111+ * 2. Redistributions in binary form must reproduce the above copyright
1212+ * notice, this list of conditions and the following disclaimer in the
1313+ * documentation and/or other materials provided with the distribution.
1414+ *
1515+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
1616+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
1717+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
1818+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
1919+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2020+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2121+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2222+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2323+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
2424+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
2525+ * SUCH DAMAGE.
2626+ *
2727+ * $FreeBSD SVN Revision 197533$
2828+ */
2929+3030+#ifndef _SYS_EVENT_H_
3131+#define _SYS_EVENT_H_
3232+3333+#include <sys/types.h>
3434+3535+#ifdef __KERNEL__
3636+#define intptr_t long
3737+#else
3838+#include <sys/types.h>
3939+#if defined(_WIN32) && _MSC_VER < 1600 && !defined(__MINGW32__)
4040+# include "../../src/windows/stdint.h"
4141+#else
4242+# include <stdint.h>
4343+#endif
4444+#define LIBKQUEUE 1
4545+#endif
4646+4747+struct timespec;
4848+4949+#define EVFILT_READ (-1)
5050+#define EVFILT_WRITE (-2)
5151+#define EVFILT_AIO (-3) /* attached to aio requests */
5252+#define EVFILT_VNODE (-4) /* attached to vnodes */
5353+#define EVFILT_PROC (-5) /* attached to struct proc */
5454+#define EVFILT_SIGNAL (-6) /* attached to struct proc */
5555+#define EVFILT_TIMER (-7) /* timers */
5656+#define EVFILT_NETDEV (-8) /* network devices */
5757+#define EVFILT_FS (-9) /* filesystem events */
5858+#define EVFILT_LIO (-10) /* attached to lio requests */
5959+#define EVFILT_USER (-11) /* User events */
6060+#define EVFILT_SYSCOUNT 11
6161+6262+#define EV_SET(kevp_, a, b, c, d, e, f) do { \
6363+ struct kevent *kevp = (kevp_); \
6464+ (kevp)->ident = (a); \
6565+ (kevp)->filter = (b); \
6666+ (kevp)->flags = (c); \
6767+ (kevp)->fflags = (d); \
6868+ (kevp)->data = (e); \
6969+ (kevp)->udata = (f); \
7070+} while(0)
7171+7272+struct kevent {
7373+ uintptr_t ident; /* identifier for this event */
7474+ short filter; /* filter for event */
7575+ unsigned short flags;
7676+ unsigned int fflags;
7777+ intptr_t data;
7878+ void *udata; /* opaque user data identifier */
7979+};
8080+8181+/* actions */
8282+#define EV_ADD 0x0001 /* add event to kq (implies enable) */
8383+#define EV_DELETE 0x0002 /* delete event from kq */
8484+#define EV_ENABLE 0x0004 /* enable event */
8585+#define EV_DISABLE 0x0008 /* disable event (not reported) */
8686+8787+/* flags */
8888+#define EV_ONESHOT 0x0010 /* only report one occurrence */
8989+#define EV_CLEAR 0x0020 /* clear event state after reporting */
9090+#define EV_RECEIPT 0x0040 /* force EV_ERROR on success, data=0 */
9191+#define EV_DISPATCH 0x0080 /* disable event after reporting */
9292+9393+#define EV_SYSFLAGS 0xF000 /* reserved by system */
9494+#define EV_FLAG1 0x2000 /* filter-specific flag */
9595+9696+/* returned values */
9797+#define EV_EOF 0x8000 /* EOF detected */
9898+#define EV_ERROR 0x4000 /* error, data contains errno */
9999+100100+ /*
101101+ * data/hint flags/masks for EVFILT_USER
102102+ *
103103+ * On input, the top two bits of fflags specifies how the lower twenty four
104104+ * bits should be applied to the stored value of fflags.
105105+ *
106106+ * On output, the top two bits will always be set to NOTE_FFNOP and the
107107+ * remaining twenty four bits will contain the stored fflags value.
108108+ */
109109+#define NOTE_FFNOP 0x00000000 /* ignore input fflags */
110110+#define NOTE_FFAND 0x40000000 /* AND fflags */
111111+#define NOTE_FFOR 0x80000000 /* OR fflags */
112112+#define NOTE_FFCOPY 0xc0000000 /* copy fflags */
113113+#define NOTE_FFCTRLMASK 0xc0000000 /* masks for operations */
114114+#define NOTE_FFLAGSMASK 0x00ffffff
115115+116116+#define NOTE_TRIGGER 0x01000000 /* Cause the event to be
117117+ triggered for output. */
118118+119119+/*
120120+ * data/hint flags for EVFILT_{READ|WRITE}
121121+ */
122122+#define NOTE_LOWAT 0x0001 /* low water mark */
123123+#undef NOTE_LOWAT /* Not supported on Linux */
124124+125125+/*
126126+ * data/hint flags for EVFILT_VNODE
127127+ */
128128+#define NOTE_DELETE 0x0001 /* vnode was removed */
129129+#define NOTE_WRITE 0x0002 /* data contents changed */
130130+#define NOTE_EXTEND 0x0004 /* size increased */
131131+#define NOTE_ATTRIB 0x0008 /* attributes changed */
132132+#define NOTE_LINK 0x0010 /* link count changed */
133133+#define NOTE_RENAME 0x0020 /* vnode was renamed */
134134+#define NOTE_REVOKE 0x0040 /* vnode access was revoked */
135135+#undef NOTE_REVOKE /* Not supported on Linux */
136136+137137+/*
138138+ * data/hint flags for EVFILT_PROC
139139+ */
140140+#define NOTE_EXIT 0x80000000 /* process exited */
141141+#define NOTE_FORK 0x40000000 /* process forked */
142142+#define NOTE_EXEC 0x20000000 /* process exec'd */
143143+#define NOTE_PCTRLMASK 0xf0000000 /* mask for hint bits */
144144+#define NOTE_PDATAMASK 0x000fffff /* mask for pid */
145145+146146+/* additional flags for EVFILT_PROC */
147147+#define NOTE_TRACK 0x00000001 /* follow across forks */
148148+#define NOTE_TRACKERR 0x00000002 /* could not track child */
149149+#define NOTE_CHILD 0x00000004 /* am a child process */
150150+151151+/*
152152+ * data/hint flags for EVFILT_NETDEV
153153+ */
154154+#define NOTE_LINKUP 0x0001 /* link is up */
155155+#define NOTE_LINKDOWN 0x0002 /* link is down */
156156+#define NOTE_LINKINV 0x0004 /* link state is invalid */
157157+158158+/* KLUDGE: This is from <sys/mount.h> on FreeBSD and is used by
159159+ the EVFILT_FS filter. */
160160+/* vfsquery flags */
161161+#define VQ_NOTRESP 0x0001 /* server down */
162162+#define VQ_NEEDAUTH 0x0002 /* server bad auth */
163163+#define VQ_LOWDISK 0x0004 /* we're low on space */
164164+#define VQ_MOUNT 0x0008 /* new filesystem arrived */
165165+#define VQ_UNMOUNT 0x0010 /* filesystem has left */
166166+#define VQ_DEAD 0x0020 /* filesystem is dead, needs force unmount */
167167+#define VQ_ASSIST 0x0040 /* filesystem needs assistance from external
168168+ program */
169169+#define VQ_NOTRESPLOCK 0x0080 /* server lockd down */
170170+171171+172172+#ifndef __KERNEL__
173173+#ifdef __cplusplus
174174+extern "C" {
175175+#endif
176176+177177+#ifdef _WIN32
178178+179179+struct timespec {
180180+ time_t tv_sec;
181181+ long tv_nsec;
182182+};
183183+184184+__declspec(dllexport) int
185185+kqueue(void);
186186+187187+__declspec(dllexport) int
188188+kevent(int kq, const struct kevent *changelist, int nchanges,
189189+ struct kevent *eventlist, int nevents,
190190+ const struct timespec *timeout);
191191+192192+#ifdef MAKE_STATIC
193193+__declspec(dllexport) int
194194+libkqueue_init();
195195+#endif
196196+197197+#else
198198+int kqueue(void);
199199+int kevent(int kq, const struct kevent *changelist, int nchanges,
200200+ struct kevent *eventlist, int nevents,
201201+ const struct timespec *timeout);
202202+#ifdef MAKE_STATIC
203203+int libkqueue_init();
204204+#endif
205205+#endif
206206+207207+#ifdef __cplusplus
208208+}
209209+#endif
210210+#endif /* !__KERNEL__* */
211211+212212+#endif /* !_SYS_EVENT_H_ */
+515
external/libkqueue-2.0.1/kqueue.2
···11+.\" $FreeBSD: Revision: 197243$
22+.\" Copyright (c) 2010 Mark Heily
33+.\" Copyright (c) 2000 Jonathan Lemon
44+.\" All rights reserved.
55+.\"
66+.\" Redistribution and use in source and binary forms, with or without
77+.\" modification, are permitted provided that the following conditions
88+.\" are met:
99+.\" 1. Redistributions of source code must retain the above copyright
1010+.\" notice, this list of conditions and the following disclaimer.
1111+.\" 2. Redistributions in binary form must reproduce the above copyright
1212+.\" notice, this list of conditions and the following disclaimer in the
1313+.\" documentation and/or other materials provided with the distribution.
1414+.\"
1515+.\" THIS SOFTWARE IS PROVIDED ``AS IS'' AND
1616+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
1717+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
1818+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
1919+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2020+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2121+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2222+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2323+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
2424+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
2525+.\" SUCH DAMAGE.
2626+.\"
2727+.\" $FreeBSD$
2828+.\"
2929+.Dd September 17, 2010
3030+.Dt KQUEUE 2
3131+.Os
3232+.Sh NAME
3333+.Nm kqueue ,
3434+.Nm kevent
3535+.Nd kernel event notification mechanism
3636+.Sh SYNOPSIS
3737+.In sys/types.h
3838+.In sys/event.h
3939+.In sys/time.h
4040+.Ft int
4141+.Fn kqueue "void"
4242+.Ft int
4343+.Fn kevent "int kq" "const struct kevent *changelist" "int nchanges" "struct kevent *eventlist" "int nevents" "const struct timespec *timeout"
4444+.Fn EV_SET "&kev" ident filter flags fflags data udata
4545+.Sh DESCRIPTION
4646+The
4747+.Fn kqueue
4848+system call
4949+provides a generic method of notifying the user when an event
5050+happens or a condition holds, based on the results of small
5151+pieces of kernel code termed filters.
5252+A kevent is identified by the (ident, filter) pair; there may only
5353+be one unique kevent per kqueue.
5454+.Pp
5555+The filter is executed upon the initial registration of a kevent
5656+in order to detect whether a preexisting condition is present, and is also
5757+executed whenever an event is passed to the filter for evaluation.
5858+If the filter determines that the condition should be reported,
5959+then the kevent is placed on the kqueue for the user to retrieve.
6060+.Pp
6161+The filter is also run when the user attempts to retrieve the kevent
6262+from the kqueue.
6363+If the filter indicates that the condition that triggered
6464+the event no longer holds, the kevent is removed from the kqueue and
6565+is not returned.
6666+.Pp
6767+Multiple events which trigger the filter do not result in multiple
6868+kevents being placed on the kqueue; instead, the filter will aggregate
6969+the events into a single struct kevent.
7070+Calling
7171+.Fn close
7272+on a file descriptor will remove any kevents that reference the descriptor.
7373+.Pp
7474+The
7575+.Fn kqueue
7676+system call
7777+creates a new kernel event queue and returns a descriptor.
7878+The queue is not inherited by a child created with
7979+.Xr fork 2 .
8080+However, if
8181+.Xr rfork 2
8282+is called without the
8383+.Dv RFFDG
8484+flag, then the descriptor table is shared,
8585+which will allow sharing of the kqueue between two processes.
8686+.Pp
8787+The
8888+.Fn kevent
8989+system call
9090+is used to register events with the queue, and return any pending
9191+events to the user.
9292+The
9393+.Fa changelist
9494+argument
9595+is a pointer to an array of
9696+.Va kevent
9797+structures, as defined in
9898+.In sys/event.h .
9999+All changes contained in the
100100+.Fa changelist
101101+are applied before any pending events are read from the queue.
102102+The
103103+.Fa nchanges
104104+argument
105105+gives the size of
106106+.Fa changelist .
107107+The
108108+.Fa eventlist
109109+argument
110110+is a pointer to an array of kevent structures.
111111+The
112112+.Fa nevents
113113+argument
114114+determines the size of
115115+.Fa eventlist .
116116+When
117117+.Fa nevents
118118+is zero,
119119+.Fn kevent
120120+will return immediately even if there is a
121121+.Fa timeout
122122+specified unlike
123123+.Xr select 2 .
124124+If
125125+.Fa timeout
126126+is a non-NULL pointer, it specifies a maximum interval to wait
127127+for an event, which will be interpreted as a struct timespec.
128128+If
129129+.Fa timeout
130130+is a NULL pointer,
131131+.Fn kevent
132132+waits indefinitely.
133133+To effect a poll, the
134134+.Fa timeout
135135+argument should be non-NULL, pointing to a zero-valued
136136+.Va timespec
137137+structure.
138138+The same array may be used for the
139139+.Fa changelist
140140+and
141141+.Fa eventlist .
142142+.Pp
143143+The
144144+.Fn EV_SET
145145+macro is provided for ease of initializing a
146146+kevent structure.
147147+.Pp
148148+The
149149+.Va kevent
150150+structure is defined as:
151151+.Bd -literal
152152+struct kevent {
153153+ uintptr_t ident; /* identifier for this event */
154154+ short filter; /* filter for event */
155155+ u_short flags; /* action flags for kqueue */
156156+ u_int fflags; /* filter flag value */
157157+ intptr_t data; /* filter data value */
158158+ void *udata; /* opaque user data identifier */
159159+};
160160+.Ed
161161+.Pp
162162+The fields of
163163+.Fa struct kevent
164164+are:
165165+.Bl -tag -width XXXfilter
166166+.It ident
167167+Value used to identify this event.
168168+The exact interpretation is determined by the attached filter,
169169+but often is a file descriptor.
170170+.It filter
171171+Identifies the kernel filter used to process this event.
172172+The pre-defined
173173+system filters are described below.
174174+.It flags
175175+Actions to perform on the event.
176176+.It fflags
177177+Filter-specific flags.
178178+.It data
179179+Filter-specific data value.
180180+.It udata
181181+Opaque user-defined value passed through the kernel unchanged.
182182+.El
183183+.Pp
184184+The
185185+.Va flags
186186+field can contain the following values:
187187+.Bl -tag -width XXXEV_ONESHOT
188188+.It EV_ADD
189189+Adds the event to the kqueue.
190190+Re-adding an existing event
191191+will modify the parameters of the original event, and not result
192192+in a duplicate entry.
193193+Adding an event automatically enables it,
194194+unless overridden by the EV_DISABLE flag.
195195+.It EV_ENABLE
196196+Permit
197197+.Fn kevent
198198+to return the event if it is triggered.
199199+.It EV_DISABLE
200200+Disable the event so
201201+.Fn kevent
202202+will not return it.
203203+The filter itself is not disabled.
204204+.It EV_DISPATCH
205205+Disable the event source immediately after delivery of an event.
206206+See
207207+.Dv EV_DISABLE
208208+above.
209209+.It EV_DELETE
210210+Removes the event from the kqueue.
211211+Events which are attached to
212212+file descriptors are automatically deleted on the last close of
213213+the descriptor.
214214+.It EV_RECEIPT
215215+This flag is useful for making bulk changes to a kqueue without draining
216216+any pending events.
217217+When passed as input, it forces
218218+.Dv EV_ERROR
219219+to always be returned.
220220+When a filter is successfully added the
221221+.Va data
222222+field will be zero.
223223+.It EV_ONESHOT
224224+Causes the event to return only the first occurrence of the filter
225225+being triggered.
226226+After the user retrieves the event from the kqueue,
227227+it is deleted.
228228+.It EV_CLEAR
229229+After the event is retrieved by the user, its state is reset.
230230+This is useful for filters which report state transitions
231231+instead of the current state.
232232+Note that some filters may automatically
233233+set this flag internally.
234234+.It EV_EOF
235235+Filters may set this flag to indicate filter-specific EOF condition.
236236+.It EV_ERROR
237237+See
238238+.Sx RETURN VALUES
239239+below.
240240+.El
241241+.Pp
242242+The predefined system filters are listed below.
243243+Arguments may be passed to and from the filter via the
244244+.Va fflags
245245+and
246246+.Va data
247247+fields in the kevent structure.
248248+.Bl -tag -width EVFILT_SIGNAL
249249+.It EVFILT_READ
250250+Takes a descriptor as the identifier, and returns whenever
251251+there is data available to read.
252252+The behavior of the filter is slightly different depending
253253+on the descriptor type.
254254+.Pp
255255+.Bl -tag -width 2n
256256+.It Sockets
257257+Sockets which have previously been passed to
258258+.Fn listen
259259+return when there is an incoming connection pending.
260260+.Va data
261261+contains the size of the listen backlog.
262262+.Pp
263263+Other socket descriptors return when there is data to be read,
264264+subject to the
265265+.Dv SO_RCVLOWAT
266266+value of the socket buffer.
267267+This may be overridden with a per-filter low water mark at the
268268+time the filter is added by setting the
269269+NOTE_LOWAT
270270+flag in
271271+.Va fflags ,
272272+and specifying the new low water mark in
273273+.Va data .
274274+On return,
275275+.Va data
276276+contains the number of bytes of protocol data available to read.
277277+.Pp
278278+If the read direction of the socket has shutdown, then the filter
279279+also sets EV_EOF in
280280+.Va flags ,
281281+and returns the socket error (if any) in
282282+.Va fflags .
283283+It is possible for EOF to be returned (indicating the connection is gone)
284284+while there is still data pending in the socket buffer.
285285+.It Vnodes
286286+Returns when the file pointer is not at the end of file.
287287+.Va data
288288+contains the offset from current position to end of file,
289289+and may be negative.
290290+.It "Fifos, Pipes"
291291+Returns when the there is data to read;
292292+.Va data
293293+contains the number of bytes available.
294294+.Pp
295295+When the last writer disconnects, the filter will set EV_EOF in
296296+.Va flags .
297297+This may be cleared by passing in EV_CLEAR, at which point the
298298+filter will resume waiting for data to become available before
299299+returning.
300300+.It "BPF devices"
301301+Returns when the BPF buffer is full, the BPF timeout has expired, or
302302+when the BPF has
303303+.Dq immediate mode
304304+enabled and there is any data to read;
305305+.Va data
306306+contains the number of bytes available.
307307+.El
308308+.It EVFILT_WRITE
309309+Takes a descriptor as the identifier, and returns whenever
310310+it is possible to write to the descriptor.
311311+For sockets, pipes
312312+and fifos,
313313+.Va data
314314+will contain the amount of space remaining in the write buffer.
315315+The filter will set EV_EOF when the reader disconnects, and for
316316+the fifo case, this may be cleared by use of EV_CLEAR.
317317+Note that this filter is not supported for vnodes or BPF devices.
318318+.Pp
319319+For sockets, the low water mark and socket error handling is
320320+identical to the EVFILT_READ case.
321321+.It EVFILT_VNODE
322322+Takes a file descriptor as the identifier and the events to watch for in
323323+.Va fflags ,
324324+and returns when one or more of the requested events occurs on the descriptor.
325325+The events to monitor are:
326326+.Bl -tag -width XXNOTE_RENAME
327327+.It NOTE_DELETE
328328+The
329329+.Fn unlink
330330+system call
331331+was called on the file referenced by the descriptor.
332332+.It NOTE_WRITE
333333+A write occurred on the file referenced by the descriptor.
334334+.It NOTE_EXTEND
335335+The file referenced by the descriptor was extended.
336336+.It NOTE_ATTRIB
337337+The file referenced by the descriptor had its attributes changed.
338338+.It NOTE_LINK
339339+The link count on the file changed.
340340+.It NOTE_RENAME
341341+The file referenced by the descriptor was renamed.
342342+.El
343343+.Pp
344344+On return,
345345+.Va fflags
346346+contains the events which triggered the filter.
347347+.It EVFILT_SIGNAL
348348+Takes the signal number to monitor as the identifier and returns
349349+when the given signal is delivered to the process.
350350+This overrides the
351351+.Fn signal
352352+and
353353+.Fn sigaction
354354+facilities, and has a higher precedence.
355355+The filter will record
356356+all attempts to deliver a signal to a process, even if the signal has
357357+been marked as SIG_IGN.
358358+.Va data
359359+returns the number of times the signal has occurred since the last call to
360360+.Fn kevent .
361361+This filter automatically sets the EV_CLEAR flag internally.
362362+.It EVFILT_TIMER
363363+Establishes an arbitrary timer identified by
364364+.Va ident .
365365+When adding a timer,
366366+.Va data
367367+specifies the timeout period in milliseconds.
368368+The timer will be periodic unless EV_ONESHOT is specified.
369369+On return,
370370+.Va data
371371+contains the number of times the timeout has expired since the last call to
372372+.Fn kevent .
373373+This filter automatically sets the EV_CLEAR flag internally.
374374+There is a system wide limit on the number of timers
375375+which is controlled by the
376376+.Va kern.kq_calloutmax
377377+sysctl.
378378+.It Dv EVFILT_USER
379379+Establishes a user event identified by
380380+.Va ident
381381+which is not assosicated with any kernel mechanism but is triggered by
382382+user level code.
383383+The lower 24 bits of the
384384+.Va fflags
385385+may be used for user defined flags and manipulated using the following:
386386+.Bl -tag -width XXNOTE_FFLAGSMASK
387387+.It Dv NOTE_FFNOP
388388+Ignore the input
389389+.Va fflags .
390390+.It Dv NOTE_FFAND
391391+Bitwise AND
392392+.Va fflags .
393393+.It Dv NOTE_FFOR
394394+Bitwise OR
395395+.Va fflags .
396396+.It Dv NOTE_COPY
397397+Copy
398398+.Va fflags .
399399+.It Dv NOTE_FFCTRLMASK
400400+Control mask for
401401+.Va fflags .
402402+.It Dv NOTE_FFLAGSMASK
403403+User defined flag mask for
404404+.Va fflags .
405405+.El
406406+.Pp
407407+A user event is triggered for output with the following:
408408+.Bl -tag -width XXNOTE_FFLAGSMASK
409409+.It Dv NOTE_TRIGGER
410410+Cause the event to be triggered.
411411+.El
412412+.Pp
413413+On return,
414414+.Va fflags
415415+contains the users defined flags in the lower 24 bits.
416416+.El
417417+.Sh RETURN VALUES
418418+The
419419+.Fn kqueue
420420+system call
421421+creates a new kernel event queue and returns a file descriptor.
422422+If there was an error creating the kernel event queue, a value of -1 is
423423+returned and errno set.
424424+.Pp
425425+The
426426+.Fn kevent
427427+system call
428428+returns the number of events placed in the
429429+.Fa eventlist ,
430430+up to the value given by
431431+.Fa nevents .
432432+If an error occurs while processing an element of the
433433+.Fa changelist
434434+and there is enough room in the
435435+.Fa eventlist ,
436436+then the event will be placed in the
437437+.Fa eventlist
438438+with
439439+.Dv EV_ERROR
440440+set in
441441+.Va flags
442442+and the system error in
443443+.Va data .
444444+Otherwise,
445445+.Dv -1
446446+will be returned, and
447447+.Dv errno
448448+will be set to indicate the error condition.
449449+If the time limit expires, then
450450+.Fn kevent
451451+returns 0.
452452+.Sh ERRORS
453453+The
454454+.Fn kqueue
455455+system call fails if:
456456+.Bl -tag -width Er
457457+.It Bq Er ENOMEM
458458+The kernel failed to allocate enough memory for the kernel queue.
459459+.It Bq Er EMFILE
460460+The per-process descriptor table is full.
461461+.It Bq Er ENFILE
462462+The system file table is full.
463463+.El
464464+.Pp
465465+The
466466+.Fn kevent
467467+system call fails if:
468468+.Bl -tag -width Er
469469+.It Bq Er EACCES
470470+The process does not have permission to register a filter.
471471+.It Bq Er EFAULT
472472+There was an error reading or writing the
473473+.Va kevent
474474+structure.
475475+.It Bq Er EBADF
476476+The specified descriptor is invalid.
477477+.It Bq Er EINTR
478478+A signal was delivered before the timeout expired and before any
479479+events were placed on the kqueue for return.
480480+.It Bq Er EINVAL
481481+The specified time limit or filter is invalid.
482482+.It Bq Er ENOENT
483483+The event could not be found to be modified or deleted.
484484+.It Bq Er ENOMEM
485485+No memory was available to register the event
486486+or, in the special case of a timer, the maximum number of
487487+timers has been exceeded.
488488+This maximum is configurable via the
489489+.Va kern.kq_calloutmax
490490+sysctl.
491491+.It Bq Er ESRCH
492492+The specified process to attach to does not exist.
493493+.El
494494+.Sh SEE ALSO
495495+.Xr aio_error 2 ,
496496+.Xr aio_read 2 ,
497497+.Xr aio_return 2 ,
498498+.Xr poll 2 ,
499499+.Xr read 2 ,
500500+.Xr select 2 ,
501501+.Xr sigaction 2 ,
502502+.Xr write 2 ,
503503+.Xr signal 3
504504+.Sh HISTORY
505505+The
506506+.Fn kqueue
507507+and
508508+.Fn kevent
509509+system calls first appeared in
510510+.Fx 4.1 .
511511+.Sh AUTHORS
512512+The
513513+.Fn kqueue
514514+system and this manual page were written by
515515+.An Jonathan Lemon Aq jlemon@FreeBSD.org .
···11+22+Name: libkqueue
33+Description: Emulates FreeBSD kqueue(2) on other platforms
44+Version: 0.1
55+Requires:
66+Libs: -lkqueue
77+Libs.private: -lpthread
88+Cflags: -I${includedir}/kqueue
+89
external/libkqueue-2.0.1/libkqueue.spec
···11+Name: libkqueue
22+Summary: Userspace implementation of the kqueue event notification mechanism
33+Version: 2.0.1
44+Release: 1
55+# The entire source code is MIT, event.h which is BSD (2-clause)
66+License: MIT and BSD
77+Group: System Environment/Libraries
88+URL: http://sourceforge.net/p/libkqueue/wiki/Home/
99+Source0: http://downloads.sourceforge.net/%{name}/%{name}-%{version}.tar.gz
1010+Provides: libkqueue.so.0
1111+1212+%description
1313+A user space implementation of the kqueue(2) kernel event notification
1414+mechanism. libkqueue acts as a translator between the kevent structure and the
1515+native kernel facilities.
1616+1717+%package devel
1818+Group: Development/Libraries
1919+Summary: Development files for %{name}-%{version}
2020+Requires: %{name}%{?_isa} = %{version}-%{release}
2121+2222+%description devel
2323+%{summary}
2424+2525+%prep
2626+%setup -q
2727+2828+# %%{configure} sets --target 'x86_64-redhat-linux-gnu' instead of 'linux'
2929+%build
3030+CFLAGS="%{optflags} -fpic" %{_configure} --prefix=%{_prefix} --libdir=%{_libdir}
3131+make
3232+3333+%install
3434+%{make_install}
3535+3636+%check
3737+make check
3838+3939+%post -p /sbin/ldconfig
4040+4141+%postun -p /sbin/ldconfig
4242+4343+%files
4444+%doc LICENSE
4545+%{_libdir}/libkqueue.so.*
4646+4747+%files devel
4848+%dir %{_includedir}/kqueue
4949+%dir %{_includedir}/kqueue/sys
5050+%{_libdir}/libkqueue.so
5151+%{_includedir}/kqueue/sys/event.h
5252+%{_libdir}/pkgconfig/libkqueue.pc
5353+%{_mandir}/man2/kqueue.2.*
5454+%{_mandir}/man2/kevent.2.*
5555+5656+%changelog
5757+* Wed May 08 2013 Mark Heily <mark@heily.com> - 2.0.1-1
5858+- New upstream release
5959+6060+* Wed May 01 2013 Eric Radman <ericshane@eradman.com> - 2.0-1
6161+- Adapt to libkqueue 2.0
6262+6363+* Thu Apr 04 2013 Eric Radman <ericshane@eradman.com> - 1.0.1-6
6464+- Set CFLAGS using optflags since we're using a custom configure
6565+- Shorten summary
6666+6767+* Wed Apr 03 2013 Eric Radman <ericshane@eradman.com> - 1.0.1-5
6868+- Use %% to avoid warning about special character in comment
6969+- Remove defattr
7070+7171+* Fri Jan 18 2013 Eric Radman <ericshane@eradman.com> - 1.0.1-4
7272+- Configure respects CFLAGS and LDFLAGS. Also pass --libdir to the configure script
7373+7474+* Sat Jan 12 2013 Eric Radman <ericshane@eradman.com> - 1.0.1-3
7575+- Add license text for event.h
7676+- Use the dir macro for the include directories
7777+- Remove static package, exclude .a file, and make sure new directories are owned by the RPM
7878+7979+* Thu Jan 03 2013 Eric Radman <ericshane@eradman.com> - 1.0.1-3
8080+- Configure respects CFLAGS and LDFLAGS. Also pass --libdir= to the configure script instead of setting LIB
8181+8282+* Mon Dec 31 2012 Eric Radman <ericshane@eradman.com> - 1.0.1-2
8383+- Do not set the buildroot (F-10 does not require it)
8484+- Do not manually clean (F-13)
8585+8686+* Thu Dec 27 2012 Eric Radman <ericshane@eradman.com> - 1.0.1-1
8787+- Initial build with separate -devel package. Based on work done by Mark Heily,
8888+ Aditya Patawari and John Haxby
8989+
+84
external/libkqueue-2.0.1/src/common/alloc.h
···11+/*
22+ * Copyright (c) 2011 Mark Heily <mark@heily.com>
33+ *
44+ * Permission to use, copy, modify, and distribute this software for any
55+ * purpose with or without fee is hereby granted, provided that the above
66+ * copyright notice and this permission notice appear in all copies.
77+ *
88+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
99+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
1010+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
1111+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
1212+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
1313+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
1414+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
1515+ */
1616+1717+1818+/*
1919+ * A simple fixed-size memory allocator.
2020+ *
2121+ * Each translation unit in a program can include this header and
2222+ * have access to it's own private memory allocator. This can be useful
2323+ * for improving the performance of programs which frequently allocate
2424+ * and deallocate objects with a fixed size.
2525+ *
2626+ * The allocator must be initialized by calling mem_init(). This
2727+ * function takes two arguments: the object size, and the maximum
2828+ * number of objects in the cache.
2929+ *
3030+ * The functions mem_alloc() and mem_free() have similar semantics
3131+ * to the traditional malloc() and free() calls. The main difference
3232+ * is that mem_alloc() does not allow you to specify a specific size.
3333+ *
3434+ */
3535+3636+#include <stdlib.h>
3737+3838+#ifndef _WIN32
3939+# include <unistd.h>
4040+#endif
4141+4242+static __thread struct {
4343+ void **ac_cache; /* An array of reusable memory objects */
4444+ size_t ac_count; /* The number of objects in the cache */
4545+ size_t ac_max; /* The maximum number of cached objects */
4646+ size_t ac_size; /* The size, in bytes, of each object */
4747+} _ma;
4848+4949+static inline int
5050+mem_init(size_t objsize, size_t cachesize)
5151+{
5252+ _ma.ac_size = objsize;
5353+ _ma.ac_cache = malloc(cachesize * sizeof(void *));
5454+ return (_ma.ac_cache == NULL ? -1 : 0);
5555+}
5656+5757+static inline void *
5858+mem_alloc(void)
5959+{
6060+ if (_ma.ac_count > 0)
6161+ return (_ma.ac_cache[_ma.ac_count--]);
6262+ else
6363+ return (malloc(_ma.ac_size));
6464+}
6565+6666+static inline void *
6767+mem_calloc(void)
6868+{
6969+ void *p;
7070+7171+ p = mem_alloc();
7272+ if (p != NULL)
7373+ memset(p, 0, _ma.ac_size);
7474+ return (p);
7575+}
7676+7777+static inline void
7878+mem_free(void *ptr)
7979+{
8080+ if (_ma.ac_count < _ma.ac_max)
8181+ _ma.ac_cache[_ma.ac_count++] = ptr;
8282+ else
8383+ free(ptr);
8484+}
+147
external/libkqueue-2.0.1/src/common/debug.h
···11+/*
22+ * Copyright (c) 2011 Mark Heily <mark@heily.com>
33+ *
44+ * Permission to use, copy, modify, and distribute this software for any
55+ * purpose with or without fee is hereby granted, provided that the above
66+ * copyright notice and this permission notice appear in all copies.
77+ *
88+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
99+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
1010+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
1111+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
1212+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
1313+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
1414+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
1515+ */
1616+1717+#ifndef _DEBUG_H
1818+#define _DEBUG_H
1919+2020+#include <assert.h>
2121+#include <stdio.h>
2222+#ifdef _WIN32
2323+# include <windows.h>
2424+#else
2525+# include <unistd.h>
2626+#endif
2727+2828+extern int DEBUG_KQUEUE;
2929+extern char *KQUEUE_DEBUG_IDENT;
3030+3131+#if defined(__linux__)
3232+# include <sys/syscall.h>
3333+# define THREAD_ID ((pid_t) syscall(__NR_gettid))
3434+#elif defined(__sun)
3535+# define THREAD_ID ((int) pthread_self())
3636+#elif defined(_WIN32)
3737+# define THREAD_ID (int)(GetCurrentThreadId())
3838+#else
3939+# error Unsupported platform
4040+#endif
4141+4242+#ifndef NDEBUG
4343+#define dbg_puts(str) do { \
4444+ if (DEBUG_KQUEUE) \
4545+ fprintf(stderr, "%s [%d]: %s(): %s\n", \
4646+ KQUEUE_DEBUG_IDENT, THREAD_ID, __func__, str); \
4747+} while (0)
4848+4949+#define dbg_printf(fmt,...) do { \
5050+ if (DEBUG_KQUEUE) \
5151+ fprintf(stderr, "%s [%d]: %s(): "fmt"\n", \
5252+ KQUEUE_DEBUG_IDENT, THREAD_ID, __func__, __VA_ARGS__); \
5353+} while (0)
5454+5555+#define dbg_perror(str) do { \
5656+ if (DEBUG_KQUEUE) \
5757+ fprintf(stderr, "%s [%d]: %s(): %s: %s (errno=%d)\n", \
5858+ KQUEUE_DEBUG_IDENT, THREAD_ID, __func__, str, \
5959+ strerror(errno), errno); \
6060+} while (0)
6161+6262+# define reset_errno() do { errno = 0; } while (0)
6363+6464+# if defined(_WIN32)
6565+# define dbg_lasterror(str) do { \
6666+ if (DEBUG_KQUEUE) \
6767+ fprintf(stderr, "%s: [%d] %s(): %s: (LastError=%d)\n", \
6868+ KQUEUE_DEBUG_IDENT, THREAD_ID, __func__, str, (int)GetLastError()); \
6969+} while (0)
7070+7171+# define dbg_wsalasterror(str) do { \
7272+ if (DEBUG_KQUEUE) \
7373+ fprintf(stderr, "%s: [%d] %s(): %s: (WSALastError=%d)\n", \
7474+ KQUEUE_DEBUG_IDENT, THREAD_ID, __func__, str, (int)WSAGetLastError()); \
7575+} while (0)
7676+7777+# else
7878+# define dbg_lasterror(str) ;
7979+# define dbg_wsalasterror(str) ;
8080+# endif
8181+8282+/*
8383+ * Tracing mutexes are a thin wrapper around the pthread_mutex_t
8484+ * datatype that tracks and reports when a mutex is locked or unlocked.
8585+ * It also allows you to assert that a mutex has (or has not) been locked
8686+ * by calling tracing_mutex_assert().
8787+ */
8888+8989+# define MTX_UNLOCKED 0
9090+# define MTX_LOCKED 1
9191+9292+typedef struct {
9393+ pthread_mutex_t mtx_lock;
9494+ int mtx_status;
9595+ int mtx_owner;
9696+} tracing_mutex_t;
9797+9898+# define tracing_mutex_init(mtx, attr) do { \
9999+ pthread_mutex_init(&(mtx)->mtx_lock, (attr)); \
100100+ (mtx)->mtx_status = MTX_UNLOCKED; \
101101+ (mtx)->mtx_owner = -1; \
102102+} while (0)
103103+104104+# define tracing_mutex_destroy(mtx) pthread_mutex_destroy(&(mtx)->mtx_lock)
105105+106106+# define tracing_mutex_assert(x,y) do { \
107107+ if ((y) == MTX_UNLOCKED) \
108108+ assert((x)->mtx_status == MTX_UNLOCKED || (x)->mtx_owner != THREAD_ID); \
109109+ else if ((y) == MTX_LOCKED) \
110110+ assert((x)->mtx_status == MTX_LOCKED && (x)->mtx_owner == THREAD_ID); \
111111+ else \
112112+ abort(); \
113113+} while (0)
114114+115115+# define tracing_mutex_lock(x) do { \
116116+ dbg_printf("waiting for %s", #x); \
117117+ pthread_mutex_lock(&((x)->mtx_lock)); \
118118+ dbg_printf("locked %s", #x); \
119119+ (x)->mtx_owner = THREAD_ID; \
120120+ (x)->mtx_status = MTX_LOCKED; \
121121+} while (0)
122122+123123+# define tracing_mutex_unlock(x) do { \
124124+ (x)->mtx_status = MTX_UNLOCKED; \
125125+ (x)->mtx_owner = -1; \
126126+ pthread_mutex_unlock(&((x)->mtx_lock)); \
127127+ dbg_printf("unlocked %s", # x); \
128128+} while (0)
129129+130130+#else /* NDEBUG */
131131+# define dbg_puts(str) do {} while (0)
132132+# define dbg_printf(fmt,...) do {} while (0)
133133+# define dbg_perror(str) do {} while (0)
134134+# define dbg_lasterror(str) do {} while (0)
135135+# define dbg_wsalasterror(str) do {} while (0)
136136+# define reset_errno() do {} while (0)
137137+# define MTX_UNLOCKED
138138+# define MTX_LOCKED
139139+# define tracing_mutex_t pthread_mutex_t
140140+# define tracing_mutex_init pthread_mutex_init
141141+# define tracing_mutex_destroy pthread_mutex_destroy
142142+# define tracing_mutex_assert(x,y) do {} while (0)
143143+# define tracing_mutex_lock pthread_mutex_lock
144144+# define tracing_mutex_unlock pthread_mutex_unlock
145145+#endif
146146+147147+#endif /* ! _DEBUG_H */
+179
external/libkqueue-2.0.1/src/common/filter.c
···11+/*
22+ * Copyright (c) 2009 Mark Heily <mark@heily.com>
33+ *
44+ * Permission to use, copy, modify, and distribute this software for any
55+ * purpose with or without fee is hereby granted, provided that the above
66+ * copyright notice and this permission notice appear in all copies.
77+ *
88+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
99+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
1010+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
1111+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
1212+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
1313+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
1414+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
1515+ */
1616+1717+#include <assert.h>
1818+#include <errno.h>
1919+#include <fcntl.h>
2020+#include <stdlib.h>
2121+#include <stdio.h>
2222+#include <string.h>
2323+2424+#include "private.h"
2525+2626+extern const struct filter evfilt_read;
2727+extern const struct filter evfilt_write;
2828+extern const struct filter evfilt_signal;
2929+extern const struct filter evfilt_vnode;
3030+extern const struct filter evfilt_proc;
3131+extern const struct filter evfilt_timer;
3232+extern const struct filter evfilt_user;
3333+3434+static int
3535+filter_register(struct kqueue *kq, short filter, const struct filter *src)
3636+{
3737+ struct filter *dst;
3838+ unsigned int filt;
3939+ int rv = 0;
4040+4141+ filt = (-1 * filter) - 1;
4242+ if (filt >= EVFILT_SYSCOUNT)
4343+ return (-1);
4444+4545+ dst = &kq->kq_filt[filt];
4646+ memcpy(dst, src, sizeof(*src));
4747+ dst->kf_kqueue = kq;
4848+ RB_INIT(&dst->kf_knote);
4949+ pthread_rwlock_init(&dst->kf_knote_mtx, NULL);
5050+ if (src->kf_id == 0) {
5151+ dbg_puts("filter is not implemented");
5252+ return (0);
5353+ }
5454+5555+ assert(src->kf_copyout);
5656+ assert(src->kn_create);
5757+ assert(src->kn_modify);
5858+ assert(src->kn_delete);
5959+ assert(src->kn_enable);
6060+ assert(src->kn_disable);
6161+6262+ /* Perform (optional) per-filter initialization */
6363+ if (src->kf_init != NULL) {
6464+ rv = src->kf_init(dst);
6565+ if (rv < 0) {
6666+ dbg_puts("filter failed to initialize");
6767+ dst->kf_id = 0;
6868+ return (-1);
6969+ }
7070+ }
7171+7272+#if DEADWOOD
7373+ /* Add the filter's event descriptor to the main fdset */
7474+ if (dst->kf_pfd > 0) {
7575+ FD_SET(dst->kf_pfd, &kq->kq_fds);
7676+ if (dst->kf_pfd > kq->kq_nfds)
7777+ kq->kq_nfds = dst->kf_pfd;
7878+ dbg_printf("fds: added %d (nfds=%d)", dst->kf_pfd, kq->kq_nfds);
7979+ }
8080+ dbg_printf("filter %d (%s) registered", filter, filter_name(filter));
8181+#endif
8282+8383+ /* FIXME: should totally remove const from src */
8484+ if (kqops.filter_init != NULL
8585+ && kqops.filter_init(kq, dst) < 0)
8686+ return (-1);
8787+8888+ return (0);
8989+}
9090+9191+int
9292+filter_register_all(struct kqueue *kq)
9393+{
9494+ int rv;
9595+9696+ FD_ZERO(&kq->kq_fds);
9797+ rv = 0;
9898+ rv += filter_register(kq, EVFILT_READ, &evfilt_read);
9999+ rv += filter_register(kq, EVFILT_WRITE, &evfilt_write);
100100+ rv += filter_register(kq, EVFILT_SIGNAL, &evfilt_signal);
101101+ rv += filter_register(kq, EVFILT_VNODE, &evfilt_vnode);
102102+ rv += filter_register(kq, EVFILT_PROC, &evfilt_proc);
103103+ rv += filter_register(kq, EVFILT_TIMER, &evfilt_timer);
104104+ rv += filter_register(kq, EVFILT_USER, &evfilt_user);
105105+ kq->kq_nfds++;
106106+ if (rv != 0) {
107107+ filter_unregister_all(kq);
108108+ return (-1);
109109+ } else {
110110+ dbg_puts("complete");
111111+ return (0);
112112+ }
113113+}
114114+115115+void
116116+filter_unregister_all(struct kqueue *kq)
117117+{
118118+ int i;
119119+120120+ for (i = 0; i < EVFILT_SYSCOUNT; i++) {
121121+ if (kq->kq_filt[i].kf_id == 0)
122122+ continue;
123123+124124+ if (kq->kq_filt[i].kf_destroy != NULL)
125125+ kq->kq_filt[i].kf_destroy(&kq->kq_filt[i]);
126126+127127+ //XXX-FIXME
128128+ //knote_free_all(&kq->kq_filt[i]);
129129+130130+ if (kqops.filter_free != NULL)
131131+ kqops.filter_free(kq, &kq->kq_filt[i]);
132132+ }
133133+ memset(&kq->kq_filt[0], 0, sizeof(kq->kq_filt));
134134+}
135135+136136+int
137137+filter_lookup(struct filter **filt, struct kqueue *kq, short id)
138138+{
139139+ if (~id < 0 || ~id >= EVFILT_SYSCOUNT) {
140140+ dbg_printf("invalid id: id %d ~id %d", id, (~id));
141141+ errno = EINVAL;
142142+ *filt = NULL;
143143+ return (-1);
144144+ }
145145+ *filt = &kq->kq_filt[~id];
146146+ if ((*filt)->kf_copyout == NULL) {
147147+ dbg_printf("filter %s is not implemented", filter_name(id));
148148+ errno = ENOSYS;
149149+ *filt = NULL;
150150+ return (-1);
151151+ }
152152+153153+ return (0);
154154+}
155155+156156+const char *
157157+filter_name(short filt)
158158+{
159159+ int id;
160160+ const char *fname[EVFILT_SYSCOUNT] = {
161161+ "EVFILT_READ",
162162+ "EVFILT_WRITE",
163163+ "EVFILT_AIO",
164164+ "EVFILT_VNODE",
165165+ "EVFILT_PROC",
166166+ "EVFILT_SIGNAL",
167167+ "EVFILT_TIMER",
168168+ "EVFILT_NETDEV",
169169+ "EVFILT_FS",
170170+ "EVFILT_LIO",
171171+ "EVFILT_USER"
172172+ };
173173+174174+ id = ~filt;
175175+ if (id < 0 || id >= EVFILT_SYSCOUNT)
176176+ return "EVFILT_INVALID";
177177+ else
178178+ return fname[id];
179179+}
+312
external/libkqueue-2.0.1/src/common/kevent.c
···11+/*
22+ * Copyright (c) 2009 Mark Heily <mark@heily.com>
33+ *
44+ * Permission to use, copy, modify, and distribute this software for any
55+ * purpose with or without fee is hereby granted, provided that the above
66+ * copyright notice and this permission notice appear in all copies.
77+ *
88+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
99+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
1010+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
1111+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
1212+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
1313+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
1414+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
1515+ */
1616+1717+/* To get asprintf(3) */
1818+#define _GNU_SOURCE
1919+2020+#include <assert.h>
2121+#include <errno.h>
2222+#include <fcntl.h>
2323+#include <signal.h>
2424+#include <stdlib.h>
2525+#include <stdio.h>
2626+#include <sys/types.h>
2727+#include <string.h>
2828+2929+#include "private.h"
3030+3131+static const char *
3232+kevent_filter_dump(const struct kevent *kev)
3333+{
3434+ static __thread char buf[64];
3535+3636+ snprintf(&buf[0], sizeof(buf), "%d (%s)",
3737+ kev->filter, filter_name(kev->filter));
3838+ return ((const char *) &buf[0]);
3939+}
4040+4141+static const char *
4242+kevent_fflags_dump(const struct kevent *kev)
4343+{
4444+ static __thread char buf[1024];
4545+4646+#define KEVFFL_DUMP(attrib) \
4747+ if (kev->fflags & attrib) \
4848+ strncat((char *) &buf[0], #attrib" ", 64);
4949+5050+ snprintf(buf, sizeof(buf), "fflags=0x%04x (", kev->fflags);
5151+ if (kev->filter == EVFILT_VNODE) {
5252+ KEVFFL_DUMP(NOTE_DELETE);
5353+ KEVFFL_DUMP(NOTE_WRITE);
5454+ KEVFFL_DUMP(NOTE_EXTEND);
5555+ KEVFFL_DUMP(NOTE_ATTRIB);
5656+ KEVFFL_DUMP(NOTE_LINK);
5757+ KEVFFL_DUMP(NOTE_RENAME);
5858+ } else if (kev->filter == EVFILT_USER) {
5959+ KEVFFL_DUMP(NOTE_FFNOP);
6060+ KEVFFL_DUMP(NOTE_FFAND);
6161+ KEVFFL_DUMP(NOTE_FFOR);
6262+ KEVFFL_DUMP(NOTE_FFCOPY);
6363+ KEVFFL_DUMP(NOTE_TRIGGER);
6464+ } else {
6565+ strncat((char *) &buf[0], " ", 1);
6666+ }
6767+ buf[strlen(buf) - 1] = ')';
6868+6969+#undef KEVFFL_DUMP
7070+7171+ return ((const char *) &buf[0]);
7272+}
7373+7474+static const char *
7575+kevent_flags_dump(const struct kevent *kev)
7676+{
7777+ static __thread char buf[1024];
7878+7979+#define KEVFL_DUMP(attrib) \
8080+ if (kev->flags & attrib) \
8181+ strncat((char *) &buf[0], #attrib" ", 64);
8282+8383+ snprintf(buf, sizeof(buf), "flags=0x%04x (", kev->flags);
8484+ KEVFL_DUMP(EV_ADD);
8585+ KEVFL_DUMP(EV_ENABLE);
8686+ KEVFL_DUMP(EV_DISABLE);
8787+ KEVFL_DUMP(EV_DELETE);
8888+ KEVFL_DUMP(EV_ONESHOT);
8989+ KEVFL_DUMP(EV_CLEAR);
9090+ KEVFL_DUMP(EV_EOF);
9191+ KEVFL_DUMP(EV_ERROR);
9292+ KEVFL_DUMP(EV_DISPATCH);
9393+ KEVFL_DUMP(EV_RECEIPT);
9494+ buf[strlen(buf) - 1] = ')';
9595+9696+#undef KEVFL_DUMP
9797+9898+ return ((const char *) &buf[0]);
9999+}
100100+101101+const char *
102102+kevent_dump(const struct kevent *kev)
103103+{
104104+ static __thread char buf[1024];
105105+106106+ snprintf((char *) &buf[0], sizeof(buf),
107107+ "{ ident=%d, filter=%s, %s, %s, data=%d, udata=%p }",
108108+ (u_int) kev->ident,
109109+ kevent_filter_dump(kev),
110110+ kevent_flags_dump(kev),
111111+ kevent_fflags_dump(kev),
112112+ (int) kev->data,
113113+ kev->udata);
114114+115115+ return ((const char *) &buf[0]);
116116+}
117117+118118+static int
119119+kevent_copyin_one(struct kqueue *kq, const struct kevent *src)
120120+{
121121+ struct knote *kn = NULL;
122122+ struct filter *filt;
123123+ int rv = 0;
124124+125125+ if (src->flags & EV_DISPATCH && src->flags & EV_ONESHOT) {
126126+ dbg_puts("Error: EV_DISPATCH and EV_ONESHOT are mutually exclusive");
127127+ errno = EINVAL;
128128+ return (-1);
129129+ }
130130+131131+ if (filter_lookup(&filt, kq, src->filter) < 0)
132132+ return (-1);
133133+134134+ dbg_printf("src=%s", kevent_dump(src));
135135+136136+ kn = knote_lookup(filt, src->ident);
137137+ dbg_printf("knote_lookup: ident %d == %p", (int)src->ident, kn);
138138+ if (kn == NULL) {
139139+ if (src->flags & EV_ADD) {
140140+ if ((kn = knote_new()) == NULL) {
141141+ errno = ENOENT;
142142+ return (-1);
143143+ }
144144+ memcpy(&kn->kev, src, sizeof(kn->kev));
145145+ kn->kev.flags &= ~EV_ENABLE;
146146+ kn->kev.flags |= EV_ADD;//FIXME why?
147147+ kn->kn_kq = kq;
148148+ assert(filt->kn_create);
149149+ if (filt->kn_create(filt, kn) < 0) {
150150+ knote_release(kn);
151151+ errno = EFAULT;
152152+ return (-1);
153153+ }
154154+ knote_insert(filt, kn);
155155+ dbg_printf("created kevent %s", kevent_dump(src));
156156+157157+/* XXX- FIXME Needs to be handled in kn_create() to prevent races */
158158+ if (src->flags & EV_DISABLE) {
159159+ kn->kev.flags |= EV_DISABLE;
160160+ return (filt->kn_disable(filt, kn));
161161+ }
162162+ //........................................
163163+164164+ return (0);
165165+ } else {
166166+ dbg_printf("no entry found for ident=%u", (unsigned int)src->ident);
167167+ errno = ENOENT;
168168+ return (-1);
169169+ }
170170+ }
171171+172172+ if (src->flags & EV_DELETE) {
173173+ rv = knote_delete(filt, kn);
174174+ dbg_printf("knote_delete returned %d", rv);
175175+ } else if (src->flags & EV_DISABLE) {
176176+ kn->kev.flags |= EV_DISABLE;
177177+ rv = filt->kn_disable(filt, kn);
178178+ dbg_printf("kn_disable returned %d", rv);
179179+ } else if (src->flags & EV_ENABLE) {
180180+ kn->kev.flags &= ~EV_DISABLE;
181181+ rv = filt->kn_enable(filt, kn);
182182+ dbg_printf("kn_enable returned %d", rv);
183183+ } else if (src->flags & EV_ADD || src->flags == 0 || src->flags & EV_RECEIPT) {
184184+ kn->kev.udata = src->udata;
185185+ rv = filt->kn_modify(filt, kn, src);
186186+ dbg_printf("kn_modify returned %d", rv);
187187+ }
188188+189189+ return (rv);
190190+}
191191+192192+/** @return number of events added to the eventlist */
193193+static int
194194+kevent_copyin(struct kqueue *kq, const struct kevent *src, int nchanges,
195195+ struct kevent *eventlist, int nevents)
196196+{
197197+ int status, nret;
198198+199199+ dbg_printf("nchanges=%d nevents=%d", nchanges, nevents);
200200+201201+ /* TODO: refactor, this has become convoluted to support EV_RECEIPT */
202202+ for (nret = 0; nchanges > 0; src++, nchanges--) {
203203+204204+ if (kevent_copyin_one(kq, src) < 0) {
205205+ dbg_printf("errno=%s",strerror(errno));
206206+ status = errno;
207207+ goto err_path;
208208+ } else {
209209+ if (src->flags & EV_RECEIPT) {
210210+ status = 0;
211211+ goto err_path;
212212+ }
213213+ }
214214+215215+ continue;
216216+217217+err_path:
218218+ if (nevents > 0) {
219219+ memcpy(eventlist, src, sizeof(*src));
220220+ eventlist->data = status;
221221+ nevents--;
222222+ eventlist++;
223223+ nret++;
224224+ } else {
225225+ return (-1);
226226+ }
227227+ }
228228+229229+ return (nret);
230230+}
231231+232232+int VISIBLE
233233+kevent(int kqfd, const struct kevent *changelist, int nchanges,
234234+ struct kevent *eventlist, int nevents,
235235+ const struct timespec *timeout)
236236+{
237237+ struct kqueue *kq;
238238+ int rv = 0;
239239+#ifndef NDEBUG
240240+ static unsigned int _kevent_counter = 0;
241241+ unsigned int myid = 0;
242242+243243+ (void) myid;
244244+#endif
245245+246246+ /* Convert the descriptor into an object pointer */
247247+ kq = kqueue_lookup(kqfd);
248248+ if (kq == NULL) {
249249+ errno = ENOENT;
250250+ return (-1);
251251+ }
252252+253253+#ifndef NDEBUG
254254+ if (DEBUG_KQUEUE) {
255255+ myid = atomic_inc(&_kevent_counter);
256256+ dbg_printf("--- kevent %u --- (nchanges = %d, nevents = %d)", myid, nchanges, nevents);
257257+ }
258258+#endif
259259+260260+ /*
261261+ * Process each kevent on the changelist.
262262+ */
263263+ if (nchanges > 0) {
264264+ kqueue_lock(kq);
265265+ rv = kevent_copyin(kq, changelist, nchanges, eventlist, nevents);
266266+ kqueue_unlock(kq);
267267+ dbg_printf("(%u) changelist: rv=%d", myid, rv);
268268+ if (rv < 0)
269269+ goto out;
270270+ if (rv > 0) {
271271+ eventlist += rv;
272272+ nevents -= rv;
273273+ }
274274+ }
275275+276276+ rv = 0;
277277+278278+ /*
279279+ * Wait for events and copy them to the eventlist
280280+ */
281281+ if (nevents > MAX_KEVENT)
282282+ nevents = MAX_KEVENT;
283283+ if (nevents > 0) {
284284+ rv = kqops.kevent_wait(kq, nevents, timeout);
285285+ dbg_printf("kqops.kevent_wait returned %d", rv);
286286+ if (fastpath(rv > 0)) {
287287+ kqueue_lock(kq);
288288+ rv = kqops.kevent_copyout(kq, rv, eventlist, nevents);
289289+ kqueue_unlock(kq);
290290+ } else if (rv == 0) {
291291+ /* Timeout reached */
292292+ } else {
293293+ dbg_printf("(%u) kevent_wait failed", myid);
294294+ goto out;
295295+ }
296296+ }
297297+298298+#ifndef NDEBUG
299299+ if (DEBUG_KQUEUE) {
300300+ int n;
301301+302302+ dbg_printf("(%u) returning %d events", myid, rv);
303303+ for (n = 0; n < rv; n++) {
304304+ dbg_printf("(%u) eventlist[%d] = %s", myid, n, kevent_dump(&eventlist[n]));
305305+ }
306306+ }
307307+#endif
308308+309309+out:
310310+ dbg_printf("--- END kevent %u ret %d ---", myid, rv);
311311+ return (rv);
312312+}
+163
external/libkqueue-2.0.1/src/common/knote.c
···11+/*
22+ * Copyright (c) 2009 Mark Heily <mark@heily.com>
33+ *
44+ * Permission to use, copy, modify, and distribute this software for any
55+ * purpose with or without fee is hereby granted, provided that the above
66+ * copyright notice and this permission notice appear in all copies.
77+ *
88+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
99+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
1010+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
1111+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
1212+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
1313+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
1414+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
1515+ */
1616+1717+#include <stdlib.h>
1818+#include <string.h>
1919+#include <sys/types.h>
2020+2121+#include "private.h"
2222+2323+#include "alloc.h"
2424+2525+int
2626+knote_init(void)
2727+{
2828+ return 0;
2929+// return (mem_init(sizeof(struct knote), 1024));
3030+}
3131+3232+static int
3333+knote_cmp(struct knote *a, struct knote *b)
3434+{
3535+ return memcmp(&a->kev.ident, &b->kev.ident, sizeof(a->kev.ident));
3636+}
3737+3838+RB_GENERATE(knt, knote, kn_entries, knote_cmp)
3939+4040+struct knote *
4141+knote_new(void)
4242+{
4343+ struct knote *res;
4444+4545+ res = calloc(1, sizeof(struct knote));
4646+ if (res == NULL)
4747+ return (NULL);
4848+4949+ res->kn_ref = 1;
5050+5151+ return (res);
5252+}
5353+5454+void
5555+knote_release(struct knote *kn)
5656+{
5757+ assert (kn->kn_ref > 0);
5858+5959+ if (atomic_dec(&kn->kn_ref) == 0) {
6060+ if (kn->kn_flags & KNFL_KNOTE_DELETED) {
6161+ dbg_printf("freeing knote at %p", kn);
6262+ free(kn);
6363+ } else {
6464+ dbg_puts("this should never happen");
6565+ }
6666+ } else {
6767+ dbg_printf("decrementing refcount of knote %p rc=%d", kn, kn->kn_ref);
6868+ }
6969+}
7070+7171+void
7272+knote_insert(struct filter *filt, struct knote *kn)
7373+{
7474+ pthread_rwlock_wrlock(&filt->kf_knote_mtx);
7575+ RB_INSERT(knt, &filt->kf_knote, kn);
7676+ pthread_rwlock_unlock(&filt->kf_knote_mtx);
7777+}
7878+7979+int
8080+knote_delete(struct filter *filt, struct knote *kn)
8181+{
8282+ struct knote query;
8383+ struct knote *tmp;
8484+8585+ if (kn->kn_flags & KNFL_KNOTE_DELETED) {
8686+ dbg_puts("ERROR: double deletion detected");
8787+ return (-1);
8888+ }
8989+9090+ /*
9191+ * Verify that the knote wasn't removed by another
9292+ * thread before we acquired the knotelist lock.
9393+ */
9494+ query.kev.ident = kn->kev.ident;
9595+ pthread_rwlock_wrlock(&filt->kf_knote_mtx);
9696+ tmp = RB_FIND(knt, &filt->kf_knote, &query);
9797+ if (tmp == kn) {
9898+ RB_REMOVE(knt, &filt->kf_knote, kn);
9999+ }
100100+ pthread_rwlock_unlock(&filt->kf_knote_mtx);
101101+102102+ filt->kn_delete(filt, kn); //XXX-FIXME check return value
103103+104104+ kn->kn_flags |= KNFL_KNOTE_DELETED;
105105+106106+ knote_release(kn);
107107+108108+ return (0);
109109+}
110110+111111+struct knote *
112112+knote_lookup(struct filter *filt, uintptr_t ident)
113113+{
114114+ struct knote query;
115115+ struct knote *ent = NULL;
116116+117117+ query.kev.ident = ident;
118118+119119+ pthread_rwlock_rdlock(&filt->kf_knote_mtx);
120120+ ent = RB_FIND(knt, &filt->kf_knote, &query);
121121+ pthread_rwlock_unlock(&filt->kf_knote_mtx);
122122+123123+#ifdef __x86_64__
124124+ dbg_printf("id=%lu ent=%p", ident, ent);
125125+#else
126126+ dbg_printf("id=%u ent=%p", ident, ent);
127127+#endif
128128+129129+ return (ent);
130130+}
131131+132132+#if DEADWOOD
133133+struct knote *
134134+knote_get_by_data(struct filter *filt, intptr_t data)
135135+{
136136+ struct knote *kn;
137137+138138+ pthread_rwlock_rdlock(&filt->kf_knote_mtx);
139139+ RB_FOREACH(kn, knt, &filt->kf_knote) {
140140+ if (data == kn->kev.data)
141141+ break;
142142+ }
143143+ if (kn != NULL) {
144144+ knote_retain(kn);
145145+ }
146146+ pthread_rwlock_unlock(&filt->kf_knote_mtx);
147147+148148+ return (kn);
149149+}
150150+#endif
151151+152152+int
153153+knote_disable(struct filter *filt, struct knote *kn)
154154+{
155155+ assert(!(kn->kev.flags & EV_DISABLE));
156156+157157+ filt->kn_disable(filt, kn); //TODO: Error checking
158158+ KNOTE_DISABLE(kn);
159159+ return (0);
160160+}
161161+162162+//TODO: knote_enable()
163163+
+171
external/libkqueue-2.0.1/src/common/kqueue.c
···11+/*
22+ * Copyright (c) 2009 Mark Heily <mark@heily.com>
33+ *
44+ * Permission to use, copy, modify, and distribute this software for any
55+ * purpose with or without fee is hereby granted, provided that the above
66+ * copyright notice and this permission notice appear in all copies.
77+ *
88+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
99+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
1010+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
1111+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
1212+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
1313+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
1414+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
1515+ */
1616+1717+#include <errno.h>
1818+#include <fcntl.h>
1919+#include <signal.h>
2020+#include <stdlib.h>
2121+#include <stdio.h>
2222+#include <sys/types.h>
2323+#include <string.h>
2424+2525+#include "private.h"
2626+2727+int DEBUG_KQUEUE = 0;
2828+char *KQUEUE_DEBUG_IDENT = "KQ";
2929+3030+#ifdef _WIN32
3131+static LONG kq_init_begin = 0;
3232+static int kq_init_complete = 0;
3333+#else
3434+pthread_mutex_t kq_mtx = PTHREAD_MUTEX_INITIALIZER;
3535+pthread_once_t kq_is_initialized = PTHREAD_ONCE_INIT;
3636+#endif
3737+3838+static unsigned int
3939+get_fd_limit(void)
4040+{
4141+#ifdef _WIN32
4242+ /* actually windows should be able to hold
4343+ way more, as they use HANDLEs for everything.
4444+ Still this number should still be sufficient for
4545+ the provided number of kqueue fds.
4646+ */
4747+ return 65536;
4848+#else
4949+ struct rlimit rlim;
5050+5151+ if (getrlimit(RLIMIT_NOFILE, &rlim) < 0) {
5252+ dbg_perror("getrlimit(2)");
5353+ return (65536);
5454+ } else {
5555+ return (rlim.rlim_max);
5656+ }
5757+#endif
5858+}
5959+6060+static struct map *kqmap;
6161+6262+void
6363+libkqueue_init(void)
6464+{
6565+#ifdef NDEBUG
6666+ DEBUG_KQUEUE = 0;
6767+#else
6868+ char *s = getenv("KQUEUE_DEBUG");
6969+ if (s != NULL && strlen(s) > 0) {
7070+ DEBUG_KQUEUE = 1;
7171+7272+#ifdef _WIN32
7373+ /* Initialize the Winsock library */
7474+ WSADATA wsaData;
7575+ if (WSAStartup(MAKEWORD(2,2), &wsaData) != 0)
7676+ abort();
7777+#endif
7878+7979+# if defined(_WIN32) && !defined(__GNUC__)
8080+ /* Enable heap surveillance */
8181+ {
8282+ int tmpFlag = _CrtSetDbgFlag( _CRTDBG_REPORT_FLAG );
8383+ tmpFlag |= _CRTDBG_CHECK_ALWAYS_DF;
8484+ _CrtSetDbgFlag(tmpFlag);
8585+ }
8686+# endif /* _WIN32 */
8787+ }
8888+#endif
8989+9090+ kqmap = map_new(get_fd_limit()); // INT_MAX
9191+ if (kqmap == NULL)
9292+ abort();
9393+ if (knote_init() < 0)
9494+ abort();
9595+ dbg_puts("library initialization complete");
9696+#ifdef _WIN32
9797+ kq_init_complete = 1;
9898+#endif
9999+}
100100+101101+#if DEADWOOD
102102+static int
103103+kqueue_cmp(struct kqueue *a, struct kqueue *b)
104104+{
105105+ return memcmp(&a->kq_id, &b->kq_id, sizeof(int));
106106+}
107107+108108+/* Must hold the kqtree_mtx when calling this */
109109+void
110110+kqueue_free(struct kqueue *kq)
111111+{
112112+ RB_REMOVE(kqt, &kqtree, kq);
113113+ filter_unregister_all(kq);
114114+ kqops.kqueue_free(kq);
115115+ free(kq);
116116+}
117117+118118+#endif
119119+120120+struct kqueue *
121121+kqueue_lookup(int kq)
122122+{
123123+ return ((struct kqueue *) map_lookup(kqmap, kq));
124124+}
125125+126126+int VISIBLE
127127+kqueue(void)
128128+{
129129+ struct kqueue *kq;
130130+ struct kqueue *tmp;
131131+132132+#ifdef _WIN32
133133+ if (InterlockedCompareExchange(&kq_init_begin, 0, 1) == 0) {
134134+ libkqueue_init();
135135+ } else {
136136+ while (kq_init_complete == 0) {
137137+ sleep(1);
138138+ }
139139+ }
140140+#else
141141+ (void) pthread_mutex_lock(&kq_mtx);
142142+ (void) pthread_once(&kq_is_initialized, libkqueue_init);
143143+ (void) pthread_mutex_unlock(&kq_mtx);
144144+#endif
145145+146146+ kq = calloc(1, sizeof(*kq));
147147+ if (kq == NULL)
148148+ return (-1);
149149+150150+ tracing_mutex_init(&kq->kq_mtx, NULL);
151151+152152+ if (kqops.kqueue_init(kq) < 0) {
153153+ free(kq);
154154+ return (-1);
155155+ }
156156+157157+ dbg_printf("created kqueue, fd=%d", kq->kq_id);
158158+159159+ tmp = map_delete(kqmap, kq->kq_id);
160160+ if (tmp != NULL) {
161161+ dbg_puts("FIXME -- memory leak here");
162162+ // TODO: kqops.kqueue_free(tmp), or (better yet) decrease it's refcount
163163+ }
164164+ if (map_insert(kqmap, kq->kq_id, kq) < 0) {
165165+ dbg_puts("map insertion failed");
166166+ kqops.kqueue_free(kq);
167167+ return (-1);
168168+ }
169169+170170+ return (kq->kq_id);
171171+}
+133
external/libkqueue-2.0.1/src/common/map.c
···11+/*
22+ * Copyright (c) 2011 Mark Heily <mark@heily.com>
33+ *
44+ * Permission to use, copy, modify, and distribute this software for any
55+ * purpose with or without fee is hereby granted, provided that the above
66+ * copyright notice and this permission notice appear in all copies.
77+ *
88+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
99+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
1010+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
1111+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
1212+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
1313+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
1414+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
1515+ */
1616+1717+#include "private.h"
1818+1919+struct map {
2020+ size_t len;
2121+ void **data;
2222+};
2323+2424+struct map *
2525+map_new(size_t len)
2626+{
2727+ struct map *dst;
2828+2929+ dst = calloc(1, sizeof(struct map));
3030+ if (dst == NULL)
3131+ return (NULL);
3232+#ifdef _WIN32
3333+ dst->data = calloc(len, sizeof(void*));
3434+ if(dst->data == NULL) {
3535+ dbg_perror("calloc()");
3636+ free(dst);
3737+ return NULL;
3838+ }
3939+ dst->len = len;
4040+#else
4141+ dst->data = mmap(NULL, len * sizeof(void *), PROT_READ | PROT_WRITE,
4242+ MAP_PRIVATE | MAP_NORESERVE | MAP_ANON, -1, 0);
4343+ if (dst->data == MAP_FAILED) {
4444+ dbg_perror("mmap(2)");
4545+ free(dst);
4646+ return (NULL);
4747+ }
4848+ dst->len = len;
4949+#endif
5050+5151+ return (dst);
5252+}
5353+5454+int
5555+map_insert(struct map *m, int idx, void *ptr)
5656+{
5757+ if (slowpath(idx < 0 || idx > (int)m->len))
5858+ return (-1);
5959+6060+ if (atomic_ptr_cas(&(m->data[idx]), 0, ptr) == NULL) {
6161+ dbg_printf("inserted %p in location %d", ptr, idx);
6262+ return (0);
6363+ } else {
6464+ dbg_printf("tried to insert a value into a non-empty location %d (value=%p)",
6565+ idx,
6666+ m->data[idx]);
6767+ return (-1);
6868+ }
6969+}
7070+7171+int
7272+map_remove(struct map *m, int idx, void *ptr)
7373+{
7474+ if (slowpath(idx < 0 || idx > (int)m->len))
7575+ return (-1);
7676+7777+ if (atomic_ptr_cas(&(m->data[idx]), ptr, 0) == NULL) {
7878+ dbg_printf("removed %p from location %d", ptr, idx);
7979+ return (0);
8080+ } else {
8181+ dbg_printf("removal failed: location %d does not contain value %p", idx, m->data[idx]);
8282+ return (-1);
8383+ }
8484+}
8585+8686+int
8787+map_replace(struct map *m, int idx, void *oldp, void *newp)
8888+{
8989+ void *tmp;
9090+9191+ if (slowpath(idx < 0 || idx > (int)m->len))
9292+ return (-1);
9393+9494+ tmp = atomic_ptr_cas(&(m->data[idx]), oldp, newp);
9595+ if (tmp == oldp) {
9696+ dbg_printf("replaced value %p in location %d with value %p",
9797+ oldp, idx, newp);
9898+ return (0);
9999+ } else {
100100+ dbg_printf("item in location %d does not match expected value %p",
101101+ idx, oldp);
102102+ return (-1);
103103+ }
104104+}
105105+106106+void *
107107+map_lookup(struct map *m, int idx)
108108+{
109109+ if (slowpath(idx < 0 || idx > (int)m->len))
110110+ return (NULL);
111111+112112+ return m->data[idx];
113113+}
114114+115115+void *
116116+map_delete(struct map *m, int idx)
117117+{
118118+ void *oval;
119119+ void *nval;
120120+121121+ if (slowpath(idx < 0 || idx > (int)m->len))
122122+ return ((void *)-1);
123123+124124+ /* Hopefully we aren't racing with another thread, but you never know.. */
125125+ do {
126126+ oval = m->data[idx];
127127+ nval = atomic_ptr_cas(&(m->data[idx]), oval, NULL);
128128+ } while (nval != oval);
129129+130130+ m->data[idx] = NULL;
131131+132132+ return ((void *) oval);
133133+}
+230
external/libkqueue-2.0.1/src/common/private.h
···11+/*
22+ * Copyright (c) 2009 Mark Heily <mark@heily.com>
33+ *
44+ * Permission to use, copy, modify, and distribute this software for any
55+ * purpose with or without fee is hereby granted, provided that the above
66+ * copyright notice and this permission notice appear in all copies.
77+ *
88+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
99+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
1010+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
1111+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
1212+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
1313+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
1414+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
1515+ */
1616+1717+#ifndef _KQUEUE_PRIVATE_H
1818+#define _KQUEUE_PRIVATE_H
1919+2020+#include <errno.h>
2121+#include <stdio.h>
2222+#include <string.h>
2323+#include "config.h"
2424+#include "tree.h"
2525+2626+/* Maximum events returnable in a single kevent() call */
2727+#define MAX_KEVENT 512
2828+2929+struct kqueue;
3030+struct kevent;
3131+struct knote;
3232+struct map;
3333+struct eventfd;
3434+struct evfilt_data;
3535+3636+#if defined(_WIN32)
3737+# include "../windows/platform.h"
3838+# include "../common/queue.h"
3939+# if !defined(NDEBUG) && !defined(__GNUC__)
4040+# include <crtdbg.h>
4141+# endif
4242+#elif defined(__linux__)
4343+# include "../posix/platform.h"
4444+# include "../linux/platform.h"
4545+#elif defined(__sun)
4646+# include "../posix/platform.h"
4747+# include "../solaris/platform.h"
4848+#else
4949+# error Unknown platform
5050+#endif
5151+5252+#include "debug.h"
5353+5454+/* Workaround for Android */
5555+#ifndef EPOLLONESHOT
5656+# define EPOLLONESHOT (1 << 30)
5757+#endif
5858+5959+struct eventfd {
6060+ int ef_id;
6161+#if defined(EVENTFD_PLATFORM_SPECIFIC)
6262+ EVENTFD_PLATFORM_SPECIFIC;
6363+#endif
6464+};
6565+6666+/*
6767+ * Flags used by knote->kn_flags
6868+ */
6969+#define KNFL_PASSIVE_SOCKET (0x01) /* Socket is in listen(2) mode */
7070+#define KNFL_REGULAR_FILE (0x02) /* File descriptor is a regular file */
7171+#define KNFL_KNOTE_DELETED (0x10) /* The knote object is no longer valid */
7272+7373+struct knote {
7474+ struct kevent kev;
7575+ int kn_flags;
7676+ union {
7777+ /* OLD */
7878+ int pfd; /* Used by timerfd */
7979+ int events; /* Used by socket */
8080+ struct {
8181+ nlink_t nlink; /* Used by vnode */
8282+ off_t size; /* Used by vnode */
8383+ } vnode;
8484+ timer_t timerid;
8585+ struct sleepreq *sleepreq; /* Used by posix/timer.c */
8686+ void *handle; /* Used by win32 filters */
8787+ } data;
8888+ struct kqueue* kn_kq;
8989+ volatile uint32_t kn_ref;
9090+#if defined(KNOTE_PLATFORM_SPECIFIC)
9191+ KNOTE_PLATFORM_SPECIFIC;
9292+#endif
9393+ RB_ENTRY(knote) kn_entries;
9494+};
9595+9696+#define KNOTE_ENABLE(ent) do { \
9797+ (ent)->kev.flags &= ~EV_DISABLE; \
9898+} while (0/*CONSTCOND*/)
9999+100100+#define KNOTE_DISABLE(ent) do { \
101101+ (ent)->kev.flags |= EV_DISABLE; \
102102+} while (0/*CONSTCOND*/)
103103+104104+struct filter {
105105+ short kf_id;
106106+107107+ /* filter operations */
108108+109109+ int (*kf_init)(struct filter *);
110110+ void (*kf_destroy)(struct filter *);
111111+ int (*kf_copyout)(struct kevent *, struct knote *, void *);
112112+113113+ /* knote operations */
114114+115115+ int (*kn_create)(struct filter *, struct knote *);
116116+ int (*kn_modify)(struct filter *, struct knote *,
117117+ const struct kevent *);
118118+ int (*kn_delete)(struct filter *, struct knote *);
119119+ int (*kn_enable)(struct filter *, struct knote *);
120120+ int (*kn_disable)(struct filter *, struct knote *);
121121+122122+ struct eventfd kf_efd; /* Used by user.c */
123123+124124+ //MOVE TO POSIX?
125125+ int kf_pfd; /* fd to poll(2) for readiness */
126126+ int kf_wfd; /* fd to write when an event occurs */
127127+ //----?
128128+129129+ struct evfilt_data *kf_data; /* filter-specific data */
130130+ RB_HEAD(knt, knote) kf_knote;
131131+ pthread_rwlock_t kf_knote_mtx;
132132+ struct kqueue *kf_kqueue;
133133+#if defined(FILTER_PLATFORM_SPECIFIC)
134134+ FILTER_PLATFORM_SPECIFIC;
135135+#endif
136136+};
137137+138138+/* Use this to declare a filter that is not implemented */
139139+#define EVFILT_NOTIMPL { 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL }
140140+141141+struct kqueue {
142142+ int kq_id;
143143+ struct filter kq_filt[EVFILT_SYSCOUNT];
144144+ fd_set kq_fds, kq_rfds;
145145+ int kq_nfds;
146146+ tracing_mutex_t kq_mtx;
147147+ volatile uint32_t kq_ref;
148148+#if defined(KQUEUE_PLATFORM_SPECIFIC)
149149+ KQUEUE_PLATFORM_SPECIFIC;
150150+#endif
151151+ RB_ENTRY(kqueue) entries;
152152+};
153153+154154+struct kqueue_vtable {
155155+ int (*kqueue_init)(struct kqueue *);
156156+ void (*kqueue_free)(struct kqueue *);
157157+ // @param timespec can be given as timeout
158158+ // @param int the number of events to wait for
159159+ // @param kqueue the queue to wait on
160160+ int (*kevent_wait)(struct kqueue *, int, const struct timespec *);
161161+ // @param kqueue the queue to look at
162162+ // @param int The number of events that should be ready
163163+ // @param kevent the structure to copy the events into
164164+ // @param int The number of events to copy
165165+ // @return the actual number of events copied
166166+ int (*kevent_copyout)(struct kqueue *, int, struct kevent *, int);
167167+ int (*filter_init)(struct kqueue *, struct filter *);
168168+ void (*filter_free)(struct kqueue *, struct filter *);
169169+ int (*eventfd_init)(struct eventfd *);
170170+ void (*eventfd_close)(struct eventfd *);
171171+ int (*eventfd_raise)(struct eventfd *);
172172+ int (*eventfd_lower)(struct eventfd *);
173173+ int (*eventfd_descriptor)(struct eventfd *);
174174+};
175175+extern const struct kqueue_vtable kqops;
176176+177177+/*
178178+ * kqueue internal API
179179+ */
180180+#define kqueue_lock(kq) tracing_mutex_lock(&(kq)->kq_mtx)
181181+#define kqueue_unlock(kq) tracing_mutex_unlock(&(kq)->kq_mtx)
182182+183183+/*
184184+ * knote internal API
185185+ */
186186+struct knote * knote_lookup(struct filter *, uintptr_t);
187187+//DEADWOOD: struct knote * knote_get_by_data(struct filter *filt, intptr_t);
188188+struct knote * knote_new(void);
189189+#define knote_retain(kn) atomic_inc(&kn->kn_ref)
190190+void knote_release(struct knote *);
191191+void knote_insert(struct filter *, struct knote *);
192192+int knote_delete(struct filter *, struct knote *);
193193+int knote_init(void);
194194+int knote_disable(struct filter *, struct knote *);
195195+#define knote_get_filter(knt) &((knt)->kn_kq->kq_filt[(knt)->kev.filter])
196196+197197+int filter_lookup(struct filter **, struct kqueue *, short);
198198+int filter_register_all(struct kqueue *);
199199+void filter_unregister_all(struct kqueue *);
200200+const char *filter_name(short);
201201+202202+int kevent_wait(struct kqueue *, const struct timespec *);
203203+int kevent_copyout(struct kqueue *, int, struct kevent *, int);
204204+void kevent_free(struct kqueue *);
205205+const char *kevent_dump(const struct kevent *);
206206+struct kqueue * kqueue_lookup(int);
207207+int kqueue_validate(struct kqueue *);
208208+209209+struct map *map_new(size_t);
210210+int map_insert(struct map *, int, void *);
211211+int map_remove(struct map *, int, void *);
212212+int map_replace(struct map *, int, void *, void *);
213213+void *map_lookup(struct map *, int);
214214+void *map_delete(struct map *, int);
215215+void map_free(struct map *);
216216+217217+/* DEADWOOD: No longer needed due to the un-smerging of POSIX and Linux
218218+219219+int posix_evfilt_user_init(struct filter *);
220220+void posix_evfilt_user_destroy(struct filter *);
221221+int posix_evfilt_user_copyout(struct kevent *, struct knote *, void *ptr UNUSED);
222222+int posix_evfilt_user_knote_create(struct filter *, struct knote *);
223223+int posix_evfilt_user_knote_modify(struct filter *, struct knote *, const struct kevent *);
224224+int posix_evfilt_user_knote_delete(struct filter *, struct knote *);
225225+int posix_evfilt_user_knote_enable(struct filter *, struct knote *);
226226+int posix_evfilt_user_knote_disable(struct filter *, struct knote *);
227227+228228+*/
229229+230230+#endif /* ! _KQUEUE_PRIVATE_H */
+763
external/libkqueue-2.0.1/src/common/tree.h
···11+/* $NetBSD: tree.h,v 1.8 2004/03/28 19:38:30 provos Exp $ */
22+/* $OpenBSD: tree.h,v 1.7 2002/10/17 21:51:54 art Exp $ */
33+/* $FreeBSD: src/sys/sys/tree.h,v 1.9.2.1.2.1 2009/10/25 01:10:29 kensmith Exp $ */
44+55+/*-
66+ * Copyright 2002 Niels Provos <provos@citi.umich.edu>
77+ * All rights reserved.
88+ *
99+ * Redistribution and use in source and binary forms, with or without
1010+ * modification, are permitted provided that the following conditions
1111+ * are met:
1212+ * 1. Redistributions of source code must retain the above copyright
1313+ * notice, this list of conditions and the following disclaimer.
1414+ * 2. Redistributions in binary form must reproduce the above copyright
1515+ * notice, this list of conditions and the following disclaimer in the
1616+ * documentation and/or other materials provided with the distribution.
1717+ *
1818+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
1919+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
2020+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
2121+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
2222+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
2323+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
2424+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
2525+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
2626+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
2727+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
2828+ */
2929+3030+#ifndef _SYS_TREE_H_
3131+#define _SYS_TREE_H_
3232+3333+/*
3434+ * This file defines data structures for different types of trees:
3535+ * splay trees and red-black trees.
3636+ *
3737+ * A splay tree is a self-organizing data structure. Every operation
3838+ * on the tree causes a splay to happen. The splay moves the requested
3939+ * node to the root of the tree and partly rebalances it.
4040+ *
4141+ * This has the benefit that request locality causes faster lookups as
4242+ * the requested nodes move to the top of the tree. On the other hand,
4343+ * every lookup causes memory writes.
4444+ *
4545+ * The Balance Theorem bounds the total access time for m operations
4646+ * and n inserts on an initially empty tree as O((m + n)lg n). The
4747+ * amortized cost for a sequence of m accesses to a splay tree is O(lg n);
4848+ *
4949+ * A red-black tree is a binary search tree with the node color as an
5050+ * extra attribute. It fulfills a set of conditions:
5151+ * - every search path from the root to a leaf consists of the
5252+ * same number of black nodes,
5353+ * - each red node (except for the root) has a black parent,
5454+ * - each leaf node is black.
5555+ *
5656+ * Every operation on a red-black tree is bounded as O(lg n).
5757+ * The maximum height of a red-black tree is 2lg (n+1).
5858+ */
5959+6060+#define SPLAY_HEAD(name, type) \
6161+struct name { \
6262+ struct type *sph_root; /* root of the tree */ \
6363+}
6464+6565+#define SPLAY_INITIALIZER(root) \
6666+ { NULL }
6767+6868+#define SPLAY_INIT(root) do { \
6969+ (root)->sph_root = NULL; \
7070+} while (/*CONSTCOND*/ 0)
7171+7272+#define SPLAY_ENTRY(type) \
7373+struct { \
7474+ struct type *spe_left; /* left element */ \
7575+ struct type *spe_right; /* right element */ \
7676+}
7777+7878+#define SPLAY_LEFT(elm, field) (elm)->field.spe_left
7979+#define SPLAY_RIGHT(elm, field) (elm)->field.spe_right
8080+#define SPLAY_ROOT(head) (head)->sph_root
8181+#define SPLAY_EMPTY(head) (SPLAY_ROOT(head) == NULL)
8282+8383+/* SPLAY_ROTATE_{LEFT,RIGHT} expect that tmp hold SPLAY_{RIGHT,LEFT} */
8484+#define SPLAY_ROTATE_RIGHT(head, tmp, field) do { \
8585+ SPLAY_LEFT((head)->sph_root, field) = SPLAY_RIGHT(tmp, field); \
8686+ SPLAY_RIGHT(tmp, field) = (head)->sph_root; \
8787+ (head)->sph_root = tmp; \
8888+} while (/*CONSTCOND*/ 0)
8989+9090+#define SPLAY_ROTATE_LEFT(head, tmp, field) do { \
9191+ SPLAY_RIGHT((head)->sph_root, field) = SPLAY_LEFT(tmp, field); \
9292+ SPLAY_LEFT(tmp, field) = (head)->sph_root; \
9393+ (head)->sph_root = tmp; \
9494+} while (/*CONSTCOND*/ 0)
9595+9696+#define SPLAY_LINKLEFT(head, tmp, field) do { \
9797+ SPLAY_LEFT(tmp, field) = (head)->sph_root; \
9898+ tmp = (head)->sph_root; \
9999+ (head)->sph_root = SPLAY_LEFT((head)->sph_root, field); \
100100+} while (/*CONSTCOND*/ 0)
101101+102102+#define SPLAY_LINKRIGHT(head, tmp, field) do { \
103103+ SPLAY_RIGHT(tmp, field) = (head)->sph_root; \
104104+ tmp = (head)->sph_root; \
105105+ (head)->sph_root = SPLAY_RIGHT((head)->sph_root, field); \
106106+} while (/*CONSTCOND*/ 0)
107107+108108+#define SPLAY_ASSEMBLE(head, node, left, right, field) do { \
109109+ SPLAY_RIGHT(left, field) = SPLAY_LEFT((head)->sph_root, field); \
110110+ SPLAY_LEFT(right, field) = SPLAY_RIGHT((head)->sph_root, field);\
111111+ SPLAY_LEFT((head)->sph_root, field) = SPLAY_RIGHT(node, field); \
112112+ SPLAY_RIGHT((head)->sph_root, field) = SPLAY_LEFT(node, field); \
113113+} while (/*CONSTCOND*/ 0)
114114+115115+/* Generates prototypes and inline functions */
116116+117117+#define SPLAY_PROTOTYPE(name, type, field, cmp) \
118118+void name##_SPLAY(struct name *, struct type *); \
119119+void name##_SPLAY_MINMAX(struct name *, int); \
120120+struct type *name##_SPLAY_INSERT(struct name *, struct type *); \
121121+struct type *name##_SPLAY_REMOVE(struct name *, struct type *); \
122122+ \
123123+/* Finds the node with the same key as elm */ \
124124+static __inline struct type * \
125125+name##_SPLAY_FIND(struct name *head, struct type *elm) \
126126+{ \
127127+ if (SPLAY_EMPTY(head)) \
128128+ return(NULL); \
129129+ name##_SPLAY(head, elm); \
130130+ if ((cmp)(elm, (head)->sph_root) == 0) \
131131+ return (head->sph_root); \
132132+ return (NULL); \
133133+} \
134134+ \
135135+static __inline struct type * \
136136+name##_SPLAY_NEXT(struct name *head, struct type *elm) \
137137+{ \
138138+ name##_SPLAY(head, elm); \
139139+ if (SPLAY_RIGHT(elm, field) != NULL) { \
140140+ elm = SPLAY_RIGHT(elm, field); \
141141+ while (SPLAY_LEFT(elm, field) != NULL) { \
142142+ elm = SPLAY_LEFT(elm, field); \
143143+ } \
144144+ } else \
145145+ elm = NULL; \
146146+ return (elm); \
147147+} \
148148+ \
149149+static __inline struct type * \
150150+name##_SPLAY_MIN_MAX(struct name *head, int val) \
151151+{ \
152152+ name##_SPLAY_MINMAX(head, val); \
153153+ return (SPLAY_ROOT(head)); \
154154+}
155155+156156+/* Main splay operation.
157157+ * Moves node close to the key of elm to top
158158+ */
159159+#define SPLAY_GENERATE(name, type, field, cmp) \
160160+struct type * \
161161+name##_SPLAY_INSERT(struct name *head, struct type *elm) \
162162+{ \
163163+ if (SPLAY_EMPTY(head)) { \
164164+ SPLAY_LEFT(elm, field) = SPLAY_RIGHT(elm, field) = NULL; \
165165+ } else { \
166166+ int __comp; \
167167+ name##_SPLAY(head, elm); \
168168+ __comp = (cmp)(elm, (head)->sph_root); \
169169+ if(__comp < 0) { \
170170+ SPLAY_LEFT(elm, field) = SPLAY_LEFT((head)->sph_root, field);\
171171+ SPLAY_RIGHT(elm, field) = (head)->sph_root; \
172172+ SPLAY_LEFT((head)->sph_root, field) = NULL; \
173173+ } else if (__comp > 0) { \
174174+ SPLAY_RIGHT(elm, field) = SPLAY_RIGHT((head)->sph_root, field);\
175175+ SPLAY_LEFT(elm, field) = (head)->sph_root; \
176176+ SPLAY_RIGHT((head)->sph_root, field) = NULL; \
177177+ } else \
178178+ return ((head)->sph_root); \
179179+ } \
180180+ (head)->sph_root = (elm); \
181181+ return (NULL); \
182182+} \
183183+ \
184184+struct type * \
185185+name##_SPLAY_REMOVE(struct name *head, struct type *elm) \
186186+{ \
187187+ struct type *__tmp; \
188188+ if (SPLAY_EMPTY(head)) \
189189+ return (NULL); \
190190+ name##_SPLAY(head, elm); \
191191+ if ((cmp)(elm, (head)->sph_root) == 0) { \
192192+ if (SPLAY_LEFT((head)->sph_root, field) == NULL) { \
193193+ (head)->sph_root = SPLAY_RIGHT((head)->sph_root, field);\
194194+ } else { \
195195+ __tmp = SPLAY_RIGHT((head)->sph_root, field); \
196196+ (head)->sph_root = SPLAY_LEFT((head)->sph_root, field);\
197197+ name##_SPLAY(head, elm); \
198198+ SPLAY_RIGHT((head)->sph_root, field) = __tmp; \
199199+ } \
200200+ return (elm); \
201201+ } \
202202+ return (NULL); \
203203+} \
204204+ \
205205+void \
206206+name##_SPLAY(struct name *head, struct type *elm) \
207207+{ \
208208+ struct type __node, *__left, *__right, *__tmp; \
209209+ int __comp; \
210210+\
211211+ SPLAY_LEFT(&__node, field) = SPLAY_RIGHT(&__node, field) = NULL;\
212212+ __left = __right = &__node; \
213213+\
214214+ while ((__comp = (cmp)(elm, (head)->sph_root)) != 0) { \
215215+ if (__comp < 0) { \
216216+ __tmp = SPLAY_LEFT((head)->sph_root, field); \
217217+ if (__tmp == NULL) \
218218+ break; \
219219+ if ((cmp)(elm, __tmp) < 0){ \
220220+ SPLAY_ROTATE_RIGHT(head, __tmp, field); \
221221+ if (SPLAY_LEFT((head)->sph_root, field) == NULL)\
222222+ break; \
223223+ } \
224224+ SPLAY_LINKLEFT(head, __right, field); \
225225+ } else if (__comp > 0) { \
226226+ __tmp = SPLAY_RIGHT((head)->sph_root, field); \
227227+ if (__tmp == NULL) \
228228+ break; \
229229+ if ((cmp)(elm, __tmp) > 0){ \
230230+ SPLAY_ROTATE_LEFT(head, __tmp, field); \
231231+ if (SPLAY_RIGHT((head)->sph_root, field) == NULL)\
232232+ break; \
233233+ } \
234234+ SPLAY_LINKRIGHT(head, __left, field); \
235235+ } \
236236+ } \
237237+ SPLAY_ASSEMBLE(head, &__node, __left, __right, field); \
238238+} \
239239+ \
240240+/* Splay with either the minimum or the maximum element \
241241+ * Used to find minimum or maximum element in tree. \
242242+ */ \
243243+void name##_SPLAY_MINMAX(struct name *head, int __comp) \
244244+{ \
245245+ struct type __node, *__left, *__right, *__tmp; \
246246+\
247247+ SPLAY_LEFT(&__node, field) = SPLAY_RIGHT(&__node, field) = NULL;\
248248+ __left = __right = &__node; \
249249+\
250250+ while (1) { \
251251+ if (__comp < 0) { \
252252+ __tmp = SPLAY_LEFT((head)->sph_root, field); \
253253+ if (__tmp == NULL) \
254254+ break; \
255255+ if (__comp < 0){ \
256256+ SPLAY_ROTATE_RIGHT(head, __tmp, field); \
257257+ if (SPLAY_LEFT((head)->sph_root, field) == NULL)\
258258+ break; \
259259+ } \
260260+ SPLAY_LINKLEFT(head, __right, field); \
261261+ } else if (__comp > 0) { \
262262+ __tmp = SPLAY_RIGHT((head)->sph_root, field); \
263263+ if (__tmp == NULL) \
264264+ break; \
265265+ if (__comp > 0) { \
266266+ SPLAY_ROTATE_LEFT(head, __tmp, field); \
267267+ if (SPLAY_RIGHT((head)->sph_root, field) == NULL)\
268268+ break; \
269269+ } \
270270+ SPLAY_LINKRIGHT(head, __left, field); \
271271+ } \
272272+ } \
273273+ SPLAY_ASSEMBLE(head, &__node, __left, __right, field); \
274274+}
275275+276276+#define SPLAY_NEGINF -1
277277+#define SPLAY_INF 1
278278+279279+#define SPLAY_INSERT(name, x, y) name##_SPLAY_INSERT(x, y)
280280+#define SPLAY_REMOVE(name, x, y) name##_SPLAY_REMOVE(x, y)
281281+#define SPLAY_FIND(name, x, y) name##_SPLAY_FIND(x, y)
282282+#define SPLAY_NEXT(name, x, y) name##_SPLAY_NEXT(x, y)
283283+#define SPLAY_MIN(name, x) (SPLAY_EMPTY(x) ? NULL \
284284+ : name##_SPLAY_MIN_MAX(x, SPLAY_NEGINF))
285285+#define SPLAY_MAX(name, x) (SPLAY_EMPTY(x) ? NULL \
286286+ : name##_SPLAY_MIN_MAX(x, SPLAY_INF))
287287+288288+#define SPLAY_FOREACH(x, name, head) \
289289+ for ((x) = SPLAY_MIN(name, head); \
290290+ (x) != NULL; \
291291+ (x) = SPLAY_NEXT(name, head, x))
292292+293293+/* Macros that define a red-black tree */
294294+#define RB_HEAD(name, type) \
295295+struct name { \
296296+ struct type *rbh_root; /* root of the tree */ \
297297+}
298298+299299+#define RB_INITIALIZER(root) \
300300+ { NULL }
301301+302302+#define RB_INIT(root) do { \
303303+ (root)->rbh_root = NULL; \
304304+} while (/*CONSTCOND*/ 0)
305305+306306+#define RB_BLACK 0
307307+#define RB_RED 1
308308+#define RB_ENTRY(type) \
309309+struct { \
310310+ struct type *rbe_left; /* left element */ \
311311+ struct type *rbe_right; /* right element */ \
312312+ struct type *rbe_parent; /* parent element */ \
313313+ int rbe_color; /* node color */ \
314314+}
315315+316316+#define RB_LEFT(elm, field) (elm)->field.rbe_left
317317+#define RB_RIGHT(elm, field) (elm)->field.rbe_right
318318+#define RB_PARENT(elm, field) (elm)->field.rbe_parent
319319+#define RB_COLOR(elm, field) (elm)->field.rbe_color
320320+#define RB_ROOT(head) (head)->rbh_root
321321+#define RB_EMPTY(head) (RB_ROOT(head) == NULL)
322322+323323+#define RB_SET(elm, parent, field) do { \
324324+ RB_PARENT(elm, field) = parent; \
325325+ RB_LEFT(elm, field) = RB_RIGHT(elm, field) = NULL; \
326326+ RB_COLOR(elm, field) = RB_RED; \
327327+} while (/*CONSTCOND*/ 0)
328328+329329+#define RB_SET_BLACKRED(black, red, field) do { \
330330+ RB_COLOR(black, field) = RB_BLACK; \
331331+ RB_COLOR(red, field) = RB_RED; \
332332+} while (/*CONSTCOND*/ 0)
333333+334334+#ifndef RB_AUGMENT
335335+#define RB_AUGMENT(x) do {} while (0)
336336+#endif
337337+338338+#define RB_ROTATE_LEFT(head, elm, tmp, field) do { \
339339+ (tmp) = RB_RIGHT(elm, field); \
340340+ if ((RB_RIGHT(elm, field) = RB_LEFT(tmp, field)) != NULL) { \
341341+ RB_PARENT(RB_LEFT(tmp, field), field) = (elm); \
342342+ } \
343343+ RB_AUGMENT(elm); \
344344+ if ((RB_PARENT(tmp, field) = RB_PARENT(elm, field)) != NULL) { \
345345+ if ((elm) == RB_LEFT(RB_PARENT(elm, field), field)) \
346346+ RB_LEFT(RB_PARENT(elm, field), field) = (tmp); \
347347+ else \
348348+ RB_RIGHT(RB_PARENT(elm, field), field) = (tmp); \
349349+ } else \
350350+ (head)->rbh_root = (tmp); \
351351+ RB_LEFT(tmp, field) = (elm); \
352352+ RB_PARENT(elm, field) = (tmp); \
353353+ RB_AUGMENT(tmp); \
354354+ if ((RB_PARENT(tmp, field))) \
355355+ RB_AUGMENT(RB_PARENT(tmp, field)); \
356356+} while (/*CONSTCOND*/ 0)
357357+358358+#define RB_ROTATE_RIGHT(head, elm, tmp, field) do { \
359359+ (tmp) = RB_LEFT(elm, field); \
360360+ if ((RB_LEFT(elm, field) = RB_RIGHT(tmp, field)) != NULL) { \
361361+ RB_PARENT(RB_RIGHT(tmp, field), field) = (elm); \
362362+ } \
363363+ RB_AUGMENT(elm); \
364364+ if ((RB_PARENT(tmp, field) = RB_PARENT(elm, field)) != NULL) { \
365365+ if ((elm) == RB_LEFT(RB_PARENT(elm, field), field)) \
366366+ RB_LEFT(RB_PARENT(elm, field), field) = (tmp); \
367367+ else \
368368+ RB_RIGHT(RB_PARENT(elm, field), field) = (tmp); \
369369+ } else \
370370+ (head)->rbh_root = (tmp); \
371371+ RB_RIGHT(tmp, field) = (elm); \
372372+ RB_PARENT(elm, field) = (tmp); \
373373+ RB_AUGMENT(tmp); \
374374+ if ((RB_PARENT(tmp, field))) \
375375+ RB_AUGMENT(RB_PARENT(tmp, field)); \
376376+} while (/*CONSTCOND*/ 0)
377377+378378+/* Generates prototypes and inline functions */
379379+#define RB_PROTOTYPE(name, type, field, cmp) \
380380+ RB_PROTOTYPE_INTERNAL(name, type, field, cmp,)
381381+#define RB_PROTOTYPE_STATIC(name, type, field, cmp) \
382382+ RB_PROTOTYPE_INTERNAL(name, type, field, cmp, __unused static)
383383+#define RB_PROTOTYPE_INTERNAL(name, type, field, cmp, attr) \
384384+attr void name##_RB_INSERT_COLOR(struct name *, struct type *); \
385385+attr void name##_RB_REMOVE_COLOR(struct name *, struct type *, struct type *);\
386386+attr struct type *name##_RB_REMOVE(struct name *, struct type *); \
387387+attr struct type *name##_RB_INSERT(struct name *, struct type *); \
388388+attr struct type *name##_RB_FIND(struct name *, struct type *); \
389389+attr struct type *name##_RB_NFIND(struct name *, struct type *); \
390390+attr struct type *name##_RB_NEXT(struct type *); \
391391+attr struct type *name##_RB_PREV(struct type *); \
392392+attr struct type *name##_RB_MINMAX(struct name *, int); \
393393+ \
394394+395395+/* Main rb operation.
396396+ * Moves node close to the key of elm to top
397397+ */
398398+#define RB_GENERATE(name, type, field, cmp) \
399399+ RB_GENERATE_INTERNAL(name, type, field, cmp,)
400400+#define RB_GENERATE_STATIC(name, type, field, cmp) \
401401+ RB_GENERATE_INTERNAL(name, type, field, cmp, __unused static)
402402+#define RB_GENERATE_INTERNAL(name, type, field, cmp, attr) \
403403+attr void \
404404+name##_RB_INSERT_COLOR(struct name *head, struct type *elm) \
405405+{ \
406406+ struct type *parent, *gparent, *tmp; \
407407+ while ((parent = RB_PARENT(elm, field)) != NULL && \
408408+ RB_COLOR(parent, field) == RB_RED) { \
409409+ gparent = RB_PARENT(parent, field); \
410410+ if (parent == RB_LEFT(gparent, field)) { \
411411+ tmp = RB_RIGHT(gparent, field); \
412412+ if (tmp && RB_COLOR(tmp, field) == RB_RED) { \
413413+ RB_COLOR(tmp, field) = RB_BLACK; \
414414+ RB_SET_BLACKRED(parent, gparent, field);\
415415+ elm = gparent; \
416416+ continue; \
417417+ } \
418418+ if (RB_RIGHT(parent, field) == elm) { \
419419+ RB_ROTATE_LEFT(head, parent, tmp, field);\
420420+ tmp = parent; \
421421+ parent = elm; \
422422+ elm = tmp; \
423423+ } \
424424+ RB_SET_BLACKRED(parent, gparent, field); \
425425+ RB_ROTATE_RIGHT(head, gparent, tmp, field); \
426426+ } else { \
427427+ tmp = RB_LEFT(gparent, field); \
428428+ if (tmp && RB_COLOR(tmp, field) == RB_RED) { \
429429+ RB_COLOR(tmp, field) = RB_BLACK; \
430430+ RB_SET_BLACKRED(parent, gparent, field);\
431431+ elm = gparent; \
432432+ continue; \
433433+ } \
434434+ if (RB_LEFT(parent, field) == elm) { \
435435+ RB_ROTATE_RIGHT(head, parent, tmp, field);\
436436+ tmp = parent; \
437437+ parent = elm; \
438438+ elm = tmp; \
439439+ } \
440440+ RB_SET_BLACKRED(parent, gparent, field); \
441441+ RB_ROTATE_LEFT(head, gparent, tmp, field); \
442442+ } \
443443+ } \
444444+ RB_COLOR(head->rbh_root, field) = RB_BLACK; \
445445+} \
446446+ \
447447+attr void \
448448+name##_RB_REMOVE_COLOR(struct name *head, struct type *parent, struct type *elm) \
449449+{ \
450450+ struct type *tmp; \
451451+ while ((elm == NULL || RB_COLOR(elm, field) == RB_BLACK) && \
452452+ elm != RB_ROOT(head)) { \
453453+ if (RB_LEFT(parent, field) == elm) { \
454454+ tmp = RB_RIGHT(parent, field); \
455455+ if (RB_COLOR(tmp, field) == RB_RED) { \
456456+ RB_SET_BLACKRED(tmp, parent, field); \
457457+ RB_ROTATE_LEFT(head, parent, tmp, field);\
458458+ tmp = RB_RIGHT(parent, field); \
459459+ } \
460460+ if ((RB_LEFT(tmp, field) == NULL || \
461461+ RB_COLOR(RB_LEFT(tmp, field), field) == RB_BLACK) &&\
462462+ (RB_RIGHT(tmp, field) == NULL || \
463463+ RB_COLOR(RB_RIGHT(tmp, field), field) == RB_BLACK)) {\
464464+ RB_COLOR(tmp, field) = RB_RED; \
465465+ elm = parent; \
466466+ parent = RB_PARENT(elm, field); \
467467+ } else { \
468468+ if (RB_RIGHT(tmp, field) == NULL || \
469469+ RB_COLOR(RB_RIGHT(tmp, field), field) == RB_BLACK) {\
470470+ struct type *oleft; \
471471+ if ((oleft = RB_LEFT(tmp, field)) \
472472+ != NULL) \
473473+ RB_COLOR(oleft, field) = RB_BLACK;\
474474+ RB_COLOR(tmp, field) = RB_RED; \
475475+ RB_ROTATE_RIGHT(head, tmp, oleft, field);\
476476+ tmp = RB_RIGHT(parent, field); \
477477+ } \
478478+ RB_COLOR(tmp, field) = RB_COLOR(parent, field);\
479479+ RB_COLOR(parent, field) = RB_BLACK; \
480480+ if (RB_RIGHT(tmp, field)) \
481481+ RB_COLOR(RB_RIGHT(tmp, field), field) = RB_BLACK;\
482482+ RB_ROTATE_LEFT(head, parent, tmp, field);\
483483+ elm = RB_ROOT(head); \
484484+ break; \
485485+ } \
486486+ } else { \
487487+ tmp = RB_LEFT(parent, field); \
488488+ if (RB_COLOR(tmp, field) == RB_RED) { \
489489+ RB_SET_BLACKRED(tmp, parent, field); \
490490+ RB_ROTATE_RIGHT(head, parent, tmp, field);\
491491+ tmp = RB_LEFT(parent, field); \
492492+ } \
493493+ if ((RB_LEFT(tmp, field) == NULL || \
494494+ RB_COLOR(RB_LEFT(tmp, field), field) == RB_BLACK) &&\
495495+ (RB_RIGHT(tmp, field) == NULL || \
496496+ RB_COLOR(RB_RIGHT(tmp, field), field) == RB_BLACK)) {\
497497+ RB_COLOR(tmp, field) = RB_RED; \
498498+ elm = parent; \
499499+ parent = RB_PARENT(elm, field); \
500500+ } else { \
501501+ if (RB_LEFT(tmp, field) == NULL || \
502502+ RB_COLOR(RB_LEFT(tmp, field), field) == RB_BLACK) {\
503503+ struct type *oright; \
504504+ if ((oright = RB_RIGHT(tmp, field)) \
505505+ != NULL) \
506506+ RB_COLOR(oright, field) = RB_BLACK;\
507507+ RB_COLOR(tmp, field) = RB_RED; \
508508+ RB_ROTATE_LEFT(head, tmp, oright, field);\
509509+ tmp = RB_LEFT(parent, field); \
510510+ } \
511511+ RB_COLOR(tmp, field) = RB_COLOR(parent, field);\
512512+ RB_COLOR(parent, field) = RB_BLACK; \
513513+ if (RB_LEFT(tmp, field)) \
514514+ RB_COLOR(RB_LEFT(tmp, field), field) = RB_BLACK;\
515515+ RB_ROTATE_RIGHT(head, parent, tmp, field);\
516516+ elm = RB_ROOT(head); \
517517+ break; \
518518+ } \
519519+ } \
520520+ } \
521521+ if (elm) \
522522+ RB_COLOR(elm, field) = RB_BLACK; \
523523+} \
524524+ \
525525+attr struct type * \
526526+name##_RB_REMOVE(struct name *head, struct type *elm) \
527527+{ \
528528+ struct type *child, *parent, *old = elm; \
529529+ int color; \
530530+ if (RB_LEFT(elm, field) == NULL) \
531531+ child = RB_RIGHT(elm, field); \
532532+ else if (RB_RIGHT(elm, field) == NULL) \
533533+ child = RB_LEFT(elm, field); \
534534+ else { \
535535+ struct type *left; \
536536+ elm = RB_RIGHT(elm, field); \
537537+ while ((left = RB_LEFT(elm, field)) != NULL) \
538538+ elm = left; \
539539+ child = RB_RIGHT(elm, field); \
540540+ parent = RB_PARENT(elm, field); \
541541+ color = RB_COLOR(elm, field); \
542542+ if (child) \
543543+ RB_PARENT(child, field) = parent; \
544544+ if (parent) { \
545545+ if (RB_LEFT(parent, field) == elm) \
546546+ RB_LEFT(parent, field) = child; \
547547+ else \
548548+ RB_RIGHT(parent, field) = child; \
549549+ RB_AUGMENT(parent); \
550550+ } else \
551551+ RB_ROOT(head) = child; \
552552+ if (RB_PARENT(elm, field) == old) \
553553+ parent = elm; \
554554+ (elm)->field = (old)->field; \
555555+ if (RB_PARENT(old, field)) { \
556556+ if (RB_LEFT(RB_PARENT(old, field), field) == old)\
557557+ RB_LEFT(RB_PARENT(old, field), field) = elm;\
558558+ else \
559559+ RB_RIGHT(RB_PARENT(old, field), field) = elm;\
560560+ RB_AUGMENT(RB_PARENT(old, field)); \
561561+ } else \
562562+ RB_ROOT(head) = elm; \
563563+ RB_PARENT(RB_LEFT(old, field), field) = elm; \
564564+ if (RB_RIGHT(old, field)) \
565565+ RB_PARENT(RB_RIGHT(old, field), field) = elm; \
566566+ if (parent) { \
567567+ left = parent; \
568568+ do { \
569569+ RB_AUGMENT(left); \
570570+ } while ((left = RB_PARENT(left, field)) != NULL); \
571571+ } \
572572+ goto color; \
573573+ } \
574574+ parent = RB_PARENT(elm, field); \
575575+ color = RB_COLOR(elm, field); \
576576+ if (child) \
577577+ RB_PARENT(child, field) = parent; \
578578+ if (parent) { \
579579+ if (RB_LEFT(parent, field) == elm) \
580580+ RB_LEFT(parent, field) = child; \
581581+ else \
582582+ RB_RIGHT(parent, field) = child; \
583583+ RB_AUGMENT(parent); \
584584+ } else \
585585+ RB_ROOT(head) = child; \
586586+color: \
587587+ if (color == RB_BLACK) \
588588+ name##_RB_REMOVE_COLOR(head, parent, child); \
589589+ return (old); \
590590+} \
591591+ \
592592+/* Inserts a node into the RB tree */ \
593593+attr struct type * \
594594+name##_RB_INSERT(struct name *head, struct type *elm) \
595595+{ \
596596+ struct type *tmp; \
597597+ struct type *parent = NULL; \
598598+ int comp = 0; \
599599+ tmp = RB_ROOT(head); \
600600+ while (tmp) { \
601601+ parent = tmp; \
602602+ comp = (cmp)(elm, parent); \
603603+ if (comp < 0) \
604604+ tmp = RB_LEFT(tmp, field); \
605605+ else if (comp > 0) \
606606+ tmp = RB_RIGHT(tmp, field); \
607607+ else \
608608+ return (tmp); \
609609+ } \
610610+ RB_SET(elm, parent, field); \
611611+ if (parent != NULL) { \
612612+ if (comp < 0) \
613613+ RB_LEFT(parent, field) = elm; \
614614+ else \
615615+ RB_RIGHT(parent, field) = elm; \
616616+ RB_AUGMENT(parent); \
617617+ } else \
618618+ RB_ROOT(head) = elm; \
619619+ name##_RB_INSERT_COLOR(head, elm); \
620620+ return (NULL); \
621621+} \
622622+ \
623623+/* Finds the node with the same key as elm */ \
624624+attr struct type * \
625625+name##_RB_FIND(struct name *head, struct type *elm) \
626626+{ \
627627+ struct type *tmp = RB_ROOT(head); \
628628+ int comp; \
629629+ while (tmp) { \
630630+ comp = cmp(elm, tmp); \
631631+ if (comp < 0) \
632632+ tmp = RB_LEFT(tmp, field); \
633633+ else if (comp > 0) \
634634+ tmp = RB_RIGHT(tmp, field); \
635635+ else \
636636+ return (tmp); \
637637+ } \
638638+ return (NULL); \
639639+} \
640640+ \
641641+/* Finds the first node greater than or equal to the search key */ \
642642+attr struct type * \
643643+name##_RB_NFIND(struct name *head, struct type *elm) \
644644+{ \
645645+ struct type *tmp = RB_ROOT(head); \
646646+ struct type *res = NULL; \
647647+ int comp; \
648648+ while (tmp) { \
649649+ comp = cmp(elm, tmp); \
650650+ if (comp < 0) { \
651651+ res = tmp; \
652652+ tmp = RB_LEFT(tmp, field); \
653653+ } \
654654+ else if (comp > 0) \
655655+ tmp = RB_RIGHT(tmp, field); \
656656+ else \
657657+ return (tmp); \
658658+ } \
659659+ return (res); \
660660+} \
661661+ \
662662+/* ARGSUSED */ \
663663+attr struct type * \
664664+name##_RB_NEXT(struct type *elm) \
665665+{ \
666666+ if (RB_RIGHT(elm, field)) { \
667667+ elm = RB_RIGHT(elm, field); \
668668+ while (RB_LEFT(elm, field)) \
669669+ elm = RB_LEFT(elm, field); \
670670+ } else { \
671671+ if (RB_PARENT(elm, field) && \
672672+ (elm == RB_LEFT(RB_PARENT(elm, field), field))) \
673673+ elm = RB_PARENT(elm, field); \
674674+ else { \
675675+ while (RB_PARENT(elm, field) && \
676676+ (elm == RB_RIGHT(RB_PARENT(elm, field), field)))\
677677+ elm = RB_PARENT(elm, field); \
678678+ elm = RB_PARENT(elm, field); \
679679+ } \
680680+ } \
681681+ return (elm); \
682682+} \
683683+ \
684684+/* ARGSUSED */ \
685685+attr struct type * \
686686+name##_RB_PREV(struct type *elm) \
687687+{ \
688688+ if (RB_LEFT(elm, field)) { \
689689+ elm = RB_LEFT(elm, field); \
690690+ while (RB_RIGHT(elm, field)) \
691691+ elm = RB_RIGHT(elm, field); \
692692+ } else { \
693693+ if (RB_PARENT(elm, field) && \
694694+ (elm == RB_RIGHT(RB_PARENT(elm, field), field))) \
695695+ elm = RB_PARENT(elm, field); \
696696+ else { \
697697+ while (RB_PARENT(elm, field) && \
698698+ (elm == RB_LEFT(RB_PARENT(elm, field), field)))\
699699+ elm = RB_PARENT(elm, field); \
700700+ elm = RB_PARENT(elm, field); \
701701+ } \
702702+ } \
703703+ return (elm); \
704704+} \
705705+ \
706706+attr struct type * \
707707+name##_RB_MINMAX(struct name *head, int val) \
708708+{ \
709709+ struct type *tmp = RB_ROOT(head); \
710710+ struct type *parent = NULL; \
711711+ while (tmp) { \
712712+ parent = tmp; \
713713+ if (val < 0) \
714714+ tmp = RB_LEFT(tmp, field); \
715715+ else \
716716+ tmp = RB_RIGHT(tmp, field); \
717717+ } \
718718+ return (parent); \
719719+}
720720+721721+#define RB_NEGINF -1
722722+#define RB_INF 1
723723+724724+#define RB_INSERT(name, x, y) name##_RB_INSERT(x, y)
725725+#define RB_REMOVE(name, x, y) name##_RB_REMOVE(x, y)
726726+#define RB_FIND(name, x, y) name##_RB_FIND(x, y)
727727+#define RB_NFIND(name, x, y) name##_RB_NFIND(x, y)
728728+#define RB_NEXT(name, x, y) name##_RB_NEXT(y)
729729+#define RB_PREV(name, x, y) name##_RB_PREV(y)
730730+#define RB_MIN(name, x) name##_RB_MINMAX(x, RB_NEGINF)
731731+#define RB_MAX(name, x) name##_RB_MINMAX(x, RB_INF)
732732+733733+#define RB_FOREACH(x, name, head) \
734734+ for ((x) = RB_MIN(name, head); \
735735+ (x) != NULL; \
736736+ (x) = name##_RB_NEXT(x))
737737+738738+#define RB_FOREACH_FROM(x, name, y) \
739739+ for ((x) = (y); \
740740+ ((x) != NULL) && ((y) = name##_RB_NEXT(x), (x) != NULL); \
741741+ (x) = (y))
742742+743743+#define RB_FOREACH_SAFE(x, name, head, y) \
744744+ for ((x) = RB_MIN(name, head); \
745745+ ((x) != NULL) && ((y) = name##_RB_NEXT(x), (x) != NULL); \
746746+ (x) = (y))
747747+748748+#define RB_FOREACH_REVERSE(x, name, head) \
749749+ for ((x) = RB_MAX(name, head); \
750750+ (x) != NULL; \
751751+ (x) = name##_RB_PREV(x))
752752+753753+#define RB_FOREACH_REVERSE_FROM(x, name, y) \
754754+ for ((x) = (y); \
755755+ ((x) != NULL) && ((y) = name##_RB_PREV(x), (x) != NULL); \
756756+ (x) = (y))
757757+758758+#define RB_FOREACH_REVERSE_SAFE(x, name, head, y) \
759759+ for ((x) = RB_MAX(name, head); \
760760+ ((x) != NULL) && ((y) = name##_RB_PREV(x), (x) != NULL); \
761761+ (x) = (y))
762762+763763+#endif /* _SYS_TREE_H_ */
+396
external/libkqueue-2.0.1/src/linux/platform.c
···11+/*
22+ * Copyright (c) 2011 Mark Heily <mark@heily.com>
33+ *
44+ * Permission to use, copy, modify, and distribute this software for any
55+ * purpose with or without fee is hereby granted, provided that the above
66+ * copyright notice and this permission notice appear in all copies.
77+ *
88+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
99+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
1010+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
1111+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
1212+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
1313+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
1414+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
1515+ */
1616+1717+# define _GNU_SOURCE
1818+# include <poll.h>
1919+#include "../common/private.h"
2020+2121+//XXX-FIXME TEMP
2222+const struct filter evfilt_proc = EVFILT_NOTIMPL;
2323+2424+/*
2525+ * Per-thread epoll event buffer used to ferry data between
2626+ * kevent_wait() and kevent_copyout().
2727+ */
2828+static __thread struct epoll_event epevt[MAX_KEVENT];
2929+3030+const struct kqueue_vtable kqops = {
3131+ linux_kqueue_init,
3232+ linux_kqueue_free,
3333+ linux_kevent_wait,
3434+ linux_kevent_copyout,
3535+ NULL,
3636+ NULL,
3737+ linux_eventfd_init,
3838+ linux_eventfd_close,
3939+ linux_eventfd_raise,
4040+ linux_eventfd_lower,
4141+ linux_eventfd_descriptor
4242+};
4343+4444+int
4545+linux_kqueue_init(struct kqueue *kq)
4646+{
4747+ kq->kq_id = epoll_create(1);
4848+ if (kq->kq_id < 0) {
4949+ dbg_perror("epoll_create(2)");
5050+ return (-1);
5151+ }
5252+5353+ if (filter_register_all(kq) < 0) {
5454+ close(kq->kq_id);
5555+ return (-1);
5656+ }
5757+5858+5959+ #if DEADWOOD
6060+ //might be useful in posix
6161+6262+ /* Add each filter's pollable descriptor to the epollset */
6363+ for (i = 0; i < EVFILT_SYSCOUNT; i++) {
6464+ filt = &kq->kq_filt[i];
6565+6666+ if (filt->kf_id == 0)
6767+ continue;
6868+6969+ memset(&ev, 0, sizeof(ev));
7070+ ev.events = EPOLLIN;
7171+ ev.data.ptr = filt;
7272+7373+ if (epoll_ctl(kq->kq_id, EPOLL_CTL_ADD, filt->kf_pfd, &ev) < 0) {
7474+ dbg_perror("epoll_ctl(2)");
7575+ close(kq->kq_id);
7676+ return (-1);
7777+ }
7878+ }
7979+#endif
8080+8181+ return (0);
8282+}
8383+8484+void
8585+linux_kqueue_free(struct kqueue *kq UNUSED)
8686+{
8787+ abort();//FIXME
8888+}
8989+9090+static int
9191+linux_kevent_wait_hires(
9292+ struct kqueue *kq,
9393+ const struct timespec *timeout)
9494+{
9595+ int n;
9696+#if HAVE_DECL_PPOLL
9797+ struct pollfd fds;
9898+9999+ dbg_printf("waiting for events (timeout=%ld sec %ld nsec)",
100100+ timeout->tv_sec, timeout->tv_nsec);
101101+ fds.fd = kqueue_epfd(kq);
102102+ fds.events = POLLIN;
103103+104104+ n = ppoll(&fds, 1, timeout, NULL);
105105+#else
106106+ int epfd;
107107+ fd_set fds;
108108+109109+ dbg_printf("waiting for events (timeout=%ld sec %ld nsec)",
110110+ timeout->tv_sec, timeout->tv_nsec);
111111+112112+ epfd = kqueue_epfd(kq);
113113+ FD_ZERO(&fds);
114114+ FD_SET(epfd, &fds);
115115+ n = pselect(epfd + 1, &fds, NULL , NULL, timeout, NULL);
116116+#endif
117117+118118+ if (n < 0) {
119119+ if (errno == EINTR) {
120120+ dbg_puts("signal caught");
121121+ return (-1);
122122+ }
123123+ dbg_perror("ppoll(2) or pselect(2)");
124124+ return (-1);
125125+ }
126126+ return (n);
127127+}
128128+129129+int
130130+linux_kevent_wait(
131131+ struct kqueue *kq,
132132+ int nevents,
133133+ const struct timespec *ts)
134134+{
135135+ int timeout, nret;
136136+137137+ /* Use a high-resolution syscall if the timeout value is less than one millisecond. */
138138+ if (ts != NULL && ts->tv_sec == 0 && ts->tv_nsec > 0 && ts->tv_nsec < 1000000) {
139139+ nret = linux_kevent_wait_hires(kq, ts);
140140+ if (nret <= 0)
141141+ return (nret);
142142+143143+ /* epoll_wait() should have ready events */
144144+ timeout = 0;
145145+ } else {
146146+ /* Convert timeout to the format used by epoll_wait() */
147147+ if (ts == NULL)
148148+ timeout = -1;
149149+ else
150150+ timeout = (1000 * ts->tv_sec) + (ts->tv_nsec / 1000000);
151151+ }
152152+153153+ dbg_puts("waiting for events");
154154+ nret = epoll_wait(kqueue_epfd(kq), &epevt[0], nevents, timeout);
155155+ if (nret < 0) {
156156+ dbg_perror("epoll_wait");
157157+ return (-1);
158158+ }
159159+160160+ return (nret);
161161+}
162162+163163+int
164164+linux_kevent_copyout(struct kqueue *kq, int nready,
165165+ struct kevent *eventlist, int nevents UNUSED)
166166+{
167167+ struct epoll_event *ev;
168168+ struct filter *filt;
169169+ struct knote *kn;
170170+ int i, nret, rv;
171171+172172+ nret = nready;
173173+ for (i = 0; i < nready; i++) {
174174+ ev = &epevt[i];
175175+ kn = (struct knote *) ev->data.ptr;
176176+ filt = &kq->kq_filt[~(kn->kev.filter)];
177177+ rv = filt->kf_copyout(eventlist, kn, ev);
178178+ if (slowpath(rv < 0)) {
179179+ dbg_puts("knote_copyout failed");
180180+ /* XXX-FIXME: hard to handle this without losing events */
181181+ abort();
182182+ }
183183+184184+ /*
185185+ * Certain flags cause the associated knote to be deleted
186186+ * or disabled.
187187+ */
188188+ if (eventlist->flags & EV_DISPATCH)
189189+ knote_disable(filt, kn); //FIXME: Error checking
190190+ if (eventlist->flags & EV_ONESHOT) {
191191+ knote_delete(filt, kn); //FIXME: Error checking
192192+ }
193193+194194+ /* If an empty kevent structure is returned, the event is discarded. */
195195+ /* TODO: add these semantics to windows + solaris platform.c */
196196+ if (fastpath(eventlist->filter != 0)) {
197197+ eventlist++;
198198+ } else {
199199+ dbg_puts("spurious wakeup, discarding event");
200200+ nret--;
201201+ }
202202+ }
203203+204204+ return (nret);
205205+}
206206+207207+int
208208+linux_eventfd_init(struct eventfd *e)
209209+{
210210+ int evfd;
211211+212212+ evfd = eventfd(0, 0);
213213+ if (evfd < 0) {
214214+ dbg_perror("eventfd");
215215+ return (-1);
216216+ }
217217+ if (fcntl(evfd, F_SETFL, O_NONBLOCK) < 0) {
218218+ dbg_perror("fcntl");
219219+ close(evfd);
220220+ return (-1);
221221+ }
222222+ e->ef_id = evfd;
223223+224224+ return (0);
225225+}
226226+227227+void
228228+linux_eventfd_close(struct eventfd *e)
229229+{
230230+ close(e->ef_id);
231231+ e->ef_id = -1;
232232+}
233233+234234+int
235235+linux_eventfd_raise(struct eventfd *e)
236236+{
237237+ uint64_t counter;
238238+ int rv = 0;
239239+240240+ dbg_puts("raising event level");
241241+ counter = 1;
242242+ if (write(e->ef_id, &counter, sizeof(counter)) < 0) {
243243+ switch (errno) {
244244+ case EAGAIN:
245245+ /* Not considered an error */
246246+ break;
247247+248248+ case EINTR:
249249+ rv = -EINTR;
250250+ break;
251251+252252+ default:
253253+ dbg_printf("write(2): %s", strerror(errno));
254254+ rv = -1;
255255+ }
256256+ }
257257+ return (rv);
258258+}
259259+260260+int
261261+linux_eventfd_lower(struct eventfd *e)
262262+{
263263+ uint64_t cur;
264264+ ssize_t n;
265265+ int rv = 0;
266266+267267+ /* Reset the counter */
268268+ dbg_puts("lowering event level");
269269+ n = read(e->ef_id, &cur, sizeof(cur));
270270+ if (n < 0) {
271271+ switch (errno) {
272272+ case EAGAIN:
273273+ /* Not considered an error */
274274+ break;
275275+276276+ case EINTR:
277277+ rv = -EINTR;
278278+ break;
279279+280280+ default:
281281+ dbg_printf("read(2): %s", strerror(errno));
282282+ rv = -1;
283283+ }
284284+ } else if (n != sizeof(cur)) {
285285+ dbg_puts("short read");
286286+ rv = -1;
287287+ }
288288+289289+ return (rv);
290290+}
291291+292292+int
293293+linux_eventfd_descriptor(struct eventfd *e)
294294+{
295295+ return (e->ef_id);
296296+}
297297+298298+int
299299+linux_get_descriptor_type(struct knote *kn)
300300+{
301301+ socklen_t slen;
302302+ struct stat sb;
303303+ int i, lsock;
304304+305305+ /*
306306+ * Test if the descriptor is a socket.
307307+ */
308308+ if (fstat(kn->kev.ident, &sb) < 0) {
309309+ dbg_perror("fstat(2)");
310310+ return (-1);
311311+ }
312312+ if (S_ISREG(sb.st_mode)) {
313313+ kn->kn_flags |= KNFL_REGULAR_FILE;
314314+ dbg_printf("fd %d is a regular file\n", (int)kn->kev.ident);
315315+ return (0);
316316+ }
317317+318318+ /*
319319+ * Test if the socket is active or passive.
320320+ */
321321+ if (! S_ISSOCK(sb.st_mode))
322322+ return (0);
323323+324324+ slen = sizeof(lsock);
325325+ lsock = 0;
326326+ i = getsockopt(kn->kev.ident, SOL_SOCKET, SO_ACCEPTCONN, (char *) &lsock, &slen);
327327+ if (i < 0) {
328328+ switch (errno) {
329329+ case ENOTSOCK: /* same as lsock = 0 */
330330+ return (0);
331331+ break;
332332+ default:
333333+ dbg_perror("getsockopt(3)");
334334+ return (-1);
335335+ }
336336+ } else {
337337+ if (lsock)
338338+ kn->kn_flags |= KNFL_PASSIVE_SOCKET;
339339+ return (0);
340340+ }
341341+}
342342+343343+char *
344344+epoll_event_dump(struct epoll_event *evt)
345345+{
346346+ static __thread char buf[128];
347347+348348+ if (evt == NULL)
349349+ return "(null)";
350350+351351+#define EPEVT_DUMP(attrib) \
352352+ if (evt->events & attrib) \
353353+ strcat(&buf[0], #attrib" ");
354354+355355+ snprintf(&buf[0], 128, " { data = %p, events = ", evt->data.ptr);
356356+ EPEVT_DUMP(EPOLLIN);
357357+ EPEVT_DUMP(EPOLLOUT);
358358+#if defined(HAVE_EPOLLRDHUP)
359359+ EPEVT_DUMP(EPOLLRDHUP);
360360+#endif
361361+ EPEVT_DUMP(EPOLLONESHOT);
362362+ EPEVT_DUMP(EPOLLET);
363363+ strcat(&buf[0], "}\n");
364364+365365+ return (&buf[0]);
366366+#undef EPEVT_DUMP
367367+}
368368+369369+int
370370+epoll_update(int op, struct filter *filt, struct knote *kn, struct epoll_event *ev)
371371+{
372372+ dbg_printf("op=%d fd=%d events=%s", op, (int)kn->kev.ident,
373373+ epoll_event_dump(ev));
374374+ if (epoll_ctl(filter_epfd(filt), op, kn->kev.ident, ev) < 0) {
375375+ dbg_printf("epoll_ctl(2): %s", strerror(errno));
376376+ return (-1);
377377+ }
378378+379379+ return (0);
380380+}
381381+382382+/*
383383+ * Given a file descriptor, return the path to the file it refers to.
384384+ */
385385+int
386386+linux_fd_to_path(char *buf, size_t bufsz, int fd)
387387+{
388388+ char path[1024]; //TODO: Maxpathlen, etc.
389389+390390+ if (snprintf(&path[0], sizeof(path), "/proc/%d/fd/%d", getpid(), fd) < 0)
391391+ return (-1);
392392+393393+ memset(buf, 0, bufsz);
394394+ return (readlink(path, buf, bufsz));
395395+}
396396+
+104
external/libkqueue-2.0.1/src/linux/platform.h
···11+/*
22+ * Copyright (c) 2011 Mark Heily <mark@heily.com>
33+ *
44+ * Permission to use, copy, modify, and distribute this software for any
55+ * purpose with or without fee is hereby granted, provided that the above
66+ * copyright notice and this permission notice appear in all copies.
77+ *
88+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
99+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
1010+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
1111+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
1212+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
1313+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
1414+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
1515+ */
1616+1717+#ifndef _KQUEUE_LINUX_PLATFORM_H
1818+#define _KQUEUE_LINUX_PLATFORM_H
1919+2020+struct filter;
2121+2222+#include <sys/syscall.h>
2323+#include <sys/epoll.h>
2424+#include <sys/queue.h>
2525+#include <sys/inotify.h>
2626+#if HAVE_SYS_EVENTFD_H
2727+# include <sys/eventfd.h>
2828+#else
2929+# define eventfd(a,b) syscall(SYS_eventfd, (a), (b))
3030+3131+ static inline int eventfd_write(int fd, uint64_t val) {
3232+ if (write(fd, &val, sizeof(val)) < (ssize_t) sizeof(val))
3333+ return (-1);
3434+ else
3535+ return (0);
3636+ }
3737+#endif
3838+#if HAVE_SYS_TIMERFD_H
3939+# include <sys/timerfd.h>
4040+#endif
4141+4242+/*
4343+ * Get the current thread ID
4444+ */
4545+# define _GNU_SOURCE
4646+# include <linux/unistd.h>
4747+# include <unistd.h>
4848+#ifndef __ANDROID__
4949+extern long int syscall (long int __sysno, ...);
5050+#endif
5151+5252+/* Convenience macros to access the epoll descriptor for the kqueue */
5353+#define kqueue_epfd(kq) ((kq)->kq_id)
5454+#define filter_epfd(filt) ((filt)->kf_kqueue->kq_id)
5555+5656+/*
5757+ * Additional members of struct filter
5858+ */
5959+#undef FILTER_PLATFORM_SPECIFIC
6060+6161+/*
6262+ * Additional members of struct knote
6363+ */
6464+#define KNOTE_PLATFORM_SPECIFIC \
6565+ int kn_epollfd; /* A copy of filter->epfd */ \
6666+ union { \
6767+ int kn_timerfd; \
6868+ int kn_signalfd; \
6969+ int kn_inotifyfd; \
7070+ int kn_eventfd; \
7171+ } kdata
7272+7373+/*
7474+ * Additional members of struct kqueue
7575+ */
7676+#define KQUEUE_PLATFORM_SPECIFIC \
7777+ struct epoll_event kq_plist[MAX_KEVENT]; \
7878+ size_t kq_nplist
7979+8080+int linux_kqueue_init(struct kqueue *);
8181+void linux_kqueue_free(struct kqueue *);
8282+8383+int linux_kevent_wait(struct kqueue *, int, const struct timespec *);
8484+int linux_kevent_copyout(struct kqueue *, int, struct kevent *, int);
8585+8686+int linux_knote_copyout(struct kevent *, struct knote *);
8787+8888+int linux_eventfd_init(struct eventfd *);
8989+void linux_eventfd_close(struct eventfd *);
9090+int linux_eventfd_raise(struct eventfd *);
9191+int linux_eventfd_lower(struct eventfd *);
9292+int linux_eventfd_descriptor(struct eventfd *);
9393+9494+/* utility functions */
9595+9696+int linux_get_descriptor_type(struct knote *);
9797+int linux_fd_to_path(char *, size_t, int);
9898+9999+/* epoll-related functions */
100100+101101+int epoll_update(int, struct filter *, struct knote *, struct epoll_event *);
102102+char * epoll_event_dump(struct epoll_event *);
103103+104104+#endif /* ! _KQUEUE_LINUX_PLATFORM_H */
+269
external/libkqueue-2.0.1/src/linux/read.c
···11+/*
22+ * Copyright (c) 2009 Mark Heily <mark@heily.com>
33+ *
44+ * Permission to use, copy, modify, and distribute this software for any
55+ * purpose with or without fee is hereby granted, provided that the above
66+ * copyright notice and this permission notice appear in all copies.
77+ *
88+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
99+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
1010+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
1111+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
1212+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
1313+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
1414+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
1515+ */
1616+1717+#include <errno.h>
1818+#include <fcntl.h>
1919+#include <linux/sockios.h>
2020+#include <pthread.h>
2121+#include <signal.h>
2222+#include <stdlib.h>
2323+#include <stdio.h>
2424+#include <sys/ioctl.h>
2525+#include <sys/queue.h>
2626+#include <sys/socket.h>
2727+#include <sys/types.h>
2828+#include <string.h>
2929+#include <unistd.h>
3030+3131+#include "private.h"
3232+3333+/*
3434+ * Return the offset from the current position to end of file.
3535+ */
3636+static intptr_t
3737+get_eof_offset(int fd)
3838+{
3939+ off_t curpos;
4040+ struct stat sb;
4141+4242+ curpos = lseek(fd, 0, SEEK_CUR);
4343+ if (curpos == (off_t) -1) {
4444+ dbg_perror("lseek(2)");
4545+ curpos = 0;
4646+ }
4747+ if (fstat(fd, &sb) < 0) {
4848+ dbg_perror("fstat(2)");
4949+ sb.st_size = 1;
5050+ }
5151+5252+ dbg_printf("curpos=%zu size=%zu\n", (size_t)curpos, (size_t)sb.st_size);
5353+ return (sb.st_size - curpos); //FIXME: can overflow
5454+}
5555+5656+int
5757+evfilt_read_copyout(struct kevent *dst, struct knote *src, void *ptr)
5858+{
5959+ struct epoll_event * const ev = (struct epoll_event *) ptr;
6060+6161+ /* Special case: for regular files, return the offset from current position to end of file */
6262+ if (src->kn_flags & KNFL_REGULAR_FILE) {
6363+ memcpy(dst, &src->kev, sizeof(*dst));
6464+ dst->data = get_eof_offset(src->kev.ident);
6565+6666+ if (dst->data == 0) {
6767+ dst->filter = 0; /* Will cause the kevent to be discarded */
6868+ if (epoll_ctl(src->kn_epollfd, EPOLL_CTL_DEL, src->kdata.kn_eventfd, NULL) < 0) {
6969+ dbg_perror("epoll_ctl(2)");
7070+ return (-1);
7171+ }
7272+7373+#if FIXME
7474+ /* XXX-FIXME Switch to using kn_inotifyfd to monitor for IN_ATTRIB events
7575+ that may signify the file size has changed.
7676+7777+ This code is not tested.
7878+ */
7979+ int inofd;
8080+ char path[PATH_MAX];
8181+8282+ inofd = inotify_init();
8383+ if (inofd < 0) {
8484+ dbg_perror("inotify_init(2)");
8585+ (void) close(inofd);
8686+ return (-1);
8787+ }
8888+ src->kdata.kn_inotifyfd = inofd;
8989+ if (linux_fd_to_path(&path[0], sizeof(path), src->kev.ident) < 0)
9090+ return (-1);
9191+ if (inotify_add_watch(inofd, path, IN_ATTRIB) < 0) {
9292+ dbg_perror("inotify_add_watch");
9393+ return (-1);
9494+ }
9595+ if (epoll_ctl(src->kn_epollfd, EPOLL_CTL_ADD, src->kdata.kn_inotifyfd, NULL) < 0) {
9696+ dbg_perror("epoll_ctl(2)");
9797+ return (-1);
9898+ }
9999+ /* FIXME: race here, should we check the EOF status again ? */
100100+#endif
101101+ }
102102+103103+ return (0);
104104+ }
105105+106106+ dbg_printf("epoll: %s", epoll_event_dump(ev));
107107+ memcpy(dst, &src->kev, sizeof(*dst));
108108+#if defined(HAVE_EPOLLRDHUP)
109109+ if (ev->events & EPOLLRDHUP || ev->events & EPOLLHUP)
110110+ dst->flags |= EV_EOF;
111111+#else
112112+ if (ev->events & EPOLLHUP)
113113+ dst->flags |= EV_EOF;
114114+#endif
115115+ if (ev->events & EPOLLERR)
116116+ dst->fflags = 1; /* FIXME: Return the actual socket error */
117117+118118+ if (src->kn_flags & KNFL_PASSIVE_SOCKET) {
119119+ /* On return, data contains the length of the
120120+ socket backlog. This is not available under Linux.
121121+ */
122122+ dst->data = 1;
123123+ } else {
124124+ /* On return, data contains the number of bytes of protocol
125125+ data available to read.
126126+ */
127127+ if (ioctl(dst->ident, SIOCINQ, &dst->data) < 0) {
128128+ /* race condition with socket close, so ignore this error */
129129+ dbg_puts("ioctl(2) of socket failed");
130130+ dst->data = 0;
131131+ } else {
132132+ if (dst->data == 0)
133133+ dst->flags |= EV_EOF;
134134+ }
135135+ }
136136+137137+ return (0);
138138+}
139139+140140+int
141141+evfilt_read_knote_create(struct filter *filt, struct knote *kn)
142142+{
143143+ struct epoll_event ev;
144144+145145+ if (linux_get_descriptor_type(kn) < 0)
146146+ return (-1);
147147+148148+ /* Convert the kevent into an epoll_event */
149149+#if defined(HAVE_EPOLLRDHUP)
150150+ kn->data.events = EPOLLIN | EPOLLRDHUP;
151151+#else
152152+ kn->data.events = EPOLLIN;
153153+#endif
154154+ if (kn->kev.flags & EV_ONESHOT || kn->kev.flags & EV_DISPATCH)
155155+ kn->data.events |= EPOLLONESHOT;
156156+ if (kn->kev.flags & EV_CLEAR)
157157+ kn->data.events |= EPOLLET;
158158+159159+ memset(&ev, 0, sizeof(ev));
160160+ ev.events = kn->data.events;
161161+ ev.data.ptr = kn;
162162+163163+ /* Special case: for regular files, add a surrogate eventfd that is always readable */
164164+ if (kn->kn_flags & KNFL_REGULAR_FILE) {
165165+ int evfd;
166166+167167+ kn->kn_epollfd = filter_epfd(filt);
168168+ evfd = eventfd(0, 0);
169169+ if (evfd < 0) {
170170+ dbg_perror("eventfd(2)");
171171+ return (-1);
172172+ }
173173+ if (eventfd_write(evfd, 1) < 0) {
174174+ dbg_perror("eventfd_write(3)");
175175+ (void) close(evfd);
176176+ return (-1);
177177+ }
178178+179179+ kn->kdata.kn_eventfd = evfd;
180180+181181+ if (epoll_ctl(kn->kn_epollfd, EPOLL_CTL_ADD, kn->kdata.kn_eventfd, &ev) < 0) {
182182+ dbg_printf("epoll_ctl(2): %s", strerror(errno));
183183+ return (-1);
184184+ }
185185+ return (0);
186186+ }
187187+188188+ return epoll_update(EPOLL_CTL_ADD, filt, kn, &ev);
189189+}
190190+191191+int
192192+evfilt_read_knote_modify(struct filter *filt, struct knote *kn,
193193+ const struct kevent *kev)
194194+{
195195+ (void) filt;
196196+ (void) kn;
197197+ (void) kev;
198198+ return (-1); /* STUB */
199199+}
200200+201201+int
202202+evfilt_read_knote_delete(struct filter *filt, struct knote *kn)
203203+{
204204+ if (kn->kev.flags & EV_DISABLE)
205205+ return (0);
206206+207207+ if ((kn->kn_flags & KNFL_REGULAR_FILE && kn->kdata.kn_eventfd != -1) < 0) {
208208+ if (epoll_ctl(kn->kn_epollfd, EPOLL_CTL_DEL, kn->kdata.kn_eventfd, NULL) < 0) {
209209+ dbg_perror("epoll_ctl(2)");
210210+ return (-1);
211211+ }
212212+ (void) close(kn->kdata.kn_eventfd);
213213+ kn->kdata.kn_eventfd = -1;
214214+ } else {
215215+ return epoll_update(EPOLL_CTL_DEL, filt, kn, NULL);
216216+ }
217217+218218+ // clang will complain about not returning a value otherwise
219219+ return (-1);
220220+}
221221+222222+int
223223+evfilt_read_knote_enable(struct filter *filt, struct knote *kn)
224224+{
225225+ struct epoll_event ev;
226226+227227+ memset(&ev, 0, sizeof(ev));
228228+ ev.events = kn->data.events;
229229+ ev.data.ptr = kn;
230230+231231+ if (kn->kn_flags & KNFL_REGULAR_FILE) {
232232+ if (epoll_ctl(kn->kn_epollfd, EPOLL_CTL_ADD, kn->kdata.kn_eventfd, &ev) < 0) {
233233+ dbg_perror("epoll_ctl(2)");
234234+ return (-1);
235235+ }
236236+ return (0);
237237+ } else {
238238+ return epoll_update(EPOLL_CTL_ADD, filt, kn, &ev);
239239+ }
240240+241241+ // clang will complain about not returning a value otherwise
242242+ return (-1);
243243+}
244244+245245+int
246246+evfilt_read_knote_disable(struct filter *filt, struct knote *kn)
247247+{
248248+ if (kn->kn_flags & KNFL_REGULAR_FILE) {
249249+ if (epoll_ctl(kn->kn_epollfd, EPOLL_CTL_DEL, kn->kdata.kn_eventfd, NULL) < 0) {
250250+ dbg_perror("epoll_ctl(2)");
251251+ return (-1);
252252+ }
253253+ return (0);
254254+ } else {
255255+ return epoll_update(EPOLL_CTL_DEL, filt, kn, NULL);
256256+ }
257257+}
258258+259259+const struct filter evfilt_read = {
260260+ EVFILT_READ,
261261+ NULL,
262262+ NULL,
263263+ evfilt_read_copyout,
264264+ evfilt_read_knote_create,
265265+ evfilt_read_knote_modify,
266266+ evfilt_read_knote_delete,
267267+ evfilt_read_knote_enable,
268268+ evfilt_read_knote_disable,
269269+};
+218
external/libkqueue-2.0.1/src/linux/signal.c
···11+/*
22+ * Copyright (c) 2009 Mark Heily <mark@heily.com>
33+ *
44+ * Permission to use, copy, modify, and distribute this software for any
55+ * purpose with or without fee is hereby granted, provided that the above
66+ * copyright notice and this permission notice appear in all copies.
77+ *
88+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
99+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
1010+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
1111+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
1212+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
1313+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
1414+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
1515+ */
1616+1717+#include "private.h"
1818+1919+#if HAVE_SYS_SIGNALFD_H
2020+# include <sys/signalfd.h>
2121+#else
2222+#define signalfd(a,b,c) syscall(SYS_signalfd, (a), (b), (c))
2323+#define SFD_NONBLOCK 04000
2424+struct signalfd_siginfo
2525+{
2626+ uint32_t ssi_signo;
2727+ int32_t ssi_errno;
2828+ int32_t ssi_code;
2929+ uint32_t ssi_pid;
3030+ uint32_t ssi_uid;
3131+ int32_t ssi_fd;
3232+ uint32_t ssi_tid;
3333+ uint32_t ssi_band;
3434+ uint32_t ssi_overrun;
3535+ uint32_t ssi_trapno;
3636+ int32_t ssi_status;
3737+ int32_t ssi_int;
3838+ uint64_t ssi_ptr;
3939+ uint64_t ssi_utime;
4040+ uint64_t ssi_stime;
4141+ uint64_t ssi_addr;
4242+ uint8_t __pad[48];
4343+};
4444+#endif
4545+4646+static void
4747+signalfd_reset(int sigfd)
4848+{
4949+ struct signalfd_siginfo sig;
5050+ ssize_t n;
5151+5252+ /* Discard any pending signal */
5353+ n = read(sigfd, &sig, sizeof(sig));
5454+ if (n < 0 || n != sizeof(sig)) {
5555+ if (errno == EWOULDBLOCK)
5656+ return;
5757+ //FIXME: eintr?
5858+ dbg_perror("read(2) from signalfd");
5959+ abort();
6060+ }
6161+}
6262+6363+static int
6464+signalfd_add(int epfd, int sigfd, void *ptr)
6565+{
6666+ struct epoll_event ev;
6767+ int rv;
6868+6969+ /* Add the signalfd to the kqueue's epoll descriptor set */
7070+ memset(&ev, 0, sizeof(ev));
7171+ ev.events = EPOLLIN;
7272+ ev.data.ptr = ptr;
7373+ rv = epoll_ctl(epfd, EPOLL_CTL_ADD, sigfd, &ev);
7474+ if (rv < 0) {
7575+ dbg_perror("epoll_ctl(2)");
7676+ return (-1);
7777+ }
7878+7979+ return (0);
8080+}
8181+8282+static int
8383+signalfd_create(int epfd, void *ptr, int signum)
8484+{
8585+ static int flags = SFD_NONBLOCK;
8686+ sigset_t sigmask;
8787+ int sigfd;
8888+8989+ /* Create a signalfd */
9090+ sigemptyset(&sigmask);
9191+ sigaddset(&sigmask, signum);
9292+ sigfd = signalfd(-1, &sigmask, flags);
9393+9494+ /* WORKAROUND: Flags are broken on kernels older than Linux 2.6.27 */
9595+ if (sigfd < 0 && errno == EINVAL && flags != 0) {
9696+ flags = 0;
9797+ sigfd = signalfd(-1, &sigmask, flags);
9898+ }
9999+ if (sigfd < 0) {
100100+ dbg_perror("signalfd(2)");
101101+ goto errout;
102102+ }
103103+104104+ /* Block the signal handler from being invoked */
105105+ if (sigprocmask(SIG_BLOCK, &sigmask, NULL) < 0) {
106106+ dbg_perror("sigprocmask(2)");
107107+ goto errout;
108108+ }
109109+110110+ signalfd_reset(sigfd);
111111+112112+ if (signalfd_add(epfd, sigfd, ptr) < 0)
113113+ goto errout;
114114+115115+ dbg_printf("added sigfd %d to epfd %d (signum=%d)", sigfd, epfd, signum);
116116+117117+ return (sigfd);
118118+119119+errout:
120120+ (void) close(sigfd);
121121+ return (-1);
122122+}
123123+124124+int
125125+evfilt_signal_copyout(struct kevent *dst, struct knote *src, void *x UNUSED)
126126+{
127127+ int sigfd;
128128+129129+ sigfd = src->kdata.kn_signalfd;
130130+131131+ signalfd_reset(sigfd);
132132+133133+ memcpy(dst, &src->kev, sizeof(*dst));
134134+ /* NOTE: dst->data should be the number of times the signal occurred,
135135+ but that information is not available.
136136+ */
137137+ dst->data = 1;
138138+139139+ return (0);
140140+}
141141+142142+int
143143+evfilt_signal_knote_create(struct filter *filt, struct knote *kn)
144144+{
145145+ int fd;
146146+147147+ fd = signalfd_create(filter_epfd(filt), kn, kn->kev.ident);
148148+ if (fd > 0) {
149149+ kn->kev.flags |= EV_CLEAR;
150150+ kn->kdata.kn_signalfd = fd;
151151+ return (0);
152152+ } else {
153153+ kn->kdata.kn_signalfd = -1;
154154+ return (-1);
155155+ }
156156+}
157157+158158+int
159159+evfilt_signal_knote_modify(struct filter *filt UNUSED,
160160+ struct knote *kn UNUSED,
161161+ const struct kevent *kev UNUSED)
162162+{
163163+ /* Nothing to do since the signal number does not change. */
164164+165165+ return (0);
166166+}
167167+168168+int
169169+evfilt_signal_knote_delete(struct filter *filt, struct knote *kn)
170170+{
171171+ const int sigfd = kn->kdata.kn_signalfd;
172172+173173+ /* Needed so that delete() can be called after disable() */
174174+ if (kn->kdata.kn_signalfd == -1)
175175+ return (0);
176176+177177+ if (epoll_ctl(filter_epfd(filt), EPOLL_CTL_DEL, sigfd, NULL) < 0) {
178178+ dbg_perror("epoll_ctl(2)");
179179+ return (-1);
180180+ }
181181+182182+ if (close(sigfd) < 0) {
183183+ dbg_perror("close(2)");
184184+ return (-1);
185185+ }
186186+187187+ /* NOTE: This does not call sigprocmask(3) to unblock the signal. */
188188+ kn->kdata.kn_signalfd = -1;
189189+190190+ return (0);
191191+}
192192+193193+int
194194+evfilt_signal_knote_enable(struct filter *filt, struct knote *kn)
195195+{
196196+ dbg_printf("enabling ident %u", (unsigned int) kn->kev.ident);
197197+ return evfilt_signal_knote_create(filt, kn);
198198+}
199199+200200+int
201201+evfilt_signal_knote_disable(struct filter *filt, struct knote *kn)
202202+{
203203+ dbg_printf("disabling ident %u", (unsigned int) kn->kev.ident);
204204+ return evfilt_signal_knote_delete(filt, kn);
205205+}
206206+207207+208208+const struct filter evfilt_signal = {
209209+ EVFILT_SIGNAL,
210210+ NULL,
211211+ NULL,
212212+ evfilt_signal_copyout,
213213+ evfilt_signal_knote_create,
214214+ evfilt_signal_knote_modify,
215215+ evfilt_signal_knote_delete,
216216+ evfilt_signal_knote_enable,
217217+ evfilt_signal_knote_disable,
218218+};
+219
external/libkqueue-2.0.1/src/linux/timer.c
···11+/*
22+ * Copyright (c) 2009 Mark Heily <mark@heily.com>
33+ *
44+ * Permission to use, copy, modify, and distribute this software for any
55+ * purpose with or without fee is hereby granted, provided that the above
66+ * copyright notice and this permission notice appear in all copies.
77+ *
88+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
99+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
1010+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
1111+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
1212+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
1313+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
1414+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
1515+ */
1616+1717+#include "private.h"
1818+1919+#ifndef HAVE_SYS_TIMERFD_H
2020+2121+/* Android 4.0 does not have this header, but the kernel supports timerfds */
2222+#ifndef SYS_timerfd_create
2323+#ifdef __ARM_EABI__
2424+#define __NR_timerfd_create (__NR_SYSCALL_BASE+350)
2525+#define __NR_timerfd_settime (__NR_SYSCALL_BASE+353)
2626+#define __NR_timerfd_gettime (__NR_SYSCALL_BASE+354)
2727+#else
2828+#error Unsupported architecture, need to get the syscall numbers
2929+#endif
3030+3131+#define SYS_timerfd_create __NR_timerfd_create
3232+#define SYS_timerfd_settime __NR_timerfd_settime
3333+#define SYS_timerfd_gettime __NR_timerfd_gettime
3434+#endif /* ! SYS_timerfd_create */
3535+3636+/* XXX-FIXME
3737+ These are horrible hacks that are only known to be true on RHEL 5 x86.
3838+ */
3939+#ifndef SYS_timerfd_settime
4040+#define SYS_timerfd_settime (SYS_timerfd_create + 1)
4141+#endif
4242+#ifndef SYS_timerfd_gettime
4343+#define SYS_timerfd_gettime (SYS_timerfd_create + 2)
4444+#endif
4545+4646+int timerfd_create(int clockid, int flags)
4747+{
4848+ return syscall(SYS_timerfd_create, clockid, flags);
4949+}
5050+5151+int timerfd_settime(int ufc, int flags, const struct itimerspec *utmr,
5252+ struct itimerspec *otmr)
5353+{
5454+ return syscall(SYS_timerfd_settime, ufc, flags, utmr, otmr);
5555+}
5656+5757+int timerfd_gettime(int ufc, struct itimerspec *otmr)
5858+{
5959+ return syscall(SYS_timerfd_gettime, ufc, otmr);
6060+}
6161+6262+#endif
6363+6464+#ifndef NDEBUG
6565+static char *
6666+itimerspec_dump(struct itimerspec *ts)
6767+{
6868+ static __thread char buf[1024];
6969+7070+ snprintf(buf, sizeof(buf),
7171+ "itimer: [ interval=%lu s %lu ns, next expire=%lu s %lu ns ]",
7272+ ts->it_interval.tv_sec,
7373+ ts->it_interval.tv_nsec,
7474+ ts->it_value.tv_sec,
7575+ ts->it_value.tv_nsec
7676+ );
7777+7878+ return (buf);
7979+}
8080+#endif
8181+8282+/* Convert milliseconds into seconds+nanoseconds */
8383+static void
8484+convert_msec_to_itimerspec(struct itimerspec *dst, int src, int oneshot)
8585+{
8686+ time_t sec, nsec;
8787+8888+ sec = src / 1000;
8989+ nsec = (src % 1000) * 1000000;
9090+9191+ /* Set the interval */
9292+ if (oneshot) {
9393+ dst->it_interval.tv_sec = 0;
9494+ dst->it_interval.tv_nsec = 0;
9595+ } else {
9696+ dst->it_interval.tv_sec = sec;
9797+ dst->it_interval.tv_nsec = nsec;
9898+ }
9999+100100+ /* Set the initial expiration */
101101+ dst->it_value.tv_sec = sec;
102102+ dst->it_value.tv_nsec = nsec;
103103+ dbg_printf("%s", itimerspec_dump(dst));
104104+}
105105+106106+int
107107+evfilt_timer_copyout(struct kevent *dst, struct knote *src, void *ptr)
108108+{
109109+ struct epoll_event * const ev = (struct epoll_event *) ptr;
110110+ uint64_t expired;
111111+ ssize_t n;
112112+113113+ memcpy(dst, &src->kev, sizeof(*dst));
114114+ if (ev->events & EPOLLERR)
115115+ dst->fflags = 1; /* FIXME: Return the actual timer error */
116116+117117+ /* On return, data contains the number of times the
118118+ timer has been trigered.
119119+ */
120120+ n = read(src->data.pfd, &expired, sizeof(expired));
121121+ if (n != sizeof(expired)) {
122122+ dbg_puts("invalid read from timerfd");
123123+ expired = 1; /* Fail gracefully */
124124+ }
125125+ dst->data = expired;
126126+127127+ return (0);
128128+}
129129+130130+int
131131+evfilt_timer_knote_create(struct filter *filt, struct knote *kn)
132132+{
133133+ struct epoll_event ev;
134134+ struct itimerspec ts;
135135+ int tfd;
136136+137137+ kn->kev.flags |= EV_CLEAR;
138138+139139+ tfd = timerfd_create(CLOCK_MONOTONIC, 0);
140140+ if (tfd < 0) {
141141+ dbg_printf("timerfd_create(2): %s", strerror(errno));
142142+ return (-1);
143143+ }
144144+ dbg_printf("created timerfd %d", tfd);
145145+146146+ convert_msec_to_itimerspec(&ts, kn->kev.data, kn->kev.flags & EV_ONESHOT);
147147+ if (timerfd_settime(tfd, 0, &ts, NULL) < 0) {
148148+ dbg_printf("timerfd_settime(2): %s", strerror(errno));
149149+ close(tfd);
150150+ return (-1);
151151+ }
152152+153153+ memset(&ev, 0, sizeof(ev));
154154+ ev.events = EPOLLIN;
155155+ ev.data.ptr = kn;
156156+ if (epoll_ctl(filter_epfd(filt), EPOLL_CTL_ADD, tfd, &ev) < 0) {
157157+ dbg_printf("epoll_ctl(2): %d", errno);
158158+ close(tfd);
159159+ return (-1);
160160+ }
161161+162162+ kn->data.pfd = tfd;
163163+ return (0);
164164+}
165165+166166+int
167167+evfilt_timer_knote_modify(struct filter *filt, struct knote *kn,
168168+ const struct kevent *kev)
169169+{
170170+ (void)filt;
171171+ (void)kn;
172172+ (void)kev;
173173+ return (0); /* STUB */
174174+}
175175+176176+int
177177+evfilt_timer_knote_delete(struct filter *filt, struct knote *kn)
178178+{
179179+ int rv = 0;
180180+181181+ if (kn->data.pfd == -1)
182182+ return (0);
183183+184184+ if (epoll_ctl(filter_epfd(filt), EPOLL_CTL_DEL, kn->data.pfd, NULL) < 0) {
185185+ dbg_printf("epoll_ctl(2): %s", strerror(errno));
186186+ rv = -1;
187187+ }
188188+ if (close(kn->data.pfd) < 0) {
189189+ dbg_printf("close(2): %s", strerror(errno));
190190+ rv = -1;
191191+ }
192192+193193+ kn->data.pfd = -1;
194194+ return (rv);
195195+}
196196+197197+int
198198+evfilt_timer_knote_enable(struct filter *filt, struct knote *kn)
199199+{
200200+ return evfilt_timer_knote_create(filt, kn);
201201+}
202202+203203+int
204204+evfilt_timer_knote_disable(struct filter *filt, struct knote *kn)
205205+{
206206+ return evfilt_timer_knote_delete(filt, kn);
207207+}
208208+209209+const struct filter evfilt_timer = {
210210+ EVFILT_TIMER,
211211+ NULL,
212212+ NULL,
213213+ evfilt_timer_copyout,
214214+ evfilt_timer_knote_create,
215215+ evfilt_timer_knote_modify,
216216+ evfilt_timer_knote_delete,
217217+ evfilt_timer_knote_enable,
218218+ evfilt_timer_knote_disable,
219219+};
+230
external/libkqueue-2.0.1/src/linux/user.c
···11+/*
22+ * Copyright (c) 2009 Mark Heily <mark@heily.com>
33+ *
44+ * Permission to use, copy, modify, and distribute this software for any
55+ * purpose with or without fee is hereby granted, provided that the above
66+ * copyright notice and this permission notice appear in all copies.
77+ *
88+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
99+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
1010+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
1111+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
1212+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
1313+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
1414+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
1515+ */
1616+1717+#include <errno.h>
1818+#include <fcntl.h>
1919+#include <pthread.h>
2020+#include <signal.h>
2121+#include <stdlib.h>
2222+#include <stdio.h>
2323+#include <sys/queue.h>
2424+#include <sys/socket.h>
2525+#include <sys/types.h>
2626+#include <string.h>
2727+#include <unistd.h>
2828+2929+#include "sys/event.h"
3030+#include "private.h"
3131+3232+/* NOTE: copy+pasted from linux_eventfd_raise() */
3333+static int
3434+eventfd_raise(int evfd)
3535+{
3636+ uint64_t counter;
3737+ int rv = 0;
3838+3939+ dbg_puts("raising event level");
4040+ counter = 1;
4141+ if (write(evfd, &counter, sizeof(counter)) < 0) {
4242+ switch (errno) {
4343+ case EAGAIN:
4444+ /* Not considered an error */
4545+ break;
4646+4747+ case EINTR:
4848+ rv = -EINTR;
4949+ break;
5050+5151+ default:
5252+ dbg_printf("write(2): %s", strerror(errno));
5353+ rv = -1;
5454+ }
5555+ }
5656+ return (rv);
5757+}
5858+5959+/* NOTE: copy+pasted from linux_eventfd_lower() */
6060+static int
6161+eventfd_lower(int evfd)
6262+{
6363+ uint64_t cur;
6464+ ssize_t n;
6565+ int rv = 0;
6666+6767+ /* Reset the counter */
6868+ dbg_puts("lowering event level");
6969+ n = read(evfd, &cur, sizeof(cur));
7070+ if (n < 0) {
7171+ switch (errno) {
7272+ case EAGAIN:
7373+ /* Not considered an error */
7474+ break;
7575+7676+ case EINTR:
7777+ rv = -EINTR;
7878+ break;
7979+8080+ default:
8181+ dbg_printf("read(2): %s", strerror(errno));
8282+ rv = -1;
8383+ }
8484+ } else if (n != sizeof(cur)) {
8585+ dbg_puts("short read");
8686+ rv = -1;
8787+ }
8888+8989+ return (rv);
9090+}
9191+9292+int
9393+linux_evfilt_user_copyout(struct kevent *dst, struct knote *src, void *ptr UNUSED)
9494+{
9595+ memcpy(dst, &src->kev, sizeof(*dst));
9696+ dst->fflags &= ~NOTE_FFCTRLMASK; //FIXME: Not sure if needed
9797+ dst->fflags &= ~NOTE_TRIGGER;
9898+ if (src->kev.flags & EV_ADD) {
9999+ /* NOTE: True on FreeBSD but not consistent behavior with
100100+ other filters. */
101101+ dst->flags &= ~EV_ADD;
102102+ }
103103+ if (src->kev.flags & EV_CLEAR)
104104+ src->kev.fflags &= ~NOTE_TRIGGER;
105105+ if (src->kev.flags & (EV_DISPATCH | EV_CLEAR | EV_ONESHOT)) {
106106+ if (eventfd_lower(src->kdata.kn_eventfd) < 0)
107107+ return (-1);
108108+ }
109109+110110+ if (src->kev.flags & EV_DISPATCH)
111111+ src->kev.fflags &= ~NOTE_TRIGGER;
112112+113113+ return (0);
114114+}
115115+116116+int
117117+linux_evfilt_user_knote_create(struct filter *filt, struct knote *kn)
118118+{
119119+ struct epoll_event ev;
120120+ int evfd;
121121+122122+ /* Create an eventfd */
123123+ evfd = eventfd(0, 0);
124124+ if (evfd < 0) {
125125+ dbg_perror("eventfd");
126126+ goto errout;
127127+ }
128128+129129+ /* Add the eventfd to the epoll set */
130130+ memset(&ev, 0, sizeof(ev));
131131+ ev.events = EPOLLIN;
132132+ ev.data.ptr = kn;
133133+ if (epoll_ctl(filter_epfd(filt), EPOLL_CTL_ADD, evfd, &ev) < 0) {
134134+ dbg_perror("epoll_ctl(2)");
135135+ goto errout;
136136+ }
137137+138138+ kn->kdata.kn_eventfd = evfd;
139139+140140+ return (0);
141141+142142+errout:
143143+ (void) close(evfd);
144144+ kn->kdata.kn_eventfd = -1;
145145+ return (-1);
146146+}
147147+148148+int
149149+linux_evfilt_user_knote_modify(struct filter *filt UNUSED, struct knote *kn,
150150+ const struct kevent *kev)
151151+{
152152+ unsigned int ffctrl;
153153+ unsigned int fflags;
154154+155155+ /* Excerpted from sys/kern/kern_event.c in FreeBSD HEAD */
156156+ ffctrl = kev->fflags & NOTE_FFCTRLMASK;
157157+ fflags = kev->fflags & NOTE_FFLAGSMASK;
158158+ switch (ffctrl) {
159159+ case NOTE_FFNOP:
160160+ break;
161161+162162+ case NOTE_FFAND:
163163+ kn->kev.fflags &= fflags;
164164+ break;
165165+166166+ case NOTE_FFOR:
167167+ kn->kev.fflags |= fflags;
168168+ break;
169169+170170+ case NOTE_FFCOPY:
171171+ kn->kev.fflags = fflags;
172172+ break;
173173+174174+ default:
175175+ /* XXX Return error? */
176176+ break;
177177+ }
178178+179179+ if ((!(kn->kev.flags & EV_DISABLE)) && kev->fflags & NOTE_TRIGGER) {
180180+ kn->kev.fflags |= NOTE_TRIGGER;
181181+ if (eventfd_raise(kn->kdata.kn_eventfd) < 0)
182182+ return (-1);
183183+ }
184184+185185+ return (0);
186186+}
187187+188188+int
189189+linux_evfilt_user_knote_delete(struct filter *filt, struct knote *kn)
190190+{
191191+ if (epoll_ctl(filter_epfd(filt), EPOLL_CTL_DEL,
192192+ kn->kdata.kn_eventfd, NULL) < 0) {
193193+ dbg_perror("epoll_ctl(2)");
194194+ return (-1);
195195+ }
196196+ if (close(kn->kdata.kn_eventfd) < 0) {
197197+ dbg_perror("close(2)");
198198+ return (-1);
199199+ }
200200+ dbg_printf("removed eventfd %d from the epollfd", kn->kdata.kn_eventfd);
201201+ kn->kdata.kn_eventfd = -1;
202202+203203+ return (0);
204204+}
205205+206206+int
207207+linux_evfilt_user_knote_enable(struct filter *filt, struct knote *kn)
208208+{
209209+ /* FIXME: what happens if NOTE_TRIGGER is in fflags?
210210+ should the event fire? */
211211+ return linux_evfilt_user_knote_create(filt, kn);
212212+}
213213+214214+int
215215+linux_evfilt_user_knote_disable(struct filter *filt, struct knote *kn)
216216+{
217217+ return linux_evfilt_user_knote_delete(filt, kn);
218218+}
219219+220220+const struct filter evfilt_user = {
221221+ EVFILT_USER,
222222+ NULL,
223223+ NULL,
224224+ linux_evfilt_user_copyout,
225225+ linux_evfilt_user_knote_create,
226226+ linux_evfilt_user_knote_modify,
227227+ linux_evfilt_user_knote_delete,
228228+ linux_evfilt_user_knote_enable,
229229+ linux_evfilt_user_knote_disable,
230230+};
+292
external/libkqueue-2.0.1/src/linux/vnode.c
···11+/*
22+ * Copyright (c) 2009 Mark Heily <mark@heily.com>
33+ *
44+ * Permission to use, copy, modify, and distribute this software for any
55+ * purpose with or without fee is hereby granted, provided that the above
66+ * copyright notice and this permission notice appear in all copies.
77+ *
88+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
99+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
1010+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
1111+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
1212+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
1313+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
1414+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
1515+ */
1616+1717+#include "private.h"
1818+1919+#ifndef NDEBUG
2020+static char *
2121+inotify_mask_dump(uint32_t mask)
2222+{
2323+ static __thread char buf[1024];
2424+2525+#define INEVT_MASK_DUMP(attrib) \
2626+ if (mask & attrib) \
2727+ strcat(buf, #attrib" ");
2828+2929+ snprintf(buf, sizeof(buf), "mask = %d (", mask);
3030+ INEVT_MASK_DUMP(IN_ACCESS);
3131+ INEVT_MASK_DUMP(IN_MODIFY);
3232+ INEVT_MASK_DUMP(IN_ATTRIB);
3333+ INEVT_MASK_DUMP(IN_CLOSE_WRITE);
3434+ INEVT_MASK_DUMP(IN_CLOSE_NOWRITE);
3535+ INEVT_MASK_DUMP(IN_OPEN);
3636+ INEVT_MASK_DUMP(IN_MOVED_FROM);
3737+ INEVT_MASK_DUMP(IN_MOVED_TO);
3838+ INEVT_MASK_DUMP(IN_CREATE);
3939+ INEVT_MASK_DUMP(IN_DELETE);
4040+ INEVT_MASK_DUMP(IN_DELETE_SELF);
4141+ INEVT_MASK_DUMP(IN_MOVE_SELF);
4242+ buf[strlen(buf) - 1] = ')';
4343+4444+ return (buf);
4545+}
4646+4747+static char *
4848+inotify_event_dump(struct inotify_event *evt)
4949+{
5050+ static __thread char buf[1024];
5151+5252+ snprintf(buf, sizeof(buf), "wd=%d mask=%s",
5353+ evt->wd,
5454+ inotify_mask_dump(evt->mask));
5555+5656+ return (buf);
5757+}
5858+5959+#endif /* !NDEBUG */
6060+6161+6262+/* TODO: USE this to get events with name field */
6363+int
6464+get_one_event(struct inotify_event *dst, int inofd)
6565+{
6666+ ssize_t n;
6767+6868+ dbg_puts("reading one inotify event");
6969+ for (;;) {
7070+ n = read(inofd, dst, sizeof(*dst));
7171+ if (n < 0) {
7272+ if (errno == EINTR)
7373+ continue;
7474+ dbg_perror("read");
7575+ return (-1);
7676+ } else {
7777+ break;
7878+ }
7979+ }
8080+ dbg_printf("read(2) from inotify wd: %ld bytes", (long) n);
8181+8282+ /* FIXME-TODO: if len > 0, read(len) */
8383+ if (dst->len != 0)
8484+ abort();
8585+8686+8787+ return (0);
8888+}
8989+9090+static int
9191+add_watch(struct filter *filt, struct knote *kn)
9292+{
9393+ struct epoll_event ev;
9494+ int ifd;
9595+ char path[PATH_MAX];
9696+ uint32_t mask;
9797+9898+ /* Convert the fd to a pathname */
9999+ if (linux_fd_to_path(&path[0], sizeof(path), kn->kev.ident) < 0)
100100+ return (-1);
101101+102102+ /* Convert the fflags to the inotify mask */
103103+ mask = IN_CLOSE;
104104+ if (kn->kev.fflags & NOTE_DELETE)
105105+ mask |= IN_ATTRIB | IN_DELETE_SELF;
106106+ if (kn->kev.fflags & NOTE_WRITE)
107107+ mask |= IN_MODIFY | IN_ATTRIB;
108108+ if (kn->kev.fflags & NOTE_EXTEND)
109109+ mask |= IN_MODIFY | IN_ATTRIB;
110110+ if ((kn->kev.fflags & NOTE_ATTRIB) ||
111111+ (kn->kev.fflags & NOTE_LINK))
112112+ mask |= IN_ATTRIB;
113113+ if (kn->kev.fflags & NOTE_RENAME)
114114+ mask |= IN_MOVE_SELF;
115115+ if (kn->kev.flags & EV_ONESHOT)
116116+ mask |= IN_ONESHOT;
117117+118118+ /* Create an inotify descriptor */
119119+ ifd = inotify_init();
120120+ if (ifd < 0) {
121121+ dbg_perror("inotify_init(2)");
122122+ return (-1);
123123+ }
124124+125125+ /* Add the watch */
126126+ dbg_printf("inotify_add_watch(2); inofd=%d, %s, path=%s",
127127+ ifd, inotify_mask_dump(mask), path);
128128+ kn->kev.data = inotify_add_watch(ifd, path, mask);
129129+ if (kn->kev.data < 0) {
130130+ dbg_perror("inotify_add_watch(2)");
131131+ goto errout;
132132+ }
133133+134134+ /* Add the inotify fd to the epoll set */
135135+ memset(&ev, 0, sizeof(ev));
136136+ ev.events = EPOLLIN;
137137+ ev.data.ptr = kn;
138138+ if (epoll_ctl(filter_epfd(filt), EPOLL_CTL_ADD, ifd, &ev) < 0) {
139139+ dbg_perror("epoll_ctl(2)");
140140+ goto errout;
141141+ }
142142+143143+ kn->kdata.kn_inotifyfd = ifd;
144144+145145+ return (0);
146146+147147+errout:
148148+ kn->kdata.kn_inotifyfd = -1;
149149+ (void) close(ifd);
150150+ return (-1);
151151+}
152152+153153+static int
154154+delete_watch(struct filter *filt, struct knote *kn)
155155+{
156156+ int ifd = kn->kdata.kn_inotifyfd;
157157+158158+ if (ifd < 0)
159159+ return (0);
160160+ if (epoll_ctl(filter_epfd(filt), EPOLL_CTL_DEL, ifd, NULL) < 0) {
161161+ dbg_perror("epoll_ctl(2)");
162162+ return (-1);
163163+ }
164164+ (void) close(ifd);
165165+ kn->kdata.kn_inotifyfd = -1;
166166+167167+ return (0);
168168+}
169169+170170+int
171171+evfilt_vnode_copyout(struct kevent *dst, struct knote *src, void *ptr UNUSED)
172172+{
173173+ struct inotify_event evt;
174174+ struct stat sb;
175175+176176+ if (get_one_event(&evt, src->kdata.kn_inotifyfd) < 0)
177177+ return (-1);
178178+179179+ dbg_printf("inotify event: %s", inotify_event_dump(&evt));
180180+ if (evt.mask & IN_IGNORED) {
181181+ /* TODO: possibly return error when fs is unmounted */
182182+ dst->filter = 0;
183183+ return (0);
184184+ }
185185+186186+ /* Check if the watched file has been closed, and
187187+ XXX-this may not exactly match the kevent() behavior if multiple file de
188188+scriptors reference the same file.
189189+ */
190190+ if (evt.mask & IN_CLOSE_WRITE || evt.mask & IN_CLOSE_NOWRITE) {
191191+ src->kn_flags |= EV_ONESHOT; /* KLUDGE: causes the knote to be deleted */
192192+ dst->filter = 0; /* KLUDGE: causes the event to be discarded */
193193+ return (0);
194194+ }
195195+196196+ memcpy(dst, &src->kev, sizeof(*dst));
197197+ dst->data = 0;
198198+199199+ /* No error checking because fstat(2) should rarely fail */
200200+ //FIXME: EINTR
201201+ if ((evt.mask & IN_ATTRIB || evt.mask & IN_MODIFY)
202202+ && fstat(src->kev.ident, &sb) == 0) {
203203+ if (sb.st_nlink == 0 && src->kev.fflags & NOTE_DELETE)
204204+ dst->fflags |= NOTE_DELETE;
205205+ if (sb.st_nlink != src->data.vnode.nlink && src->kev.fflags & NOTE_LINK)
206206+ dst->fflags |= NOTE_LINK;
207207+#if HAVE_NOTE_TRUNCATE
208208+ if (sb.st_nsize == 0 && src->kev.fflags & NOTE_TRUNCATE)
209209+ dst->fflags |= NOTE_TRUNCATE;
210210+#endif
211211+ if (sb.st_size > src->data.vnode.size && src->kev.fflags & NOTE_WRITE)
212212+ dst->fflags |= NOTE_EXTEND;
213213+ src->data.vnode.nlink = sb.st_nlink;
214214+ src->data.vnode.size = sb.st_size;
215215+ }
216216+217217+ if (evt.mask & IN_MODIFY && src->kev.fflags & NOTE_WRITE)
218218+ dst->fflags |= NOTE_WRITE;
219219+ if (evt.mask & IN_ATTRIB && src->kev.fflags & NOTE_ATTRIB)
220220+ dst->fflags |= NOTE_ATTRIB;
221221+ if (evt.mask & IN_MOVE_SELF && src->kev.fflags & NOTE_RENAME)
222222+ dst->fflags |= NOTE_RENAME;
223223+ if (evt.mask & IN_DELETE_SELF && src->kev.fflags & NOTE_DELETE)
224224+ dst->fflags |= NOTE_DELETE;
225225+226226+ if (evt.mask & IN_MODIFY && src->kev.fflags & NOTE_WRITE)
227227+ dst->fflags |= NOTE_WRITE;
228228+ if (evt.mask & IN_ATTRIB && src->kev.fflags & NOTE_ATTRIB)
229229+ dst->fflags |= NOTE_ATTRIB;
230230+ if (evt.mask & IN_MOVE_SELF && src->kev.fflags & NOTE_RENAME)
231231+ dst->fflags |= NOTE_RENAME;
232232+ if (evt.mask & IN_DELETE_SELF && src->kev.fflags & NOTE_DELETE)
233233+ dst->fflags |= NOTE_DELETE;
234234+235235+ return (0);
236236+}
237237+238238+int
239239+evfilt_vnode_knote_create(struct filter *filt, struct knote *kn)
240240+{
241241+ struct stat sb;
242242+243243+ if (fstat(kn->kev.ident, &sb) < 0) {
244244+ dbg_puts("fstat failed");
245245+ return (-1);
246246+ }
247247+ kn->data.vnode.nlink = sb.st_nlink;
248248+ kn->data.vnode.size = sb.st_size;
249249+ kn->kev.data = -1;
250250+251251+ return (add_watch(filt, kn));
252252+}
253253+254254+int
255255+evfilt_vnode_knote_modify(struct filter *filt, struct knote *kn,
256256+ const struct kevent *kev)
257257+{
258258+ (void)filt;
259259+ (void)kn;
260260+ (void)kev;
261261+ return (-1); /* FIXME - STUB */
262262+}
263263+264264+int
265265+evfilt_vnode_knote_delete(struct filter *filt, struct knote *kn)
266266+{
267267+ return delete_watch(filt, kn);
268268+}
269269+270270+int
271271+evfilt_vnode_knote_enable(struct filter *filt, struct knote *kn)
272272+{
273273+ return add_watch(filt, kn);
274274+}
275275+276276+int
277277+evfilt_vnode_knote_disable(struct filter *filt, struct knote *kn)
278278+{
279279+ return delete_watch(filt, kn);
280280+}
281281+282282+const struct filter evfilt_vnode = {
283283+ EVFILT_VNODE,
284284+ NULL,
285285+ NULL,
286286+ evfilt_vnode_copyout,
287287+ evfilt_vnode_knote_create,
288288+ evfilt_vnode_knote_modify,
289289+ evfilt_vnode_knote_delete,
290290+ evfilt_vnode_knote_enable,
291291+ evfilt_vnode_knote_disable,
292292+};
+133
external/libkqueue-2.0.1/src/linux/write.c
···11+/*
22+ * Copyright (c) 2009 Mark Heily <mark@heily.com>
33+ *
44+ * Permission to use, copy, modify, and distribute this software for any
55+ * purpose with or without fee is hereby granted, provided that the above
66+ * copyright notice and this permission notice appear in all copies.
77+ *
88+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
99+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
1010+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
1111+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
1212+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
1313+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
1414+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
1515+ */
1616+1717+#include <errno.h>
1818+#include <fcntl.h>
1919+#include <linux/sockios.h>
2020+#include <pthread.h>
2121+#include <signal.h>
2222+#include <stdlib.h>
2323+#include <stdio.h>
2424+#include <sys/ioctl.h>
2525+#include <sys/queue.h>
2626+#include <sys/socket.h>
2727+#include <sys/types.h>
2828+#include <string.h>
2929+#include <unistd.h>
3030+3131+#include "private.h"
3232+3333+int
3434+evfilt_socket_copyout(struct kevent *dst, struct knote *src, void *ptr)
3535+{
3636+ struct epoll_event * const ev = (struct epoll_event *) ptr;
3737+3838+ epoll_event_dump(ev);
3939+ memcpy(dst, &src->kev, sizeof(*dst));
4040+#if defined(HAVE_EPOLLRDHUP)
4141+ if (ev->events & EPOLLRDHUP || ev->events & EPOLLHUP)
4242+ dst->flags |= EV_EOF;
4343+#else
4444+ if (ev->events & EPOLLHUP)
4545+ dst->flags |= EV_EOF;
4646+#endif
4747+ if (ev->events & EPOLLERR)
4848+ dst->fflags = 1; /* FIXME: Return the actual socket error */
4949+5050+ /* On return, data contains the the amount of space remaining in the write buffer */
5151+ if (ioctl(dst->ident, SIOCOUTQ, &dst->data) < 0) {
5252+ /* race condition with socket close, so ignore this error */
5353+ dbg_puts("ioctl(2) of socket failed");
5454+ dst->data = 0;
5555+ }
5656+5757+ return (0);
5858+}
5959+6060+int
6161+evfilt_socket_knote_create(struct filter *filt, struct knote *kn)
6262+{
6363+ struct epoll_event ev;
6464+6565+ if (linux_get_descriptor_type(kn) < 0)
6666+ return (-1);
6767+6868+ /* TODO: return EBADF? */
6969+ if (kn->kn_flags & KNFL_REGULAR_FILE)
7070+ return (-1);
7171+7272+ /* Convert the kevent into an epoll_event */
7373+ kn->data.events = EPOLLOUT;
7474+ if (kn->kev.flags & EV_ONESHOT || kn->kev.flags & EV_DISPATCH)
7575+ kn->data.events |= EPOLLONESHOT;
7676+ if (kn->kev.flags & EV_CLEAR)
7777+ kn->data.events |= EPOLLET;
7878+7979+ memset(&ev, 0, sizeof(ev));
8080+ ev.events = kn->data.events;
8181+ ev.data.ptr = kn;
8282+8383+ return epoll_update(EPOLL_CTL_ADD, filt, kn, &ev);
8484+}
8585+8686+int
8787+evfilt_socket_knote_modify(struct filter *filt, struct knote *kn,
8888+ const struct kevent *kev)
8989+{
9090+ (void) filt;
9191+ (void) kn;
9292+ (void) kev;
9393+ return (-1); /* STUB */
9494+}
9595+9696+int
9797+evfilt_socket_knote_delete(struct filter *filt, struct knote *kn)
9898+{
9999+ if (kn->kev.flags & EV_DISABLE)
100100+ return (0);
101101+ else
102102+ return epoll_update(EPOLL_CTL_DEL, filt, kn, NULL);
103103+}
104104+105105+int
106106+evfilt_socket_knote_enable(struct filter *filt, struct knote *kn)
107107+{
108108+ struct epoll_event ev;
109109+110110+ memset(&ev, 0, sizeof(ev));
111111+ ev.events = kn->data.events;
112112+ ev.data.ptr = kn;
113113+114114+ return epoll_update(EPOLL_CTL_ADD, filt, kn, &ev);
115115+}
116116+117117+int
118118+evfilt_socket_knote_disable(struct filter *filt, struct knote *kn)
119119+{
120120+ return epoll_update(EPOLL_CTL_DEL, filt, kn, NULL);
121121+}
122122+123123+const struct filter evfilt_write = {
124124+ EVFILT_WRITE,
125125+ NULL,
126126+ NULL,
127127+ evfilt_socket_copyout,
128128+ evfilt_socket_knote_create,
129129+ evfilt_socket_knote_modify,
130130+ evfilt_socket_knote_delete,
131131+ evfilt_socket_knote_enable,
132132+ evfilt_socket_knote_disable,
133133+};
+90
external/libkqueue-2.0.1/src/posix/platform.c
···11+/*
22+ * Copyright (c) 2011 Mark Heily <mark@heily.com>
33+ *
44+ * Permission to use, copy, modify, and distribute this software for any
55+ * purpose with or without fee is hereby granted, provided that the above
66+ * copyright notice and this permission notice appear in all copies.
77+ *
88+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
99+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
1010+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
1111+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
1212+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
1313+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
1414+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
1515+ */
1616+1717+#include "../common/private.h"
1818+1919+int
2020+posix_kqueue_init(struct kqueue *kq UNUSED)
2121+{
2222+ return (0);
2323+}
2424+2525+void
2626+posix_kqueue_free(struct kqueue *kq UNUSED)
2727+{
2828+}
2929+3030+int
3131+posix_eventfd_init(struct eventfd *e)
3232+{
3333+ int sd[2];
3434+3535+ if (socketpair(AF_UNIX, SOCK_STREAM, 0, sd) < 0) {
3636+ return (-1);
3737+ }
3838+ if ((fcntl(sd[0], F_SETFL, O_NONBLOCK) < 0) ||
3939+ (fcntl(sd[1], F_SETFL, O_NONBLOCK) < 0)) {
4040+ close(sd[0]);
4141+ close(sd[1]);
4242+ return (-1);
4343+ }
4444+ e->ef_wfd = sd[0];
4545+ e->ef_id = sd[1];
4646+4747+ return (0);
4848+}
4949+5050+void
5151+posix_eventfd_close(struct eventfd *e)
5252+{
5353+ close(e->ef_id);
5454+ close(e->ef_wfd);
5555+ e->ef_id = -1;
5656+}
5757+5858+int
5959+posix_eventfd_raise(struct eventfd *e)
6060+{
6161+ dbg_puts("raising event level");
6262+ if (write(e->ef_wfd, ".", 1) < 0) {
6363+ /* FIXME: handle EAGAIN and EINTR */
6464+ dbg_printf("write(2) on fd %d: %s", e->ef_wfd, strerror(errno));
6565+ return (-1);
6666+ }
6767+ return (0);
6868+}
6969+7070+int
7171+posix_eventfd_lower(struct eventfd *e)
7272+{
7373+ char buf[1024];
7474+7575+ /* Reset the counter */
7676+ dbg_puts("lowering event level");
7777+ if (read(e->ef_id, &buf, sizeof(buf)) < 0) {
7878+ /* FIXME: handle EAGAIN and EINTR */
7979+ /* FIXME: loop so as to consume all data.. may need mutex */
8080+ dbg_printf("read(2): %s", strerror(errno));
8181+ return (-1);
8282+ }
8383+ return (0);
8484+}
8585+8686+int
8787+posix_eventfd_descriptor(struct eventfd *e)
8888+{
8989+ return (e->ef_id);
9090+}
+81
external/libkqueue-2.0.1/src/posix/platform.h
···11+/*
22+ * Copyright (c) 2011 Mark Heily <mark@heily.com>
33+ *
44+ * Permission to use, copy, modify, and distribute this software for any
55+ * purpose with or without fee is hereby granted, provided that the above
66+ * copyright notice and this permission notice appear in all copies.
77+ *
88+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
99+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
1010+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
1111+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
1212+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
1313+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
1414+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
1515+ */
1616+1717+#ifndef _KQUEUE_POSIX_PLATFORM_H
1818+#define _KQUEUE_POSIX_PLATFORM_H
1919+2020+/* Required by glibc for MAP_ANON */
2121+#define __USE_MISC 1
2222+2323+#include "../../include/sys/event.h"
2424+2525+/*
2626+ * GCC-compatible atomic operations
2727+ */
2828+#define atomic_inc(p) __sync_add_and_fetch((p), 1)
2929+#define atomic_dec(p) __sync_sub_and_fetch((p), 1)
3030+#define atomic_cas(p, oval, nval) __sync_val_compare_and_swap(p, oval, nval)
3131+#define atomic_ptr_cas(p, oval, nval) __sync_val_compare_and_swap(p, oval, nval)
3232+3333+/*
3434+ * GCC-compatible branch prediction macros
3535+ */
3636+#define fastpath(x) __builtin_expect((x), 1)
3737+#define slowpath(x) __builtin_expect((x), 0)
3838+3939+/*
4040+ * GCC-compatible attributes
4141+ */
4242+#define VISIBLE __attribute__((visibility("default")))
4343+#define HIDDEN __attribute__((visibility("hidden")))
4444+#define UNUSED __attribute__((unused))
4545+4646+#include <fcntl.h>
4747+#include <limits.h>
4848+#include <signal.h>
4949+#include <stdbool.h>
5050+#include <stdlib.h>
5151+#include <stdio.h>
5252+#include <stdint.h>
5353+#include <pthread.h>
5454+#include <poll.h>
5555+#include <sys/resource.h>
5656+#include <sys/select.h>
5757+#include <sys/socket.h>
5858+#include <sys/stat.h>
5959+#include <sys/types.h>
6060+#include <sys/mman.h>
6161+#include <unistd.h>
6262+6363+/*
6464+ * Additional members of 'struct eventfd'
6565+ */
6666+#define EVENTFD_PLATFORM_SPECIFIC \
6767+ int ef_wfd
6868+6969+void posix_kqueue_free(struct kqueue *);
7070+int posix_kqueue_init(struct kqueue *);
7171+7272+int posix_kevent_wait(struct kqueue *, const struct timespec *);
7373+int posix_kevent_copyout(struct kqueue *, int, struct kevent *, int);
7474+7575+int posix_eventfd_init(struct eventfd *);
7676+void posix_eventfd_close(struct eventfd *);
7777+int posix_eventfd_raise(struct eventfd *);
7878+int posix_eventfd_lower(struct eventfd *);
7979+int posix_eventfd_descriptor(struct eventfd *);
8080+8181+#endif /* ! _KQUEUE_POSIX_PLATFORM_H */
+137
external/libkqueue-2.0.1/test/common.h
···11+/*
22+ * Copyright (c) 2009 Mark Heily <mark@heily.com>
33+ *
44+ * Permission to use, copy, modify, and distribute this software for any
55+ * purpose with or without fee is hereby granted, provided that the above
66+ * copyright notice and this permission notice appear in all copies.
77+ *
88+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
99+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
1010+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
1111+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
1212+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
1313+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
1414+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
1515+ */
1616+1717+#ifndef _COMMON_H
1818+#define _COMMON_H
1919+2020+2121+#if HAVE_ERR_H
2222+# include <err.h>
2323+#else
2424+# define err(rc,msg,...) do { perror(msg); exit(rc); } while (0)
2525+# define errx(rc,msg,...) do { puts(msg); exit(rc); } while (0)
2626+#endif
2727+2828+#define die(str) do { \
2929+ fprintf(stderr, "%s(): %s: %s\n", __func__,str, strerror(errno));\
3030+ abort();\
3131+} while (0)
3232+3333+#include <assert.h>
3434+#include <errno.h>
3535+#include <fcntl.h>
3636+#include <signal.h>
3737+#include <stdlib.h>
3838+#include <stdio.h>
3939+#include <string.h>
4040+#include <stdint.h>
4141+4242+#ifndef _WIN32
4343+#include <sys/socket.h>
4444+#include <sys/stat.h>
4545+#include <sys/types.h>
4646+#include <unistd.h>
4747+#include <sys/event.h>
4848+#include <arpa/inet.h>
4949+#include <pthread.h>
5050+#include <poll.h>
5151+#include "../config.h"
5252+#else
5353+# include "../include/sys/event.h"
5454+# include "../src/windows/platform.h"
5555+#endif
5656+5757+struct test_context;
5858+5959+struct unit_test {
6060+ const char *ut_name;
6161+ int ut_enabled;
6262+ void (*ut_func)(struct test_context *);
6363+};
6464+6565+#define MAX_TESTS 50
6666+struct test_context {
6767+ struct unit_test tests[MAX_TESTS];
6868+ char *cur_test_id;
6969+ int iterations;
7070+ int iteration;
7171+ int kqfd;
7272+7373+ /* EVFILT_READ and EVFILT_WRITE */
7474+ int client_fd;
7575+ int server_fd;
7676+7777+ /* EVFILT_VNODE */
7878+ int vnode_fd;
7979+ char testfile[1024];
8080+};
8181+8282+void test_evfilt_read(struct test_context *);
8383+void test_evfilt_signal(struct test_context *);
8484+void test_evfilt_vnode(struct test_context *);
8585+void test_evfilt_timer(struct test_context *);
8686+void test_evfilt_proc(struct test_context *);
8787+#ifdef EVFILT_USER
8888+void test_evfilt_user(struct test_context *);
8989+#endif
9090+9191+#define test(f,ctx,...) do { \
9292+ assert(ctx != NULL); \
9393+ test_begin(ctx, "test_"#f"()\t"__VA_ARGS__); \
9494+ test_##f(ctx); \
9595+ test_end(ctx); \
9696+} while (/*CONSTCOND*/0)
9797+9898+extern const char * kevent_to_str(struct kevent *);
9999+void kevent_get(struct kevent *, int);
100100+void kevent_get_hires(struct kevent *, int);
101101+void kevent_update(int kqfd, struct kevent *kev);
102102+103103+#define kevent_cmp(a,b) _kevent_cmp(a,b, __FILE__, __LINE__)
104104+void _kevent_cmp(struct kevent *, struct kevent *, const char *, int);
105105+106106+void
107107+kevent_add(int kqfd, struct kevent *kev,
108108+ uintptr_t ident,
109109+ short filter,
110110+ u_short flags,
111111+ u_int fflags,
112112+ intptr_t data,
113113+ void *udata);
114114+115115+/* DEPRECATED: */
116116+#define KEV_CMP(kev,_ident,_filter,_flags) do { \
117117+ if (kev.ident != (_ident) || \
118118+ kev.filter != (_filter) || \
119119+ kev.flags != (_flags)) \
120120+ err(1, "kevent mismatch: got [%d,%d,%d] but expecting [%d,%d,%d]", \
121121+ (int)_ident, (int)_filter, (int)_flags,\
122122+ (int)kev.ident, kev.filter, kev.flags);\
123123+} while (0);
124124+125125+/* Checks if any events are pending, which is an error. */
126126+#define test_no_kevents(a) _test_no_kevents(a, __FILE__, __LINE__)
127127+void _test_no_kevents(int, const char *, int);
128128+129129+/* From test.c */
130130+void test_begin(struct test_context *, const char *);
131131+void test_end(struct test_context *);
132132+void test_atexit(void);
133133+void testing_begin(void);
134134+void testing_end(void);
135135+int testing_make_uid(void);
136136+137137+#endif /* _COMMON_H */
+199
external/libkqueue-2.0.1/test/kevent.c
···11+/*
22+ * Copyright (c) 2009 Mark Heily <mark@heily.com>
33+ *
44+ * Permission to use, copy, modify, and distribute this software for any
55+ * purpose with or without fee is hereby granted, provided that the above
66+ * copyright notice and this permission notice appear in all copies.
77+ *
88+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
99+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
1010+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
1111+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
1212+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
1313+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
1414+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
1515+ */
1616+1717+#include "common.h"
1818+1919+extern int kqfd;
2020+2121+/* Checks if any events are pending, which is an error. */
2222+void
2323+_test_no_kevents(int kqfd, const char *file, int line)
2424+{
2525+ int nfds;
2626+ struct timespec timeo;
2727+ struct kevent kev;
2828+2929+ memset(&timeo, 0, sizeof(timeo));
3030+ nfds = kevent(kqfd, NULL, 0, &kev, 1, &timeo);
3131+ if (nfds < 0)
3232+ err(1, "kevent(2)");
3333+ if (nfds > 0) {
3434+ printf("\n[%s:%d]: Unexpected event:", file, line);
3535+ err(1, kevent_to_str(&kev));
3636+ }
3737+}
3838+3939+/* Retrieve a single kevent */
4040+void
4141+kevent_get(struct kevent *kev, int kqfd)
4242+{
4343+ struct kevent buf;
4444+ int nfds;
4545+4646+ if (kev == NULL)
4747+ kev = &buf;
4848+4949+ nfds = kevent(kqfd, NULL, 0, kev, 1, NULL);
5050+ if (nfds < 1)
5151+ err(1, "kevent(2)");
5252+}
5353+5454+/* In Linux, a kevent() call with less than 1ms resolution
5555+ will perform a pselect() call to obtain the higer resolution.
5656+ This test exercises that codepath.
5757+ */
5858+void
5959+kevent_get_hires(struct kevent *kev, int kqfd)
6060+{
6161+ int nfds;
6262+ struct timespec timeo;
6363+6464+ timeo.tv_sec = 0;
6565+ timeo.tv_nsec = 500000;
6666+ nfds = kevent(kqfd, NULL, 0, kev, 1, &timeo);
6767+ if (nfds < 1)
6868+ die("kevent(2)");
6969+}
7070+7171+char *
7272+kevent_fflags_dump(struct kevent *kev)
7373+{
7474+ char *buf;
7575+7676+#define KEVFFL_DUMP(attrib) \
7777+ if (kev->fflags & attrib) \
7878+ strncat(buf, #attrib" ", 64);
7979+8080+ if ((buf = calloc(1, 1024)) == NULL)
8181+ abort();
8282+8383+ /* Not every filter has meaningful fflags */
8484+ if (kev->filter != EVFILT_VNODE) {
8585+ snprintf(buf, 1024, "fflags = %d", kev->fflags);
8686+ return (buf);
8787+ }
8888+8989+ snprintf(buf, 1024, "fflags = %d (", kev->fflags);
9090+ KEVFFL_DUMP(NOTE_DELETE);
9191+ KEVFFL_DUMP(NOTE_WRITE);
9292+ KEVFFL_DUMP(NOTE_EXTEND);
9393+#if HAVE_NOTE_TRUNCATE
9494+ KEVFFL_DUMP(NOTE_TRUNCATE);
9595+#endif
9696+ KEVFFL_DUMP(NOTE_ATTRIB);
9797+ KEVFFL_DUMP(NOTE_LINK);
9898+ KEVFFL_DUMP(NOTE_RENAME);
9999+#if HAVE_NOTE_REVOKE
100100+ KEVFFL_DUMP(NOTE_REVOKE);
101101+#endif
102102+ buf[strlen(buf) - 1] = ')';
103103+104104+ return (buf);
105105+}
106106+107107+char *
108108+kevent_flags_dump(struct kevent *kev)
109109+{
110110+ char *buf;
111111+112112+#define KEVFL_DUMP(attrib) \
113113+ if (kev->flags & attrib) \
114114+ strncat(buf, #attrib" ", 64);
115115+116116+ if ((buf = calloc(1, 1024)) == NULL)
117117+ abort();
118118+119119+ snprintf(buf, 1024, "flags = %d (", kev->flags);
120120+ KEVFL_DUMP(EV_ADD);
121121+ KEVFL_DUMP(EV_ENABLE);
122122+ KEVFL_DUMP(EV_DISABLE);
123123+ KEVFL_DUMP(EV_DELETE);
124124+ KEVFL_DUMP(EV_ONESHOT);
125125+ KEVFL_DUMP(EV_CLEAR);
126126+ KEVFL_DUMP(EV_EOF);
127127+ KEVFL_DUMP(EV_ERROR);
128128+#ifdef EV_DISPATCH
129129+ KEVFL_DUMP(EV_DISPATCH);
130130+#endif
131131+#ifdef EV_RECEIPT
132132+ KEVFL_DUMP(EV_RECEIPT);
133133+#endif
134134+ buf[strlen(buf) - 1] = ')';
135135+136136+ return (buf);
137137+}
138138+139139+/* TODO - backport changes from src/common/kevent.c kevent_dump() */
140140+const char *
141141+kevent_to_str(struct kevent *kev)
142142+{
143143+ char buf[512];
144144+145145+ snprintf(&buf[0], sizeof(buf),
146146+ "[ident=%d, filter=%d, %s, %s, data=%d, udata=%p]",
147147+ (u_int) kev->ident,
148148+ kev->filter,
149149+ kevent_flags_dump(kev),
150150+ kevent_fflags_dump(kev),
151151+ (int) kev->data,
152152+ kev->udata);
153153+154154+ return (strdup(buf));
155155+}
156156+157157+void
158158+kevent_update(int kqfd, struct kevent *kev)
159159+{
160160+ if (kevent(kqfd, kev, 1, NULL, 0, NULL) < 0) {
161161+ printf("Unable to add the following kevent:\n%s\n",
162162+ kevent_to_str(kev));
163163+ die("kevent");
164164+ }
165165+}
166166+167167+void
168168+kevent_add(int kqfd, struct kevent *kev,
169169+ uintptr_t ident,
170170+ short filter,
171171+ u_short flags,
172172+ u_int fflags,
173173+ intptr_t data,
174174+ void *udata)
175175+{
176176+ EV_SET(kev, ident, filter, flags, fflags, data, NULL);
177177+ if (kevent(kqfd, kev, 1, NULL, 0, NULL) < 0) {
178178+ printf("Unable to add the following kevent:\n%s\n",
179179+ kevent_to_str(kev));
180180+ die("kevent");
181181+ }
182182+}
183183+184184+void
185185+_kevent_cmp(struct kevent *k1, struct kevent *k2, const char *file, int line)
186186+{
187187+/* XXX-
188188+ Workaround for inconsistent implementation of kevent(2)
189189+ */
190190+#if defined (__FreeBSD_kernel__) || defined (__FreeBSD__)
191191+ if (k1->flags & EV_ADD)
192192+ k2->flags |= EV_ADD;
193193+#endif
194194+ if (memcmp(k1, k2, sizeof(*k1)) != 0) {
195195+ printf("[%s:%d]: kevent_cmp() failed:\n expected %s\n but got %s\n",
196196+ file, line, kevent_to_str(k1), kevent_to_str(k2));
197197+ abort();
198198+ }
199199+}
+280
external/libkqueue-2.0.1/test/main.c
···11+/*
22+ * Copyright (c) 2009 Mark Heily <mark@heily.com>
33+ *
44+ * Permission to use, copy, modify, and distribute this software for any
55+ * purpose with or without fee is hereby granted, provided that the above
66+ * copyright notice and this permission notice appear in all copies.
77+ *
88+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
99+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
1010+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
1111+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
1212+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
1313+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
1414+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
1515+ */
1616+1717+#include "common.h"
1818+1919+/* Maximum number of threads that can be created */
2020+#define MAX_THREADS 100
2121+2222+void
2323+test_kqueue_descriptor_is_pollable(void)
2424+{
2525+ int kq, rv;
2626+ struct kevent kev;
2727+ fd_set fds;
2828+ struct timeval tv;
2929+3030+ if ((kq = kqueue()) < 0)
3131+ die("kqueue()");
3232+3333+ test_no_kevents(kq);
3434+ kevent_add(kq, &kev, 2, EVFILT_TIMER, EV_ADD | EV_ONESHOT, 0, 1000, NULL);
3535+ test_no_kevents(kq);
3636+3737+ FD_ZERO(&fds);
3838+ FD_SET(kq, &fds);
3939+ tv.tv_sec = 5;
4040+ tv.tv_usec = 0;
4141+ rv = select(1, &fds, NULL, NULL, &tv);
4242+ if (rv < 0)
4343+ die("select() error");
4444+ if (rv == 0)
4545+ die("select() no events");
4646+ if (!FD_ISSET(kq, &fds)) {
4747+ die("descriptor is not ready for reading");
4848+ }
4949+5050+ close(kq);
5151+}
5252+5353+/*
5454+ * Test the method for detecting when one end of a socketpair
5555+ * has been closed. This technique is used in kqueue_validate()
5656+ */
5757+static void
5858+test_peer_close_detection(void *unused)
5959+{
6060+#ifdef _WIN32
6161+ return;
6262+ //FIXME
6363+#else
6464+ int sockfd[2];
6565+ char buf[1];
6666+ struct pollfd pfd;
6767+6868+ if (socketpair(AF_UNIX, SOCK_STREAM, 0, sockfd) < 0)
6969+ die("socketpair");
7070+7171+ pfd.fd = sockfd[0];
7272+ pfd.events = POLLIN | POLLHUP;
7373+ pfd.revents = 0;
7474+7575+ if (poll(&pfd, 1, 0) > 0)
7676+ die("unexpected data");
7777+7878+ if (close(sockfd[1]) < 0)
7979+ die("close");
8080+8181+ if (poll(&pfd, 1, 0) > 0) {
8282+ if (recv(sockfd[0], buf, sizeof(buf), MSG_PEEK | MSG_DONTWAIT) != 0)
8383+ die("failed to detect peer shutdown");
8484+ }
8585+#endif
8686+}
8787+8888+void
8989+test_kqueue(void *unused)
9090+{
9191+ int kqfd;
9292+9393+ if ((kqfd = kqueue()) < 0)
9494+ die("kqueue()");
9595+ test_no_kevents(kqfd);
9696+ if (close(kqfd) < 0)
9797+ die("close()");
9898+}
9999+100100+void
101101+test_kevent(void *unused)
102102+{
103103+ struct kevent kev;
104104+105105+ memset(&kev, 0, sizeof(kev));
106106+107107+ /* Provide an invalid kqueue descriptor */
108108+ if (kevent(-1, &kev, 1, NULL, 0, NULL) == 0)
109109+ die("invalid kq parameter");
110110+}
111111+112112+void
113113+test_ev_receipt(void *unused)
114114+{
115115+ int kq;
116116+ struct kevent kev;
117117+118118+ if ((kq = kqueue()) < 0)
119119+ die("kqueue()");
120120+#if defined(EV_RECEIPT) && !defined(_WIN32)
121121+122122+ EV_SET(&kev, SIGUSR2, EVFILT_SIGNAL, EV_ADD | EV_RECEIPT, 0, 0, NULL);
123123+ if (kevent(kq, &kev, 1, &kev, 1, NULL) < 0)
124124+ die("kevent");
125125+126126+ /* TODO: check the receipt */
127127+128128+ close(kq);
129129+#else
130130+ memset(&kev, 0, sizeof(kev));
131131+ puts("Skipped -- EV_RECEIPT is not available or running on Win32");
132132+#endif
133133+}
134134+135135+void
136136+run_iteration(struct test_context *ctx)
137137+{
138138+ struct unit_test *test;
139139+140140+ for (test = &ctx->tests[0]; test->ut_name != NULL; test++) {
141141+ if (test->ut_enabled)
142142+ test->ut_func(ctx);
143143+ }
144144+ free(ctx);
145145+}
146146+147147+void
148148+test_harness(struct unit_test tests[MAX_TESTS], int iterations)
149149+{
150150+ int i, n, kqfd;
151151+ struct test_context *ctx;
152152+153153+ printf("Running %d iterations\n", iterations);
154154+155155+ testing_begin();
156156+157157+ ctx = calloc(1, sizeof(*ctx));
158158+159159+ test(peer_close_detection, ctx);
160160+161161+ test(kqueue, ctx);
162162+ test(kevent, ctx);
163163+164164+ if ((kqfd = kqueue()) < 0)
165165+ die("kqueue()");
166166+167167+ test(ev_receipt, ctx);
168168+ /* TODO: this fails now, but would be good later
169169+ test(kqueue_descriptor_is_pollable);
170170+ */
171171+172172+ free(ctx);
173173+174174+ n = 0;
175175+ for (i = 0; i < iterations; i++) {
176176+ ctx = calloc(1, sizeof(*ctx));
177177+ if (ctx == NULL)
178178+ abort();
179179+ ctx->iteration = n++;
180180+ ctx->kqfd = kqfd;
181181+ memcpy(&ctx->tests, tests, sizeof(ctx->tests));
182182+ ctx->iterations = iterations;
183183+184184+ run_iteration(ctx);
185185+ }
186186+ testing_end();
187187+188188+ close(kqfd);
189189+}
190190+191191+void
192192+usage(void)
193193+{
194194+ printf("usage:\n"
195195+ " -h This message\n"
196196+ " -n Number of iterations (default: 1)\n"
197197+ "\n\n"
198198+ );
199199+ exit(1);
200200+}
201201+202202+int
203203+main(int argc, char **argv)
204204+{
205205+ struct unit_test tests[MAX_TESTS] = {
206206+ { "socket", 1, test_evfilt_read },
207207+#if !defined(_WIN32) && !defined(__ANDROID__)
208208+ // XXX-FIXME -- BROKEN ON LINUX WHEN RUN IN A SEPARATE THREAD
209209+ { "signal", 1, test_evfilt_signal },
210210+#endif
211211+#if FIXME
212212+ { "proc", 1, test_evfilt_proc },
213213+#endif
214214+ { "timer", 1, test_evfilt_timer },
215215+#ifndef _WIN32
216216+ { "vnode", 1, test_evfilt_vnode },
217217+#endif
218218+#ifdef EVFILT_USER
219219+ { "user", 1, test_evfilt_user },
220220+#endif
221221+ { NULL, 0, NULL },
222222+ };
223223+ struct unit_test *test;
224224+ int c, i, iterations;
225225+ char *arg;
226226+ int match;
227227+228228+#ifdef _WIN32
229229+ /* Initialize the Winsock library */
230230+ WSADATA wsaData;
231231+ if (WSAStartup(MAKEWORD(2,2), &wsaData) != 0)
232232+ err(1, "WSAStartup failed");
233233+#endif
234234+235235+ iterations = 1;
236236+237237+/* Windows does not provide a POSIX-compatible getopt */
238238+#ifndef _WIN32
239239+ while ((c = getopt (argc, argv, "hn:")) != -1) {
240240+ switch (c) {
241241+ case 'h':
242242+ usage();
243243+ break;
244244+ case 'n':
245245+ iterations = atoi(optarg);
246246+ break;
247247+ default:
248248+ usage();
249249+ }
250250+ }
251251+252252+ /* If specific tests are requested, disable all tests by default */
253253+ if (optind < argc) {
254254+ for (test = &tests[0]; test->ut_name != NULL; test++) {
255255+ test->ut_enabled = 0;
256256+ }
257257+ }
258258+ for (i = optind; i < argc; i++) {
259259+ match = 0;
260260+ arg = argv[i];
261261+ for (test = &tests[0]; test->ut_name != NULL; test++) {
262262+ if (strcmp(arg, test->ut_name) == 0) {
263263+ test->ut_enabled = 1;
264264+ match = 1;
265265+ break;
266266+ }
267267+ }
268268+ if (!match) {
269269+ printf("ERROR: invalid option: %s\n", arg);
270270+ exit(1);
271271+ } else {
272272+ printf("enabled test: %s\n", arg);
273273+ }
274274+ }
275275+#endif
276276+277277+ test_harness(tests, iterations);
278278+279279+ return (0);
280280+}
+229
external/libkqueue-2.0.1/test/proc.c
···11+/*
22+ * Copyright (c) 2009 Mark Heily <mark@heily.com>
33+ *
44+ * Permission to use, copy, modify, and distribute this software for any
55+ * purpose with or without fee is hereby granted, provided that the above
66+ * copyright notice and this permission notice appear in all copies.
77+ *
88+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
99+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
1010+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
1111+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
1212+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
1313+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
1414+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
1515+ */
1616+1717+#include "common.h"
1818+1919+static int sigusr1_caught = 0;
2020+static pid_t pid;
2121+static int kqfd;
2222+2323+static void
2424+sig_handler(int signum)
2525+{
2626+ sigusr1_caught = 1;
2727+}
2828+2929+static void
3030+test_kevent_proc_add(struct test_context *ctx)
3131+{
3232+ struct kevent kev;
3333+3434+ test_no_kevents(kqfd);
3535+ kevent_add(kqfd, &kev, pid, EVFILT_PROC, EV_ADD, 0, 0, NULL);
3636+ test_no_kevents(kqfd);
3737+}
3838+3939+static void
4040+test_kevent_proc_delete(struct test_context *ctx)
4141+{
4242+ struct kevent kev;
4343+4444+ test_no_kevents(kqfd);
4545+ kevent_add(kqfd, &kev, pid, EVFILT_PROC, EV_DELETE, 0, 0, NULL);
4646+ if (kill(pid, SIGKILL) < 0)
4747+ die("kill");
4848+ sleep(1);
4949+ test_no_kevents(kqfd);
5050+}
5151+5252+static void
5353+test_kevent_proc_get(struct test_context *ctx)
5454+{
5555+ struct kevent kev, buf;
5656+5757+ /* Create a child that waits to be killed and then exits */
5858+ pid = fork();
5959+ if (pid == 0) {
6060+ pause();
6161+ printf(" -- child caught signal, exiting\n");
6262+ exit(2);
6363+ }
6464+ printf(" -- child created (pid %d)\n", (int) pid);
6565+6666+ test_no_kevents(kqfd);
6767+ kevent_add(kqfd, &kev, pid, EVFILT_PROC, EV_ADD, 0, 0, NULL);
6868+6969+ /* Cause the child to exit, then retrieve the event */
7070+ printf(" -- killing process %d\n", (int) pid);
7171+ if (kill(pid, SIGUSR1) < 0)
7272+ die("kill");
7373+ kevent_get(&buf, kqfd);
7474+ kevent_cmp(&kev, &buf);
7575+ test_no_kevents(kqfd);
7676+}
7777+7878+#ifdef TODO
7979+void
8080+test_kevent_signal_disable(struct test_context *ctx)
8181+{
8282+ const char *test_id = "kevent(EVFILT_SIGNAL, EV_DISABLE)";
8383+ struct kevent kev;
8484+8585+ test_begin(test_id);
8686+8787+ EV_SET(&kev, SIGUSR1, EVFILT_SIGNAL, EV_DISABLE, 0, 0, NULL);
8888+ if (kevent(kqfd, &kev, 1, NULL, 0, NULL) < 0)
8989+ die("%s", test_id);
9090+9191+ /* Block SIGUSR1, then send it to ourselves */
9292+ sigset_t mask;
9393+ sigemptyset(&mask);
9494+ sigaddset(&mask, SIGUSR1);
9595+ if (sigprocmask(SIG_BLOCK, &mask, NULL) == -1)
9696+ die("sigprocmask");
9797+ if (kill(getpid(), SIGKILL) < 0)
9898+ die("kill");
9999+100100+ test_no_kevents();
101101+102102+ success();
103103+}
104104+105105+void
106106+test_kevent_signal_enable(struct test_context *ctx)
107107+{
108108+ const char *test_id = "kevent(EVFILT_SIGNAL, EV_ENABLE)";
109109+ struct kevent kev;
110110+111111+ test_begin(test_id);
112112+113113+ EV_SET(&kev, SIGUSR1, EVFILT_SIGNAL, EV_ENABLE, 0, 0, NULL);
114114+ if (kevent(kqfd, &kev, 1, NULL, 0, NULL) < 0)
115115+ die("%s", test_id);
116116+117117+ /* Block SIGUSR1, then send it to ourselves */
118118+ sigset_t mask;
119119+ sigemptyset(&mask);
120120+ sigaddset(&mask, SIGUSR1);
121121+ if (sigprocmask(SIG_BLOCK, &mask, NULL) == -1)
122122+ die("sigprocmask");
123123+ if (kill(getpid(), SIGUSR1) < 0)
124124+ die("kill");
125125+126126+ kev.flags = EV_ADD | EV_CLEAR;
127127+#if LIBKQUEUE
128128+ kev.data = 1; /* WORKAROUND */
129129+#else
130130+ kev.data = 2; // one extra time from test_kevent_signal_disable()
131131+#endif
132132+ kevent_cmp(&kev, kevent_get(kqfd));
133133+134134+ /* Delete the watch */
135135+ kev.flags = EV_DELETE;
136136+ if (kevent(kqfd, &kev, 1, NULL, 0, NULL) < 0)
137137+ die("%s", test_id);
138138+139139+ success();
140140+}
141141+142142+void
143143+test_kevent_signal_del(struct test_context *ctx)
144144+{
145145+ const char *test_id = "kevent(EVFILT_SIGNAL, EV_DELETE)";
146146+ struct kevent kev;
147147+148148+ test_begin(test_id);
149149+150150+ /* Delete the kevent */
151151+ EV_SET(&kev, SIGUSR1, EVFILT_SIGNAL, EV_DELETE, 0, 0, NULL);
152152+ if (kevent(kqfd, &kev, 1, NULL, 0, NULL) < 0)
153153+ die("%s", test_id);
154154+155155+ /* Block SIGUSR1, then send it to ourselves */
156156+ sigset_t mask;
157157+ sigemptyset(&mask);
158158+ sigaddset(&mask, SIGUSR1);
159159+ if (sigprocmask(SIG_BLOCK, &mask, NULL) == -1)
160160+ die("sigprocmask");
161161+ if (kill(getpid(), SIGUSR1) < 0)
162162+ die("kill");
163163+164164+ test_no_kevents();
165165+ success();
166166+}
167167+168168+void
169169+test_kevent_signal_oneshot(struct test_context *ctx)
170170+{
171171+ const char *test_id = "kevent(EVFILT_SIGNAL, EV_ONESHOT)";
172172+ struct kevent kev;
173173+174174+ test_begin(test_id);
175175+176176+ EV_SET(&kev, SIGUSR1, EVFILT_SIGNAL, EV_ADD | EV_ONESHOT, 0, 0, NULL);
177177+ if (kevent(kqfd, &kev, 1, NULL, 0, NULL) < 0)
178178+ die("%s", test_id);
179179+180180+ /* Block SIGUSR1, then send it to ourselves */
181181+ sigset_t mask;
182182+ sigemptyset(&mask);
183183+ sigaddset(&mask, SIGUSR1);
184184+ if (sigprocmask(SIG_BLOCK, &mask, NULL) == -1)
185185+ die("sigprocmask");
186186+ if (kill(getpid(), SIGUSR1) < 0)
187187+ die("kill");
188188+189189+ kev.flags |= EV_CLEAR;
190190+ kev.data = 1;
191191+ kevent_cmp(&kev, kevent_get(kqfd));
192192+193193+ /* Send another one and make sure we get no events */
194194+ if (kill(getpid(), SIGUSR1) < 0)
195195+ die("kill");
196196+ test_no_kevents();
197197+198198+ success();
199199+}
200200+#endif
201201+202202+void
203203+test_evfilt_proc(struct test_context *ctx)
204204+{
205205+ signal(SIGUSR1, sig_handler);
206206+207207+ /* Create a child that waits to be killed and then exits */
208208+ pid = fork();
209209+ if (pid == 0) {
210210+ pause();
211211+ exit(2);
212212+ }
213213+ printf(" -- child created (pid %d)\n", (int) pid);
214214+215215+ test(kevent_proc_add, ctx);
216216+ test(kevent_proc_delete, ctx);
217217+ test(kevent_proc_get, ctx);
218218+219219+ signal(SIGUSR1, SIG_DFL);
220220+221221+#if TODO
222222+ test_kevent_signal_add();
223223+ test_kevent_signal_del();
224224+ test_kevent_signal_get();
225225+ test_kevent_signal_disable();
226226+ test_kevent_signal_enable();
227227+ test_kevent_signal_oneshot();
228228+#endif
229229+}
+442
external/libkqueue-2.0.1/test/read.c
···11+/*
22+ * Copyright (c) 2009 Mark Heily <mark@heily.com>
33+ *
44+ * Permission to use, copy, modify, and distribute this software for any
55+ * purpose with or without fee is hereby granted, provided that the above
66+ * copyright notice and this permission notice appear in all copies.
77+ *
88+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
99+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
1010+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
1111+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
1212+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
1313+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
1414+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
1515+ */
1616+1717+1818+#include "common.h"
1919+2020+2121+/*
2222+ * Create a connected TCP socket.
2323+ */
2424+static void
2525+create_socket_connection(int *client, int *server, const short port)
2626+{
2727+ struct sockaddr_in sain;
2828+ socklen_t sa_len = sizeof(sain);
2929+ int one = 1;
3030+ int clnt, srvr, accepted;
3131+3232+ /* Create a passive socket */
3333+ memset(&sain, 0, sizeof(sain));
3434+ sain.sin_family = AF_INET;
3535+ sain.sin_port = htons(port);
3636+ if ((srvr = socket(PF_INET, SOCK_STREAM, 0)) < 0)
3737+ err(1, "socket");
3838+ if (setsockopt(srvr, SOL_SOCKET, SO_REUSEADDR,
3939+ (char *) &one, sizeof(one)) != 0)
4040+ err(1, "setsockopt");
4141+ if (bind(srvr, (struct sockaddr *) &sain, sa_len) < 0) {
4242+ printf("unable to bind to port %d\n", port);
4343+ err(1, "bind-1");
4444+ }
4545+ if (listen(srvr, 100) < 0)
4646+ err(1, "listen");
4747+4848+ /* Simulate a client connecting to the server */
4949+ sain.sin_family = AF_INET;
5050+ sain.sin_port = htons(port);
5151+ sain.sin_addr.s_addr = inet_addr("127.0.0.1");
5252+ if ((clnt = socket(AF_INET, SOCK_STREAM, 0)) < 0)
5353+ err(1, "clnt: socket");
5454+ if (connect(clnt, (struct sockaddr *) &sain, sa_len) < 0)
5555+ err(1, "clnt: connect");
5656+ if ((accepted = accept(srvr, NULL, 0)) < 0)
5757+ err(1, "srvr: accept");
5858+5959+ *client = clnt;
6060+ *server = accepted;
6161+}
6262+6363+static void
6464+kevent_socket_drain(struct test_context *ctx)
6565+{
6666+ char buf[1];
6767+6868+ /* Drain the read buffer, then make sure there are no more events. */
6969+ if (recv(ctx->client_fd, &buf[0], 1, 0) < 1)
7070+ die("recv(2)");
7171+}
7272+7373+static void
7474+kevent_socket_fill(struct test_context *ctx)
7575+{
7676+ if (send(ctx->server_fd, ".", 1, 0) < 1)
7777+ die("send(2)");
7878+}
7979+8080+8181+void
8282+test_kevent_socket_add(struct test_context *ctx)
8383+{
8484+ struct kevent kev;
8585+8686+ kevent_add(ctx->kqfd, &kev, ctx->client_fd, EVFILT_READ, EV_ADD, 0, 0, &ctx->client_fd);
8787+}
8888+8989+void
9090+test_kevent_socket_add_without_ev_add(struct test_context *ctx)
9191+{
9292+ struct kevent kev;
9393+9494+ /* Try to add a kevent without specifying EV_ADD */
9595+ EV_SET(&kev, ctx->client_fd, EVFILT_READ, 0, 0, 0, &ctx->client_fd);
9696+ if (kevent(ctx->kqfd, &kev, 1, NULL, 0, NULL) == 0)
9797+ die("kevent should have failed");
9898+9999+ kevent_socket_fill(ctx);
100100+ test_no_kevents(ctx->kqfd);
101101+ kevent_socket_drain(ctx);
102102+103103+ /* Try to delete a kevent which does not exist */
104104+ kev.flags = EV_DELETE;
105105+ if (kevent(ctx->kqfd, &kev, 1, NULL, 0, NULL) == 0)
106106+ die("kevent should have failed");
107107+}
108108+109109+void
110110+test_kevent_socket_get(struct test_context *ctx)
111111+{
112112+ struct kevent kev, ret;
113113+114114+ EV_SET(&kev, ctx->client_fd, EVFILT_READ, EV_ADD, 0, 0, &ctx->client_fd);
115115+ if (kevent(ctx->kqfd, &kev, 1, NULL, 0, NULL) < 0)
116116+ die("kevent:1");
117117+118118+ kevent_socket_fill(ctx);
119119+120120+ kev.data = 1;
121121+ kevent_get(&ret, ctx->kqfd);
122122+ kevent_cmp(&kev, &ret);
123123+124124+ kevent_socket_drain(ctx);
125125+ test_no_kevents(ctx->kqfd);
126126+127127+ kev.flags = EV_DELETE;
128128+ if (kevent(ctx->kqfd, &kev, 1, NULL, 0, NULL) < 0)
129129+ die("kevent:2");
130130+}
131131+132132+void
133133+test_kevent_socket_clear(struct test_context *ctx)
134134+{
135135+ struct kevent kev, ret;
136136+137137+ test_no_kevents(ctx->kqfd);
138138+ kevent_socket_drain(ctx);
139139+140140+ EV_SET(&kev, ctx->client_fd, EVFILT_READ, EV_ADD | EV_CLEAR, 0, 0, &ctx->client_fd);
141141+ if (kevent(ctx->kqfd, &kev, 1, NULL, 0, NULL) < 0)
142142+ die("kevent1");
143143+144144+ kevent_socket_fill(ctx);
145145+ kevent_socket_fill(ctx);
146146+147147+/* Solaris does not offer a way to get the amount of data pending */
148148+#if defined(__sun__)
149149+ kev.data = 1;
150150+#else
151151+ kev.data = 2;
152152+#endif
153153+ kevent_get(&ret, ctx->kqfd);
154154+ kevent_cmp(&kev, &ret);
155155+156156+ /* We filled twice, but drain once. Edge-triggered would not generate
157157+ additional events.
158158+ */
159159+ kevent_socket_drain(ctx);
160160+ test_no_kevents(ctx->kqfd);
161161+162162+ kevent_socket_drain(ctx);
163163+ EV_SET(&kev, ctx->client_fd, EVFILT_READ, EV_DELETE, 0, 0, &ctx->client_fd);
164164+ if (kevent(ctx->kqfd, &kev, 1, NULL, 0, NULL) < 0)
165165+ die("kevent2");
166166+}
167167+168168+void
169169+test_kevent_socket_disable_and_enable(struct test_context *ctx)
170170+{
171171+ struct kevent kev, ret;
172172+173173+ /* Add an event, then disable it. */
174174+ EV_SET(&kev, ctx->client_fd, EVFILT_READ, EV_ADD, 0, 0, &ctx->client_fd);
175175+ if (kevent(ctx->kqfd, &kev, 1, NULL, 0, NULL) < 0)
176176+ die("kevent");
177177+ EV_SET(&kev, ctx->client_fd, EVFILT_READ, EV_DISABLE, 0, 0, &ctx->client_fd);
178178+ if (kevent(ctx->kqfd, &kev, 1, NULL, 0, NULL) < 0)
179179+ die("kevent");
180180+181181+ kevent_socket_fill(ctx);
182182+ test_no_kevents(ctx->kqfd);
183183+184184+ /* Re-enable the knote, then see if an event is generated */
185185+ kev.flags = EV_ENABLE;
186186+ if (kevent(ctx->kqfd, &kev, 1, NULL, 0, NULL) < 0)
187187+ die("kevent");
188188+ kev.flags = EV_ADD;
189189+ kev.data = 1;
190190+ kevent_get(&ret, ctx->kqfd);
191191+ kevent_cmp(&kev, &ret);
192192+193193+ kevent_socket_drain(ctx);
194194+195195+ kev.flags = EV_DELETE;
196196+ if (kevent(ctx->kqfd, &kev, 1, NULL, 0, NULL) < 0)
197197+ die("kevent");
198198+}
199199+200200+void
201201+test_kevent_socket_del(struct test_context *ctx)
202202+{
203203+ struct kevent kev;
204204+205205+ EV_SET(&kev, ctx->client_fd, EVFILT_READ, EV_DELETE, 0, 0, &ctx->client_fd);
206206+ if (kevent(ctx->kqfd, &kev, 1, NULL, 0, NULL) < 0)
207207+ die("kevent");
208208+209209+ kevent_socket_fill(ctx);
210210+ test_no_kevents(ctx->kqfd);
211211+ kevent_socket_drain(ctx);
212212+}
213213+214214+void
215215+test_kevent_socket_oneshot(struct test_context *ctx)
216216+{
217217+ struct kevent kev, ret;
218218+219219+ /* Re-add the watch and make sure no events are pending */
220220+ kevent_add(ctx->kqfd, &kev, ctx->client_fd, EVFILT_READ, EV_ADD | EV_ONESHOT, 0, 0, &ctx->client_fd);
221221+ test_no_kevents(ctx->kqfd);
222222+223223+ kevent_socket_fill(ctx);
224224+ kev.data = 1;
225225+ kevent_get(&ret, ctx->kqfd);
226226+ kevent_cmp(&kev, &ret);
227227+228228+ test_no_kevents(ctx->kqfd);
229229+230230+ /* Verify that the kernel watch has been deleted */
231231+ kevent_socket_fill(ctx);
232232+ test_no_kevents(ctx->kqfd);
233233+ kevent_socket_drain(ctx);
234234+235235+ /* Verify that the kevent structure does not exist. */
236236+ kev.flags = EV_DELETE;
237237+ if (kevent(ctx->kqfd, &kev, 1, NULL, 0, NULL) == 0)
238238+ die("kevent() should have failed");
239239+}
240240+241241+/*
242242+ * Test if the data field returns 1 when a listen(2) socket has
243243+ * a pending connection.
244244+ */
245245+void
246246+test_kevent_socket_listen_backlog(struct test_context *ctx)
247247+{
248248+ struct kevent kev, ret;
249249+ struct sockaddr_in sain;
250250+ socklen_t sa_len = sizeof(sain);
251251+ int one = 1;
252252+ short port;
253253+ int clnt, srvr;
254254+255255+ port = 14973 + ctx->iteration;
256256+257257+ /* Create a passive socket */
258258+ memset(&sain, 0, sizeof(sain));
259259+ sain.sin_family = AF_INET;
260260+ sain.sin_port = htons(port);
261261+ if ((srvr = socket(PF_INET, SOCK_STREAM, 0)) < 0)
262262+ err(1, "socket()");
263263+ if (setsockopt(srvr, SOL_SOCKET, SO_REUSEADDR,
264264+ (char *) &one, sizeof(one)) != 0)
265265+ err(1, "setsockopt()");
266266+ if (bind(srvr, (struct sockaddr *) &sain, sa_len) < 0)
267267+ err(1, "bind-2", port);
268268+ if (listen(srvr, 100) < 0)
269269+ err(1, "listen()");
270270+271271+ /* Watch for events on the socket */
272272+ test_no_kevents(ctx->kqfd);
273273+ kevent_add(ctx->kqfd, &kev, srvr, EVFILT_READ, EV_ADD | EV_ONESHOT, 0, 0, NULL);
274274+ test_no_kevents(ctx->kqfd);
275275+276276+ /* Simulate a client connecting to the server */
277277+ sain.sin_family = AF_INET;
278278+ sain.sin_port = htons(port);
279279+ sain.sin_addr.s_addr = inet_addr("127.0.0.1");
280280+ if ((clnt = socket(AF_INET, SOCK_STREAM, 0)) < 0)
281281+ err(1, "socket()");
282282+ if (connect(clnt, (struct sockaddr *) &sain, sa_len) < 0)
283283+ err(1, "connect()");
284284+285285+ /* Verify that data=1 */
286286+ kev.data = 1;
287287+ kevent_get(&ret, ctx->kqfd);
288288+ kevent_cmp(&kev, &ret);
289289+ test_no_kevents(ctx->kqfd);
290290+}
291291+292292+#ifdef EV_DISPATCH
293293+void
294294+test_kevent_socket_dispatch(struct test_context *ctx)
295295+{
296296+ struct kevent kev, ret;
297297+298298+ /* Re-add the watch and make sure no events are pending */
299299+ kevent_add(ctx->kqfd, &kev, ctx->client_fd, EVFILT_READ, EV_ADD | EV_DISPATCH, 0, 0, &ctx->client_fd);
300300+ test_no_kevents(ctx->kqfd);
301301+302302+ /* The event will occur only once, even though EV_CLEAR is not
303303+ specified. */
304304+ kevent_socket_fill(ctx);
305305+ kev.data = 1;
306306+ kevent_get(&ret, ctx->kqfd);
307307+ kevent_cmp(&kev, &ret);
308308+ test_no_kevents(ctx->kqfd);
309309+310310+ /* Re-enable the kevent */
311311+ /* FIXME- is EV_DISPATCH needed when rearming ? */
312312+ kevent_add(ctx->kqfd, &kev, ctx->client_fd, EVFILT_READ, EV_ENABLE | EV_DISPATCH, 0, 0, &ctx->client_fd);
313313+ kev.data = 1;
314314+ kev.flags = EV_ADD | EV_DISPATCH; /* FIXME: may not be portable */
315315+ kevent_get(&ret, ctx->kqfd);
316316+ kevent_cmp(&kev, &ret);
317317+ test_no_kevents(ctx->kqfd);
318318+319319+ /* Since the knote is disabled, the EV_DELETE operation succeeds. */
320320+ kevent_add(ctx->kqfd, &kev, ctx->client_fd, EVFILT_READ, EV_DELETE, 0, 0, &ctx->client_fd);
321321+322322+ kevent_socket_drain(ctx);
323323+}
324324+#endif /* EV_DISPATCH */
325325+326326+#if BROKEN_ON_LINUX
327327+void
328328+test_kevent_socket_lowat(struct test_context *ctx)
329329+{
330330+ struct kevent kev;
331331+332332+ test_begin(test_id);
333333+334334+ /* Re-add the watch and make sure no events are pending */
335335+ puts("-- re-adding knote, setting low watermark to 2 bytes");
336336+ EV_SET(&kev, ctx->client_fd, EVFILT_READ, EV_ADD | EV_ONESHOT, NOTE_LOWAT, 2, &ctx->client_fd);
337337+ if (kevent(ctx->kqfd, &kev, 1, NULL, 0, NULL) < 0)
338338+ die("%s", test_id);
339339+ test_no_kevents();
340340+341341+ puts("-- checking that one byte does not trigger an event..");
342342+ kevent_socket_fill(ctx);
343343+ test_no_kevents();
344344+345345+ puts("-- checking that two bytes triggers an event..");
346346+ kevent_socket_fill(ctx);
347347+ if (kevent(ctx->kqfd, NULL, 0, &kev, 1, NULL) != 1)
348348+ die("%s", test_id);
349349+ KEV_CMP(kev, ctx->client_fd, EVFILT_READ, 0);
350350+ test_no_kevents();
351351+352352+ kevent_socket_drain(ctx);
353353+ kevent_socket_drain(ctx);
354354+}
355355+#endif
356356+357357+void
358358+test_kevent_socket_eof(struct test_context *ctx)
359359+{
360360+ struct kevent kev, ret;
361361+362362+ /* Re-add the watch and make sure no events are pending */
363363+ kevent_add(ctx->kqfd, &kev, ctx->client_fd, EVFILT_READ, EV_ADD, 0, 0, &ctx->client_fd);
364364+ test_no_kevents(ctx->kqfd);
365365+366366+ //if (shutdown(ctx->server_fd, SHUT_RDWR) < 0)
367367+ // die("close(2)");
368368+ if (close(ctx->server_fd) < 0)
369369+ die("close(2)");
370370+371371+ kev.flags |= EV_EOF;
372372+ kevent_get(&ret, ctx->kqfd);
373373+ kevent_cmp(&kev, &ret);
374374+375375+ /* Delete the watch */
376376+ kevent_add(ctx->kqfd, &kev, ctx->client_fd, EVFILT_READ, EV_DELETE, 0, 0, &ctx->client_fd);
377377+}
378378+379379+/* Test if EVFILT_READ works with regular files */
380380+void
381381+test_kevent_regular_file(struct test_context *ctx)
382382+{
383383+ struct kevent kev, ret;
384384+ off_t curpos;
385385+ int fd;
386386+387387+ fd = open("/etc/hosts", O_RDONLY);
388388+ if (fd < 0)
389389+ abort();
390390+391391+ EV_SET(&kev, fd, EVFILT_READ, EV_ADD, 0, 0, &fd);
392392+ if (kevent(ctx->kqfd, &kev, 1, NULL, 0, NULL) < 0)
393393+ die("kevent");
394394+395395+ kevent_get(&ret, ctx->kqfd);
396396+397397+ /* Set file position to EOF-1 */
398398+ ret.data--;
399399+ if ((curpos = lseek(fd, ret.data, SEEK_SET)) != ret.data) {
400400+ printf("seek to %u failed with rv=%lu\n",
401401+ (unsigned int) ret.data, curpos);
402402+ abort();
403403+ }
404404+405405+ /* Set file position to EOF */
406406+ kevent_get(NULL, ctx->kqfd);
407407+ ret.data = curpos + 1;
408408+ if ((curpos = lseek(fd, ret.data, SEEK_SET)) != ret.data) {
409409+ printf("seek to %u failed with rv=%lu\n",
410410+ (unsigned int) ret.data, curpos);
411411+ abort();
412412+ }
413413+414414+ test_no_kevents(ctx->kqfd);
415415+416416+ kev.flags = EV_DELETE;
417417+ if (kevent(ctx->kqfd, &kev, 1, NULL, 0, NULL) < 0)
418418+ die("kevent");
419419+ close(fd);
420420+}
421421+422422+void
423423+test_evfilt_read(struct test_context *ctx)
424424+{
425425+ create_socket_connection(&ctx->client_fd, &ctx->server_fd, ctx->iteration + 23456);
426426+427427+ test(kevent_socket_add, ctx);
428428+ test(kevent_socket_del, ctx);
429429+ test(kevent_socket_add_without_ev_add, ctx);
430430+ test(kevent_socket_get, ctx);
431431+ test(kevent_socket_disable_and_enable, ctx);
432432+ test(kevent_socket_oneshot, ctx);
433433+ test(kevent_socket_clear, ctx);
434434+#ifdef EV_DISPATCH
435435+ test(kevent_socket_dispatch, ctx);
436436+#endif
437437+ test(kevent_socket_listen_backlog, ctx);
438438+ test(kevent_socket_eof, ctx);
439439+ test(kevent_regular_file, ctx);
440440+ close(ctx->client_fd);
441441+ close(ctx->server_fd);
442442+}
+194
external/libkqueue-2.0.1/test/signal.c
···11+/*
22+ * Copyright (c) 2009 Mark Heily <mark@heily.com>
33+ *
44+ * Permission to use, copy, modify, and distribute this software for any
55+ * purpose with or without fee is hereby granted, provided that the above
66+ * copyright notice and this permission notice appear in all copies.
77+ *
88+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
99+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
1010+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
1111+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
1212+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
1313+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
1414+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
1515+ */
1616+1717+#include "common.h"
1818+1919+void
2020+test_kevent_signal_add(struct test_context *ctx)
2121+{
2222+ struct kevent kev;
2323+2424+ kevent_add(ctx->kqfd, &kev, SIGUSR1, EVFILT_SIGNAL, EV_ADD, 0, 0, NULL);
2525+}
2626+2727+void
2828+test_kevent_signal_get(struct test_context *ctx)
2929+{
3030+ struct kevent kev, ret;
3131+3232+ kevent_add(ctx->kqfd, &kev, SIGUSR1, EVFILT_SIGNAL, EV_ADD, 0, 0, NULL);
3333+3434+ if (kill(getpid(), SIGUSR1) < 0)
3535+ die("kill");
3636+3737+ kev.flags |= EV_CLEAR;
3838+ kev.data = 1;
3939+ kevent_get(&ret, ctx->kqfd);
4040+ kevent_cmp(&kev, &ret);
4141+}
4242+4343+void
4444+test_kevent_signal_disable(struct test_context *ctx)
4545+{
4646+ struct kevent kev;
4747+4848+ kevent_add(ctx->kqfd, &kev, SIGUSR1, EVFILT_SIGNAL, EV_DISABLE, 0, 0, NULL);
4949+5050+ if (kill(getpid(), SIGUSR1) < 0)
5151+ die("kill");
5252+5353+ test_no_kevents(ctx->kqfd);
5454+}
5555+5656+void
5757+test_kevent_signal_enable(struct test_context *ctx)
5858+{
5959+ struct kevent kev, ret;
6060+6161+ kevent_add(ctx->kqfd, &kev, SIGUSR1, EVFILT_SIGNAL, EV_ENABLE, 0, 0, NULL);
6262+6363+ if (kill(getpid(), SIGUSR1) < 0)
6464+ die("kill");
6565+6666+ kev.flags = EV_ADD | EV_CLEAR;
6767+#if LIBKQUEUE
6868+ kev.data = 1; /* WORKAROUND */
6969+#else
7070+ kev.data = 2; // one extra time from test_kevent_signal_disable()
7171+#endif
7272+ kevent_get(&ret, ctx->kqfd);
7373+ kevent_cmp(&kev, &ret);
7474+7575+ /* Delete the watch */
7676+ kev.flags = EV_DELETE;
7777+ if (kevent(ctx->kqfd, &kev, 1, NULL, 0, NULL) < 0)
7878+ die("kevent");
7979+}
8080+8181+void
8282+test_kevent_signal_del(struct test_context *ctx)
8383+{
8484+ struct kevent kev;
8585+8686+ /* Delete the kevent */
8787+ kevent_add(ctx->kqfd, &kev, SIGUSR1, EVFILT_SIGNAL, EV_DELETE, 0, 0, NULL);
8888+8989+ signal(SIGUSR1, SIG_IGN);
9090+ if (kill(getpid(), SIGUSR1) < 0)
9191+ die("kill");
9292+9393+ test_no_kevents(ctx->kqfd);
9494+}
9595+9696+void
9797+test_kevent_signal_oneshot(struct test_context *ctx)
9898+{
9999+ struct kevent kev, ret;
100100+101101+ kevent_add(ctx->kqfd, &kev, SIGUSR1, EVFILT_SIGNAL, EV_ADD | EV_ONESHOT, 0, 0, NULL);
102102+103103+ if (kill(getpid(), SIGUSR1) < 0)
104104+ die("kill");
105105+106106+ kev.flags |= EV_CLEAR;
107107+ kev.data = 1;
108108+ kevent_get(&ret, ctx->kqfd);
109109+ kevent_cmp(&kev, &ret);
110110+111111+ /* Send another one and make sure we get no events */
112112+ test_no_kevents(ctx->kqfd);
113113+ if (kill(getpid(), SIGUSR1) < 0)
114114+ die("kill");
115115+ test_no_kevents(ctx->kqfd);
116116+}
117117+118118+void
119119+test_kevent_signal_modify(struct test_context *ctx)
120120+{
121121+ struct kevent kev, ret;
122122+123123+ kevent_add(ctx->kqfd, &kev, SIGUSR1, EVFILT_SIGNAL, EV_ADD, 0, 0, NULL);
124124+ kevent_add(ctx->kqfd, &kev, SIGUSR1, EVFILT_SIGNAL, EV_ADD, 0, 0, ((void *)-1));
125125+126126+ if (kill(getpid(), SIGUSR1) < 0)
127127+ die("kill");
128128+129129+ kev.flags |= EV_CLEAR;
130130+ kev.data = 1;
131131+ kevent_get(&ret, ctx->kqfd);
132132+ kevent_cmp(&kev, &ret);
133133+134134+ test_kevent_signal_del(ctx);
135135+}
136136+137137+#ifdef EV_DISPATCH
138138+void
139139+test_kevent_signal_dispatch(struct test_context *ctx)
140140+{
141141+ struct kevent kev, ret;
142142+143143+ test_no_kevents(ctx->kqfd);
144144+145145+ kevent_add(ctx->kqfd, &kev, SIGUSR1, EVFILT_SIGNAL, EV_ADD | EV_CLEAR | EV_DISPATCH, 0, 0, NULL);
146146+147147+ /* Get one event */
148148+ if (kill(getpid(), SIGUSR1) < 0)
149149+ die("kill");
150150+ kev.data = 1;
151151+ kevent_get(&ret, ctx->kqfd);
152152+ kevent_cmp(&kev, &ret);
153153+154154+ /* Confirm that the knote is disabled */
155155+ if (kill(getpid(), SIGUSR1) < 0)
156156+ die("kill");
157157+ test_no_kevents(ctx->kqfd);
158158+159159+ /* Enable the knote and make sure no events are pending */
160160+ kevent_add(ctx->kqfd, &kev, SIGUSR1, EVFILT_SIGNAL, EV_ENABLE | EV_DISPATCH, 0, 0, NULL);
161161+ test_no_kevents(ctx->kqfd);
162162+163163+ /* Get the next event */
164164+ if (kill(getpid(), SIGUSR1) < 0)
165165+ die("kill");
166166+ kev.flags = EV_ADD | EV_CLEAR | EV_DISPATCH;
167167+ kev.data = 1;
168168+ kevent_get(&ret, ctx->kqfd);
169169+ kevent_cmp(&kev, &ret);
170170+171171+ /* Remove the knote and ensure the event no longer fires */
172172+ kevent_add(ctx->kqfd, &kev, SIGUSR1, EVFILT_SIGNAL, EV_DELETE, 0, 0, NULL);
173173+ if (kill(getpid(), SIGUSR1) < 0)
174174+ die("kill");
175175+ test_no_kevents(ctx->kqfd);
176176+}
177177+#endif /* EV_DISPATCH */
178178+179179+void
180180+test_evfilt_signal(struct test_context *ctx)
181181+{
182182+ signal(SIGUSR1, SIG_IGN);
183183+184184+ test(kevent_signal_add, ctx);
185185+ test(kevent_signal_del, ctx);
186186+ test(kevent_signal_get, ctx);
187187+ test(kevent_signal_disable, ctx);
188188+ test(kevent_signal_enable, ctx);
189189+ test(kevent_signal_oneshot, ctx);
190190+ test(kevent_signal_modify, ctx);
191191+#ifdef EV_DISPATCH
192192+ test(kevent_signal_dispatch, ctx);
193193+#endif
194194+}
+112
external/libkqueue-2.0.1/test/test.c
···11+/*
22+ * Copyright (c) 2009 Mark Heily <mark@heily.com>
33+ *
44+ * Permission to use, copy, modify, and distribute this software for any
55+ * purpose with or without fee is hereby granted, provided that the above
66+ * copyright notice and this permission notice appear in all copies.
77+ *
88+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
99+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
1010+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
1111+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
1212+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
1313+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
1414+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
1515+ */
1616+1717+#if defined(__linux__) && !defined(__ANDROID__)
1818+#include <execinfo.h>
1919+#endif
2020+#include <sys/types.h>
2121+#include <limits.h>
2222+2323+#include "common.h"
2424+2525+static int testnum = 1;
2626+static int error_flag = 1;
2727+2828+/* FIXME: not portable beyond linux */
2929+#ifndef _WIN32
3030+static void
3131+error_handler(int signum)
3232+{
3333+#if defined(__linux__) && !defined(__ANDROID__)
3434+ void *buf[32];
3535+3636+ /* FIXME: the symbols aren't printing */
3737+ printf("***** ERROR: Program received signal %d *****\n", signum);
3838+ backtrace_symbols_fd(buf, sizeof(buf) / sizeof(void *), 2);
3939+#else
4040+ printf("***** ERROR: Program received signal %d *****\n", signum);
4141+#endif
4242+ exit(1);
4343+}
4444+#endif /* ! _WIN32 */
4545+4646+static void
4747+testing_atexit(void)
4848+{
4949+ if (error_flag) {
5050+ printf(" *** TEST FAILED ***\n");
5151+ //TODO: print detailed log
5252+ } else {
5353+ printf("\n---\n"
5454+ "+OK All %d tests completed.\n", testnum - 1);
5555+ }
5656+}
5757+5858+void
5959+test_begin(struct test_context *ctx, const char *func)
6060+{
6161+ if (ctx->cur_test_id)
6262+ free(ctx->cur_test_id);
6363+ ctx->cur_test_id = strdup(func);
6464+6565+ printf("%d: %s\n", testnum++, ctx->cur_test_id);
6666+ //TODO: redirect stdout/err to logfile
6767+}
6868+6969+void
7070+test_end(struct test_context *ctx)
7171+{
7272+ free(ctx->cur_test_id);
7373+ ctx->cur_test_id = NULL;
7474+}
7575+7676+void
7777+testing_begin(void)
7878+{
7979+#ifndef _WIN32
8080+ struct sigaction sa;
8181+8282+ /* Install a signal handler for crashes and hangs */
8383+ memset(&sa, 0, sizeof(sa));
8484+ sa.sa_handler = error_handler;
8585+ sigemptyset(&sa.sa_mask);
8686+ sigaction(SIGSEGV, &sa, NULL);
8787+ sigaction(SIGABRT, &sa, NULL);
8888+ sigaction(SIGINT, &sa, NULL);
8989+#endif
9090+9191+ atexit(testing_atexit);
9292+9393+}
9494+9595+void
9696+testing_end(void)
9797+{
9898+ error_flag = 0;
9999+}
100100+101101+/* Generate a unique ID */
102102+int
103103+testing_make_uid(void)
104104+{
105105+ static int id = 0;
106106+107107+ if (id == INT_MAX)
108108+ abort();
109109+ id++;
110110+111111+ return (id);
112112+}
+170
external/libkqueue-2.0.1/test/timer.c
···11+/*
22+ * Copyright (c) 2009 Mark Heily <mark@heily.com>
33+ *
44+ * Permission to use, copy, modify, and distribute this software for any
55+ * purpose with or without fee is hereby granted, provided that the above
66+ * copyright notice and this permission notice appear in all copies.
77+ *
88+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
99+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
1010+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
1111+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
1212+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
1313+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
1414+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
1515+ */
1616+1717+#include "common.h"
1818+1919+void
2020+test_kevent_timer_add(struct test_context *ctx)
2121+{
2222+ struct kevent kev;
2323+2424+ kevent_add(ctx->kqfd, &kev, 1, EVFILT_TIMER, EV_ADD, 0, 1000, NULL);
2525+}
2626+2727+void
2828+test_kevent_timer_del(struct test_context *ctx)
2929+{
3030+ struct kevent kev;
3131+3232+ kevent_add(ctx->kqfd, &kev, 1, EVFILT_TIMER, EV_DELETE, 0, 0, NULL);
3333+3434+ test_no_kevents(ctx->kqfd);
3535+}
3636+3737+void
3838+test_kevent_timer_get(struct test_context *ctx)
3939+{
4040+ struct kevent kev, ret;
4141+4242+ kevent_add(ctx->kqfd, &kev, 1, EVFILT_TIMER, EV_ADD, 0, 1000, NULL);
4343+4444+ kev.flags |= EV_CLEAR;
4545+ kev.data = 1;
4646+ kevent_get(&ret, ctx->kqfd);
4747+ kevent_cmp(&kev, &ret);
4848+4949+ kevent_add(ctx->kqfd, &kev, 1, EVFILT_TIMER, EV_DELETE, 0, 0, NULL);
5050+}
5151+5252+static void
5353+test_kevent_timer_oneshot(struct test_context *ctx)
5454+{
5555+ struct kevent kev, ret;
5656+5757+ test_no_kevents(ctx->kqfd);
5858+5959+ kevent_add(ctx->kqfd, &kev, 2, EVFILT_TIMER, EV_ADD | EV_ONESHOT, 0, 500,NULL);
6060+6161+ /* Retrieve the event */
6262+ kev.flags = EV_ADD | EV_CLEAR | EV_ONESHOT;
6363+ kev.data = 1;
6464+ kevent_get(&ret, ctx->kqfd);
6565+ kevent_cmp(&kev, &ret);
6666+6767+ /* Check if the event occurs again */
6868+ sleep(3);
6969+ test_no_kevents(ctx->kqfd);
7070+}
7171+7272+static void
7373+test_kevent_timer_periodic(struct test_context *ctx)
7474+{
7575+ struct kevent kev, ret;
7676+7777+ test_no_kevents(ctx->kqfd);
7878+7979+ kevent_add(ctx->kqfd, &kev, 3, EVFILT_TIMER, EV_ADD, 0, 1000,NULL);
8080+8181+ /* Retrieve the event */
8282+ kev.flags = EV_ADD | EV_CLEAR;
8383+ kev.data = 1;
8484+ kevent_get(&ret, ctx->kqfd);
8585+ kevent_cmp(&kev, &ret);
8686+8787+ /* Check if the event occurs again */
8888+ sleep(1);
8989+ kevent_get(&ret, ctx->kqfd);
9090+ kevent_cmp(&kev, &ret);
9191+9292+ /* Delete the event */
9393+ kev.flags = EV_DELETE;
9494+ kevent_update(ctx->kqfd, &kev);
9595+}
9696+9797+static void
9898+test_kevent_timer_disable_and_enable(struct test_context *ctx)
9999+{
100100+ struct kevent kev, ret;
101101+102102+ test_no_kevents(ctx->kqfd);
103103+104104+ /* Add the watch and immediately disable it */
105105+ kevent_add(ctx->kqfd, &kev, 4, EVFILT_TIMER, EV_ADD | EV_ONESHOT, 0, 2000,NULL);
106106+ kev.flags = EV_DISABLE;
107107+ kevent_update(ctx->kqfd, &kev);
108108+ test_no_kevents(ctx->kqfd);
109109+110110+ /* Re-enable and check again */
111111+ kev.flags = EV_ENABLE;
112112+ kevent_update(ctx->kqfd, &kev);
113113+114114+ kev.flags = EV_ADD | EV_CLEAR | EV_ONESHOT;
115115+ kev.data = 1;
116116+ kevent_get(&ret, ctx->kqfd);
117117+ kevent_cmp(&kev, &ret);
118118+}
119119+120120+#ifdef EV_DISPATCH
121121+void
122122+test_kevent_timer_dispatch(struct test_context *ctx)
123123+{
124124+ struct kevent kev, ret;
125125+126126+ test_no_kevents(ctx->kqfd);
127127+128128+ kevent_add(ctx->kqfd, &kev, 4, EVFILT_TIMER, EV_ADD | EV_DISPATCH, 0, 800, NULL);
129129+130130+ /* Get one event */
131131+ kev.flags = EV_ADD | EV_CLEAR | EV_DISPATCH;
132132+ kev.data = 1;
133133+ kevent_get(&ret, ctx->kqfd);
134134+ kevent_cmp(&kev, &ret);
135135+136136+ /* Confirm that the knote is disabled */
137137+ sleep(1);
138138+ test_no_kevents(ctx->kqfd);
139139+140140+ /* Enable the knote and make sure no events are pending */
141141+ kevent_add(ctx->kqfd, &kev, 4, EVFILT_TIMER, EV_ENABLE | EV_DISPATCH, 0, 800, NULL);
142142+ test_no_kevents(ctx->kqfd);
143143+144144+ /* Get the next event */
145145+ sleep(1);
146146+ kev.flags = EV_ADD | EV_CLEAR | EV_DISPATCH;
147147+ kev.data = 1;
148148+ kevent_get(&ret, ctx->kqfd);
149149+ kevent_cmp(&kev, &ret);
150150+151151+ /* Remove the knote and ensure the event no longer fires */
152152+ kevent_add(ctx->kqfd, &kev, 4, EVFILT_TIMER, EV_DELETE, 0, 0, NULL);
153153+ sleep(1);
154154+ test_no_kevents(ctx->kqfd);
155155+}
156156+#endif /* EV_DISPATCH */
157157+158158+void
159159+test_evfilt_timer(struct test_context *ctx)
160160+{
161161+ test(kevent_timer_add, ctx);
162162+ test(kevent_timer_del, ctx);
163163+ test(kevent_timer_get, ctx);
164164+ test(kevent_timer_oneshot, ctx);
165165+ test(kevent_timer_periodic, ctx);
166166+ test(kevent_timer_disable_and_enable, ctx);
167167+#ifdef EV_DISPATCH
168168+ test(kevent_timer_dispatch, ctx);
169169+#endif
170170+}
+170
external/libkqueue-2.0.1/test/user.c
···11+/*
22+ * Copyright (c) 2009 Mark Heily <mark@heily.com>
33+ *
44+ * Permission to use, copy, modify, and distribute this software for any
55+ * purpose with or without fee is hereby granted, provided that the above
66+ * copyright notice and this permission notice appear in all copies.
77+ *
88+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
99+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
1010+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
1111+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
1212+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
1313+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
1414+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
1515+ */
1616+1717+#include "common.h"
1818+1919+static void
2020+test_kevent_user_add_and_delete(struct test_context *ctx)
2121+{
2222+ struct kevent kev;
2323+2424+ kevent_add(ctx->kqfd, &kev, 1, EVFILT_USER, EV_ADD, 0, 0, NULL);
2525+ test_no_kevents(ctx->kqfd);
2626+2727+ kevent_add(ctx->kqfd, &kev, 1, EVFILT_USER, EV_DELETE, 0, 0, NULL);
2828+ test_no_kevents(ctx->kqfd);
2929+}
3030+3131+static void
3232+test_kevent_user_get(struct test_context *ctx)
3333+{
3434+ struct kevent kev, ret;
3535+3636+ test_no_kevents(ctx->kqfd);
3737+3838+ /* Add the event, and then trigger it */
3939+ kevent_add(ctx->kqfd, &kev, 1, EVFILT_USER, EV_ADD | EV_CLEAR, 0, 0, NULL);
4040+ kevent_add(ctx->kqfd, &kev, 1, EVFILT_USER, 0, NOTE_TRIGGER, 0, NULL);
4141+4242+ kev.fflags &= ~NOTE_FFCTRLMASK;
4343+ kev.fflags &= ~NOTE_TRIGGER;
4444+ kev.flags = EV_CLEAR;
4545+ kevent_get(&ret, ctx->kqfd);
4646+ kevent_cmp(&kev, &ret);
4747+4848+ test_no_kevents(ctx->kqfd);
4949+}
5050+5151+static void
5252+test_kevent_user_get_hires(struct test_context *ctx)
5353+{
5454+ struct kevent kev, ret;
5555+5656+ test_no_kevents(ctx->kqfd);
5757+5858+ /* Add the event, and then trigger it */
5959+ kevent_add(ctx->kqfd, &kev, 1, EVFILT_USER, EV_ADD | EV_CLEAR, 0, 0, NULL);
6060+ kevent_add(ctx->kqfd, &kev, 1, EVFILT_USER, 0, NOTE_TRIGGER, 0, NULL);
6161+6262+ kev.fflags &= ~NOTE_FFCTRLMASK;
6363+ kev.fflags &= ~NOTE_TRIGGER;
6464+ kev.flags = EV_CLEAR;
6565+ kevent_get_hires(&ret, ctx->kqfd);
6666+ kevent_cmp(&kev, &ret);
6767+6868+ test_no_kevents(ctx->kqfd);
6969+}
7070+7171+static void
7272+test_kevent_user_disable_and_enable(struct test_context *ctx)
7373+{
7474+ struct kevent kev, ret;
7575+7676+ test_no_kevents(ctx->kqfd);
7777+7878+ kevent_add(ctx->kqfd, &kev, 1, EVFILT_USER, EV_ADD, 0, 0, NULL);
7979+ kevent_add(ctx->kqfd, &kev, 1, EVFILT_USER, EV_DISABLE, 0, 0, NULL);
8080+8181+ /* Trigger the event, but since it is disabled, nothing will happen. */
8282+ kevent_add(ctx->kqfd, &kev, 1, EVFILT_USER, 0, NOTE_TRIGGER, 0, NULL);
8383+ test_no_kevents(ctx->kqfd);
8484+8585+ kevent_add(ctx->kqfd, &kev, 1, EVFILT_USER, EV_ENABLE, 0, 0, NULL);
8686+ kevent_add(ctx->kqfd, &kev, 1, EVFILT_USER, 0, NOTE_TRIGGER, 0, NULL);
8787+8888+ kev.flags = EV_CLEAR;
8989+ kev.fflags &= ~NOTE_FFCTRLMASK;
9090+ kev.fflags &= ~NOTE_TRIGGER;
9191+ kevent_get(&ret, ctx->kqfd);
9292+ kevent_cmp(&kev, &ret);
9393+}
9494+9595+static void
9696+test_kevent_user_oneshot(struct test_context *ctx)
9797+{
9898+ struct kevent kev, ret;
9999+100100+ test_no_kevents(ctx->kqfd);
101101+102102+ kevent_add(ctx->kqfd, &kev, 2, EVFILT_USER, EV_ADD | EV_ONESHOT, 0, 0, NULL);
103103+104104+ puts(" -- event 1");
105105+ kevent_add(ctx->kqfd, &kev, 2, EVFILT_USER, 0, NOTE_TRIGGER, 0, NULL);
106106+107107+ kev.flags = EV_ONESHOT;
108108+ kev.fflags &= ~NOTE_FFCTRLMASK;
109109+ kev.fflags &= ~NOTE_TRIGGER;
110110+ kevent_get(&ret, ctx->kqfd);
111111+ kevent_cmp(&kev, &ret);
112112+113113+ test_no_kevents(ctx->kqfd);
114114+}
115115+116116+#ifdef EV_DISPATCH
117117+void
118118+test_kevent_user_dispatch(struct test_context *ctx)
119119+{
120120+ struct kevent kev, ret;
121121+122122+ test_no_kevents(ctx->kqfd);
123123+124124+ /* Add the event, and then trigger it */
125125+ kevent_add(ctx->kqfd, &kev, 1, EVFILT_USER, EV_ADD | EV_CLEAR | EV_DISPATCH, 0, 0, NULL);
126126+ kevent_add(ctx->kqfd, &kev, 1, EVFILT_USER, 0, NOTE_TRIGGER, 0, NULL);
127127+128128+ /* Retrieve one event */
129129+ kev.fflags &= ~NOTE_FFCTRLMASK;
130130+ kev.fflags &= ~NOTE_TRIGGER;
131131+ kev.flags = EV_CLEAR;
132132+ kevent_get(&ret, ctx->kqfd);
133133+ kevent_cmp(&kev, &ret);
134134+135135+ /* Confirm that the knote is disabled automatically */
136136+ test_no_kevents(ctx->kqfd);
137137+138138+ /* Re-enable the kevent */
139139+ /* FIXME- is EV_DISPATCH needed when rearming ? */
140140+ kevent_add(ctx->kqfd, &kev, 1, EVFILT_USER, EV_ENABLE | EV_CLEAR | EV_DISPATCH, 0, 0, NULL);
141141+ test_no_kevents(ctx->kqfd);
142142+143143+ /* Trigger the event */
144144+ kevent_add(ctx->kqfd, &kev, 1, EVFILT_USER, 0, NOTE_TRIGGER, 0, NULL);
145145+ kev.fflags &= ~NOTE_FFCTRLMASK;
146146+ kev.fflags &= ~NOTE_TRIGGER;
147147+ kev.flags = EV_CLEAR;
148148+ kevent_get(&ret, ctx->kqfd);
149149+ kevent_cmp(&kev, &ret);
150150+ test_no_kevents(ctx->kqfd);
151151+152152+ /* Delete the watch */
153153+ kevent_add(ctx->kqfd, &kev, 1, EVFILT_USER, EV_DELETE, 0, 0, NULL);
154154+ test_no_kevents(ctx->kqfd);
155155+}
156156+#endif /* EV_DISPATCH */
157157+158158+void
159159+test_evfilt_user(struct test_context *ctx)
160160+{
161161+ test(kevent_user_add_and_delete, ctx);
162162+ test(kevent_user_get, ctx);
163163+ test(kevent_user_get_hires, ctx);
164164+ test(kevent_user_disable_and_enable, ctx);
165165+ test(kevent_user_oneshot, ctx);
166166+#ifdef EV_DISPATCH
167167+ test(kevent_user_dispatch, ctx);
168168+#endif
169169+ /* TODO: try different fflags operations */
170170+}
+272
external/libkqueue-2.0.1/test/vnode.c
···11+/*
22+ * Copyright (c) 2009 Mark Heily <mark@heily.com>
33+ *
44+ * Permission to use, copy, modify, and distribute this software for any
55+ * purpose with or without fee is hereby granted, provided that the above
66+ * copyright notice and this permission notice appear in all copies.
77+ *
88+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
99+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
1010+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
1111+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
1212+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
1313+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
1414+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
1515+ */
1616+1717+#include "common.h"
1818+1919+/* Create an empty file */
2020+static void
2121+testfile_create(const char *path)
2222+{
2323+ int fd;
2424+2525+ if ((fd = open(path, O_CREAT | O_WRONLY, 0600)) < 0)
2626+ die("open");
2727+ close(fd);
2828+}
2929+3030+static void
3131+testfile_touch(const char *path)
3232+{
3333+ char buf[1024];
3434+3535+ snprintf(&buf[0], sizeof(buf), "touch %s", path);
3636+ if (system(buf) != 0)
3737+ die("system");
3838+}
3939+4040+static void
4141+testfile_write(const char *path)
4242+{
4343+ char buf[1024];
4444+4545+ snprintf(&buf[0], sizeof(buf), "echo hi >> %s", path);
4646+ if (system(buf) != 0)
4747+ die("system");
4848+}
4949+5050+static void
5151+testfile_rename(const char *path, int step)
5252+{
5353+ char buf[1024];
5454+5555+ snprintf(&buf[0], sizeof(buf), "%s.tmp", path);
5656+ /* XXX-FIXME use of 'step' conceals a major memory corruption
5757+ when the file is renamed twice.
5858+ To replicate, remove "if step" conditional so
5959+ two renames occur in this function.
6060+ */
6161+ if (step == 0) {
6262+ if (rename(path, buf) != 0)
6363+ err(1,"rename");
6464+ } else {
6565+ if (rename(buf, path) != 0)
6666+ err(1,"rename");
6767+ }
6868+}
6969+7070+void
7171+test_kevent_vnode_add(struct test_context *ctx)
7272+{
7373+ struct kevent kev;
7474+7575+ testfile_create(ctx->testfile);
7676+7777+ ctx->vnode_fd = open(ctx->testfile, O_RDWR);
7878+ if (ctx->vnode_fd < 0)
7979+ err(1, "open of %s", ctx->testfile);
8080+8181+ kevent_add(ctx->kqfd, &kev, ctx->vnode_fd, EVFILT_VNODE, EV_ADD,
8282+ NOTE_WRITE | NOTE_ATTRIB | NOTE_RENAME | NOTE_DELETE, 0, NULL);
8383+}
8484+8585+void
8686+test_kevent_vnode_note_delete(struct test_context *ctx)
8787+{
8888+ struct kevent kev, ret;
8989+9090+ kevent_add(ctx->kqfd, &kev, ctx->vnode_fd, EVFILT_VNODE, EV_ADD | EV_ONESHOT, NOTE_DELETE, 0, NULL);
9191+9292+ if (unlink(ctx->testfile) < 0)
9393+ die("unlink");
9494+9595+ kevent_get(&ret, ctx->kqfd);
9696+ kevent_cmp(&kev, &ret);
9797+}
9898+9999+void
100100+test_kevent_vnode_note_write(struct test_context *ctx)
101101+{
102102+ struct kevent kev, ret;
103103+104104+ kevent_add(ctx->kqfd, &kev, ctx->vnode_fd, EVFILT_VNODE, EV_ADD | EV_ONESHOT, NOTE_WRITE, 0, NULL);
105105+106106+ testfile_write(ctx->testfile);
107107+108108+ /* BSD kqueue adds NOTE_EXTEND even though it was not requested */
109109+ /* BSD kqueue removes EV_ENABLE */
110110+ kev.flags &= ~EV_ENABLE; // XXX-FIXME compatibility issue
111111+ kev.fflags |= NOTE_EXTEND; // XXX-FIXME compatibility issue
112112+ kevent_get(&ret, ctx->kqfd);
113113+ kevent_cmp(&kev, &ret);
114114+}
115115+116116+void
117117+test_kevent_vnode_note_attrib(struct test_context *ctx)
118118+{
119119+ struct kevent kev;
120120+ int nfds;
121121+122122+ kevent_add(ctx->kqfd, &kev, ctx->vnode_fd, EVFILT_VNODE, EV_ADD | EV_ONESHOT, NOTE_ATTRIB, 0, NULL);
123123+124124+ testfile_touch(ctx->testfile);
125125+126126+ nfds = kevent(ctx->kqfd, NULL, 0, &kev, 1, NULL);
127127+ if (nfds < 1)
128128+ die("kevent");
129129+ if (kev.ident != ctx->vnode_fd ||
130130+ kev.filter != EVFILT_VNODE ||
131131+ kev.fflags != NOTE_ATTRIB)
132132+ err(1, "%s - incorrect event (sig=%u; filt=%d; flags=%d)",
133133+ test_id, (unsigned int)kev.ident, kev.filter, kev.flags);
134134+}
135135+136136+void
137137+test_kevent_vnode_note_rename(struct test_context *ctx)
138138+{
139139+ struct kevent kev;
140140+ int nfds;
141141+142142+ kevent_add(ctx->kqfd, &kev, ctx->vnode_fd, EVFILT_VNODE, EV_ADD | EV_ONESHOT, NOTE_RENAME, 0, NULL);
143143+144144+ testfile_rename(ctx->testfile, 0);
145145+146146+ nfds = kevent(ctx->kqfd, NULL, 0, &kev, 1, NULL);
147147+ if (nfds < 1)
148148+ die("kevent");
149149+ if (kev.ident != ctx->vnode_fd ||
150150+ kev.filter != EVFILT_VNODE ||
151151+ kev.fflags != NOTE_RENAME)
152152+ err(1, "%s - incorrect event (sig=%u; filt=%d; flags=%d)",
153153+ test_id, (unsigned int)kev.ident, kev.filter, kev.flags);
154154+155155+ testfile_rename(ctx->testfile, 1);
156156+157157+ test_no_kevents(ctx->kqfd);
158158+}
159159+160160+void
161161+test_kevent_vnode_del(struct test_context *ctx)
162162+{
163163+ struct kevent kev;
164164+165165+ kevent_add(ctx->kqfd, &kev, ctx->vnode_fd, EVFILT_VNODE, EV_DELETE, 0, 0, NULL);
166166+}
167167+168168+void
169169+test_kevent_vnode_disable_and_enable(struct test_context *ctx)
170170+{
171171+ struct kevent kev;
172172+ int nfds;
173173+174174+ test_no_kevents(ctx->kqfd);
175175+176176+ /* Add the watch and immediately disable it */
177177+ kevent_add(ctx->kqfd, &kev, ctx->vnode_fd, EVFILT_VNODE, EV_ADD | EV_ONESHOT, NOTE_ATTRIB, 0, NULL);
178178+ kev.flags = EV_DISABLE;
179179+ kevent_update(ctx->kqfd, &kev);
180180+181181+ /* Confirm that the watch is disabled */
182182+ testfile_touch(ctx->testfile);
183183+ test_no_kevents(ctx->kqfd);
184184+185185+ /* Re-enable and check again */
186186+ kev.flags = EV_ENABLE;
187187+ kevent_update(ctx->kqfd, &kev);
188188+ testfile_touch(ctx->testfile);
189189+ nfds = kevent(ctx->kqfd, NULL, 0, &kev, 1, NULL);
190190+ if (nfds < 1)
191191+ die("kevent");
192192+ if (kev.ident != ctx->vnode_fd ||
193193+ kev.filter != EVFILT_VNODE ||
194194+ kev.fflags != NOTE_ATTRIB)
195195+ err(1, "%s - incorrect event (sig=%u; filt=%d; flags=%d)",
196196+ test_id, (unsigned int)kev.ident, kev.filter, kev.flags);
197197+}
198198+199199+#ifdef EV_DISPATCH
200200+void
201201+test_kevent_vnode_dispatch(struct test_context *ctx)
202202+{
203203+ struct kevent kev, ret;
204204+ int nfds;
205205+206206+ test_no_kevents(ctx->kqfd);
207207+208208+ kevent_add(ctx->kqfd, &kev, ctx->vnode_fd, EVFILT_VNODE, EV_ADD | EV_DISPATCH, NOTE_ATTRIB, 0, NULL);
209209+210210+ testfile_touch(ctx->testfile);
211211+212212+ nfds = kevent(ctx->kqfd, NULL, 0, &kev, 1, NULL);
213213+ if (nfds < 1)
214214+ die("kevent");
215215+ if (kev.ident != ctx->vnode_fd ||
216216+ kev.filter != EVFILT_VNODE ||
217217+ kev.fflags != NOTE_ATTRIB)
218218+ err(1, "%s - incorrect event (sig=%u; filt=%d; flags=%d)",
219219+ test_id, (unsigned int)kev.ident, kev.filter, kev.flags);
220220+221221+ /* Confirm that the watch is disabled automatically */
222222+ testfile_touch(ctx->testfile);
223223+ test_no_kevents(ctx->kqfd);
224224+225225+ /* Re-enable the kevent */
226226+ /* FIXME- is EV_DISPATCH needed when rearming ? */
227227+ kevent_add(ctx->kqfd, &kev, ctx->vnode_fd, EVFILT_VNODE, EV_ENABLE | EV_DISPATCH, 0, 0, NULL);
228228+ kev.flags = EV_ADD | EV_DISPATCH; /* FIXME: may not be portable */
229229+ kev.fflags = NOTE_ATTRIB;
230230+ testfile_touch(ctx->testfile);
231231+ kevent_get(&ret, ctx->kqfd);
232232+ kevent_cmp(&kev, &ret);
233233+ test_no_kevents(ctx->kqfd);
234234+235235+ /* Delete the watch */
236236+ kevent_add(ctx->kqfd, &kev, ctx->vnode_fd, EVFILT_VNODE, EV_DELETE, NOTE_ATTRIB, 0, NULL);
237237+}
238238+#endif /* EV_DISPATCH */
239239+240240+void
241241+test_evfilt_vnode(struct test_context *ctx)
242242+{
243243+#if (defined(__sun) && !defined(HAVE_PORT_SOURCE_FILE))
244244+ puts("**NOTE** EVFILT_VNODE is not supported on this version of Solaris");
245245+ return;
246246+#endif
247247+248248+ char *tmpdir = getenv("TMPDIR");
249249+ if (tmpdir == NULL)
250250+#ifdef __ANDROID__
251251+ tmpdir = "/data/local/tmp";
252252+#else
253253+ tmpdir = "/tmp";
254254+#endif
255255+256256+ snprintf(ctx->testfile, sizeof(ctx->testfile), "%s/kqueue-test%d.tmp",
257257+ tmpdir, testing_make_uid());
258258+259259+ test(kevent_vnode_add, ctx);
260260+ test(kevent_vnode_del, ctx);
261261+ test(kevent_vnode_disable_and_enable, ctx);
262262+#ifdef EV_DISPATCH
263263+ test(kevent_vnode_dispatch, ctx);
264264+#endif
265265+ test(kevent_vnode_note_write, ctx);
266266+ test(kevent_vnode_note_attrib, ctx);
267267+ test(kevent_vnode_note_rename, ctx);
268268+ test(kevent_vnode_note_delete, ctx);
269269+ /* TODO: test r590 corner case where a descriptor is closed and
270270+ the associated knote is automatically freed. */
271271+ unlink(ctx->testfile);
272272+}
···11+Version 0.8.2 r195
22+released 7/16/2011
33+---
44+55+ * Use LDADD instead of LDFLAGS (fixes Debian bug #631674)
66+ * Make the "idle" test optional as it does not work on 32-bit Linux
77+ * Use time_t for PWQ_SPIN_USEC to fix a build problem on 32-bit Linux
88+99+Version 0.8.1 r?
1010+released 7/16/2011
1111+---
1212+1313+ * Uploaded to Debian, but not generally released.
1414+1515+Version 0.8 r190
1616+released 7/08/2011
1717+---
1818+1919+ * Remove the 'struct worker' datatype and related housekeeping chores.
2020+2121+ * Fix incorrect usage of pthread_cond_timedwait() for overcommit threads.
2222+2323+ * Various improvements and bug fixes for the Windows port.
2424+2525+ * Prevent a race condition that could cause a use-after-free if a witem
2626+ were freed before manager_workqueue_additem() returned.
2727+2828+ * Prevent races involving the scoreboard variables.
2929+3030+ * Fix a lost wakeup bug when calling worker_stop().
3131+3232+ * Finally fixed the long standing TODO and removed the global lock for pwq enqueue/dequeue.
3333+3434+ * Only signal wakeups for the pool if there are idle threads available to process data.
3535+3636+ * Use atomics for updating the mask with pending workqueues as the global lock was removed.
3737+3838+ * Added optional idle thread spinning by using the PWQ_SPIN_USEC and PWQ_SPIN_THREADS environment variables. The accrued changes decrease latency from 7-8 microseconds to ~1 +- 0.5 microsecond depending on spin configuration. By default, no spinning will be done.
3939+4040+ * Renamed USE_RT_THREADS to PWQ_RT_THREADS for consistency.
4141+4242+ * Allow specification of number of CPU:s by using the environment variable PWQ_ACTIVE_CPU - this is useful when using e.g. processor sets (fewer CPU:s are truly available to the process than is physically available in the machine). Proper auto-detection of this would be even nicer in the future, but investigation for the various platforms is required - this environment variable allows for a simple workaround in the meantime.
4343+4444+Version 0.7.1 r157
4545+released 7/02/2011
4646+---
4747+4848+ * Fix a memory leak in worker_overcommit_main() when reaping idle threads.
4949+5050+Version 0.7 r150
5151+released 6/13/2011
5252+---
5353+5454+ * Replace pthread emulation macros with winpthreads.h from
5555+ http://locklessinc.com/articles/pthreads_on_windows/
5656+5757+ * Fix witem_cache test to link on solaris also
5858+5959+ * Avoid possible overrun of priority level
6060+6161+ * Fixed possible deadlock.
6262+6363+ * Cleaned up witem cache interface and usage for easier reading of code.
6464+6565+ * Link with libumem on Solaris
6666+6767+ * Add -Wextra to CFLAGS and fix the related warnings
6868+6969+ * Implement the workqueue overcommit attribute.
7070+ Make wqlist an array instead of an array of lists.
7171+ Change wqlist_scan() to be more efficient.
7272+7373+Version 0.6 r134
7474+released 5/16/2011
7575+---
7676+7777+ * Add a pthread_atfork() handler to reinitialize the library after fork().
7878+7979+ * Defer the manager thread creation until pthread_workqueue_create_np().
8080+8181+Version 0.5.1 r125
8282+released 5/7/2011
8383+---
8484+8585+ * Fix the testing/latency Makefile to work on 32-bit Linux.
8686+ * Remove unused variables from testing/latency.c
8787+8888+Version 0.5 r120
8989+released 5/6/2011
9090+---
9191+9292+ * Add CMakeLists.txt for building under CMake.
9393+9494+ * Support building on Windows under MinGW and MSVC.
9595+9696+ * Fixed a deadlock during startup. We could actually raise and get a lost wakeup of the pthread_cond_wait in manager_init() as the manager already managed to signal before we went to sleep. (happened around 1/1000 of startups on a large multicore).
9797+9898+ * Finetune ramp-up logic when system is under heavy load - allow up to worker_idle_threshold threads regardless of system load, otherwise limit thread creation when system is under NCPU:s load rather than 2*NCPU:s (it is way too late to limit it on a larger multicore machine...).
9999+100100+ * Create a witem_cache_init() function so that the TLS key can be made private to witem_cache.o
101101+102102+ * Fix compilation on 32-bit Linux (Credit: Marius Zwicker)
103103+104104+ * Don't reset the signal mask, it should be blocked for the manager thread (and any subsequently started threads) as well
105105+106106+ * Enabled experimental support for real-time threads scheduling class on Solaris, specify PWQ_RT_THREADS to enable it. Be careful when using, may take all available resources unless used in combination with processor sets, thus effectivively hanging the machine
107107+108108+ * Add option for static library build activated by defining MAKE_STATIC
109109+110110+ * Enable debugging on windows by an environment variable as well
111111+112112+Version 0.4.1 r99
113113+released 3/13/2011
114114+---
115115+116116+ * Add -lpthread to LDFLAGS
117117+118118+Version 0.4 r97
119119+released 3/12/2011
120120+---
121121+122122+ * Improved printf debugging; to use it, define the environment variable "PWQ_DEBUG=yes"
123123+124124+ * New function threads_runnable() determines how many LWPs are on the run queue and uses
125125+ this information to improve the thread pool management heuristic.
126126+127127+ * All ELF symbols are now hidden by default, and only the public API symbols are visible.
128128+129129+ * Improved workqueue ramp-up and ramp-down behavior.
130130+131131+Version 0.3 r81
132132+released 3/6/2011
133133+---
134134+135135+ * Fix DESTDIR support in the 'make install' target.
136136+137137+Version 0.2 r77
138138+released 3/6/2011
139139+---
140140+141141+ * Add support for FreeBSD, Solaris, and Microsoft Windows
142142+143143+ * Fix a race condition that would cause deadlock in rare cases when either:
144144+ 1) pthread_cond_signal() was called while no other threads were
145145+ blocked a call to pthread_cond_wait(), or
146146+ 2) pthread_cond_signal() was called multiple times before the any thread
147147+ blocking in a call to pthread_cond_wait() was awoken by the scheduler.
148148+149149+ The fix is to ensure that the call to pthread_cond_signal() occurs while
150150+ the calling thread holds the same mutex used by the threads that call
151151+ pthread_cond_wait().
152152+153153+ Credit to Joakim Johansson for finding the bug and providing a patch.
154154+155155+Version 0.1 r?
156156+released 6/13/2010
157157+---
158158+159159+ * Initial release for Debian as a patch applied to libdispatch. There
160160+ was no tarball released for this version.
+118
external/libpthread_workqueue-0.8.2/Makefile
···11+#
22+# Copyright (c) 2010 Mark Heily <mark@heily.com>
33+#
44+# Permission to use, copy, modify, and distribute this software for any
55+# purpose with or without fee is hereby granted, provided that the above
66+# copyright notice and this permission notice appear in all copies.
77+#
88+# THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
99+# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
1010+# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
1111+# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
1212+# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
1313+# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
1414+# OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
1515+#
1616+1717+# Flags to pass to dpkg-buildpackage
1818+DPKGFLAGS=-uc -us
1919+2020+.PHONY :: install uninstall check dist dist-upload publish-www clean merge distclean fresh-build rpm edit cscope valgrind testing
2121+2222+include config.mk
2323+2424+all: $(PROGRAM).so testing
2525+2626+%.dll: $(OBJS)
2727+ $(LD) -o $@ $(LDFLAGS) $(OBJS) $(LDADD)
2828+2929+%.o: %.c $(DEPS)
3030+ $(CC) -c -o $@ $(CFLAGS) $<
3131+3232+$(PROGRAM).a: $(OBJS)
3333+ $(AR) rcs $(PROGRAM).a $(OBJS)
3434+3535+$(PROGRAM).so: $(OBJS)
3636+ $(LD) -shared $(LDFLAGS) $(OBJS) $(LDADD)
3737+ $(LN) -sf $(PROGRAM).so.$(ABI_VERSION) $(PROGRAM).so
3838+ $(LN) -sf $(PROGRAM).so.$(ABI_VERSION) $(PROGRAM).so.$(ABI_MAJOR)
3939+4040+install: $(PROGRAM).so
4141+ $(INSTALL) -d -m 755 $(DESTDIR)$(INCLUDEDIR)
4242+ $(INSTALL) -d -m 755 $(DESTDIR)$(LIBDIR)
4343+ $(INSTALL) -m 644 $(HEADERS) $(DESTDIR)$(INCLUDEDIR)
4444+ $(INSTALL) -m 644 $(PROGRAM).so.$(ABI_VERSION) $(DESTDIR)$(LIBDIR)
4545+ $(LN) -sf $(PROGRAM).so.$(ABI_VERSION) $(DESTDIR)$(LIBDIR)/$(PROGRAM).so.$(ABI_MAJOR)
4646+ $(LN) -sf $(PROGRAM).so.$(ABI_VERSION) $(DESTDIR)$(LIBDIR)/$(PROGRAM).so
4747+ $(INSTALL) -d -m 755 $(DESTDIR)$(MANDIR)/man3
4848+ $(INSTALL) -m 644 pthread_workqueue.3 $(DESTDIR)$(MANDIR)/man3/pthread_workqueue.3
4949+5050+uninstall:
5151+ rm -f $(INCLUDEDIR)/pthread_workqueue.h
5252+ rm -f $(LIBDIR)/pthread_workqueue.so
5353+ rm -f $(LIBDIR)/pthread_workqueue.so.*
5454+ rm -f $(LIBDIR)/pthread_workqueue.a
5555+ rm -f $(MANDIR)/man3/pthread_workqueue.3
5656+5757+reinstall: uninstall install
5858+5959+check: $(PROGRAM).so
6060+ cd testing && make check
6161+6262+edit:
6363+ $(EDITOR) `find ./src -name '*.c' -o -name '*.h'` Makefile
6464+6565+$(PROGRAM)-$(VERSION).tar.gz:
6666+ mkdir $(PROGRAM)-$(VERSION)
6767+ cp Makefile ChangeLog configure config.inc $(MANS) $(PROGRAM)-$(VERSION)
6868+ cp -R src testing include $(PROGRAM)-$(VERSION)
6969+ find $(PROGRAM)-$(VERSION) -name '.svn' -exec rm -rf {} \; 2>/dev/null || true
7070+ tar zcf $(PROGRAM)-$(VERSION).tar.gz $(PROGRAM)-$(VERSION)
7171+ rm -rf $(PROGRAM)-$(VERSION)
7272+7373+testing:
7474+ cd testing && make
7575+7676+dist: clean $(PROGRAM)-$(VERSION).tar.gz
7777+7878+%.asc:
7979+ gpg --armor --detach-sign `echo '$@' | sed 's/.asc$$//'`
8080+8181+dist-upload: dist $(DISTFILE).asc
8282+ scp $(DISTFILE) $(DISTFILE).asc heily.com:/var/www/heily.com/dist/$(PROGRAM)
8383+8484+publish-www:
8585+ cp -R www/* ~/public_html/libkqueue/
8686+8787+clean:
8888+ rm -f tags $(DISTFILE) $(DISTFILE).asc *.a $(OBJS) *.pc *.so *.so.* test-$(PROGRAM)
8989+ cd testing && make clean
9090+ rm -rf pkg
9191+9292+distclean: clean
9393+ rm -f *.tar.gz config.mk config.h $(PROGRAM).pc $(PROGRAM).la rpm.spec
9494+ rm -rf $(PROGRAM)-$(VERSION) 2>/dev/null || true
9595+9696+rpm: clean $(DISTFILE)
9797+ rm -rf rpm *.rpm *.deb
9898+ mkdir -p rpm/BUILD rpm/RPMS rpm/SOURCES rpm/SPECS rpm/SRPMS
9999+ mkdir -p rpm/RPMS/i386 rpm/RPMS/x86_64
100100+ cp $(DISTFILE) rpm/SOURCES
101101+ rpmbuild -bb rpm.spec
102102+ mv ./rpm/RPMS/* .
103103+ rm -rf rpm
104104+ rmdir i386 x86_64 # WORKAROUND: These aren't supposed to exist
105105+ fakeroot alien --scripts *.rpm
106106+107107+deb: clean $(DISTFILE)
108108+ mkdir pkg
109109+ cd pkg && tar zxf ../$(DISTFILE) && mv libpthread_workqueue-$(VERSION) libpthread-workqueue-$(VERSION)
110110+ cp $(DISTFILE) pkg/libpthread-workqueue_$(VERSION).orig.tar.gz
111111+ cp -R ports/debian pkg/libpthread-workqueue-$(VERSION)
112112+ cd pkg && \
113113+ rm -rf `find libpthread-workqueue-$(VERSION)/debian -type d -name .svn` ; \
114114+ perl -pi -e 's/\@\@VERSION\@\@/$(VERSION)/' libpthread-workqueue-$(VERSION)/debian/changelog ; \
115115+ cd libpthread-workqueue-$(VERSION) && dpkg-buildpackage $(DPKGFLAGS)
116116+ lintian -i pkg/*.deb
117117+ @printf "\nThe following packages have been created:\n"
118118+ @find ./pkg -name '*.deb' | sed 's/^/ /'
···11+/*-
22+ * Copyright (c) 2010, Mark Heily <mark@heily.com>
33+ * Copyright (c) 2009, Stacey Son <sson@freebsd.org>
44+ * Copyright (c) 2000-2008, Apple Inc.
55+ * All rights reserved.
66+ *
77+ * Redistribution and use in source and binary forms, with or without
88+ * modification, are permitted provided that the following conditions
99+ * are met:
1010+ * 1. Redistributions of source code must retain the above copyright
1111+ * notice unmodified, this list of conditions, and the following
1212+ * disclaimer.
1313+ * 2. Redistributions in binary form must reproduce the above copyright
1414+ * notice, this list of conditions and the following disclaimer in the
1515+ * documentation and/or other materials provided with the distribution.
1616+ *
1717+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
1818+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
1919+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
2020+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
2121+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
2222+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
2323+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
2424+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
2525+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
2626+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
2727+ *
2828+ */
2929+3030+#ifndef _PTHREAD_WORKQUEUE_H
3131+#define _PTHREAD_WORKQUEUE_H
3232+3333+#if _WIN32
3434+#define _PWQ_EXPORT __declspec(dllexport)
3535+#else
3636+#define _PWQ_EXPORT
3737+#endif
3838+3939+typedef struct _pthread_workqueue * pthread_workqueue_t;
4040+typedef void * pthread_workitem_handle_t;
4141+4242+/* Pad size to 64 bytes. */
4343+typedef struct {
4444+ unsigned int sig;
4545+ int queueprio;
4646+ int overcommit;
4747+ unsigned int pad[13];
4848+} pthread_workqueue_attr_t;
4949+5050+/* Work queue priority attributes. */
5151+#define WORKQ_HIGH_PRIOQUEUE 0
5252+#define WORKQ_DEFAULT_PRIOQUEUE 1
5353+#define WORKQ_LOW_PRIOQUEUE 2
5454+5555+#if defined(__cplusplus)
5656+ extern "C" {
5757+#endif
5858+5959+int _PWQ_EXPORT pthread_workqueue_create_np(pthread_workqueue_t * workqp,
6060+ const pthread_workqueue_attr_t * attr);
6161+6262+int _PWQ_EXPORT pthread_workqueue_additem_np(pthread_workqueue_t workq,
6363+ void (*workitem_func)(void *), void * workitem_arg,
6464+ pthread_workitem_handle_t * itemhandlep, unsigned int *gencountp);
6565+6666+int _PWQ_EXPORT pthread_workqueue_attr_init_np(pthread_workqueue_attr_t * attrp);
6767+6868+int _PWQ_EXPORT pthread_workqueue_attr_destroy_np(pthread_workqueue_attr_t * attr);
6969+7070+int _PWQ_EXPORT pthread_workqueue_attr_setqueuepriority_np(pthread_workqueue_attr_t * attr,
7171+ int qprio);
7272+7373+int _PWQ_EXPORT pthread_workqueue_attr_getovercommit_np(
7474+ const pthread_workqueue_attr_t * attr, int * ocommp);
7575+7676+int _PWQ_EXPORT pthread_workqueue_attr_setovercommit_np(pthread_workqueue_attr_t * attr,
7777+ int ocomm);
7878+7979+int _PWQ_EXPORT pthread_workqueue_requestconcurrency_np(pthread_workqueue_t workq,
8080+ int queue, int request_concurrency);
8181+8282+int _PWQ_EXPORT pthread_workqueue_getovercommit_np(pthread_workqueue_t workq,
8383+ unsigned int *ocommp);
8484+8585+void _PWQ_EXPORT pthread_workqueue_main_np(void);
8686+8787+#ifdef MAKE_STATIC
8888+int _PWQ_EXPORT pthread_workqueue_init_np(void);
8989+#endif
9090+9191+/* NOTE: this is not part of the Darwin API */
9292+unsigned long _PWQ_EXPORT pthread_workqueue_peek_np(const char *);
9393+9494+#if defined(__cplusplus)
9595+ }
9696+#endif
9797+9898+#undef _PWQ_EXPORT
9999+100100+#endif /* _PTHREAD_WORKQUEUE_H */
···11+.\" Copyright (C) 2010 mark@heily.com
22+.\" Copyright (C) 2009 sson@FreeBSD.org
33+.\" All rights reserved.
44+.\"
55+.\" Redistribution and use in source and binary forms, with or without
66+.\" modification, are permitted provided that the following conditions
77+.\" are met:
88+.\" 1. Redistributions of source code must retain the above copyright
99+.\" notice(s), this list of conditions and the following disclaimer as
1010+.\" the first lines of this file unmodified other than the possible
1111+.\" addition of one or more copyright notices.
1212+.\" 2. Redistributions in binary form must reproduce the above copyright
1313+.\" notice(s), this list of conditions and the following disclaimer in
1414+.\" the documentation and/or other materials provided with the
1515+.\" distribution.
1616+.\"
1717+.\" THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER(S) ``AS IS'' AND ANY
1818+.\" EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
1919+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
2020+.\" PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) BE
2121+.\" LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
2222+.\" CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
2323+.\" SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
2424+.\" BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
2525+.\" WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
2626+.\" OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
2727+.\" EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
2828+.\"
2929+.\" $FreeBSD: $
3030+.Dd December 12, 2009
3131+.Dt PTHREAD_WORKQUEUE 3
3232+.Os
3333+.Sh NAME
3434+.Nm pthread_workqueue_init_np ,
3535+.Nm pthread_workqueue_create_np ,
3636+.Nm pthread_workqueue_additem_np
3737+.Nd thread workqueue operations
3838+.Pp
3939+.Nm pthread_workqueue_attr_init_np ,
4040+.Nm pthread_workqueue_attr_destroy_np ,
4141+.Nm pthread_workqueue_attr_getovercommit_np ,
4242+.Nm pthread_workqueue_attr_setovercommit_np ,
4343+.Nm pthread_workqueue_attr_getqueuepriority_np ,
4444+.Nm pthread_workqueue_attr_setqueuepriority_np
4545+.Nd thread workqueue attribute operations
4646+.Sh SYNOPSIS
4747+.In pthread_workqueue.h
4848+.Ft int
4949+.Fn pthread_workqueue_init_np "void"
5050+.Ft int
5151+.Fn pthread_workqueue_create_np "pthread_workqueue_t *workqp" "const pthread_workqueue_attr_t * attr"
5252+.Ft int
5353+.Fn pthread_workqueue_additem_np "pthread_workqueue_t workq" "void ( *workitem_func)(void *)" "void * workitem_arg" "pthread_workitem_handle_t * itemhandlep" "unsigned int *gencountp"
5454+.Ft int
5555+.Fn pthread_workqueue_attr_init_np "pthread_workqueue_attr_t *attr"
5656+.Ft int
5757+.Fn pthread_workqueue_attr_destroy_np "pthread_workqueue_attr_t *attr"
5858+.Ft int
5959+.Fn pthread_workqueue_attr_getovercommit_np "pthread_workqueue_attr_t *attr" "int *ocommp"
6060+.Ft int
6161+.Fn pthread_workqueue_attr_setovercommit_np "pthread_workqueue_attr_t *attr" "int ocomm"
6262+.Ft int
6363+.Fn pthread_workqueue_attr_getqueuepriority_np "pthread_workqueue_attr_t *attr" "int *qpriop"
6464+.Ft int
6565+.Fn pthread_workqueue_attr_setqueuepriority_np "pthread_workqueue_attr_t *attr" "int qprio"
6666+.Sh DESCRIPTION
6767+The
6868+.Fn pthread_workqueue_*_np
6969+functions are used to create and submit work items to a thread pool.
7070+.Pp
7171+The user may create multiple work queues of different priority and
7272+manually overcommit the available resources.
7373+.Pp
7474+.Fn pthread_workqueue_init_np
7575+allocates and initializes the thread workqueue subsystem.
7676+.Pp
7777+.Fn pthread_workqueue_create_np
7878+creates a new thread workqueue with the attributes given by
7979+.Fa attr .
8080+If
8181+.Fa attr
8282+is NULL then the default attributes are used.
8383+A workqueue handle is returned in the
8484+.Fa workqp
8585+parameter.
8686+.Pp
8787+Thread workqueue attributes are used to specify parameters to
8888+.Fn pthread_workqueue_create_np .
8989+One attribute object can be used in multiple calls to
9090+.Fn pthread_workqueue_create_np ,
9191+with or without modifications between calls.
9292+.Pp
9393+.Fn pthread_workqueue_additem_np
9494+is used to submit work items to the thread pool specified by
9595+.Fa workq
9696+parameter.
9797+The work item function and function argument are given by
9898+.Fa workitem_func
9999+and
100100+.Fa workitem_arg .
101101+The work item handle is returned in
102102+.Fa itemhandlep .
103103+.Pp
104104+The
105105+.Fn pthread_workqueue_attr_init_np
106106+function initializes
107107+.Fa attr
108108+with all the default thread workqueue attributes.
109109+.Pp
110110+The
111111+.Fn pthread_workqueue_attr_destroy_np
112112+function destroys
113113+.Fa attr .
114114+.Pp
115115+The
116116+.Fn pthread_workqueue_attr_set*_np
117117+functions set the attribute that corresponds to each function name.
118118+.Fn pthread_workqueue_attr_setovercommit_np
119119+can be used to set the overcommit flag.
120120+If the overcommit flag is set then more threads will be started, if
121121+needed, which may overcommit the physical resources of the system.
122122+.Fn pthread_workqueue_attr_setqueuepriority_np
123123+sets the queue priority attribute of the thread work queue and must be
124124+set to one of the following values:
125125+.Bl -tag -width "Va WORKQ_DEFAULT_PRIOQUEUE"
126126+.It Va WORKQ_HIGH_PRIOQUEUE
127127+Work items in the queue with this attribute will be given higher priority by
128128+the thread scheduler.
129129+.It Va WORKQ_DEFAULT_PRIOQUEUE
130130+Work items in the queue with this attribute are given the default
131131+priority.
132132+.It Va WORKQ_LOW_PRIOQUEUE
133133+Work items in the queue with this attribute will be given lower priority
134134+by the thread scheduler.
135135+.El
136136+.Pp
137137+The
138138+.Fn pthread_workqueue_attr_get*_np
139139+functions copy the value of the attribute that corresponds to each function name
140140+to the location pointed to by the second function parameter.
141141+.Sh RETURN VALUES
142142+If successful, these functions return 0.
143143+Otherwise, an error number is returned to indicate the error.
144144+.Sh ERRORS
145145+The
146146+.Fn pthread_workqueue_init_np
147147+function will fail if:
148148+.Bl -tag -width Er
149149+.It Bq Er ENOMEM
150150+Out of memory.
151151+.El
152152+.Pp
153153+The
154154+.Fn pthread_workqueue_create_np
155155+function will fail if:
156156+.Bl -tag -width Er
157157+.It Bq Er ENOMEM
158158+Out of memory.
159159+.El
160160+.Pp
161161+The
162162+.Fn pthread_workqueue_additem_np
163163+function will fail if:
164164+.Bl -tag -width Er
165165+.It Bq Er EINVAL
166166+Invalid workqueue handle.
167167+.It Bq Er ENOMEM
168168+Out of memory.
169169+.It Bq Er ESRCH
170170+Can not find workqueue.
171171+.El
172172+.Pp
173173+The
174174+.Fn pthread_workqueue_attr_init_np
175175+function will fail if:
176176+.Bl -tag -width Er
177177+.It Bq Er ENOMEM
178178+Out of memory.
179179+.El
180180+.Pp
181181+The
182182+.Fn pthread_workqueue_attr_destroy_np
183183+function will fail if:
184184+.Bl -tag -width Er
185185+.It Bq Er EINVAL
186186+Invalid value for
187187+.Fa attr .
188188+.El
189189+.Pp
190190+The
191191+.Fn pthread_workqueue_attr_setqueuepriority_np
192192+function will fail if:
193193+.Bl -tag -width Er
194194+.It Bq Er EINVAL
195195+Invalid value for
196196+.Fa attr
197197+or for
198198+.Fa qprio.
199199+.El
200200+.Pp
201201+The
202202+.Fn pthread_workqueue_attr_setovercommit_np ,
203203+.Fn pthread_workqueue_attr_getovercommit_np
204204+and
205205+.Fn pthread_workqueue_attr_getqueuepriority_np
206206+functions will fail if:
207207+.Bl -tag -width Er
208208+.It Bq Er EINVAL
209209+Invalid value for
210210+.Fa attr .
211211+.El
212212+.Sh SEE ALSO
213213+.Xr pthread 3 ,
214214+.Xr sysctl 3
215215+.Sh BUGS
216216+There is no way, currently, to remove or destory work queues and pending
217217+work items other than exiting the process.
218218+.Pp
219219+All worker threads run at the same thread priority; however, items placed on high-priority workqueues will be executed before those on lower-priority workqueues.
220220+.Sh HISTORY
221221+This thread workqueues code was created to support Grand Central Dispatch (GCD
222222+or libdispatch) and first appeared in
223223+.Fx 8.0 .
224224+.Sh AUTHORS
225225+.An "Mark Heily" Aq mark@heily.com .
226226+.Br
227227+.Pp
228228+Based on earlier work by
229229+.An "Stacey Son" Aq sson@FreeBSD.org
230230+and
231231+.An Apple, Inc.
+201
external/libpthread_workqueue-0.8.2/src/api.c
···11+/*-
22+ * Copyright (c) 2010, Mark Heily <mark@heily.com>
33+ * Copyright (c) 2009, Stacey Son <sson@freebsd.org>
44+ * Copyright (c) 2000-2008, Apple Inc.
55+ * All rights reserved.
66+ *
77+ * Redistribution and use in source and binary forms, with or without
88+ * modification, are permitted provided that the following conditions
99+ * are met:
1010+ * 1. Redistributions of source code must retain the above copyright
1111+ * notice unmodified, this list of conditions, and the following
1212+ * disclaimer.
1313+ * 2. Redistributions in binary form must reproduce the above copyright
1414+ * notice, this list of conditions and the following disclaimer in the
1515+ * documentation and/or other materials provided with the distribution.
1616+ *
1717+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
1818+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
1919+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
2020+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
2121+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
2222+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
2323+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
2424+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
2525+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
2626+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
2727+ *
2828+ */
2929+3030+#include "private.h"
3131+3232+unsigned int PWQ_ACTIVE_CPU = 0;
3333+int DEBUG_WORKQUEUE = 0;
3434+char *WORKQUEUE_DEBUG_IDENT = "WQ";
3535+3636+static int
3737+valid_workq(pthread_workqueue_t workq)
3838+{
3939+ if (workq->sig == PTHREAD_WORKQUEUE_SIG)
4040+ return (1);
4141+ else
4242+ return (0);
4343+}
4444+4545+int VISIBLE CONSTRUCTOR
4646+pthread_workqueue_init_np(void)
4747+{
4848+#ifdef NDEBUG
4949+ DEBUG_WORKQUEUE = 0;
5050+#else
5151+ DEBUG_WORKQUEUE = (getenv("PWQ_DEBUG") == NULL) ? 0 : 1;
5252+# ifndef _WIN32
5353+ PWQ_RT_THREADS = (getenv("PWQ_RT_THREADS") == NULL) ? 0 : 1;
5454+ PWQ_ACTIVE_CPU = (getenv("PWQ_ACTIVE_CPU") == NULL) ? 0 : atoi(getenv("PWQ_ACTIVE_CPU"));
5555+5656+ if (getenv("PWQ_SPIN_USEC") != NULL)
5757+ PWQ_SPIN_USEC = atoi(getenv("PWQ_SPIN_USEC"));
5858+5959+ if (getenv("PWQ_SPIN_THREADS") != NULL)
6060+ PWQ_SPIN_THREADS = atoi(getenv("PWQ_SPIN_THREADS"));
6161+6262+# endif
6363+#endif
6464+6565+ if (manager_init() < 0)
6666+ return (-1);
6767+6868+ dbg_puts("pthread_workqueue library initialized");
6969+ return (0);
7070+}
7171+7272+int VISIBLE
7373+pthread_workqueue_create_np(pthread_workqueue_t *workqp,
7474+ const pthread_workqueue_attr_t * attr)
7575+{
7676+ pthread_workqueue_t workq;
7777+7878+ if ((attr != NULL) && ((attr->sig != PTHREAD_WORKQUEUE_ATTR_SIG) ||
7979+ (attr->queueprio < 0) || (attr->queueprio >= WORKQ_NUM_PRIOQUEUE)))
8080+ return (EINVAL);
8181+ if ((workq = calloc(1, sizeof(*workq))) == NULL)
8282+ return (ENOMEM);
8383+ workq->sig = PTHREAD_WORKQUEUE_SIG;
8484+ workq->flags = 0;
8585+ STAILQ_INIT(&workq->item_listhead);
8686+ pthread_spin_init(&workq->mtx, PTHREAD_PROCESS_PRIVATE);
8787+ if (attr == NULL) {
8888+ workq->queueprio = WORKQ_DEFAULT_PRIOQUEUE;
8989+ workq->overcommit = 0;
9090+ } else {
9191+ workq->queueprio = attr->queueprio;
9292+ workq->overcommit = attr->overcommit;
9393+ }
9494+9595+ manager_workqueue_create(workq);
9696+9797+ dbg_printf("created queue %p", (void *) workq);
9898+9999+ *workqp = workq;
100100+ return (0);
101101+}
102102+103103+int VISIBLE
104104+pthread_workqueue_additem_np(pthread_workqueue_t workq,
105105+ void (*workitem_func)(void *), void * workitem_arg,
106106+ pthread_workitem_handle_t * itemhandlep,
107107+ unsigned int *gencountp)
108108+{
109109+ struct work *witem;
110110+111111+ if (valid_workq(workq) == 0)
112112+ return (EINVAL);
113113+114114+ witem = witem_alloc(workitem_func, workitem_arg);
115115+116116+ if (itemhandlep != NULL)
117117+ *itemhandlep = (pthread_workitem_handle_t *) witem;
118118+ if (gencountp != NULL)
119119+ *gencountp = witem->gencount;
120120+121121+ manager_workqueue_additem(workq, witem);
122122+123123+ dbg_printf("added item %p to queue %p", (void *) witem, (void *) workq);
124124+125125+ return (0);
126126+}
127127+128128+int VISIBLE
129129+pthread_workqueue_attr_init_np(pthread_workqueue_attr_t *attr)
130130+{
131131+ attr->queueprio = WORKQ_DEFAULT_PRIOQUEUE;
132132+ attr->sig = PTHREAD_WORKQUEUE_ATTR_SIG;
133133+ attr->overcommit = 0;
134134+ return (0);
135135+}
136136+137137+int VISIBLE
138138+pthread_workqueue_attr_destroy_np(pthread_workqueue_attr_t *attr)
139139+{
140140+ if (attr->sig == PTHREAD_WORKQUEUE_ATTR_SIG)
141141+ return (0);
142142+ else
143143+ return (EINVAL); /* Not an attribute struct. */
144144+}
145145+146146+int VISIBLE
147147+pthread_workqueue_attr_getovercommit_np(
148148+ const pthread_workqueue_attr_t *attr, int *ocommp)
149149+{
150150+ if (attr->sig == PTHREAD_WORKQUEUE_ATTR_SIG) {
151151+ *ocommp = attr->overcommit;
152152+ return (0);
153153+ } else
154154+ return (EINVAL); /* Not an attribute struct. */
155155+}
156156+157157+int VISIBLE
158158+pthread_workqueue_attr_setovercommit_np(pthread_workqueue_attr_t *attr,
159159+ int ocomm)
160160+{
161161+ if (attr->sig == PTHREAD_WORKQUEUE_ATTR_SIG) {
162162+ attr->overcommit = ocomm;
163163+ return (0);
164164+ } else
165165+ return (EINVAL);
166166+}
167167+168168+int VISIBLE
169169+pthread_workqueue_attr_getqueuepriority_np(
170170+ pthread_workqueue_attr_t *attr, int *qpriop)
171171+{
172172+ if (attr->sig == PTHREAD_WORKQUEUE_ATTR_SIG) {
173173+ *qpriop = attr->queueprio;
174174+ return (0);
175175+ } else
176176+ return (EINVAL);
177177+}
178178+179179+int VISIBLE
180180+pthread_workqueue_attr_setqueuepriority_np(
181181+ pthread_workqueue_attr_t *attr, int qprio)
182182+{
183183+ if (attr->sig == PTHREAD_WORKQUEUE_ATTR_SIG) {
184184+ switch(qprio) {
185185+ case WORKQ_HIGH_PRIOQUEUE:
186186+ case WORKQ_DEFAULT_PRIOQUEUE:
187187+ case WORKQ_LOW_PRIOQUEUE:
188188+ attr->queueprio = qprio;
189189+ return (0);
190190+ default:
191191+ return (EINVAL);
192192+ }
193193+ } else
194194+ return (EINVAL);
195195+}
196196+197197+unsigned long VISIBLE
198198+pthread_workqueue_peek_np(const char *key)
199199+{
200200+ return manager_peek(key);
201201+}
+83
external/libpthread_workqueue-0.8.2/src/debug.h
···11+/*
22+ * Copyright (c) 2011 Mark Heily <mark@heily.com>
33+ *
44+ * Permission to use, copy, modify, and distribute this software for any
55+ * purpose with or without fee is hereby granted, provided that the above
66+ * copyright notice and this permission notice appear in all copies.
77+ *
88+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
99+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
1010+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
1111+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
1212+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
1313+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
1414+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
1515+ */
1616+1717+#ifndef _DEBUG_H
1818+#define _DEBUG_H
1919+2020+#include <assert.h>
2121+2222+extern int DEBUG_WORKQUEUE;
2323+extern char *WORKQUEUE_DEBUG_IDENT;
2424+2525+#if defined(__linux__)
2626+2727+#include <linux/unistd.h>
2828+#include <sys/syscall.h>
2929+#include <unistd.h>
3030+3131+# define THREAD_ID ((pid_t) syscall(__NR_gettid))
3232+#elif defined(__sun)
3333+# define THREAD_ID (pthread_self())
3434+#elif defined(__FreeBSD__) /* FIXME -- could use thr_self() */
3535+# define THREAD_ID (0)
3636+#elif defined(_WIN32)
3737+# define THREAD_ID (int)(GetCurrentThreadId())
3838+#else
3939+# error Unsupported platform
4040+#endif
4141+4242+4343+#ifndef NDEBUG
4444+#define dbg_puts(str) do { \
4545+ if (DEBUG_WORKQUEUE) \
4646+ fprintf(stderr, "%s [%d]: %s(): %s\n", \
4747+ WORKQUEUE_DEBUG_IDENT, THREAD_ID, __func__, str); \
4848+} while (0)
4949+5050+#define dbg_printf(fmt,...) do { \
5151+ if (DEBUG_WORKQUEUE) \
5252+ fprintf(stderr, "%s [%d]: %s(): "fmt"\n", \
5353+ WORKQUEUE_DEBUG_IDENT, THREAD_ID, __func__, __VA_ARGS__); \
5454+} while (0)
5555+5656+#define dbg_perror(str) do { \
5757+ if (DEBUG_WORKQUEUE) \
5858+ fprintf(stderr, "%s [%d]: %s(): %s: %s (errno=%d)\n", \
5959+ WORKQUEUE_DEBUG_IDENT, THREAD_ID, __func__, str, \
6060+ strerror(errno), errno); \
6161+} while (0)
6262+6363+# define reset_errno() do { errno = 0; } while (0)
6464+6565+# if defined(_WIN32)
6666+# define dbg_lasterror(str) do { \
6767+ if (DEBUG_WORKQUEUE) \
6868+ fprintf(stderr, "%s: [%d] %s(): %s: (LastError=%d)\n", \
6969+ THREAD_ID, __func__, str, GetLastError()); \
7070+} while (0)
7171+# else
7272+# define dbg_lasterror(str) ;
7373+# endif
7474+7575+#else /* NDEBUG */
7676+# define dbg_puts(str) ;
7777+# define dbg_printf(fmt,...) ;
7878+# define dbg_perror(str) ;
7979+# define dbg_lasterror(str) ;
8080+# define reset_errno() ;
8181+#endif
8282+8383+#endif /* ! _DEBUG_H */
···11+/*-
22+ * Copyright (c) 2011, Joakim Johansson <jocke@tbricks.com>
33+ * Copyright (c) 2010, Mark Heily <mark@heily.com>
44+ * Copyright (c) 2009, Stacey Son <sson@freebsd.org>
55+ * Copyright (c) 2000-2008, Apple Inc.
66+ * All rights reserved.
77+ *
88+ * Redistribution and use in source and binary forms, with or without
99+ * modification, are permitted provided that the following conditions
1010+ * are met:
1111+ * 1. Redistributions of source code must retain the above copyright
1212+ * notice unmodified, this list of conditions, and the following
1313+ * disclaimer.
1414+ * 2. Redistributions in binary form must reproduce the above copyright
1515+ * notice, this list of conditions and the following disclaimer in the
1616+ * documentation and/or other materials provided with the distribution.
1717+ *
1818+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
1919+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
2020+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
2121+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
2222+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
2323+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
2424+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
2525+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
2626+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
2727+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
2828+ *
2929+ */
3030+3131+#include "platform.h"
3232+#include "private.h"
3333+#include "pthread_workqueue.h"
3434+#include "thread_info.h"
3535+#include "thread_rt.h"
3636+3737+#include <sys/time.h>
3838+3939+/* Environment setting */
4040+unsigned int PWQ_RT_THREADS = 0;
4141+time_t PWQ_SPIN_USEC = 10000; // The number of microseconds we should spin loop if desired
4242+unsigned int PWQ_SPIN_THREADS = 0; // The number of threads that should be kept spinning
4343+unsigned volatile int current_threads_spinning = 0; // The number of threads currently spinning
4444+4545+/* Tunable constants */
4646+4747+#define WORKER_IDLE_SECONDS_THRESHOLD 5
4848+4949+/* Function prototypes */
5050+static unsigned int get_load_average(void);
5151+static void * worker_main(void *arg);
5252+static void * overcommit_worker_main(void *arg);
5353+static unsigned int get_process_limit(void);
5454+static void manager_start(void);
5555+5656+static unsigned int cpu_count;
5757+static unsigned int worker_min;
5858+static unsigned int worker_idle_threshold; // we don't go down below this if we had to increase # workers
5959+6060+/* Overcommit */
6161+static struct _pthread_workqueue *ocwq[PTHREAD_WORKQUEUE_MAX];
6262+static int ocwq_mask;
6363+static pthread_mutex_t ocwq_mtx;
6464+static pthread_cond_t ocwq_has_work;
6565+static unsigned int ocwq_idle_threads;
6666+6767+/* Non-overcommit */
6868+static struct _pthread_workqueue *wqlist[PTHREAD_WORKQUEUE_MAX];
6969+static volatile unsigned int wqlist_mask; // mask of currently pending workqueues, atomics used for manipulation
7070+static pthread_mutex_t wqlist_mtx;
7171+7272+static pthread_cond_t wqlist_has_work;
7373+static int wqlist_has_manager;
7474+static pthread_attr_t detached_attr;
7575+7676+static struct {
7777+ volatile unsigned int load,
7878+ count,
7979+ idle;
8080+ unsigned int sb_wake_pending;
8181+ pthread_mutex_t sb_wake_mtx;
8282+ pthread_cond_t sb_wake_cond;
8383+} scoreboard;
8484+8585+static unsigned int
8686+worker_idle_threshold_per_cpu(void)
8787+{
8888+ switch (cpu_count)
8989+ {
9090+ case 0:
9191+ case 1:
9292+ case 2:
9393+ case 4:
9494+ return 2;
9595+ case 6:
9696+ return 3;
9797+ case 8:
9898+ case 12:
9999+ return 4;
100100+ case 16:
101101+ case 24:
102102+ return 6;
103103+ case 32:
104104+ case 64:
105105+ return 8;
106106+ default:
107107+ return cpu_count / 4;
108108+ }
109109+110110+ return 2;
111111+}
112112+113113+static void
114114+manager_reinit(void)
115115+{
116116+ if (manager_init() < 0)
117117+ abort();
118118+}
119119+120120+int
121121+manager_init(void)
122122+{
123123+ wqlist_has_manager = 0;
124124+ pthread_cond_init(&wqlist_has_work, NULL);
125125+126126+ pthread_mutex_init(&wqlist_mtx, NULL);
127127+ wqlist_mask = 0;
128128+129129+ pthread_cond_init(&ocwq_has_work, NULL);
130130+ pthread_mutex_init(&ocwq_mtx, NULL);
131131+ ocwq_mask = 0;
132132+ ocwq_idle_threads = 0;
133133+134134+ witem_cache_init();
135135+136136+ cpu_count = (PWQ_ACTIVE_CPU > 0) ? (PWQ_ACTIVE_CPU) : (unsigned int) sysconf(_SC_NPROCESSORS_ONLN);
137137+138138+ pthread_attr_init(&detached_attr);
139139+ pthread_attr_setdetachstate(&detached_attr, PTHREAD_CREATE_DETACHED);
140140+141141+ /* Initialize the scoreboard */
142142+ pthread_cond_init(&scoreboard.sb_wake_cond, NULL);
143143+ pthread_mutex_init(&scoreboard.sb_wake_mtx, NULL);
144144+145145+ /* Determine the initial thread pool constraints */
146146+ worker_min = 2; // we can start with a small amount, worker_idle_threshold will be used as new dynamic low watermark
147147+ worker_idle_threshold = worker_idle_threshold_per_cpu();
148148+149149+ if (pthread_atfork(NULL, NULL, manager_reinit) < 0) {
150150+ dbg_perror("pthread_atfork()");
151151+ return (-1);
152152+ }
153153+154154+ return (0);
155155+}
156156+157157+void
158158+manager_workqueue_create(struct _pthread_workqueue *workq)
159159+{
160160+ pthread_mutex_lock(&wqlist_mtx);
161161+ if (!workq->overcommit && !wqlist_has_manager)
162162+ manager_start();
163163+164164+ if (workq->overcommit) {
165165+ if (ocwq[workq->queueprio] == NULL) {
166166+ ocwq[workq->queueprio] = workq;
167167+ workq->wqlist_index = workq->queueprio;
168168+ } else {
169169+ puts("queue already exists\n");
170170+ abort();
171171+ }
172172+ } else {
173173+ if (wqlist[workq->queueprio] == NULL) {
174174+ wqlist[workq->queueprio] = workq; //FIXME: sort by priority
175175+ workq->wqlist_index = workq->queueprio;
176176+ } else {
177177+ puts("queue already exists\n");
178178+ abort();
179179+ }
180180+ }
181181+ pthread_mutex_unlock(&wqlist_mtx);
182182+}
183183+184184+static struct work *
185185+wqlist_scan(int *queue_priority)
186186+{
187187+ pthread_workqueue_t workq;
188188+ struct work *witem;
189189+ int idx;
190190+191191+ idx = ffs(wqlist_mask);
192192+ if (idx == 0)
193193+ return (NULL);
194194+195195+ workq = wqlist[idx - 1];
196196+197197+ pthread_spin_lock(&workq->mtx);
198198+199199+ witem = STAILQ_FIRST(&workq->item_listhead);
200200+ if (witem != NULL) {
201201+ STAILQ_REMOVE_HEAD(&workq->item_listhead, item_entry);
202202+ if (STAILQ_EMPTY(&workq->item_listhead))
203203+ {
204204+ unsigned int wqlist_index_bit = (0x1 << workq->wqlist_index);
205205+ unsigned int new_mask;
206206+ // Remove this now empty wq from the mask, the only contention here is with threads performing the same
207207+ // operation on another workqueue, so we will not be long
208208+ // the 'bit' for this queue is protected by the spin lock, so we will only clear a bit which we have
209209+ // ownership for (see additem() below for the corresponding part on the producer side)
210210+ do
211211+ {
212212+ new_mask = atomic_and(&wqlist_mask, ~(wqlist_index_bit));
213213+ } while (new_mask & wqlist_index_bit);
214214+ }
215215+ if (queue_priority != NULL)
216216+ *queue_priority = workq->queueprio;
217217+218218+ pthread_spin_unlock(&workq->mtx);
219219+ return (witem);
220220+ } else {
221221+ // this could happen if multiple threads raced and found the same bit with ffs() and
222222+ // emptied the queue completely, so we should just bail out
223223+ pthread_spin_unlock(&workq->mtx);
224224+ return (NULL);
225225+ }
226226+}
227227+228228+static void _wakeup_manager(void)
229229+{
230230+ dbg_puts("asking manager to wake up");
231231+232232+ pthread_mutex_lock(&scoreboard.sb_wake_mtx);
233233+ scoreboard.sb_wake_pending = 1;
234234+ pthread_cond_signal(&scoreboard.sb_wake_cond);
235235+ pthread_mutex_unlock(&scoreboard.sb_wake_mtx);
236236+ return;
237237+}
238238+239239+static void *
240240+overcommit_worker_main(void *arg)
241241+{
242242+ struct timespec ts;
243243+ pthread_workqueue_t workq;
244244+ void (*func)(void *);
245245+ void *func_arg;
246246+ struct work *witem;
247247+ int rv, idx;
248248+249249+ (void)arg;
250250+251251+ pthread_mutex_lock(&ocwq_mtx);
252252+253253+ for (;;) {
254254+ /* Find the highest priority workqueue that is non-empty */
255255+ idx = ffs(ocwq_mask);
256256+ if (idx > 0) {
257257+ workq = ocwq[idx - 1];
258258+ witem = STAILQ_FIRST(&workq->item_listhead);
259259+ if (witem != NULL) {
260260+ /* Remove the first work item */
261261+ STAILQ_REMOVE_HEAD(&workq->item_listhead, item_entry);
262262+ if (STAILQ_EMPTY(&workq->item_listhead))
263263+ ocwq_mask &= ~(0x1 << workq->wqlist_index);
264264+ /* Execute the work item */
265265+ pthread_mutex_unlock(&ocwq_mtx);
266266+ func = witem->func;
267267+ func_arg = witem->func_arg;
268268+ witem_free(witem);
269269+ func(func_arg);
270270+ pthread_mutex_lock(&ocwq_mtx);
271271+ continue;
272272+ }
273273+ }
274274+275275+ /* Wait for more work to be available. */
276276+ clock_gettime(CLOCK_REALTIME, &ts);
277277+ ts.tv_sec += 15;
278278+ ocwq_idle_threads++;
279279+ dbg_printf("waiting for work (idle=%d)", ocwq_idle_threads);
280280+ rv = pthread_cond_timedwait(&ocwq_has_work, &ocwq_mtx, &ts);
281281+ if (rv != 0) {
282282+ /* Normally, the signaler will decrement the idle counter,
283283+ but this path is not taken in response to a signaler.
284284+ */
285285+ ocwq_idle_threads--;
286286+ pthread_mutex_unlock(&ocwq_mtx);
287287+288288+ if (rv == ETIMEDOUT) {
289289+ dbg_puts("timeout, no work available");
290290+ break;
291291+ } else {
292292+ dbg_perror("pthread_cond_timedwait");
293293+ //TODO: some kind of crash mechanism
294294+ break;
295295+ }
296296+ }
297297+ }
298298+299299+ dbg_printf("worker exiting (idle=%d)", ocwq_idle_threads);
300300+ pthread_exit(NULL);
301301+}
302302+303303+static void *
304304+worker_main(void *arg)
305305+{
306306+ struct work *witem;
307307+ void (*func)(void *);
308308+ void *func_arg;
309309+ int queue_priority = 0;
310310+ struct timespec ts_start, ts_now;
311311+312312+ (void) arg;
313313+ dbg_puts("worker thread started");
314314+315315+ if (PWQ_RT_THREADS)
316316+ ptwq_set_current_thread_priority(WORKQ_HIGH_PRIOQUEUE); // start at highest priority possible
317317+318318+ for (;;) {
319319+320320+ witem = wqlist_scan(&queue_priority);
321321+322322+ // Only take overhead of sleeping and/or spinning if we
323323+ // could not get a witem cheaply using the spinlock above
324324+ if (slowpath(!witem))
325325+ {
326326+ // Optional busy loop for getting the next item for a while if so configured
327327+ // We'll only spin limited thread at a time (this is really mostly useful when running
328328+ // in low latency configurations using dedicated processor sets)
329329+ if ((PWQ_SPIN_THREADS > 0) && (current_threads_spinning <= PWQ_SPIN_THREADS))
330330+ {
331331+ atomic_inc(¤t_threads_spinning);
332332+333333+ // If we are racing with another thread, let's skip
334334+ // spinning and instead go through the slowpath below
335335+336336+ if (current_threads_spinning <= PWQ_SPIN_THREADS)
337337+ {
338338+ clock_gettime(CLOCK_REALTIME, &ts_start);
339339+ ts_now.tv_sec = ts_start.tv_sec;
340340+ ts_now.tv_nsec = ts_start.tv_nsec;
341341+342342+ // Spin until we get an item or PWQ_SPIN_USEC microseconds passes
343343+ while (!witem && (((ts_now.tv_sec - ts_start.tv_sec) * 1000000) + (((ts_now.tv_nsec - ts_start.tv_nsec) / 1000)) <= PWQ_SPIN_USEC))
344344+ {
345345+ witem = wqlist_scan(&queue_priority);
346346+ if (!witem)
347347+ {
348348+ // Perhaps a hardware pause
349349+ // instruction could be used here to keep the pace down, probably not needed though
350350+ clock_gettime(CLOCK_REALTIME, &ts_now);
351351+ }
352352+ }
353353+ }
354354+355355+ atomic_dec(¤t_threads_spinning);
356356+ }
357357+358358+ // No witem from the busy loop, let's wait for wakeup
359359+ if (!witem)
360360+ {
361361+ pthread_mutex_lock(&wqlist_mtx);
362362+363363+ /*
364364+ TODO: Consider using pthread_cond_timedwait() so that
365365+ workers can self-terminate if they are idle too long.
366366+ This would also be a failsafe in case there are bugs
367367+ with the scoreboard that cause us to "leak" workers.
368368+ */
369369+ while ((witem = wqlist_scan(&queue_priority)) == NULL)
370370+ pthread_cond_wait(&wqlist_has_work, &wqlist_mtx);
371371+372372+ pthread_mutex_unlock(&wqlist_mtx);
373373+ }
374374+ }
375375+376376+ atomic_dec(&scoreboard.idle);
377377+378378+ if (slowpath(witem->func == NULL)) {
379379+ dbg_puts("worker exiting..");
380380+ atomic_dec(&scoreboard.count);
381381+ witem_free(witem);
382382+ pthread_exit(0);
383383+ }
384384+385385+ dbg_printf("count=%u idle=%u wake_pending=%u",
386386+ scoreboard.count, scoreboard.idle, scoreboard.sb_wake_pending);
387387+388388+ /* Force the manager thread to wakeup if all workers are busy */
389389+ if (slowpath(scoreboard.idle == 0 && !scoreboard.sb_wake_pending))
390390+ _wakeup_manager();
391391+392392+ // If using RT threads, decrease thread prio if we aren't a high prio queue
393393+ if (PWQ_RT_THREADS && (queue_priority != WORKQ_HIGH_PRIOQUEUE))
394394+ ptwq_set_current_thread_priority(queue_priority);
395395+396396+ /* Invoke the callback function, free witem first for possible reuse */
397397+ func = witem->func;
398398+ func_arg = witem->func_arg;
399399+ witem_free(witem);
400400+401401+ func(func_arg);
402402+403403+ atomic_inc(&scoreboard.idle); // initial inc was one in worker_start, this is to avoid a race
404404+405405+ // Only take the overhead and change RT priority back if it was not a high priority queue being serviced
406406+ if (PWQ_RT_THREADS && (queue_priority != WORKQ_HIGH_PRIOQUEUE))
407407+ ptwq_set_current_thread_priority(WORKQ_HIGH_PRIOQUEUE);
408408+ }
409409+410410+ /* NOTREACHED */
411411+ return (NULL);
412412+}
413413+414414+static int
415415+worker_start(void)
416416+{
417417+ pthread_t tid;
418418+419419+ dbg_puts("Spawning another worker");
420420+421421+ atomic_inc(&scoreboard.idle);
422422+ atomic_inc(&scoreboard.count);
423423+424424+ if (pthread_create(&tid, &detached_attr, worker_main, NULL) != 0) {
425425+ dbg_perror("pthread_create(3)");
426426+ atomic_dec(&scoreboard.idle);
427427+ atomic_dec(&scoreboard.count);
428428+ return (-1);
429429+ }
430430+431431+ return (0);
432432+}
433433+434434+static int
435435+worker_stop(void)
436436+{
437437+ struct work *witem;
438438+ pthread_workqueue_t workq;
439439+ int i;
440440+ unsigned int wqlist_index_bit, new_mask;
441441+442442+ witem = witem_alloc(NULL, NULL);
443443+444444+ pthread_mutex_lock(&wqlist_mtx);
445445+ for (i = 0; i < PTHREAD_WORKQUEUE_MAX; i++) {
446446+ workq = wqlist[i];
447447+ if (workq == NULL)
448448+ continue;
449449+450450+ wqlist_index_bit = (0x1 << workq->wqlist_index);
451451+452452+ pthread_spin_lock(&workq->mtx);
453453+454454+ do
455455+ {
456456+ new_mask = atomic_or(&wqlist_mask, wqlist_index_bit);
457457+ } while (!(new_mask & wqlist_index_bit));
458458+459459+ STAILQ_INSERT_TAIL(&workq->item_listhead, witem, item_entry);
460460+461461+ pthread_spin_unlock(&workq->mtx);
462462+463463+ pthread_cond_signal(&wqlist_has_work);
464464+ pthread_mutex_unlock(&wqlist_mtx);
465465+466466+ return (0);
467467+ }
468468+469469+ /* FIXME: this means there are no workqueues.. should never happen */
470470+ dbg_puts("Attempting to add a workitem without a workqueue");
471471+ abort();
472472+473473+ return (-1);
474474+}
475475+476476+static void *
477477+manager_main(void *unused __attribute__ ((unused)))
478478+{
479479+ unsigned int load_max = cpu_count;
480480+ unsigned int worker_max, current_thread_count = 0;
481481+ unsigned int worker_idle_seconds_accumulated = 0;
482482+ unsigned int max_threads_to_stop = 0;
483483+ unsigned int i;
484484+ int cond_wait_rv = 0;
485485+ sigset_t sigmask;
486486+ struct timespec ts;
487487+ struct timeval tp;
488488+489489+ worker_max = get_process_limit();
490490+ scoreboard.load = get_load_average();
491491+492492+ /* Block all signals */
493493+ sigfillset(&sigmask);
494494+ pthread_sigmask(SIG_BLOCK, &sigmask, NULL);
495495+496496+ /* Create the minimum number of workers */
497497+ scoreboard.count = 0;
498498+ for (i = 0; i < worker_min; i++)
499499+ worker_start();
500500+501501+ for (;;) {
502502+503503+ pthread_mutex_lock(&scoreboard.sb_wake_mtx);
504504+505505+ dbg_puts("manager is sleeping");
506506+507507+ (void) gettimeofday(&tp, NULL); // TODO - error checking
508508+509509+ /* Convert from timeval to timespec */
510510+ ts.tv_sec = tp.tv_sec;
511511+ ts.tv_nsec = tp.tv_usec * 1000;
512512+ ts.tv_sec += 1; // wake once per second and check if we have too many idle threads...
513513+514514+ // We should only sleep on the condition if there are no pending signal, spurious wakeup is also ok
515515+ if (scoreboard.sb_wake_pending == 0)
516516+ cond_wait_rv = pthread_cond_timedwait(&scoreboard.sb_wake_cond, &scoreboard.sb_wake_mtx, &ts);
517517+518518+ scoreboard.sb_wake_pending = 0; // we must set this before spawning any new threads below, or we race...
519519+520520+ dbg_puts("manager is awake");
521521+522522+ dbg_printf("load=%u idle=%u workers=%u max_workers=%u worker_min = %u",
523523+ scoreboard.load, scoreboard.idle, scoreboard.count, worker_max, worker_min);
524524+525525+ // If no workers available, check if we should create a new one
526526+ if (scoreboard.idle == 0 && (scoreboard.count > 0)) // last part required for an extremely unlikely race at startup
527527+ {
528528+ scoreboard.load = get_load_average();
529529+530530+ if ((scoreboard.load < load_max) && (scoreboard.count < worker_max))
531531+ {
532532+ if (scoreboard.count < worker_idle_threshold) // allow cheap rampup up to worker_idle_threshold without going to /proc
533533+ {
534534+ worker_start();
535535+ }
536536+ else // check through /proc, will be a bit more expensive in terms of latency
537537+ if (threads_runnable(¤t_thread_count) == 0)
538538+ {
539539+ // only start thread if we have less runnable threads than cpus
540540+ if (current_thread_count >= cpu_count)
541541+ {
542542+ dbg_printf("Not spawning worker thread, thread_runnable = %d >= cpu_count = %d",
543543+ current_thread_count, cpu_count);
544544+ }
545545+ else
546546+ {
547547+ worker_start();
548548+ }
549549+ }
550550+ else // always start thread if we can't get runnable count
551551+ {
552552+ worker_start();
553553+ }
554554+ }
555555+ else // high load, allow rampup up to worker_idle_threshold regardless of this
556556+ {
557557+ if (scoreboard.count < worker_idle_threshold)
558558+ {
559559+ worker_start();
560560+ }
561561+ }
562562+ }
563563+ else
564564+ {
565565+ if (cond_wait_rv == ETIMEDOUT) // Only check for ramp down on the 'timer tick'
566566+ {
567567+ if ((scoreboard.idle - worker_idle_threshold) > 0) // only accumulate if there are 'too many' idle threads
568568+ {
569569+ worker_idle_seconds_accumulated += scoreboard.idle; // keep track of many idle 'thread seconds' we have
570570+571571+ dbg_printf("worker_idle_seconds_accumulated = %d, scoreboard.idle = %d, scoreboard.count = %d\n",
572572+ worker_idle_seconds_accumulated, scoreboard.idle, scoreboard.count);
573573+ }
574574+575575+ // Only consider ramp down if we have accumulated enough thread 'idle seconds'
576576+ // this logic will ensure that a large number of idle threads will ramp down faster
577577+ max_threads_to_stop = worker_idle_seconds_accumulated / WORKER_IDLE_SECONDS_THRESHOLD;
578578+579579+ if (max_threads_to_stop > 0)
580580+ {
581581+ worker_idle_seconds_accumulated = 0;
582582+583583+ if (max_threads_to_stop > (scoreboard.idle - worker_idle_threshold))
584584+ max_threads_to_stop = (scoreboard.idle - worker_idle_threshold);
585585+586586+ // Only stop threads if we actually have 'too many' idle ones in the pool
587587+ if (scoreboard.idle > worker_idle_threshold)
588588+ {
589589+ for (i = 0; i < max_threads_to_stop; i++)
590590+ {
591591+ dbg_puts("Removing one thread from the thread pool");
592592+ worker_stop();
593593+ }
594594+ }
595595+ }
596596+ }
597597+ }
598598+599599+ pthread_mutex_unlock(&scoreboard.sb_wake_mtx);
600600+ }
601601+602602+ /*NOTREACHED*/
603603+ return (NULL);
604604+}
605605+606606+static void
607607+manager_start(void)
608608+{
609609+ pthread_t tid;
610610+ int rv;
611611+612612+ dbg_puts("starting the manager thread");
613613+614614+ do {
615615+ rv = pthread_create(&tid, &detached_attr, manager_main, NULL);
616616+ if (rv == EAGAIN) {
617617+ sleep(1);
618618+ } else if (rv != 0) {
619619+ /* FIXME: not nice */
620620+ dbg_printf("thread creation failed, rv=%d", rv);
621621+ abort();
622622+ }
623623+ } while (rv != 0);
624624+625625+ wqlist_has_manager = 1;
626626+}
627627+628628+void
629629+manager_workqueue_additem(struct _pthread_workqueue *workq, struct work *witem)
630630+{
631631+ unsigned int wqlist_index_bit = (0x1 << workq->wqlist_index);
632632+633633+ if (workq->overcommit) {
634634+ pthread_t tid;
635635+636636+ pthread_mutex_lock(&ocwq_mtx);
637637+ pthread_spin_lock(&workq->mtx);
638638+ STAILQ_INSERT_TAIL(&workq->item_listhead, witem, item_entry);
639639+ pthread_spin_unlock(&workq->mtx);
640640+ ocwq_mask |= wqlist_index_bit;
641641+ if (ocwq_idle_threads > 0) {
642642+ dbg_puts("signaling an idle worker");
643643+ pthread_cond_signal(&ocwq_has_work);
644644+ ocwq_idle_threads--;
645645+ } else {
646646+ (void)pthread_create(&tid, &detached_attr, overcommit_worker_main, NULL);
647647+ }
648648+ pthread_mutex_unlock(&ocwq_mtx);
649649+ } else {
650650+ pthread_spin_lock(&workq->mtx);
651651+652652+ // Only set the mask for the first item added to the workqueue.
653653+ if (STAILQ_EMPTY(&workq->item_listhead))
654654+ {
655655+ unsigned int new_mask;
656656+657657+ // The only possible contention here are with threads performing the same
658658+ // operation on another workqueue, so we will not be blocked long...
659659+ // Threads operating on the same workqueue will be serialized by the spinlock so it is very unlikely.
660660+ do
661661+ {
662662+ new_mask = atomic_or(&wqlist_mask, wqlist_index_bit);
663663+ } while (!(new_mask & wqlist_index_bit));
664664+ }
665665+666666+ STAILQ_INSERT_TAIL(&workq->item_listhead, witem, item_entry);
667667+668668+ pthread_spin_unlock(&workq->mtx);
669669+670670+ // Only signal thread wakeup if there are idle threads available
671671+ // and no other thread have managed to race us and empty the wqlist on our behalf already
672672+ if ((scoreboard.idle > 0)) // && ((wqlist_mask & wqlist_index_bit) != 0)) // disabling this fringe optimization for now
673673+ {
674674+ pthread_mutex_lock(&wqlist_mtx);
675675+ pthread_cond_signal(&wqlist_has_work);
676676+ pthread_mutex_unlock(&wqlist_mtx);
677677+ }
678678+ }
679679+}
680680+681681+682682+static unsigned int
683683+get_process_limit(void)
684684+{
685685+#if __linux__
686686+ struct rlimit rlim;
687687+688688+ if (getrlimit(RLIMIT_NPROC, &rlim) < 0) {
689689+ dbg_perror("getrlimit(2)");
690690+ return (50);
691691+ } else {
692692+ return (rlim.rlim_max);
693693+ }
694694+#else
695695+ /* Solaris doesn't define this limit anywhere I can see.. */
696696+ return (64);
697697+#endif
698698+}
699699+700700+static unsigned int
701701+get_load_average(void)
702702+{
703703+ double loadavg;
704704+705705+ /* TODO: proper error handling */
706706+ if (getloadavg(&loadavg, 1) != 1) {
707707+ dbg_perror("getloadavg(3)");
708708+ return (1);
709709+ }
710710+ if (loadavg > INT_MAX || loadavg < 0)
711711+ loadavg = 1;
712712+713713+ return ((int) loadavg);
714714+}
715715+716716+unsigned long
717717+manager_peek(const char *key)
718718+{
719719+ uint64_t rv;
720720+721721+ if (strcmp(key, "combined_idle") == 0) {
722722+ rv = scoreboard.idle;
723723+ if (scoreboard.idle > worker_min)
724724+ rv -= worker_min;
725725+ rv += ocwq_idle_threads;
726726+ } else if (strcmp(key, "idle") == 0) {
727727+ rv = scoreboard.idle;
728728+ if (scoreboard.idle > worker_min)
729729+ rv -= worker_min;
730730+ } else if (strcmp(key, "ocomm_idle") == 0) {
731731+ rv = ocwq_idle_threads;
732732+ } else {
733733+ dbg_printf("invalid key: %s", key);
734734+ abort();
735735+ }
736736+737737+ return rv;
738738+}
···11+/*
22+ * Copyright (c) 2011, Joakim Johansson <jocke@tbricks.com>
33+ *
44+ * All rights reserved.
55+ *
66+ * Redistribution and use in source and binary forms, with or without
77+ * modification, are permitted provided that the following conditions
88+ * are met:
99+ * 1. Redistributions of source code must retain the above copyright
1010+ * notice unmodified, this list of conditions, and the following
1111+ * disclaimer.
1212+ * 2. Redistributions in binary form must reproduce the above copyright
1313+ * notice, this list of conditions and the following disclaimer in the
1414+ * documentation and/or other materials provided with the distribution.
1515+ *
1616+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
1717+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
1818+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
1919+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
2020+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
2121+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
2222+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
2323+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
2424+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
2525+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
2626+ *
2727+ */
2828+2929+#include "platform.h"
3030+#include "private.h"
3131+3232+#if defined(__sun)
3333+3434+#include <stdio.h>
3535+#include <procfs.h>
3636+#include <sys/types.h>
3737+#include <sys/stat.h>
3838+#include <sys/syscall.h>
3939+#include <fcntl.h>
4040+4141+/*
4242+4343+ /proc for Solaris
4444+4545+ STRUCTURE OF /proc/pid
4646+ A given directory /proc/pid contains the following entries.
4747+ A process can use the invisible alias /proc/self if it
4848+ wishes to open one of its own /proc files (invisible in the
4949+ sense that the name ``self'' does not appear in a directory
5050+ listing of /proc obtained from ls(1), getdents(2), or
5151+ readdir(3C)).
5252+...
5353+ lstatus
5454+ Contains a prheader structure followed by an array of
5555+ lwpstatus structures, one for each active lwp in the process
5656+ (see also /proc/pid/lwp/lwpid/lwpstatus, below). The
5757+ prheader structure describes the number and size of the
5858+ array entries that follow.
5959+6060+ typedef struct prheader {
6161+ long pr_nent; // number of entries
6262+ size_t pr_entsize; // size of each entry, in bytes
6363+ } prheader_t;
6464+6565+ The lwpstatus structure may grow by the addition of elements
6666+ at the end in future releases of the system. Programs must
6767+ use pr_entsize in the file header to index through the
6868+ array. These comments apply to all /proc files that include
6969+ a prheader structure (lpsinfo and lusage, below).
7070+7171+ /proc/self/lstatus
7272+ */
7373+7474+int threads_runnable(unsigned int *threads_running)
7575+{
7676+ const char *path = "/proc/self/lstatus";
7777+ int read_fd, retval = -1, i;
7878+ unsigned int running_count = 0;
7979+ char *lwp_buffer;
8080+ ssize_t actual_read;
8181+ lwpstatus_t *lwpstatus;
8282+ prheader_t prheader;
8383+8484+ read_fd = open(path, O_RDONLY);
8585+ if (read_fd == -1)
8686+ {
8787+ dbg_perror("open()");
8888+ return retval;
8989+ }
9090+9191+ if (fcntl(read_fd, F_SETFL, O_NONBLOCK) != 0)
9292+ {
9393+ dbg_perror("fcntl()");
9494+ goto errout;
9595+ }
9696+9797+ actual_read = read(read_fd, &prheader, sizeof(prheader_t));
9898+9999+ if (actual_read != sizeof(prheader_t))
100100+ {
101101+ dbg_printf("read returned wrong number of bytes - %ld instead of %ld", actual_read, sizeof(prheader_t));
102102+ goto errout;
103103+ }
104104+105105+ dbg_printf("read prheader, pr_nent = %ld, pr_entsize = %ld, sizeof(lwpstatus_t) = %ld",prheader.pr_nent, prheader.pr_entsize, sizeof(lwpstatus_t));
106106+107107+ lwp_buffer = malloc(prheader.pr_nent * prheader.pr_entsize);
108108+109109+ if (!lwp_buffer)
110110+ {
111111+ dbg_perror("malloc(prheader.pr_nent * prheader.pr_entsize)");
112112+ goto errout;
113113+ }
114114+115115+ actual_read = read(read_fd, lwp_buffer, (prheader.pr_nent * prheader.pr_entsize));
116116+117117+ if (actual_read != (prheader.pr_nent * prheader.pr_entsize))
118118+ {
119119+ dbg_printf("read returned wrong number of bytes - %ld instead of %ld", actual_read, prheader.pr_nent * prheader.pr_entsize);
120120+ free(lwp_buffer);
121121+ goto errout;
122122+ }
123123+124124+ for (i = 0; i < prheader.pr_nent; i++)
125125+ {
126126+ lwpstatus = (lwpstatus_t *) (lwp_buffer + (i * prheader.pr_entsize));
127127+ dbg_printf("lwp %d, syscall = %d", lwpstatus->pr_lwpid, lwpstatus->pr_syscall);
128128+129129+ if (lwpstatus->pr_flags & PR_ASLEEP)
130130+ {
131131+ dbg_printf("lwp %d is sleeping",lwpstatus->pr_lwpid);
132132+ }
133133+ else
134134+ {
135135+ running_count++;
136136+ dbg_printf("lwp %d is running",lwpstatus->pr_lwpid);
137137+ }
138138+ }
139139+140140+ free(lwp_buffer);
141141+ retval = 0;
142142+ *threads_running = running_count;
143143+144144+errout:
145145+ if (close(read_fd) != 0)
146146+ {
147147+ dbg_perror("close()");
148148+ }
149149+150150+ return retval;
151151+}
152152+153153+#elif defined(__linux__)
154154+155155+/*
156156+157157+ /proc for Linux
158158+159159+ /proc/self
160160+ This directory refers to the process accessing the /proc filesystem, and is identical to the /proc directory named by the process ID of the same process.
161161+162162+ �������
163163+164164+ /proc/[number]/stat
165165+ Status information about the process. This is used by ps(1). It is defined in /usr/src/linux/fs/proc/array.c.
166166+ The fields, in order, with their proper scanf(3) format specifiers, are:
167167+168168+ pid %d
169169+ The process ID.
170170+171171+ comm %s
172172+ The filename of the executable, in parentheses. This is visible whether or not the executable is swapped out.
173173+174174+ state %c
175175+ One character from the string "RSDZTW" where R is running, S is sleeping in an interruptible wait, D is waiting in uninterruptible disk sleep, Z is zombie, T is traced or stopped (on a signal), and W is paging.
176176+177177+ ---------------
178178+179179+ /proc/[number]/task (since kernel 2.6.0-test6)
180180+ This is a directory that contains one subdirectory for each thread in the process. The name of each subdirectory is the numerical thread ID of the thread (see gettid(2)). Within each of these subdirectories, there is a set of files with the same names and contents as under the /proc/[number] directories. For attributes that are shared by all threads, the contents for each of the files under the task/[thread-ID] subdirectories will be the same as in the corresponding file in the parent /proc/[number] directory (e.g., in a multithreaded process, all of the task/[thread-ID]/cwd files will have the same value as the /proc/[number]/cwd file in the parent directory, since all of the threads in a process share a working directory). For attributes that are distinct for each thread, the corresponding files under task/[thread-ID] may have different values (e.g., various fields in each of the task/[thread-ID]/status files may be different for each thread).
181181+ In a multithreaded process, the contents of the /proc/[number]/task directory are not available if the main thread has already terminated (typically by calling pthread_exit(3)).
182182+183183+ ---------------
184184+185185+ Example:
186186+ read data from /proc/self/task/11019/stat: [11019 (lt-dispatch_sta) D 20832 10978 20832 34819 10978 4202560 251 3489 0 0 0 2 2 5 20 0 37 0 138715543 2538807296 13818 18446744073709551615 4194304 4203988 140736876632592 139770298610200 139771956665732 0 0 0 0 0 0 0 -1 2 0 0 0 0 0
187187+188188+*/
189189+190190+#include <stdio.h>
191191+#include <sys/types.h>
192192+#include <dirent.h>
193193+#include <errno.h>
194194+#include <fcntl.h>
195195+196196+#define MAX_RESULT_SIZE 4096
197197+198198+static int _read_file(const char *path, char *result)
199199+{
200200+ int read_fd, retval = -1;
201201+ ssize_t actual_read;
202202+203203+ read_fd = open(path, O_RDONLY);
204204+ if (read_fd == -1)
205205+ {
206206+ dbg_perror("open()");
207207+ return retval;
208208+ }
209209+210210+ if (fcntl(read_fd, F_SETFL, O_NONBLOCK) != 0)
211211+ {
212212+ dbg_perror("fcntl()");
213213+ goto errout;
214214+ }
215215+216216+217217+ actual_read = read(read_fd, result, MAX_RESULT_SIZE);
218218+219219+# ifdef __ia64__
220220+ dbg_printf("read %ld from %s", actual_read, path);
221221+# else
222222+ dbg_printf("read %zd from %s", actual_read, path);
223223+#endif
224224+225225+ if (actual_read == 0)
226226+ {
227227+ goto errout;
228228+ }
229229+230230+ retval = 0;
231231+232232+errout:
233233+ if (close(read_fd) != 0)
234234+ {
235235+ dbg_perror("close()");
236236+ }
237237+238238+ return retval;
239239+}
240240+241241+242242+int threads_runnable(unsigned int *threads_running)
243243+{
244244+ DIR *dip;
245245+ struct dirent *dit;
246246+ const char *task_path = "/proc/self/task";
247247+ char thread_path[1024];
248248+ char thread_data[MAX_RESULT_SIZE+1];
249249+ char dummy[MAX_RESULT_SIZE+1];
250250+ char state;
251251+ int pid;
252252+ unsigned int running_count = 0;
253253+254254+ dbg_puts("Checking threads_runnable()");
255255+256256+ if ((dip = opendir(task_path)) == NULL)
257257+ {
258258+ dbg_perror("opendir");
259259+ return -1;
260260+ }
261261+262262+ while ((dit = readdir(dip)) != NULL)
263263+ {
264264+ memset(thread_data, 0, sizeof(thread_data));
265265+266266+ sprintf(thread_path, "%s/%s/stat",task_path, dit->d_name);
267267+268268+ if (_read_file(thread_path, thread_data) == 0)
269269+ {
270270+ if (sscanf(thread_data, "%d %s %c", &pid, dummy, &state) == 3)
271271+ {
272272+ dbg_printf("The state for thread %s is %c", dit->d_name, state);
273273+ switch (state)
274274+ {
275275+ case 'R':
276276+ running_count++;
277277+ break;
278278+ default:
279279+ break;
280280+ }
281281+ }
282282+ else
283283+ {
284284+ dbg_printf("Failed to scan state for thread %s (%s)", dit->d_name, thread_data);
285285+ }
286286+ }
287287+ }
288288+289289+ if (closedir(dip) == -1)
290290+ {
291291+ perror("closedir");
292292+ }
293293+294294+ dbg_printf("Running count is %d", running_count);
295295+ *threads_running = running_count;
296296+297297+ return 0;
298298+}
299299+300300+#else
301301+302302+int threads_runnable(unsigned int *threads_running)
303303+{
304304+ return -1;
305305+}
306306+307307+#endif
···11+/*
22+ * Copyright (c) 2011, Joakim Johansson <jocke@tbricks.com>
33+ *
44+ * All rights reserved.
55+ *
66+ * Redistribution and use in source and binary forms, with or without
77+ * modification, are permitted provided that the following conditions
88+ * are met:
99+ * 1. Redistributions of source code must retain the above copyright
1010+ * notice unmodified, this list of conditions, and the following
1111+ * disclaimer.
1212+ * 2. Redistributions in binary form must reproduce the above copyright
1313+ * notice, this list of conditions and the following disclaimer in the
1414+ * documentation and/or other materials provided with the distribution.
1515+ *
1616+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
1717+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
1818+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
1919+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
2020+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
2121+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
2222+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
2323+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
2424+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
2525+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
2626+ *
2727+ */
2828+2929+#include "platform.h"
3030+#include "private.h"
3131+3232+#if defined(__sun)
3333+3434+#include <stdio.h>
3535+#include <pthread.h>
3636+#include <sys/types.h>
3737+#include <sys/signal.h>
3838+#include <sys/procset.h>
3939+#include <sys/priocntl.h>
4040+#include <sys/rtpriocntl.h>
4141+#include <sys/tspriocntl.h>
4242+#include <sys/iapriocntl.h>
4343+#include <sys/fsspriocntl.h>
4444+#include <sys/fxpriocntl.h>
4545+4646+// Set the RT priority - it is inveresed from the queue priorities, higher is better
4747+// We give '0' to low prio queues and the highest possible for the 'high' prio queue (currently 2)
4848+4949+void ptwq_set_current_thread_priority(int priority)
5050+{
5151+ long retval = 0;
5252+5353+ dbg_printf("reconfiguring thread for priority level=%u", priority);
5454+5555+ switch (priority)
5656+ {
5757+ case WORKQ_LOW_PRIOQUEUE:
5858+ retval = priocntl(P_LWPID, P_MYID, PC_SETXPARMS, "TS", 0); // run low prio queues as time sharing
5959+ break;
6060+ case WORKQ_DEFAULT_PRIOQUEUE:
6161+ retval = priocntl(P_LWPID, P_MYID, PC_SETXPARMS, "RT", RT_KY_PRI, WORKQ_NUM_PRIOQUEUE - priority - 1, 0);
6262+ break;
6363+ case WORKQ_HIGH_PRIOQUEUE:
6464+ retval = priocntl(P_LWPID, P_MYID, PC_SETXPARMS, "RT", RT_KY_PRI, WORKQ_NUM_PRIOQUEUE - priority - 1, 0);
6565+ break;
6666+ default:
6767+ dbg_printf("Unknown priority level = %u", priority);
6868+ break;
6969+ }
7070+7171+7272+ if (retval != 0)
7373+ dbg_perror("priocntl()");
7474+7575+ return;
7676+}
7777+7878+#else
7979+8080+void ptwq_set_current_thread_priority(int priority __attribute__ ((unused)))
8181+{
8282+ return;
8383+}
8484+8585+#endif
+127
external/libpthread_workqueue-0.8.2/src/private.h
···11+/*-
22+ * Copyright (c) 2011, Mark Heily <mark@heily.com>
33+ * Copyright (c) 2009, Stacey Son <sson@freebsd.org>
44+ * Copyright (c) 2000-2008, Apple Inc.
55+ * All rights reserved.
66+ *
77+ * Redistribution and use in source and binary forms, with or without
88+ * modification, are permitted provided that the following conditions
99+ * are met:
1010+ * 1. Redistributions of source code must retain the above copyright
1111+ * notice unmodified, this list of conditions, and the following
1212+ * disclaimer.
1313+ * 2. Redistributions in binary form must reproduce the above copyright
1414+ * notice, this list of conditions and the following disclaimer in the
1515+ * documentation and/or other materials provided with the distribution.
1616+ *
1717+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
1818+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
1919+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
2020+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
2121+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
2222+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
2323+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
2424+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
2525+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
2626+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
2727+ *
2828+ */
2929+3030+#ifndef _PTWQ_PRIVATE_H
3131+#define _PTWQ_PRIVATE_H 1
3232+3333+#include <errno.h>
3434+#include <limits.h>
3535+#include <signal.h>
3636+#include <stdlib.h>
3737+#include <stdio.h>
3838+#include <string.h>
3939+4040+#if defined(_WIN32)
4141+# include "windows/platform.h"
4242+#else
4343+# include "posix/platform.h"
4444+#endif
4545+4646+#include "pthread_workqueue.h"
4747+#include "debug.h"
4848+4949+/* The maximum number of workqueues that can be created.
5050+ This is based on libdispatch only needing 6 workqueues.
5151+ */
5252+#define PTHREAD_WORKQUEUE_MAX 31
5353+5454+/* The total number of priority levels. */
5555+#define WORKQ_NUM_PRIOQUEUE 3
5656+5757+/* Signatures/magic numbers. */
5858+#define PTHREAD_WORKQUEUE_SIG 0xBEBEBEBE
5959+#define PTHREAD_WORKQUEUE_ATTR_SIG 0xBEBEBEBE
6060+6161+/* Whether to use real-time threads for the workers if available */
6262+6363+extern unsigned int PWQ_RT_THREADS;
6464+extern time_t PWQ_SPIN_USEC;
6565+extern unsigned int PWQ_SPIN_THREADS;
6666+6767+/* A limit of the number of cpu:s that we view as available, useful when e.g. using processor sets */
6868+extern unsigned int PWQ_ACTIVE_CPU;
6969+7070+#if __GNUC__
7171+#define fastpath(x) ((__typeof__(x))__builtin_expect((long)(x), ~0l))
7272+#define slowpath(x) ((__typeof__(x))__builtin_expect((long)(x), 0l))
7373+#else
7474+#define fastpath(x) (x)
7575+#define slowpath(x) (x)
7676+#endif
7777+7878+#define CACHELINE_SIZE 64
7979+#define ROUND_UP_TO_CACHELINE_SIZE(x) (((x) + (CACHELINE_SIZE - 1)) & ~(CACHELINE_SIZE - 1))
8080+8181+/*
8282+ * The work item cache, has three different optional implementations:
8383+ * 1. No cache, just normal malloc/free using the standard malloc library in use
8484+ * 2. Libumem based object cache, requires linkage with libumem - for non-Solaris see http://labs.omniti.com/labs/portableumem
8585+ * this is the most balanced cache supporting migration across threads of allocated/freed witems
8686+ * 3. TSD based cache, modelled on libdispatch continuation implementation, can lead to imbalance with assymetric
8787+ * producer/consumer threads as allocated memory is cached by the thread freeing it
8888+ */
8989+9090+#define WITEM_CACHE_TYPE 1 // Set to 1, 2 or 3 to specify witem cache implementation to use
9191+9292+struct work {
9393+ STAILQ_ENTRY(work) item_entry;
9494+ void (*func)(void *);
9595+ void *func_arg;
9696+ unsigned int flags;
9797+ unsigned int gencount;
9898+#if (WITEM_CACHE_TYPE == 3)
9999+ struct work *volatile wi_next;
100100+#endif
101101+};
102102+103103+struct _pthread_workqueue {
104104+ unsigned int sig; /* Unique signature for this structure */
105105+ unsigned int flags;
106106+ int queueprio;
107107+ int overcommit;
108108+ unsigned int wqlist_index;
109109+ STAILQ_HEAD(,work) item_listhead;
110110+ pthread_spinlock_t mtx;
111111+#ifdef WORKQUEUE_PLATFORM_SPECIFIC
112112+ WORKQUEUE_PLATFORM_SPECIFIC;
113113+#endif
114114+};
115115+116116+/* manager.c */
117117+int manager_init(void);
118118+unsigned long manager_peek(const char *);
119119+void manager_workqueue_create(struct _pthread_workqueue *);
120120+void manager_workqueue_additem(struct _pthread_workqueue *, struct work *);
121121+122122+struct work *witem_alloc(void (*func)(void *), void *func_arg); // returns a properly initialized witem
123123+void witem_free(struct work *wi);
124124+int witem_cache_init(void);
125125+void witem_cache_cleanup(void *value);
126126+127127+#endif /* _PTWQ_PRIVATE_H */
···11+/*
22+ * Copyright (c) 2011, Joakim Johansson <jocke@tbricks.com>
33+ *
44+ * All rights reserved.
55+ *
66+ * Redistribution and use in source and binary forms, with or without
77+ * modification, are permitted provided that the following conditions
88+ * are met:
99+ * 1. Redistributions of source code must retain the above copyright
1010+ * notice unmodified, this list of conditions, and the following
1111+ * disclaimer.
1212+ * 2. Redistributions in binary form must reproduce the above copyright
1313+ * notice, this list of conditions and the following disclaimer in the
1414+ * documentation and/or other materials provided with the distribution.
1515+ *
1616+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
1717+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
1818+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
1919+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
2020+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
2121+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
2222+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
2323+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
2424+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
2525+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
2626+ *
2727+ */
2828+2929+#ifndef _PTWQ_POSIX_THREAD_INFO_H
3030+#define _PTWQ_POSIX_THREAD_INFO_H 1
3131+3232+int threads_runnable(unsigned int *threads_running);
3333+3434+#endif /* _PTWQ_POSIX_THREAD_INFO_H */
···11+/*
22+ * Copyright (c) 2011, Joakim Johansson <jocke@tbricks.com>
33+ *
44+ * All rights reserved.
55+ *
66+ * Redistribution and use in source and binary forms, with or without
77+ * modification, are permitted provided that the following conditions
88+ * are met:
99+ * 1. Redistributions of source code must retain the above copyright
1010+ * notice unmodified, this list of conditions, and the following
1111+ * disclaimer.
1212+ * 2. Redistributions in binary form must reproduce the above copyright
1313+ * notice, this list of conditions and the following disclaimer in the
1414+ * documentation and/or other materials provided with the distribution.
1515+ *
1616+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
1717+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
1818+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
1919+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
2020+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
2121+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
2222+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
2323+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
2424+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
2525+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
2626+ *
2727+ */
2828+2929+#ifndef _PTWQ_THREAD_RT_H
3030+#define _PTWQ_THREAD_RT_H 1
3131+3232+void ptwq_set_current_thread_priority(int priority); // higher is better
3333+3434+#endif /* _PTWQ_THREAD_RT_H */
···11+/*-
22+ * Copyright (c) 2011, Mark Heily <mark@heily.com>
33+ * All rights reserved.
44+ *
55+ * Redistribution and use in source and binary forms, with or without
66+ * modification, are permitted provided that the following conditions
77+ * are met:
88+ * 1. Redistributions of source code must retain the above copyright
99+ * notice unmodified, this list of conditions, and the following
1010+ * disclaimer.
1111+ * 2. Redistributions in binary form must reproduce the above copyright
1212+ * notice, this list of conditions and the following disclaimer in the
1313+ * documentation and/or other materials provided with the distribution.
1414+ *
1515+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
1616+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
1717+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
1818+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
1919+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
2020+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
2121+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
2222+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
2323+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
2424+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
2525+ *
2626+ */
2727+2828+#include "platform.h"
2929+#include "../private.h"
3030+#include "pthread_workqueue.h"
3131+3232+#ifdef PROVIDE_LEGACY_XP_SUPPORT
3333+3434+static LIST_HEAD(, _pthread_workqueue) wqlist[WORKQ_NUM_PRIOQUEUE];
3535+static pthread_rwlock_t wqlist_mtx;
3636+3737+int
3838+manager_init(void)
3939+{
4040+ pthread_rwlock_init(&wqlist_mtx, NULL);
4141+ return (0);
4242+}
4343+4444+void
4545+manager_workqueue_create(struct _pthread_workqueue *workq)
4646+{
4747+ pthread_rwlock_wrlock(&wqlist_mtx);
4848+ LIST_INSERT_HEAD(&wqlist[workq->queueprio], workq, wqlist_entry);
4949+ pthread_rwlock_unlock(&wqlist_mtx);
5050+5151+ pthread_spin_init(&workq->mtx, PTHREAD_PROCESS_PRIVATE);
5252+}
5353+5454+/* The caller must hold the wqlist_mtx. */
5555+static struct work *
5656+wqlist_scan(void)
5757+{
5858+ pthread_workqueue_t workq;
5959+ struct work *witem = NULL;
6060+ int i;
6161+6262+ pthread_rwlock_rdlock(&wqlist_mtx);
6363+ for (i = 0; i < WORKQ_NUM_PRIOQUEUE; i++) {
6464+ LIST_FOREACH(workq, &wqlist[i], wqlist_entry) {
6565+ pthread_spin_lock(&workq->mtx);
6666+6767+ if (STAILQ_EMPTY(&workq->item_listhead)) {
6868+ pthread_spin_unlock(&workq->mtx);
6969+ continue;
7070+ }
7171+7272+ witem = STAILQ_FIRST(&workq->item_listhead);
7373+ if (witem != NULL)
7474+ STAILQ_REMOVE_HEAD(&workq->item_listhead, item_entry);
7575+7676+ pthread_spin_unlock(&workq->mtx);
7777+ goto out;
7878+ }
7979+ }
8080+8181+out:
8282+ pthread_rwlock_unlock(&wqlist_mtx);
8383+ return (witem);
8484+}
8585+8686+DWORD WINAPI
8787+worker_main(LPVOID arg)
8888+{
8989+ struct work *witem;
9090+9191+ witem = wqlist_scan();
9292+ if (witem == NULL)
9393+ return (0);
9494+9595+ witem->func(witem->func_arg);
9696+ free(witem);
9797+ return (0);
9898+}
9999+100100+void
101101+manager_workqueue_additem(struct _pthread_workqueue *workq, struct work *witem)
102102+{
103103+ pthread_spin_lock(&workq->mtx);
104104+ STAILQ_INSERT_TAIL(&workq->item_listhead, witem, item_entry);
105105+ pthread_spin_unlock(&workq->mtx);
106106+ if (!QueueUserWorkItem(worker_main, NULL, WT_EXECUTELONGFUNCTION))
107107+ abort();
108108+}
109109+110110+#else
111111+112112+int
113113+manager_init(void)
114114+{
115115+ return (0);
116116+}
117117+118118+void
119119+manager_workqueue_create(struct _pthread_workqueue *workq)
120120+{
121121+ PTP_POOL pool;
122122+ PTP_CALLBACK_ENVIRON callback;
123123+ SYSTEM_INFO sysinfo;
124124+125125+ pool = CreateThreadpool(NULL);
126126+ if(pool == NULL){
127127+ dbg_lasterror("CreateThreadpool()");
128128+ return;
129129+ }
130130+131131+ InitializeThreadpoolEnvironment(&workq->win_callback_env);
132132+ callback = &workq->win_callback_env;
133133+ SetThreadpoolCallbackPool(callback, pool);
134134+135135+ switch(workq->queueprio){
136136+ case WORKQ_HIGH_PRIOQUEUE:
137137+ // weird but this seems the only valid solution !?
138138+ SetThreadpoolCallbackPriority(callback, TP_CALLBACK_PRIORITY_LOW);
139139+ break;
140140+ case WORKQ_LOW_PRIOQUEUE:
141141+ // see above
142142+ SetThreadpoolCallbackPriority(callback, TP_CALLBACK_PRIORITY_HIGH);
143143+ break;
144144+ default:
145145+ SetThreadpoolCallbackPriority(callback, TP_CALLBACK_PRIORITY_NORMAL);
146146+ break;
147147+ }
148148+149149+ // we need a proper way to implement overcommitting on windows
150150+ if(workq->overcommit){
151151+ GetSystemInfo(&sysinfo);
152152+ SetThreadpoolThreadMaximum(pool, sysinfo.dwNumberOfProcessors * 2);
153153+ }
154154+155155+ workq->win_thread_pool = pool;
156156+}
157157+158158+VOID CALLBACK
159159+worker_main( PTP_CALLBACK_INSTANCE instance, PVOID Parameter, PTP_WORK work )
160160+{
161161+ struct work* witem = (struct work*)Parameter;
162162+163163+ assert(witem);
164164+ witem->func(witem->func_arg);
165165+ free(witem);
166166+ CloseThreadpoolWork(work);
167167+}
168168+169169+void
170170+manager_workqueue_additem(struct _pthread_workqueue *workq, struct work *witem)
171171+{
172172+ PTP_WORK work = CreateThreadpoolWork(worker_main, witem, &workq->win_callback_env);
173173+ if(work == NULL) {
174174+ dbg_lasterror("CreateThreadpoolWork()");
175175+ return;
176176+ }
177177+ SubmitThreadpoolWork(work);
178178+}
179179+180180+// TODO: We need to cleanly close the environment and threadpools!
181181+182182+#endif
183183+184184+unsigned long
185185+manager_peek(const char *key)
186186+{
187187+ unsigned long rv;
188188+189189+ if (strcmp(key, "combined_idle") == 0) {
190190+ dbg_puts("TODO");
191191+ abort();
192192+ } else {
193193+ dbg_printf("invalid key: ", key);
194194+ abort();
195195+ }
196196+197197+ return rv;
198198+}
···11+/*-
22+ * Copyright (c) 2011, Mark Heily <mark@heily.com>
33+ * All rights reserved.
44+ *
55+ * Redistribution and use in source and binary forms, with or without
66+ * modification, are permitted provided that the following conditions
77+ * are met:
88+ * 1. Redistributions of source code must retain the above copyright
99+ * notice unmodified, this list of conditions, and the following
1010+ * disclaimer.
1111+ * 2. Redistributions in binary form must reproduce the above copyright
1212+ * notice, this list of conditions and the following disclaimer in the
1313+ * documentation and/or other materials provided with the distribution.
1414+ *
1515+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
1616+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
1717+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
1818+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
1919+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
2020+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
2121+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
2222+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
2323+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
2424+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
2525+ *
2626+ */
2727+2828+#include "platform.h"
2929+#include "../private.h"
3030+#include "pthread_workqueue.h"
3131+3232+#ifndef MAKE_STATIC
3333+3434+// The constructor to be called
3535+int VISIBLE CONSTRUCTOR pthread_workqueue_init_np(void);
3636+3737+BOOL WINAPI DllMain(
3838+ HINSTANCE hinstDLL, // handle to DLL module
3939+ DWORD fdwReason, // reason for calling function
4040+ LPVOID lpReserved ) // reserved
4141+{
4242+ // Perform actions based on the reason for calling.
4343+ switch( fdwReason )
4444+ {
4545+ case DLL_PROCESS_ATTACH:
4646+ // Initialize once for each new process.
4747+ // Return FALSE to fail DLL load.
4848+ if( pthread_workqueue_init_np() < 0)
4949+ return FALSE;
5050+ break;
5151+5252+ }
5353+ return TRUE; // Successful DLL_PROCESS_ATTACH.
5454+}
5555+5656+#endif
···11+/*-
22+ * Copyright (c) 2011, Mark Heily <mark@heily.com>
33+ * All rights reserved.
44+ *
55+ * Redistribution and use in source and binary forms, with or without
66+ * modification, are permitted provided that the following conditions
77+ * are met:
88+ * 1. Redistributions of source code must retain the above copyright
99+ * notice unmodified, this list of conditions, and the following
1010+ * disclaimer.
1111+ * 2. Redistributions in binary form must reproduce the above copyright
1212+ * notice, this list of conditions and the following disclaimer in the
1313+ * documentation and/or other materials provided with the distribution.
1414+ *
1515+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
1616+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
1717+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
1818+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
1919+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
2020+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
2121+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
2222+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
2323+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
2424+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
2525+ *
2626+ */
2727+2828+/*
2929+ * Windows condition variables
3030+ */
3131+#if WINVER >= 0x0600
3232+3333+typedef CONDITION_VARIABLE pthread_cond_t;
3434+typedef int pthread_condattr_t;
3535+3636+static inline int
3737+pthread_cond_init(pthread_cond_t *cond, pthread_condattr_t *cond_attr)
3838+{
3939+ InitializeConditionVariable(cond);
4040+ return (0);
4141+}
4242+4343+static inline int
4444+pthread_cond_wait(pthread_cond_t *cond, pthread_mutex_t *mutex)
4545+{
4646+ return (SleepConditionVariableCS(cond, mutex, INFINITE) == 0);
4747+}
4848+4949+static inline int
5050+pthread_cond_signal(pthread_cond_t *cond)
5151+{
5252+ WakeConditionVariable(cond);
5353+ return (0);
5454+}
5555+5656+#else
5757+# error Conditional variables require Vista or newer
5858+#endif
···11+/*
22+ * Copyright (c) 2011, Joakim Johansson <jocke@tbricks.com>
33+ *
44+ * All rights reserved.
55+ *
66+ * Redistribution and use in source and binary forms, with or without
77+ * modification, are permitted provided that the following conditions
88+ * are met:
99+ * 1. Redistributions of source code must retain the above copyright
1010+ * notice unmodified, this list of conditions, and the following
1111+ * disclaimer.
1212+ * 2. Redistributions in binary form must reproduce the above copyright
1313+ * notice, this list of conditions and the following disclaimer in the
1414+ * documentation and/or other materials provided with the distribution.
1515+ *
1616+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
1717+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
1818+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
1919+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
2020+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
2121+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
2222+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
2323+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
2424+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
2525+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
2626+ *
2727+ */
2828+2929+int threads_runnable(unsigned int *threads_running)
3030+{
3131+ return -1;
3232+}
···11+/*
22+ * Copyright (c) 2011, Joakim Johansson <jocke@tbricks.com>
33+ *
44+ * All rights reserved.
55+ *
66+ * Redistribution and use in source and binary forms, with or without
77+ * modification, are permitted provided that the following conditions
88+ * are met:
99+ * 1. Redistributions of source code must retain the above copyright
1010+ * notice unmodified, this list of conditions, and the following
1111+ * disclaimer.
1212+ * 2. Redistributions in binary form must reproduce the above copyright
1313+ * notice, this list of conditions and the following disclaimer in the
1414+ * documentation and/or other materials provided with the distribution.
1515+ *
1616+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
1717+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
1818+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
1919+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
2020+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
2121+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
2222+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
2323+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
2424+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
2525+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
2626+ *
2727+ */
2828+2929+void ptwq_set_current_thread_priority(int priority)
3030+{
3131+ return;
3232+}
···11+#
22+# Copyright (c) 2011 Marius Zwicker <marius@mlba-team.de>
33+#
44+# Permission to use, copy, modify, and distribute this software for any
55+# purpose with or without fee is hereby granted, provided that the above
66+# copyright notice and this permission notice appear in all copies.
77+#
88+# THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
99+# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
1010+# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
1111+# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
1212+# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
1313+# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
1414+# OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
1515+#
1616+1717+#files
1818+set(API api/test.c)
1919+set(WITEM_CACHE witem_cache/test.c)
2020+set(LATENCY latency/latency.c latency/latency.h)
2121+2222+2323+#includes
2424+include_directories(
2525+ ../include
2626+)
2727+2828+if(UNIX)
2929+ add_definitions(
3030+ -DNO_CONFIG_H
3131+ )
3232+endif()
3333+3434+add_executable(test_api_pthread_workqueue ${API})
3535+target_link_libraries(test_api_pthread_workqueue pthread_workqueue)
3636+set_target_properties(test_api_pthread_workqueue PROPERTIES DEBUG_POSTFIX "D")
3737+3838+add_executable(test_latency_pthread_workqueue ${LATENCY})
3939+target_link_libraries(test_latency_pthread_workqueue pthread_workqueue)
4040+4141+if(NOT WIN32)
4242+4343+ #add_executable(test_witem_cache_pthread_workqueue ${WITEM_CACHE})
4444+ #target_link_libraries(test_witem_cache_pthread_workqueue pthreads_workqueue)
4545+4646+endif()
···11+#
22+# Copyright (c) 2011 Mark Heily <mark@heily.com>
33+#
44+# Permission to use, copy, modify, and distribute this software for any
55+# purpose with or without fee is hereby granted, provided that the above
66+# copyright notice and this permission notice appear in all copies.
77+#
88+# THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
99+# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
1010+# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
1111+# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
1212+# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
1313+# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
1414+# OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
1515+#
1616+1717+# TODO: add libdispatch to TESTS
1818+1919+TESTS=api latency witem_cache
2020+EXTRA_TESTS=idle
2121+2222+all clean check:
2323+ for x in $(TESTS) ; do cd $$x && make $@ && cd .. ; done
2424+2525+extra-check:
2626+ for x in $(EXTRA_TESTS) ; do cd $$x && make check && cd .. ; done
···11+#
22+# Copyright (c) 2011 Mark Heily <mark@heily.com>
33+#
44+# Permission to use, copy, modify, and distribute this software for any
55+# purpose with or without fee is hereby granted, provided that the above
66+# copyright notice and this permission notice appear in all copies.
77+#
88+# THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
99+# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
1010+# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
1111+# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
1212+# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
1313+# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
1414+# OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
1515+#
1616+1717+.PHONY :: install uninstall check dist dist-upload publish-www clean merge distclean fresh-build rpm edit cscope valgrind
1818+1919+include ../../config.mk
2020+2121+all: test-$(PROGRAM)
2222+2323+test-$(PROGRAM): test.c
2424+ $(CC) $(CFLAGS) -g -O0 -o test-$(PROGRAM) -I../.. -I../../include -L../.. test.c -lpthread_workqueue -lpthread
2525+2626+check: test-$(PROGRAM)
2727+ LD_LIBRARY_PATH=../..:/usr/sfw/lib/amd64 ./test-$(PROGRAM)
2828+2929+debug: test-$(PROGRAM)
3030+ LD_LIBRARY_PATH=../.. gdb ./test-$(PROGRAM)
3131+3232+valgrind: test-$(PROGRAM)
3333+ valgrind --tool=memcheck --leak-check=full --show-reachable=yes --num-callers=20 --track-fds=yes ./test-$(PROGRAM)
3434+3535+clean:
3636+ rm -f test-$(PROGRAM)
···11+#
22+# Copyright (c) 2011 Mark Heily <mark@heily.com>
33+#
44+# Permission to use, copy, modify, and distribute this software for any
55+# purpose with or without fee is hereby granted, provided that the above
66+# copyright notice and this permission notice appear in all copies.
77+#
88+# THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
99+# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
1010+# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
1111+# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
1212+# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
1313+# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
1414+# OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
1515+#
1616+1717+include ../../config.mk
1818+1919+all: idle
2020+2121+idle: main.c
2222+ $(CC) $(CFLAGS) -g -O0 -o $@ -I../.. -I../../include -L../.. -Wl,-rpath,$(BASEDIR) main.c -lpthread_workqueue -lpthread
2323+2424+check: idle
2525+ LD_LIBRARY_PATH=../..:/usr/sfw/lib/amd64 PWQ_DEBUG=yes ./idle
2626+2727+clean:
2828+ rm -f idle
···11+/*-
22+ * Copyright (c) 2011, Mark Heily <mark@heily.com>
33+ * All rights reserved.
44+ *
55+ * Redistribution and use in source and binary forms, with or without
66+ * modification, are permitted provided that the following conditions
77+ * are met:
88+ * 1. Redistributions of source code must retain the above copyright
99+ * notice unmodified, this list of conditions, and the following
1010+ * disclaimer.
1111+ * 2. Redistributions in binary form must reproduce the above copyright
1212+ * notice, this list of conditions and the following disclaimer in the
1313+ * documentation and/or other materials provided with the distribution.
1414+ *
1515+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
1616+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
1717+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
1818+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
1919+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
2020+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
2121+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
2222+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
2323+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
2424+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
2525+ *
2626+ */
2727+2828+#include <err.h>
2929+#include <stdio.h>
3030+#include <stdlib.h>
3131+#include <unistd.h>
3232+3333+#include <pthread_workqueue.h>
3434+3535+void f(void *arg)
3636+{
3737+ long x = (long) arg;
3838+3939+ printf("worker %ld running\n", x);
4040+ sleep(1);
4141+ printf("worker %ld finished\n", x);
4242+}
4343+4444+void run_idle_test(pthread_workqueue_t wq)
4545+{
4646+ long i;
4747+ int rv;
4848+4949+ for (i = 0; i < 100; i++) {
5050+ rv = pthread_workqueue_additem_np(wq, f, (void *) i, NULL, NULL);
5151+ if (rv != 0) abort();
5252+ }
5353+5454+ sleep(2);
5555+5656+ int rounds = 0;
5757+ for (;;) {
5858+ unsigned long idle = pthread_workqueue_peek_np("combined_idle");
5959+ unsigned long norml_idle = pthread_workqueue_peek_np("idle");
6060+ unsigned long ocomm_idle = pthread_workqueue_peek_np("ocomm_idle");
6161+ printf("idle = %lu (overcommit = %lu non-overcommit = %lu)\n",
6262+ idle, ocomm_idle, norml_idle);
6363+ if (idle == 0 || (norml_idle == 1 && ocomm_idle == 0))
6464+ break;
6565+6666+ sleep(1);
6767+ if (rounds++ > 240) {
6868+ printf("\n*** ERROR: idle threads were not reaped properly\n");
6969+ exit(1);
7070+ }
7171+ }
7272+}
7373+7474+/*
7575+ * Enqueue a large number of short-lived workitems, to allow observation
7676+ * of how idle threads are terminated.
7777+ */
7878+int main(int argc, char *argv[])
7979+{
8080+ pthread_workqueue_t wq;
8181+ pthread_workqueue_t ocwq;
8282+ pthread_workqueue_attr_t attr;
8383+ pthread_workqueue_attr_t ocattr;
8484+ int i, rounds;
8585+ int rv;
8686+8787+ if (argc == 2)
8888+ rounds = atoi(argv[1]);
8989+ else
9090+ rounds = 1;
9191+9292+ pthread_workqueue_attr_init_np(&attr);
9393+ pthread_workqueue_attr_setovercommit_np(&attr, 0);
9494+ rv = pthread_workqueue_create_np(&wq, &attr);
9595+ if (rv != 0) abort();
9696+9797+ pthread_workqueue_attr_init_np(&ocattr);
9898+ pthread_workqueue_attr_setovercommit_np(&ocattr, 1);
9999+ rv = pthread_workqueue_create_np(&ocwq, &ocattr);
100100+ if (rv != 0) abort();
101101+102102+ for (i = 0; i < rounds; i++) {
103103+ run_idle_test(wq);
104104+ run_idle_test(ocwq);
105105+ }
106106+ printf("\n---\nOK: all excess idle threads have been terminated after %d rounds.\n", rounds);
107107+ exit(0);
108108+}
···11+/*
22+ * Copyright (c) 2011 Mark Heily.
33+ * Copyright (c) 2008-2009 Apple Inc. All rights reserved.
44+ *
55+ * @APPLE_APACHE_LICENSE_HEADER_START@
66+ *
77+ * Licensed under the Apache License, Version 2.0 (the "License");
88+ * you may not use this file except in compliance with the License.
99+ * You may obtain a copy of the License at
1010+ *
1111+ * http://www.apache.org/licenses/LICENSE-2.0
1212+ *
1313+ * Unless required by applicable law or agreed to in writing, software
1414+ * distributed under the License is distributed on an "AS IS" BASIS,
1515+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1616+ * See the License for the specific language governing permissions and
1717+ * limitations under the License.
1818+ *
1919+ * @APPLE_APACHE_LICENSE_HEADER_END@
2020+ */
2121+2222+#include <stdio.h>
2323+#include <stdlib.h>
2424+#include <unistd.h>
2525+2626+#include <dispatch/dispatch.h>
2727+2828+void
2929+work(void *context __attribute__((unused)))
3030+{
3131+ puts("work complete");
3232+ exit(0);
3333+}
3434+3535+int main(void) {
3636+ dispatch_queue_t q = dispatch_get_main_queue();
3737+ dispatch_sync_f(dispatch_get_main_queue(), NULL, work);
3838+ dispatch_main();
3939+ return 0;
4040+}
···11+#
22+# Copyright (c) 2011 Mark Heily <mark@heily.com>
33+#
44+# Permission to use, copy, modify, and distribute this software for any
55+# purpose with or without fee is hereby granted, provided that the above
66+# copyright notice and this permission notice appear in all copies.
77+#
88+# THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
99+# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
1010+# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
1111+# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
1212+# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
1313+# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
1414+# OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
1515+#
1616+1717+.PHONY :: install uninstall check dist dist-upload publish-www clean merge distclean fresh-build rpm edit cscope valgrind
1818+1919+include ../../config.mk
2020+2121+all: test-$(PROGRAM)
2222+2323+test-$(PROGRAM): test.c
2424+ $(CC) $(CFLAGS) -g -O0 -o test-$(PROGRAM) -I../.. -I../../include -L../.. test.c -lpthread_workqueue -lpthread -lrt
2525+2626+check: test-$(PROGRAM)
2727+ LD_LIBRARY_PATH=../..:/usr/sfw/lib/amd64 ./test-$(PROGRAM)
2828+2929+debug: test-$(PROGRAM)
3030+ LD_LIBRARY_PATH=../.. gdb ./test-$(PROGRAM)
3131+3232+valgrind: test-$(PROGRAM)
3333+ LD_LIBRARY_PATH=../..:/usr/sfw/lib/amd64 \
3434+ valgrind --tool=memcheck --leak-check=full --show-reachable=yes --num-callers=20 --track-fds=yes ./test-$(PROGRAM)
3535+3636+clean:
3737+ rm -f test-$(PROGRAM)
···11+/*-
22+ * Copyright (c) 2011, Mark Heily <mark@heily.com>
33+ * All rights reserved.
44+ *
55+ * Redistribution and use in source and binary forms, with or without
66+ * modification, are permitted provided that the following conditions
77+ * are met:
88+ * 1. Redistributions of source code must retain the above copyright
99+ * notice unmodified, this list of conditions, and the following
1010+ * disclaimer.
1111+ * 2. Redistributions in binary form must reproduce the above copyright
1212+ * notice, this list of conditions and the following disclaimer in the
1313+ * documentation and/or other materials provided with the distribution.
1414+ *
1515+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
1616+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
1717+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
1818+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
1919+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
2020+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
2121+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
2222+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
2323+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
2424+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
2525+ *
2626+ */
2727+2828+#include <limits.h>
2929+#include <stdlib.h>
3030+#include <stdio.h>
3131+#include <string.h>
3232+#include <unistd.h>
3333+3434+#include <time.h>
3535+3636+#include "config.h"
3737+#include "src/private.h"
3838+3939+#if HAVE_ERR_H
4040+# include <err.h>
4141+#else
4242+# define err(rc,msg,...) do { perror(msg); exit(rc); } while (0)
4343+# define errx(rc,msg,...) do { puts(msg); exit(rc); } while (0)
4444+#endif
4545+4646+#include "pthread_workqueue.h"
4747+4848+pthread_workqueue_t wq;
4949+5050+void additem(void (*func)(void *),
5151+ void * arg)
5252+{
5353+ int rv;
5454+5555+ rv = pthread_workqueue_additem_np(wq, *func, arg, NULL, NULL);
5656+ if (rv != 0)
5757+ errx(1, "unable to add item: %s", strerror(rv));
5858+}
5959+6060+6161+void
6262+feedback(void *arg)
6363+{
6464+ int *i = (int *) arg;
6565+ struct timespec tv;
6666+6767+ (*i)--;
6868+ if ((*i) <= 0) {
6969+ puts("All tests completed.\n");
7070+ exit(0);
7171+ } else {
7272+ additem(feedback, arg);
7373+ tv.tv_sec = 0;
7474+ tv.tv_nsec = 750;
7575+ nanosleep(&tv, NULL);
7676+ }
7777+}
7878+7979+int main() {
8080+ int i = 10000;
8181+8282+ pthread_workqueue_create_np(&wq, NULL);
8383+ additem(feedback, &i);
8484+ pause();
8585+}