this repo has no description
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

Adding libdispatch, libkqueue and libpwq code

+14710
+1
external/libkqueue
··· 1 + libkqueue-2.0.1
+279
external/libkqueue-2.0.1/GNUmakefile
··· 1 + # AUTOMATICALLY GENERATED -- DO NOT EDIT 2 + AR = ar 3 + BINDIR = $(EPREFIX)/bin 4 + CC = cc 5 + DATADIR = $(DATAROOTDIR) 6 + DATAROOTDIR = $(PREFIX)/share 7 + DOCDIR = $(DATAROOTDIR)/doc/$(PACKAGE) 8 + EPREFIX = $(PREFIX) 9 + INCLUDEDIR = $(PREFIX)/include 10 + INFODIR = $(DATAROOTDIR)/info 11 + INSTALL ?= /usr/bin/install 12 + LD = cc 13 + LIBDIR = $(EPREFIX)/lib 14 + LIBEXECDIR = $(EPREFIX)/libexec 15 + LOCALEDIR = $(DATAROOTDIR)/locale 16 + LOCALSTATEDIR = $(PREFIX)/var 17 + MANDIR = $(DATAROOTDIR)/man 18 + OLDINCLUDEDIR = /usr/include 19 + PKGCONFIGDIR = $(LIBDIR)/pkgconfig 20 + PKGDATADIR = $(DATADIR)/$(PACKAGE) 21 + PKGINCLUDEDIR = $(INCLUDEDIR)/$(PACKAGE) 22 + PKGLIBDIR = $(LIBDIR)/$(PACKAGE) 23 + PREFIX = /usr/local 24 + RANLIB = ranlib 25 + SBINDIR = $(EPREFIX)/sbin 26 + SHAREDSTATEDIR = $(PREFIX)/com 27 + SYSCONFDIR = $(PREFIX)/etc 28 + 29 + 30 + # 31 + # Detect the canonical system type of the system we are building on 32 + # (build) and the system the package runs on (host) 33 + # 34 + BUILD_CPU=$(shell uname -m) 35 + HOST_CPU=$(BUILD_CPU) 36 + BUILD_VENDOR=unknown 37 + HOST_VENDOR=$(BUILD_VENDOR) 38 + BUILD_KERNEL=$(shell uname | tr '[A-Z]' '[a-z]') 39 + HOST_KERNEL=$(BUILD_KERNEL) 40 + BUILD_SYSTEM=gnu 41 + HOST_SYSTEM=$(BUILD_SYSTEM) 42 + BUILD_TYPE=$(BUILD_CPU)-$(BUILD_VENDOR)-$(BUILD_KERNEL)-$(BUILD_SYSTEM) 43 + HOST_TYPE=$(HOST_CPU)-$(HOST_VENDOR)-$(HOST_KERNEL)-$(HOST_SYSTEM) 44 + 45 + # Allow variables to be overridden via a ./configure script that outputs config.mk 46 + # FIXME -- requires GNU Make 47 + -include config.mk 48 + 49 + default: all 50 + 51 + all: libkqueue.so libkqueue.a kqtest libkqueue.pc 52 + 53 + check: kqtest 54 + ./kqtest 55 + 56 + clean: 57 + rm -f *.rpm 58 + rm -f libkqueue-2.0.1.tar.gz 59 + rm -f src/common/filter.o 60 + rm -f src/common/knote.o 61 + rm -f src/common/map.o 62 + rm -f src/common/kevent.o 63 + rm -f src/common/kqueue.o 64 + rm -f src/posix/platform.o 65 + rm -f src/linux/platform.o 66 + rm -f src/linux/read.o 67 + rm -f src/linux/write.o 68 + rm -f src/linux/user.o 69 + rm -f src/linux/vnode.o 70 + rm -f src/linux/signal.o 71 + rm -f src/linux/timer.o 72 + rm -f libkqueue.so 73 + rm -f libkqueue.a 74 + rm -f test/main.o 75 + rm -f test/kevent.o 76 + rm -f test/test.o 77 + rm -f test/proc.o 78 + rm -f test/read.o 79 + rm -f test/signal.o 80 + rm -f test/timer.o 81 + rm -f test/vnode.o 82 + rm -f test/user.o 83 + rm -f kqtest 84 + 85 + config.h: 86 + @echo "checking build system type... $(BUILD_TYPE)" 87 + @echo "checking host system type... $(HOST_TYPE)" 88 + @echo "/* AUTOMATICALLY GENERATED -- DO NOT EDIT */" > config.h.tmp 89 + @date > config.log 90 + @printf "checking whether EPOLLRDHUP is declared in sys/epoll.h... " | tee -a config.log 91 + @( printf '#define _GNU_SOURCE\n#include <sys/epoll.h>\nint main() { EPOLLRDHUP; }' | $(CC) $(CFLAGS) -E -x c - ) >/dev/null 2>>config.log && ( echo '#define HAVE_DECL_EPOLLRDHUP 1' >> config.h.tmp ; echo 'yes' ) || (echo '#define HAVE_DECL_EPOLLRDHUP 0' >> config.h.tmp ; echo 'no' ) 92 + @printf "checking whether ppoll is declared in poll.h... " | tee -a config.log 93 + @( printf '#define _GNU_SOURCE\n#include <poll.h>\nint main() { ppoll; }' | $(CC) $(CFLAGS) -E -x c - ) >/dev/null 2>>config.log && ( echo '#define HAVE_DECL_PPOLL 1' >> config.h.tmp ; echo 'yes' ) || (echo '#define HAVE_DECL_PPOLL 0' >> config.h.tmp ; echo 'no' ) 94 + @printf "checking for sys/epoll.h... " 95 + @( echo '#include <sys/epoll.h>' | $(CC) $(CFLAGS) -E -x c - ) >/dev/null 2>&1 && ( echo '#define HAVE_SYS_EPOLL_H 1' >> config.h.tmp ; echo 'yes' ) || (echo '/* #undef HAVE_SYS_EPOLL_H */' >> config.h.tmp ; echo 'no' ) 96 + @printf "checking for sys/event.h... " 97 + @( echo '#include <sys/event.h>' | $(CC) $(CFLAGS) -E -x c - ) >/dev/null 2>&1 && ( echo '#define HAVE_SYS_EVENT_H 1' >> config.h.tmp ; echo 'yes' ) || (echo '/* #undef HAVE_SYS_EVENT_H */' >> config.h.tmp ; echo 'no' ) 98 + @printf "checking for sys/eventfd.h... " 99 + @( echo '#include <sys/eventfd.h>' | $(CC) $(CFLAGS) -E -x c - ) >/dev/null 2>&1 && ( echo '#define HAVE_SYS_EVENTFD_H 1' >> config.h.tmp ; echo 'yes' ) || (echo '/* #undef HAVE_SYS_EVENTFD_H */' >> config.h.tmp ; echo 'no' ) 100 + @printf "checking for sys/inotify.h... " 101 + @( echo '#include <sys/inotify.h>' | $(CC) $(CFLAGS) -E -x c - ) >/dev/null 2>&1 && ( echo '#define HAVE_SYS_INOTIFY_H 1' >> config.h.tmp ; echo 'yes' ) || (echo '/* #undef HAVE_SYS_INOTIFY_H */' >> config.h.tmp ; echo 'no' ) 102 + @printf "checking for sys/signalfd.h... " 103 + @( echo '#include <sys/signalfd.h>' | $(CC) $(CFLAGS) -E -x c - ) >/dev/null 2>&1 && ( echo '#define HAVE_SYS_SIGNALFD_H 1' >> config.h.tmp ; echo 'yes' ) || (echo '/* #undef HAVE_SYS_SIGNALFD_H */' >> config.h.tmp ; echo 'no' ) 104 + @printf "checking for sys/timerfd.h... " 105 + @( echo '#include <sys/timerfd.h>' | $(CC) $(CFLAGS) -E -x c - ) >/dev/null 2>&1 && ( echo '#define HAVE_SYS_TIMERFD_H 1' >> config.h.tmp ; echo 'yes' ) || (echo '/* #undef HAVE_SYS_TIMERFD_H */' >> config.h.tmp ; echo 'no' ) 106 + @rm -f conftest.c conftest.o 107 + @echo "creating config.h" 108 + @mv config.h.tmp config.h 109 + 110 + dist: libkqueue-2.0.1.tar.gz 111 + 112 + distclean: clean 113 + rm -f GNUmakefile 114 + rm -f libkqueue-2.0.1.tar.gz 115 + rm -f config.h 116 + rm -f config.yaml 117 + 118 + distdir: config.h 119 + umask 22 ; mkdir -p '$(distdir)/src/common' 120 + umask 22 ; mkdir -p '$(distdir)/src/common/../posix' 121 + umask 22 ; mkdir -p '$(distdir)/src/common/../posix/../../include/sys' 122 + umask 22 ; mkdir -p '$(distdir)/src/common/../linux' 123 + umask 22 ; mkdir -p '$(distdir)/src/posix' 124 + umask 22 ; mkdir -p '$(distdir)/src/posix/../common' 125 + umask 22 ; mkdir -p '$(distdir)/src/posix/../common/../posix' 126 + umask 22 ; mkdir -p '$(distdir)/src/posix/../common/../posix/../../include/sys' 127 + umask 22 ; mkdir -p '$(distdir)/src/posix/../common/../linux' 128 + umask 22 ; mkdir -p '$(distdir)/src/linux' 129 + umask 22 ; mkdir -p '$(distdir)/src/linux/../common' 130 + umask 22 ; mkdir -p '$(distdir)/src/linux/../common/../posix' 131 + umask 22 ; mkdir -p '$(distdir)/src/linux/../common/../posix/../../include/sys' 132 + umask 22 ; mkdir -p '$(distdir)/src/linux/../common/../linux' 133 + umask 22 ; mkdir -p '$(distdir)/include/sys' 134 + umask 22 ; mkdir -p '$(distdir)/test' 135 + umask 22 ; mkdir -p '$(distdir)/test/..' 136 + cp -RL libkqueue.spec config.h GNUmakefile kqueue.2 libkqueue.pc.in configure configure.rb LICENSE $(distdir) 137 + cp -RL src/common/filter.c src/common/private.h src/common/tree.h src/common/debug.h src/common/knote.c src/common/alloc.h src/common/map.c src/common/kevent.c src/common/kqueue.c $(distdir)/src/common 138 + cp -RL src/common/../posix/platform.h $(distdir)/src/common/../posix 139 + cp -RL src/common/../posix/../../include/sys/event.h $(distdir)/src/common/../posix/../../include/sys 140 + cp -RL src/common/../linux/platform.h $(distdir)/src/common/../linux 141 + cp -RL src/posix/platform.c $(distdir)/src/posix 142 + cp -RL src/posix/../common/private.h src/posix/../common/tree.h src/posix/../common/debug.h $(distdir)/src/posix/../common 143 + cp -RL src/posix/../common/../posix/platform.h $(distdir)/src/posix/../common/../posix 144 + cp -RL src/posix/../common/../posix/../../include/sys/event.h $(distdir)/src/posix/../common/../posix/../../include/sys 145 + cp -RL src/posix/../common/../linux/platform.h $(distdir)/src/posix/../common/../linux 146 + cp -RL src/linux/platform.c src/linux/read.c src/linux/write.c src/linux/user.c src/linux/vnode.c src/linux/signal.c src/linux/timer.c $(distdir)/src/linux 147 + cp -RL src/linux/../common/private.h src/linux/../common/tree.h src/linux/../common/debug.h $(distdir)/src/linux/../common 148 + cp -RL src/linux/../common/../posix/platform.h $(distdir)/src/linux/../common/../posix 149 + cp -RL src/linux/../common/../posix/../../include/sys/event.h $(distdir)/src/linux/../common/../posix/../../include/sys 150 + cp -RL src/linux/../common/../linux/platform.h $(distdir)/src/linux/../common/../linux 151 + cp -RL include/sys/event.h $(distdir)/include/sys 152 + cp -RL test/main.c test/common.h test/kevent.c test/test.c test/proc.c test/read.c test/signal.c test/timer.c test/vnode.c test/user.c $(distdir)/test 153 + cp -RL test/../config.h $(distdir)/test/.. 154 + 155 + install: 156 + /usr/bin/test -e $(DESTDIR)$(LIBDIR) || $(INSTALL) -d -m 755 $(DESTDIR)$(LIBDIR) 157 + $(INSTALL) -m 0644 libkqueue.so $(DESTDIR)$(LIBDIR)/libkqueue.so.0.0 158 + /usr/bin/test -e $(DESTDIR)$(INCLUDEDIR)/kqueue/sys || $(INSTALL) -d -m 755 $(DESTDIR)$(INCLUDEDIR)/kqueue/sys 159 + $(INSTALL) -m 644 include/sys/event.h $(DESTDIR)$(INCLUDEDIR)/kqueue/sys 160 + /usr/bin/test -e $(DESTDIR)$(MANDIR)/man2 || $(INSTALL) -d -m 755 $(DESTDIR)$(MANDIR)/man2 161 + $(INSTALL) -m 644 kqueue.2 $(DESTDIR)$(MANDIR)/man2 162 + /usr/bin/test -e $(DESTDIR)$(PKGCONFIGDIR) || $(INSTALL) -d -m 755 $(DESTDIR)$(PKGCONFIGDIR) 163 + $(INSTALL) -m 644 libkqueue.pc $(DESTDIR)$(PKGCONFIGDIR) 164 + rm -f $(DESTDIR)$(LIBDIR)/libkqueue.so 165 + ln -s libkqueue.so.0.0 $(DESTDIR)$(LIBDIR)/libkqueue.so 166 + rm -f $(DESTDIR)$(LIBDIR)/libkqueue.so.0 167 + ln -s libkqueue.so.0.0 $(DESTDIR)$(LIBDIR)/libkqueue.so.0 168 + rm -f $(DESTDIR)$(MANDIR)/man2/kevent.2 169 + ln -s kqueue.2 $(DESTDIR)$(MANDIR)/man2/kevent.2 170 + 171 + kqtest: test/main.o test/kevent.o test/test.o test/proc.o test/read.o test/signal.o test/timer.o test/vnode.o test/user.o 172 + $(LD) -o kqtest -L . -Wl,-rpath,. -L . $(LDFLAGS) test/main.o test/kevent.o test/test.o test/proc.o test/read.o test/signal.o test/timer.o test/vnode.o test/user.o libkqueue.a -lpthread -lrt $(LDADD) 173 + 174 + libkqueue-2.0.1.tar.gz: 175 + rm -rf libkqueue-2.0.1 176 + mkdir libkqueue-2.0.1 177 + $(MAKE) distdir distdir=libkqueue-2.0.1 178 + rm -rf libkqueue-2.0.1.tar libkqueue-2.0.1.tar.gz 179 + tar cf libkqueue-2.0.1.tar libkqueue-2.0.1 180 + gzip libkqueue-2.0.1.tar 181 + rm -rf libkqueue-2.0.1 182 + 183 + libkqueue.a: src/common/filter.o src/common/knote.o src/common/map.o src/common/kevent.o src/common/kqueue.o src/posix/platform.o src/linux/platform.o src/linux/read.o src/linux/write.o src/linux/user.o src/linux/vnode.o src/linux/signal.o src/linux/timer.o 184 + ifneq ($(DISABLE_STATIC),1) 185 + $(AR) cru libkqueue.a src/common/filter.o src/common/knote.o src/common/map.o src/common/kevent.o src/common/kqueue.o src/posix/platform.o src/linux/platform.o src/linux/read.o src/linux/write.o src/linux/user.o src/linux/vnode.o src/linux/signal.o src/linux/timer.o 186 + $(RANLIB) libkqueue.a 187 + endif 188 + 189 + libkqueue.pc: config.h 190 + @echo 'creating libkqueue.pc' 191 + @printf "prefix=$(PREFIX)\nexec_prefix=$(EPREFIX)\nlibdir=$(LIBDIR)\nincludedir=$(INCLUDEDIR)\n" > libkqueue.pc 192 + @cat libkqueue.pc.in >> libkqueue.pc 193 + 194 + libkqueue.so: src/common/filter.o src/common/knote.o src/common/map.o src/common/kevent.o src/common/kqueue.o src/posix/platform.o src/linux/platform.o src/linux/read.o src/linux/write.o src/linux/user.o src/linux/vnode.o src/linux/signal.o src/linux/timer.o 195 + $(LD) -o libkqueue.so -shared -fPIC -L . -Wl,-soname,libkqueue.so.0 $(LDFLAGS) src/common/filter.o src/common/knote.o src/common/map.o src/common/kevent.o src/common/kqueue.o src/posix/platform.o src/linux/platform.o src/linux/read.o src/linux/write.o src/linux/user.o src/linux/vnode.o src/linux/signal.o src/linux/timer.o -lpthread -lrt $(LDADD) 196 + 197 + package: clean libkqueue-2.0.1.tar.gz 198 + rm -rf rpm *.rpm 199 + mkdir -p rpm/BUILD rpm/RPMS rpm/SOURCES rpm/SPECS rpm/SRPMS 200 + mkdir -p rpm/RPMS/`uname -m` 201 + cp libkqueue-2.0.1.tar.gz rpm/SOURCES 202 + cp libkqueue.spec rpm/SPECS/libkqueue.spec 203 + perl -pi -e 's/^Version:.*/Version: 2.0.1/' rpm/SPECS/libkqueue.spec 204 + rpmbuild --define "_topdir `pwd`/rpm" -bs rpm/SPECS/libkqueue.spec 205 + rpmbuild --define "_topdir `pwd`/rpm" -bb rpm/SPECS/libkqueue.spec 206 + mv ./rpm/SRPMS/* ./rpm/RPMS/*/*.rpm . 207 + rm -rf rpm 208 + 209 + src/common/filter.o: src/common/filter.c src/common/private.h config.h src/common/tree.h src/common/../posix/platform.h src/common/../posix/../../include/sys/event.h src/common/../linux/platform.h src/common/debug.h GNUmakefile 210 + $(CC) -DHAVE_CONFIG_H -I. -I./src/common -I./include -Wall -Wextra -Wno-missing-field-initializers -Werror -g -O2 -std=c99 -D_XOPEN_SOURCE=600 -fvisibility=hidden -o src/common/filter.o -fPIC -DPIC $(CFLAGS) -c src/common/filter.c 211 + 212 + src/common/kevent.o: src/common/kevent.c src/common/private.h config.h src/common/tree.h src/common/../posix/platform.h src/common/../posix/../../include/sys/event.h src/common/../linux/platform.h src/common/debug.h GNUmakefile 213 + $(CC) -DHAVE_CONFIG_H -I. -I./src/common -I./include -Wall -Wextra -Wno-missing-field-initializers -Werror -g -O2 -std=c99 -D_XOPEN_SOURCE=600 -fvisibility=hidden -o src/common/kevent.o -fPIC -DPIC $(CFLAGS) -c src/common/kevent.c 214 + 215 + src/common/knote.o: src/common/knote.c src/common/private.h config.h src/common/tree.h src/common/../posix/platform.h src/common/../posix/../../include/sys/event.h src/common/../linux/platform.h src/common/debug.h src/common/alloc.h GNUmakefile 216 + $(CC) -DHAVE_CONFIG_H -I. -I./src/common -I./include -Wall -Wextra -Wno-missing-field-initializers -Werror -g -O2 -std=c99 -D_XOPEN_SOURCE=600 -fvisibility=hidden -o src/common/knote.o -fPIC -DPIC $(CFLAGS) -c src/common/knote.c 217 + 218 + src/common/kqueue.o: src/common/kqueue.c src/common/private.h config.h src/common/tree.h src/common/../posix/platform.h src/common/../posix/../../include/sys/event.h src/common/../linux/platform.h src/common/debug.h GNUmakefile 219 + $(CC) -DHAVE_CONFIG_H -I. -I./src/common -I./include -Wall -Wextra -Wno-missing-field-initializers -Werror -g -O2 -std=c99 -D_XOPEN_SOURCE=600 -fvisibility=hidden -o src/common/kqueue.o -fPIC -DPIC $(CFLAGS) -c src/common/kqueue.c 220 + 221 + src/common/map.o: src/common/map.c src/common/private.h config.h src/common/tree.h src/common/../posix/platform.h src/common/../posix/../../include/sys/event.h src/common/../linux/platform.h src/common/debug.h GNUmakefile 222 + $(CC) -DHAVE_CONFIG_H -I. -I./src/common -I./include -Wall -Wextra -Wno-missing-field-initializers -Werror -g -O2 -std=c99 -D_XOPEN_SOURCE=600 -fvisibility=hidden -o src/common/map.o -fPIC -DPIC $(CFLAGS) -c src/common/map.c 223 + 224 + src/linux/platform.o: src/linux/platform.c src/linux/../common/private.h config.h src/linux/../common/tree.h src/linux/../common/../posix/platform.h src/linux/../common/../posix/../../include/sys/event.h src/linux/../common/../linux/platform.h src/linux/../common/debug.h GNUmakefile 225 + $(CC) -DHAVE_CONFIG_H -I. -I./src/common -I./include -Wall -Wextra -Wno-missing-field-initializers -Werror -g -O2 -std=c99 -D_XOPEN_SOURCE=600 -fvisibility=hidden -o src/linux/platform.o -fPIC -DPIC $(CFLAGS) -c src/linux/platform.c 226 + 227 + src/linux/read.o: src/linux/read.c src/common/private.h config.h src/common/tree.h src/common/../posix/platform.h src/common/../posix/../../include/sys/event.h src/common/../linux/platform.h src/common/debug.h GNUmakefile 228 + $(CC) -DHAVE_CONFIG_H -I. -I./src/common -I./include -Wall -Wextra -Wno-missing-field-initializers -Werror -g -O2 -std=c99 -D_XOPEN_SOURCE=600 -fvisibility=hidden -o src/linux/read.o -fPIC -DPIC $(CFLAGS) -c src/linux/read.c 229 + 230 + src/linux/signal.o: src/linux/signal.c src/common/private.h config.h src/common/tree.h src/common/../posix/platform.h src/common/../posix/../../include/sys/event.h src/common/../linux/platform.h src/common/debug.h GNUmakefile 231 + $(CC) -DHAVE_CONFIG_H -I. -I./src/common -I./include -Wall -Wextra -Wno-missing-field-initializers -Werror -g -O2 -std=c99 -D_XOPEN_SOURCE=600 -fvisibility=hidden -o src/linux/signal.o -fPIC -DPIC $(CFLAGS) -c src/linux/signal.c 232 + 233 + src/linux/timer.o: src/linux/timer.c src/common/private.h config.h src/common/tree.h src/common/../posix/platform.h src/common/../posix/../../include/sys/event.h src/common/../linux/platform.h src/common/debug.h GNUmakefile 234 + $(CC) -DHAVE_CONFIG_H -I. -I./src/common -I./include -Wall -Wextra -Wno-missing-field-initializers -Werror -g -O2 -std=c99 -D_XOPEN_SOURCE=600 -fvisibility=hidden -o src/linux/timer.o -fPIC -DPIC $(CFLAGS) -c src/linux/timer.c 235 + 236 + src/linux/user.o: src/linux/user.c include/sys/event.h src/common/private.h config.h src/common/tree.h src/common/../posix/platform.h src/common/../posix/../../include/sys/event.h src/common/../linux/platform.h src/common/debug.h GNUmakefile 237 + $(CC) -DHAVE_CONFIG_H -I. -I./src/common -I./include -Wall -Wextra -Wno-missing-field-initializers -Werror -g -O2 -std=c99 -D_XOPEN_SOURCE=600 -fvisibility=hidden -o src/linux/user.o -fPIC -DPIC $(CFLAGS) -c src/linux/user.c 238 + 239 + src/linux/vnode.o: src/linux/vnode.c src/common/private.h config.h src/common/tree.h src/common/../posix/platform.h src/common/../posix/../../include/sys/event.h src/common/../linux/platform.h src/common/debug.h GNUmakefile 240 + $(CC) -DHAVE_CONFIG_H -I. -I./src/common -I./include -Wall -Wextra -Wno-missing-field-initializers -Werror -g -O2 -std=c99 -D_XOPEN_SOURCE=600 -fvisibility=hidden -o src/linux/vnode.o -fPIC -DPIC $(CFLAGS) -c src/linux/vnode.c 241 + 242 + src/linux/write.o: src/linux/write.c src/common/private.h config.h src/common/tree.h src/common/../posix/platform.h src/common/../posix/../../include/sys/event.h src/common/../linux/platform.h src/common/debug.h GNUmakefile 243 + $(CC) -DHAVE_CONFIG_H -I. -I./src/common -I./include -Wall -Wextra -Wno-missing-field-initializers -Werror -g -O2 -std=c99 -D_XOPEN_SOURCE=600 -fvisibility=hidden -o src/linux/write.o -fPIC -DPIC $(CFLAGS) -c src/linux/write.c 244 + 245 + src/posix/platform.o: src/posix/platform.c src/posix/../common/private.h config.h src/posix/../common/tree.h src/posix/../common/../posix/platform.h src/posix/../common/../posix/../../include/sys/event.h src/posix/../common/../linux/platform.h src/posix/../common/debug.h GNUmakefile 246 + $(CC) -DHAVE_CONFIG_H -I. -I./src/common -I./include -Wall -Wextra -Wno-missing-field-initializers -Werror -g -O2 -std=c99 -D_XOPEN_SOURCE=600 -fvisibility=hidden -o src/posix/platform.o -fPIC -DPIC $(CFLAGS) -c src/posix/platform.c 247 + 248 + test/kevent.o: test/kevent.c test/common.h include/sys/event.h test/../config.h GNUmakefile 249 + $(CC) -DHAVE_CONFIG_H -I. -g -O0 -Wall -Werror -I./include -I./test -g -O0 -o test/kevent.o $(CFLAGS) -c test/kevent.c 250 + 251 + test/main.o: test/main.c test/common.h include/sys/event.h test/../config.h GNUmakefile 252 + $(CC) -DHAVE_CONFIG_H -I. -g -O0 -Wall -Werror -I./include -I./test -g -O0 -o test/main.o $(CFLAGS) -c test/main.c 253 + 254 + test/proc.o: test/proc.c test/common.h include/sys/event.h test/../config.h GNUmakefile 255 + $(CC) -DHAVE_CONFIG_H -I. -g -O0 -Wall -Werror -I./include -I./test -g -O0 -o test/proc.o $(CFLAGS) -c test/proc.c 256 + 257 + test/read.o: test/read.c test/common.h include/sys/event.h test/../config.h GNUmakefile 258 + $(CC) -DHAVE_CONFIG_H -I. -g -O0 -Wall -Werror -I./include -I./test -g -O0 -o test/read.o $(CFLAGS) -c test/read.c 259 + 260 + test/signal.o: test/signal.c test/common.h include/sys/event.h test/../config.h GNUmakefile 261 + $(CC) -DHAVE_CONFIG_H -I. -g -O0 -Wall -Werror -I./include -I./test -g -O0 -o test/signal.o $(CFLAGS) -c test/signal.c 262 + 263 + test/test.o: test/test.c test/common.h include/sys/event.h test/../config.h GNUmakefile 264 + $(CC) -DHAVE_CONFIG_H -I. -g -O0 -Wall -Werror -I./include -I./test -g -O0 -o test/test.o $(CFLAGS) -c test/test.c 265 + 266 + test/timer.o: test/timer.c test/common.h include/sys/event.h test/../config.h GNUmakefile 267 + $(CC) -DHAVE_CONFIG_H -I. -g -O0 -Wall -Werror -I./include -I./test -g -O0 -o test/timer.o $(CFLAGS) -c test/timer.c 268 + 269 + test/user.o: test/user.c test/common.h include/sys/event.h test/../config.h GNUmakefile 270 + $(CC) -DHAVE_CONFIG_H -I. -g -O0 -Wall -Werror -I./include -I./test -g -O0 -o test/user.o $(CFLAGS) -c test/user.c 271 + 272 + test/vnode.o: test/vnode.c test/common.h include/sys/event.h test/../config.h GNUmakefile 273 + $(CC) -DHAVE_CONFIG_H -I. -g -O0 -Wall -Werror -I./include -I./test -g -O0 -o test/vnode.o $(CFLAGS) -c test/vnode.c 274 + 275 + uninstall: 276 + rm -f $(DESTDIR)$(LIBDIR)/libkqueue.so 277 + rm -f $(DESTDIR)$(INCLUDEDIR)/kqueue/sys/include/sys/event.h 278 + rm -f $(DESTDIR)$(MANDIR)/man2/kqueue.2 279 + rm -f $(DESTDIR)$(PKGCONFIGDIR)/libkqueue.pc
+42
external/libkqueue-2.0.1/LICENSE
··· 1 + == all source == 2 + 3 + Copyright (c) 2009 Mark Heily <mark@heily.com> 4 + 5 + Permission to use, copy, modify, and distribute this software for any 6 + purpose with or without fee is hereby granted, provided that the above 7 + copyright notice and this permission notice appear in all copies. 8 + 9 + THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 10 + WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 11 + MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 12 + ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 13 + WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 14 + ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 15 + OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 16 + 17 + == event.h == 18 + 19 + Copyright (c) 1999,2000,2001 Jonathan Lemon <jlemon@FreeBSD.org> 20 + All rights reserved. 21 + 22 + Redistribution and use in source and binary forms, with or without 23 + modification, are permitted provided that the following conditions 24 + are met: 25 + 1. Redistributions of source code must retain the above copyright 26 + notice, this list of conditions and the following disclaimer. 27 + 2. Redistributions in binary form must reproduce the above copyright 28 + notice, this list of conditions and the following disclaimer in the 29 + documentation and/or other materials provided with the distribution. 30 + 31 + THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 32 + ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 33 + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 34 + ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 35 + FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 36 + DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 37 + OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 38 + HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 39 + LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 40 + OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 41 + SUCH DAMAGE. 42 +
+9
external/libkqueue-2.0.1/config.h
··· 1 + /* AUTOMATICALLY GENERATED -- DO NOT EDIT */ 2 + #define HAVE_DECL_EPOLLRDHUP 1 3 + #define HAVE_DECL_PPOLL 1 4 + #define HAVE_SYS_EPOLL_H 1 5 + /* #undef HAVE_SYS_EVENT_H */ 6 + #define HAVE_SYS_EVENTFD_H 1 7 + #define HAVE_SYS_INOTIFY_H 1 8 + #define HAVE_SYS_SIGNALFD_H 1 9 + #define HAVE_SYS_TIMERFD_H 1
+198
external/libkqueue-2.0.1/configure
··· 1 + #!/bin/sh 2 + # 3 + # Copyright (c) 2013 Mark Heily <mark@heily.com> 4 + # 5 + # Permission to use, copy, modify, and distribute this software for any 6 + # purpose with or without fee is hereby granted, provided that the above 7 + # copyright notice and this permission notice appear in all copies. 8 + # 9 + # THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 10 + # WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 11 + # MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 12 + # ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 13 + # WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 14 + # ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 15 + # OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 16 + # 17 + 18 + usage() { 19 + cat << "EOF" 20 + Usage: configure [options] 21 + 22 + Installation options: 23 + --bindir [DIRECTORY] TODO describe this [$(EPREFIX)/bin] 24 + --datadir [DIRECTORY] TODO describe this [$(DATAROOTDIR)] 25 + --datarootdir [DIRECTORY] TODO describe this [$(PREFIX)/share] 26 + --docdir [DIRECTORY] TODO describe this [$(DATAROOTDIR)/doc/$(PACKAGE)] 27 + --eprefix [DIRECTORY] TODO describe this [$(PREFIX)] 28 + --includedir [DIRECTORY] TODO describe this [$(PREFIX)/include] 29 + --infodir [DIRECTORY] TODO describe this [$(DATAROOTDIR)/info] 30 + --libdir [DIRECTORY] TODO describe this [$(EPREFIX)/lib] 31 + --libexecdir [DIRECTORY] TODO describe this [$(EPREFIX)/libexec] 32 + --localedir [DIRECTORY] TODO describe this [$(DATAROOTDIR)/locale] 33 + --localstatedir [DIRECTORY] TODO describe this [$(PREFIX)/var] 34 + --mandir [DIRECTORY] TODO describe this [$(DATAROOTDIR)/man] 35 + --oldincludedir [DIRECTORY] TODO describe this [/usr/include] 36 + --pkgconfigdir [DIRECTORY] where to install pkg-config files [$(LIBDIR)/pkgconfig] 37 + --pkgdatadir [DIRECTORY] TODO describe this [$(DATADIR)/$(PACKAGE)] 38 + --pkgincludedir [DIRECTORY] TODO describe this [$(INCLUDEDIR)/$(PACKAGE)] 39 + --pkglibdir [DIRECTORY] TODO describe this [$(LIBDIR)/$(PACKAGE)] 40 + --prefix [DIRECTORY] TODO describe this [/usr/local] 41 + --sbindir [DIRECTORY] TODO describe this [$(EPREFIX)/sbin] 42 + --sharedstatedir [DIRECTORY] TODO describe this [$(PREFIX)/com] 43 + --sysconfdir [DIRECTORY] TODO describe this [$(PREFIX)/etc] 44 + 45 + Project options: 46 + 47 + System types: 48 + --build BUILD set the system type for building 49 + --host HOST cross-compile programs to run on a different system type 50 + --target TARGET build a compiler for cross-compiling 51 + 52 + Optional Features: 53 + 54 + Common options: 55 + --disable-static Disable generation of static libraries 56 + --disable-option-checking 57 + -h, --help Show this message 58 + -V, --version Display version information and exit 59 + EOF 60 + } 61 + 62 + err() { 63 + echo "*** ERROR *** $*" 64 + exit 1 65 + } 66 + 67 + require_var() { 68 + key=$1 69 + eval "val=\$$key" 70 + if [ "$val" = "" ] ; then 71 + echo "ERROR: you must provide --$2 as a command line option" 72 + exit 1 73 + fi 74 + } 75 + 76 + 77 + echo "# Automatically generated by ./configure -- do not edit" > config.mk 78 + for arg in $* 79 + do 80 + if [ `echo "$arg" | grep "^--"` = "$arg" ] ; then 81 + key=`echo $arg | sed "s/^--//; s/=.*//; s/^with-//;"` 82 + val=`echo $arg | sed "s/.*=//"` 83 + uc_key=`echo "$key" | tr "a-z" "A-Z" | tr "-" "_"` 84 + case $key in 85 + "help") 86 + usage 87 + exit 1 88 + ;; 89 + bindir|datadir|datarootdir|docdir|includedir|infodir|libdir|libexecdir|localedir|localstatedir|mandir|pkgconfigdir|pkgdatadir|pkgincludedir|pkglibdir|prefix|sbindir|sharedstatedir|sysconfdir) 90 + echo "$uc_key=$val" >> config.mk 91 + ;; 92 + exec-prefix) 93 + echo "EPREFIX=$val" >> config.mk 94 + ;; 95 + program-prefix) 96 + if [ "$val" != "" ] ; then err "FIXME - not implemented" ; fi 97 + ;; 98 + disable-static) 99 + echo "$uc_key=1" >> config.mk 100 + ;; 101 + build|host) 102 + # TODO: we should split this up, and override the other Makeconf 103 + # variables like *_VENDOR, *_ARCH, *_CPU, *_KERNEL, *_SYSTEM 104 + echo "$uc_key=$val" >> config.mk 105 + eval "${key}_system_type=\"$val\"" 106 + ;; 107 + disable-option-checking) 108 + # Not implemented, this behavior is the default (for now) 109 + ;; 110 + disable-dependency-tracking) 111 + # Not implemented, dependency tracking is done in Ruby (for now) 112 + ;; 113 + # Android-specific variables 114 + ndk|sdk) 115 + echo "$uc_key=$val" >> config.mk 116 + eval "$key=\"$val\"" 117 + ;; 118 + *) 119 + echo "Warning: unrecognized option: $arg" 120 + ;; 121 + esac 122 + fi 123 + done 124 + 125 + # Android-specific options 126 + if [ "`echo ${host_system_type} | grep androideabi`" != "" ] ; then 127 + exec ./configure.rb $* 128 + # require_var ndk with-ndk 129 + # require_var sdk with-sdk 130 + fi 131 + 132 + printf "checking for a C compiler... " 133 + for cmd in ${host_system_type}-cc cc gcc gcc4 clang 134 + do 135 + $cmd --version >/dev/null 2>&1 136 + if [ $? -eq 0 ] ; then cc="$cmd" ; break ; fi 137 + done 138 + if [ -n "$CC" ] ; then cc="$CC" ; fi 139 + if [ -n "$cc" ] ; then 140 + echo "$cc" 141 + echo "CC=$cc" >> config.mk 142 + if [ "$cc" != "cc" ] ; then echo "LD=$cc" >> config.mk ; fi 143 + if [ -n "$CFLAGS" ] ; then echo "CFLAGS=$CFLAGS" >> config.mk ; fi 144 + else 145 + echo "not found" 146 + err "Please install a compiler and add it to your PATH" 147 + fi 148 + 149 + printf "checking for ar.. " 150 + for ar in ${host_system_type}-ar ar gar 151 + do 152 + $ar --version >/dev/null 2>&1 153 + if [ $? -eq 0 ] ; then ar="$ar" ; break ; fi 154 + done 155 + if [ -n "$ar" ] ; then 156 + echo "$ar" 157 + echo "AR=$ar" >> config.mk 158 + else 159 + echo "not found" 160 + err "Please install an archiver and add it to your PATH" 161 + fi 162 + 163 + printf "checking for ranlib.. " 164 + for ranlib in ${host_system_type}-ranlib ranlib 165 + do 166 + $ar --version >/dev/null 2>&1 167 + if [ $? -eq 0 ] ; then ranlib="$ranlib" ; break ; fi 168 + done 169 + if [ -n "$ranlib" ] ; then 170 + echo "$ranlib" 171 + echo "RANLIB=$ranlib" >> config.mk 172 + else 173 + echo "not found" 174 + err "Please install ranlib and add it to your PATH" 175 + fi 176 + 177 + printf "checking for a usable make command... " 178 + for cmd in make gmake 179 + do 180 + $cmd --version >/dev/null 2>&1 181 + if [ $? -eq 0 ] ; then make="$cmd" ; break ; fi 182 + done 183 + if [ -n "$make" ] ; then 184 + echo "yes" 185 + echo "MAKE=$make" >> config.mk 186 + else 187 + echo "not found" 188 + err "Please install GNU Make and add it to your PATH as either make or gmake" 189 + fi 190 + 191 + # Allow additional variables from the environment to override the defaults 192 + # 193 + test -n "$LD" && echo "LD=$LD" >> config.mk 194 + test -n "$LDFLAGS" && echo "LDFLAGS=$LDFLAGS" >> config.mk 195 + # TODO: need to add Makefile support for: LIBS, CPP, CPPFLAGS 196 + 197 + rm -f config.h 198 + $make config.h
+320
external/libkqueue-2.0.1/configure.rb
··· 1 + #!/usr/bin/env ruby 2 + # 3 + # Copyright (c) 2012 Mark Heily <mark@heily.com> 4 + # 5 + # Permission to use, copy, modify, and distribute this software for any 6 + # purpose with or without fee is hereby granted, provided that the above 7 + # copyright notice and this permission notice appear in all copies. 8 + # 9 + # THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 10 + # WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 11 + # MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 12 + # ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 13 + # WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 14 + # ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 15 + # OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 16 + # 17 + 18 + begin 19 + require 'makeconf' 20 + rescue LoadError 21 + $LOAD_PATH << "makeconf" 22 + require 'makeconf' 23 + end 24 + 25 + # Determine the list of compiler flags 26 + def get_cflags 27 + cflags='-I./src/common -I./include -Wall -Wextra -Wno-missing-field-initializers -Werror -g -O2 -std=c99 -D_XOPEN_SOURCE=600'.split(/ /) 28 + 29 + if Platform.is_linux? 30 + # TODO - note this as a GCC 4.X dependency 31 + cflags.push ' -fvisibility=hidden' 32 + end 33 + if Platform.is_solaris? 34 + cflags.push "-D__EXTENSIONS__" 35 + end 36 + cflags 37 + end 38 + 39 + # Determine the list of source code files for libkqueue 40 + def get_source_list(project) 41 + src = %w{ 42 + src/common/filter.c 43 + src/common/knote.c 44 + src/common/map.c 45 + src/common/kevent.c 46 + src/common/kqueue.c 47 + } 48 + 49 + if Platform.is_solaris? 50 + src.push 'src/solaris/signal.c', 51 + 'src/solaris/timer.c', 52 + 'src/solaris/platform.c', 53 + 'src/solaris/user.c' 54 + end 55 + 56 + if Platform.is_linux? or Platform.is_solaris? 57 + src.push 'src/posix/platform.c' 58 + end 59 + 60 + if Platform.is_linux? 61 + src.push 'src/linux/platform.c', 62 + 'src/linux/read.c', 63 + 'src/linux/write.c', 64 + 'src/linux/user.c', 65 + 'src/linux/vnode.c' 66 + 67 + # FIXME: needed for RHEL5 68 + #src.push 'src/posix/user.c' 69 + 70 + if project.check_header('sys/signalfd.h') 71 + src.push 'src/linux/signal.c' 72 + else 73 + src.push 'src/posix/signal.c' 74 + end 75 + 76 + src.push 'src/linux/timer.c' 77 + end 78 + 79 + if Platform.is_windows? 80 + src.push 'src/windows/timer.c', 81 + 'src/windows/platform.c', 82 + 'src/windows/read.c', 83 + 'src/windows/user.c' 84 + end 85 + 86 + src 87 + end 88 + 89 + # Generate the linker flags 90 + def get_ldadd 91 + ldadd = '' 92 + 93 + if Platform.is_linux? or Platform.is_solaris? 94 + ldadd += ' -lpthread' 95 + end 96 + 97 + if Platform.is_linux? 98 + ldadd += ' -lrt' 99 + end 100 + 101 + if Platform.is_windows? 102 + ldadd += ' ws2_32.lib' 103 + end 104 + 105 + ldadd 106 + end 107 + 108 + # 109 + # MAIN() 110 + # 111 + 112 + project = Project.new \ 113 + :id => 'libkqueue', 114 + :version => '2.0.1' 115 + 116 + kq = Library.new( 117 + :id => 'libkqueue', 118 + :cflags => get_cflags(), 119 + :ldadd => get_ldadd(), 120 + :sources => get_source_list(project) 121 + ) 122 + 123 + 124 + project.check_header 'sys/event.h' 125 + if Platform.is_linux? 126 + project.check_decl 'EPOLLRDHUP', :include => 'sys/epoll.h' 127 + project.check_decl 'ppoll', :cflags => '#define _GNU_SOURCE', :include => 'poll.h' 128 + 129 + 130 + project.check_header('sys/epoll.h') or throw 'epoll is required' 131 + project.check_header('sys/inotify.h') or throw 'inotify is required' 132 + project.check_header %w{ sys/signalfd.h sys/timerfd.h sys/eventfd.h } 133 + end 134 + 135 + project.add(kq) 136 + 137 + project.add(Header.new( 138 + :id => 'event.h', 139 + :sources => 'include/sys/event.h', 140 + :namespace => 'kqueue/sys' 141 + )) 142 + 143 + project.add(Manual.new('kqueue.2', :alias => 'kevent.2')) 144 + 145 + test_ldadd = get_ldadd() 146 + test_ldadd += ' libkqueue.a' 147 + if Platform.is_windows? 148 + project.add( 149 + Test.new( 150 + :id => 'kqtest', 151 + :cflags => '-g -O0 -Wall -Werror -Iinclude -Itest', 152 + :sources => %w{ 153 + test/main.c 154 + test/kevent.c 155 + test/test.c 156 + test/read.c 157 + test/timer.c 158 + test/vnode.c 159 + test/user.c 160 + }, # NOTE: signal.c and proc.c are removed 161 + :ldadd => test_ldadd.split(' ') 162 + ) 163 + ) 164 + else 165 + project.add( 166 + Test.new( 167 + :id => 'kqtest', 168 + :cflags => '-g -O0 -Wall -Werror -I./include -I./test', 169 + :sources => %w{ 170 + test/main.c 171 + test/kevent.c 172 + test/test.c 173 + test/proc.c 174 + test/read.c 175 + test/signal.c 176 + test/timer.c 177 + test/vnode.c 178 + test/user.c 179 + }, 180 + :ldadd => test_ldadd.split(' ') 181 + ) 182 + ) 183 + end 184 + 185 + 186 + project.add(PkgConfig.new( 187 + :name => 'libkqueue', 188 + :description => 'Emulates FreeBSD kqueue(2) on other platforms', 189 + :requires => '', 190 + :libs => '-lkqueue', 191 + :libs_private => '-lpthread', 192 + :export_cflags => '-I${includedir}/kqueue' 193 + )) 194 + 195 + project.packager.add 'libkqueue.spec' 196 + 197 + mc = Makeconf.new() 198 + mc.configure(project) 199 + 200 + __END__ 201 + # 202 + # BEGIN: old config.inc contents 203 + # 204 + program="libkqueue" 205 + version="2.0a" 206 + abi_major="0" 207 + abi_minor="0" 208 + abi_version="$abi_major.$abi_minor" 209 + cflags="-Wall -Wextra -Wno-missing-field-initializers -Werror -g -O2 -std=c99 -D_XOPEN_SOURCE=600" 210 + ldflags="" 211 + sources="src/common/filter.c src/common/knote.c src/common/map.c 212 + src/common/kevent.c src/common/kqueue.c" 213 + libdepends="" 214 + deps="src/common/private.h src/common/debug.h" 215 + mans="kqueue.2" 216 + headers="src/common/private.h" 217 + extra_dist="*.in" 218 + subdirs="src include test" 219 + 220 + # Package metadata 221 + pkg_summary="Emulates the kqueue and kevent system calls" 222 + pkg_description="Emulates the kqueue and kevent system calls" 223 + license="BSD" 224 + author="Mark Heily" 225 + 226 + pre_configure_hook() { 227 + if [ "$debug" = "yes" ] ; then 228 + cflags="$cflags -g3 -O0 -rdynamic" 229 + fi 230 + 231 + if [ "$target" != "windows" ] ; then 232 + cflags="$cflags -fpic" 233 + fi 234 + 235 + optional_headers="err.h" 236 + 237 + libdepends=" -L$libdir" 238 + if [ $target = "linux" ] ; then 239 + 240 + check_symbol sys/epoll.h EPOLLRDHUP 241 + 242 + # TODO - note this as a GCC 4.X dependency 243 + cflags="$cflags -fvisibility=hidden" 244 + 245 + libdepends="$libdepends -lpthread -lrt" 246 + required_headers="sys/epoll.h sys/inotify.h" 247 + optional_headers="sys/signalfd.h sys/timerfd.h sys/eventfd.h" 248 + fi 249 + 250 + if [ $target = "solaris" ] ; then 251 + cflags="$cflags -m64" 252 + ldflags="$ldflags -m64" 253 + libdepends="$libdepends -lsocket -lnsl" 254 + fi 255 + } 256 + 257 + post_configure_hook() { 258 + finalize target "$target" 259 + 260 + platform="src/posix/platform.c" 261 + evfilt_signal="src/posix/signal.c" 262 + evfilt_proc="src/$target/proc.c" 263 + evfilt_socket="src/$target/socket.c" 264 + evfilt_timer="src/posix/timer.c" 265 + evfilt_user="src/posix/user.c" 266 + evfilt_vnode="src/$target/vnode.c" 267 + 268 + if [ $target = "linux" ] ; then 269 + evfilt_user="src/linux/user.c" 270 + evfilt_socket="src/linux/read.c src/linux/write.c" 271 + 272 + #XXX-FIXME disabled 273 + evfilt_proc="" 274 + 275 + if [ "$have_sys_signalfd_h" = "yes" ] ; then 276 + evfilt_signal="src/linux/signal.c" 277 + fi 278 + if [ "$have_sys_timerfd_h" = "yes" ] ; then 279 + evfilt_timer="src/linux/timer.c" 280 + fi 281 + platform="$platform src/linux/platform.c" 282 + fi 283 + 284 + if [ $target = "solaris" ] ; then 285 + cflags="$cflags -D__EXTENSIONS__" 286 + platform="$platform src/solaris/platform.c" 287 + evfilt_timer="src/solaris/timer.c" 288 + evfilt_user="src/solaris/user.c" 289 + evfilt_signal="src/solaris/signal.c" 290 + evfilt_proc="" 291 + evfilt_vnode="" 292 + fi 293 + 294 + # FIXME: This will compile but not actually work 295 + if [ $target = "freebsd" ] ; then 296 + evfilt_signal="src/posix/signal.c" 297 + evfilt_proc="" 298 + evfilt_socket="" 299 + evfilt_timer="" 300 + evfilt_vnode="" 301 + fi 302 + 303 + if [ $target = "windows" ] ; then 304 + platform="src/windows/platform.c" 305 + cflags="$cflags -march=i686 -lws2_32" 306 + ldflags="$ldflags -march=i686" 307 + ldadd="-lws2_32" 308 + evfilt_proc="" 309 + evfilt_signal="" 310 + #evfilt_socket="src/windows/read.c src/linux/write.c" 311 + evfilt_socket="src/windows/read.c" 312 + evfilt_timer="src/windows/timer.c" 313 + evfilt_user="src/windows/user.c" 314 + evfilt_vnode="" 315 + fi 316 + 317 + sources="$sources $platform 318 + $evfilt_signal $evfilt_proc 319 + $evfilt_socket $evfilt_timer $evfilt_user $evfilt_vnode" 320 + }
+212
external/libkqueue-2.0.1/include/sys/event.h
··· 1 + /*- 2 + * Copyright (c) 2009 Mark Heily <mark@heily.com> 3 + * Copyright (c) 1999,2000,2001 Jonathan Lemon <jlemon@FreeBSD.org> 4 + * All rights reserved. 5 + * 6 + * Redistribution and use in source and binary forms, with or without 7 + * modification, are permitted provided that the following conditions 8 + * are met: 9 + * 1. Redistributions of source code must retain the above copyright 10 + * notice, this list of conditions and the following disclaimer. 11 + * 2. Redistributions in binary form must reproduce the above copyright 12 + * notice, this list of conditions and the following disclaimer in the 13 + * documentation and/or other materials provided with the distribution. 14 + * 15 + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 16 + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 17 + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 18 + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 19 + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 20 + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 21 + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 22 + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 23 + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 24 + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 25 + * SUCH DAMAGE. 26 + * 27 + * $FreeBSD SVN Revision 197533$ 28 + */ 29 + 30 + #ifndef _SYS_EVENT_H_ 31 + #define _SYS_EVENT_H_ 32 + 33 + #include <sys/types.h> 34 + 35 + #ifdef __KERNEL__ 36 + #define intptr_t long 37 + #else 38 + #include <sys/types.h> 39 + #if defined(_WIN32) && _MSC_VER < 1600 && !defined(__MINGW32__) 40 + # include "../../src/windows/stdint.h" 41 + #else 42 + # include <stdint.h> 43 + #endif 44 + #define LIBKQUEUE 1 45 + #endif 46 + 47 + struct timespec; 48 + 49 + #define EVFILT_READ (-1) 50 + #define EVFILT_WRITE (-2) 51 + #define EVFILT_AIO (-3) /* attached to aio requests */ 52 + #define EVFILT_VNODE (-4) /* attached to vnodes */ 53 + #define EVFILT_PROC (-5) /* attached to struct proc */ 54 + #define EVFILT_SIGNAL (-6) /* attached to struct proc */ 55 + #define EVFILT_TIMER (-7) /* timers */ 56 + #define EVFILT_NETDEV (-8) /* network devices */ 57 + #define EVFILT_FS (-9) /* filesystem events */ 58 + #define EVFILT_LIO (-10) /* attached to lio requests */ 59 + #define EVFILT_USER (-11) /* User events */ 60 + #define EVFILT_SYSCOUNT 11 61 + 62 + #define EV_SET(kevp_, a, b, c, d, e, f) do { \ 63 + struct kevent *kevp = (kevp_); \ 64 + (kevp)->ident = (a); \ 65 + (kevp)->filter = (b); \ 66 + (kevp)->flags = (c); \ 67 + (kevp)->fflags = (d); \ 68 + (kevp)->data = (e); \ 69 + (kevp)->udata = (f); \ 70 + } while(0) 71 + 72 + struct kevent { 73 + uintptr_t ident; /* identifier for this event */ 74 + short filter; /* filter for event */ 75 + unsigned short flags; 76 + unsigned int fflags; 77 + intptr_t data; 78 + void *udata; /* opaque user data identifier */ 79 + }; 80 + 81 + /* actions */ 82 + #define EV_ADD 0x0001 /* add event to kq (implies enable) */ 83 + #define EV_DELETE 0x0002 /* delete event from kq */ 84 + #define EV_ENABLE 0x0004 /* enable event */ 85 + #define EV_DISABLE 0x0008 /* disable event (not reported) */ 86 + 87 + /* flags */ 88 + #define EV_ONESHOT 0x0010 /* only report one occurrence */ 89 + #define EV_CLEAR 0x0020 /* clear event state after reporting */ 90 + #define EV_RECEIPT 0x0040 /* force EV_ERROR on success, data=0 */ 91 + #define EV_DISPATCH 0x0080 /* disable event after reporting */ 92 + 93 + #define EV_SYSFLAGS 0xF000 /* reserved by system */ 94 + #define EV_FLAG1 0x2000 /* filter-specific flag */ 95 + 96 + /* returned values */ 97 + #define EV_EOF 0x8000 /* EOF detected */ 98 + #define EV_ERROR 0x4000 /* error, data contains errno */ 99 + 100 + /* 101 + * data/hint flags/masks for EVFILT_USER 102 + * 103 + * On input, the top two bits of fflags specifies how the lower twenty four 104 + * bits should be applied to the stored value of fflags. 105 + * 106 + * On output, the top two bits will always be set to NOTE_FFNOP and the 107 + * remaining twenty four bits will contain the stored fflags value. 108 + */ 109 + #define NOTE_FFNOP 0x00000000 /* ignore input fflags */ 110 + #define NOTE_FFAND 0x40000000 /* AND fflags */ 111 + #define NOTE_FFOR 0x80000000 /* OR fflags */ 112 + #define NOTE_FFCOPY 0xc0000000 /* copy fflags */ 113 + #define NOTE_FFCTRLMASK 0xc0000000 /* masks for operations */ 114 + #define NOTE_FFLAGSMASK 0x00ffffff 115 + 116 + #define NOTE_TRIGGER 0x01000000 /* Cause the event to be 117 + triggered for output. */ 118 + 119 + /* 120 + * data/hint flags for EVFILT_{READ|WRITE} 121 + */ 122 + #define NOTE_LOWAT 0x0001 /* low water mark */ 123 + #undef NOTE_LOWAT /* Not supported on Linux */ 124 + 125 + /* 126 + * data/hint flags for EVFILT_VNODE 127 + */ 128 + #define NOTE_DELETE 0x0001 /* vnode was removed */ 129 + #define NOTE_WRITE 0x0002 /* data contents changed */ 130 + #define NOTE_EXTEND 0x0004 /* size increased */ 131 + #define NOTE_ATTRIB 0x0008 /* attributes changed */ 132 + #define NOTE_LINK 0x0010 /* link count changed */ 133 + #define NOTE_RENAME 0x0020 /* vnode was renamed */ 134 + #define NOTE_REVOKE 0x0040 /* vnode access was revoked */ 135 + #undef NOTE_REVOKE /* Not supported on Linux */ 136 + 137 + /* 138 + * data/hint flags for EVFILT_PROC 139 + */ 140 + #define NOTE_EXIT 0x80000000 /* process exited */ 141 + #define NOTE_FORK 0x40000000 /* process forked */ 142 + #define NOTE_EXEC 0x20000000 /* process exec'd */ 143 + #define NOTE_PCTRLMASK 0xf0000000 /* mask for hint bits */ 144 + #define NOTE_PDATAMASK 0x000fffff /* mask for pid */ 145 + 146 + /* additional flags for EVFILT_PROC */ 147 + #define NOTE_TRACK 0x00000001 /* follow across forks */ 148 + #define NOTE_TRACKERR 0x00000002 /* could not track child */ 149 + #define NOTE_CHILD 0x00000004 /* am a child process */ 150 + 151 + /* 152 + * data/hint flags for EVFILT_NETDEV 153 + */ 154 + #define NOTE_LINKUP 0x0001 /* link is up */ 155 + #define NOTE_LINKDOWN 0x0002 /* link is down */ 156 + #define NOTE_LINKINV 0x0004 /* link state is invalid */ 157 + 158 + /* KLUDGE: This is from <sys/mount.h> on FreeBSD and is used by 159 + the EVFILT_FS filter. */ 160 + /* vfsquery flags */ 161 + #define VQ_NOTRESP 0x0001 /* server down */ 162 + #define VQ_NEEDAUTH 0x0002 /* server bad auth */ 163 + #define VQ_LOWDISK 0x0004 /* we're low on space */ 164 + #define VQ_MOUNT 0x0008 /* new filesystem arrived */ 165 + #define VQ_UNMOUNT 0x0010 /* filesystem has left */ 166 + #define VQ_DEAD 0x0020 /* filesystem is dead, needs force unmount */ 167 + #define VQ_ASSIST 0x0040 /* filesystem needs assistance from external 168 + program */ 169 + #define VQ_NOTRESPLOCK 0x0080 /* server lockd down */ 170 + 171 + 172 + #ifndef __KERNEL__ 173 + #ifdef __cplusplus 174 + extern "C" { 175 + #endif 176 + 177 + #ifdef _WIN32 178 + 179 + struct timespec { 180 + time_t tv_sec; 181 + long tv_nsec; 182 + }; 183 + 184 + __declspec(dllexport) int 185 + kqueue(void); 186 + 187 + __declspec(dllexport) int 188 + kevent(int kq, const struct kevent *changelist, int nchanges, 189 + struct kevent *eventlist, int nevents, 190 + const struct timespec *timeout); 191 + 192 + #ifdef MAKE_STATIC 193 + __declspec(dllexport) int 194 + libkqueue_init(); 195 + #endif 196 + 197 + #else 198 + int kqueue(void); 199 + int kevent(int kq, const struct kevent *changelist, int nchanges, 200 + struct kevent *eventlist, int nevents, 201 + const struct timespec *timeout); 202 + #ifdef MAKE_STATIC 203 + int libkqueue_init(); 204 + #endif 205 + #endif 206 + 207 + #ifdef __cplusplus 208 + } 209 + #endif 210 + #endif /* !__KERNEL__* */ 211 + 212 + #endif /* !_SYS_EVENT_H_ */
+515
external/libkqueue-2.0.1/kqueue.2
··· 1 + .\" $FreeBSD: Revision: 197243$ 2 + .\" Copyright (c) 2010 Mark Heily 3 + .\" Copyright (c) 2000 Jonathan Lemon 4 + .\" All rights reserved. 5 + .\" 6 + .\" Redistribution and use in source and binary forms, with or without 7 + .\" modification, are permitted provided that the following conditions 8 + .\" are met: 9 + .\" 1. Redistributions of source code must retain the above copyright 10 + .\" notice, this list of conditions and the following disclaimer. 11 + .\" 2. Redistributions in binary form must reproduce the above copyright 12 + .\" notice, this list of conditions and the following disclaimer in the 13 + .\" documentation and/or other materials provided with the distribution. 14 + .\" 15 + .\" THIS SOFTWARE IS PROVIDED ``AS IS'' AND 16 + .\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 17 + .\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 18 + .\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 19 + .\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 20 + .\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 21 + .\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 22 + .\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 23 + .\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 24 + .\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 25 + .\" SUCH DAMAGE. 26 + .\" 27 + .\" $FreeBSD$ 28 + .\" 29 + .Dd September 17, 2010 30 + .Dt KQUEUE 2 31 + .Os 32 + .Sh NAME 33 + .Nm kqueue , 34 + .Nm kevent 35 + .Nd kernel event notification mechanism 36 + .Sh SYNOPSIS 37 + .In sys/types.h 38 + .In sys/event.h 39 + .In sys/time.h 40 + .Ft int 41 + .Fn kqueue "void" 42 + .Ft int 43 + .Fn kevent "int kq" "const struct kevent *changelist" "int nchanges" "struct kevent *eventlist" "int nevents" "const struct timespec *timeout" 44 + .Fn EV_SET "&kev" ident filter flags fflags data udata 45 + .Sh DESCRIPTION 46 + The 47 + .Fn kqueue 48 + system call 49 + provides a generic method of notifying the user when an event 50 + happens or a condition holds, based on the results of small 51 + pieces of kernel code termed filters. 52 + A kevent is identified by the (ident, filter) pair; there may only 53 + be one unique kevent per kqueue. 54 + .Pp 55 + The filter is executed upon the initial registration of a kevent 56 + in order to detect whether a preexisting condition is present, and is also 57 + executed whenever an event is passed to the filter for evaluation. 58 + If the filter determines that the condition should be reported, 59 + then the kevent is placed on the kqueue for the user to retrieve. 60 + .Pp 61 + The filter is also run when the user attempts to retrieve the kevent 62 + from the kqueue. 63 + If the filter indicates that the condition that triggered 64 + the event no longer holds, the kevent is removed from the kqueue and 65 + is not returned. 66 + .Pp 67 + Multiple events which trigger the filter do not result in multiple 68 + kevents being placed on the kqueue; instead, the filter will aggregate 69 + the events into a single struct kevent. 70 + Calling 71 + .Fn close 72 + on a file descriptor will remove any kevents that reference the descriptor. 73 + .Pp 74 + The 75 + .Fn kqueue 76 + system call 77 + creates a new kernel event queue and returns a descriptor. 78 + The queue is not inherited by a child created with 79 + .Xr fork 2 . 80 + However, if 81 + .Xr rfork 2 82 + is called without the 83 + .Dv RFFDG 84 + flag, then the descriptor table is shared, 85 + which will allow sharing of the kqueue between two processes. 86 + .Pp 87 + The 88 + .Fn kevent 89 + system call 90 + is used to register events with the queue, and return any pending 91 + events to the user. 92 + The 93 + .Fa changelist 94 + argument 95 + is a pointer to an array of 96 + .Va kevent 97 + structures, as defined in 98 + .In sys/event.h . 99 + All changes contained in the 100 + .Fa changelist 101 + are applied before any pending events are read from the queue. 102 + The 103 + .Fa nchanges 104 + argument 105 + gives the size of 106 + .Fa changelist . 107 + The 108 + .Fa eventlist 109 + argument 110 + is a pointer to an array of kevent structures. 111 + The 112 + .Fa nevents 113 + argument 114 + determines the size of 115 + .Fa eventlist . 116 + When 117 + .Fa nevents 118 + is zero, 119 + .Fn kevent 120 + will return immediately even if there is a 121 + .Fa timeout 122 + specified unlike 123 + .Xr select 2 . 124 + If 125 + .Fa timeout 126 + is a non-NULL pointer, it specifies a maximum interval to wait 127 + for an event, which will be interpreted as a struct timespec. 128 + If 129 + .Fa timeout 130 + is a NULL pointer, 131 + .Fn kevent 132 + waits indefinitely. 133 + To effect a poll, the 134 + .Fa timeout 135 + argument should be non-NULL, pointing to a zero-valued 136 + .Va timespec 137 + structure. 138 + The same array may be used for the 139 + .Fa changelist 140 + and 141 + .Fa eventlist . 142 + .Pp 143 + The 144 + .Fn EV_SET 145 + macro is provided for ease of initializing a 146 + kevent structure. 147 + .Pp 148 + The 149 + .Va kevent 150 + structure is defined as: 151 + .Bd -literal 152 + struct kevent { 153 + uintptr_t ident; /* identifier for this event */ 154 + short filter; /* filter for event */ 155 + u_short flags; /* action flags for kqueue */ 156 + u_int fflags; /* filter flag value */ 157 + intptr_t data; /* filter data value */ 158 + void *udata; /* opaque user data identifier */ 159 + }; 160 + .Ed 161 + .Pp 162 + The fields of 163 + .Fa struct kevent 164 + are: 165 + .Bl -tag -width XXXfilter 166 + .It ident 167 + Value used to identify this event. 168 + The exact interpretation is determined by the attached filter, 169 + but often is a file descriptor. 170 + .It filter 171 + Identifies the kernel filter used to process this event. 172 + The pre-defined 173 + system filters are described below. 174 + .It flags 175 + Actions to perform on the event. 176 + .It fflags 177 + Filter-specific flags. 178 + .It data 179 + Filter-specific data value. 180 + .It udata 181 + Opaque user-defined value passed through the kernel unchanged. 182 + .El 183 + .Pp 184 + The 185 + .Va flags 186 + field can contain the following values: 187 + .Bl -tag -width XXXEV_ONESHOT 188 + .It EV_ADD 189 + Adds the event to the kqueue. 190 + Re-adding an existing event 191 + will modify the parameters of the original event, and not result 192 + in a duplicate entry. 193 + Adding an event automatically enables it, 194 + unless overridden by the EV_DISABLE flag. 195 + .It EV_ENABLE 196 + Permit 197 + .Fn kevent 198 + to return the event if it is triggered. 199 + .It EV_DISABLE 200 + Disable the event so 201 + .Fn kevent 202 + will not return it. 203 + The filter itself is not disabled. 204 + .It EV_DISPATCH 205 + Disable the event source immediately after delivery of an event. 206 + See 207 + .Dv EV_DISABLE 208 + above. 209 + .It EV_DELETE 210 + Removes the event from the kqueue. 211 + Events which are attached to 212 + file descriptors are automatically deleted on the last close of 213 + the descriptor. 214 + .It EV_RECEIPT 215 + This flag is useful for making bulk changes to a kqueue without draining 216 + any pending events. 217 + When passed as input, it forces 218 + .Dv EV_ERROR 219 + to always be returned. 220 + When a filter is successfully added the 221 + .Va data 222 + field will be zero. 223 + .It EV_ONESHOT 224 + Causes the event to return only the first occurrence of the filter 225 + being triggered. 226 + After the user retrieves the event from the kqueue, 227 + it is deleted. 228 + .It EV_CLEAR 229 + After the event is retrieved by the user, its state is reset. 230 + This is useful for filters which report state transitions 231 + instead of the current state. 232 + Note that some filters may automatically 233 + set this flag internally. 234 + .It EV_EOF 235 + Filters may set this flag to indicate filter-specific EOF condition. 236 + .It EV_ERROR 237 + See 238 + .Sx RETURN VALUES 239 + below. 240 + .El 241 + .Pp 242 + The predefined system filters are listed below. 243 + Arguments may be passed to and from the filter via the 244 + .Va fflags 245 + and 246 + .Va data 247 + fields in the kevent structure. 248 + .Bl -tag -width EVFILT_SIGNAL 249 + .It EVFILT_READ 250 + Takes a descriptor as the identifier, and returns whenever 251 + there is data available to read. 252 + The behavior of the filter is slightly different depending 253 + on the descriptor type. 254 + .Pp 255 + .Bl -tag -width 2n 256 + .It Sockets 257 + Sockets which have previously been passed to 258 + .Fn listen 259 + return when there is an incoming connection pending. 260 + .Va data 261 + contains the size of the listen backlog. 262 + .Pp 263 + Other socket descriptors return when there is data to be read, 264 + subject to the 265 + .Dv SO_RCVLOWAT 266 + value of the socket buffer. 267 + This may be overridden with a per-filter low water mark at the 268 + time the filter is added by setting the 269 + NOTE_LOWAT 270 + flag in 271 + .Va fflags , 272 + and specifying the new low water mark in 273 + .Va data . 274 + On return, 275 + .Va data 276 + contains the number of bytes of protocol data available to read. 277 + .Pp 278 + If the read direction of the socket has shutdown, then the filter 279 + also sets EV_EOF in 280 + .Va flags , 281 + and returns the socket error (if any) in 282 + .Va fflags . 283 + It is possible for EOF to be returned (indicating the connection is gone) 284 + while there is still data pending in the socket buffer. 285 + .It Vnodes 286 + Returns when the file pointer is not at the end of file. 287 + .Va data 288 + contains the offset from current position to end of file, 289 + and may be negative. 290 + .It "Fifos, Pipes" 291 + Returns when the there is data to read; 292 + .Va data 293 + contains the number of bytes available. 294 + .Pp 295 + When the last writer disconnects, the filter will set EV_EOF in 296 + .Va flags . 297 + This may be cleared by passing in EV_CLEAR, at which point the 298 + filter will resume waiting for data to become available before 299 + returning. 300 + .It "BPF devices" 301 + Returns when the BPF buffer is full, the BPF timeout has expired, or 302 + when the BPF has 303 + .Dq immediate mode 304 + enabled and there is any data to read; 305 + .Va data 306 + contains the number of bytes available. 307 + .El 308 + .It EVFILT_WRITE 309 + Takes a descriptor as the identifier, and returns whenever 310 + it is possible to write to the descriptor. 311 + For sockets, pipes 312 + and fifos, 313 + .Va data 314 + will contain the amount of space remaining in the write buffer. 315 + The filter will set EV_EOF when the reader disconnects, and for 316 + the fifo case, this may be cleared by use of EV_CLEAR. 317 + Note that this filter is not supported for vnodes or BPF devices. 318 + .Pp 319 + For sockets, the low water mark and socket error handling is 320 + identical to the EVFILT_READ case. 321 + .It EVFILT_VNODE 322 + Takes a file descriptor as the identifier and the events to watch for in 323 + .Va fflags , 324 + and returns when one or more of the requested events occurs on the descriptor. 325 + The events to monitor are: 326 + .Bl -tag -width XXNOTE_RENAME 327 + .It NOTE_DELETE 328 + The 329 + .Fn unlink 330 + system call 331 + was called on the file referenced by the descriptor. 332 + .It NOTE_WRITE 333 + A write occurred on the file referenced by the descriptor. 334 + .It NOTE_EXTEND 335 + The file referenced by the descriptor was extended. 336 + .It NOTE_ATTRIB 337 + The file referenced by the descriptor had its attributes changed. 338 + .It NOTE_LINK 339 + The link count on the file changed. 340 + .It NOTE_RENAME 341 + The file referenced by the descriptor was renamed. 342 + .El 343 + .Pp 344 + On return, 345 + .Va fflags 346 + contains the events which triggered the filter. 347 + .It EVFILT_SIGNAL 348 + Takes the signal number to monitor as the identifier and returns 349 + when the given signal is delivered to the process. 350 + This overrides the 351 + .Fn signal 352 + and 353 + .Fn sigaction 354 + facilities, and has a higher precedence. 355 + The filter will record 356 + all attempts to deliver a signal to a process, even if the signal has 357 + been marked as SIG_IGN. 358 + .Va data 359 + returns the number of times the signal has occurred since the last call to 360 + .Fn kevent . 361 + This filter automatically sets the EV_CLEAR flag internally. 362 + .It EVFILT_TIMER 363 + Establishes an arbitrary timer identified by 364 + .Va ident . 365 + When adding a timer, 366 + .Va data 367 + specifies the timeout period in milliseconds. 368 + The timer will be periodic unless EV_ONESHOT is specified. 369 + On return, 370 + .Va data 371 + contains the number of times the timeout has expired since the last call to 372 + .Fn kevent . 373 + This filter automatically sets the EV_CLEAR flag internally. 374 + There is a system wide limit on the number of timers 375 + which is controlled by the 376 + .Va kern.kq_calloutmax 377 + sysctl. 378 + .It Dv EVFILT_USER 379 + Establishes a user event identified by 380 + .Va ident 381 + which is not assosicated with any kernel mechanism but is triggered by 382 + user level code. 383 + The lower 24 bits of the 384 + .Va fflags 385 + may be used for user defined flags and manipulated using the following: 386 + .Bl -tag -width XXNOTE_FFLAGSMASK 387 + .It Dv NOTE_FFNOP 388 + Ignore the input 389 + .Va fflags . 390 + .It Dv NOTE_FFAND 391 + Bitwise AND 392 + .Va fflags . 393 + .It Dv NOTE_FFOR 394 + Bitwise OR 395 + .Va fflags . 396 + .It Dv NOTE_COPY 397 + Copy 398 + .Va fflags . 399 + .It Dv NOTE_FFCTRLMASK 400 + Control mask for 401 + .Va fflags . 402 + .It Dv NOTE_FFLAGSMASK 403 + User defined flag mask for 404 + .Va fflags . 405 + .El 406 + .Pp 407 + A user event is triggered for output with the following: 408 + .Bl -tag -width XXNOTE_FFLAGSMASK 409 + .It Dv NOTE_TRIGGER 410 + Cause the event to be triggered. 411 + .El 412 + .Pp 413 + On return, 414 + .Va fflags 415 + contains the users defined flags in the lower 24 bits. 416 + .El 417 + .Sh RETURN VALUES 418 + The 419 + .Fn kqueue 420 + system call 421 + creates a new kernel event queue and returns a file descriptor. 422 + If there was an error creating the kernel event queue, a value of -1 is 423 + returned and errno set. 424 + .Pp 425 + The 426 + .Fn kevent 427 + system call 428 + returns the number of events placed in the 429 + .Fa eventlist , 430 + up to the value given by 431 + .Fa nevents . 432 + If an error occurs while processing an element of the 433 + .Fa changelist 434 + and there is enough room in the 435 + .Fa eventlist , 436 + then the event will be placed in the 437 + .Fa eventlist 438 + with 439 + .Dv EV_ERROR 440 + set in 441 + .Va flags 442 + and the system error in 443 + .Va data . 444 + Otherwise, 445 + .Dv -1 446 + will be returned, and 447 + .Dv errno 448 + will be set to indicate the error condition. 449 + If the time limit expires, then 450 + .Fn kevent 451 + returns 0. 452 + .Sh ERRORS 453 + The 454 + .Fn kqueue 455 + system call fails if: 456 + .Bl -tag -width Er 457 + .It Bq Er ENOMEM 458 + The kernel failed to allocate enough memory for the kernel queue. 459 + .It Bq Er EMFILE 460 + The per-process descriptor table is full. 461 + .It Bq Er ENFILE 462 + The system file table is full. 463 + .El 464 + .Pp 465 + The 466 + .Fn kevent 467 + system call fails if: 468 + .Bl -tag -width Er 469 + .It Bq Er EACCES 470 + The process does not have permission to register a filter. 471 + .It Bq Er EFAULT 472 + There was an error reading or writing the 473 + .Va kevent 474 + structure. 475 + .It Bq Er EBADF 476 + The specified descriptor is invalid. 477 + .It Bq Er EINTR 478 + A signal was delivered before the timeout expired and before any 479 + events were placed on the kqueue for return. 480 + .It Bq Er EINVAL 481 + The specified time limit or filter is invalid. 482 + .It Bq Er ENOENT 483 + The event could not be found to be modified or deleted. 484 + .It Bq Er ENOMEM 485 + No memory was available to register the event 486 + or, in the special case of a timer, the maximum number of 487 + timers has been exceeded. 488 + This maximum is configurable via the 489 + .Va kern.kq_calloutmax 490 + sysctl. 491 + .It Bq Er ESRCH 492 + The specified process to attach to does not exist. 493 + .El 494 + .Sh SEE ALSO 495 + .Xr aio_error 2 , 496 + .Xr aio_read 2 , 497 + .Xr aio_return 2 , 498 + .Xr poll 2 , 499 + .Xr read 2 , 500 + .Xr select 2 , 501 + .Xr sigaction 2 , 502 + .Xr write 2 , 503 + .Xr signal 3 504 + .Sh HISTORY 505 + The 506 + .Fn kqueue 507 + and 508 + .Fn kevent 509 + system calls first appeared in 510 + .Fx 4.1 . 511 + .Sh AUTHORS 512 + The 513 + .Fn kqueue 514 + system and this manual page were written by 515 + .An Jonathan Lemon Aq jlemon@FreeBSD.org .
+1
external/libkqueue-2.0.1/libkqueue
··· 1 + libkqueue
+8
external/libkqueue-2.0.1/libkqueue.pc.in
··· 1 + 2 + Name: libkqueue 3 + Description: Emulates FreeBSD kqueue(2) on other platforms 4 + Version: 0.1 5 + Requires: 6 + Libs: -lkqueue 7 + Libs.private: -lpthread 8 + Cflags: -I${includedir}/kqueue
+89
external/libkqueue-2.0.1/libkqueue.spec
··· 1 + Name: libkqueue 2 + Summary: Userspace implementation of the kqueue event notification mechanism 3 + Version: 2.0.1 4 + Release: 1 5 + # The entire source code is MIT, event.h which is BSD (2-clause) 6 + License: MIT and BSD 7 + Group: System Environment/Libraries 8 + URL: http://sourceforge.net/p/libkqueue/wiki/Home/ 9 + Source0: http://downloads.sourceforge.net/%{name}/%{name}-%{version}.tar.gz 10 + Provides: libkqueue.so.0 11 + 12 + %description 13 + A user space implementation of the kqueue(2) kernel event notification 14 + mechanism. libkqueue acts as a translator between the kevent structure and the 15 + native kernel facilities. 16 + 17 + %package devel 18 + Group: Development/Libraries 19 + Summary: Development files for %{name}-%{version} 20 + Requires: %{name}%{?_isa} = %{version}-%{release} 21 + 22 + %description devel 23 + %{summary} 24 + 25 + %prep 26 + %setup -q 27 + 28 + # %%{configure} sets --target 'x86_64-redhat-linux-gnu' instead of 'linux' 29 + %build 30 + CFLAGS="%{optflags} -fpic" %{_configure} --prefix=%{_prefix} --libdir=%{_libdir} 31 + make 32 + 33 + %install 34 + %{make_install} 35 + 36 + %check 37 + make check 38 + 39 + %post -p /sbin/ldconfig 40 + 41 + %postun -p /sbin/ldconfig 42 + 43 + %files 44 + %doc LICENSE 45 + %{_libdir}/libkqueue.so.* 46 + 47 + %files devel 48 + %dir %{_includedir}/kqueue 49 + %dir %{_includedir}/kqueue/sys 50 + %{_libdir}/libkqueue.so 51 + %{_includedir}/kqueue/sys/event.h 52 + %{_libdir}/pkgconfig/libkqueue.pc 53 + %{_mandir}/man2/kqueue.2.* 54 + %{_mandir}/man2/kevent.2.* 55 + 56 + %changelog 57 + * Wed May 08 2013 Mark Heily <mark@heily.com> - 2.0.1-1 58 + - New upstream release 59 + 60 + * Wed May 01 2013 Eric Radman <ericshane@eradman.com> - 2.0-1 61 + - Adapt to libkqueue 2.0 62 + 63 + * Thu Apr 04 2013 Eric Radman <ericshane@eradman.com> - 1.0.1-6 64 + - Set CFLAGS using optflags since we're using a custom configure 65 + - Shorten summary 66 + 67 + * Wed Apr 03 2013 Eric Radman <ericshane@eradman.com> - 1.0.1-5 68 + - Use %% to avoid warning about special character in comment 69 + - Remove defattr 70 + 71 + * Fri Jan 18 2013 Eric Radman <ericshane@eradman.com> - 1.0.1-4 72 + - Configure respects CFLAGS and LDFLAGS. Also pass --libdir to the configure script 73 + 74 + * Sat Jan 12 2013 Eric Radman <ericshane@eradman.com> - 1.0.1-3 75 + - Add license text for event.h 76 + - Use the dir macro for the include directories 77 + - Remove static package, exclude .a file, and make sure new directories are owned by the RPM 78 + 79 + * Thu Jan 03 2013 Eric Radman <ericshane@eradman.com> - 1.0.1-3 80 + - Configure respects CFLAGS and LDFLAGS. Also pass --libdir= to the configure script instead of setting LIB 81 + 82 + * Mon Dec 31 2012 Eric Radman <ericshane@eradman.com> - 1.0.1-2 83 + - Do not set the buildroot (F-10 does not require it) 84 + - Do not manually clean (F-13) 85 + 86 + * Thu Dec 27 2012 Eric Radman <ericshane@eradman.com> - 1.0.1-1 87 + - Initial build with separate -devel package. Based on work done by Mark Heily, 88 + Aditya Patawari and John Haxby 89 +
+84
external/libkqueue-2.0.1/src/common/alloc.h
··· 1 + /* 2 + * Copyright (c) 2011 Mark Heily <mark@heily.com> 3 + * 4 + * Permission to use, copy, modify, and distribute this software for any 5 + * purpose with or without fee is hereby granted, provided that the above 6 + * copyright notice and this permission notice appear in all copies. 7 + * 8 + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 9 + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 10 + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 11 + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 12 + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 13 + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 14 + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 15 + */ 16 + 17 + 18 + /* 19 + * A simple fixed-size memory allocator. 20 + * 21 + * Each translation unit in a program can include this header and 22 + * have access to it's own private memory allocator. This can be useful 23 + * for improving the performance of programs which frequently allocate 24 + * and deallocate objects with a fixed size. 25 + * 26 + * The allocator must be initialized by calling mem_init(). This 27 + * function takes two arguments: the object size, and the maximum 28 + * number of objects in the cache. 29 + * 30 + * The functions mem_alloc() and mem_free() have similar semantics 31 + * to the traditional malloc() and free() calls. The main difference 32 + * is that mem_alloc() does not allow you to specify a specific size. 33 + * 34 + */ 35 + 36 + #include <stdlib.h> 37 + 38 + #ifndef _WIN32 39 + # include <unistd.h> 40 + #endif 41 + 42 + static __thread struct { 43 + void **ac_cache; /* An array of reusable memory objects */ 44 + size_t ac_count; /* The number of objects in the cache */ 45 + size_t ac_max; /* The maximum number of cached objects */ 46 + size_t ac_size; /* The size, in bytes, of each object */ 47 + } _ma; 48 + 49 + static inline int 50 + mem_init(size_t objsize, size_t cachesize) 51 + { 52 + _ma.ac_size = objsize; 53 + _ma.ac_cache = malloc(cachesize * sizeof(void *)); 54 + return (_ma.ac_cache == NULL ? -1 : 0); 55 + } 56 + 57 + static inline void * 58 + mem_alloc(void) 59 + { 60 + if (_ma.ac_count > 0) 61 + return (_ma.ac_cache[_ma.ac_count--]); 62 + else 63 + return (malloc(_ma.ac_size)); 64 + } 65 + 66 + static inline void * 67 + mem_calloc(void) 68 + { 69 + void *p; 70 + 71 + p = mem_alloc(); 72 + if (p != NULL) 73 + memset(p, 0, _ma.ac_size); 74 + return (p); 75 + } 76 + 77 + static inline void 78 + mem_free(void *ptr) 79 + { 80 + if (_ma.ac_count < _ma.ac_max) 81 + _ma.ac_cache[_ma.ac_count++] = ptr; 82 + else 83 + free(ptr); 84 + }
+147
external/libkqueue-2.0.1/src/common/debug.h
··· 1 + /* 2 + * Copyright (c) 2011 Mark Heily <mark@heily.com> 3 + * 4 + * Permission to use, copy, modify, and distribute this software for any 5 + * purpose with or without fee is hereby granted, provided that the above 6 + * copyright notice and this permission notice appear in all copies. 7 + * 8 + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 9 + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 10 + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 11 + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 12 + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 13 + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 14 + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 15 + */ 16 + 17 + #ifndef _DEBUG_H 18 + #define _DEBUG_H 19 + 20 + #include <assert.h> 21 + #include <stdio.h> 22 + #ifdef _WIN32 23 + # include <windows.h> 24 + #else 25 + # include <unistd.h> 26 + #endif 27 + 28 + extern int DEBUG_KQUEUE; 29 + extern char *KQUEUE_DEBUG_IDENT; 30 + 31 + #if defined(__linux__) 32 + # include <sys/syscall.h> 33 + # define THREAD_ID ((pid_t) syscall(__NR_gettid)) 34 + #elif defined(__sun) 35 + # define THREAD_ID ((int) pthread_self()) 36 + #elif defined(_WIN32) 37 + # define THREAD_ID (int)(GetCurrentThreadId()) 38 + #else 39 + # error Unsupported platform 40 + #endif 41 + 42 + #ifndef NDEBUG 43 + #define dbg_puts(str) do { \ 44 + if (DEBUG_KQUEUE) \ 45 + fprintf(stderr, "%s [%d]: %s(): %s\n", \ 46 + KQUEUE_DEBUG_IDENT, THREAD_ID, __func__, str); \ 47 + } while (0) 48 + 49 + #define dbg_printf(fmt,...) do { \ 50 + if (DEBUG_KQUEUE) \ 51 + fprintf(stderr, "%s [%d]: %s(): "fmt"\n", \ 52 + KQUEUE_DEBUG_IDENT, THREAD_ID, __func__, __VA_ARGS__); \ 53 + } while (0) 54 + 55 + #define dbg_perror(str) do { \ 56 + if (DEBUG_KQUEUE) \ 57 + fprintf(stderr, "%s [%d]: %s(): %s: %s (errno=%d)\n", \ 58 + KQUEUE_DEBUG_IDENT, THREAD_ID, __func__, str, \ 59 + strerror(errno), errno); \ 60 + } while (0) 61 + 62 + # define reset_errno() do { errno = 0; } while (0) 63 + 64 + # if defined(_WIN32) 65 + # define dbg_lasterror(str) do { \ 66 + if (DEBUG_KQUEUE) \ 67 + fprintf(stderr, "%s: [%d] %s(): %s: (LastError=%d)\n", \ 68 + KQUEUE_DEBUG_IDENT, THREAD_ID, __func__, str, (int)GetLastError()); \ 69 + } while (0) 70 + 71 + # define dbg_wsalasterror(str) do { \ 72 + if (DEBUG_KQUEUE) \ 73 + fprintf(stderr, "%s: [%d] %s(): %s: (WSALastError=%d)\n", \ 74 + KQUEUE_DEBUG_IDENT, THREAD_ID, __func__, str, (int)WSAGetLastError()); \ 75 + } while (0) 76 + 77 + # else 78 + # define dbg_lasterror(str) ; 79 + # define dbg_wsalasterror(str) ; 80 + # endif 81 + 82 + /* 83 + * Tracing mutexes are a thin wrapper around the pthread_mutex_t 84 + * datatype that tracks and reports when a mutex is locked or unlocked. 85 + * It also allows you to assert that a mutex has (or has not) been locked 86 + * by calling tracing_mutex_assert(). 87 + */ 88 + 89 + # define MTX_UNLOCKED 0 90 + # define MTX_LOCKED 1 91 + 92 + typedef struct { 93 + pthread_mutex_t mtx_lock; 94 + int mtx_status; 95 + int mtx_owner; 96 + } tracing_mutex_t; 97 + 98 + # define tracing_mutex_init(mtx, attr) do { \ 99 + pthread_mutex_init(&(mtx)->mtx_lock, (attr)); \ 100 + (mtx)->mtx_status = MTX_UNLOCKED; \ 101 + (mtx)->mtx_owner = -1; \ 102 + } while (0) 103 + 104 + # define tracing_mutex_destroy(mtx) pthread_mutex_destroy(&(mtx)->mtx_lock) 105 + 106 + # define tracing_mutex_assert(x,y) do { \ 107 + if ((y) == MTX_UNLOCKED) \ 108 + assert((x)->mtx_status == MTX_UNLOCKED || (x)->mtx_owner != THREAD_ID); \ 109 + else if ((y) == MTX_LOCKED) \ 110 + assert((x)->mtx_status == MTX_LOCKED && (x)->mtx_owner == THREAD_ID); \ 111 + else \ 112 + abort(); \ 113 + } while (0) 114 + 115 + # define tracing_mutex_lock(x) do { \ 116 + dbg_printf("waiting for %s", #x); \ 117 + pthread_mutex_lock(&((x)->mtx_lock)); \ 118 + dbg_printf("locked %s", #x); \ 119 + (x)->mtx_owner = THREAD_ID; \ 120 + (x)->mtx_status = MTX_LOCKED; \ 121 + } while (0) 122 + 123 + # define tracing_mutex_unlock(x) do { \ 124 + (x)->mtx_status = MTX_UNLOCKED; \ 125 + (x)->mtx_owner = -1; \ 126 + pthread_mutex_unlock(&((x)->mtx_lock)); \ 127 + dbg_printf("unlocked %s", # x); \ 128 + } while (0) 129 + 130 + #else /* NDEBUG */ 131 + # define dbg_puts(str) do {} while (0) 132 + # define dbg_printf(fmt,...) do {} while (0) 133 + # define dbg_perror(str) do {} while (0) 134 + # define dbg_lasterror(str) do {} while (0) 135 + # define dbg_wsalasterror(str) do {} while (0) 136 + # define reset_errno() do {} while (0) 137 + # define MTX_UNLOCKED 138 + # define MTX_LOCKED 139 + # define tracing_mutex_t pthread_mutex_t 140 + # define tracing_mutex_init pthread_mutex_init 141 + # define tracing_mutex_destroy pthread_mutex_destroy 142 + # define tracing_mutex_assert(x,y) do {} while (0) 143 + # define tracing_mutex_lock pthread_mutex_lock 144 + # define tracing_mutex_unlock pthread_mutex_unlock 145 + #endif 146 + 147 + #endif /* ! _DEBUG_H */
+179
external/libkqueue-2.0.1/src/common/filter.c
··· 1 + /* 2 + * Copyright (c) 2009 Mark Heily <mark@heily.com> 3 + * 4 + * Permission to use, copy, modify, and distribute this software for any 5 + * purpose with or without fee is hereby granted, provided that the above 6 + * copyright notice and this permission notice appear in all copies. 7 + * 8 + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 9 + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 10 + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 11 + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 12 + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 13 + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 14 + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 15 + */ 16 + 17 + #include <assert.h> 18 + #include <errno.h> 19 + #include <fcntl.h> 20 + #include <stdlib.h> 21 + #include <stdio.h> 22 + #include <string.h> 23 + 24 + #include "private.h" 25 + 26 + extern const struct filter evfilt_read; 27 + extern const struct filter evfilt_write; 28 + extern const struct filter evfilt_signal; 29 + extern const struct filter evfilt_vnode; 30 + extern const struct filter evfilt_proc; 31 + extern const struct filter evfilt_timer; 32 + extern const struct filter evfilt_user; 33 + 34 + static int 35 + filter_register(struct kqueue *kq, short filter, const struct filter *src) 36 + { 37 + struct filter *dst; 38 + unsigned int filt; 39 + int rv = 0; 40 + 41 + filt = (-1 * filter) - 1; 42 + if (filt >= EVFILT_SYSCOUNT) 43 + return (-1); 44 + 45 + dst = &kq->kq_filt[filt]; 46 + memcpy(dst, src, sizeof(*src)); 47 + dst->kf_kqueue = kq; 48 + RB_INIT(&dst->kf_knote); 49 + pthread_rwlock_init(&dst->kf_knote_mtx, NULL); 50 + if (src->kf_id == 0) { 51 + dbg_puts("filter is not implemented"); 52 + return (0); 53 + } 54 + 55 + assert(src->kf_copyout); 56 + assert(src->kn_create); 57 + assert(src->kn_modify); 58 + assert(src->kn_delete); 59 + assert(src->kn_enable); 60 + assert(src->kn_disable); 61 + 62 + /* Perform (optional) per-filter initialization */ 63 + if (src->kf_init != NULL) { 64 + rv = src->kf_init(dst); 65 + if (rv < 0) { 66 + dbg_puts("filter failed to initialize"); 67 + dst->kf_id = 0; 68 + return (-1); 69 + } 70 + } 71 + 72 + #if DEADWOOD 73 + /* Add the filter's event descriptor to the main fdset */ 74 + if (dst->kf_pfd > 0) { 75 + FD_SET(dst->kf_pfd, &kq->kq_fds); 76 + if (dst->kf_pfd > kq->kq_nfds) 77 + kq->kq_nfds = dst->kf_pfd; 78 + dbg_printf("fds: added %d (nfds=%d)", dst->kf_pfd, kq->kq_nfds); 79 + } 80 + dbg_printf("filter %d (%s) registered", filter, filter_name(filter)); 81 + #endif 82 + 83 + /* FIXME: should totally remove const from src */ 84 + if (kqops.filter_init != NULL 85 + && kqops.filter_init(kq, dst) < 0) 86 + return (-1); 87 + 88 + return (0); 89 + } 90 + 91 + int 92 + filter_register_all(struct kqueue *kq) 93 + { 94 + int rv; 95 + 96 + FD_ZERO(&kq->kq_fds); 97 + rv = 0; 98 + rv += filter_register(kq, EVFILT_READ, &evfilt_read); 99 + rv += filter_register(kq, EVFILT_WRITE, &evfilt_write); 100 + rv += filter_register(kq, EVFILT_SIGNAL, &evfilt_signal); 101 + rv += filter_register(kq, EVFILT_VNODE, &evfilt_vnode); 102 + rv += filter_register(kq, EVFILT_PROC, &evfilt_proc); 103 + rv += filter_register(kq, EVFILT_TIMER, &evfilt_timer); 104 + rv += filter_register(kq, EVFILT_USER, &evfilt_user); 105 + kq->kq_nfds++; 106 + if (rv != 0) { 107 + filter_unregister_all(kq); 108 + return (-1); 109 + } else { 110 + dbg_puts("complete"); 111 + return (0); 112 + } 113 + } 114 + 115 + void 116 + filter_unregister_all(struct kqueue *kq) 117 + { 118 + int i; 119 + 120 + for (i = 0; i < EVFILT_SYSCOUNT; i++) { 121 + if (kq->kq_filt[i].kf_id == 0) 122 + continue; 123 + 124 + if (kq->kq_filt[i].kf_destroy != NULL) 125 + kq->kq_filt[i].kf_destroy(&kq->kq_filt[i]); 126 + 127 + //XXX-FIXME 128 + //knote_free_all(&kq->kq_filt[i]); 129 + 130 + if (kqops.filter_free != NULL) 131 + kqops.filter_free(kq, &kq->kq_filt[i]); 132 + } 133 + memset(&kq->kq_filt[0], 0, sizeof(kq->kq_filt)); 134 + } 135 + 136 + int 137 + filter_lookup(struct filter **filt, struct kqueue *kq, short id) 138 + { 139 + if (~id < 0 || ~id >= EVFILT_SYSCOUNT) { 140 + dbg_printf("invalid id: id %d ~id %d", id, (~id)); 141 + errno = EINVAL; 142 + *filt = NULL; 143 + return (-1); 144 + } 145 + *filt = &kq->kq_filt[~id]; 146 + if ((*filt)->kf_copyout == NULL) { 147 + dbg_printf("filter %s is not implemented", filter_name(id)); 148 + errno = ENOSYS; 149 + *filt = NULL; 150 + return (-1); 151 + } 152 + 153 + return (0); 154 + } 155 + 156 + const char * 157 + filter_name(short filt) 158 + { 159 + int id; 160 + const char *fname[EVFILT_SYSCOUNT] = { 161 + "EVFILT_READ", 162 + "EVFILT_WRITE", 163 + "EVFILT_AIO", 164 + "EVFILT_VNODE", 165 + "EVFILT_PROC", 166 + "EVFILT_SIGNAL", 167 + "EVFILT_TIMER", 168 + "EVFILT_NETDEV", 169 + "EVFILT_FS", 170 + "EVFILT_LIO", 171 + "EVFILT_USER" 172 + }; 173 + 174 + id = ~filt; 175 + if (id < 0 || id >= EVFILT_SYSCOUNT) 176 + return "EVFILT_INVALID"; 177 + else 178 + return fname[id]; 179 + }
+312
external/libkqueue-2.0.1/src/common/kevent.c
··· 1 + /* 2 + * Copyright (c) 2009 Mark Heily <mark@heily.com> 3 + * 4 + * Permission to use, copy, modify, and distribute this software for any 5 + * purpose with or without fee is hereby granted, provided that the above 6 + * copyright notice and this permission notice appear in all copies. 7 + * 8 + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 9 + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 10 + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 11 + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 12 + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 13 + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 14 + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 15 + */ 16 + 17 + /* To get asprintf(3) */ 18 + #define _GNU_SOURCE 19 + 20 + #include <assert.h> 21 + #include <errno.h> 22 + #include <fcntl.h> 23 + #include <signal.h> 24 + #include <stdlib.h> 25 + #include <stdio.h> 26 + #include <sys/types.h> 27 + #include <string.h> 28 + 29 + #include "private.h" 30 + 31 + static const char * 32 + kevent_filter_dump(const struct kevent *kev) 33 + { 34 + static __thread char buf[64]; 35 + 36 + snprintf(&buf[0], sizeof(buf), "%d (%s)", 37 + kev->filter, filter_name(kev->filter)); 38 + return ((const char *) &buf[0]); 39 + } 40 + 41 + static const char * 42 + kevent_fflags_dump(const struct kevent *kev) 43 + { 44 + static __thread char buf[1024]; 45 + 46 + #define KEVFFL_DUMP(attrib) \ 47 + if (kev->fflags & attrib) \ 48 + strncat((char *) &buf[0], #attrib" ", 64); 49 + 50 + snprintf(buf, sizeof(buf), "fflags=0x%04x (", kev->fflags); 51 + if (kev->filter == EVFILT_VNODE) { 52 + KEVFFL_DUMP(NOTE_DELETE); 53 + KEVFFL_DUMP(NOTE_WRITE); 54 + KEVFFL_DUMP(NOTE_EXTEND); 55 + KEVFFL_DUMP(NOTE_ATTRIB); 56 + KEVFFL_DUMP(NOTE_LINK); 57 + KEVFFL_DUMP(NOTE_RENAME); 58 + } else if (kev->filter == EVFILT_USER) { 59 + KEVFFL_DUMP(NOTE_FFNOP); 60 + KEVFFL_DUMP(NOTE_FFAND); 61 + KEVFFL_DUMP(NOTE_FFOR); 62 + KEVFFL_DUMP(NOTE_FFCOPY); 63 + KEVFFL_DUMP(NOTE_TRIGGER); 64 + } else { 65 + strncat((char *) &buf[0], " ", 1); 66 + } 67 + buf[strlen(buf) - 1] = ')'; 68 + 69 + #undef KEVFFL_DUMP 70 + 71 + return ((const char *) &buf[0]); 72 + } 73 + 74 + static const char * 75 + kevent_flags_dump(const struct kevent *kev) 76 + { 77 + static __thread char buf[1024]; 78 + 79 + #define KEVFL_DUMP(attrib) \ 80 + if (kev->flags & attrib) \ 81 + strncat((char *) &buf[0], #attrib" ", 64); 82 + 83 + snprintf(buf, sizeof(buf), "flags=0x%04x (", kev->flags); 84 + KEVFL_DUMP(EV_ADD); 85 + KEVFL_DUMP(EV_ENABLE); 86 + KEVFL_DUMP(EV_DISABLE); 87 + KEVFL_DUMP(EV_DELETE); 88 + KEVFL_DUMP(EV_ONESHOT); 89 + KEVFL_DUMP(EV_CLEAR); 90 + KEVFL_DUMP(EV_EOF); 91 + KEVFL_DUMP(EV_ERROR); 92 + KEVFL_DUMP(EV_DISPATCH); 93 + KEVFL_DUMP(EV_RECEIPT); 94 + buf[strlen(buf) - 1] = ')'; 95 + 96 + #undef KEVFL_DUMP 97 + 98 + return ((const char *) &buf[0]); 99 + } 100 + 101 + const char * 102 + kevent_dump(const struct kevent *kev) 103 + { 104 + static __thread char buf[1024]; 105 + 106 + snprintf((char *) &buf[0], sizeof(buf), 107 + "{ ident=%d, filter=%s, %s, %s, data=%d, udata=%p }", 108 + (u_int) kev->ident, 109 + kevent_filter_dump(kev), 110 + kevent_flags_dump(kev), 111 + kevent_fflags_dump(kev), 112 + (int) kev->data, 113 + kev->udata); 114 + 115 + return ((const char *) &buf[0]); 116 + } 117 + 118 + static int 119 + kevent_copyin_one(struct kqueue *kq, const struct kevent *src) 120 + { 121 + struct knote *kn = NULL; 122 + struct filter *filt; 123 + int rv = 0; 124 + 125 + if (src->flags & EV_DISPATCH && src->flags & EV_ONESHOT) { 126 + dbg_puts("Error: EV_DISPATCH and EV_ONESHOT are mutually exclusive"); 127 + errno = EINVAL; 128 + return (-1); 129 + } 130 + 131 + if (filter_lookup(&filt, kq, src->filter) < 0) 132 + return (-1); 133 + 134 + dbg_printf("src=%s", kevent_dump(src)); 135 + 136 + kn = knote_lookup(filt, src->ident); 137 + dbg_printf("knote_lookup: ident %d == %p", (int)src->ident, kn); 138 + if (kn == NULL) { 139 + if (src->flags & EV_ADD) { 140 + if ((kn = knote_new()) == NULL) { 141 + errno = ENOENT; 142 + return (-1); 143 + } 144 + memcpy(&kn->kev, src, sizeof(kn->kev)); 145 + kn->kev.flags &= ~EV_ENABLE; 146 + kn->kev.flags |= EV_ADD;//FIXME why? 147 + kn->kn_kq = kq; 148 + assert(filt->kn_create); 149 + if (filt->kn_create(filt, kn) < 0) { 150 + knote_release(kn); 151 + errno = EFAULT; 152 + return (-1); 153 + } 154 + knote_insert(filt, kn); 155 + dbg_printf("created kevent %s", kevent_dump(src)); 156 + 157 + /* XXX- FIXME Needs to be handled in kn_create() to prevent races */ 158 + if (src->flags & EV_DISABLE) { 159 + kn->kev.flags |= EV_DISABLE; 160 + return (filt->kn_disable(filt, kn)); 161 + } 162 + //........................................ 163 + 164 + return (0); 165 + } else { 166 + dbg_printf("no entry found for ident=%u", (unsigned int)src->ident); 167 + errno = ENOENT; 168 + return (-1); 169 + } 170 + } 171 + 172 + if (src->flags & EV_DELETE) { 173 + rv = knote_delete(filt, kn); 174 + dbg_printf("knote_delete returned %d", rv); 175 + } else if (src->flags & EV_DISABLE) { 176 + kn->kev.flags |= EV_DISABLE; 177 + rv = filt->kn_disable(filt, kn); 178 + dbg_printf("kn_disable returned %d", rv); 179 + } else if (src->flags & EV_ENABLE) { 180 + kn->kev.flags &= ~EV_DISABLE; 181 + rv = filt->kn_enable(filt, kn); 182 + dbg_printf("kn_enable returned %d", rv); 183 + } else if (src->flags & EV_ADD || src->flags == 0 || src->flags & EV_RECEIPT) { 184 + kn->kev.udata = src->udata; 185 + rv = filt->kn_modify(filt, kn, src); 186 + dbg_printf("kn_modify returned %d", rv); 187 + } 188 + 189 + return (rv); 190 + } 191 + 192 + /** @return number of events added to the eventlist */ 193 + static int 194 + kevent_copyin(struct kqueue *kq, const struct kevent *src, int nchanges, 195 + struct kevent *eventlist, int nevents) 196 + { 197 + int status, nret; 198 + 199 + dbg_printf("nchanges=%d nevents=%d", nchanges, nevents); 200 + 201 + /* TODO: refactor, this has become convoluted to support EV_RECEIPT */ 202 + for (nret = 0; nchanges > 0; src++, nchanges--) { 203 + 204 + if (kevent_copyin_one(kq, src) < 0) { 205 + dbg_printf("errno=%s",strerror(errno)); 206 + status = errno; 207 + goto err_path; 208 + } else { 209 + if (src->flags & EV_RECEIPT) { 210 + status = 0; 211 + goto err_path; 212 + } 213 + } 214 + 215 + continue; 216 + 217 + err_path: 218 + if (nevents > 0) { 219 + memcpy(eventlist, src, sizeof(*src)); 220 + eventlist->data = status; 221 + nevents--; 222 + eventlist++; 223 + nret++; 224 + } else { 225 + return (-1); 226 + } 227 + } 228 + 229 + return (nret); 230 + } 231 + 232 + int VISIBLE 233 + kevent(int kqfd, const struct kevent *changelist, int nchanges, 234 + struct kevent *eventlist, int nevents, 235 + const struct timespec *timeout) 236 + { 237 + struct kqueue *kq; 238 + int rv = 0; 239 + #ifndef NDEBUG 240 + static unsigned int _kevent_counter = 0; 241 + unsigned int myid = 0; 242 + 243 + (void) myid; 244 + #endif 245 + 246 + /* Convert the descriptor into an object pointer */ 247 + kq = kqueue_lookup(kqfd); 248 + if (kq == NULL) { 249 + errno = ENOENT; 250 + return (-1); 251 + } 252 + 253 + #ifndef NDEBUG 254 + if (DEBUG_KQUEUE) { 255 + myid = atomic_inc(&_kevent_counter); 256 + dbg_printf("--- kevent %u --- (nchanges = %d, nevents = %d)", myid, nchanges, nevents); 257 + } 258 + #endif 259 + 260 + /* 261 + * Process each kevent on the changelist. 262 + */ 263 + if (nchanges > 0) { 264 + kqueue_lock(kq); 265 + rv = kevent_copyin(kq, changelist, nchanges, eventlist, nevents); 266 + kqueue_unlock(kq); 267 + dbg_printf("(%u) changelist: rv=%d", myid, rv); 268 + if (rv < 0) 269 + goto out; 270 + if (rv > 0) { 271 + eventlist += rv; 272 + nevents -= rv; 273 + } 274 + } 275 + 276 + rv = 0; 277 + 278 + /* 279 + * Wait for events and copy them to the eventlist 280 + */ 281 + if (nevents > MAX_KEVENT) 282 + nevents = MAX_KEVENT; 283 + if (nevents > 0) { 284 + rv = kqops.kevent_wait(kq, nevents, timeout); 285 + dbg_printf("kqops.kevent_wait returned %d", rv); 286 + if (fastpath(rv > 0)) { 287 + kqueue_lock(kq); 288 + rv = kqops.kevent_copyout(kq, rv, eventlist, nevents); 289 + kqueue_unlock(kq); 290 + } else if (rv == 0) { 291 + /* Timeout reached */ 292 + } else { 293 + dbg_printf("(%u) kevent_wait failed", myid); 294 + goto out; 295 + } 296 + } 297 + 298 + #ifndef NDEBUG 299 + if (DEBUG_KQUEUE) { 300 + int n; 301 + 302 + dbg_printf("(%u) returning %d events", myid, rv); 303 + for (n = 0; n < rv; n++) { 304 + dbg_printf("(%u) eventlist[%d] = %s", myid, n, kevent_dump(&eventlist[n])); 305 + } 306 + } 307 + #endif 308 + 309 + out: 310 + dbg_printf("--- END kevent %u ret %d ---", myid, rv); 311 + return (rv); 312 + }
+163
external/libkqueue-2.0.1/src/common/knote.c
··· 1 + /* 2 + * Copyright (c) 2009 Mark Heily <mark@heily.com> 3 + * 4 + * Permission to use, copy, modify, and distribute this software for any 5 + * purpose with or without fee is hereby granted, provided that the above 6 + * copyright notice and this permission notice appear in all copies. 7 + * 8 + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 9 + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 10 + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 11 + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 12 + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 13 + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 14 + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 15 + */ 16 + 17 + #include <stdlib.h> 18 + #include <string.h> 19 + #include <sys/types.h> 20 + 21 + #include "private.h" 22 + 23 + #include "alloc.h" 24 + 25 + int 26 + knote_init(void) 27 + { 28 + return 0; 29 + // return (mem_init(sizeof(struct knote), 1024)); 30 + } 31 + 32 + static int 33 + knote_cmp(struct knote *a, struct knote *b) 34 + { 35 + return memcmp(&a->kev.ident, &b->kev.ident, sizeof(a->kev.ident)); 36 + } 37 + 38 + RB_GENERATE(knt, knote, kn_entries, knote_cmp) 39 + 40 + struct knote * 41 + knote_new(void) 42 + { 43 + struct knote *res; 44 + 45 + res = calloc(1, sizeof(struct knote)); 46 + if (res == NULL) 47 + return (NULL); 48 + 49 + res->kn_ref = 1; 50 + 51 + return (res); 52 + } 53 + 54 + void 55 + knote_release(struct knote *kn) 56 + { 57 + assert (kn->kn_ref > 0); 58 + 59 + if (atomic_dec(&kn->kn_ref) == 0) { 60 + if (kn->kn_flags & KNFL_KNOTE_DELETED) { 61 + dbg_printf("freeing knote at %p", kn); 62 + free(kn); 63 + } else { 64 + dbg_puts("this should never happen"); 65 + } 66 + } else { 67 + dbg_printf("decrementing refcount of knote %p rc=%d", kn, kn->kn_ref); 68 + } 69 + } 70 + 71 + void 72 + knote_insert(struct filter *filt, struct knote *kn) 73 + { 74 + pthread_rwlock_wrlock(&filt->kf_knote_mtx); 75 + RB_INSERT(knt, &filt->kf_knote, kn); 76 + pthread_rwlock_unlock(&filt->kf_knote_mtx); 77 + } 78 + 79 + int 80 + knote_delete(struct filter *filt, struct knote *kn) 81 + { 82 + struct knote query; 83 + struct knote *tmp; 84 + 85 + if (kn->kn_flags & KNFL_KNOTE_DELETED) { 86 + dbg_puts("ERROR: double deletion detected"); 87 + return (-1); 88 + } 89 + 90 + /* 91 + * Verify that the knote wasn't removed by another 92 + * thread before we acquired the knotelist lock. 93 + */ 94 + query.kev.ident = kn->kev.ident; 95 + pthread_rwlock_wrlock(&filt->kf_knote_mtx); 96 + tmp = RB_FIND(knt, &filt->kf_knote, &query); 97 + if (tmp == kn) { 98 + RB_REMOVE(knt, &filt->kf_knote, kn); 99 + } 100 + pthread_rwlock_unlock(&filt->kf_knote_mtx); 101 + 102 + filt->kn_delete(filt, kn); //XXX-FIXME check return value 103 + 104 + kn->kn_flags |= KNFL_KNOTE_DELETED; 105 + 106 + knote_release(kn); 107 + 108 + return (0); 109 + } 110 + 111 + struct knote * 112 + knote_lookup(struct filter *filt, uintptr_t ident) 113 + { 114 + struct knote query; 115 + struct knote *ent = NULL; 116 + 117 + query.kev.ident = ident; 118 + 119 + pthread_rwlock_rdlock(&filt->kf_knote_mtx); 120 + ent = RB_FIND(knt, &filt->kf_knote, &query); 121 + pthread_rwlock_unlock(&filt->kf_knote_mtx); 122 + 123 + #ifdef __x86_64__ 124 + dbg_printf("id=%lu ent=%p", ident, ent); 125 + #else 126 + dbg_printf("id=%u ent=%p", ident, ent); 127 + #endif 128 + 129 + return (ent); 130 + } 131 + 132 + #if DEADWOOD 133 + struct knote * 134 + knote_get_by_data(struct filter *filt, intptr_t data) 135 + { 136 + struct knote *kn; 137 + 138 + pthread_rwlock_rdlock(&filt->kf_knote_mtx); 139 + RB_FOREACH(kn, knt, &filt->kf_knote) { 140 + if (data == kn->kev.data) 141 + break; 142 + } 143 + if (kn != NULL) { 144 + knote_retain(kn); 145 + } 146 + pthread_rwlock_unlock(&filt->kf_knote_mtx); 147 + 148 + return (kn); 149 + } 150 + #endif 151 + 152 + int 153 + knote_disable(struct filter *filt, struct knote *kn) 154 + { 155 + assert(!(kn->kev.flags & EV_DISABLE)); 156 + 157 + filt->kn_disable(filt, kn); //TODO: Error checking 158 + KNOTE_DISABLE(kn); 159 + return (0); 160 + } 161 + 162 + //TODO: knote_enable() 163 +
+171
external/libkqueue-2.0.1/src/common/kqueue.c
··· 1 + /* 2 + * Copyright (c) 2009 Mark Heily <mark@heily.com> 3 + * 4 + * Permission to use, copy, modify, and distribute this software for any 5 + * purpose with or without fee is hereby granted, provided that the above 6 + * copyright notice and this permission notice appear in all copies. 7 + * 8 + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 9 + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 10 + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 11 + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 12 + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 13 + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 14 + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 15 + */ 16 + 17 + #include <errno.h> 18 + #include <fcntl.h> 19 + #include <signal.h> 20 + #include <stdlib.h> 21 + #include <stdio.h> 22 + #include <sys/types.h> 23 + #include <string.h> 24 + 25 + #include "private.h" 26 + 27 + int DEBUG_KQUEUE = 0; 28 + char *KQUEUE_DEBUG_IDENT = "KQ"; 29 + 30 + #ifdef _WIN32 31 + static LONG kq_init_begin = 0; 32 + static int kq_init_complete = 0; 33 + #else 34 + pthread_mutex_t kq_mtx = PTHREAD_MUTEX_INITIALIZER; 35 + pthread_once_t kq_is_initialized = PTHREAD_ONCE_INIT; 36 + #endif 37 + 38 + static unsigned int 39 + get_fd_limit(void) 40 + { 41 + #ifdef _WIN32 42 + /* actually windows should be able to hold 43 + way more, as they use HANDLEs for everything. 44 + Still this number should still be sufficient for 45 + the provided number of kqueue fds. 46 + */ 47 + return 65536; 48 + #else 49 + struct rlimit rlim; 50 + 51 + if (getrlimit(RLIMIT_NOFILE, &rlim) < 0) { 52 + dbg_perror("getrlimit(2)"); 53 + return (65536); 54 + } else { 55 + return (rlim.rlim_max); 56 + } 57 + #endif 58 + } 59 + 60 + static struct map *kqmap; 61 + 62 + void 63 + libkqueue_init(void) 64 + { 65 + #ifdef NDEBUG 66 + DEBUG_KQUEUE = 0; 67 + #else 68 + char *s = getenv("KQUEUE_DEBUG"); 69 + if (s != NULL && strlen(s) > 0) { 70 + DEBUG_KQUEUE = 1; 71 + 72 + #ifdef _WIN32 73 + /* Initialize the Winsock library */ 74 + WSADATA wsaData; 75 + if (WSAStartup(MAKEWORD(2,2), &wsaData) != 0) 76 + abort(); 77 + #endif 78 + 79 + # if defined(_WIN32) && !defined(__GNUC__) 80 + /* Enable heap surveillance */ 81 + { 82 + int tmpFlag = _CrtSetDbgFlag( _CRTDBG_REPORT_FLAG ); 83 + tmpFlag |= _CRTDBG_CHECK_ALWAYS_DF; 84 + _CrtSetDbgFlag(tmpFlag); 85 + } 86 + # endif /* _WIN32 */ 87 + } 88 + #endif 89 + 90 + kqmap = map_new(get_fd_limit()); // INT_MAX 91 + if (kqmap == NULL) 92 + abort(); 93 + if (knote_init() < 0) 94 + abort(); 95 + dbg_puts("library initialization complete"); 96 + #ifdef _WIN32 97 + kq_init_complete = 1; 98 + #endif 99 + } 100 + 101 + #if DEADWOOD 102 + static int 103 + kqueue_cmp(struct kqueue *a, struct kqueue *b) 104 + { 105 + return memcmp(&a->kq_id, &b->kq_id, sizeof(int)); 106 + } 107 + 108 + /* Must hold the kqtree_mtx when calling this */ 109 + void 110 + kqueue_free(struct kqueue *kq) 111 + { 112 + RB_REMOVE(kqt, &kqtree, kq); 113 + filter_unregister_all(kq); 114 + kqops.kqueue_free(kq); 115 + free(kq); 116 + } 117 + 118 + #endif 119 + 120 + struct kqueue * 121 + kqueue_lookup(int kq) 122 + { 123 + return ((struct kqueue *) map_lookup(kqmap, kq)); 124 + } 125 + 126 + int VISIBLE 127 + kqueue(void) 128 + { 129 + struct kqueue *kq; 130 + struct kqueue *tmp; 131 + 132 + #ifdef _WIN32 133 + if (InterlockedCompareExchange(&kq_init_begin, 0, 1) == 0) { 134 + libkqueue_init(); 135 + } else { 136 + while (kq_init_complete == 0) { 137 + sleep(1); 138 + } 139 + } 140 + #else 141 + (void) pthread_mutex_lock(&kq_mtx); 142 + (void) pthread_once(&kq_is_initialized, libkqueue_init); 143 + (void) pthread_mutex_unlock(&kq_mtx); 144 + #endif 145 + 146 + kq = calloc(1, sizeof(*kq)); 147 + if (kq == NULL) 148 + return (-1); 149 + 150 + tracing_mutex_init(&kq->kq_mtx, NULL); 151 + 152 + if (kqops.kqueue_init(kq) < 0) { 153 + free(kq); 154 + return (-1); 155 + } 156 + 157 + dbg_printf("created kqueue, fd=%d", kq->kq_id); 158 + 159 + tmp = map_delete(kqmap, kq->kq_id); 160 + if (tmp != NULL) { 161 + dbg_puts("FIXME -- memory leak here"); 162 + // TODO: kqops.kqueue_free(tmp), or (better yet) decrease it's refcount 163 + } 164 + if (map_insert(kqmap, kq->kq_id, kq) < 0) { 165 + dbg_puts("map insertion failed"); 166 + kqops.kqueue_free(kq); 167 + return (-1); 168 + } 169 + 170 + return (kq->kq_id); 171 + }
+133
external/libkqueue-2.0.1/src/common/map.c
··· 1 + /* 2 + * Copyright (c) 2011 Mark Heily <mark@heily.com> 3 + * 4 + * Permission to use, copy, modify, and distribute this software for any 5 + * purpose with or without fee is hereby granted, provided that the above 6 + * copyright notice and this permission notice appear in all copies. 7 + * 8 + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 9 + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 10 + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 11 + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 12 + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 13 + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 14 + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 15 + */ 16 + 17 + #include "private.h" 18 + 19 + struct map { 20 + size_t len; 21 + void **data; 22 + }; 23 + 24 + struct map * 25 + map_new(size_t len) 26 + { 27 + struct map *dst; 28 + 29 + dst = calloc(1, sizeof(struct map)); 30 + if (dst == NULL) 31 + return (NULL); 32 + #ifdef _WIN32 33 + dst->data = calloc(len, sizeof(void*)); 34 + if(dst->data == NULL) { 35 + dbg_perror("calloc()"); 36 + free(dst); 37 + return NULL; 38 + } 39 + dst->len = len; 40 + #else 41 + dst->data = mmap(NULL, len * sizeof(void *), PROT_READ | PROT_WRITE, 42 + MAP_PRIVATE | MAP_NORESERVE | MAP_ANON, -1, 0); 43 + if (dst->data == MAP_FAILED) { 44 + dbg_perror("mmap(2)"); 45 + free(dst); 46 + return (NULL); 47 + } 48 + dst->len = len; 49 + #endif 50 + 51 + return (dst); 52 + } 53 + 54 + int 55 + map_insert(struct map *m, int idx, void *ptr) 56 + { 57 + if (slowpath(idx < 0 || idx > (int)m->len)) 58 + return (-1); 59 + 60 + if (atomic_ptr_cas(&(m->data[idx]), 0, ptr) == NULL) { 61 + dbg_printf("inserted %p in location %d", ptr, idx); 62 + return (0); 63 + } else { 64 + dbg_printf("tried to insert a value into a non-empty location %d (value=%p)", 65 + idx, 66 + m->data[idx]); 67 + return (-1); 68 + } 69 + } 70 + 71 + int 72 + map_remove(struct map *m, int idx, void *ptr) 73 + { 74 + if (slowpath(idx < 0 || idx > (int)m->len)) 75 + return (-1); 76 + 77 + if (atomic_ptr_cas(&(m->data[idx]), ptr, 0) == NULL) { 78 + dbg_printf("removed %p from location %d", ptr, idx); 79 + return (0); 80 + } else { 81 + dbg_printf("removal failed: location %d does not contain value %p", idx, m->data[idx]); 82 + return (-1); 83 + } 84 + } 85 + 86 + int 87 + map_replace(struct map *m, int idx, void *oldp, void *newp) 88 + { 89 + void *tmp; 90 + 91 + if (slowpath(idx < 0 || idx > (int)m->len)) 92 + return (-1); 93 + 94 + tmp = atomic_ptr_cas(&(m->data[idx]), oldp, newp); 95 + if (tmp == oldp) { 96 + dbg_printf("replaced value %p in location %d with value %p", 97 + oldp, idx, newp); 98 + return (0); 99 + } else { 100 + dbg_printf("item in location %d does not match expected value %p", 101 + idx, oldp); 102 + return (-1); 103 + } 104 + } 105 + 106 + void * 107 + map_lookup(struct map *m, int idx) 108 + { 109 + if (slowpath(idx < 0 || idx > (int)m->len)) 110 + return (NULL); 111 + 112 + return m->data[idx]; 113 + } 114 + 115 + void * 116 + map_delete(struct map *m, int idx) 117 + { 118 + void *oval; 119 + void *nval; 120 + 121 + if (slowpath(idx < 0 || idx > (int)m->len)) 122 + return ((void *)-1); 123 + 124 + /* Hopefully we aren't racing with another thread, but you never know.. */ 125 + do { 126 + oval = m->data[idx]; 127 + nval = atomic_ptr_cas(&(m->data[idx]), oval, NULL); 128 + } while (nval != oval); 129 + 130 + m->data[idx] = NULL; 131 + 132 + return ((void *) oval); 133 + }
+230
external/libkqueue-2.0.1/src/common/private.h
··· 1 + /* 2 + * Copyright (c) 2009 Mark Heily <mark@heily.com> 3 + * 4 + * Permission to use, copy, modify, and distribute this software for any 5 + * purpose with or without fee is hereby granted, provided that the above 6 + * copyright notice and this permission notice appear in all copies. 7 + * 8 + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 9 + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 10 + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 11 + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 12 + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 13 + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 14 + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 15 + */ 16 + 17 + #ifndef _KQUEUE_PRIVATE_H 18 + #define _KQUEUE_PRIVATE_H 19 + 20 + #include <errno.h> 21 + #include <stdio.h> 22 + #include <string.h> 23 + #include "config.h" 24 + #include "tree.h" 25 + 26 + /* Maximum events returnable in a single kevent() call */ 27 + #define MAX_KEVENT 512 28 + 29 + struct kqueue; 30 + struct kevent; 31 + struct knote; 32 + struct map; 33 + struct eventfd; 34 + struct evfilt_data; 35 + 36 + #if defined(_WIN32) 37 + # include "../windows/platform.h" 38 + # include "../common/queue.h" 39 + # if !defined(NDEBUG) && !defined(__GNUC__) 40 + # include <crtdbg.h> 41 + # endif 42 + #elif defined(__linux__) 43 + # include "../posix/platform.h" 44 + # include "../linux/platform.h" 45 + #elif defined(__sun) 46 + # include "../posix/platform.h" 47 + # include "../solaris/platform.h" 48 + #else 49 + # error Unknown platform 50 + #endif 51 + 52 + #include "debug.h" 53 + 54 + /* Workaround for Android */ 55 + #ifndef EPOLLONESHOT 56 + # define EPOLLONESHOT (1 << 30) 57 + #endif 58 + 59 + struct eventfd { 60 + int ef_id; 61 + #if defined(EVENTFD_PLATFORM_SPECIFIC) 62 + EVENTFD_PLATFORM_SPECIFIC; 63 + #endif 64 + }; 65 + 66 + /* 67 + * Flags used by knote->kn_flags 68 + */ 69 + #define KNFL_PASSIVE_SOCKET (0x01) /* Socket is in listen(2) mode */ 70 + #define KNFL_REGULAR_FILE (0x02) /* File descriptor is a regular file */ 71 + #define KNFL_KNOTE_DELETED (0x10) /* The knote object is no longer valid */ 72 + 73 + struct knote { 74 + struct kevent kev; 75 + int kn_flags; 76 + union { 77 + /* OLD */ 78 + int pfd; /* Used by timerfd */ 79 + int events; /* Used by socket */ 80 + struct { 81 + nlink_t nlink; /* Used by vnode */ 82 + off_t size; /* Used by vnode */ 83 + } vnode; 84 + timer_t timerid; 85 + struct sleepreq *sleepreq; /* Used by posix/timer.c */ 86 + void *handle; /* Used by win32 filters */ 87 + } data; 88 + struct kqueue* kn_kq; 89 + volatile uint32_t kn_ref; 90 + #if defined(KNOTE_PLATFORM_SPECIFIC) 91 + KNOTE_PLATFORM_SPECIFIC; 92 + #endif 93 + RB_ENTRY(knote) kn_entries; 94 + }; 95 + 96 + #define KNOTE_ENABLE(ent) do { \ 97 + (ent)->kev.flags &= ~EV_DISABLE; \ 98 + } while (0/*CONSTCOND*/) 99 + 100 + #define KNOTE_DISABLE(ent) do { \ 101 + (ent)->kev.flags |= EV_DISABLE; \ 102 + } while (0/*CONSTCOND*/) 103 + 104 + struct filter { 105 + short kf_id; 106 + 107 + /* filter operations */ 108 + 109 + int (*kf_init)(struct filter *); 110 + void (*kf_destroy)(struct filter *); 111 + int (*kf_copyout)(struct kevent *, struct knote *, void *); 112 + 113 + /* knote operations */ 114 + 115 + int (*kn_create)(struct filter *, struct knote *); 116 + int (*kn_modify)(struct filter *, struct knote *, 117 + const struct kevent *); 118 + int (*kn_delete)(struct filter *, struct knote *); 119 + int (*kn_enable)(struct filter *, struct knote *); 120 + int (*kn_disable)(struct filter *, struct knote *); 121 + 122 + struct eventfd kf_efd; /* Used by user.c */ 123 + 124 + //MOVE TO POSIX? 125 + int kf_pfd; /* fd to poll(2) for readiness */ 126 + int kf_wfd; /* fd to write when an event occurs */ 127 + //----? 128 + 129 + struct evfilt_data *kf_data; /* filter-specific data */ 130 + RB_HEAD(knt, knote) kf_knote; 131 + pthread_rwlock_t kf_knote_mtx; 132 + struct kqueue *kf_kqueue; 133 + #if defined(FILTER_PLATFORM_SPECIFIC) 134 + FILTER_PLATFORM_SPECIFIC; 135 + #endif 136 + }; 137 + 138 + /* Use this to declare a filter that is not implemented */ 139 + #define EVFILT_NOTIMPL { 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL } 140 + 141 + struct kqueue { 142 + int kq_id; 143 + struct filter kq_filt[EVFILT_SYSCOUNT]; 144 + fd_set kq_fds, kq_rfds; 145 + int kq_nfds; 146 + tracing_mutex_t kq_mtx; 147 + volatile uint32_t kq_ref; 148 + #if defined(KQUEUE_PLATFORM_SPECIFIC) 149 + KQUEUE_PLATFORM_SPECIFIC; 150 + #endif 151 + RB_ENTRY(kqueue) entries; 152 + }; 153 + 154 + struct kqueue_vtable { 155 + int (*kqueue_init)(struct kqueue *); 156 + void (*kqueue_free)(struct kqueue *); 157 + // @param timespec can be given as timeout 158 + // @param int the number of events to wait for 159 + // @param kqueue the queue to wait on 160 + int (*kevent_wait)(struct kqueue *, int, const struct timespec *); 161 + // @param kqueue the queue to look at 162 + // @param int The number of events that should be ready 163 + // @param kevent the structure to copy the events into 164 + // @param int The number of events to copy 165 + // @return the actual number of events copied 166 + int (*kevent_copyout)(struct kqueue *, int, struct kevent *, int); 167 + int (*filter_init)(struct kqueue *, struct filter *); 168 + void (*filter_free)(struct kqueue *, struct filter *); 169 + int (*eventfd_init)(struct eventfd *); 170 + void (*eventfd_close)(struct eventfd *); 171 + int (*eventfd_raise)(struct eventfd *); 172 + int (*eventfd_lower)(struct eventfd *); 173 + int (*eventfd_descriptor)(struct eventfd *); 174 + }; 175 + extern const struct kqueue_vtable kqops; 176 + 177 + /* 178 + * kqueue internal API 179 + */ 180 + #define kqueue_lock(kq) tracing_mutex_lock(&(kq)->kq_mtx) 181 + #define kqueue_unlock(kq) tracing_mutex_unlock(&(kq)->kq_mtx) 182 + 183 + /* 184 + * knote internal API 185 + */ 186 + struct knote * knote_lookup(struct filter *, uintptr_t); 187 + //DEADWOOD: struct knote * knote_get_by_data(struct filter *filt, intptr_t); 188 + struct knote * knote_new(void); 189 + #define knote_retain(kn) atomic_inc(&kn->kn_ref) 190 + void knote_release(struct knote *); 191 + void knote_insert(struct filter *, struct knote *); 192 + int knote_delete(struct filter *, struct knote *); 193 + int knote_init(void); 194 + int knote_disable(struct filter *, struct knote *); 195 + #define knote_get_filter(knt) &((knt)->kn_kq->kq_filt[(knt)->kev.filter]) 196 + 197 + int filter_lookup(struct filter **, struct kqueue *, short); 198 + int filter_register_all(struct kqueue *); 199 + void filter_unregister_all(struct kqueue *); 200 + const char *filter_name(short); 201 + 202 + int kevent_wait(struct kqueue *, const struct timespec *); 203 + int kevent_copyout(struct kqueue *, int, struct kevent *, int); 204 + void kevent_free(struct kqueue *); 205 + const char *kevent_dump(const struct kevent *); 206 + struct kqueue * kqueue_lookup(int); 207 + int kqueue_validate(struct kqueue *); 208 + 209 + struct map *map_new(size_t); 210 + int map_insert(struct map *, int, void *); 211 + int map_remove(struct map *, int, void *); 212 + int map_replace(struct map *, int, void *, void *); 213 + void *map_lookup(struct map *, int); 214 + void *map_delete(struct map *, int); 215 + void map_free(struct map *); 216 + 217 + /* DEADWOOD: No longer needed due to the un-smerging of POSIX and Linux 218 + 219 + int posix_evfilt_user_init(struct filter *); 220 + void posix_evfilt_user_destroy(struct filter *); 221 + int posix_evfilt_user_copyout(struct kevent *, struct knote *, void *ptr UNUSED); 222 + int posix_evfilt_user_knote_create(struct filter *, struct knote *); 223 + int posix_evfilt_user_knote_modify(struct filter *, struct knote *, const struct kevent *); 224 + int posix_evfilt_user_knote_delete(struct filter *, struct knote *); 225 + int posix_evfilt_user_knote_enable(struct filter *, struct knote *); 226 + int posix_evfilt_user_knote_disable(struct filter *, struct knote *); 227 + 228 + */ 229 + 230 + #endif /* ! _KQUEUE_PRIVATE_H */
+763
external/libkqueue-2.0.1/src/common/tree.h
··· 1 + /* $NetBSD: tree.h,v 1.8 2004/03/28 19:38:30 provos Exp $ */ 2 + /* $OpenBSD: tree.h,v 1.7 2002/10/17 21:51:54 art Exp $ */ 3 + /* $FreeBSD: src/sys/sys/tree.h,v 1.9.2.1.2.1 2009/10/25 01:10:29 kensmith Exp $ */ 4 + 5 + /*- 6 + * Copyright 2002 Niels Provos <provos@citi.umich.edu> 7 + * All rights reserved. 8 + * 9 + * Redistribution and use in source and binary forms, with or without 10 + * modification, are permitted provided that the following conditions 11 + * are met: 12 + * 1. Redistributions of source code must retain the above copyright 13 + * notice, this list of conditions and the following disclaimer. 14 + * 2. Redistributions in binary form must reproduce the above copyright 15 + * notice, this list of conditions and the following disclaimer in the 16 + * documentation and/or other materials provided with the distribution. 17 + * 18 + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 19 + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 20 + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 21 + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 22 + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 23 + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 24 + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 25 + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 26 + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 27 + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 28 + */ 29 + 30 + #ifndef _SYS_TREE_H_ 31 + #define _SYS_TREE_H_ 32 + 33 + /* 34 + * This file defines data structures for different types of trees: 35 + * splay trees and red-black trees. 36 + * 37 + * A splay tree is a self-organizing data structure. Every operation 38 + * on the tree causes a splay to happen. The splay moves the requested 39 + * node to the root of the tree and partly rebalances it. 40 + * 41 + * This has the benefit that request locality causes faster lookups as 42 + * the requested nodes move to the top of the tree. On the other hand, 43 + * every lookup causes memory writes. 44 + * 45 + * The Balance Theorem bounds the total access time for m operations 46 + * and n inserts on an initially empty tree as O((m + n)lg n). The 47 + * amortized cost for a sequence of m accesses to a splay tree is O(lg n); 48 + * 49 + * A red-black tree is a binary search tree with the node color as an 50 + * extra attribute. It fulfills a set of conditions: 51 + * - every search path from the root to a leaf consists of the 52 + * same number of black nodes, 53 + * - each red node (except for the root) has a black parent, 54 + * - each leaf node is black. 55 + * 56 + * Every operation on a red-black tree is bounded as O(lg n). 57 + * The maximum height of a red-black tree is 2lg (n+1). 58 + */ 59 + 60 + #define SPLAY_HEAD(name, type) \ 61 + struct name { \ 62 + struct type *sph_root; /* root of the tree */ \ 63 + } 64 + 65 + #define SPLAY_INITIALIZER(root) \ 66 + { NULL } 67 + 68 + #define SPLAY_INIT(root) do { \ 69 + (root)->sph_root = NULL; \ 70 + } while (/*CONSTCOND*/ 0) 71 + 72 + #define SPLAY_ENTRY(type) \ 73 + struct { \ 74 + struct type *spe_left; /* left element */ \ 75 + struct type *spe_right; /* right element */ \ 76 + } 77 + 78 + #define SPLAY_LEFT(elm, field) (elm)->field.spe_left 79 + #define SPLAY_RIGHT(elm, field) (elm)->field.spe_right 80 + #define SPLAY_ROOT(head) (head)->sph_root 81 + #define SPLAY_EMPTY(head) (SPLAY_ROOT(head) == NULL) 82 + 83 + /* SPLAY_ROTATE_{LEFT,RIGHT} expect that tmp hold SPLAY_{RIGHT,LEFT} */ 84 + #define SPLAY_ROTATE_RIGHT(head, tmp, field) do { \ 85 + SPLAY_LEFT((head)->sph_root, field) = SPLAY_RIGHT(tmp, field); \ 86 + SPLAY_RIGHT(tmp, field) = (head)->sph_root; \ 87 + (head)->sph_root = tmp; \ 88 + } while (/*CONSTCOND*/ 0) 89 + 90 + #define SPLAY_ROTATE_LEFT(head, tmp, field) do { \ 91 + SPLAY_RIGHT((head)->sph_root, field) = SPLAY_LEFT(tmp, field); \ 92 + SPLAY_LEFT(tmp, field) = (head)->sph_root; \ 93 + (head)->sph_root = tmp; \ 94 + } while (/*CONSTCOND*/ 0) 95 + 96 + #define SPLAY_LINKLEFT(head, tmp, field) do { \ 97 + SPLAY_LEFT(tmp, field) = (head)->sph_root; \ 98 + tmp = (head)->sph_root; \ 99 + (head)->sph_root = SPLAY_LEFT((head)->sph_root, field); \ 100 + } while (/*CONSTCOND*/ 0) 101 + 102 + #define SPLAY_LINKRIGHT(head, tmp, field) do { \ 103 + SPLAY_RIGHT(tmp, field) = (head)->sph_root; \ 104 + tmp = (head)->sph_root; \ 105 + (head)->sph_root = SPLAY_RIGHT((head)->sph_root, field); \ 106 + } while (/*CONSTCOND*/ 0) 107 + 108 + #define SPLAY_ASSEMBLE(head, node, left, right, field) do { \ 109 + SPLAY_RIGHT(left, field) = SPLAY_LEFT((head)->sph_root, field); \ 110 + SPLAY_LEFT(right, field) = SPLAY_RIGHT((head)->sph_root, field);\ 111 + SPLAY_LEFT((head)->sph_root, field) = SPLAY_RIGHT(node, field); \ 112 + SPLAY_RIGHT((head)->sph_root, field) = SPLAY_LEFT(node, field); \ 113 + } while (/*CONSTCOND*/ 0) 114 + 115 + /* Generates prototypes and inline functions */ 116 + 117 + #define SPLAY_PROTOTYPE(name, type, field, cmp) \ 118 + void name##_SPLAY(struct name *, struct type *); \ 119 + void name##_SPLAY_MINMAX(struct name *, int); \ 120 + struct type *name##_SPLAY_INSERT(struct name *, struct type *); \ 121 + struct type *name##_SPLAY_REMOVE(struct name *, struct type *); \ 122 + \ 123 + /* Finds the node with the same key as elm */ \ 124 + static __inline struct type * \ 125 + name##_SPLAY_FIND(struct name *head, struct type *elm) \ 126 + { \ 127 + if (SPLAY_EMPTY(head)) \ 128 + return(NULL); \ 129 + name##_SPLAY(head, elm); \ 130 + if ((cmp)(elm, (head)->sph_root) == 0) \ 131 + return (head->sph_root); \ 132 + return (NULL); \ 133 + } \ 134 + \ 135 + static __inline struct type * \ 136 + name##_SPLAY_NEXT(struct name *head, struct type *elm) \ 137 + { \ 138 + name##_SPLAY(head, elm); \ 139 + if (SPLAY_RIGHT(elm, field) != NULL) { \ 140 + elm = SPLAY_RIGHT(elm, field); \ 141 + while (SPLAY_LEFT(elm, field) != NULL) { \ 142 + elm = SPLAY_LEFT(elm, field); \ 143 + } \ 144 + } else \ 145 + elm = NULL; \ 146 + return (elm); \ 147 + } \ 148 + \ 149 + static __inline struct type * \ 150 + name##_SPLAY_MIN_MAX(struct name *head, int val) \ 151 + { \ 152 + name##_SPLAY_MINMAX(head, val); \ 153 + return (SPLAY_ROOT(head)); \ 154 + } 155 + 156 + /* Main splay operation. 157 + * Moves node close to the key of elm to top 158 + */ 159 + #define SPLAY_GENERATE(name, type, field, cmp) \ 160 + struct type * \ 161 + name##_SPLAY_INSERT(struct name *head, struct type *elm) \ 162 + { \ 163 + if (SPLAY_EMPTY(head)) { \ 164 + SPLAY_LEFT(elm, field) = SPLAY_RIGHT(elm, field) = NULL; \ 165 + } else { \ 166 + int __comp; \ 167 + name##_SPLAY(head, elm); \ 168 + __comp = (cmp)(elm, (head)->sph_root); \ 169 + if(__comp < 0) { \ 170 + SPLAY_LEFT(elm, field) = SPLAY_LEFT((head)->sph_root, field);\ 171 + SPLAY_RIGHT(elm, field) = (head)->sph_root; \ 172 + SPLAY_LEFT((head)->sph_root, field) = NULL; \ 173 + } else if (__comp > 0) { \ 174 + SPLAY_RIGHT(elm, field) = SPLAY_RIGHT((head)->sph_root, field);\ 175 + SPLAY_LEFT(elm, field) = (head)->sph_root; \ 176 + SPLAY_RIGHT((head)->sph_root, field) = NULL; \ 177 + } else \ 178 + return ((head)->sph_root); \ 179 + } \ 180 + (head)->sph_root = (elm); \ 181 + return (NULL); \ 182 + } \ 183 + \ 184 + struct type * \ 185 + name##_SPLAY_REMOVE(struct name *head, struct type *elm) \ 186 + { \ 187 + struct type *__tmp; \ 188 + if (SPLAY_EMPTY(head)) \ 189 + return (NULL); \ 190 + name##_SPLAY(head, elm); \ 191 + if ((cmp)(elm, (head)->sph_root) == 0) { \ 192 + if (SPLAY_LEFT((head)->sph_root, field) == NULL) { \ 193 + (head)->sph_root = SPLAY_RIGHT((head)->sph_root, field);\ 194 + } else { \ 195 + __tmp = SPLAY_RIGHT((head)->sph_root, field); \ 196 + (head)->sph_root = SPLAY_LEFT((head)->sph_root, field);\ 197 + name##_SPLAY(head, elm); \ 198 + SPLAY_RIGHT((head)->sph_root, field) = __tmp; \ 199 + } \ 200 + return (elm); \ 201 + } \ 202 + return (NULL); \ 203 + } \ 204 + \ 205 + void \ 206 + name##_SPLAY(struct name *head, struct type *elm) \ 207 + { \ 208 + struct type __node, *__left, *__right, *__tmp; \ 209 + int __comp; \ 210 + \ 211 + SPLAY_LEFT(&__node, field) = SPLAY_RIGHT(&__node, field) = NULL;\ 212 + __left = __right = &__node; \ 213 + \ 214 + while ((__comp = (cmp)(elm, (head)->sph_root)) != 0) { \ 215 + if (__comp < 0) { \ 216 + __tmp = SPLAY_LEFT((head)->sph_root, field); \ 217 + if (__tmp == NULL) \ 218 + break; \ 219 + if ((cmp)(elm, __tmp) < 0){ \ 220 + SPLAY_ROTATE_RIGHT(head, __tmp, field); \ 221 + if (SPLAY_LEFT((head)->sph_root, field) == NULL)\ 222 + break; \ 223 + } \ 224 + SPLAY_LINKLEFT(head, __right, field); \ 225 + } else if (__comp > 0) { \ 226 + __tmp = SPLAY_RIGHT((head)->sph_root, field); \ 227 + if (__tmp == NULL) \ 228 + break; \ 229 + if ((cmp)(elm, __tmp) > 0){ \ 230 + SPLAY_ROTATE_LEFT(head, __tmp, field); \ 231 + if (SPLAY_RIGHT((head)->sph_root, field) == NULL)\ 232 + break; \ 233 + } \ 234 + SPLAY_LINKRIGHT(head, __left, field); \ 235 + } \ 236 + } \ 237 + SPLAY_ASSEMBLE(head, &__node, __left, __right, field); \ 238 + } \ 239 + \ 240 + /* Splay with either the minimum or the maximum element \ 241 + * Used to find minimum or maximum element in tree. \ 242 + */ \ 243 + void name##_SPLAY_MINMAX(struct name *head, int __comp) \ 244 + { \ 245 + struct type __node, *__left, *__right, *__tmp; \ 246 + \ 247 + SPLAY_LEFT(&__node, field) = SPLAY_RIGHT(&__node, field) = NULL;\ 248 + __left = __right = &__node; \ 249 + \ 250 + while (1) { \ 251 + if (__comp < 0) { \ 252 + __tmp = SPLAY_LEFT((head)->sph_root, field); \ 253 + if (__tmp == NULL) \ 254 + break; \ 255 + if (__comp < 0){ \ 256 + SPLAY_ROTATE_RIGHT(head, __tmp, field); \ 257 + if (SPLAY_LEFT((head)->sph_root, field) == NULL)\ 258 + break; \ 259 + } \ 260 + SPLAY_LINKLEFT(head, __right, field); \ 261 + } else if (__comp > 0) { \ 262 + __tmp = SPLAY_RIGHT((head)->sph_root, field); \ 263 + if (__tmp == NULL) \ 264 + break; \ 265 + if (__comp > 0) { \ 266 + SPLAY_ROTATE_LEFT(head, __tmp, field); \ 267 + if (SPLAY_RIGHT((head)->sph_root, field) == NULL)\ 268 + break; \ 269 + } \ 270 + SPLAY_LINKRIGHT(head, __left, field); \ 271 + } \ 272 + } \ 273 + SPLAY_ASSEMBLE(head, &__node, __left, __right, field); \ 274 + } 275 + 276 + #define SPLAY_NEGINF -1 277 + #define SPLAY_INF 1 278 + 279 + #define SPLAY_INSERT(name, x, y) name##_SPLAY_INSERT(x, y) 280 + #define SPLAY_REMOVE(name, x, y) name##_SPLAY_REMOVE(x, y) 281 + #define SPLAY_FIND(name, x, y) name##_SPLAY_FIND(x, y) 282 + #define SPLAY_NEXT(name, x, y) name##_SPLAY_NEXT(x, y) 283 + #define SPLAY_MIN(name, x) (SPLAY_EMPTY(x) ? NULL \ 284 + : name##_SPLAY_MIN_MAX(x, SPLAY_NEGINF)) 285 + #define SPLAY_MAX(name, x) (SPLAY_EMPTY(x) ? NULL \ 286 + : name##_SPLAY_MIN_MAX(x, SPLAY_INF)) 287 + 288 + #define SPLAY_FOREACH(x, name, head) \ 289 + for ((x) = SPLAY_MIN(name, head); \ 290 + (x) != NULL; \ 291 + (x) = SPLAY_NEXT(name, head, x)) 292 + 293 + /* Macros that define a red-black tree */ 294 + #define RB_HEAD(name, type) \ 295 + struct name { \ 296 + struct type *rbh_root; /* root of the tree */ \ 297 + } 298 + 299 + #define RB_INITIALIZER(root) \ 300 + { NULL } 301 + 302 + #define RB_INIT(root) do { \ 303 + (root)->rbh_root = NULL; \ 304 + } while (/*CONSTCOND*/ 0) 305 + 306 + #define RB_BLACK 0 307 + #define RB_RED 1 308 + #define RB_ENTRY(type) \ 309 + struct { \ 310 + struct type *rbe_left; /* left element */ \ 311 + struct type *rbe_right; /* right element */ \ 312 + struct type *rbe_parent; /* parent element */ \ 313 + int rbe_color; /* node color */ \ 314 + } 315 + 316 + #define RB_LEFT(elm, field) (elm)->field.rbe_left 317 + #define RB_RIGHT(elm, field) (elm)->field.rbe_right 318 + #define RB_PARENT(elm, field) (elm)->field.rbe_parent 319 + #define RB_COLOR(elm, field) (elm)->field.rbe_color 320 + #define RB_ROOT(head) (head)->rbh_root 321 + #define RB_EMPTY(head) (RB_ROOT(head) == NULL) 322 + 323 + #define RB_SET(elm, parent, field) do { \ 324 + RB_PARENT(elm, field) = parent; \ 325 + RB_LEFT(elm, field) = RB_RIGHT(elm, field) = NULL; \ 326 + RB_COLOR(elm, field) = RB_RED; \ 327 + } while (/*CONSTCOND*/ 0) 328 + 329 + #define RB_SET_BLACKRED(black, red, field) do { \ 330 + RB_COLOR(black, field) = RB_BLACK; \ 331 + RB_COLOR(red, field) = RB_RED; \ 332 + } while (/*CONSTCOND*/ 0) 333 + 334 + #ifndef RB_AUGMENT 335 + #define RB_AUGMENT(x) do {} while (0) 336 + #endif 337 + 338 + #define RB_ROTATE_LEFT(head, elm, tmp, field) do { \ 339 + (tmp) = RB_RIGHT(elm, field); \ 340 + if ((RB_RIGHT(elm, field) = RB_LEFT(tmp, field)) != NULL) { \ 341 + RB_PARENT(RB_LEFT(tmp, field), field) = (elm); \ 342 + } \ 343 + RB_AUGMENT(elm); \ 344 + if ((RB_PARENT(tmp, field) = RB_PARENT(elm, field)) != NULL) { \ 345 + if ((elm) == RB_LEFT(RB_PARENT(elm, field), field)) \ 346 + RB_LEFT(RB_PARENT(elm, field), field) = (tmp); \ 347 + else \ 348 + RB_RIGHT(RB_PARENT(elm, field), field) = (tmp); \ 349 + } else \ 350 + (head)->rbh_root = (tmp); \ 351 + RB_LEFT(tmp, field) = (elm); \ 352 + RB_PARENT(elm, field) = (tmp); \ 353 + RB_AUGMENT(tmp); \ 354 + if ((RB_PARENT(tmp, field))) \ 355 + RB_AUGMENT(RB_PARENT(tmp, field)); \ 356 + } while (/*CONSTCOND*/ 0) 357 + 358 + #define RB_ROTATE_RIGHT(head, elm, tmp, field) do { \ 359 + (tmp) = RB_LEFT(elm, field); \ 360 + if ((RB_LEFT(elm, field) = RB_RIGHT(tmp, field)) != NULL) { \ 361 + RB_PARENT(RB_RIGHT(tmp, field), field) = (elm); \ 362 + } \ 363 + RB_AUGMENT(elm); \ 364 + if ((RB_PARENT(tmp, field) = RB_PARENT(elm, field)) != NULL) { \ 365 + if ((elm) == RB_LEFT(RB_PARENT(elm, field), field)) \ 366 + RB_LEFT(RB_PARENT(elm, field), field) = (tmp); \ 367 + else \ 368 + RB_RIGHT(RB_PARENT(elm, field), field) = (tmp); \ 369 + } else \ 370 + (head)->rbh_root = (tmp); \ 371 + RB_RIGHT(tmp, field) = (elm); \ 372 + RB_PARENT(elm, field) = (tmp); \ 373 + RB_AUGMENT(tmp); \ 374 + if ((RB_PARENT(tmp, field))) \ 375 + RB_AUGMENT(RB_PARENT(tmp, field)); \ 376 + } while (/*CONSTCOND*/ 0) 377 + 378 + /* Generates prototypes and inline functions */ 379 + #define RB_PROTOTYPE(name, type, field, cmp) \ 380 + RB_PROTOTYPE_INTERNAL(name, type, field, cmp,) 381 + #define RB_PROTOTYPE_STATIC(name, type, field, cmp) \ 382 + RB_PROTOTYPE_INTERNAL(name, type, field, cmp, __unused static) 383 + #define RB_PROTOTYPE_INTERNAL(name, type, field, cmp, attr) \ 384 + attr void name##_RB_INSERT_COLOR(struct name *, struct type *); \ 385 + attr void name##_RB_REMOVE_COLOR(struct name *, struct type *, struct type *);\ 386 + attr struct type *name##_RB_REMOVE(struct name *, struct type *); \ 387 + attr struct type *name##_RB_INSERT(struct name *, struct type *); \ 388 + attr struct type *name##_RB_FIND(struct name *, struct type *); \ 389 + attr struct type *name##_RB_NFIND(struct name *, struct type *); \ 390 + attr struct type *name##_RB_NEXT(struct type *); \ 391 + attr struct type *name##_RB_PREV(struct type *); \ 392 + attr struct type *name##_RB_MINMAX(struct name *, int); \ 393 + \ 394 + 395 + /* Main rb operation. 396 + * Moves node close to the key of elm to top 397 + */ 398 + #define RB_GENERATE(name, type, field, cmp) \ 399 + RB_GENERATE_INTERNAL(name, type, field, cmp,) 400 + #define RB_GENERATE_STATIC(name, type, field, cmp) \ 401 + RB_GENERATE_INTERNAL(name, type, field, cmp, __unused static) 402 + #define RB_GENERATE_INTERNAL(name, type, field, cmp, attr) \ 403 + attr void \ 404 + name##_RB_INSERT_COLOR(struct name *head, struct type *elm) \ 405 + { \ 406 + struct type *parent, *gparent, *tmp; \ 407 + while ((parent = RB_PARENT(elm, field)) != NULL && \ 408 + RB_COLOR(parent, field) == RB_RED) { \ 409 + gparent = RB_PARENT(parent, field); \ 410 + if (parent == RB_LEFT(gparent, field)) { \ 411 + tmp = RB_RIGHT(gparent, field); \ 412 + if (tmp && RB_COLOR(tmp, field) == RB_RED) { \ 413 + RB_COLOR(tmp, field) = RB_BLACK; \ 414 + RB_SET_BLACKRED(parent, gparent, field);\ 415 + elm = gparent; \ 416 + continue; \ 417 + } \ 418 + if (RB_RIGHT(parent, field) == elm) { \ 419 + RB_ROTATE_LEFT(head, parent, tmp, field);\ 420 + tmp = parent; \ 421 + parent = elm; \ 422 + elm = tmp; \ 423 + } \ 424 + RB_SET_BLACKRED(parent, gparent, field); \ 425 + RB_ROTATE_RIGHT(head, gparent, tmp, field); \ 426 + } else { \ 427 + tmp = RB_LEFT(gparent, field); \ 428 + if (tmp && RB_COLOR(tmp, field) == RB_RED) { \ 429 + RB_COLOR(tmp, field) = RB_BLACK; \ 430 + RB_SET_BLACKRED(parent, gparent, field);\ 431 + elm = gparent; \ 432 + continue; \ 433 + } \ 434 + if (RB_LEFT(parent, field) == elm) { \ 435 + RB_ROTATE_RIGHT(head, parent, tmp, field);\ 436 + tmp = parent; \ 437 + parent = elm; \ 438 + elm = tmp; \ 439 + } \ 440 + RB_SET_BLACKRED(parent, gparent, field); \ 441 + RB_ROTATE_LEFT(head, gparent, tmp, field); \ 442 + } \ 443 + } \ 444 + RB_COLOR(head->rbh_root, field) = RB_BLACK; \ 445 + } \ 446 + \ 447 + attr void \ 448 + name##_RB_REMOVE_COLOR(struct name *head, struct type *parent, struct type *elm) \ 449 + { \ 450 + struct type *tmp; \ 451 + while ((elm == NULL || RB_COLOR(elm, field) == RB_BLACK) && \ 452 + elm != RB_ROOT(head)) { \ 453 + if (RB_LEFT(parent, field) == elm) { \ 454 + tmp = RB_RIGHT(parent, field); \ 455 + if (RB_COLOR(tmp, field) == RB_RED) { \ 456 + RB_SET_BLACKRED(tmp, parent, field); \ 457 + RB_ROTATE_LEFT(head, parent, tmp, field);\ 458 + tmp = RB_RIGHT(parent, field); \ 459 + } \ 460 + if ((RB_LEFT(tmp, field) == NULL || \ 461 + RB_COLOR(RB_LEFT(tmp, field), field) == RB_BLACK) &&\ 462 + (RB_RIGHT(tmp, field) == NULL || \ 463 + RB_COLOR(RB_RIGHT(tmp, field), field) == RB_BLACK)) {\ 464 + RB_COLOR(tmp, field) = RB_RED; \ 465 + elm = parent; \ 466 + parent = RB_PARENT(elm, field); \ 467 + } else { \ 468 + if (RB_RIGHT(tmp, field) == NULL || \ 469 + RB_COLOR(RB_RIGHT(tmp, field), field) == RB_BLACK) {\ 470 + struct type *oleft; \ 471 + if ((oleft = RB_LEFT(tmp, field)) \ 472 + != NULL) \ 473 + RB_COLOR(oleft, field) = RB_BLACK;\ 474 + RB_COLOR(tmp, field) = RB_RED; \ 475 + RB_ROTATE_RIGHT(head, tmp, oleft, field);\ 476 + tmp = RB_RIGHT(parent, field); \ 477 + } \ 478 + RB_COLOR(tmp, field) = RB_COLOR(parent, field);\ 479 + RB_COLOR(parent, field) = RB_BLACK; \ 480 + if (RB_RIGHT(tmp, field)) \ 481 + RB_COLOR(RB_RIGHT(tmp, field), field) = RB_BLACK;\ 482 + RB_ROTATE_LEFT(head, parent, tmp, field);\ 483 + elm = RB_ROOT(head); \ 484 + break; \ 485 + } \ 486 + } else { \ 487 + tmp = RB_LEFT(parent, field); \ 488 + if (RB_COLOR(tmp, field) == RB_RED) { \ 489 + RB_SET_BLACKRED(tmp, parent, field); \ 490 + RB_ROTATE_RIGHT(head, parent, tmp, field);\ 491 + tmp = RB_LEFT(parent, field); \ 492 + } \ 493 + if ((RB_LEFT(tmp, field) == NULL || \ 494 + RB_COLOR(RB_LEFT(tmp, field), field) == RB_BLACK) &&\ 495 + (RB_RIGHT(tmp, field) == NULL || \ 496 + RB_COLOR(RB_RIGHT(tmp, field), field) == RB_BLACK)) {\ 497 + RB_COLOR(tmp, field) = RB_RED; \ 498 + elm = parent; \ 499 + parent = RB_PARENT(elm, field); \ 500 + } else { \ 501 + if (RB_LEFT(tmp, field) == NULL || \ 502 + RB_COLOR(RB_LEFT(tmp, field), field) == RB_BLACK) {\ 503 + struct type *oright; \ 504 + if ((oright = RB_RIGHT(tmp, field)) \ 505 + != NULL) \ 506 + RB_COLOR(oright, field) = RB_BLACK;\ 507 + RB_COLOR(tmp, field) = RB_RED; \ 508 + RB_ROTATE_LEFT(head, tmp, oright, field);\ 509 + tmp = RB_LEFT(parent, field); \ 510 + } \ 511 + RB_COLOR(tmp, field) = RB_COLOR(parent, field);\ 512 + RB_COLOR(parent, field) = RB_BLACK; \ 513 + if (RB_LEFT(tmp, field)) \ 514 + RB_COLOR(RB_LEFT(tmp, field), field) = RB_BLACK;\ 515 + RB_ROTATE_RIGHT(head, parent, tmp, field);\ 516 + elm = RB_ROOT(head); \ 517 + break; \ 518 + } \ 519 + } \ 520 + } \ 521 + if (elm) \ 522 + RB_COLOR(elm, field) = RB_BLACK; \ 523 + } \ 524 + \ 525 + attr struct type * \ 526 + name##_RB_REMOVE(struct name *head, struct type *elm) \ 527 + { \ 528 + struct type *child, *parent, *old = elm; \ 529 + int color; \ 530 + if (RB_LEFT(elm, field) == NULL) \ 531 + child = RB_RIGHT(elm, field); \ 532 + else if (RB_RIGHT(elm, field) == NULL) \ 533 + child = RB_LEFT(elm, field); \ 534 + else { \ 535 + struct type *left; \ 536 + elm = RB_RIGHT(elm, field); \ 537 + while ((left = RB_LEFT(elm, field)) != NULL) \ 538 + elm = left; \ 539 + child = RB_RIGHT(elm, field); \ 540 + parent = RB_PARENT(elm, field); \ 541 + color = RB_COLOR(elm, field); \ 542 + if (child) \ 543 + RB_PARENT(child, field) = parent; \ 544 + if (parent) { \ 545 + if (RB_LEFT(parent, field) == elm) \ 546 + RB_LEFT(parent, field) = child; \ 547 + else \ 548 + RB_RIGHT(parent, field) = child; \ 549 + RB_AUGMENT(parent); \ 550 + } else \ 551 + RB_ROOT(head) = child; \ 552 + if (RB_PARENT(elm, field) == old) \ 553 + parent = elm; \ 554 + (elm)->field = (old)->field; \ 555 + if (RB_PARENT(old, field)) { \ 556 + if (RB_LEFT(RB_PARENT(old, field), field) == old)\ 557 + RB_LEFT(RB_PARENT(old, field), field) = elm;\ 558 + else \ 559 + RB_RIGHT(RB_PARENT(old, field), field) = elm;\ 560 + RB_AUGMENT(RB_PARENT(old, field)); \ 561 + } else \ 562 + RB_ROOT(head) = elm; \ 563 + RB_PARENT(RB_LEFT(old, field), field) = elm; \ 564 + if (RB_RIGHT(old, field)) \ 565 + RB_PARENT(RB_RIGHT(old, field), field) = elm; \ 566 + if (parent) { \ 567 + left = parent; \ 568 + do { \ 569 + RB_AUGMENT(left); \ 570 + } while ((left = RB_PARENT(left, field)) != NULL); \ 571 + } \ 572 + goto color; \ 573 + } \ 574 + parent = RB_PARENT(elm, field); \ 575 + color = RB_COLOR(elm, field); \ 576 + if (child) \ 577 + RB_PARENT(child, field) = parent; \ 578 + if (parent) { \ 579 + if (RB_LEFT(parent, field) == elm) \ 580 + RB_LEFT(parent, field) = child; \ 581 + else \ 582 + RB_RIGHT(parent, field) = child; \ 583 + RB_AUGMENT(parent); \ 584 + } else \ 585 + RB_ROOT(head) = child; \ 586 + color: \ 587 + if (color == RB_BLACK) \ 588 + name##_RB_REMOVE_COLOR(head, parent, child); \ 589 + return (old); \ 590 + } \ 591 + \ 592 + /* Inserts a node into the RB tree */ \ 593 + attr struct type * \ 594 + name##_RB_INSERT(struct name *head, struct type *elm) \ 595 + { \ 596 + struct type *tmp; \ 597 + struct type *parent = NULL; \ 598 + int comp = 0; \ 599 + tmp = RB_ROOT(head); \ 600 + while (tmp) { \ 601 + parent = tmp; \ 602 + comp = (cmp)(elm, parent); \ 603 + if (comp < 0) \ 604 + tmp = RB_LEFT(tmp, field); \ 605 + else if (comp > 0) \ 606 + tmp = RB_RIGHT(tmp, field); \ 607 + else \ 608 + return (tmp); \ 609 + } \ 610 + RB_SET(elm, parent, field); \ 611 + if (parent != NULL) { \ 612 + if (comp < 0) \ 613 + RB_LEFT(parent, field) = elm; \ 614 + else \ 615 + RB_RIGHT(parent, field) = elm; \ 616 + RB_AUGMENT(parent); \ 617 + } else \ 618 + RB_ROOT(head) = elm; \ 619 + name##_RB_INSERT_COLOR(head, elm); \ 620 + return (NULL); \ 621 + } \ 622 + \ 623 + /* Finds the node with the same key as elm */ \ 624 + attr struct type * \ 625 + name##_RB_FIND(struct name *head, struct type *elm) \ 626 + { \ 627 + struct type *tmp = RB_ROOT(head); \ 628 + int comp; \ 629 + while (tmp) { \ 630 + comp = cmp(elm, tmp); \ 631 + if (comp < 0) \ 632 + tmp = RB_LEFT(tmp, field); \ 633 + else if (comp > 0) \ 634 + tmp = RB_RIGHT(tmp, field); \ 635 + else \ 636 + return (tmp); \ 637 + } \ 638 + return (NULL); \ 639 + } \ 640 + \ 641 + /* Finds the first node greater than or equal to the search key */ \ 642 + attr struct type * \ 643 + name##_RB_NFIND(struct name *head, struct type *elm) \ 644 + { \ 645 + struct type *tmp = RB_ROOT(head); \ 646 + struct type *res = NULL; \ 647 + int comp; \ 648 + while (tmp) { \ 649 + comp = cmp(elm, tmp); \ 650 + if (comp < 0) { \ 651 + res = tmp; \ 652 + tmp = RB_LEFT(tmp, field); \ 653 + } \ 654 + else if (comp > 0) \ 655 + tmp = RB_RIGHT(tmp, field); \ 656 + else \ 657 + return (tmp); \ 658 + } \ 659 + return (res); \ 660 + } \ 661 + \ 662 + /* ARGSUSED */ \ 663 + attr struct type * \ 664 + name##_RB_NEXT(struct type *elm) \ 665 + { \ 666 + if (RB_RIGHT(elm, field)) { \ 667 + elm = RB_RIGHT(elm, field); \ 668 + while (RB_LEFT(elm, field)) \ 669 + elm = RB_LEFT(elm, field); \ 670 + } else { \ 671 + if (RB_PARENT(elm, field) && \ 672 + (elm == RB_LEFT(RB_PARENT(elm, field), field))) \ 673 + elm = RB_PARENT(elm, field); \ 674 + else { \ 675 + while (RB_PARENT(elm, field) && \ 676 + (elm == RB_RIGHT(RB_PARENT(elm, field), field)))\ 677 + elm = RB_PARENT(elm, field); \ 678 + elm = RB_PARENT(elm, field); \ 679 + } \ 680 + } \ 681 + return (elm); \ 682 + } \ 683 + \ 684 + /* ARGSUSED */ \ 685 + attr struct type * \ 686 + name##_RB_PREV(struct type *elm) \ 687 + { \ 688 + if (RB_LEFT(elm, field)) { \ 689 + elm = RB_LEFT(elm, field); \ 690 + while (RB_RIGHT(elm, field)) \ 691 + elm = RB_RIGHT(elm, field); \ 692 + } else { \ 693 + if (RB_PARENT(elm, field) && \ 694 + (elm == RB_RIGHT(RB_PARENT(elm, field), field))) \ 695 + elm = RB_PARENT(elm, field); \ 696 + else { \ 697 + while (RB_PARENT(elm, field) && \ 698 + (elm == RB_LEFT(RB_PARENT(elm, field), field)))\ 699 + elm = RB_PARENT(elm, field); \ 700 + elm = RB_PARENT(elm, field); \ 701 + } \ 702 + } \ 703 + return (elm); \ 704 + } \ 705 + \ 706 + attr struct type * \ 707 + name##_RB_MINMAX(struct name *head, int val) \ 708 + { \ 709 + struct type *tmp = RB_ROOT(head); \ 710 + struct type *parent = NULL; \ 711 + while (tmp) { \ 712 + parent = tmp; \ 713 + if (val < 0) \ 714 + tmp = RB_LEFT(tmp, field); \ 715 + else \ 716 + tmp = RB_RIGHT(tmp, field); \ 717 + } \ 718 + return (parent); \ 719 + } 720 + 721 + #define RB_NEGINF -1 722 + #define RB_INF 1 723 + 724 + #define RB_INSERT(name, x, y) name##_RB_INSERT(x, y) 725 + #define RB_REMOVE(name, x, y) name##_RB_REMOVE(x, y) 726 + #define RB_FIND(name, x, y) name##_RB_FIND(x, y) 727 + #define RB_NFIND(name, x, y) name##_RB_NFIND(x, y) 728 + #define RB_NEXT(name, x, y) name##_RB_NEXT(y) 729 + #define RB_PREV(name, x, y) name##_RB_PREV(y) 730 + #define RB_MIN(name, x) name##_RB_MINMAX(x, RB_NEGINF) 731 + #define RB_MAX(name, x) name##_RB_MINMAX(x, RB_INF) 732 + 733 + #define RB_FOREACH(x, name, head) \ 734 + for ((x) = RB_MIN(name, head); \ 735 + (x) != NULL; \ 736 + (x) = name##_RB_NEXT(x)) 737 + 738 + #define RB_FOREACH_FROM(x, name, y) \ 739 + for ((x) = (y); \ 740 + ((x) != NULL) && ((y) = name##_RB_NEXT(x), (x) != NULL); \ 741 + (x) = (y)) 742 + 743 + #define RB_FOREACH_SAFE(x, name, head, y) \ 744 + for ((x) = RB_MIN(name, head); \ 745 + ((x) != NULL) && ((y) = name##_RB_NEXT(x), (x) != NULL); \ 746 + (x) = (y)) 747 + 748 + #define RB_FOREACH_REVERSE(x, name, head) \ 749 + for ((x) = RB_MAX(name, head); \ 750 + (x) != NULL; \ 751 + (x) = name##_RB_PREV(x)) 752 + 753 + #define RB_FOREACH_REVERSE_FROM(x, name, y) \ 754 + for ((x) = (y); \ 755 + ((x) != NULL) && ((y) = name##_RB_PREV(x), (x) != NULL); \ 756 + (x) = (y)) 757 + 758 + #define RB_FOREACH_REVERSE_SAFE(x, name, head, y) \ 759 + for ((x) = RB_MAX(name, head); \ 760 + ((x) != NULL) && ((y) = name##_RB_PREV(x), (x) != NULL); \ 761 + (x) = (y)) 762 + 763 + #endif /* _SYS_TREE_H_ */
+396
external/libkqueue-2.0.1/src/linux/platform.c
··· 1 + /* 2 + * Copyright (c) 2011 Mark Heily <mark@heily.com> 3 + * 4 + * Permission to use, copy, modify, and distribute this software for any 5 + * purpose with or without fee is hereby granted, provided that the above 6 + * copyright notice and this permission notice appear in all copies. 7 + * 8 + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 9 + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 10 + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 11 + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 12 + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 13 + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 14 + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 15 + */ 16 + 17 + # define _GNU_SOURCE 18 + # include <poll.h> 19 + #include "../common/private.h" 20 + 21 + //XXX-FIXME TEMP 22 + const struct filter evfilt_proc = EVFILT_NOTIMPL; 23 + 24 + /* 25 + * Per-thread epoll event buffer used to ferry data between 26 + * kevent_wait() and kevent_copyout(). 27 + */ 28 + static __thread struct epoll_event epevt[MAX_KEVENT]; 29 + 30 + const struct kqueue_vtable kqops = { 31 + linux_kqueue_init, 32 + linux_kqueue_free, 33 + linux_kevent_wait, 34 + linux_kevent_copyout, 35 + NULL, 36 + NULL, 37 + linux_eventfd_init, 38 + linux_eventfd_close, 39 + linux_eventfd_raise, 40 + linux_eventfd_lower, 41 + linux_eventfd_descriptor 42 + }; 43 + 44 + int 45 + linux_kqueue_init(struct kqueue *kq) 46 + { 47 + kq->kq_id = epoll_create(1); 48 + if (kq->kq_id < 0) { 49 + dbg_perror("epoll_create(2)"); 50 + return (-1); 51 + } 52 + 53 + if (filter_register_all(kq) < 0) { 54 + close(kq->kq_id); 55 + return (-1); 56 + } 57 + 58 + 59 + #if DEADWOOD 60 + //might be useful in posix 61 + 62 + /* Add each filter's pollable descriptor to the epollset */ 63 + for (i = 0; i < EVFILT_SYSCOUNT; i++) { 64 + filt = &kq->kq_filt[i]; 65 + 66 + if (filt->kf_id == 0) 67 + continue; 68 + 69 + memset(&ev, 0, sizeof(ev)); 70 + ev.events = EPOLLIN; 71 + ev.data.ptr = filt; 72 + 73 + if (epoll_ctl(kq->kq_id, EPOLL_CTL_ADD, filt->kf_pfd, &ev) < 0) { 74 + dbg_perror("epoll_ctl(2)"); 75 + close(kq->kq_id); 76 + return (-1); 77 + } 78 + } 79 + #endif 80 + 81 + return (0); 82 + } 83 + 84 + void 85 + linux_kqueue_free(struct kqueue *kq UNUSED) 86 + { 87 + abort();//FIXME 88 + } 89 + 90 + static int 91 + linux_kevent_wait_hires( 92 + struct kqueue *kq, 93 + const struct timespec *timeout) 94 + { 95 + int n; 96 + #if HAVE_DECL_PPOLL 97 + struct pollfd fds; 98 + 99 + dbg_printf("waiting for events (timeout=%ld sec %ld nsec)", 100 + timeout->tv_sec, timeout->tv_nsec); 101 + fds.fd = kqueue_epfd(kq); 102 + fds.events = POLLIN; 103 + 104 + n = ppoll(&fds, 1, timeout, NULL); 105 + #else 106 + int epfd; 107 + fd_set fds; 108 + 109 + dbg_printf("waiting for events (timeout=%ld sec %ld nsec)", 110 + timeout->tv_sec, timeout->tv_nsec); 111 + 112 + epfd = kqueue_epfd(kq); 113 + FD_ZERO(&fds); 114 + FD_SET(epfd, &fds); 115 + n = pselect(epfd + 1, &fds, NULL , NULL, timeout, NULL); 116 + #endif 117 + 118 + if (n < 0) { 119 + if (errno == EINTR) { 120 + dbg_puts("signal caught"); 121 + return (-1); 122 + } 123 + dbg_perror("ppoll(2) or pselect(2)"); 124 + return (-1); 125 + } 126 + return (n); 127 + } 128 + 129 + int 130 + linux_kevent_wait( 131 + struct kqueue *kq, 132 + int nevents, 133 + const struct timespec *ts) 134 + { 135 + int timeout, nret; 136 + 137 + /* Use a high-resolution syscall if the timeout value is less than one millisecond. */ 138 + if (ts != NULL && ts->tv_sec == 0 && ts->tv_nsec > 0 && ts->tv_nsec < 1000000) { 139 + nret = linux_kevent_wait_hires(kq, ts); 140 + if (nret <= 0) 141 + return (nret); 142 + 143 + /* epoll_wait() should have ready events */ 144 + timeout = 0; 145 + } else { 146 + /* Convert timeout to the format used by epoll_wait() */ 147 + if (ts == NULL) 148 + timeout = -1; 149 + else 150 + timeout = (1000 * ts->tv_sec) + (ts->tv_nsec / 1000000); 151 + } 152 + 153 + dbg_puts("waiting for events"); 154 + nret = epoll_wait(kqueue_epfd(kq), &epevt[0], nevents, timeout); 155 + if (nret < 0) { 156 + dbg_perror("epoll_wait"); 157 + return (-1); 158 + } 159 + 160 + return (nret); 161 + } 162 + 163 + int 164 + linux_kevent_copyout(struct kqueue *kq, int nready, 165 + struct kevent *eventlist, int nevents UNUSED) 166 + { 167 + struct epoll_event *ev; 168 + struct filter *filt; 169 + struct knote *kn; 170 + int i, nret, rv; 171 + 172 + nret = nready; 173 + for (i = 0; i < nready; i++) { 174 + ev = &epevt[i]; 175 + kn = (struct knote *) ev->data.ptr; 176 + filt = &kq->kq_filt[~(kn->kev.filter)]; 177 + rv = filt->kf_copyout(eventlist, kn, ev); 178 + if (slowpath(rv < 0)) { 179 + dbg_puts("knote_copyout failed"); 180 + /* XXX-FIXME: hard to handle this without losing events */ 181 + abort(); 182 + } 183 + 184 + /* 185 + * Certain flags cause the associated knote to be deleted 186 + * or disabled. 187 + */ 188 + if (eventlist->flags & EV_DISPATCH) 189 + knote_disable(filt, kn); //FIXME: Error checking 190 + if (eventlist->flags & EV_ONESHOT) { 191 + knote_delete(filt, kn); //FIXME: Error checking 192 + } 193 + 194 + /* If an empty kevent structure is returned, the event is discarded. */ 195 + /* TODO: add these semantics to windows + solaris platform.c */ 196 + if (fastpath(eventlist->filter != 0)) { 197 + eventlist++; 198 + } else { 199 + dbg_puts("spurious wakeup, discarding event"); 200 + nret--; 201 + } 202 + } 203 + 204 + return (nret); 205 + } 206 + 207 + int 208 + linux_eventfd_init(struct eventfd *e) 209 + { 210 + int evfd; 211 + 212 + evfd = eventfd(0, 0); 213 + if (evfd < 0) { 214 + dbg_perror("eventfd"); 215 + return (-1); 216 + } 217 + if (fcntl(evfd, F_SETFL, O_NONBLOCK) < 0) { 218 + dbg_perror("fcntl"); 219 + close(evfd); 220 + return (-1); 221 + } 222 + e->ef_id = evfd; 223 + 224 + return (0); 225 + } 226 + 227 + void 228 + linux_eventfd_close(struct eventfd *e) 229 + { 230 + close(e->ef_id); 231 + e->ef_id = -1; 232 + } 233 + 234 + int 235 + linux_eventfd_raise(struct eventfd *e) 236 + { 237 + uint64_t counter; 238 + int rv = 0; 239 + 240 + dbg_puts("raising event level"); 241 + counter = 1; 242 + if (write(e->ef_id, &counter, sizeof(counter)) < 0) { 243 + switch (errno) { 244 + case EAGAIN: 245 + /* Not considered an error */ 246 + break; 247 + 248 + case EINTR: 249 + rv = -EINTR; 250 + break; 251 + 252 + default: 253 + dbg_printf("write(2): %s", strerror(errno)); 254 + rv = -1; 255 + } 256 + } 257 + return (rv); 258 + } 259 + 260 + int 261 + linux_eventfd_lower(struct eventfd *e) 262 + { 263 + uint64_t cur; 264 + ssize_t n; 265 + int rv = 0; 266 + 267 + /* Reset the counter */ 268 + dbg_puts("lowering event level"); 269 + n = read(e->ef_id, &cur, sizeof(cur)); 270 + if (n < 0) { 271 + switch (errno) { 272 + case EAGAIN: 273 + /* Not considered an error */ 274 + break; 275 + 276 + case EINTR: 277 + rv = -EINTR; 278 + break; 279 + 280 + default: 281 + dbg_printf("read(2): %s", strerror(errno)); 282 + rv = -1; 283 + } 284 + } else if (n != sizeof(cur)) { 285 + dbg_puts("short read"); 286 + rv = -1; 287 + } 288 + 289 + return (rv); 290 + } 291 + 292 + int 293 + linux_eventfd_descriptor(struct eventfd *e) 294 + { 295 + return (e->ef_id); 296 + } 297 + 298 + int 299 + linux_get_descriptor_type(struct knote *kn) 300 + { 301 + socklen_t slen; 302 + struct stat sb; 303 + int i, lsock; 304 + 305 + /* 306 + * Test if the descriptor is a socket. 307 + */ 308 + if (fstat(kn->kev.ident, &sb) < 0) { 309 + dbg_perror("fstat(2)"); 310 + return (-1); 311 + } 312 + if (S_ISREG(sb.st_mode)) { 313 + kn->kn_flags |= KNFL_REGULAR_FILE; 314 + dbg_printf("fd %d is a regular file\n", (int)kn->kev.ident); 315 + return (0); 316 + } 317 + 318 + /* 319 + * Test if the socket is active or passive. 320 + */ 321 + if (! S_ISSOCK(sb.st_mode)) 322 + return (0); 323 + 324 + slen = sizeof(lsock); 325 + lsock = 0; 326 + i = getsockopt(kn->kev.ident, SOL_SOCKET, SO_ACCEPTCONN, (char *) &lsock, &slen); 327 + if (i < 0) { 328 + switch (errno) { 329 + case ENOTSOCK: /* same as lsock = 0 */ 330 + return (0); 331 + break; 332 + default: 333 + dbg_perror("getsockopt(3)"); 334 + return (-1); 335 + } 336 + } else { 337 + if (lsock) 338 + kn->kn_flags |= KNFL_PASSIVE_SOCKET; 339 + return (0); 340 + } 341 + } 342 + 343 + char * 344 + epoll_event_dump(struct epoll_event *evt) 345 + { 346 + static __thread char buf[128]; 347 + 348 + if (evt == NULL) 349 + return "(null)"; 350 + 351 + #define EPEVT_DUMP(attrib) \ 352 + if (evt->events & attrib) \ 353 + strcat(&buf[0], #attrib" "); 354 + 355 + snprintf(&buf[0], 128, " { data = %p, events = ", evt->data.ptr); 356 + EPEVT_DUMP(EPOLLIN); 357 + EPEVT_DUMP(EPOLLOUT); 358 + #if defined(HAVE_EPOLLRDHUP) 359 + EPEVT_DUMP(EPOLLRDHUP); 360 + #endif 361 + EPEVT_DUMP(EPOLLONESHOT); 362 + EPEVT_DUMP(EPOLLET); 363 + strcat(&buf[0], "}\n"); 364 + 365 + return (&buf[0]); 366 + #undef EPEVT_DUMP 367 + } 368 + 369 + int 370 + epoll_update(int op, struct filter *filt, struct knote *kn, struct epoll_event *ev) 371 + { 372 + dbg_printf("op=%d fd=%d events=%s", op, (int)kn->kev.ident, 373 + epoll_event_dump(ev)); 374 + if (epoll_ctl(filter_epfd(filt), op, kn->kev.ident, ev) < 0) { 375 + dbg_printf("epoll_ctl(2): %s", strerror(errno)); 376 + return (-1); 377 + } 378 + 379 + return (0); 380 + } 381 + 382 + /* 383 + * Given a file descriptor, return the path to the file it refers to. 384 + */ 385 + int 386 + linux_fd_to_path(char *buf, size_t bufsz, int fd) 387 + { 388 + char path[1024]; //TODO: Maxpathlen, etc. 389 + 390 + if (snprintf(&path[0], sizeof(path), "/proc/%d/fd/%d", getpid(), fd) < 0) 391 + return (-1); 392 + 393 + memset(buf, 0, bufsz); 394 + return (readlink(path, buf, bufsz)); 395 + } 396 +
+104
external/libkqueue-2.0.1/src/linux/platform.h
··· 1 + /* 2 + * Copyright (c) 2011 Mark Heily <mark@heily.com> 3 + * 4 + * Permission to use, copy, modify, and distribute this software for any 5 + * purpose with or without fee is hereby granted, provided that the above 6 + * copyright notice and this permission notice appear in all copies. 7 + * 8 + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 9 + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 10 + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 11 + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 12 + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 13 + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 14 + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 15 + */ 16 + 17 + #ifndef _KQUEUE_LINUX_PLATFORM_H 18 + #define _KQUEUE_LINUX_PLATFORM_H 19 + 20 + struct filter; 21 + 22 + #include <sys/syscall.h> 23 + #include <sys/epoll.h> 24 + #include <sys/queue.h> 25 + #include <sys/inotify.h> 26 + #if HAVE_SYS_EVENTFD_H 27 + # include <sys/eventfd.h> 28 + #else 29 + # define eventfd(a,b) syscall(SYS_eventfd, (a), (b)) 30 + 31 + static inline int eventfd_write(int fd, uint64_t val) { 32 + if (write(fd, &val, sizeof(val)) < (ssize_t) sizeof(val)) 33 + return (-1); 34 + else 35 + return (0); 36 + } 37 + #endif 38 + #if HAVE_SYS_TIMERFD_H 39 + # include <sys/timerfd.h> 40 + #endif 41 + 42 + /* 43 + * Get the current thread ID 44 + */ 45 + # define _GNU_SOURCE 46 + # include <linux/unistd.h> 47 + # include <unistd.h> 48 + #ifndef __ANDROID__ 49 + extern long int syscall (long int __sysno, ...); 50 + #endif 51 + 52 + /* Convenience macros to access the epoll descriptor for the kqueue */ 53 + #define kqueue_epfd(kq) ((kq)->kq_id) 54 + #define filter_epfd(filt) ((filt)->kf_kqueue->kq_id) 55 + 56 + /* 57 + * Additional members of struct filter 58 + */ 59 + #undef FILTER_PLATFORM_SPECIFIC 60 + 61 + /* 62 + * Additional members of struct knote 63 + */ 64 + #define KNOTE_PLATFORM_SPECIFIC \ 65 + int kn_epollfd; /* A copy of filter->epfd */ \ 66 + union { \ 67 + int kn_timerfd; \ 68 + int kn_signalfd; \ 69 + int kn_inotifyfd; \ 70 + int kn_eventfd; \ 71 + } kdata 72 + 73 + /* 74 + * Additional members of struct kqueue 75 + */ 76 + #define KQUEUE_PLATFORM_SPECIFIC \ 77 + struct epoll_event kq_plist[MAX_KEVENT]; \ 78 + size_t kq_nplist 79 + 80 + int linux_kqueue_init(struct kqueue *); 81 + void linux_kqueue_free(struct kqueue *); 82 + 83 + int linux_kevent_wait(struct kqueue *, int, const struct timespec *); 84 + int linux_kevent_copyout(struct kqueue *, int, struct kevent *, int); 85 + 86 + int linux_knote_copyout(struct kevent *, struct knote *); 87 + 88 + int linux_eventfd_init(struct eventfd *); 89 + void linux_eventfd_close(struct eventfd *); 90 + int linux_eventfd_raise(struct eventfd *); 91 + int linux_eventfd_lower(struct eventfd *); 92 + int linux_eventfd_descriptor(struct eventfd *); 93 + 94 + /* utility functions */ 95 + 96 + int linux_get_descriptor_type(struct knote *); 97 + int linux_fd_to_path(char *, size_t, int); 98 + 99 + /* epoll-related functions */ 100 + 101 + int epoll_update(int, struct filter *, struct knote *, struct epoll_event *); 102 + char * epoll_event_dump(struct epoll_event *); 103 + 104 + #endif /* ! _KQUEUE_LINUX_PLATFORM_H */
+269
external/libkqueue-2.0.1/src/linux/read.c
··· 1 + /* 2 + * Copyright (c) 2009 Mark Heily <mark@heily.com> 3 + * 4 + * Permission to use, copy, modify, and distribute this software for any 5 + * purpose with or without fee is hereby granted, provided that the above 6 + * copyright notice and this permission notice appear in all copies. 7 + * 8 + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 9 + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 10 + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 11 + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 12 + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 13 + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 14 + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 15 + */ 16 + 17 + #include <errno.h> 18 + #include <fcntl.h> 19 + #include <linux/sockios.h> 20 + #include <pthread.h> 21 + #include <signal.h> 22 + #include <stdlib.h> 23 + #include <stdio.h> 24 + #include <sys/ioctl.h> 25 + #include <sys/queue.h> 26 + #include <sys/socket.h> 27 + #include <sys/types.h> 28 + #include <string.h> 29 + #include <unistd.h> 30 + 31 + #include "private.h" 32 + 33 + /* 34 + * Return the offset from the current position to end of file. 35 + */ 36 + static intptr_t 37 + get_eof_offset(int fd) 38 + { 39 + off_t curpos; 40 + struct stat sb; 41 + 42 + curpos = lseek(fd, 0, SEEK_CUR); 43 + if (curpos == (off_t) -1) { 44 + dbg_perror("lseek(2)"); 45 + curpos = 0; 46 + } 47 + if (fstat(fd, &sb) < 0) { 48 + dbg_perror("fstat(2)"); 49 + sb.st_size = 1; 50 + } 51 + 52 + dbg_printf("curpos=%zu size=%zu\n", (size_t)curpos, (size_t)sb.st_size); 53 + return (sb.st_size - curpos); //FIXME: can overflow 54 + } 55 + 56 + int 57 + evfilt_read_copyout(struct kevent *dst, struct knote *src, void *ptr) 58 + { 59 + struct epoll_event * const ev = (struct epoll_event *) ptr; 60 + 61 + /* Special case: for regular files, return the offset from current position to end of file */ 62 + if (src->kn_flags & KNFL_REGULAR_FILE) { 63 + memcpy(dst, &src->kev, sizeof(*dst)); 64 + dst->data = get_eof_offset(src->kev.ident); 65 + 66 + if (dst->data == 0) { 67 + dst->filter = 0; /* Will cause the kevent to be discarded */ 68 + if (epoll_ctl(src->kn_epollfd, EPOLL_CTL_DEL, src->kdata.kn_eventfd, NULL) < 0) { 69 + dbg_perror("epoll_ctl(2)"); 70 + return (-1); 71 + } 72 + 73 + #if FIXME 74 + /* XXX-FIXME Switch to using kn_inotifyfd to monitor for IN_ATTRIB events 75 + that may signify the file size has changed. 76 + 77 + This code is not tested. 78 + */ 79 + int inofd; 80 + char path[PATH_MAX]; 81 + 82 + inofd = inotify_init(); 83 + if (inofd < 0) { 84 + dbg_perror("inotify_init(2)"); 85 + (void) close(inofd); 86 + return (-1); 87 + } 88 + src->kdata.kn_inotifyfd = inofd; 89 + if (linux_fd_to_path(&path[0], sizeof(path), src->kev.ident) < 0) 90 + return (-1); 91 + if (inotify_add_watch(inofd, path, IN_ATTRIB) < 0) { 92 + dbg_perror("inotify_add_watch"); 93 + return (-1); 94 + } 95 + if (epoll_ctl(src->kn_epollfd, EPOLL_CTL_ADD, src->kdata.kn_inotifyfd, NULL) < 0) { 96 + dbg_perror("epoll_ctl(2)"); 97 + return (-1); 98 + } 99 + /* FIXME: race here, should we check the EOF status again ? */ 100 + #endif 101 + } 102 + 103 + return (0); 104 + } 105 + 106 + dbg_printf("epoll: %s", epoll_event_dump(ev)); 107 + memcpy(dst, &src->kev, sizeof(*dst)); 108 + #if defined(HAVE_EPOLLRDHUP) 109 + if (ev->events & EPOLLRDHUP || ev->events & EPOLLHUP) 110 + dst->flags |= EV_EOF; 111 + #else 112 + if (ev->events & EPOLLHUP) 113 + dst->flags |= EV_EOF; 114 + #endif 115 + if (ev->events & EPOLLERR) 116 + dst->fflags = 1; /* FIXME: Return the actual socket error */ 117 + 118 + if (src->kn_flags & KNFL_PASSIVE_SOCKET) { 119 + /* On return, data contains the length of the 120 + socket backlog. This is not available under Linux. 121 + */ 122 + dst->data = 1; 123 + } else { 124 + /* On return, data contains the number of bytes of protocol 125 + data available to read. 126 + */ 127 + if (ioctl(dst->ident, SIOCINQ, &dst->data) < 0) { 128 + /* race condition with socket close, so ignore this error */ 129 + dbg_puts("ioctl(2) of socket failed"); 130 + dst->data = 0; 131 + } else { 132 + if (dst->data == 0) 133 + dst->flags |= EV_EOF; 134 + } 135 + } 136 + 137 + return (0); 138 + } 139 + 140 + int 141 + evfilt_read_knote_create(struct filter *filt, struct knote *kn) 142 + { 143 + struct epoll_event ev; 144 + 145 + if (linux_get_descriptor_type(kn) < 0) 146 + return (-1); 147 + 148 + /* Convert the kevent into an epoll_event */ 149 + #if defined(HAVE_EPOLLRDHUP) 150 + kn->data.events = EPOLLIN | EPOLLRDHUP; 151 + #else 152 + kn->data.events = EPOLLIN; 153 + #endif 154 + if (kn->kev.flags & EV_ONESHOT || kn->kev.flags & EV_DISPATCH) 155 + kn->data.events |= EPOLLONESHOT; 156 + if (kn->kev.flags & EV_CLEAR) 157 + kn->data.events |= EPOLLET; 158 + 159 + memset(&ev, 0, sizeof(ev)); 160 + ev.events = kn->data.events; 161 + ev.data.ptr = kn; 162 + 163 + /* Special case: for regular files, add a surrogate eventfd that is always readable */ 164 + if (kn->kn_flags & KNFL_REGULAR_FILE) { 165 + int evfd; 166 + 167 + kn->kn_epollfd = filter_epfd(filt); 168 + evfd = eventfd(0, 0); 169 + if (evfd < 0) { 170 + dbg_perror("eventfd(2)"); 171 + return (-1); 172 + } 173 + if (eventfd_write(evfd, 1) < 0) { 174 + dbg_perror("eventfd_write(3)"); 175 + (void) close(evfd); 176 + return (-1); 177 + } 178 + 179 + kn->kdata.kn_eventfd = evfd; 180 + 181 + if (epoll_ctl(kn->kn_epollfd, EPOLL_CTL_ADD, kn->kdata.kn_eventfd, &ev) < 0) { 182 + dbg_printf("epoll_ctl(2): %s", strerror(errno)); 183 + return (-1); 184 + } 185 + return (0); 186 + } 187 + 188 + return epoll_update(EPOLL_CTL_ADD, filt, kn, &ev); 189 + } 190 + 191 + int 192 + evfilt_read_knote_modify(struct filter *filt, struct knote *kn, 193 + const struct kevent *kev) 194 + { 195 + (void) filt; 196 + (void) kn; 197 + (void) kev; 198 + return (-1); /* STUB */ 199 + } 200 + 201 + int 202 + evfilt_read_knote_delete(struct filter *filt, struct knote *kn) 203 + { 204 + if (kn->kev.flags & EV_DISABLE) 205 + return (0); 206 + 207 + if ((kn->kn_flags & KNFL_REGULAR_FILE && kn->kdata.kn_eventfd != -1) < 0) { 208 + if (epoll_ctl(kn->kn_epollfd, EPOLL_CTL_DEL, kn->kdata.kn_eventfd, NULL) < 0) { 209 + dbg_perror("epoll_ctl(2)"); 210 + return (-1); 211 + } 212 + (void) close(kn->kdata.kn_eventfd); 213 + kn->kdata.kn_eventfd = -1; 214 + } else { 215 + return epoll_update(EPOLL_CTL_DEL, filt, kn, NULL); 216 + } 217 + 218 + // clang will complain about not returning a value otherwise 219 + return (-1); 220 + } 221 + 222 + int 223 + evfilt_read_knote_enable(struct filter *filt, struct knote *kn) 224 + { 225 + struct epoll_event ev; 226 + 227 + memset(&ev, 0, sizeof(ev)); 228 + ev.events = kn->data.events; 229 + ev.data.ptr = kn; 230 + 231 + if (kn->kn_flags & KNFL_REGULAR_FILE) { 232 + if (epoll_ctl(kn->kn_epollfd, EPOLL_CTL_ADD, kn->kdata.kn_eventfd, &ev) < 0) { 233 + dbg_perror("epoll_ctl(2)"); 234 + return (-1); 235 + } 236 + return (0); 237 + } else { 238 + return epoll_update(EPOLL_CTL_ADD, filt, kn, &ev); 239 + } 240 + 241 + // clang will complain about not returning a value otherwise 242 + return (-1); 243 + } 244 + 245 + int 246 + evfilt_read_knote_disable(struct filter *filt, struct knote *kn) 247 + { 248 + if (kn->kn_flags & KNFL_REGULAR_FILE) { 249 + if (epoll_ctl(kn->kn_epollfd, EPOLL_CTL_DEL, kn->kdata.kn_eventfd, NULL) < 0) { 250 + dbg_perror("epoll_ctl(2)"); 251 + return (-1); 252 + } 253 + return (0); 254 + } else { 255 + return epoll_update(EPOLL_CTL_DEL, filt, kn, NULL); 256 + } 257 + } 258 + 259 + const struct filter evfilt_read = { 260 + EVFILT_READ, 261 + NULL, 262 + NULL, 263 + evfilt_read_copyout, 264 + evfilt_read_knote_create, 265 + evfilt_read_knote_modify, 266 + evfilt_read_knote_delete, 267 + evfilt_read_knote_enable, 268 + evfilt_read_knote_disable, 269 + };
+218
external/libkqueue-2.0.1/src/linux/signal.c
··· 1 + /* 2 + * Copyright (c) 2009 Mark Heily <mark@heily.com> 3 + * 4 + * Permission to use, copy, modify, and distribute this software for any 5 + * purpose with or without fee is hereby granted, provided that the above 6 + * copyright notice and this permission notice appear in all copies. 7 + * 8 + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 9 + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 10 + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 11 + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 12 + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 13 + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 14 + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 15 + */ 16 + 17 + #include "private.h" 18 + 19 + #if HAVE_SYS_SIGNALFD_H 20 + # include <sys/signalfd.h> 21 + #else 22 + #define signalfd(a,b,c) syscall(SYS_signalfd, (a), (b), (c)) 23 + #define SFD_NONBLOCK 04000 24 + struct signalfd_siginfo 25 + { 26 + uint32_t ssi_signo; 27 + int32_t ssi_errno; 28 + int32_t ssi_code; 29 + uint32_t ssi_pid; 30 + uint32_t ssi_uid; 31 + int32_t ssi_fd; 32 + uint32_t ssi_tid; 33 + uint32_t ssi_band; 34 + uint32_t ssi_overrun; 35 + uint32_t ssi_trapno; 36 + int32_t ssi_status; 37 + int32_t ssi_int; 38 + uint64_t ssi_ptr; 39 + uint64_t ssi_utime; 40 + uint64_t ssi_stime; 41 + uint64_t ssi_addr; 42 + uint8_t __pad[48]; 43 + }; 44 + #endif 45 + 46 + static void 47 + signalfd_reset(int sigfd) 48 + { 49 + struct signalfd_siginfo sig; 50 + ssize_t n; 51 + 52 + /* Discard any pending signal */ 53 + n = read(sigfd, &sig, sizeof(sig)); 54 + if (n < 0 || n != sizeof(sig)) { 55 + if (errno == EWOULDBLOCK) 56 + return; 57 + //FIXME: eintr? 58 + dbg_perror("read(2) from signalfd"); 59 + abort(); 60 + } 61 + } 62 + 63 + static int 64 + signalfd_add(int epfd, int sigfd, void *ptr) 65 + { 66 + struct epoll_event ev; 67 + int rv; 68 + 69 + /* Add the signalfd to the kqueue's epoll descriptor set */ 70 + memset(&ev, 0, sizeof(ev)); 71 + ev.events = EPOLLIN; 72 + ev.data.ptr = ptr; 73 + rv = epoll_ctl(epfd, EPOLL_CTL_ADD, sigfd, &ev); 74 + if (rv < 0) { 75 + dbg_perror("epoll_ctl(2)"); 76 + return (-1); 77 + } 78 + 79 + return (0); 80 + } 81 + 82 + static int 83 + signalfd_create(int epfd, void *ptr, int signum) 84 + { 85 + static int flags = SFD_NONBLOCK; 86 + sigset_t sigmask; 87 + int sigfd; 88 + 89 + /* Create a signalfd */ 90 + sigemptyset(&sigmask); 91 + sigaddset(&sigmask, signum); 92 + sigfd = signalfd(-1, &sigmask, flags); 93 + 94 + /* WORKAROUND: Flags are broken on kernels older than Linux 2.6.27 */ 95 + if (sigfd < 0 && errno == EINVAL && flags != 0) { 96 + flags = 0; 97 + sigfd = signalfd(-1, &sigmask, flags); 98 + } 99 + if (sigfd < 0) { 100 + dbg_perror("signalfd(2)"); 101 + goto errout; 102 + } 103 + 104 + /* Block the signal handler from being invoked */ 105 + if (sigprocmask(SIG_BLOCK, &sigmask, NULL) < 0) { 106 + dbg_perror("sigprocmask(2)"); 107 + goto errout; 108 + } 109 + 110 + signalfd_reset(sigfd); 111 + 112 + if (signalfd_add(epfd, sigfd, ptr) < 0) 113 + goto errout; 114 + 115 + dbg_printf("added sigfd %d to epfd %d (signum=%d)", sigfd, epfd, signum); 116 + 117 + return (sigfd); 118 + 119 + errout: 120 + (void) close(sigfd); 121 + return (-1); 122 + } 123 + 124 + int 125 + evfilt_signal_copyout(struct kevent *dst, struct knote *src, void *x UNUSED) 126 + { 127 + int sigfd; 128 + 129 + sigfd = src->kdata.kn_signalfd; 130 + 131 + signalfd_reset(sigfd); 132 + 133 + memcpy(dst, &src->kev, sizeof(*dst)); 134 + /* NOTE: dst->data should be the number of times the signal occurred, 135 + but that information is not available. 136 + */ 137 + dst->data = 1; 138 + 139 + return (0); 140 + } 141 + 142 + int 143 + evfilt_signal_knote_create(struct filter *filt, struct knote *kn) 144 + { 145 + int fd; 146 + 147 + fd = signalfd_create(filter_epfd(filt), kn, kn->kev.ident); 148 + if (fd > 0) { 149 + kn->kev.flags |= EV_CLEAR; 150 + kn->kdata.kn_signalfd = fd; 151 + return (0); 152 + } else { 153 + kn->kdata.kn_signalfd = -1; 154 + return (-1); 155 + } 156 + } 157 + 158 + int 159 + evfilt_signal_knote_modify(struct filter *filt UNUSED, 160 + struct knote *kn UNUSED, 161 + const struct kevent *kev UNUSED) 162 + { 163 + /* Nothing to do since the signal number does not change. */ 164 + 165 + return (0); 166 + } 167 + 168 + int 169 + evfilt_signal_knote_delete(struct filter *filt, struct knote *kn) 170 + { 171 + const int sigfd = kn->kdata.kn_signalfd; 172 + 173 + /* Needed so that delete() can be called after disable() */ 174 + if (kn->kdata.kn_signalfd == -1) 175 + return (0); 176 + 177 + if (epoll_ctl(filter_epfd(filt), EPOLL_CTL_DEL, sigfd, NULL) < 0) { 178 + dbg_perror("epoll_ctl(2)"); 179 + return (-1); 180 + } 181 + 182 + if (close(sigfd) < 0) { 183 + dbg_perror("close(2)"); 184 + return (-1); 185 + } 186 + 187 + /* NOTE: This does not call sigprocmask(3) to unblock the signal. */ 188 + kn->kdata.kn_signalfd = -1; 189 + 190 + return (0); 191 + } 192 + 193 + int 194 + evfilt_signal_knote_enable(struct filter *filt, struct knote *kn) 195 + { 196 + dbg_printf("enabling ident %u", (unsigned int) kn->kev.ident); 197 + return evfilt_signal_knote_create(filt, kn); 198 + } 199 + 200 + int 201 + evfilt_signal_knote_disable(struct filter *filt, struct knote *kn) 202 + { 203 + dbg_printf("disabling ident %u", (unsigned int) kn->kev.ident); 204 + return evfilt_signal_knote_delete(filt, kn); 205 + } 206 + 207 + 208 + const struct filter evfilt_signal = { 209 + EVFILT_SIGNAL, 210 + NULL, 211 + NULL, 212 + evfilt_signal_copyout, 213 + evfilt_signal_knote_create, 214 + evfilt_signal_knote_modify, 215 + evfilt_signal_knote_delete, 216 + evfilt_signal_knote_enable, 217 + evfilt_signal_knote_disable, 218 + };
+219
external/libkqueue-2.0.1/src/linux/timer.c
··· 1 + /* 2 + * Copyright (c) 2009 Mark Heily <mark@heily.com> 3 + * 4 + * Permission to use, copy, modify, and distribute this software for any 5 + * purpose with or without fee is hereby granted, provided that the above 6 + * copyright notice and this permission notice appear in all copies. 7 + * 8 + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 9 + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 10 + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 11 + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 12 + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 13 + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 14 + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 15 + */ 16 + 17 + #include "private.h" 18 + 19 + #ifndef HAVE_SYS_TIMERFD_H 20 + 21 + /* Android 4.0 does not have this header, but the kernel supports timerfds */ 22 + #ifndef SYS_timerfd_create 23 + #ifdef __ARM_EABI__ 24 + #define __NR_timerfd_create (__NR_SYSCALL_BASE+350) 25 + #define __NR_timerfd_settime (__NR_SYSCALL_BASE+353) 26 + #define __NR_timerfd_gettime (__NR_SYSCALL_BASE+354) 27 + #else 28 + #error Unsupported architecture, need to get the syscall numbers 29 + #endif 30 + 31 + #define SYS_timerfd_create __NR_timerfd_create 32 + #define SYS_timerfd_settime __NR_timerfd_settime 33 + #define SYS_timerfd_gettime __NR_timerfd_gettime 34 + #endif /* ! SYS_timerfd_create */ 35 + 36 + /* XXX-FIXME 37 + These are horrible hacks that are only known to be true on RHEL 5 x86. 38 + */ 39 + #ifndef SYS_timerfd_settime 40 + #define SYS_timerfd_settime (SYS_timerfd_create + 1) 41 + #endif 42 + #ifndef SYS_timerfd_gettime 43 + #define SYS_timerfd_gettime (SYS_timerfd_create + 2) 44 + #endif 45 + 46 + int timerfd_create(int clockid, int flags) 47 + { 48 + return syscall(SYS_timerfd_create, clockid, flags); 49 + } 50 + 51 + int timerfd_settime(int ufc, int flags, const struct itimerspec *utmr, 52 + struct itimerspec *otmr) 53 + { 54 + return syscall(SYS_timerfd_settime, ufc, flags, utmr, otmr); 55 + } 56 + 57 + int timerfd_gettime(int ufc, struct itimerspec *otmr) 58 + { 59 + return syscall(SYS_timerfd_gettime, ufc, otmr); 60 + } 61 + 62 + #endif 63 + 64 + #ifndef NDEBUG 65 + static char * 66 + itimerspec_dump(struct itimerspec *ts) 67 + { 68 + static __thread char buf[1024]; 69 + 70 + snprintf(buf, sizeof(buf), 71 + "itimer: [ interval=%lu s %lu ns, next expire=%lu s %lu ns ]", 72 + ts->it_interval.tv_sec, 73 + ts->it_interval.tv_nsec, 74 + ts->it_value.tv_sec, 75 + ts->it_value.tv_nsec 76 + ); 77 + 78 + return (buf); 79 + } 80 + #endif 81 + 82 + /* Convert milliseconds into seconds+nanoseconds */ 83 + static void 84 + convert_msec_to_itimerspec(struct itimerspec *dst, int src, int oneshot) 85 + { 86 + time_t sec, nsec; 87 + 88 + sec = src / 1000; 89 + nsec = (src % 1000) * 1000000; 90 + 91 + /* Set the interval */ 92 + if (oneshot) { 93 + dst->it_interval.tv_sec = 0; 94 + dst->it_interval.tv_nsec = 0; 95 + } else { 96 + dst->it_interval.tv_sec = sec; 97 + dst->it_interval.tv_nsec = nsec; 98 + } 99 + 100 + /* Set the initial expiration */ 101 + dst->it_value.tv_sec = sec; 102 + dst->it_value.tv_nsec = nsec; 103 + dbg_printf("%s", itimerspec_dump(dst)); 104 + } 105 + 106 + int 107 + evfilt_timer_copyout(struct kevent *dst, struct knote *src, void *ptr) 108 + { 109 + struct epoll_event * const ev = (struct epoll_event *) ptr; 110 + uint64_t expired; 111 + ssize_t n; 112 + 113 + memcpy(dst, &src->kev, sizeof(*dst)); 114 + if (ev->events & EPOLLERR) 115 + dst->fflags = 1; /* FIXME: Return the actual timer error */ 116 + 117 + /* On return, data contains the number of times the 118 + timer has been trigered. 119 + */ 120 + n = read(src->data.pfd, &expired, sizeof(expired)); 121 + if (n != sizeof(expired)) { 122 + dbg_puts("invalid read from timerfd"); 123 + expired = 1; /* Fail gracefully */ 124 + } 125 + dst->data = expired; 126 + 127 + return (0); 128 + } 129 + 130 + int 131 + evfilt_timer_knote_create(struct filter *filt, struct knote *kn) 132 + { 133 + struct epoll_event ev; 134 + struct itimerspec ts; 135 + int tfd; 136 + 137 + kn->kev.flags |= EV_CLEAR; 138 + 139 + tfd = timerfd_create(CLOCK_MONOTONIC, 0); 140 + if (tfd < 0) { 141 + dbg_printf("timerfd_create(2): %s", strerror(errno)); 142 + return (-1); 143 + } 144 + dbg_printf("created timerfd %d", tfd); 145 + 146 + convert_msec_to_itimerspec(&ts, kn->kev.data, kn->kev.flags & EV_ONESHOT); 147 + if (timerfd_settime(tfd, 0, &ts, NULL) < 0) { 148 + dbg_printf("timerfd_settime(2): %s", strerror(errno)); 149 + close(tfd); 150 + return (-1); 151 + } 152 + 153 + memset(&ev, 0, sizeof(ev)); 154 + ev.events = EPOLLIN; 155 + ev.data.ptr = kn; 156 + if (epoll_ctl(filter_epfd(filt), EPOLL_CTL_ADD, tfd, &ev) < 0) { 157 + dbg_printf("epoll_ctl(2): %d", errno); 158 + close(tfd); 159 + return (-1); 160 + } 161 + 162 + kn->data.pfd = tfd; 163 + return (0); 164 + } 165 + 166 + int 167 + evfilt_timer_knote_modify(struct filter *filt, struct knote *kn, 168 + const struct kevent *kev) 169 + { 170 + (void)filt; 171 + (void)kn; 172 + (void)kev; 173 + return (0); /* STUB */ 174 + } 175 + 176 + int 177 + evfilt_timer_knote_delete(struct filter *filt, struct knote *kn) 178 + { 179 + int rv = 0; 180 + 181 + if (kn->data.pfd == -1) 182 + return (0); 183 + 184 + if (epoll_ctl(filter_epfd(filt), EPOLL_CTL_DEL, kn->data.pfd, NULL) < 0) { 185 + dbg_printf("epoll_ctl(2): %s", strerror(errno)); 186 + rv = -1; 187 + } 188 + if (close(kn->data.pfd) < 0) { 189 + dbg_printf("close(2): %s", strerror(errno)); 190 + rv = -1; 191 + } 192 + 193 + kn->data.pfd = -1; 194 + return (rv); 195 + } 196 + 197 + int 198 + evfilt_timer_knote_enable(struct filter *filt, struct knote *kn) 199 + { 200 + return evfilt_timer_knote_create(filt, kn); 201 + } 202 + 203 + int 204 + evfilt_timer_knote_disable(struct filter *filt, struct knote *kn) 205 + { 206 + return evfilt_timer_knote_delete(filt, kn); 207 + } 208 + 209 + const struct filter evfilt_timer = { 210 + EVFILT_TIMER, 211 + NULL, 212 + NULL, 213 + evfilt_timer_copyout, 214 + evfilt_timer_knote_create, 215 + evfilt_timer_knote_modify, 216 + evfilt_timer_knote_delete, 217 + evfilt_timer_knote_enable, 218 + evfilt_timer_knote_disable, 219 + };
+230
external/libkqueue-2.0.1/src/linux/user.c
··· 1 + /* 2 + * Copyright (c) 2009 Mark Heily <mark@heily.com> 3 + * 4 + * Permission to use, copy, modify, and distribute this software for any 5 + * purpose with or without fee is hereby granted, provided that the above 6 + * copyright notice and this permission notice appear in all copies. 7 + * 8 + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 9 + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 10 + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 11 + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 12 + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 13 + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 14 + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 15 + */ 16 + 17 + #include <errno.h> 18 + #include <fcntl.h> 19 + #include <pthread.h> 20 + #include <signal.h> 21 + #include <stdlib.h> 22 + #include <stdio.h> 23 + #include <sys/queue.h> 24 + #include <sys/socket.h> 25 + #include <sys/types.h> 26 + #include <string.h> 27 + #include <unistd.h> 28 + 29 + #include "sys/event.h" 30 + #include "private.h" 31 + 32 + /* NOTE: copy+pasted from linux_eventfd_raise() */ 33 + static int 34 + eventfd_raise(int evfd) 35 + { 36 + uint64_t counter; 37 + int rv = 0; 38 + 39 + dbg_puts("raising event level"); 40 + counter = 1; 41 + if (write(evfd, &counter, sizeof(counter)) < 0) { 42 + switch (errno) { 43 + case EAGAIN: 44 + /* Not considered an error */ 45 + break; 46 + 47 + case EINTR: 48 + rv = -EINTR; 49 + break; 50 + 51 + default: 52 + dbg_printf("write(2): %s", strerror(errno)); 53 + rv = -1; 54 + } 55 + } 56 + return (rv); 57 + } 58 + 59 + /* NOTE: copy+pasted from linux_eventfd_lower() */ 60 + static int 61 + eventfd_lower(int evfd) 62 + { 63 + uint64_t cur; 64 + ssize_t n; 65 + int rv = 0; 66 + 67 + /* Reset the counter */ 68 + dbg_puts("lowering event level"); 69 + n = read(evfd, &cur, sizeof(cur)); 70 + if (n < 0) { 71 + switch (errno) { 72 + case EAGAIN: 73 + /* Not considered an error */ 74 + break; 75 + 76 + case EINTR: 77 + rv = -EINTR; 78 + break; 79 + 80 + default: 81 + dbg_printf("read(2): %s", strerror(errno)); 82 + rv = -1; 83 + } 84 + } else if (n != sizeof(cur)) { 85 + dbg_puts("short read"); 86 + rv = -1; 87 + } 88 + 89 + return (rv); 90 + } 91 + 92 + int 93 + linux_evfilt_user_copyout(struct kevent *dst, struct knote *src, void *ptr UNUSED) 94 + { 95 + memcpy(dst, &src->kev, sizeof(*dst)); 96 + dst->fflags &= ~NOTE_FFCTRLMASK; //FIXME: Not sure if needed 97 + dst->fflags &= ~NOTE_TRIGGER; 98 + if (src->kev.flags & EV_ADD) { 99 + /* NOTE: True on FreeBSD but not consistent behavior with 100 + other filters. */ 101 + dst->flags &= ~EV_ADD; 102 + } 103 + if (src->kev.flags & EV_CLEAR) 104 + src->kev.fflags &= ~NOTE_TRIGGER; 105 + if (src->kev.flags & (EV_DISPATCH | EV_CLEAR | EV_ONESHOT)) { 106 + if (eventfd_lower(src->kdata.kn_eventfd) < 0) 107 + return (-1); 108 + } 109 + 110 + if (src->kev.flags & EV_DISPATCH) 111 + src->kev.fflags &= ~NOTE_TRIGGER; 112 + 113 + return (0); 114 + } 115 + 116 + int 117 + linux_evfilt_user_knote_create(struct filter *filt, struct knote *kn) 118 + { 119 + struct epoll_event ev; 120 + int evfd; 121 + 122 + /* Create an eventfd */ 123 + evfd = eventfd(0, 0); 124 + if (evfd < 0) { 125 + dbg_perror("eventfd"); 126 + goto errout; 127 + } 128 + 129 + /* Add the eventfd to the epoll set */ 130 + memset(&ev, 0, sizeof(ev)); 131 + ev.events = EPOLLIN; 132 + ev.data.ptr = kn; 133 + if (epoll_ctl(filter_epfd(filt), EPOLL_CTL_ADD, evfd, &ev) < 0) { 134 + dbg_perror("epoll_ctl(2)"); 135 + goto errout; 136 + } 137 + 138 + kn->kdata.kn_eventfd = evfd; 139 + 140 + return (0); 141 + 142 + errout: 143 + (void) close(evfd); 144 + kn->kdata.kn_eventfd = -1; 145 + return (-1); 146 + } 147 + 148 + int 149 + linux_evfilt_user_knote_modify(struct filter *filt UNUSED, struct knote *kn, 150 + const struct kevent *kev) 151 + { 152 + unsigned int ffctrl; 153 + unsigned int fflags; 154 + 155 + /* Excerpted from sys/kern/kern_event.c in FreeBSD HEAD */ 156 + ffctrl = kev->fflags & NOTE_FFCTRLMASK; 157 + fflags = kev->fflags & NOTE_FFLAGSMASK; 158 + switch (ffctrl) { 159 + case NOTE_FFNOP: 160 + break; 161 + 162 + case NOTE_FFAND: 163 + kn->kev.fflags &= fflags; 164 + break; 165 + 166 + case NOTE_FFOR: 167 + kn->kev.fflags |= fflags; 168 + break; 169 + 170 + case NOTE_FFCOPY: 171 + kn->kev.fflags = fflags; 172 + break; 173 + 174 + default: 175 + /* XXX Return error? */ 176 + break; 177 + } 178 + 179 + if ((!(kn->kev.flags & EV_DISABLE)) && kev->fflags & NOTE_TRIGGER) { 180 + kn->kev.fflags |= NOTE_TRIGGER; 181 + if (eventfd_raise(kn->kdata.kn_eventfd) < 0) 182 + return (-1); 183 + } 184 + 185 + return (0); 186 + } 187 + 188 + int 189 + linux_evfilt_user_knote_delete(struct filter *filt, struct knote *kn) 190 + { 191 + if (epoll_ctl(filter_epfd(filt), EPOLL_CTL_DEL, 192 + kn->kdata.kn_eventfd, NULL) < 0) { 193 + dbg_perror("epoll_ctl(2)"); 194 + return (-1); 195 + } 196 + if (close(kn->kdata.kn_eventfd) < 0) { 197 + dbg_perror("close(2)"); 198 + return (-1); 199 + } 200 + dbg_printf("removed eventfd %d from the epollfd", kn->kdata.kn_eventfd); 201 + kn->kdata.kn_eventfd = -1; 202 + 203 + return (0); 204 + } 205 + 206 + int 207 + linux_evfilt_user_knote_enable(struct filter *filt, struct knote *kn) 208 + { 209 + /* FIXME: what happens if NOTE_TRIGGER is in fflags? 210 + should the event fire? */ 211 + return linux_evfilt_user_knote_create(filt, kn); 212 + } 213 + 214 + int 215 + linux_evfilt_user_knote_disable(struct filter *filt, struct knote *kn) 216 + { 217 + return linux_evfilt_user_knote_delete(filt, kn); 218 + } 219 + 220 + const struct filter evfilt_user = { 221 + EVFILT_USER, 222 + NULL, 223 + NULL, 224 + linux_evfilt_user_copyout, 225 + linux_evfilt_user_knote_create, 226 + linux_evfilt_user_knote_modify, 227 + linux_evfilt_user_knote_delete, 228 + linux_evfilt_user_knote_enable, 229 + linux_evfilt_user_knote_disable, 230 + };
+292
external/libkqueue-2.0.1/src/linux/vnode.c
··· 1 + /* 2 + * Copyright (c) 2009 Mark Heily <mark@heily.com> 3 + * 4 + * Permission to use, copy, modify, and distribute this software for any 5 + * purpose with or without fee is hereby granted, provided that the above 6 + * copyright notice and this permission notice appear in all copies. 7 + * 8 + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 9 + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 10 + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 11 + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 12 + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 13 + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 14 + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 15 + */ 16 + 17 + #include "private.h" 18 + 19 + #ifndef NDEBUG 20 + static char * 21 + inotify_mask_dump(uint32_t mask) 22 + { 23 + static __thread char buf[1024]; 24 + 25 + #define INEVT_MASK_DUMP(attrib) \ 26 + if (mask & attrib) \ 27 + strcat(buf, #attrib" "); 28 + 29 + snprintf(buf, sizeof(buf), "mask = %d (", mask); 30 + INEVT_MASK_DUMP(IN_ACCESS); 31 + INEVT_MASK_DUMP(IN_MODIFY); 32 + INEVT_MASK_DUMP(IN_ATTRIB); 33 + INEVT_MASK_DUMP(IN_CLOSE_WRITE); 34 + INEVT_MASK_DUMP(IN_CLOSE_NOWRITE); 35 + INEVT_MASK_DUMP(IN_OPEN); 36 + INEVT_MASK_DUMP(IN_MOVED_FROM); 37 + INEVT_MASK_DUMP(IN_MOVED_TO); 38 + INEVT_MASK_DUMP(IN_CREATE); 39 + INEVT_MASK_DUMP(IN_DELETE); 40 + INEVT_MASK_DUMP(IN_DELETE_SELF); 41 + INEVT_MASK_DUMP(IN_MOVE_SELF); 42 + buf[strlen(buf) - 1] = ')'; 43 + 44 + return (buf); 45 + } 46 + 47 + static char * 48 + inotify_event_dump(struct inotify_event *evt) 49 + { 50 + static __thread char buf[1024]; 51 + 52 + snprintf(buf, sizeof(buf), "wd=%d mask=%s", 53 + evt->wd, 54 + inotify_mask_dump(evt->mask)); 55 + 56 + return (buf); 57 + } 58 + 59 + #endif /* !NDEBUG */ 60 + 61 + 62 + /* TODO: USE this to get events with name field */ 63 + int 64 + get_one_event(struct inotify_event *dst, int inofd) 65 + { 66 + ssize_t n; 67 + 68 + dbg_puts("reading one inotify event"); 69 + for (;;) { 70 + n = read(inofd, dst, sizeof(*dst)); 71 + if (n < 0) { 72 + if (errno == EINTR) 73 + continue; 74 + dbg_perror("read"); 75 + return (-1); 76 + } else { 77 + break; 78 + } 79 + } 80 + dbg_printf("read(2) from inotify wd: %ld bytes", (long) n); 81 + 82 + /* FIXME-TODO: if len > 0, read(len) */ 83 + if (dst->len != 0) 84 + abort(); 85 + 86 + 87 + return (0); 88 + } 89 + 90 + static int 91 + add_watch(struct filter *filt, struct knote *kn) 92 + { 93 + struct epoll_event ev; 94 + int ifd; 95 + char path[PATH_MAX]; 96 + uint32_t mask; 97 + 98 + /* Convert the fd to a pathname */ 99 + if (linux_fd_to_path(&path[0], sizeof(path), kn->kev.ident) < 0) 100 + return (-1); 101 + 102 + /* Convert the fflags to the inotify mask */ 103 + mask = IN_CLOSE; 104 + if (kn->kev.fflags & NOTE_DELETE) 105 + mask |= IN_ATTRIB | IN_DELETE_SELF; 106 + if (kn->kev.fflags & NOTE_WRITE) 107 + mask |= IN_MODIFY | IN_ATTRIB; 108 + if (kn->kev.fflags & NOTE_EXTEND) 109 + mask |= IN_MODIFY | IN_ATTRIB; 110 + if ((kn->kev.fflags & NOTE_ATTRIB) || 111 + (kn->kev.fflags & NOTE_LINK)) 112 + mask |= IN_ATTRIB; 113 + if (kn->kev.fflags & NOTE_RENAME) 114 + mask |= IN_MOVE_SELF; 115 + if (kn->kev.flags & EV_ONESHOT) 116 + mask |= IN_ONESHOT; 117 + 118 + /* Create an inotify descriptor */ 119 + ifd = inotify_init(); 120 + if (ifd < 0) { 121 + dbg_perror("inotify_init(2)"); 122 + return (-1); 123 + } 124 + 125 + /* Add the watch */ 126 + dbg_printf("inotify_add_watch(2); inofd=%d, %s, path=%s", 127 + ifd, inotify_mask_dump(mask), path); 128 + kn->kev.data = inotify_add_watch(ifd, path, mask); 129 + if (kn->kev.data < 0) { 130 + dbg_perror("inotify_add_watch(2)"); 131 + goto errout; 132 + } 133 + 134 + /* Add the inotify fd to the epoll set */ 135 + memset(&ev, 0, sizeof(ev)); 136 + ev.events = EPOLLIN; 137 + ev.data.ptr = kn; 138 + if (epoll_ctl(filter_epfd(filt), EPOLL_CTL_ADD, ifd, &ev) < 0) { 139 + dbg_perror("epoll_ctl(2)"); 140 + goto errout; 141 + } 142 + 143 + kn->kdata.kn_inotifyfd = ifd; 144 + 145 + return (0); 146 + 147 + errout: 148 + kn->kdata.kn_inotifyfd = -1; 149 + (void) close(ifd); 150 + return (-1); 151 + } 152 + 153 + static int 154 + delete_watch(struct filter *filt, struct knote *kn) 155 + { 156 + int ifd = kn->kdata.kn_inotifyfd; 157 + 158 + if (ifd < 0) 159 + return (0); 160 + if (epoll_ctl(filter_epfd(filt), EPOLL_CTL_DEL, ifd, NULL) < 0) { 161 + dbg_perror("epoll_ctl(2)"); 162 + return (-1); 163 + } 164 + (void) close(ifd); 165 + kn->kdata.kn_inotifyfd = -1; 166 + 167 + return (0); 168 + } 169 + 170 + int 171 + evfilt_vnode_copyout(struct kevent *dst, struct knote *src, void *ptr UNUSED) 172 + { 173 + struct inotify_event evt; 174 + struct stat sb; 175 + 176 + if (get_one_event(&evt, src->kdata.kn_inotifyfd) < 0) 177 + return (-1); 178 + 179 + dbg_printf("inotify event: %s", inotify_event_dump(&evt)); 180 + if (evt.mask & IN_IGNORED) { 181 + /* TODO: possibly return error when fs is unmounted */ 182 + dst->filter = 0; 183 + return (0); 184 + } 185 + 186 + /* Check if the watched file has been closed, and 187 + XXX-this may not exactly match the kevent() behavior if multiple file de 188 + scriptors reference the same file. 189 + */ 190 + if (evt.mask & IN_CLOSE_WRITE || evt.mask & IN_CLOSE_NOWRITE) { 191 + src->kn_flags |= EV_ONESHOT; /* KLUDGE: causes the knote to be deleted */ 192 + dst->filter = 0; /* KLUDGE: causes the event to be discarded */ 193 + return (0); 194 + } 195 + 196 + memcpy(dst, &src->kev, sizeof(*dst)); 197 + dst->data = 0; 198 + 199 + /* No error checking because fstat(2) should rarely fail */ 200 + //FIXME: EINTR 201 + if ((evt.mask & IN_ATTRIB || evt.mask & IN_MODIFY) 202 + && fstat(src->kev.ident, &sb) == 0) { 203 + if (sb.st_nlink == 0 && src->kev.fflags & NOTE_DELETE) 204 + dst->fflags |= NOTE_DELETE; 205 + if (sb.st_nlink != src->data.vnode.nlink && src->kev.fflags & NOTE_LINK) 206 + dst->fflags |= NOTE_LINK; 207 + #if HAVE_NOTE_TRUNCATE 208 + if (sb.st_nsize == 0 && src->kev.fflags & NOTE_TRUNCATE) 209 + dst->fflags |= NOTE_TRUNCATE; 210 + #endif 211 + if (sb.st_size > src->data.vnode.size && src->kev.fflags & NOTE_WRITE) 212 + dst->fflags |= NOTE_EXTEND; 213 + src->data.vnode.nlink = sb.st_nlink; 214 + src->data.vnode.size = sb.st_size; 215 + } 216 + 217 + if (evt.mask & IN_MODIFY && src->kev.fflags & NOTE_WRITE) 218 + dst->fflags |= NOTE_WRITE; 219 + if (evt.mask & IN_ATTRIB && src->kev.fflags & NOTE_ATTRIB) 220 + dst->fflags |= NOTE_ATTRIB; 221 + if (evt.mask & IN_MOVE_SELF && src->kev.fflags & NOTE_RENAME) 222 + dst->fflags |= NOTE_RENAME; 223 + if (evt.mask & IN_DELETE_SELF && src->kev.fflags & NOTE_DELETE) 224 + dst->fflags |= NOTE_DELETE; 225 + 226 + if (evt.mask & IN_MODIFY && src->kev.fflags & NOTE_WRITE) 227 + dst->fflags |= NOTE_WRITE; 228 + if (evt.mask & IN_ATTRIB && src->kev.fflags & NOTE_ATTRIB) 229 + dst->fflags |= NOTE_ATTRIB; 230 + if (evt.mask & IN_MOVE_SELF && src->kev.fflags & NOTE_RENAME) 231 + dst->fflags |= NOTE_RENAME; 232 + if (evt.mask & IN_DELETE_SELF && src->kev.fflags & NOTE_DELETE) 233 + dst->fflags |= NOTE_DELETE; 234 + 235 + return (0); 236 + } 237 + 238 + int 239 + evfilt_vnode_knote_create(struct filter *filt, struct knote *kn) 240 + { 241 + struct stat sb; 242 + 243 + if (fstat(kn->kev.ident, &sb) < 0) { 244 + dbg_puts("fstat failed"); 245 + return (-1); 246 + } 247 + kn->data.vnode.nlink = sb.st_nlink; 248 + kn->data.vnode.size = sb.st_size; 249 + kn->kev.data = -1; 250 + 251 + return (add_watch(filt, kn)); 252 + } 253 + 254 + int 255 + evfilt_vnode_knote_modify(struct filter *filt, struct knote *kn, 256 + const struct kevent *kev) 257 + { 258 + (void)filt; 259 + (void)kn; 260 + (void)kev; 261 + return (-1); /* FIXME - STUB */ 262 + } 263 + 264 + int 265 + evfilt_vnode_knote_delete(struct filter *filt, struct knote *kn) 266 + { 267 + return delete_watch(filt, kn); 268 + } 269 + 270 + int 271 + evfilt_vnode_knote_enable(struct filter *filt, struct knote *kn) 272 + { 273 + return add_watch(filt, kn); 274 + } 275 + 276 + int 277 + evfilt_vnode_knote_disable(struct filter *filt, struct knote *kn) 278 + { 279 + return delete_watch(filt, kn); 280 + } 281 + 282 + const struct filter evfilt_vnode = { 283 + EVFILT_VNODE, 284 + NULL, 285 + NULL, 286 + evfilt_vnode_copyout, 287 + evfilt_vnode_knote_create, 288 + evfilt_vnode_knote_modify, 289 + evfilt_vnode_knote_delete, 290 + evfilt_vnode_knote_enable, 291 + evfilt_vnode_knote_disable, 292 + };
+133
external/libkqueue-2.0.1/src/linux/write.c
··· 1 + /* 2 + * Copyright (c) 2009 Mark Heily <mark@heily.com> 3 + * 4 + * Permission to use, copy, modify, and distribute this software for any 5 + * purpose with or without fee is hereby granted, provided that the above 6 + * copyright notice and this permission notice appear in all copies. 7 + * 8 + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 9 + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 10 + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 11 + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 12 + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 13 + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 14 + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 15 + */ 16 + 17 + #include <errno.h> 18 + #include <fcntl.h> 19 + #include <linux/sockios.h> 20 + #include <pthread.h> 21 + #include <signal.h> 22 + #include <stdlib.h> 23 + #include <stdio.h> 24 + #include <sys/ioctl.h> 25 + #include <sys/queue.h> 26 + #include <sys/socket.h> 27 + #include <sys/types.h> 28 + #include <string.h> 29 + #include <unistd.h> 30 + 31 + #include "private.h" 32 + 33 + int 34 + evfilt_socket_copyout(struct kevent *dst, struct knote *src, void *ptr) 35 + { 36 + struct epoll_event * const ev = (struct epoll_event *) ptr; 37 + 38 + epoll_event_dump(ev); 39 + memcpy(dst, &src->kev, sizeof(*dst)); 40 + #if defined(HAVE_EPOLLRDHUP) 41 + if (ev->events & EPOLLRDHUP || ev->events & EPOLLHUP) 42 + dst->flags |= EV_EOF; 43 + #else 44 + if (ev->events & EPOLLHUP) 45 + dst->flags |= EV_EOF; 46 + #endif 47 + if (ev->events & EPOLLERR) 48 + dst->fflags = 1; /* FIXME: Return the actual socket error */ 49 + 50 + /* On return, data contains the the amount of space remaining in the write buffer */ 51 + if (ioctl(dst->ident, SIOCOUTQ, &dst->data) < 0) { 52 + /* race condition with socket close, so ignore this error */ 53 + dbg_puts("ioctl(2) of socket failed"); 54 + dst->data = 0; 55 + } 56 + 57 + return (0); 58 + } 59 + 60 + int 61 + evfilt_socket_knote_create(struct filter *filt, struct knote *kn) 62 + { 63 + struct epoll_event ev; 64 + 65 + if (linux_get_descriptor_type(kn) < 0) 66 + return (-1); 67 + 68 + /* TODO: return EBADF? */ 69 + if (kn->kn_flags & KNFL_REGULAR_FILE) 70 + return (-1); 71 + 72 + /* Convert the kevent into an epoll_event */ 73 + kn->data.events = EPOLLOUT; 74 + if (kn->kev.flags & EV_ONESHOT || kn->kev.flags & EV_DISPATCH) 75 + kn->data.events |= EPOLLONESHOT; 76 + if (kn->kev.flags & EV_CLEAR) 77 + kn->data.events |= EPOLLET; 78 + 79 + memset(&ev, 0, sizeof(ev)); 80 + ev.events = kn->data.events; 81 + ev.data.ptr = kn; 82 + 83 + return epoll_update(EPOLL_CTL_ADD, filt, kn, &ev); 84 + } 85 + 86 + int 87 + evfilt_socket_knote_modify(struct filter *filt, struct knote *kn, 88 + const struct kevent *kev) 89 + { 90 + (void) filt; 91 + (void) kn; 92 + (void) kev; 93 + return (-1); /* STUB */ 94 + } 95 + 96 + int 97 + evfilt_socket_knote_delete(struct filter *filt, struct knote *kn) 98 + { 99 + if (kn->kev.flags & EV_DISABLE) 100 + return (0); 101 + else 102 + return epoll_update(EPOLL_CTL_DEL, filt, kn, NULL); 103 + } 104 + 105 + int 106 + evfilt_socket_knote_enable(struct filter *filt, struct knote *kn) 107 + { 108 + struct epoll_event ev; 109 + 110 + memset(&ev, 0, sizeof(ev)); 111 + ev.events = kn->data.events; 112 + ev.data.ptr = kn; 113 + 114 + return epoll_update(EPOLL_CTL_ADD, filt, kn, &ev); 115 + } 116 + 117 + int 118 + evfilt_socket_knote_disable(struct filter *filt, struct knote *kn) 119 + { 120 + return epoll_update(EPOLL_CTL_DEL, filt, kn, NULL); 121 + } 122 + 123 + const struct filter evfilt_write = { 124 + EVFILT_WRITE, 125 + NULL, 126 + NULL, 127 + evfilt_socket_copyout, 128 + evfilt_socket_knote_create, 129 + evfilt_socket_knote_modify, 130 + evfilt_socket_knote_delete, 131 + evfilt_socket_knote_enable, 132 + evfilt_socket_knote_disable, 133 + };
+90
external/libkqueue-2.0.1/src/posix/platform.c
··· 1 + /* 2 + * Copyright (c) 2011 Mark Heily <mark@heily.com> 3 + * 4 + * Permission to use, copy, modify, and distribute this software for any 5 + * purpose with or without fee is hereby granted, provided that the above 6 + * copyright notice and this permission notice appear in all copies. 7 + * 8 + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 9 + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 10 + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 11 + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 12 + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 13 + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 14 + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 15 + */ 16 + 17 + #include "../common/private.h" 18 + 19 + int 20 + posix_kqueue_init(struct kqueue *kq UNUSED) 21 + { 22 + return (0); 23 + } 24 + 25 + void 26 + posix_kqueue_free(struct kqueue *kq UNUSED) 27 + { 28 + } 29 + 30 + int 31 + posix_eventfd_init(struct eventfd *e) 32 + { 33 + int sd[2]; 34 + 35 + if (socketpair(AF_UNIX, SOCK_STREAM, 0, sd) < 0) { 36 + return (-1); 37 + } 38 + if ((fcntl(sd[0], F_SETFL, O_NONBLOCK) < 0) || 39 + (fcntl(sd[1], F_SETFL, O_NONBLOCK) < 0)) { 40 + close(sd[0]); 41 + close(sd[1]); 42 + return (-1); 43 + } 44 + e->ef_wfd = sd[0]; 45 + e->ef_id = sd[1]; 46 + 47 + return (0); 48 + } 49 + 50 + void 51 + posix_eventfd_close(struct eventfd *e) 52 + { 53 + close(e->ef_id); 54 + close(e->ef_wfd); 55 + e->ef_id = -1; 56 + } 57 + 58 + int 59 + posix_eventfd_raise(struct eventfd *e) 60 + { 61 + dbg_puts("raising event level"); 62 + if (write(e->ef_wfd, ".", 1) < 0) { 63 + /* FIXME: handle EAGAIN and EINTR */ 64 + dbg_printf("write(2) on fd %d: %s", e->ef_wfd, strerror(errno)); 65 + return (-1); 66 + } 67 + return (0); 68 + } 69 + 70 + int 71 + posix_eventfd_lower(struct eventfd *e) 72 + { 73 + char buf[1024]; 74 + 75 + /* Reset the counter */ 76 + dbg_puts("lowering event level"); 77 + if (read(e->ef_id, &buf, sizeof(buf)) < 0) { 78 + /* FIXME: handle EAGAIN and EINTR */ 79 + /* FIXME: loop so as to consume all data.. may need mutex */ 80 + dbg_printf("read(2): %s", strerror(errno)); 81 + return (-1); 82 + } 83 + return (0); 84 + } 85 + 86 + int 87 + posix_eventfd_descriptor(struct eventfd *e) 88 + { 89 + return (e->ef_id); 90 + }
+81
external/libkqueue-2.0.1/src/posix/platform.h
··· 1 + /* 2 + * Copyright (c) 2011 Mark Heily <mark@heily.com> 3 + * 4 + * Permission to use, copy, modify, and distribute this software for any 5 + * purpose with or without fee is hereby granted, provided that the above 6 + * copyright notice and this permission notice appear in all copies. 7 + * 8 + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 9 + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 10 + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 11 + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 12 + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 13 + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 14 + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 15 + */ 16 + 17 + #ifndef _KQUEUE_POSIX_PLATFORM_H 18 + #define _KQUEUE_POSIX_PLATFORM_H 19 + 20 + /* Required by glibc for MAP_ANON */ 21 + #define __USE_MISC 1 22 + 23 + #include "../../include/sys/event.h" 24 + 25 + /* 26 + * GCC-compatible atomic operations 27 + */ 28 + #define atomic_inc(p) __sync_add_and_fetch((p), 1) 29 + #define atomic_dec(p) __sync_sub_and_fetch((p), 1) 30 + #define atomic_cas(p, oval, nval) __sync_val_compare_and_swap(p, oval, nval) 31 + #define atomic_ptr_cas(p, oval, nval) __sync_val_compare_and_swap(p, oval, nval) 32 + 33 + /* 34 + * GCC-compatible branch prediction macros 35 + */ 36 + #define fastpath(x) __builtin_expect((x), 1) 37 + #define slowpath(x) __builtin_expect((x), 0) 38 + 39 + /* 40 + * GCC-compatible attributes 41 + */ 42 + #define VISIBLE __attribute__((visibility("default"))) 43 + #define HIDDEN __attribute__((visibility("hidden"))) 44 + #define UNUSED __attribute__((unused)) 45 + 46 + #include <fcntl.h> 47 + #include <limits.h> 48 + #include <signal.h> 49 + #include <stdbool.h> 50 + #include <stdlib.h> 51 + #include <stdio.h> 52 + #include <stdint.h> 53 + #include <pthread.h> 54 + #include <poll.h> 55 + #include <sys/resource.h> 56 + #include <sys/select.h> 57 + #include <sys/socket.h> 58 + #include <sys/stat.h> 59 + #include <sys/types.h> 60 + #include <sys/mman.h> 61 + #include <unistd.h> 62 + 63 + /* 64 + * Additional members of 'struct eventfd' 65 + */ 66 + #define EVENTFD_PLATFORM_SPECIFIC \ 67 + int ef_wfd 68 + 69 + void posix_kqueue_free(struct kqueue *); 70 + int posix_kqueue_init(struct kqueue *); 71 + 72 + int posix_kevent_wait(struct kqueue *, const struct timespec *); 73 + int posix_kevent_copyout(struct kqueue *, int, struct kevent *, int); 74 + 75 + int posix_eventfd_init(struct eventfd *); 76 + void posix_eventfd_close(struct eventfd *); 77 + int posix_eventfd_raise(struct eventfd *); 78 + int posix_eventfd_lower(struct eventfd *); 79 + int posix_eventfd_descriptor(struct eventfd *); 80 + 81 + #endif /* ! _KQUEUE_POSIX_PLATFORM_H */
+137
external/libkqueue-2.0.1/test/common.h
··· 1 + /* 2 + * Copyright (c) 2009 Mark Heily <mark@heily.com> 3 + * 4 + * Permission to use, copy, modify, and distribute this software for any 5 + * purpose with or without fee is hereby granted, provided that the above 6 + * copyright notice and this permission notice appear in all copies. 7 + * 8 + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 9 + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 10 + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 11 + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 12 + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 13 + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 14 + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 15 + */ 16 + 17 + #ifndef _COMMON_H 18 + #define _COMMON_H 19 + 20 + 21 + #if HAVE_ERR_H 22 + # include <err.h> 23 + #else 24 + # define err(rc,msg,...) do { perror(msg); exit(rc); } while (0) 25 + # define errx(rc,msg,...) do { puts(msg); exit(rc); } while (0) 26 + #endif 27 + 28 + #define die(str) do { \ 29 + fprintf(stderr, "%s(): %s: %s\n", __func__,str, strerror(errno));\ 30 + abort();\ 31 + } while (0) 32 + 33 + #include <assert.h> 34 + #include <errno.h> 35 + #include <fcntl.h> 36 + #include <signal.h> 37 + #include <stdlib.h> 38 + #include <stdio.h> 39 + #include <string.h> 40 + #include <stdint.h> 41 + 42 + #ifndef _WIN32 43 + #include <sys/socket.h> 44 + #include <sys/stat.h> 45 + #include <sys/types.h> 46 + #include <unistd.h> 47 + #include <sys/event.h> 48 + #include <arpa/inet.h> 49 + #include <pthread.h> 50 + #include <poll.h> 51 + #include "../config.h" 52 + #else 53 + # include "../include/sys/event.h" 54 + # include "../src/windows/platform.h" 55 + #endif 56 + 57 + struct test_context; 58 + 59 + struct unit_test { 60 + const char *ut_name; 61 + int ut_enabled; 62 + void (*ut_func)(struct test_context *); 63 + }; 64 + 65 + #define MAX_TESTS 50 66 + struct test_context { 67 + struct unit_test tests[MAX_TESTS]; 68 + char *cur_test_id; 69 + int iterations; 70 + int iteration; 71 + int kqfd; 72 + 73 + /* EVFILT_READ and EVFILT_WRITE */ 74 + int client_fd; 75 + int server_fd; 76 + 77 + /* EVFILT_VNODE */ 78 + int vnode_fd; 79 + char testfile[1024]; 80 + }; 81 + 82 + void test_evfilt_read(struct test_context *); 83 + void test_evfilt_signal(struct test_context *); 84 + void test_evfilt_vnode(struct test_context *); 85 + void test_evfilt_timer(struct test_context *); 86 + void test_evfilt_proc(struct test_context *); 87 + #ifdef EVFILT_USER 88 + void test_evfilt_user(struct test_context *); 89 + #endif 90 + 91 + #define test(f,ctx,...) do { \ 92 + assert(ctx != NULL); \ 93 + test_begin(ctx, "test_"#f"()\t"__VA_ARGS__); \ 94 + test_##f(ctx); \ 95 + test_end(ctx); \ 96 + } while (/*CONSTCOND*/0) 97 + 98 + extern const char * kevent_to_str(struct kevent *); 99 + void kevent_get(struct kevent *, int); 100 + void kevent_get_hires(struct kevent *, int); 101 + void kevent_update(int kqfd, struct kevent *kev); 102 + 103 + #define kevent_cmp(a,b) _kevent_cmp(a,b, __FILE__, __LINE__) 104 + void _kevent_cmp(struct kevent *, struct kevent *, const char *, int); 105 + 106 + void 107 + kevent_add(int kqfd, struct kevent *kev, 108 + uintptr_t ident, 109 + short filter, 110 + u_short flags, 111 + u_int fflags, 112 + intptr_t data, 113 + void *udata); 114 + 115 + /* DEPRECATED: */ 116 + #define KEV_CMP(kev,_ident,_filter,_flags) do { \ 117 + if (kev.ident != (_ident) || \ 118 + kev.filter != (_filter) || \ 119 + kev.flags != (_flags)) \ 120 + err(1, "kevent mismatch: got [%d,%d,%d] but expecting [%d,%d,%d]", \ 121 + (int)_ident, (int)_filter, (int)_flags,\ 122 + (int)kev.ident, kev.filter, kev.flags);\ 123 + } while (0); 124 + 125 + /* Checks if any events are pending, which is an error. */ 126 + #define test_no_kevents(a) _test_no_kevents(a, __FILE__, __LINE__) 127 + void _test_no_kevents(int, const char *, int); 128 + 129 + /* From test.c */ 130 + void test_begin(struct test_context *, const char *); 131 + void test_end(struct test_context *); 132 + void test_atexit(void); 133 + void testing_begin(void); 134 + void testing_end(void); 135 + int testing_make_uid(void); 136 + 137 + #endif /* _COMMON_H */
+199
external/libkqueue-2.0.1/test/kevent.c
··· 1 + /* 2 + * Copyright (c) 2009 Mark Heily <mark@heily.com> 3 + * 4 + * Permission to use, copy, modify, and distribute this software for any 5 + * purpose with or without fee is hereby granted, provided that the above 6 + * copyright notice and this permission notice appear in all copies. 7 + * 8 + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 9 + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 10 + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 11 + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 12 + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 13 + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 14 + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 15 + */ 16 + 17 + #include "common.h" 18 + 19 + extern int kqfd; 20 + 21 + /* Checks if any events are pending, which is an error. */ 22 + void 23 + _test_no_kevents(int kqfd, const char *file, int line) 24 + { 25 + int nfds; 26 + struct timespec timeo; 27 + struct kevent kev; 28 + 29 + memset(&timeo, 0, sizeof(timeo)); 30 + nfds = kevent(kqfd, NULL, 0, &kev, 1, &timeo); 31 + if (nfds < 0) 32 + err(1, "kevent(2)"); 33 + if (nfds > 0) { 34 + printf("\n[%s:%d]: Unexpected event:", file, line); 35 + err(1, kevent_to_str(&kev)); 36 + } 37 + } 38 + 39 + /* Retrieve a single kevent */ 40 + void 41 + kevent_get(struct kevent *kev, int kqfd) 42 + { 43 + struct kevent buf; 44 + int nfds; 45 + 46 + if (kev == NULL) 47 + kev = &buf; 48 + 49 + nfds = kevent(kqfd, NULL, 0, kev, 1, NULL); 50 + if (nfds < 1) 51 + err(1, "kevent(2)"); 52 + } 53 + 54 + /* In Linux, a kevent() call with less than 1ms resolution 55 + will perform a pselect() call to obtain the higer resolution. 56 + This test exercises that codepath. 57 + */ 58 + void 59 + kevent_get_hires(struct kevent *kev, int kqfd) 60 + { 61 + int nfds; 62 + struct timespec timeo; 63 + 64 + timeo.tv_sec = 0; 65 + timeo.tv_nsec = 500000; 66 + nfds = kevent(kqfd, NULL, 0, kev, 1, &timeo); 67 + if (nfds < 1) 68 + die("kevent(2)"); 69 + } 70 + 71 + char * 72 + kevent_fflags_dump(struct kevent *kev) 73 + { 74 + char *buf; 75 + 76 + #define KEVFFL_DUMP(attrib) \ 77 + if (kev->fflags & attrib) \ 78 + strncat(buf, #attrib" ", 64); 79 + 80 + if ((buf = calloc(1, 1024)) == NULL) 81 + abort(); 82 + 83 + /* Not every filter has meaningful fflags */ 84 + if (kev->filter != EVFILT_VNODE) { 85 + snprintf(buf, 1024, "fflags = %d", kev->fflags); 86 + return (buf); 87 + } 88 + 89 + snprintf(buf, 1024, "fflags = %d (", kev->fflags); 90 + KEVFFL_DUMP(NOTE_DELETE); 91 + KEVFFL_DUMP(NOTE_WRITE); 92 + KEVFFL_DUMP(NOTE_EXTEND); 93 + #if HAVE_NOTE_TRUNCATE 94 + KEVFFL_DUMP(NOTE_TRUNCATE); 95 + #endif 96 + KEVFFL_DUMP(NOTE_ATTRIB); 97 + KEVFFL_DUMP(NOTE_LINK); 98 + KEVFFL_DUMP(NOTE_RENAME); 99 + #if HAVE_NOTE_REVOKE 100 + KEVFFL_DUMP(NOTE_REVOKE); 101 + #endif 102 + buf[strlen(buf) - 1] = ')'; 103 + 104 + return (buf); 105 + } 106 + 107 + char * 108 + kevent_flags_dump(struct kevent *kev) 109 + { 110 + char *buf; 111 + 112 + #define KEVFL_DUMP(attrib) \ 113 + if (kev->flags & attrib) \ 114 + strncat(buf, #attrib" ", 64); 115 + 116 + if ((buf = calloc(1, 1024)) == NULL) 117 + abort(); 118 + 119 + snprintf(buf, 1024, "flags = %d (", kev->flags); 120 + KEVFL_DUMP(EV_ADD); 121 + KEVFL_DUMP(EV_ENABLE); 122 + KEVFL_DUMP(EV_DISABLE); 123 + KEVFL_DUMP(EV_DELETE); 124 + KEVFL_DUMP(EV_ONESHOT); 125 + KEVFL_DUMP(EV_CLEAR); 126 + KEVFL_DUMP(EV_EOF); 127 + KEVFL_DUMP(EV_ERROR); 128 + #ifdef EV_DISPATCH 129 + KEVFL_DUMP(EV_DISPATCH); 130 + #endif 131 + #ifdef EV_RECEIPT 132 + KEVFL_DUMP(EV_RECEIPT); 133 + #endif 134 + buf[strlen(buf) - 1] = ')'; 135 + 136 + return (buf); 137 + } 138 + 139 + /* TODO - backport changes from src/common/kevent.c kevent_dump() */ 140 + const char * 141 + kevent_to_str(struct kevent *kev) 142 + { 143 + char buf[512]; 144 + 145 + snprintf(&buf[0], sizeof(buf), 146 + "[ident=%d, filter=%d, %s, %s, data=%d, udata=%p]", 147 + (u_int) kev->ident, 148 + kev->filter, 149 + kevent_flags_dump(kev), 150 + kevent_fflags_dump(kev), 151 + (int) kev->data, 152 + kev->udata); 153 + 154 + return (strdup(buf)); 155 + } 156 + 157 + void 158 + kevent_update(int kqfd, struct kevent *kev) 159 + { 160 + if (kevent(kqfd, kev, 1, NULL, 0, NULL) < 0) { 161 + printf("Unable to add the following kevent:\n%s\n", 162 + kevent_to_str(kev)); 163 + die("kevent"); 164 + } 165 + } 166 + 167 + void 168 + kevent_add(int kqfd, struct kevent *kev, 169 + uintptr_t ident, 170 + short filter, 171 + u_short flags, 172 + u_int fflags, 173 + intptr_t data, 174 + void *udata) 175 + { 176 + EV_SET(kev, ident, filter, flags, fflags, data, NULL); 177 + if (kevent(kqfd, kev, 1, NULL, 0, NULL) < 0) { 178 + printf("Unable to add the following kevent:\n%s\n", 179 + kevent_to_str(kev)); 180 + die("kevent"); 181 + } 182 + } 183 + 184 + void 185 + _kevent_cmp(struct kevent *k1, struct kevent *k2, const char *file, int line) 186 + { 187 + /* XXX- 188 + Workaround for inconsistent implementation of kevent(2) 189 + */ 190 + #if defined (__FreeBSD_kernel__) || defined (__FreeBSD__) 191 + if (k1->flags & EV_ADD) 192 + k2->flags |= EV_ADD; 193 + #endif 194 + if (memcmp(k1, k2, sizeof(*k1)) != 0) { 195 + printf("[%s:%d]: kevent_cmp() failed:\n expected %s\n but got %s\n", 196 + file, line, kevent_to_str(k1), kevent_to_str(k2)); 197 + abort(); 198 + } 199 + }
+280
external/libkqueue-2.0.1/test/main.c
··· 1 + /* 2 + * Copyright (c) 2009 Mark Heily <mark@heily.com> 3 + * 4 + * Permission to use, copy, modify, and distribute this software for any 5 + * purpose with or without fee is hereby granted, provided that the above 6 + * copyright notice and this permission notice appear in all copies. 7 + * 8 + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 9 + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 10 + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 11 + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 12 + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 13 + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 14 + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 15 + */ 16 + 17 + #include "common.h" 18 + 19 + /* Maximum number of threads that can be created */ 20 + #define MAX_THREADS 100 21 + 22 + void 23 + test_kqueue_descriptor_is_pollable(void) 24 + { 25 + int kq, rv; 26 + struct kevent kev; 27 + fd_set fds; 28 + struct timeval tv; 29 + 30 + if ((kq = kqueue()) < 0) 31 + die("kqueue()"); 32 + 33 + test_no_kevents(kq); 34 + kevent_add(kq, &kev, 2, EVFILT_TIMER, EV_ADD | EV_ONESHOT, 0, 1000, NULL); 35 + test_no_kevents(kq); 36 + 37 + FD_ZERO(&fds); 38 + FD_SET(kq, &fds); 39 + tv.tv_sec = 5; 40 + tv.tv_usec = 0; 41 + rv = select(1, &fds, NULL, NULL, &tv); 42 + if (rv < 0) 43 + die("select() error"); 44 + if (rv == 0) 45 + die("select() no events"); 46 + if (!FD_ISSET(kq, &fds)) { 47 + die("descriptor is not ready for reading"); 48 + } 49 + 50 + close(kq); 51 + } 52 + 53 + /* 54 + * Test the method for detecting when one end of a socketpair 55 + * has been closed. This technique is used in kqueue_validate() 56 + */ 57 + static void 58 + test_peer_close_detection(void *unused) 59 + { 60 + #ifdef _WIN32 61 + return; 62 + //FIXME 63 + #else 64 + int sockfd[2]; 65 + char buf[1]; 66 + struct pollfd pfd; 67 + 68 + if (socketpair(AF_UNIX, SOCK_STREAM, 0, sockfd) < 0) 69 + die("socketpair"); 70 + 71 + pfd.fd = sockfd[0]; 72 + pfd.events = POLLIN | POLLHUP; 73 + pfd.revents = 0; 74 + 75 + if (poll(&pfd, 1, 0) > 0) 76 + die("unexpected data"); 77 + 78 + if (close(sockfd[1]) < 0) 79 + die("close"); 80 + 81 + if (poll(&pfd, 1, 0) > 0) { 82 + if (recv(sockfd[0], buf, sizeof(buf), MSG_PEEK | MSG_DONTWAIT) != 0) 83 + die("failed to detect peer shutdown"); 84 + } 85 + #endif 86 + } 87 + 88 + void 89 + test_kqueue(void *unused) 90 + { 91 + int kqfd; 92 + 93 + if ((kqfd = kqueue()) < 0) 94 + die("kqueue()"); 95 + test_no_kevents(kqfd); 96 + if (close(kqfd) < 0) 97 + die("close()"); 98 + } 99 + 100 + void 101 + test_kevent(void *unused) 102 + { 103 + struct kevent kev; 104 + 105 + memset(&kev, 0, sizeof(kev)); 106 + 107 + /* Provide an invalid kqueue descriptor */ 108 + if (kevent(-1, &kev, 1, NULL, 0, NULL) == 0) 109 + die("invalid kq parameter"); 110 + } 111 + 112 + void 113 + test_ev_receipt(void *unused) 114 + { 115 + int kq; 116 + struct kevent kev; 117 + 118 + if ((kq = kqueue()) < 0) 119 + die("kqueue()"); 120 + #if defined(EV_RECEIPT) && !defined(_WIN32) 121 + 122 + EV_SET(&kev, SIGUSR2, EVFILT_SIGNAL, EV_ADD | EV_RECEIPT, 0, 0, NULL); 123 + if (kevent(kq, &kev, 1, &kev, 1, NULL) < 0) 124 + die("kevent"); 125 + 126 + /* TODO: check the receipt */ 127 + 128 + close(kq); 129 + #else 130 + memset(&kev, 0, sizeof(kev)); 131 + puts("Skipped -- EV_RECEIPT is not available or running on Win32"); 132 + #endif 133 + } 134 + 135 + void 136 + run_iteration(struct test_context *ctx) 137 + { 138 + struct unit_test *test; 139 + 140 + for (test = &ctx->tests[0]; test->ut_name != NULL; test++) { 141 + if (test->ut_enabled) 142 + test->ut_func(ctx); 143 + } 144 + free(ctx); 145 + } 146 + 147 + void 148 + test_harness(struct unit_test tests[MAX_TESTS], int iterations) 149 + { 150 + int i, n, kqfd; 151 + struct test_context *ctx; 152 + 153 + printf("Running %d iterations\n", iterations); 154 + 155 + testing_begin(); 156 + 157 + ctx = calloc(1, sizeof(*ctx)); 158 + 159 + test(peer_close_detection, ctx); 160 + 161 + test(kqueue, ctx); 162 + test(kevent, ctx); 163 + 164 + if ((kqfd = kqueue()) < 0) 165 + die("kqueue()"); 166 + 167 + test(ev_receipt, ctx); 168 + /* TODO: this fails now, but would be good later 169 + test(kqueue_descriptor_is_pollable); 170 + */ 171 + 172 + free(ctx); 173 + 174 + n = 0; 175 + for (i = 0; i < iterations; i++) { 176 + ctx = calloc(1, sizeof(*ctx)); 177 + if (ctx == NULL) 178 + abort(); 179 + ctx->iteration = n++; 180 + ctx->kqfd = kqfd; 181 + memcpy(&ctx->tests, tests, sizeof(ctx->tests)); 182 + ctx->iterations = iterations; 183 + 184 + run_iteration(ctx); 185 + } 186 + testing_end(); 187 + 188 + close(kqfd); 189 + } 190 + 191 + void 192 + usage(void) 193 + { 194 + printf("usage:\n" 195 + " -h This message\n" 196 + " -n Number of iterations (default: 1)\n" 197 + "\n\n" 198 + ); 199 + exit(1); 200 + } 201 + 202 + int 203 + main(int argc, char **argv) 204 + { 205 + struct unit_test tests[MAX_TESTS] = { 206 + { "socket", 1, test_evfilt_read }, 207 + #if !defined(_WIN32) && !defined(__ANDROID__) 208 + // XXX-FIXME -- BROKEN ON LINUX WHEN RUN IN A SEPARATE THREAD 209 + { "signal", 1, test_evfilt_signal }, 210 + #endif 211 + #if FIXME 212 + { "proc", 1, test_evfilt_proc }, 213 + #endif 214 + { "timer", 1, test_evfilt_timer }, 215 + #ifndef _WIN32 216 + { "vnode", 1, test_evfilt_vnode }, 217 + #endif 218 + #ifdef EVFILT_USER 219 + { "user", 1, test_evfilt_user }, 220 + #endif 221 + { NULL, 0, NULL }, 222 + }; 223 + struct unit_test *test; 224 + int c, i, iterations; 225 + char *arg; 226 + int match; 227 + 228 + #ifdef _WIN32 229 + /* Initialize the Winsock library */ 230 + WSADATA wsaData; 231 + if (WSAStartup(MAKEWORD(2,2), &wsaData) != 0) 232 + err(1, "WSAStartup failed"); 233 + #endif 234 + 235 + iterations = 1; 236 + 237 + /* Windows does not provide a POSIX-compatible getopt */ 238 + #ifndef _WIN32 239 + while ((c = getopt (argc, argv, "hn:")) != -1) { 240 + switch (c) { 241 + case 'h': 242 + usage(); 243 + break; 244 + case 'n': 245 + iterations = atoi(optarg); 246 + break; 247 + default: 248 + usage(); 249 + } 250 + } 251 + 252 + /* If specific tests are requested, disable all tests by default */ 253 + if (optind < argc) { 254 + for (test = &tests[0]; test->ut_name != NULL; test++) { 255 + test->ut_enabled = 0; 256 + } 257 + } 258 + for (i = optind; i < argc; i++) { 259 + match = 0; 260 + arg = argv[i]; 261 + for (test = &tests[0]; test->ut_name != NULL; test++) { 262 + if (strcmp(arg, test->ut_name) == 0) { 263 + test->ut_enabled = 1; 264 + match = 1; 265 + break; 266 + } 267 + } 268 + if (!match) { 269 + printf("ERROR: invalid option: %s\n", arg); 270 + exit(1); 271 + } else { 272 + printf("enabled test: %s\n", arg); 273 + } 274 + } 275 + #endif 276 + 277 + test_harness(tests, iterations); 278 + 279 + return (0); 280 + }
+229
external/libkqueue-2.0.1/test/proc.c
··· 1 + /* 2 + * Copyright (c) 2009 Mark Heily <mark@heily.com> 3 + * 4 + * Permission to use, copy, modify, and distribute this software for any 5 + * purpose with or without fee is hereby granted, provided that the above 6 + * copyright notice and this permission notice appear in all copies. 7 + * 8 + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 9 + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 10 + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 11 + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 12 + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 13 + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 14 + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 15 + */ 16 + 17 + #include "common.h" 18 + 19 + static int sigusr1_caught = 0; 20 + static pid_t pid; 21 + static int kqfd; 22 + 23 + static void 24 + sig_handler(int signum) 25 + { 26 + sigusr1_caught = 1; 27 + } 28 + 29 + static void 30 + test_kevent_proc_add(struct test_context *ctx) 31 + { 32 + struct kevent kev; 33 + 34 + test_no_kevents(kqfd); 35 + kevent_add(kqfd, &kev, pid, EVFILT_PROC, EV_ADD, 0, 0, NULL); 36 + test_no_kevents(kqfd); 37 + } 38 + 39 + static void 40 + test_kevent_proc_delete(struct test_context *ctx) 41 + { 42 + struct kevent kev; 43 + 44 + test_no_kevents(kqfd); 45 + kevent_add(kqfd, &kev, pid, EVFILT_PROC, EV_DELETE, 0, 0, NULL); 46 + if (kill(pid, SIGKILL) < 0) 47 + die("kill"); 48 + sleep(1); 49 + test_no_kevents(kqfd); 50 + } 51 + 52 + static void 53 + test_kevent_proc_get(struct test_context *ctx) 54 + { 55 + struct kevent kev, buf; 56 + 57 + /* Create a child that waits to be killed and then exits */ 58 + pid = fork(); 59 + if (pid == 0) { 60 + pause(); 61 + printf(" -- child caught signal, exiting\n"); 62 + exit(2); 63 + } 64 + printf(" -- child created (pid %d)\n", (int) pid); 65 + 66 + test_no_kevents(kqfd); 67 + kevent_add(kqfd, &kev, pid, EVFILT_PROC, EV_ADD, 0, 0, NULL); 68 + 69 + /* Cause the child to exit, then retrieve the event */ 70 + printf(" -- killing process %d\n", (int) pid); 71 + if (kill(pid, SIGUSR1) < 0) 72 + die("kill"); 73 + kevent_get(&buf, kqfd); 74 + kevent_cmp(&kev, &buf); 75 + test_no_kevents(kqfd); 76 + } 77 + 78 + #ifdef TODO 79 + void 80 + test_kevent_signal_disable(struct test_context *ctx) 81 + { 82 + const char *test_id = "kevent(EVFILT_SIGNAL, EV_DISABLE)"; 83 + struct kevent kev; 84 + 85 + test_begin(test_id); 86 + 87 + EV_SET(&kev, SIGUSR1, EVFILT_SIGNAL, EV_DISABLE, 0, 0, NULL); 88 + if (kevent(kqfd, &kev, 1, NULL, 0, NULL) < 0) 89 + die("%s", test_id); 90 + 91 + /* Block SIGUSR1, then send it to ourselves */ 92 + sigset_t mask; 93 + sigemptyset(&mask); 94 + sigaddset(&mask, SIGUSR1); 95 + if (sigprocmask(SIG_BLOCK, &mask, NULL) == -1) 96 + die("sigprocmask"); 97 + if (kill(getpid(), SIGKILL) < 0) 98 + die("kill"); 99 + 100 + test_no_kevents(); 101 + 102 + success(); 103 + } 104 + 105 + void 106 + test_kevent_signal_enable(struct test_context *ctx) 107 + { 108 + const char *test_id = "kevent(EVFILT_SIGNAL, EV_ENABLE)"; 109 + struct kevent kev; 110 + 111 + test_begin(test_id); 112 + 113 + EV_SET(&kev, SIGUSR1, EVFILT_SIGNAL, EV_ENABLE, 0, 0, NULL); 114 + if (kevent(kqfd, &kev, 1, NULL, 0, NULL) < 0) 115 + die("%s", test_id); 116 + 117 + /* Block SIGUSR1, then send it to ourselves */ 118 + sigset_t mask; 119 + sigemptyset(&mask); 120 + sigaddset(&mask, SIGUSR1); 121 + if (sigprocmask(SIG_BLOCK, &mask, NULL) == -1) 122 + die("sigprocmask"); 123 + if (kill(getpid(), SIGUSR1) < 0) 124 + die("kill"); 125 + 126 + kev.flags = EV_ADD | EV_CLEAR; 127 + #if LIBKQUEUE 128 + kev.data = 1; /* WORKAROUND */ 129 + #else 130 + kev.data = 2; // one extra time from test_kevent_signal_disable() 131 + #endif 132 + kevent_cmp(&kev, kevent_get(kqfd)); 133 + 134 + /* Delete the watch */ 135 + kev.flags = EV_DELETE; 136 + if (kevent(kqfd, &kev, 1, NULL, 0, NULL) < 0) 137 + die("%s", test_id); 138 + 139 + success(); 140 + } 141 + 142 + void 143 + test_kevent_signal_del(struct test_context *ctx) 144 + { 145 + const char *test_id = "kevent(EVFILT_SIGNAL, EV_DELETE)"; 146 + struct kevent kev; 147 + 148 + test_begin(test_id); 149 + 150 + /* Delete the kevent */ 151 + EV_SET(&kev, SIGUSR1, EVFILT_SIGNAL, EV_DELETE, 0, 0, NULL); 152 + if (kevent(kqfd, &kev, 1, NULL, 0, NULL) < 0) 153 + die("%s", test_id); 154 + 155 + /* Block SIGUSR1, then send it to ourselves */ 156 + sigset_t mask; 157 + sigemptyset(&mask); 158 + sigaddset(&mask, SIGUSR1); 159 + if (sigprocmask(SIG_BLOCK, &mask, NULL) == -1) 160 + die("sigprocmask"); 161 + if (kill(getpid(), SIGUSR1) < 0) 162 + die("kill"); 163 + 164 + test_no_kevents(); 165 + success(); 166 + } 167 + 168 + void 169 + test_kevent_signal_oneshot(struct test_context *ctx) 170 + { 171 + const char *test_id = "kevent(EVFILT_SIGNAL, EV_ONESHOT)"; 172 + struct kevent kev; 173 + 174 + test_begin(test_id); 175 + 176 + EV_SET(&kev, SIGUSR1, EVFILT_SIGNAL, EV_ADD | EV_ONESHOT, 0, 0, NULL); 177 + if (kevent(kqfd, &kev, 1, NULL, 0, NULL) < 0) 178 + die("%s", test_id); 179 + 180 + /* Block SIGUSR1, then send it to ourselves */ 181 + sigset_t mask; 182 + sigemptyset(&mask); 183 + sigaddset(&mask, SIGUSR1); 184 + if (sigprocmask(SIG_BLOCK, &mask, NULL) == -1) 185 + die("sigprocmask"); 186 + if (kill(getpid(), SIGUSR1) < 0) 187 + die("kill"); 188 + 189 + kev.flags |= EV_CLEAR; 190 + kev.data = 1; 191 + kevent_cmp(&kev, kevent_get(kqfd)); 192 + 193 + /* Send another one and make sure we get no events */ 194 + if (kill(getpid(), SIGUSR1) < 0) 195 + die("kill"); 196 + test_no_kevents(); 197 + 198 + success(); 199 + } 200 + #endif 201 + 202 + void 203 + test_evfilt_proc(struct test_context *ctx) 204 + { 205 + signal(SIGUSR1, sig_handler); 206 + 207 + /* Create a child that waits to be killed and then exits */ 208 + pid = fork(); 209 + if (pid == 0) { 210 + pause(); 211 + exit(2); 212 + } 213 + printf(" -- child created (pid %d)\n", (int) pid); 214 + 215 + test(kevent_proc_add, ctx); 216 + test(kevent_proc_delete, ctx); 217 + test(kevent_proc_get, ctx); 218 + 219 + signal(SIGUSR1, SIG_DFL); 220 + 221 + #if TODO 222 + test_kevent_signal_add(); 223 + test_kevent_signal_del(); 224 + test_kevent_signal_get(); 225 + test_kevent_signal_disable(); 226 + test_kevent_signal_enable(); 227 + test_kevent_signal_oneshot(); 228 + #endif 229 + }
+442
external/libkqueue-2.0.1/test/read.c
··· 1 + /* 2 + * Copyright (c) 2009 Mark Heily <mark@heily.com> 3 + * 4 + * Permission to use, copy, modify, and distribute this software for any 5 + * purpose with or without fee is hereby granted, provided that the above 6 + * copyright notice and this permission notice appear in all copies. 7 + * 8 + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 9 + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 10 + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 11 + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 12 + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 13 + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 14 + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 15 + */ 16 + 17 + 18 + #include "common.h" 19 + 20 + 21 + /* 22 + * Create a connected TCP socket. 23 + */ 24 + static void 25 + create_socket_connection(int *client, int *server, const short port) 26 + { 27 + struct sockaddr_in sain; 28 + socklen_t sa_len = sizeof(sain); 29 + int one = 1; 30 + int clnt, srvr, accepted; 31 + 32 + /* Create a passive socket */ 33 + memset(&sain, 0, sizeof(sain)); 34 + sain.sin_family = AF_INET; 35 + sain.sin_port = htons(port); 36 + if ((srvr = socket(PF_INET, SOCK_STREAM, 0)) < 0) 37 + err(1, "socket"); 38 + if (setsockopt(srvr, SOL_SOCKET, SO_REUSEADDR, 39 + (char *) &one, sizeof(one)) != 0) 40 + err(1, "setsockopt"); 41 + if (bind(srvr, (struct sockaddr *) &sain, sa_len) < 0) { 42 + printf("unable to bind to port %d\n", port); 43 + err(1, "bind-1"); 44 + } 45 + if (listen(srvr, 100) < 0) 46 + err(1, "listen"); 47 + 48 + /* Simulate a client connecting to the server */ 49 + sain.sin_family = AF_INET; 50 + sain.sin_port = htons(port); 51 + sain.sin_addr.s_addr = inet_addr("127.0.0.1"); 52 + if ((clnt = socket(AF_INET, SOCK_STREAM, 0)) < 0) 53 + err(1, "clnt: socket"); 54 + if (connect(clnt, (struct sockaddr *) &sain, sa_len) < 0) 55 + err(1, "clnt: connect"); 56 + if ((accepted = accept(srvr, NULL, 0)) < 0) 57 + err(1, "srvr: accept"); 58 + 59 + *client = clnt; 60 + *server = accepted; 61 + } 62 + 63 + static void 64 + kevent_socket_drain(struct test_context *ctx) 65 + { 66 + char buf[1]; 67 + 68 + /* Drain the read buffer, then make sure there are no more events. */ 69 + if (recv(ctx->client_fd, &buf[0], 1, 0) < 1) 70 + die("recv(2)"); 71 + } 72 + 73 + static void 74 + kevent_socket_fill(struct test_context *ctx) 75 + { 76 + if (send(ctx->server_fd, ".", 1, 0) < 1) 77 + die("send(2)"); 78 + } 79 + 80 + 81 + void 82 + test_kevent_socket_add(struct test_context *ctx) 83 + { 84 + struct kevent kev; 85 + 86 + kevent_add(ctx->kqfd, &kev, ctx->client_fd, EVFILT_READ, EV_ADD, 0, 0, &ctx->client_fd); 87 + } 88 + 89 + void 90 + test_kevent_socket_add_without_ev_add(struct test_context *ctx) 91 + { 92 + struct kevent kev; 93 + 94 + /* Try to add a kevent without specifying EV_ADD */ 95 + EV_SET(&kev, ctx->client_fd, EVFILT_READ, 0, 0, 0, &ctx->client_fd); 96 + if (kevent(ctx->kqfd, &kev, 1, NULL, 0, NULL) == 0) 97 + die("kevent should have failed"); 98 + 99 + kevent_socket_fill(ctx); 100 + test_no_kevents(ctx->kqfd); 101 + kevent_socket_drain(ctx); 102 + 103 + /* Try to delete a kevent which does not exist */ 104 + kev.flags = EV_DELETE; 105 + if (kevent(ctx->kqfd, &kev, 1, NULL, 0, NULL) == 0) 106 + die("kevent should have failed"); 107 + } 108 + 109 + void 110 + test_kevent_socket_get(struct test_context *ctx) 111 + { 112 + struct kevent kev, ret; 113 + 114 + EV_SET(&kev, ctx->client_fd, EVFILT_READ, EV_ADD, 0, 0, &ctx->client_fd); 115 + if (kevent(ctx->kqfd, &kev, 1, NULL, 0, NULL) < 0) 116 + die("kevent:1"); 117 + 118 + kevent_socket_fill(ctx); 119 + 120 + kev.data = 1; 121 + kevent_get(&ret, ctx->kqfd); 122 + kevent_cmp(&kev, &ret); 123 + 124 + kevent_socket_drain(ctx); 125 + test_no_kevents(ctx->kqfd); 126 + 127 + kev.flags = EV_DELETE; 128 + if (kevent(ctx->kqfd, &kev, 1, NULL, 0, NULL) < 0) 129 + die("kevent:2"); 130 + } 131 + 132 + void 133 + test_kevent_socket_clear(struct test_context *ctx) 134 + { 135 + struct kevent kev, ret; 136 + 137 + test_no_kevents(ctx->kqfd); 138 + kevent_socket_drain(ctx); 139 + 140 + EV_SET(&kev, ctx->client_fd, EVFILT_READ, EV_ADD | EV_CLEAR, 0, 0, &ctx->client_fd); 141 + if (kevent(ctx->kqfd, &kev, 1, NULL, 0, NULL) < 0) 142 + die("kevent1"); 143 + 144 + kevent_socket_fill(ctx); 145 + kevent_socket_fill(ctx); 146 + 147 + /* Solaris does not offer a way to get the amount of data pending */ 148 + #if defined(__sun__) 149 + kev.data = 1; 150 + #else 151 + kev.data = 2; 152 + #endif 153 + kevent_get(&ret, ctx->kqfd); 154 + kevent_cmp(&kev, &ret); 155 + 156 + /* We filled twice, but drain once. Edge-triggered would not generate 157 + additional events. 158 + */ 159 + kevent_socket_drain(ctx); 160 + test_no_kevents(ctx->kqfd); 161 + 162 + kevent_socket_drain(ctx); 163 + EV_SET(&kev, ctx->client_fd, EVFILT_READ, EV_DELETE, 0, 0, &ctx->client_fd); 164 + if (kevent(ctx->kqfd, &kev, 1, NULL, 0, NULL) < 0) 165 + die("kevent2"); 166 + } 167 + 168 + void 169 + test_kevent_socket_disable_and_enable(struct test_context *ctx) 170 + { 171 + struct kevent kev, ret; 172 + 173 + /* Add an event, then disable it. */ 174 + EV_SET(&kev, ctx->client_fd, EVFILT_READ, EV_ADD, 0, 0, &ctx->client_fd); 175 + if (kevent(ctx->kqfd, &kev, 1, NULL, 0, NULL) < 0) 176 + die("kevent"); 177 + EV_SET(&kev, ctx->client_fd, EVFILT_READ, EV_DISABLE, 0, 0, &ctx->client_fd); 178 + if (kevent(ctx->kqfd, &kev, 1, NULL, 0, NULL) < 0) 179 + die("kevent"); 180 + 181 + kevent_socket_fill(ctx); 182 + test_no_kevents(ctx->kqfd); 183 + 184 + /* Re-enable the knote, then see if an event is generated */ 185 + kev.flags = EV_ENABLE; 186 + if (kevent(ctx->kqfd, &kev, 1, NULL, 0, NULL) < 0) 187 + die("kevent"); 188 + kev.flags = EV_ADD; 189 + kev.data = 1; 190 + kevent_get(&ret, ctx->kqfd); 191 + kevent_cmp(&kev, &ret); 192 + 193 + kevent_socket_drain(ctx); 194 + 195 + kev.flags = EV_DELETE; 196 + if (kevent(ctx->kqfd, &kev, 1, NULL, 0, NULL) < 0) 197 + die("kevent"); 198 + } 199 + 200 + void 201 + test_kevent_socket_del(struct test_context *ctx) 202 + { 203 + struct kevent kev; 204 + 205 + EV_SET(&kev, ctx->client_fd, EVFILT_READ, EV_DELETE, 0, 0, &ctx->client_fd); 206 + if (kevent(ctx->kqfd, &kev, 1, NULL, 0, NULL) < 0) 207 + die("kevent"); 208 + 209 + kevent_socket_fill(ctx); 210 + test_no_kevents(ctx->kqfd); 211 + kevent_socket_drain(ctx); 212 + } 213 + 214 + void 215 + test_kevent_socket_oneshot(struct test_context *ctx) 216 + { 217 + struct kevent kev, ret; 218 + 219 + /* Re-add the watch and make sure no events are pending */ 220 + kevent_add(ctx->kqfd, &kev, ctx->client_fd, EVFILT_READ, EV_ADD | EV_ONESHOT, 0, 0, &ctx->client_fd); 221 + test_no_kevents(ctx->kqfd); 222 + 223 + kevent_socket_fill(ctx); 224 + kev.data = 1; 225 + kevent_get(&ret, ctx->kqfd); 226 + kevent_cmp(&kev, &ret); 227 + 228 + test_no_kevents(ctx->kqfd); 229 + 230 + /* Verify that the kernel watch has been deleted */ 231 + kevent_socket_fill(ctx); 232 + test_no_kevents(ctx->kqfd); 233 + kevent_socket_drain(ctx); 234 + 235 + /* Verify that the kevent structure does not exist. */ 236 + kev.flags = EV_DELETE; 237 + if (kevent(ctx->kqfd, &kev, 1, NULL, 0, NULL) == 0) 238 + die("kevent() should have failed"); 239 + } 240 + 241 + /* 242 + * Test if the data field returns 1 when a listen(2) socket has 243 + * a pending connection. 244 + */ 245 + void 246 + test_kevent_socket_listen_backlog(struct test_context *ctx) 247 + { 248 + struct kevent kev, ret; 249 + struct sockaddr_in sain; 250 + socklen_t sa_len = sizeof(sain); 251 + int one = 1; 252 + short port; 253 + int clnt, srvr; 254 + 255 + port = 14973 + ctx->iteration; 256 + 257 + /* Create a passive socket */ 258 + memset(&sain, 0, sizeof(sain)); 259 + sain.sin_family = AF_INET; 260 + sain.sin_port = htons(port); 261 + if ((srvr = socket(PF_INET, SOCK_STREAM, 0)) < 0) 262 + err(1, "socket()"); 263 + if (setsockopt(srvr, SOL_SOCKET, SO_REUSEADDR, 264 + (char *) &one, sizeof(one)) != 0) 265 + err(1, "setsockopt()"); 266 + if (bind(srvr, (struct sockaddr *) &sain, sa_len) < 0) 267 + err(1, "bind-2", port); 268 + if (listen(srvr, 100) < 0) 269 + err(1, "listen()"); 270 + 271 + /* Watch for events on the socket */ 272 + test_no_kevents(ctx->kqfd); 273 + kevent_add(ctx->kqfd, &kev, srvr, EVFILT_READ, EV_ADD | EV_ONESHOT, 0, 0, NULL); 274 + test_no_kevents(ctx->kqfd); 275 + 276 + /* Simulate a client connecting to the server */ 277 + sain.sin_family = AF_INET; 278 + sain.sin_port = htons(port); 279 + sain.sin_addr.s_addr = inet_addr("127.0.0.1"); 280 + if ((clnt = socket(AF_INET, SOCK_STREAM, 0)) < 0) 281 + err(1, "socket()"); 282 + if (connect(clnt, (struct sockaddr *) &sain, sa_len) < 0) 283 + err(1, "connect()"); 284 + 285 + /* Verify that data=1 */ 286 + kev.data = 1; 287 + kevent_get(&ret, ctx->kqfd); 288 + kevent_cmp(&kev, &ret); 289 + test_no_kevents(ctx->kqfd); 290 + } 291 + 292 + #ifdef EV_DISPATCH 293 + void 294 + test_kevent_socket_dispatch(struct test_context *ctx) 295 + { 296 + struct kevent kev, ret; 297 + 298 + /* Re-add the watch and make sure no events are pending */ 299 + kevent_add(ctx->kqfd, &kev, ctx->client_fd, EVFILT_READ, EV_ADD | EV_DISPATCH, 0, 0, &ctx->client_fd); 300 + test_no_kevents(ctx->kqfd); 301 + 302 + /* The event will occur only once, even though EV_CLEAR is not 303 + specified. */ 304 + kevent_socket_fill(ctx); 305 + kev.data = 1; 306 + kevent_get(&ret, ctx->kqfd); 307 + kevent_cmp(&kev, &ret); 308 + test_no_kevents(ctx->kqfd); 309 + 310 + /* Re-enable the kevent */ 311 + /* FIXME- is EV_DISPATCH needed when rearming ? */ 312 + kevent_add(ctx->kqfd, &kev, ctx->client_fd, EVFILT_READ, EV_ENABLE | EV_DISPATCH, 0, 0, &ctx->client_fd); 313 + kev.data = 1; 314 + kev.flags = EV_ADD | EV_DISPATCH; /* FIXME: may not be portable */ 315 + kevent_get(&ret, ctx->kqfd); 316 + kevent_cmp(&kev, &ret); 317 + test_no_kevents(ctx->kqfd); 318 + 319 + /* Since the knote is disabled, the EV_DELETE operation succeeds. */ 320 + kevent_add(ctx->kqfd, &kev, ctx->client_fd, EVFILT_READ, EV_DELETE, 0, 0, &ctx->client_fd); 321 + 322 + kevent_socket_drain(ctx); 323 + } 324 + #endif /* EV_DISPATCH */ 325 + 326 + #if BROKEN_ON_LINUX 327 + void 328 + test_kevent_socket_lowat(struct test_context *ctx) 329 + { 330 + struct kevent kev; 331 + 332 + test_begin(test_id); 333 + 334 + /* Re-add the watch and make sure no events are pending */ 335 + puts("-- re-adding knote, setting low watermark to 2 bytes"); 336 + EV_SET(&kev, ctx->client_fd, EVFILT_READ, EV_ADD | EV_ONESHOT, NOTE_LOWAT, 2, &ctx->client_fd); 337 + if (kevent(ctx->kqfd, &kev, 1, NULL, 0, NULL) < 0) 338 + die("%s", test_id); 339 + test_no_kevents(); 340 + 341 + puts("-- checking that one byte does not trigger an event.."); 342 + kevent_socket_fill(ctx); 343 + test_no_kevents(); 344 + 345 + puts("-- checking that two bytes triggers an event.."); 346 + kevent_socket_fill(ctx); 347 + if (kevent(ctx->kqfd, NULL, 0, &kev, 1, NULL) != 1) 348 + die("%s", test_id); 349 + KEV_CMP(kev, ctx->client_fd, EVFILT_READ, 0); 350 + test_no_kevents(); 351 + 352 + kevent_socket_drain(ctx); 353 + kevent_socket_drain(ctx); 354 + } 355 + #endif 356 + 357 + void 358 + test_kevent_socket_eof(struct test_context *ctx) 359 + { 360 + struct kevent kev, ret; 361 + 362 + /* Re-add the watch and make sure no events are pending */ 363 + kevent_add(ctx->kqfd, &kev, ctx->client_fd, EVFILT_READ, EV_ADD, 0, 0, &ctx->client_fd); 364 + test_no_kevents(ctx->kqfd); 365 + 366 + //if (shutdown(ctx->server_fd, SHUT_RDWR) < 0) 367 + // die("close(2)"); 368 + if (close(ctx->server_fd) < 0) 369 + die("close(2)"); 370 + 371 + kev.flags |= EV_EOF; 372 + kevent_get(&ret, ctx->kqfd); 373 + kevent_cmp(&kev, &ret); 374 + 375 + /* Delete the watch */ 376 + kevent_add(ctx->kqfd, &kev, ctx->client_fd, EVFILT_READ, EV_DELETE, 0, 0, &ctx->client_fd); 377 + } 378 + 379 + /* Test if EVFILT_READ works with regular files */ 380 + void 381 + test_kevent_regular_file(struct test_context *ctx) 382 + { 383 + struct kevent kev, ret; 384 + off_t curpos; 385 + int fd; 386 + 387 + fd = open("/etc/hosts", O_RDONLY); 388 + if (fd < 0) 389 + abort(); 390 + 391 + EV_SET(&kev, fd, EVFILT_READ, EV_ADD, 0, 0, &fd); 392 + if (kevent(ctx->kqfd, &kev, 1, NULL, 0, NULL) < 0) 393 + die("kevent"); 394 + 395 + kevent_get(&ret, ctx->kqfd); 396 + 397 + /* Set file position to EOF-1 */ 398 + ret.data--; 399 + if ((curpos = lseek(fd, ret.data, SEEK_SET)) != ret.data) { 400 + printf("seek to %u failed with rv=%lu\n", 401 + (unsigned int) ret.data, curpos); 402 + abort(); 403 + } 404 + 405 + /* Set file position to EOF */ 406 + kevent_get(NULL, ctx->kqfd); 407 + ret.data = curpos + 1; 408 + if ((curpos = lseek(fd, ret.data, SEEK_SET)) != ret.data) { 409 + printf("seek to %u failed with rv=%lu\n", 410 + (unsigned int) ret.data, curpos); 411 + abort(); 412 + } 413 + 414 + test_no_kevents(ctx->kqfd); 415 + 416 + kev.flags = EV_DELETE; 417 + if (kevent(ctx->kqfd, &kev, 1, NULL, 0, NULL) < 0) 418 + die("kevent"); 419 + close(fd); 420 + } 421 + 422 + void 423 + test_evfilt_read(struct test_context *ctx) 424 + { 425 + create_socket_connection(&ctx->client_fd, &ctx->server_fd, ctx->iteration + 23456); 426 + 427 + test(kevent_socket_add, ctx); 428 + test(kevent_socket_del, ctx); 429 + test(kevent_socket_add_without_ev_add, ctx); 430 + test(kevent_socket_get, ctx); 431 + test(kevent_socket_disable_and_enable, ctx); 432 + test(kevent_socket_oneshot, ctx); 433 + test(kevent_socket_clear, ctx); 434 + #ifdef EV_DISPATCH 435 + test(kevent_socket_dispatch, ctx); 436 + #endif 437 + test(kevent_socket_listen_backlog, ctx); 438 + test(kevent_socket_eof, ctx); 439 + test(kevent_regular_file, ctx); 440 + close(ctx->client_fd); 441 + close(ctx->server_fd); 442 + }
+194
external/libkqueue-2.0.1/test/signal.c
··· 1 + /* 2 + * Copyright (c) 2009 Mark Heily <mark@heily.com> 3 + * 4 + * Permission to use, copy, modify, and distribute this software for any 5 + * purpose with or without fee is hereby granted, provided that the above 6 + * copyright notice and this permission notice appear in all copies. 7 + * 8 + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 9 + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 10 + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 11 + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 12 + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 13 + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 14 + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 15 + */ 16 + 17 + #include "common.h" 18 + 19 + void 20 + test_kevent_signal_add(struct test_context *ctx) 21 + { 22 + struct kevent kev; 23 + 24 + kevent_add(ctx->kqfd, &kev, SIGUSR1, EVFILT_SIGNAL, EV_ADD, 0, 0, NULL); 25 + } 26 + 27 + void 28 + test_kevent_signal_get(struct test_context *ctx) 29 + { 30 + struct kevent kev, ret; 31 + 32 + kevent_add(ctx->kqfd, &kev, SIGUSR1, EVFILT_SIGNAL, EV_ADD, 0, 0, NULL); 33 + 34 + if (kill(getpid(), SIGUSR1) < 0) 35 + die("kill"); 36 + 37 + kev.flags |= EV_CLEAR; 38 + kev.data = 1; 39 + kevent_get(&ret, ctx->kqfd); 40 + kevent_cmp(&kev, &ret); 41 + } 42 + 43 + void 44 + test_kevent_signal_disable(struct test_context *ctx) 45 + { 46 + struct kevent kev; 47 + 48 + kevent_add(ctx->kqfd, &kev, SIGUSR1, EVFILT_SIGNAL, EV_DISABLE, 0, 0, NULL); 49 + 50 + if (kill(getpid(), SIGUSR1) < 0) 51 + die("kill"); 52 + 53 + test_no_kevents(ctx->kqfd); 54 + } 55 + 56 + void 57 + test_kevent_signal_enable(struct test_context *ctx) 58 + { 59 + struct kevent kev, ret; 60 + 61 + kevent_add(ctx->kqfd, &kev, SIGUSR1, EVFILT_SIGNAL, EV_ENABLE, 0, 0, NULL); 62 + 63 + if (kill(getpid(), SIGUSR1) < 0) 64 + die("kill"); 65 + 66 + kev.flags = EV_ADD | EV_CLEAR; 67 + #if LIBKQUEUE 68 + kev.data = 1; /* WORKAROUND */ 69 + #else 70 + kev.data = 2; // one extra time from test_kevent_signal_disable() 71 + #endif 72 + kevent_get(&ret, ctx->kqfd); 73 + kevent_cmp(&kev, &ret); 74 + 75 + /* Delete the watch */ 76 + kev.flags = EV_DELETE; 77 + if (kevent(ctx->kqfd, &kev, 1, NULL, 0, NULL) < 0) 78 + die("kevent"); 79 + } 80 + 81 + void 82 + test_kevent_signal_del(struct test_context *ctx) 83 + { 84 + struct kevent kev; 85 + 86 + /* Delete the kevent */ 87 + kevent_add(ctx->kqfd, &kev, SIGUSR1, EVFILT_SIGNAL, EV_DELETE, 0, 0, NULL); 88 + 89 + signal(SIGUSR1, SIG_IGN); 90 + if (kill(getpid(), SIGUSR1) < 0) 91 + die("kill"); 92 + 93 + test_no_kevents(ctx->kqfd); 94 + } 95 + 96 + void 97 + test_kevent_signal_oneshot(struct test_context *ctx) 98 + { 99 + struct kevent kev, ret; 100 + 101 + kevent_add(ctx->kqfd, &kev, SIGUSR1, EVFILT_SIGNAL, EV_ADD | EV_ONESHOT, 0, 0, NULL); 102 + 103 + if (kill(getpid(), SIGUSR1) < 0) 104 + die("kill"); 105 + 106 + kev.flags |= EV_CLEAR; 107 + kev.data = 1; 108 + kevent_get(&ret, ctx->kqfd); 109 + kevent_cmp(&kev, &ret); 110 + 111 + /* Send another one and make sure we get no events */ 112 + test_no_kevents(ctx->kqfd); 113 + if (kill(getpid(), SIGUSR1) < 0) 114 + die("kill"); 115 + test_no_kevents(ctx->kqfd); 116 + } 117 + 118 + void 119 + test_kevent_signal_modify(struct test_context *ctx) 120 + { 121 + struct kevent kev, ret; 122 + 123 + kevent_add(ctx->kqfd, &kev, SIGUSR1, EVFILT_SIGNAL, EV_ADD, 0, 0, NULL); 124 + kevent_add(ctx->kqfd, &kev, SIGUSR1, EVFILT_SIGNAL, EV_ADD, 0, 0, ((void *)-1)); 125 + 126 + if (kill(getpid(), SIGUSR1) < 0) 127 + die("kill"); 128 + 129 + kev.flags |= EV_CLEAR; 130 + kev.data = 1; 131 + kevent_get(&ret, ctx->kqfd); 132 + kevent_cmp(&kev, &ret); 133 + 134 + test_kevent_signal_del(ctx); 135 + } 136 + 137 + #ifdef EV_DISPATCH 138 + void 139 + test_kevent_signal_dispatch(struct test_context *ctx) 140 + { 141 + struct kevent kev, ret; 142 + 143 + test_no_kevents(ctx->kqfd); 144 + 145 + kevent_add(ctx->kqfd, &kev, SIGUSR1, EVFILT_SIGNAL, EV_ADD | EV_CLEAR | EV_DISPATCH, 0, 0, NULL); 146 + 147 + /* Get one event */ 148 + if (kill(getpid(), SIGUSR1) < 0) 149 + die("kill"); 150 + kev.data = 1; 151 + kevent_get(&ret, ctx->kqfd); 152 + kevent_cmp(&kev, &ret); 153 + 154 + /* Confirm that the knote is disabled */ 155 + if (kill(getpid(), SIGUSR1) < 0) 156 + die("kill"); 157 + test_no_kevents(ctx->kqfd); 158 + 159 + /* Enable the knote and make sure no events are pending */ 160 + kevent_add(ctx->kqfd, &kev, SIGUSR1, EVFILT_SIGNAL, EV_ENABLE | EV_DISPATCH, 0, 0, NULL); 161 + test_no_kevents(ctx->kqfd); 162 + 163 + /* Get the next event */ 164 + if (kill(getpid(), SIGUSR1) < 0) 165 + die("kill"); 166 + kev.flags = EV_ADD | EV_CLEAR | EV_DISPATCH; 167 + kev.data = 1; 168 + kevent_get(&ret, ctx->kqfd); 169 + kevent_cmp(&kev, &ret); 170 + 171 + /* Remove the knote and ensure the event no longer fires */ 172 + kevent_add(ctx->kqfd, &kev, SIGUSR1, EVFILT_SIGNAL, EV_DELETE, 0, 0, NULL); 173 + if (kill(getpid(), SIGUSR1) < 0) 174 + die("kill"); 175 + test_no_kevents(ctx->kqfd); 176 + } 177 + #endif /* EV_DISPATCH */ 178 + 179 + void 180 + test_evfilt_signal(struct test_context *ctx) 181 + { 182 + signal(SIGUSR1, SIG_IGN); 183 + 184 + test(kevent_signal_add, ctx); 185 + test(kevent_signal_del, ctx); 186 + test(kevent_signal_get, ctx); 187 + test(kevent_signal_disable, ctx); 188 + test(kevent_signal_enable, ctx); 189 + test(kevent_signal_oneshot, ctx); 190 + test(kevent_signal_modify, ctx); 191 + #ifdef EV_DISPATCH 192 + test(kevent_signal_dispatch, ctx); 193 + #endif 194 + }
+112
external/libkqueue-2.0.1/test/test.c
··· 1 + /* 2 + * Copyright (c) 2009 Mark Heily <mark@heily.com> 3 + * 4 + * Permission to use, copy, modify, and distribute this software for any 5 + * purpose with or without fee is hereby granted, provided that the above 6 + * copyright notice and this permission notice appear in all copies. 7 + * 8 + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 9 + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 10 + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 11 + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 12 + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 13 + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 14 + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 15 + */ 16 + 17 + #if defined(__linux__) && !defined(__ANDROID__) 18 + #include <execinfo.h> 19 + #endif 20 + #include <sys/types.h> 21 + #include <limits.h> 22 + 23 + #include "common.h" 24 + 25 + static int testnum = 1; 26 + static int error_flag = 1; 27 + 28 + /* FIXME: not portable beyond linux */ 29 + #ifndef _WIN32 30 + static void 31 + error_handler(int signum) 32 + { 33 + #if defined(__linux__) && !defined(__ANDROID__) 34 + void *buf[32]; 35 + 36 + /* FIXME: the symbols aren't printing */ 37 + printf("***** ERROR: Program received signal %d *****\n", signum); 38 + backtrace_symbols_fd(buf, sizeof(buf) / sizeof(void *), 2); 39 + #else 40 + printf("***** ERROR: Program received signal %d *****\n", signum); 41 + #endif 42 + exit(1); 43 + } 44 + #endif /* ! _WIN32 */ 45 + 46 + static void 47 + testing_atexit(void) 48 + { 49 + if (error_flag) { 50 + printf(" *** TEST FAILED ***\n"); 51 + //TODO: print detailed log 52 + } else { 53 + printf("\n---\n" 54 + "+OK All %d tests completed.\n", testnum - 1); 55 + } 56 + } 57 + 58 + void 59 + test_begin(struct test_context *ctx, const char *func) 60 + { 61 + if (ctx->cur_test_id) 62 + free(ctx->cur_test_id); 63 + ctx->cur_test_id = strdup(func); 64 + 65 + printf("%d: %s\n", testnum++, ctx->cur_test_id); 66 + //TODO: redirect stdout/err to logfile 67 + } 68 + 69 + void 70 + test_end(struct test_context *ctx) 71 + { 72 + free(ctx->cur_test_id); 73 + ctx->cur_test_id = NULL; 74 + } 75 + 76 + void 77 + testing_begin(void) 78 + { 79 + #ifndef _WIN32 80 + struct sigaction sa; 81 + 82 + /* Install a signal handler for crashes and hangs */ 83 + memset(&sa, 0, sizeof(sa)); 84 + sa.sa_handler = error_handler; 85 + sigemptyset(&sa.sa_mask); 86 + sigaction(SIGSEGV, &sa, NULL); 87 + sigaction(SIGABRT, &sa, NULL); 88 + sigaction(SIGINT, &sa, NULL); 89 + #endif 90 + 91 + atexit(testing_atexit); 92 + 93 + } 94 + 95 + void 96 + testing_end(void) 97 + { 98 + error_flag = 0; 99 + } 100 + 101 + /* Generate a unique ID */ 102 + int 103 + testing_make_uid(void) 104 + { 105 + static int id = 0; 106 + 107 + if (id == INT_MAX) 108 + abort(); 109 + id++; 110 + 111 + return (id); 112 + }
+170
external/libkqueue-2.0.1/test/timer.c
··· 1 + /* 2 + * Copyright (c) 2009 Mark Heily <mark@heily.com> 3 + * 4 + * Permission to use, copy, modify, and distribute this software for any 5 + * purpose with or without fee is hereby granted, provided that the above 6 + * copyright notice and this permission notice appear in all copies. 7 + * 8 + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 9 + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 10 + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 11 + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 12 + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 13 + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 14 + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 15 + */ 16 + 17 + #include "common.h" 18 + 19 + void 20 + test_kevent_timer_add(struct test_context *ctx) 21 + { 22 + struct kevent kev; 23 + 24 + kevent_add(ctx->kqfd, &kev, 1, EVFILT_TIMER, EV_ADD, 0, 1000, NULL); 25 + } 26 + 27 + void 28 + test_kevent_timer_del(struct test_context *ctx) 29 + { 30 + struct kevent kev; 31 + 32 + kevent_add(ctx->kqfd, &kev, 1, EVFILT_TIMER, EV_DELETE, 0, 0, NULL); 33 + 34 + test_no_kevents(ctx->kqfd); 35 + } 36 + 37 + void 38 + test_kevent_timer_get(struct test_context *ctx) 39 + { 40 + struct kevent kev, ret; 41 + 42 + kevent_add(ctx->kqfd, &kev, 1, EVFILT_TIMER, EV_ADD, 0, 1000, NULL); 43 + 44 + kev.flags |= EV_CLEAR; 45 + kev.data = 1; 46 + kevent_get(&ret, ctx->kqfd); 47 + kevent_cmp(&kev, &ret); 48 + 49 + kevent_add(ctx->kqfd, &kev, 1, EVFILT_TIMER, EV_DELETE, 0, 0, NULL); 50 + } 51 + 52 + static void 53 + test_kevent_timer_oneshot(struct test_context *ctx) 54 + { 55 + struct kevent kev, ret; 56 + 57 + test_no_kevents(ctx->kqfd); 58 + 59 + kevent_add(ctx->kqfd, &kev, 2, EVFILT_TIMER, EV_ADD | EV_ONESHOT, 0, 500,NULL); 60 + 61 + /* Retrieve the event */ 62 + kev.flags = EV_ADD | EV_CLEAR | EV_ONESHOT; 63 + kev.data = 1; 64 + kevent_get(&ret, ctx->kqfd); 65 + kevent_cmp(&kev, &ret); 66 + 67 + /* Check if the event occurs again */ 68 + sleep(3); 69 + test_no_kevents(ctx->kqfd); 70 + } 71 + 72 + static void 73 + test_kevent_timer_periodic(struct test_context *ctx) 74 + { 75 + struct kevent kev, ret; 76 + 77 + test_no_kevents(ctx->kqfd); 78 + 79 + kevent_add(ctx->kqfd, &kev, 3, EVFILT_TIMER, EV_ADD, 0, 1000,NULL); 80 + 81 + /* Retrieve the event */ 82 + kev.flags = EV_ADD | EV_CLEAR; 83 + kev.data = 1; 84 + kevent_get(&ret, ctx->kqfd); 85 + kevent_cmp(&kev, &ret); 86 + 87 + /* Check if the event occurs again */ 88 + sleep(1); 89 + kevent_get(&ret, ctx->kqfd); 90 + kevent_cmp(&kev, &ret); 91 + 92 + /* Delete the event */ 93 + kev.flags = EV_DELETE; 94 + kevent_update(ctx->kqfd, &kev); 95 + } 96 + 97 + static void 98 + test_kevent_timer_disable_and_enable(struct test_context *ctx) 99 + { 100 + struct kevent kev, ret; 101 + 102 + test_no_kevents(ctx->kqfd); 103 + 104 + /* Add the watch and immediately disable it */ 105 + kevent_add(ctx->kqfd, &kev, 4, EVFILT_TIMER, EV_ADD | EV_ONESHOT, 0, 2000,NULL); 106 + kev.flags = EV_DISABLE; 107 + kevent_update(ctx->kqfd, &kev); 108 + test_no_kevents(ctx->kqfd); 109 + 110 + /* Re-enable and check again */ 111 + kev.flags = EV_ENABLE; 112 + kevent_update(ctx->kqfd, &kev); 113 + 114 + kev.flags = EV_ADD | EV_CLEAR | EV_ONESHOT; 115 + kev.data = 1; 116 + kevent_get(&ret, ctx->kqfd); 117 + kevent_cmp(&kev, &ret); 118 + } 119 + 120 + #ifdef EV_DISPATCH 121 + void 122 + test_kevent_timer_dispatch(struct test_context *ctx) 123 + { 124 + struct kevent kev, ret; 125 + 126 + test_no_kevents(ctx->kqfd); 127 + 128 + kevent_add(ctx->kqfd, &kev, 4, EVFILT_TIMER, EV_ADD | EV_DISPATCH, 0, 800, NULL); 129 + 130 + /* Get one event */ 131 + kev.flags = EV_ADD | EV_CLEAR | EV_DISPATCH; 132 + kev.data = 1; 133 + kevent_get(&ret, ctx->kqfd); 134 + kevent_cmp(&kev, &ret); 135 + 136 + /* Confirm that the knote is disabled */ 137 + sleep(1); 138 + test_no_kevents(ctx->kqfd); 139 + 140 + /* Enable the knote and make sure no events are pending */ 141 + kevent_add(ctx->kqfd, &kev, 4, EVFILT_TIMER, EV_ENABLE | EV_DISPATCH, 0, 800, NULL); 142 + test_no_kevents(ctx->kqfd); 143 + 144 + /* Get the next event */ 145 + sleep(1); 146 + kev.flags = EV_ADD | EV_CLEAR | EV_DISPATCH; 147 + kev.data = 1; 148 + kevent_get(&ret, ctx->kqfd); 149 + kevent_cmp(&kev, &ret); 150 + 151 + /* Remove the knote and ensure the event no longer fires */ 152 + kevent_add(ctx->kqfd, &kev, 4, EVFILT_TIMER, EV_DELETE, 0, 0, NULL); 153 + sleep(1); 154 + test_no_kevents(ctx->kqfd); 155 + } 156 + #endif /* EV_DISPATCH */ 157 + 158 + void 159 + test_evfilt_timer(struct test_context *ctx) 160 + { 161 + test(kevent_timer_add, ctx); 162 + test(kevent_timer_del, ctx); 163 + test(kevent_timer_get, ctx); 164 + test(kevent_timer_oneshot, ctx); 165 + test(kevent_timer_periodic, ctx); 166 + test(kevent_timer_disable_and_enable, ctx); 167 + #ifdef EV_DISPATCH 168 + test(kevent_timer_dispatch, ctx); 169 + #endif 170 + }
+170
external/libkqueue-2.0.1/test/user.c
··· 1 + /* 2 + * Copyright (c) 2009 Mark Heily <mark@heily.com> 3 + * 4 + * Permission to use, copy, modify, and distribute this software for any 5 + * purpose with or without fee is hereby granted, provided that the above 6 + * copyright notice and this permission notice appear in all copies. 7 + * 8 + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 9 + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 10 + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 11 + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 12 + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 13 + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 14 + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 15 + */ 16 + 17 + #include "common.h" 18 + 19 + static void 20 + test_kevent_user_add_and_delete(struct test_context *ctx) 21 + { 22 + struct kevent kev; 23 + 24 + kevent_add(ctx->kqfd, &kev, 1, EVFILT_USER, EV_ADD, 0, 0, NULL); 25 + test_no_kevents(ctx->kqfd); 26 + 27 + kevent_add(ctx->kqfd, &kev, 1, EVFILT_USER, EV_DELETE, 0, 0, NULL); 28 + test_no_kevents(ctx->kqfd); 29 + } 30 + 31 + static void 32 + test_kevent_user_get(struct test_context *ctx) 33 + { 34 + struct kevent kev, ret; 35 + 36 + test_no_kevents(ctx->kqfd); 37 + 38 + /* Add the event, and then trigger it */ 39 + kevent_add(ctx->kqfd, &kev, 1, EVFILT_USER, EV_ADD | EV_CLEAR, 0, 0, NULL); 40 + kevent_add(ctx->kqfd, &kev, 1, EVFILT_USER, 0, NOTE_TRIGGER, 0, NULL); 41 + 42 + kev.fflags &= ~NOTE_FFCTRLMASK; 43 + kev.fflags &= ~NOTE_TRIGGER; 44 + kev.flags = EV_CLEAR; 45 + kevent_get(&ret, ctx->kqfd); 46 + kevent_cmp(&kev, &ret); 47 + 48 + test_no_kevents(ctx->kqfd); 49 + } 50 + 51 + static void 52 + test_kevent_user_get_hires(struct test_context *ctx) 53 + { 54 + struct kevent kev, ret; 55 + 56 + test_no_kevents(ctx->kqfd); 57 + 58 + /* Add the event, and then trigger it */ 59 + kevent_add(ctx->kqfd, &kev, 1, EVFILT_USER, EV_ADD | EV_CLEAR, 0, 0, NULL); 60 + kevent_add(ctx->kqfd, &kev, 1, EVFILT_USER, 0, NOTE_TRIGGER, 0, NULL); 61 + 62 + kev.fflags &= ~NOTE_FFCTRLMASK; 63 + kev.fflags &= ~NOTE_TRIGGER; 64 + kev.flags = EV_CLEAR; 65 + kevent_get_hires(&ret, ctx->kqfd); 66 + kevent_cmp(&kev, &ret); 67 + 68 + test_no_kevents(ctx->kqfd); 69 + } 70 + 71 + static void 72 + test_kevent_user_disable_and_enable(struct test_context *ctx) 73 + { 74 + struct kevent kev, ret; 75 + 76 + test_no_kevents(ctx->kqfd); 77 + 78 + kevent_add(ctx->kqfd, &kev, 1, EVFILT_USER, EV_ADD, 0, 0, NULL); 79 + kevent_add(ctx->kqfd, &kev, 1, EVFILT_USER, EV_DISABLE, 0, 0, NULL); 80 + 81 + /* Trigger the event, but since it is disabled, nothing will happen. */ 82 + kevent_add(ctx->kqfd, &kev, 1, EVFILT_USER, 0, NOTE_TRIGGER, 0, NULL); 83 + test_no_kevents(ctx->kqfd); 84 + 85 + kevent_add(ctx->kqfd, &kev, 1, EVFILT_USER, EV_ENABLE, 0, 0, NULL); 86 + kevent_add(ctx->kqfd, &kev, 1, EVFILT_USER, 0, NOTE_TRIGGER, 0, NULL); 87 + 88 + kev.flags = EV_CLEAR; 89 + kev.fflags &= ~NOTE_FFCTRLMASK; 90 + kev.fflags &= ~NOTE_TRIGGER; 91 + kevent_get(&ret, ctx->kqfd); 92 + kevent_cmp(&kev, &ret); 93 + } 94 + 95 + static void 96 + test_kevent_user_oneshot(struct test_context *ctx) 97 + { 98 + struct kevent kev, ret; 99 + 100 + test_no_kevents(ctx->kqfd); 101 + 102 + kevent_add(ctx->kqfd, &kev, 2, EVFILT_USER, EV_ADD | EV_ONESHOT, 0, 0, NULL); 103 + 104 + puts(" -- event 1"); 105 + kevent_add(ctx->kqfd, &kev, 2, EVFILT_USER, 0, NOTE_TRIGGER, 0, NULL); 106 + 107 + kev.flags = EV_ONESHOT; 108 + kev.fflags &= ~NOTE_FFCTRLMASK; 109 + kev.fflags &= ~NOTE_TRIGGER; 110 + kevent_get(&ret, ctx->kqfd); 111 + kevent_cmp(&kev, &ret); 112 + 113 + test_no_kevents(ctx->kqfd); 114 + } 115 + 116 + #ifdef EV_DISPATCH 117 + void 118 + test_kevent_user_dispatch(struct test_context *ctx) 119 + { 120 + struct kevent kev, ret; 121 + 122 + test_no_kevents(ctx->kqfd); 123 + 124 + /* Add the event, and then trigger it */ 125 + kevent_add(ctx->kqfd, &kev, 1, EVFILT_USER, EV_ADD | EV_CLEAR | EV_DISPATCH, 0, 0, NULL); 126 + kevent_add(ctx->kqfd, &kev, 1, EVFILT_USER, 0, NOTE_TRIGGER, 0, NULL); 127 + 128 + /* Retrieve one event */ 129 + kev.fflags &= ~NOTE_FFCTRLMASK; 130 + kev.fflags &= ~NOTE_TRIGGER; 131 + kev.flags = EV_CLEAR; 132 + kevent_get(&ret, ctx->kqfd); 133 + kevent_cmp(&kev, &ret); 134 + 135 + /* Confirm that the knote is disabled automatically */ 136 + test_no_kevents(ctx->kqfd); 137 + 138 + /* Re-enable the kevent */ 139 + /* FIXME- is EV_DISPATCH needed when rearming ? */ 140 + kevent_add(ctx->kqfd, &kev, 1, EVFILT_USER, EV_ENABLE | EV_CLEAR | EV_DISPATCH, 0, 0, NULL); 141 + test_no_kevents(ctx->kqfd); 142 + 143 + /* Trigger the event */ 144 + kevent_add(ctx->kqfd, &kev, 1, EVFILT_USER, 0, NOTE_TRIGGER, 0, NULL); 145 + kev.fflags &= ~NOTE_FFCTRLMASK; 146 + kev.fflags &= ~NOTE_TRIGGER; 147 + kev.flags = EV_CLEAR; 148 + kevent_get(&ret, ctx->kqfd); 149 + kevent_cmp(&kev, &ret); 150 + test_no_kevents(ctx->kqfd); 151 + 152 + /* Delete the watch */ 153 + kevent_add(ctx->kqfd, &kev, 1, EVFILT_USER, EV_DELETE, 0, 0, NULL); 154 + test_no_kevents(ctx->kqfd); 155 + } 156 + #endif /* EV_DISPATCH */ 157 + 158 + void 159 + test_evfilt_user(struct test_context *ctx) 160 + { 161 + test(kevent_user_add_and_delete, ctx); 162 + test(kevent_user_get, ctx); 163 + test(kevent_user_get_hires, ctx); 164 + test(kevent_user_disable_and_enable, ctx); 165 + test(kevent_user_oneshot, ctx); 166 + #ifdef EV_DISPATCH 167 + test(kevent_user_dispatch, ctx); 168 + #endif 169 + /* TODO: try different fflags operations */ 170 + }
+272
external/libkqueue-2.0.1/test/vnode.c
··· 1 + /* 2 + * Copyright (c) 2009 Mark Heily <mark@heily.com> 3 + * 4 + * Permission to use, copy, modify, and distribute this software for any 5 + * purpose with or without fee is hereby granted, provided that the above 6 + * copyright notice and this permission notice appear in all copies. 7 + * 8 + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 9 + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 10 + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 11 + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 12 + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 13 + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 14 + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 15 + */ 16 + 17 + #include "common.h" 18 + 19 + /* Create an empty file */ 20 + static void 21 + testfile_create(const char *path) 22 + { 23 + int fd; 24 + 25 + if ((fd = open(path, O_CREAT | O_WRONLY, 0600)) < 0) 26 + die("open"); 27 + close(fd); 28 + } 29 + 30 + static void 31 + testfile_touch(const char *path) 32 + { 33 + char buf[1024]; 34 + 35 + snprintf(&buf[0], sizeof(buf), "touch %s", path); 36 + if (system(buf) != 0) 37 + die("system"); 38 + } 39 + 40 + static void 41 + testfile_write(const char *path) 42 + { 43 + char buf[1024]; 44 + 45 + snprintf(&buf[0], sizeof(buf), "echo hi >> %s", path); 46 + if (system(buf) != 0) 47 + die("system"); 48 + } 49 + 50 + static void 51 + testfile_rename(const char *path, int step) 52 + { 53 + char buf[1024]; 54 + 55 + snprintf(&buf[0], sizeof(buf), "%s.tmp", path); 56 + /* XXX-FIXME use of 'step' conceals a major memory corruption 57 + when the file is renamed twice. 58 + To replicate, remove "if step" conditional so 59 + two renames occur in this function. 60 + */ 61 + if (step == 0) { 62 + if (rename(path, buf) != 0) 63 + err(1,"rename"); 64 + } else { 65 + if (rename(buf, path) != 0) 66 + err(1,"rename"); 67 + } 68 + } 69 + 70 + void 71 + test_kevent_vnode_add(struct test_context *ctx) 72 + { 73 + struct kevent kev; 74 + 75 + testfile_create(ctx->testfile); 76 + 77 + ctx->vnode_fd = open(ctx->testfile, O_RDWR); 78 + if (ctx->vnode_fd < 0) 79 + err(1, "open of %s", ctx->testfile); 80 + 81 + kevent_add(ctx->kqfd, &kev, ctx->vnode_fd, EVFILT_VNODE, EV_ADD, 82 + NOTE_WRITE | NOTE_ATTRIB | NOTE_RENAME | NOTE_DELETE, 0, NULL); 83 + } 84 + 85 + void 86 + test_kevent_vnode_note_delete(struct test_context *ctx) 87 + { 88 + struct kevent kev, ret; 89 + 90 + kevent_add(ctx->kqfd, &kev, ctx->vnode_fd, EVFILT_VNODE, EV_ADD | EV_ONESHOT, NOTE_DELETE, 0, NULL); 91 + 92 + if (unlink(ctx->testfile) < 0) 93 + die("unlink"); 94 + 95 + kevent_get(&ret, ctx->kqfd); 96 + kevent_cmp(&kev, &ret); 97 + } 98 + 99 + void 100 + test_kevent_vnode_note_write(struct test_context *ctx) 101 + { 102 + struct kevent kev, ret; 103 + 104 + kevent_add(ctx->kqfd, &kev, ctx->vnode_fd, EVFILT_VNODE, EV_ADD | EV_ONESHOT, NOTE_WRITE, 0, NULL); 105 + 106 + testfile_write(ctx->testfile); 107 + 108 + /* BSD kqueue adds NOTE_EXTEND even though it was not requested */ 109 + /* BSD kqueue removes EV_ENABLE */ 110 + kev.flags &= ~EV_ENABLE; // XXX-FIXME compatibility issue 111 + kev.fflags |= NOTE_EXTEND; // XXX-FIXME compatibility issue 112 + kevent_get(&ret, ctx->kqfd); 113 + kevent_cmp(&kev, &ret); 114 + } 115 + 116 + void 117 + test_kevent_vnode_note_attrib(struct test_context *ctx) 118 + { 119 + struct kevent kev; 120 + int nfds; 121 + 122 + kevent_add(ctx->kqfd, &kev, ctx->vnode_fd, EVFILT_VNODE, EV_ADD | EV_ONESHOT, NOTE_ATTRIB, 0, NULL); 123 + 124 + testfile_touch(ctx->testfile); 125 + 126 + nfds = kevent(ctx->kqfd, NULL, 0, &kev, 1, NULL); 127 + if (nfds < 1) 128 + die("kevent"); 129 + if (kev.ident != ctx->vnode_fd || 130 + kev.filter != EVFILT_VNODE || 131 + kev.fflags != NOTE_ATTRIB) 132 + err(1, "%s - incorrect event (sig=%u; filt=%d; flags=%d)", 133 + test_id, (unsigned int)kev.ident, kev.filter, kev.flags); 134 + } 135 + 136 + void 137 + test_kevent_vnode_note_rename(struct test_context *ctx) 138 + { 139 + struct kevent kev; 140 + int nfds; 141 + 142 + kevent_add(ctx->kqfd, &kev, ctx->vnode_fd, EVFILT_VNODE, EV_ADD | EV_ONESHOT, NOTE_RENAME, 0, NULL); 143 + 144 + testfile_rename(ctx->testfile, 0); 145 + 146 + nfds = kevent(ctx->kqfd, NULL, 0, &kev, 1, NULL); 147 + if (nfds < 1) 148 + die("kevent"); 149 + if (kev.ident != ctx->vnode_fd || 150 + kev.filter != EVFILT_VNODE || 151 + kev.fflags != NOTE_RENAME) 152 + err(1, "%s - incorrect event (sig=%u; filt=%d; flags=%d)", 153 + test_id, (unsigned int)kev.ident, kev.filter, kev.flags); 154 + 155 + testfile_rename(ctx->testfile, 1); 156 + 157 + test_no_kevents(ctx->kqfd); 158 + } 159 + 160 + void 161 + test_kevent_vnode_del(struct test_context *ctx) 162 + { 163 + struct kevent kev; 164 + 165 + kevent_add(ctx->kqfd, &kev, ctx->vnode_fd, EVFILT_VNODE, EV_DELETE, 0, 0, NULL); 166 + } 167 + 168 + void 169 + test_kevent_vnode_disable_and_enable(struct test_context *ctx) 170 + { 171 + struct kevent kev; 172 + int nfds; 173 + 174 + test_no_kevents(ctx->kqfd); 175 + 176 + /* Add the watch and immediately disable it */ 177 + kevent_add(ctx->kqfd, &kev, ctx->vnode_fd, EVFILT_VNODE, EV_ADD | EV_ONESHOT, NOTE_ATTRIB, 0, NULL); 178 + kev.flags = EV_DISABLE; 179 + kevent_update(ctx->kqfd, &kev); 180 + 181 + /* Confirm that the watch is disabled */ 182 + testfile_touch(ctx->testfile); 183 + test_no_kevents(ctx->kqfd); 184 + 185 + /* Re-enable and check again */ 186 + kev.flags = EV_ENABLE; 187 + kevent_update(ctx->kqfd, &kev); 188 + testfile_touch(ctx->testfile); 189 + nfds = kevent(ctx->kqfd, NULL, 0, &kev, 1, NULL); 190 + if (nfds < 1) 191 + die("kevent"); 192 + if (kev.ident != ctx->vnode_fd || 193 + kev.filter != EVFILT_VNODE || 194 + kev.fflags != NOTE_ATTRIB) 195 + err(1, "%s - incorrect event (sig=%u; filt=%d; flags=%d)", 196 + test_id, (unsigned int)kev.ident, kev.filter, kev.flags); 197 + } 198 + 199 + #ifdef EV_DISPATCH 200 + void 201 + test_kevent_vnode_dispatch(struct test_context *ctx) 202 + { 203 + struct kevent kev, ret; 204 + int nfds; 205 + 206 + test_no_kevents(ctx->kqfd); 207 + 208 + kevent_add(ctx->kqfd, &kev, ctx->vnode_fd, EVFILT_VNODE, EV_ADD | EV_DISPATCH, NOTE_ATTRIB, 0, NULL); 209 + 210 + testfile_touch(ctx->testfile); 211 + 212 + nfds = kevent(ctx->kqfd, NULL, 0, &kev, 1, NULL); 213 + if (nfds < 1) 214 + die("kevent"); 215 + if (kev.ident != ctx->vnode_fd || 216 + kev.filter != EVFILT_VNODE || 217 + kev.fflags != NOTE_ATTRIB) 218 + err(1, "%s - incorrect event (sig=%u; filt=%d; flags=%d)", 219 + test_id, (unsigned int)kev.ident, kev.filter, kev.flags); 220 + 221 + /* Confirm that the watch is disabled automatically */ 222 + testfile_touch(ctx->testfile); 223 + test_no_kevents(ctx->kqfd); 224 + 225 + /* Re-enable the kevent */ 226 + /* FIXME- is EV_DISPATCH needed when rearming ? */ 227 + kevent_add(ctx->kqfd, &kev, ctx->vnode_fd, EVFILT_VNODE, EV_ENABLE | EV_DISPATCH, 0, 0, NULL); 228 + kev.flags = EV_ADD | EV_DISPATCH; /* FIXME: may not be portable */ 229 + kev.fflags = NOTE_ATTRIB; 230 + testfile_touch(ctx->testfile); 231 + kevent_get(&ret, ctx->kqfd); 232 + kevent_cmp(&kev, &ret); 233 + test_no_kevents(ctx->kqfd); 234 + 235 + /* Delete the watch */ 236 + kevent_add(ctx->kqfd, &kev, ctx->vnode_fd, EVFILT_VNODE, EV_DELETE, NOTE_ATTRIB, 0, NULL); 237 + } 238 + #endif /* EV_DISPATCH */ 239 + 240 + void 241 + test_evfilt_vnode(struct test_context *ctx) 242 + { 243 + #if (defined(__sun) && !defined(HAVE_PORT_SOURCE_FILE)) 244 + puts("**NOTE** EVFILT_VNODE is not supported on this version of Solaris"); 245 + return; 246 + #endif 247 + 248 + char *tmpdir = getenv("TMPDIR"); 249 + if (tmpdir == NULL) 250 + #ifdef __ANDROID__ 251 + tmpdir = "/data/local/tmp"; 252 + #else 253 + tmpdir = "/tmp"; 254 + #endif 255 + 256 + snprintf(ctx->testfile, sizeof(ctx->testfile), "%s/kqueue-test%d.tmp", 257 + tmpdir, testing_make_uid()); 258 + 259 + test(kevent_vnode_add, ctx); 260 + test(kevent_vnode_del, ctx); 261 + test(kevent_vnode_disable_and_enable, ctx); 262 + #ifdef EV_DISPATCH 263 + test(kevent_vnode_dispatch, ctx); 264 + #endif 265 + test(kevent_vnode_note_write, ctx); 266 + test(kevent_vnode_note_attrib, ctx); 267 + test(kevent_vnode_note_rename, ctx); 268 + test(kevent_vnode_note_delete, ctx); 269 + /* TODO: test r590 corner case where a descriptor is closed and 270 + the associated knote is automatically freed. */ 271 + unlink(ctx->testfile); 272 + }
+1
external/libpthread_workqueue
··· 1 + libpthread_workqueue-0.8.2
+160
external/libpthread_workqueue-0.8.2/ChangeLog
··· 1 + Version 0.8.2 r195 2 + released 7/16/2011 3 + --- 4 + 5 + * Use LDADD instead of LDFLAGS (fixes Debian bug #631674) 6 + * Make the "idle" test optional as it does not work on 32-bit Linux 7 + * Use time_t for PWQ_SPIN_USEC to fix a build problem on 32-bit Linux 8 + 9 + Version 0.8.1 r? 10 + released 7/16/2011 11 + --- 12 + 13 + * Uploaded to Debian, but not generally released. 14 + 15 + Version 0.8 r190 16 + released 7/08/2011 17 + --- 18 + 19 + * Remove the 'struct worker' datatype and related housekeeping chores. 20 + 21 + * Fix incorrect usage of pthread_cond_timedwait() for overcommit threads. 22 + 23 + * Various improvements and bug fixes for the Windows port. 24 + 25 + * Prevent a race condition that could cause a use-after-free if a witem 26 + were freed before manager_workqueue_additem() returned. 27 + 28 + * Prevent races involving the scoreboard variables. 29 + 30 + * Fix a lost wakeup bug when calling worker_stop(). 31 + 32 + * Finally fixed the long standing TODO and removed the global lock for pwq enqueue/dequeue. 33 + 34 + * Only signal wakeups for the pool if there are idle threads available to process data. 35 + 36 + * Use atomics for updating the mask with pending workqueues as the global lock was removed. 37 + 38 + * 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. 39 + 40 + * Renamed USE_RT_THREADS to PWQ_RT_THREADS for consistency. 41 + 42 + * 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. 43 + 44 + Version 0.7.1 r157 45 + released 7/02/2011 46 + --- 47 + 48 + * Fix a memory leak in worker_overcommit_main() when reaping idle threads. 49 + 50 + Version 0.7 r150 51 + released 6/13/2011 52 + --- 53 + 54 + * Replace pthread emulation macros with winpthreads.h from 55 + http://locklessinc.com/articles/pthreads_on_windows/ 56 + 57 + * Fix witem_cache test to link on solaris also 58 + 59 + * Avoid possible overrun of priority level 60 + 61 + * Fixed possible deadlock. 62 + 63 + * Cleaned up witem cache interface and usage for easier reading of code. 64 + 65 + * Link with libumem on Solaris 66 + 67 + * Add -Wextra to CFLAGS and fix the related warnings 68 + 69 + * Implement the workqueue overcommit attribute. 70 + Make wqlist an array instead of an array of lists. 71 + Change wqlist_scan() to be more efficient. 72 + 73 + Version 0.6 r134 74 + released 5/16/2011 75 + --- 76 + 77 + * Add a pthread_atfork() handler to reinitialize the library after fork(). 78 + 79 + * Defer the manager thread creation until pthread_workqueue_create_np(). 80 + 81 + Version 0.5.1 r125 82 + released 5/7/2011 83 + --- 84 + 85 + * Fix the testing/latency Makefile to work on 32-bit Linux. 86 + * Remove unused variables from testing/latency.c 87 + 88 + Version 0.5 r120 89 + released 5/6/2011 90 + --- 91 + 92 + * Add CMakeLists.txt for building under CMake. 93 + 94 + * Support building on Windows under MinGW and MSVC. 95 + 96 + * 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). 97 + 98 + * 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...). 99 + 100 + * Create a witem_cache_init() function so that the TLS key can be made private to witem_cache.o 101 + 102 + * Fix compilation on 32-bit Linux (Credit: Marius Zwicker) 103 + 104 + * Don't reset the signal mask, it should be blocked for the manager thread (and any subsequently started threads) as well 105 + 106 + * 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 107 + 108 + * Add option for static library build activated by defining MAKE_STATIC 109 + 110 + * Enable debugging on windows by an environment variable as well 111 + 112 + Version 0.4.1 r99 113 + released 3/13/2011 114 + --- 115 + 116 + * Add -lpthread to LDFLAGS 117 + 118 + Version 0.4 r97 119 + released 3/12/2011 120 + --- 121 + 122 + * Improved printf debugging; to use it, define the environment variable "PWQ_DEBUG=yes" 123 + 124 + * New function threads_runnable() determines how many LWPs are on the run queue and uses 125 + this information to improve the thread pool management heuristic. 126 + 127 + * All ELF symbols are now hidden by default, and only the public API symbols are visible. 128 + 129 + * Improved workqueue ramp-up and ramp-down behavior. 130 + 131 + Version 0.3 r81 132 + released 3/6/2011 133 + --- 134 + 135 + * Fix DESTDIR support in the 'make install' target. 136 + 137 + Version 0.2 r77 138 + released 3/6/2011 139 + --- 140 + 141 + * Add support for FreeBSD, Solaris, and Microsoft Windows 142 + 143 + * Fix a race condition that would cause deadlock in rare cases when either: 144 + 1) pthread_cond_signal() was called while no other threads were 145 + blocked a call to pthread_cond_wait(), or 146 + 2) pthread_cond_signal() was called multiple times before the any thread 147 + blocking in a call to pthread_cond_wait() was awoken by the scheduler. 148 + 149 + The fix is to ensure that the call to pthread_cond_signal() occurs while 150 + the calling thread holds the same mutex used by the threads that call 151 + pthread_cond_wait(). 152 + 153 + Credit to Joakim Johansson for finding the bug and providing a patch. 154 + 155 + Version 0.1 r? 156 + released 6/13/2010 157 + --- 158 + 159 + * Initial release for Debian as a patch applied to libdispatch. There 160 + was no tarball released for this version.
+118
external/libpthread_workqueue-0.8.2/Makefile
··· 1 + # 2 + # Copyright (c) 2010 Mark Heily <mark@heily.com> 3 + # 4 + # Permission to use, copy, modify, and distribute this software for any 5 + # purpose with or without fee is hereby granted, provided that the above 6 + # copyright notice and this permission notice appear in all copies. 7 + # 8 + # THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 9 + # WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 10 + # MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 11 + # ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 12 + # WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 13 + # ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 14 + # OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 15 + # 16 + 17 + # Flags to pass to dpkg-buildpackage 18 + DPKGFLAGS=-uc -us 19 + 20 + .PHONY :: install uninstall check dist dist-upload publish-www clean merge distclean fresh-build rpm edit cscope valgrind testing 21 + 22 + include config.mk 23 + 24 + all: $(PROGRAM).so testing 25 + 26 + %.dll: $(OBJS) 27 + $(LD) -o $@ $(LDFLAGS) $(OBJS) $(LDADD) 28 + 29 + %.o: %.c $(DEPS) 30 + $(CC) -c -o $@ $(CFLAGS) $< 31 + 32 + $(PROGRAM).a: $(OBJS) 33 + $(AR) rcs $(PROGRAM).a $(OBJS) 34 + 35 + $(PROGRAM).so: $(OBJS) 36 + $(LD) -shared $(LDFLAGS) $(OBJS) $(LDADD) 37 + $(LN) -sf $(PROGRAM).so.$(ABI_VERSION) $(PROGRAM).so 38 + $(LN) -sf $(PROGRAM).so.$(ABI_VERSION) $(PROGRAM).so.$(ABI_MAJOR) 39 + 40 + install: $(PROGRAM).so 41 + $(INSTALL) -d -m 755 $(DESTDIR)$(INCLUDEDIR) 42 + $(INSTALL) -d -m 755 $(DESTDIR)$(LIBDIR) 43 + $(INSTALL) -m 644 $(HEADERS) $(DESTDIR)$(INCLUDEDIR) 44 + $(INSTALL) -m 644 $(PROGRAM).so.$(ABI_VERSION) $(DESTDIR)$(LIBDIR) 45 + $(LN) -sf $(PROGRAM).so.$(ABI_VERSION) $(DESTDIR)$(LIBDIR)/$(PROGRAM).so.$(ABI_MAJOR) 46 + $(LN) -sf $(PROGRAM).so.$(ABI_VERSION) $(DESTDIR)$(LIBDIR)/$(PROGRAM).so 47 + $(INSTALL) -d -m 755 $(DESTDIR)$(MANDIR)/man3 48 + $(INSTALL) -m 644 pthread_workqueue.3 $(DESTDIR)$(MANDIR)/man3/pthread_workqueue.3 49 + 50 + uninstall: 51 + rm -f $(INCLUDEDIR)/pthread_workqueue.h 52 + rm -f $(LIBDIR)/pthread_workqueue.so 53 + rm -f $(LIBDIR)/pthread_workqueue.so.* 54 + rm -f $(LIBDIR)/pthread_workqueue.a 55 + rm -f $(MANDIR)/man3/pthread_workqueue.3 56 + 57 + reinstall: uninstall install 58 + 59 + check: $(PROGRAM).so 60 + cd testing && make check 61 + 62 + edit: 63 + $(EDITOR) `find ./src -name '*.c' -o -name '*.h'` Makefile 64 + 65 + $(PROGRAM)-$(VERSION).tar.gz: 66 + mkdir $(PROGRAM)-$(VERSION) 67 + cp Makefile ChangeLog configure config.inc $(MANS) $(PROGRAM)-$(VERSION) 68 + cp -R src testing include $(PROGRAM)-$(VERSION) 69 + find $(PROGRAM)-$(VERSION) -name '.svn' -exec rm -rf {} \; 2>/dev/null || true 70 + tar zcf $(PROGRAM)-$(VERSION).tar.gz $(PROGRAM)-$(VERSION) 71 + rm -rf $(PROGRAM)-$(VERSION) 72 + 73 + testing: 74 + cd testing && make 75 + 76 + dist: clean $(PROGRAM)-$(VERSION).tar.gz 77 + 78 + %.asc: 79 + gpg --armor --detach-sign `echo '$@' | sed 's/.asc$$//'` 80 + 81 + dist-upload: dist $(DISTFILE).asc 82 + scp $(DISTFILE) $(DISTFILE).asc heily.com:/var/www/heily.com/dist/$(PROGRAM) 83 + 84 + publish-www: 85 + cp -R www/* ~/public_html/libkqueue/ 86 + 87 + clean: 88 + rm -f tags $(DISTFILE) $(DISTFILE).asc *.a $(OBJS) *.pc *.so *.so.* test-$(PROGRAM) 89 + cd testing && make clean 90 + rm -rf pkg 91 + 92 + distclean: clean 93 + rm -f *.tar.gz config.mk config.h $(PROGRAM).pc $(PROGRAM).la rpm.spec 94 + rm -rf $(PROGRAM)-$(VERSION) 2>/dev/null || true 95 + 96 + rpm: clean $(DISTFILE) 97 + rm -rf rpm *.rpm *.deb 98 + mkdir -p rpm/BUILD rpm/RPMS rpm/SOURCES rpm/SPECS rpm/SRPMS 99 + mkdir -p rpm/RPMS/i386 rpm/RPMS/x86_64 100 + cp $(DISTFILE) rpm/SOURCES 101 + rpmbuild -bb rpm.spec 102 + mv ./rpm/RPMS/* . 103 + rm -rf rpm 104 + rmdir i386 x86_64 # WORKAROUND: These aren't supposed to exist 105 + fakeroot alien --scripts *.rpm 106 + 107 + deb: clean $(DISTFILE) 108 + mkdir pkg 109 + cd pkg && tar zxf ../$(DISTFILE) && mv libpthread_workqueue-$(VERSION) libpthread-workqueue-$(VERSION) 110 + cp $(DISTFILE) pkg/libpthread-workqueue_$(VERSION).orig.tar.gz 111 + cp -R ports/debian pkg/libpthread-workqueue-$(VERSION) 112 + cd pkg && \ 113 + rm -rf `find libpthread-workqueue-$(VERSION)/debian -type d -name .svn` ; \ 114 + perl -pi -e 's/\@\@VERSION\@\@/$(VERSION)/' libpthread-workqueue-$(VERSION)/debian/changelog ; \ 115 + cd libpthread-workqueue-$(VERSION) && dpkg-buildpackage $(DPKGFLAGS) 116 + lintian -i pkg/*.deb 117 + @printf "\nThe following packages have been created:\n" 118 + @find ./pkg -name '*.deb' | sed 's/^/ /'
+57
external/libpthread_workqueue-0.8.2/config.inc
··· 1 + program="libpthread_workqueue" 2 + version="0.8.2" 3 + abi_major="0" 4 + abi_minor="0" 5 + abi_version="$abi_major.$abi_minor" 6 + cflags="-Wall -Wextra -Werror -D_XOPEN_SOURCE=600 -D__EXTENSIONS__ -D_GNU_SOURCE -std=c99 -I./include -I./src" 7 + ldflags="" 8 + ldadd="-lpthread -lrt" 9 + sources='src/api.c src/$(API)/manager.c src/$(API)/thread_info.c src/witem_cache.c src/$(API)/thread_rt.c' 10 + libdepends="" 11 + deps="src/*.h" 12 + mans="pthread_workqueue.3" 13 + headers="include/pthread_workqueue.h" 14 + extra_dist="LICENSE" 15 + subdirs="" 16 + 17 + # Package metadata 18 + pkg_summary="pthread_workqueue library" 19 + pkg_description="pthread_workqueue library" 20 + license="BSD" 21 + author="Mark Heily" 22 + 23 + pre_configure_hook() { 24 + if [ "$debug" = "yes" ] ; then 25 + cflags="$cflags -g3 -O0 -DPTHREAD_WORKQUEUE_DEBUG -rdynamic" 26 + else 27 + cflags="$cflags -g -O2" 28 + fi 29 + check_header err.h 30 + } 31 + 32 + post_configure_hook() { 33 + 34 + cflags="$cflags" 35 + case "$target" in 36 + windows) 37 + cflags="$cflags -mthreads" 38 + ldflags="$ldflags -mthreads" 39 + ;; 40 + solaris) 41 + # TODO: would like to have -fvisibility=hidden but not supported 42 + # by SFWgcc 43 + # 44 + cflags="$cflags -m64 -fpic" 45 + ldflags="$ldflags -m64 -fpic -lumem" 46 + ;; 47 + *) 48 + if [ "`uname -m`" = "x86_64" ] ; then 49 + arch_flags="-m64" 50 + else 51 + arch_flags="" 52 + fi 53 + cflags="$cflags $arch_flags -fpic -fvisibility=hidden -pthread" 54 + ldflags="$ldflags $arch_flags -fpic -pthread" 55 + ;; 56 + esac 57 + }
+351
external/libpthread_workqueue-0.8.2/configure
··· 1 + #!/bin/sh 2 + # 3 + # Copyright (c) 2009-2011 Mark Heily <mark@heily.com> 4 + # 5 + # Permission to use, copy, modify, and distribute this software for any 6 + # purpose with or without fee is hereby granted, provided that the above 7 + # copyright notice and this permission notice appear in all copies. 8 + # 9 + # THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 10 + # WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 11 + # MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 12 + # ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 13 + # WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 14 + # ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 15 + # OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 16 + # 17 + 18 + makeconf_version="$Revision: 10 $" 19 + 20 + c_exports="program version target api cflags" 21 + 22 + make_exports="program version target api distfile basedir \ 23 + prefix bindir sbindir libdir includedir mandir \ 24 + cflags ldflags ldadd libdepends \ 25 + sources objs deps mans headers extra_dist subdirs \ 26 + abi_major abi_minor abi_version \ 27 + cc cpp ld ln ar install diff" 28 + 29 + required_headers= 30 + optional_headers= 31 + 32 + pre_configure_hook() { 33 + return 34 + } 35 + 36 + post_configure_hook() { 37 + return 38 + } 39 + 40 + export_to_make() { 41 + for id in $* 42 + do 43 + uc_id=`echo $id | $tr '[:lower:]' '[:upper:]'`; 44 + eval "echo \"$uc_id=\"\$$id\"\" >> config.mk" 45 + done 46 + } 47 + 48 + export_to_c() { 49 + for id in $* 50 + do 51 + uc_id=`echo $id | $tr '[:lower:]' '[:upper:]'`; 52 + eval "echo \"#define $uc_id \\\"\$$id\\\"\" >> config.h" 53 + done 54 + } 55 + 56 + finalize() { 57 + uc_id=`echo \"$1\" | $tr '[:lower:]' '[:upper:]'`; 58 + eval "if [ \"\$$1\" = \"\" ] ; then $1=\"$2\" ; fi" 59 + } 60 + 61 + process_argv() { 62 + for arg in $* 63 + do 64 + if [ "$arg" = "--makeconf-version" ] ; then 65 + echo $makeconf_version | sed 's/[^0-9.]//g' 66 + exit 0 67 + fi 68 + id=`echo "$arg" | sed 's/=.*//; s/^--//;'` 69 + val=`echo "$arg" | sed 's/^.*=//'` 70 + if [ "$val" = "" ] ; then val=1 ; fi 71 + eval "$id=\"$val\"" 72 + done 73 + } 74 + 75 + process_env() { 76 + test -n "$CC" && cc="$CC" 77 + test -n "$CPP" && cpp="$CPP" 78 + test -n "$CPPFLAGS" && cppflags="$CPPFLAGS" 79 + test -n "$CFLAGS" && cflags="$CFLAGS" 80 + test -n "$LD" && ld="$LD" 81 + test -n "$LN" && ld="$LN" 82 + test -n "$LDFLAGS" && ldflags="$LDFLAGS" 83 + test -n "$AR" && ar="$AR" 84 + basedir=`pwd` 85 + } 86 + 87 + check_header() { 88 + sym=`echo "have_$1" | sed 's,[./],_,g'` 89 + uc_sym=`echo "$sym" | $tr '[:lower:]' '[:upper:]'`; 90 + path=$1 91 + 92 + printf "checking for $path.. " 93 + if [ -f "/usr/include/$path" ] ; then 94 + echo "yes" 95 + echo "#define $uc_sym 1" >> config.h 96 + eval "$sym=yes" 97 + return 0 98 + else 99 + echo "no" 100 + echo "#undef $uc_sym" >> config.h 101 + eval "$sym=no" 102 + return 1 103 + fi 104 + } 105 + 106 + # Determine the path to an executable binary 107 + check_binary() { 108 + id=$1 109 + shift 110 + 111 + for path in $* 112 + do 113 + test -f $path 114 + if [ $? = 0 ] ; then 115 + eval "$id=\"$path\"" 116 + return 117 + fi 118 + done 119 + 120 + echo "not found" 121 + return 122 + } 123 + 124 + check_headers() { 125 + for header in $* 126 + do 127 + check_header "$header" 128 + done 129 + } 130 + 131 + check_symbol() { 132 + header=$1 133 + symbol=$2 134 + 135 + uc_symbol=`echo "HAVE_$symbol" | $tr '[:lower:]' '[:upper:]' | sed 's,[./],_,g'` 136 + lc_symbol=`echo "have_$symbol" | $tr '[:upper:]' '[:lower:]' | sed 's,[./],_,g'` 137 + 138 + if [ -f "$header" ] ; then 139 + path="$header" 140 + elif [ -f "/usr/include/$header" ] ; then 141 + path="/usr/include/$header" 142 + else 143 + echo "*** ERROR: Cannot find <$header>" 144 + exit 1 145 + fi 146 + 147 + printf "checking $header for $symbol.. " 148 + if [ "`grep $symbol $path`" != "" ] ; then 149 + eval "$lc_symbol=yes" 150 + echo "#define $uc_symbol 1" >> config.h 151 + echo "yes" 152 + return 0 153 + else 154 + eval "$lc_symbol=no" 155 + echo "no" 156 + echo "#undef $uc_symbol" >> config.h 157 + return 1 158 + fi 159 + } 160 + 161 + check_install() { 162 + printf "checking for a BSD-compatible install.. " 163 + if [ "`uname -s`" = "SunOS" ] ; then 164 + default_install=/usr/ucb/install 165 + else 166 + default_install=/usr/bin/install 167 + fi 168 + finalize install "$default_install" 169 + echo "$install" 170 + } 171 + 172 + check_target() { 173 + printf "checking operating system type.. " 174 + default_target=`uname -s | $tr '[:upper:]' '[:lower:]'` 175 + default_api="posix" 176 + case "$default_target" in 177 + sunos) 178 + default_target="solaris" 179 + ;; 180 + "gnu/kfreebsd") 181 + default_target="freebsd" 182 + ;; 183 + mingw*) 184 + default_target="windows" 185 + default_api="windows" 186 + ;; 187 + esac 188 + finalize target "$default_target" 189 + finalize api "$default_api" 190 + echo "$api" 191 + } 192 + 193 + check_compiler() { 194 + printf "checking for a C compiler.. " 195 + check_binary default_cc "$cc" "`which $cc 2>/dev/null`" "/usr/bin/cc" "/usr/bin/gcc" "/usr/sfw/bin/gcc" "`which gcc 2>/dev/null`" 196 + finalize cc "$default_cc" 197 + # test -x "$cc" || err "Unable to locate a C compiler" 198 + echo "$cc" 199 + } 200 + 201 + check_linker() { 202 + printf "checking for a suitable linker.. " 203 + 204 + # Workaround for "hidden symbol <foo> is referenced by DSO" linker error 205 + # seen when compiling libdispatch. 206 + # Appears to be a problem with GCC 4.0 and binutils 207 + # 208 + default_ld="$cc" 209 + ldflags="-o $program.so.$abi_major.$abi_minor $ldflags" 210 + 211 + # FIXME: port to solaris 212 + if [ "$target" = "linux" ] ; then 213 + ldflags="$ldflags -Wl,-export-dynamic -Wl,-soname,$program.so.$abi_major" 214 + fi 215 + 216 + if [ "$target" = "solaris" ] ; then 217 + ldflags="$ldflags" 218 + fi 219 + 220 + finalize ld "$default_ld" 221 + echo "$ld" 222 + } 223 + 224 + check_archiver() { 225 + printf "checking for a suitable archiver.. " 226 + if [ "`uname -s`" = "SunOS" -a "`uname -v | grep Nexenta`" = "" ] ; then 227 + default_ar="/usr/sfw/bin/gar" 228 + else 229 + default_ar="/usr/bin/ar" 230 + fi 231 + finalize ar "$default_ar" 232 + echo "$ar" 233 + } 234 + 235 + err() { 236 + echo "*** ERROR *** $*" 237 + rm -f config.mk $program.pc config.h 238 + exit 1 239 + } 240 + 241 + check_diff() { 242 + # TODO: Support non-GNU diff syntax 243 + # TODO: Search for the command 244 + printf "checking for a suitable diff(1) command.. " 245 + finalize diff "diff -ruN -dEbwBp -x .svn -x .o -x config.h -x config.mk" 246 + echo "found" 247 + } 248 + 249 + subst_vars() { 250 + outfile=$1 251 + 252 + if [ ! -f "${outfile}.in" ] ; then 253 + return 254 + fi 255 + 256 + echo "Creating $outfile" 257 + rm -f $outfile 258 + sed -e " 259 + s,@@CWD@@,`pwd`,g; 260 + s,@@PROGRAM@@,$program,g; 261 + s,@@VERSION@@,$version,g; 262 + s,@@PREFIX@@,$prefix,g; 263 + s,@@LIBDIR@@,$libdir,g; 264 + s,@@INCLUDEDIR@@,$includedir,g; 265 + s,@@MANDIR@@,$mandir,g; 266 + s,@@LIBDEPENDS@@,$libdepends,g; 267 + s,@@PKG_SUMMARY@@,$pkg_summary,g; 268 + s,@@RPM_DATE@@,`date +'%a %b %d %Y'`,g; 269 + s,@@PKG_DESCRIPTION@@,$pkg_description,g; 270 + s,@@LICENSE@@,$license,g; 271 + s,@@AUTHOR@@,$author,g; 272 + " < ${outfile}.in > $outfile 273 + chmod 400 $outfile 274 + } 275 + 276 + ####################################################################### 277 + # 278 + # MAIN() 279 + # 280 + ####################################################################### 281 + 282 + # Workaround for Solaris "Bad string" issue when LOCALE is undefined 283 + tr="/usr/bin/tr" 284 + test -f /usr/xpg4/bin/tr && tr="/usr/xpg4/bin/tr" 285 + 286 + . ./config.inc 287 + 288 + # Initialize the output files 289 + # 290 + for output_file in config.mk 291 + do 292 + rm -f $output_file 293 + echo "# AUTOMATICALLY GENERATED -- DO NOT EDIT" > $output_file 294 + done 295 + if [ "$sources" != "" ] ; then 296 + rm -f config.h 297 + echo "/* AUTOMATICALLY GENERATED -- DO NOT EDIT */" > config.h 298 + fi 299 + 300 + process_argv "$*" 301 + process_env 302 + 303 + check_target 304 + check_compiler 305 + check_linker 306 + check_archiver 307 + check_install 308 + check_diff 309 + 310 + finalize program "$program" 311 + finalize version "$version" 312 + finalize abi_major "$abi_major" 313 + finalize abi_minor "$abi_minor" 314 + finalize abi_version "$abi_major.$abi_minor" 315 + finalize prefix "/usr/local" 316 + finalize bindir "\\\$(PREFIX)/bin" 317 + finalize sbindir "\\\$(PREFIX)/sbin" 318 + finalize libdir "\\\$(PREFIX)/lib" 319 + finalize includedir "\\\$(PREFIX)/include" 320 + finalize mandir "\\\$(PREFIX)/share/man" 321 + finalize cflags "$cflags" 322 + finalize libdepends "$libdepends" 323 + finalize ldadd "" 324 + finalize ldflags "" 325 + finalize deps "" 326 + finalize ln "`which ln`" 327 + finalize distfile "$program-$version.tar.gz" 328 + 329 + pre_configure_hook 330 + 331 + for header in $required_headers 332 + do 333 + check_header "$header" || err "$header is required, but cannot be found." 334 + done 335 + check_headers $optional_headers 336 + 337 + post_configure_hook 338 + 339 + objs="`echo \"$sources\" | sed 's/\.c/\.o/g'`" 340 + 341 + subst_vars "$program.pc" 342 + subst_vars "$program.la" 343 + subst_vars "rpm.spec" 344 + 345 + if [ "$sources" != "" ] ; then 346 + echo "Creating config.h" 347 + export_to_c $c_exports 348 + fi 349 + 350 + echo "Creating config.mk" 351 + export_to_make "$make_exports"
+100
external/libpthread_workqueue-0.8.2/include/pthread_workqueue.h
··· 1 + /*- 2 + * Copyright (c) 2010, Mark Heily <mark@heily.com> 3 + * Copyright (c) 2009, Stacey Son <sson@freebsd.org> 4 + * Copyright (c) 2000-2008, Apple Inc. 5 + * All rights reserved. 6 + * 7 + * Redistribution and use in source and binary forms, with or without 8 + * modification, are permitted provided that the following conditions 9 + * are met: 10 + * 1. Redistributions of source code must retain the above copyright 11 + * notice unmodified, this list of conditions, and the following 12 + * disclaimer. 13 + * 2. Redistributions in binary form must reproduce the above copyright 14 + * notice, this list of conditions and the following disclaimer in the 15 + * documentation and/or other materials provided with the distribution. 16 + * 17 + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 18 + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 19 + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 20 + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 21 + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 22 + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 23 + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 24 + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 25 + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 26 + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27 + * 28 + */ 29 + 30 + #ifndef _PTHREAD_WORKQUEUE_H 31 + #define _PTHREAD_WORKQUEUE_H 32 + 33 + #if _WIN32 34 + #define _PWQ_EXPORT __declspec(dllexport) 35 + #else 36 + #define _PWQ_EXPORT 37 + #endif 38 + 39 + typedef struct _pthread_workqueue * pthread_workqueue_t; 40 + typedef void * pthread_workitem_handle_t; 41 + 42 + /* Pad size to 64 bytes. */ 43 + typedef struct { 44 + unsigned int sig; 45 + int queueprio; 46 + int overcommit; 47 + unsigned int pad[13]; 48 + } pthread_workqueue_attr_t; 49 + 50 + /* Work queue priority attributes. */ 51 + #define WORKQ_HIGH_PRIOQUEUE 0 52 + #define WORKQ_DEFAULT_PRIOQUEUE 1 53 + #define WORKQ_LOW_PRIOQUEUE 2 54 + 55 + #if defined(__cplusplus) 56 + extern "C" { 57 + #endif 58 + 59 + int _PWQ_EXPORT pthread_workqueue_create_np(pthread_workqueue_t * workqp, 60 + const pthread_workqueue_attr_t * attr); 61 + 62 + int _PWQ_EXPORT pthread_workqueue_additem_np(pthread_workqueue_t workq, 63 + void (*workitem_func)(void *), void * workitem_arg, 64 + pthread_workitem_handle_t * itemhandlep, unsigned int *gencountp); 65 + 66 + int _PWQ_EXPORT pthread_workqueue_attr_init_np(pthread_workqueue_attr_t * attrp); 67 + 68 + int _PWQ_EXPORT pthread_workqueue_attr_destroy_np(pthread_workqueue_attr_t * attr); 69 + 70 + int _PWQ_EXPORT pthread_workqueue_attr_setqueuepriority_np(pthread_workqueue_attr_t * attr, 71 + int qprio); 72 + 73 + int _PWQ_EXPORT pthread_workqueue_attr_getovercommit_np( 74 + const pthread_workqueue_attr_t * attr, int * ocommp); 75 + 76 + int _PWQ_EXPORT pthread_workqueue_attr_setovercommit_np(pthread_workqueue_attr_t * attr, 77 + int ocomm); 78 + 79 + int _PWQ_EXPORT pthread_workqueue_requestconcurrency_np(pthread_workqueue_t workq, 80 + int queue, int request_concurrency); 81 + 82 + int _PWQ_EXPORT pthread_workqueue_getovercommit_np(pthread_workqueue_t workq, 83 + unsigned int *ocommp); 84 + 85 + void _PWQ_EXPORT pthread_workqueue_main_np(void); 86 + 87 + #ifdef MAKE_STATIC 88 + int _PWQ_EXPORT pthread_workqueue_init_np(void); 89 + #endif 90 + 91 + /* NOTE: this is not part of the Darwin API */ 92 + unsigned long _PWQ_EXPORT pthread_workqueue_peek_np(const char *); 93 + 94 + #if defined(__cplusplus) 95 + } 96 + #endif 97 + 98 + #undef _PWQ_EXPORT 99 + 100 + #endif /* _PTHREAD_WORKQUEUE_H */
+231
external/libpthread_workqueue-0.8.2/pthread_workqueue.3
··· 1 + .\" Copyright (C) 2010 mark@heily.com 2 + .\" Copyright (C) 2009 sson@FreeBSD.org 3 + .\" All rights reserved. 4 + .\" 5 + .\" Redistribution and use in source and binary forms, with or without 6 + .\" modification, are permitted provided that the following conditions 7 + .\" are met: 8 + .\" 1. Redistributions of source code must retain the above copyright 9 + .\" notice(s), this list of conditions and the following disclaimer as 10 + .\" the first lines of this file unmodified other than the possible 11 + .\" addition of one or more copyright notices. 12 + .\" 2. Redistributions in binary form must reproduce the above copyright 13 + .\" notice(s), this list of conditions and the following disclaimer in 14 + .\" the documentation and/or other materials provided with the 15 + .\" distribution. 16 + .\" 17 + .\" THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER(S) ``AS IS'' AND ANY 18 + .\" EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 19 + .\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 20 + .\" PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) BE 21 + .\" LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 22 + .\" CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 23 + .\" SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR 24 + .\" BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 25 + .\" WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE 26 + .\" OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, 27 + .\" EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 28 + .\" 29 + .\" $FreeBSD: $ 30 + .Dd December 12, 2009 31 + .Dt PTHREAD_WORKQUEUE 3 32 + .Os 33 + .Sh NAME 34 + .Nm pthread_workqueue_init_np , 35 + .Nm pthread_workqueue_create_np , 36 + .Nm pthread_workqueue_additem_np 37 + .Nd thread workqueue operations 38 + .Pp 39 + .Nm pthread_workqueue_attr_init_np , 40 + .Nm pthread_workqueue_attr_destroy_np , 41 + .Nm pthread_workqueue_attr_getovercommit_np , 42 + .Nm pthread_workqueue_attr_setovercommit_np , 43 + .Nm pthread_workqueue_attr_getqueuepriority_np , 44 + .Nm pthread_workqueue_attr_setqueuepriority_np 45 + .Nd thread workqueue attribute operations 46 + .Sh SYNOPSIS 47 + .In pthread_workqueue.h 48 + .Ft int 49 + .Fn pthread_workqueue_init_np "void" 50 + .Ft int 51 + .Fn pthread_workqueue_create_np "pthread_workqueue_t *workqp" "const pthread_workqueue_attr_t * attr" 52 + .Ft int 53 + .Fn pthread_workqueue_additem_np "pthread_workqueue_t workq" "void ( *workitem_func)(void *)" "void * workitem_arg" "pthread_workitem_handle_t * itemhandlep" "unsigned int *gencountp" 54 + .Ft int 55 + .Fn pthread_workqueue_attr_init_np "pthread_workqueue_attr_t *attr" 56 + .Ft int 57 + .Fn pthread_workqueue_attr_destroy_np "pthread_workqueue_attr_t *attr" 58 + .Ft int 59 + .Fn pthread_workqueue_attr_getovercommit_np "pthread_workqueue_attr_t *attr" "int *ocommp" 60 + .Ft int 61 + .Fn pthread_workqueue_attr_setovercommit_np "pthread_workqueue_attr_t *attr" "int ocomm" 62 + .Ft int 63 + .Fn pthread_workqueue_attr_getqueuepriority_np "pthread_workqueue_attr_t *attr" "int *qpriop" 64 + .Ft int 65 + .Fn pthread_workqueue_attr_setqueuepriority_np "pthread_workqueue_attr_t *attr" "int qprio" 66 + .Sh DESCRIPTION 67 + The 68 + .Fn pthread_workqueue_*_np 69 + functions are used to create and submit work items to a thread pool. 70 + .Pp 71 + The user may create multiple work queues of different priority and 72 + manually overcommit the available resources. 73 + .Pp 74 + .Fn pthread_workqueue_init_np 75 + allocates and initializes the thread workqueue subsystem. 76 + .Pp 77 + .Fn pthread_workqueue_create_np 78 + creates a new thread workqueue with the attributes given by 79 + .Fa attr . 80 + If 81 + .Fa attr 82 + is NULL then the default attributes are used. 83 + A workqueue handle is returned in the 84 + .Fa workqp 85 + parameter. 86 + .Pp 87 + Thread workqueue attributes are used to specify parameters to 88 + .Fn pthread_workqueue_create_np . 89 + One attribute object can be used in multiple calls to 90 + .Fn pthread_workqueue_create_np , 91 + with or without modifications between calls. 92 + .Pp 93 + .Fn pthread_workqueue_additem_np 94 + is used to submit work items to the thread pool specified by 95 + .Fa workq 96 + parameter. 97 + The work item function and function argument are given by 98 + .Fa workitem_func 99 + and 100 + .Fa workitem_arg . 101 + The work item handle is returned in 102 + .Fa itemhandlep . 103 + .Pp 104 + The 105 + .Fn pthread_workqueue_attr_init_np 106 + function initializes 107 + .Fa attr 108 + with all the default thread workqueue attributes. 109 + .Pp 110 + The 111 + .Fn pthread_workqueue_attr_destroy_np 112 + function destroys 113 + .Fa attr . 114 + .Pp 115 + The 116 + .Fn pthread_workqueue_attr_set*_np 117 + functions set the attribute that corresponds to each function name. 118 + .Fn pthread_workqueue_attr_setovercommit_np 119 + can be used to set the overcommit flag. 120 + If the overcommit flag is set then more threads will be started, if 121 + needed, which may overcommit the physical resources of the system. 122 + .Fn pthread_workqueue_attr_setqueuepriority_np 123 + sets the queue priority attribute of the thread work queue and must be 124 + set to one of the following values: 125 + .Bl -tag -width "Va WORKQ_DEFAULT_PRIOQUEUE" 126 + .It Va WORKQ_HIGH_PRIOQUEUE 127 + Work items in the queue with this attribute will be given higher priority by 128 + the thread scheduler. 129 + .It Va WORKQ_DEFAULT_PRIOQUEUE 130 + Work items in the queue with this attribute are given the default 131 + priority. 132 + .It Va WORKQ_LOW_PRIOQUEUE 133 + Work items in the queue with this attribute will be given lower priority 134 + by the thread scheduler. 135 + .El 136 + .Pp 137 + The 138 + .Fn pthread_workqueue_attr_get*_np 139 + functions copy the value of the attribute that corresponds to each function name 140 + to the location pointed to by the second function parameter. 141 + .Sh RETURN VALUES 142 + If successful, these functions return 0. 143 + Otherwise, an error number is returned to indicate the error. 144 + .Sh ERRORS 145 + The 146 + .Fn pthread_workqueue_init_np 147 + function will fail if: 148 + .Bl -tag -width Er 149 + .It Bq Er ENOMEM 150 + Out of memory. 151 + .El 152 + .Pp 153 + The 154 + .Fn pthread_workqueue_create_np 155 + function will fail if: 156 + .Bl -tag -width Er 157 + .It Bq Er ENOMEM 158 + Out of memory. 159 + .El 160 + .Pp 161 + The 162 + .Fn pthread_workqueue_additem_np 163 + function will fail if: 164 + .Bl -tag -width Er 165 + .It Bq Er EINVAL 166 + Invalid workqueue handle. 167 + .It Bq Er ENOMEM 168 + Out of memory. 169 + .It Bq Er ESRCH 170 + Can not find workqueue. 171 + .El 172 + .Pp 173 + The 174 + .Fn pthread_workqueue_attr_init_np 175 + function will fail if: 176 + .Bl -tag -width Er 177 + .It Bq Er ENOMEM 178 + Out of memory. 179 + .El 180 + .Pp 181 + The 182 + .Fn pthread_workqueue_attr_destroy_np 183 + function will fail if: 184 + .Bl -tag -width Er 185 + .It Bq Er EINVAL 186 + Invalid value for 187 + .Fa attr . 188 + .El 189 + .Pp 190 + The 191 + .Fn pthread_workqueue_attr_setqueuepriority_np 192 + function will fail if: 193 + .Bl -tag -width Er 194 + .It Bq Er EINVAL 195 + Invalid value for 196 + .Fa attr 197 + or for 198 + .Fa qprio. 199 + .El 200 + .Pp 201 + The 202 + .Fn pthread_workqueue_attr_setovercommit_np , 203 + .Fn pthread_workqueue_attr_getovercommit_np 204 + and 205 + .Fn pthread_workqueue_attr_getqueuepriority_np 206 + functions will fail if: 207 + .Bl -tag -width Er 208 + .It Bq Er EINVAL 209 + Invalid value for 210 + .Fa attr . 211 + .El 212 + .Sh SEE ALSO 213 + .Xr pthread 3 , 214 + .Xr sysctl 3 215 + .Sh BUGS 216 + There is no way, currently, to remove or destory work queues and pending 217 + work items other than exiting the process. 218 + .Pp 219 + 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. 220 + .Sh HISTORY 221 + This thread workqueues code was created to support Grand Central Dispatch (GCD 222 + or libdispatch) and first appeared in 223 + .Fx 8.0 . 224 + .Sh AUTHORS 225 + .An "Mark Heily" Aq mark@heily.com . 226 + .Br 227 + .Pp 228 + Based on earlier work by 229 + .An "Stacey Son" Aq sson@FreeBSD.org 230 + and 231 + .An Apple, Inc.
+201
external/libpthread_workqueue-0.8.2/src/api.c
··· 1 + /*- 2 + * Copyright (c) 2010, Mark Heily <mark@heily.com> 3 + * Copyright (c) 2009, Stacey Son <sson@freebsd.org> 4 + * Copyright (c) 2000-2008, Apple Inc. 5 + * All rights reserved. 6 + * 7 + * Redistribution and use in source and binary forms, with or without 8 + * modification, are permitted provided that the following conditions 9 + * are met: 10 + * 1. Redistributions of source code must retain the above copyright 11 + * notice unmodified, this list of conditions, and the following 12 + * disclaimer. 13 + * 2. Redistributions in binary form must reproduce the above copyright 14 + * notice, this list of conditions and the following disclaimer in the 15 + * documentation and/or other materials provided with the distribution. 16 + * 17 + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 18 + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 19 + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 20 + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 21 + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 22 + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 23 + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 24 + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 25 + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 26 + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27 + * 28 + */ 29 + 30 + #include "private.h" 31 + 32 + unsigned int PWQ_ACTIVE_CPU = 0; 33 + int DEBUG_WORKQUEUE = 0; 34 + char *WORKQUEUE_DEBUG_IDENT = "WQ"; 35 + 36 + static int 37 + valid_workq(pthread_workqueue_t workq) 38 + { 39 + if (workq->sig == PTHREAD_WORKQUEUE_SIG) 40 + return (1); 41 + else 42 + return (0); 43 + } 44 + 45 + int VISIBLE CONSTRUCTOR 46 + pthread_workqueue_init_np(void) 47 + { 48 + #ifdef NDEBUG 49 + DEBUG_WORKQUEUE = 0; 50 + #else 51 + DEBUG_WORKQUEUE = (getenv("PWQ_DEBUG") == NULL) ? 0 : 1; 52 + # ifndef _WIN32 53 + PWQ_RT_THREADS = (getenv("PWQ_RT_THREADS") == NULL) ? 0 : 1; 54 + PWQ_ACTIVE_CPU = (getenv("PWQ_ACTIVE_CPU") == NULL) ? 0 : atoi(getenv("PWQ_ACTIVE_CPU")); 55 + 56 + if (getenv("PWQ_SPIN_USEC") != NULL) 57 + PWQ_SPIN_USEC = atoi(getenv("PWQ_SPIN_USEC")); 58 + 59 + if (getenv("PWQ_SPIN_THREADS") != NULL) 60 + PWQ_SPIN_THREADS = atoi(getenv("PWQ_SPIN_THREADS")); 61 + 62 + # endif 63 + #endif 64 + 65 + if (manager_init() < 0) 66 + return (-1); 67 + 68 + dbg_puts("pthread_workqueue library initialized"); 69 + return (0); 70 + } 71 + 72 + int VISIBLE 73 + pthread_workqueue_create_np(pthread_workqueue_t *workqp, 74 + const pthread_workqueue_attr_t * attr) 75 + { 76 + pthread_workqueue_t workq; 77 + 78 + if ((attr != NULL) && ((attr->sig != PTHREAD_WORKQUEUE_ATTR_SIG) || 79 + (attr->queueprio < 0) || (attr->queueprio >= WORKQ_NUM_PRIOQUEUE))) 80 + return (EINVAL); 81 + if ((workq = calloc(1, sizeof(*workq))) == NULL) 82 + return (ENOMEM); 83 + workq->sig = PTHREAD_WORKQUEUE_SIG; 84 + workq->flags = 0; 85 + STAILQ_INIT(&workq->item_listhead); 86 + pthread_spin_init(&workq->mtx, PTHREAD_PROCESS_PRIVATE); 87 + if (attr == NULL) { 88 + workq->queueprio = WORKQ_DEFAULT_PRIOQUEUE; 89 + workq->overcommit = 0; 90 + } else { 91 + workq->queueprio = attr->queueprio; 92 + workq->overcommit = attr->overcommit; 93 + } 94 + 95 + manager_workqueue_create(workq); 96 + 97 + dbg_printf("created queue %p", (void *) workq); 98 + 99 + *workqp = workq; 100 + return (0); 101 + } 102 + 103 + int VISIBLE 104 + pthread_workqueue_additem_np(pthread_workqueue_t workq, 105 + void (*workitem_func)(void *), void * workitem_arg, 106 + pthread_workitem_handle_t * itemhandlep, 107 + unsigned int *gencountp) 108 + { 109 + struct work *witem; 110 + 111 + if (valid_workq(workq) == 0) 112 + return (EINVAL); 113 + 114 + witem = witem_alloc(workitem_func, workitem_arg); 115 + 116 + if (itemhandlep != NULL) 117 + *itemhandlep = (pthread_workitem_handle_t *) witem; 118 + if (gencountp != NULL) 119 + *gencountp = witem->gencount; 120 + 121 + manager_workqueue_additem(workq, witem); 122 + 123 + dbg_printf("added item %p to queue %p", (void *) witem, (void *) workq); 124 + 125 + return (0); 126 + } 127 + 128 + int VISIBLE 129 + pthread_workqueue_attr_init_np(pthread_workqueue_attr_t *attr) 130 + { 131 + attr->queueprio = WORKQ_DEFAULT_PRIOQUEUE; 132 + attr->sig = PTHREAD_WORKQUEUE_ATTR_SIG; 133 + attr->overcommit = 0; 134 + return (0); 135 + } 136 + 137 + int VISIBLE 138 + pthread_workqueue_attr_destroy_np(pthread_workqueue_attr_t *attr) 139 + { 140 + if (attr->sig == PTHREAD_WORKQUEUE_ATTR_SIG) 141 + return (0); 142 + else 143 + return (EINVAL); /* Not an attribute struct. */ 144 + } 145 + 146 + int VISIBLE 147 + pthread_workqueue_attr_getovercommit_np( 148 + const pthread_workqueue_attr_t *attr, int *ocommp) 149 + { 150 + if (attr->sig == PTHREAD_WORKQUEUE_ATTR_SIG) { 151 + *ocommp = attr->overcommit; 152 + return (0); 153 + } else 154 + return (EINVAL); /* Not an attribute struct. */ 155 + } 156 + 157 + int VISIBLE 158 + pthread_workqueue_attr_setovercommit_np(pthread_workqueue_attr_t *attr, 159 + int ocomm) 160 + { 161 + if (attr->sig == PTHREAD_WORKQUEUE_ATTR_SIG) { 162 + attr->overcommit = ocomm; 163 + return (0); 164 + } else 165 + return (EINVAL); 166 + } 167 + 168 + int VISIBLE 169 + pthread_workqueue_attr_getqueuepriority_np( 170 + pthread_workqueue_attr_t *attr, int *qpriop) 171 + { 172 + if (attr->sig == PTHREAD_WORKQUEUE_ATTR_SIG) { 173 + *qpriop = attr->queueprio; 174 + return (0); 175 + } else 176 + return (EINVAL); 177 + } 178 + 179 + int VISIBLE 180 + pthread_workqueue_attr_setqueuepriority_np( 181 + pthread_workqueue_attr_t *attr, int qprio) 182 + { 183 + if (attr->sig == PTHREAD_WORKQUEUE_ATTR_SIG) { 184 + switch(qprio) { 185 + case WORKQ_HIGH_PRIOQUEUE: 186 + case WORKQ_DEFAULT_PRIOQUEUE: 187 + case WORKQ_LOW_PRIOQUEUE: 188 + attr->queueprio = qprio; 189 + return (0); 190 + default: 191 + return (EINVAL); 192 + } 193 + } else 194 + return (EINVAL); 195 + } 196 + 197 + unsigned long VISIBLE 198 + pthread_workqueue_peek_np(const char *key) 199 + { 200 + return manager_peek(key); 201 + }
+83
external/libpthread_workqueue-0.8.2/src/debug.h
··· 1 + /* 2 + * Copyright (c) 2011 Mark Heily <mark@heily.com> 3 + * 4 + * Permission to use, copy, modify, and distribute this software for any 5 + * purpose with or without fee is hereby granted, provided that the above 6 + * copyright notice and this permission notice appear in all copies. 7 + * 8 + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 9 + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 10 + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 11 + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 12 + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 13 + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 14 + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 15 + */ 16 + 17 + #ifndef _DEBUG_H 18 + #define _DEBUG_H 19 + 20 + #include <assert.h> 21 + 22 + extern int DEBUG_WORKQUEUE; 23 + extern char *WORKQUEUE_DEBUG_IDENT; 24 + 25 + #if defined(__linux__) 26 + 27 + #include <linux/unistd.h> 28 + #include <sys/syscall.h> 29 + #include <unistd.h> 30 + 31 + # define THREAD_ID ((pid_t) syscall(__NR_gettid)) 32 + #elif defined(__sun) 33 + # define THREAD_ID (pthread_self()) 34 + #elif defined(__FreeBSD__) /* FIXME -- could use thr_self() */ 35 + # define THREAD_ID (0) 36 + #elif defined(_WIN32) 37 + # define THREAD_ID (int)(GetCurrentThreadId()) 38 + #else 39 + # error Unsupported platform 40 + #endif 41 + 42 + 43 + #ifndef NDEBUG 44 + #define dbg_puts(str) do { \ 45 + if (DEBUG_WORKQUEUE) \ 46 + fprintf(stderr, "%s [%d]: %s(): %s\n", \ 47 + WORKQUEUE_DEBUG_IDENT, THREAD_ID, __func__, str); \ 48 + } while (0) 49 + 50 + #define dbg_printf(fmt,...) do { \ 51 + if (DEBUG_WORKQUEUE) \ 52 + fprintf(stderr, "%s [%d]: %s(): "fmt"\n", \ 53 + WORKQUEUE_DEBUG_IDENT, THREAD_ID, __func__, __VA_ARGS__); \ 54 + } while (0) 55 + 56 + #define dbg_perror(str) do { \ 57 + if (DEBUG_WORKQUEUE) \ 58 + fprintf(stderr, "%s [%d]: %s(): %s: %s (errno=%d)\n", \ 59 + WORKQUEUE_DEBUG_IDENT, THREAD_ID, __func__, str, \ 60 + strerror(errno), errno); \ 61 + } while (0) 62 + 63 + # define reset_errno() do { errno = 0; } while (0) 64 + 65 + # if defined(_WIN32) 66 + # define dbg_lasterror(str) do { \ 67 + if (DEBUG_WORKQUEUE) \ 68 + fprintf(stderr, "%s: [%d] %s(): %s: (LastError=%d)\n", \ 69 + THREAD_ID, __func__, str, GetLastError()); \ 70 + } while (0) 71 + # else 72 + # define dbg_lasterror(str) ; 73 + # endif 74 + 75 + #else /* NDEBUG */ 76 + # define dbg_puts(str) ; 77 + # define dbg_printf(fmt,...) ; 78 + # define dbg_perror(str) ; 79 + # define dbg_lasterror(str) ; 80 + # define reset_errno() ; 81 + #endif 82 + 83 + #endif /* ! _DEBUG_H */
+738
external/libpthread_workqueue-0.8.2/src/posix/manager.c
··· 1 + /*- 2 + * Copyright (c) 2011, Joakim Johansson <jocke@tbricks.com> 3 + * Copyright (c) 2010, Mark Heily <mark@heily.com> 4 + * Copyright (c) 2009, Stacey Son <sson@freebsd.org> 5 + * Copyright (c) 2000-2008, Apple Inc. 6 + * All rights reserved. 7 + * 8 + * Redistribution and use in source and binary forms, with or without 9 + * modification, are permitted provided that the following conditions 10 + * are met: 11 + * 1. Redistributions of source code must retain the above copyright 12 + * notice unmodified, this list of conditions, and the following 13 + * disclaimer. 14 + * 2. Redistributions in binary form must reproduce the above copyright 15 + * notice, this list of conditions and the following disclaimer in the 16 + * documentation and/or other materials provided with the distribution. 17 + * 18 + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 19 + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 20 + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 21 + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 22 + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 23 + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 24 + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 25 + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 26 + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 27 + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 28 + * 29 + */ 30 + 31 + #include "platform.h" 32 + #include "private.h" 33 + #include "pthread_workqueue.h" 34 + #include "thread_info.h" 35 + #include "thread_rt.h" 36 + 37 + #include <sys/time.h> 38 + 39 + /* Environment setting */ 40 + unsigned int PWQ_RT_THREADS = 0; 41 + time_t PWQ_SPIN_USEC = 10000; // The number of microseconds we should spin loop if desired 42 + unsigned int PWQ_SPIN_THREADS = 0; // The number of threads that should be kept spinning 43 + unsigned volatile int current_threads_spinning = 0; // The number of threads currently spinning 44 + 45 + /* Tunable constants */ 46 + 47 + #define WORKER_IDLE_SECONDS_THRESHOLD 5 48 + 49 + /* Function prototypes */ 50 + static unsigned int get_load_average(void); 51 + static void * worker_main(void *arg); 52 + static void * overcommit_worker_main(void *arg); 53 + static unsigned int get_process_limit(void); 54 + static void manager_start(void); 55 + 56 + static unsigned int cpu_count; 57 + static unsigned int worker_min; 58 + static unsigned int worker_idle_threshold; // we don't go down below this if we had to increase # workers 59 + 60 + /* Overcommit */ 61 + static struct _pthread_workqueue *ocwq[PTHREAD_WORKQUEUE_MAX]; 62 + static int ocwq_mask; 63 + static pthread_mutex_t ocwq_mtx; 64 + static pthread_cond_t ocwq_has_work; 65 + static unsigned int ocwq_idle_threads; 66 + 67 + /* Non-overcommit */ 68 + static struct _pthread_workqueue *wqlist[PTHREAD_WORKQUEUE_MAX]; 69 + static volatile unsigned int wqlist_mask; // mask of currently pending workqueues, atomics used for manipulation 70 + static pthread_mutex_t wqlist_mtx; 71 + 72 + static pthread_cond_t wqlist_has_work; 73 + static int wqlist_has_manager; 74 + static pthread_attr_t detached_attr; 75 + 76 + static struct { 77 + volatile unsigned int load, 78 + count, 79 + idle; 80 + unsigned int sb_wake_pending; 81 + pthread_mutex_t sb_wake_mtx; 82 + pthread_cond_t sb_wake_cond; 83 + } scoreboard; 84 + 85 + static unsigned int 86 + worker_idle_threshold_per_cpu(void) 87 + { 88 + switch (cpu_count) 89 + { 90 + case 0: 91 + case 1: 92 + case 2: 93 + case 4: 94 + return 2; 95 + case 6: 96 + return 3; 97 + case 8: 98 + case 12: 99 + return 4; 100 + case 16: 101 + case 24: 102 + return 6; 103 + case 32: 104 + case 64: 105 + return 8; 106 + default: 107 + return cpu_count / 4; 108 + } 109 + 110 + return 2; 111 + } 112 + 113 + static void 114 + manager_reinit(void) 115 + { 116 + if (manager_init() < 0) 117 + abort(); 118 + } 119 + 120 + int 121 + manager_init(void) 122 + { 123 + wqlist_has_manager = 0; 124 + pthread_cond_init(&wqlist_has_work, NULL); 125 + 126 + pthread_mutex_init(&wqlist_mtx, NULL); 127 + wqlist_mask = 0; 128 + 129 + pthread_cond_init(&ocwq_has_work, NULL); 130 + pthread_mutex_init(&ocwq_mtx, NULL); 131 + ocwq_mask = 0; 132 + ocwq_idle_threads = 0; 133 + 134 + witem_cache_init(); 135 + 136 + cpu_count = (PWQ_ACTIVE_CPU > 0) ? (PWQ_ACTIVE_CPU) : (unsigned int) sysconf(_SC_NPROCESSORS_ONLN); 137 + 138 + pthread_attr_init(&detached_attr); 139 + pthread_attr_setdetachstate(&detached_attr, PTHREAD_CREATE_DETACHED); 140 + 141 + /* Initialize the scoreboard */ 142 + pthread_cond_init(&scoreboard.sb_wake_cond, NULL); 143 + pthread_mutex_init(&scoreboard.sb_wake_mtx, NULL); 144 + 145 + /* Determine the initial thread pool constraints */ 146 + worker_min = 2; // we can start with a small amount, worker_idle_threshold will be used as new dynamic low watermark 147 + worker_idle_threshold = worker_idle_threshold_per_cpu(); 148 + 149 + if (pthread_atfork(NULL, NULL, manager_reinit) < 0) { 150 + dbg_perror("pthread_atfork()"); 151 + return (-1); 152 + } 153 + 154 + return (0); 155 + } 156 + 157 + void 158 + manager_workqueue_create(struct _pthread_workqueue *workq) 159 + { 160 + pthread_mutex_lock(&wqlist_mtx); 161 + if (!workq->overcommit && !wqlist_has_manager) 162 + manager_start(); 163 + 164 + if (workq->overcommit) { 165 + if (ocwq[workq->queueprio] == NULL) { 166 + ocwq[workq->queueprio] = workq; 167 + workq->wqlist_index = workq->queueprio; 168 + } else { 169 + puts("queue already exists\n"); 170 + abort(); 171 + } 172 + } else { 173 + if (wqlist[workq->queueprio] == NULL) { 174 + wqlist[workq->queueprio] = workq; //FIXME: sort by priority 175 + workq->wqlist_index = workq->queueprio; 176 + } else { 177 + puts("queue already exists\n"); 178 + abort(); 179 + } 180 + } 181 + pthread_mutex_unlock(&wqlist_mtx); 182 + } 183 + 184 + static struct work * 185 + wqlist_scan(int *queue_priority) 186 + { 187 + pthread_workqueue_t workq; 188 + struct work *witem; 189 + int idx; 190 + 191 + idx = ffs(wqlist_mask); 192 + if (idx == 0) 193 + return (NULL); 194 + 195 + workq = wqlist[idx - 1]; 196 + 197 + pthread_spin_lock(&workq->mtx); 198 + 199 + witem = STAILQ_FIRST(&workq->item_listhead); 200 + if (witem != NULL) { 201 + STAILQ_REMOVE_HEAD(&workq->item_listhead, item_entry); 202 + if (STAILQ_EMPTY(&workq->item_listhead)) 203 + { 204 + unsigned int wqlist_index_bit = (0x1 << workq->wqlist_index); 205 + unsigned int new_mask; 206 + // Remove this now empty wq from the mask, the only contention here is with threads performing the same 207 + // operation on another workqueue, so we will not be long 208 + // the 'bit' for this queue is protected by the spin lock, so we will only clear a bit which we have 209 + // ownership for (see additem() below for the corresponding part on the producer side) 210 + do 211 + { 212 + new_mask = atomic_and(&wqlist_mask, ~(wqlist_index_bit)); 213 + } while (new_mask & wqlist_index_bit); 214 + } 215 + if (queue_priority != NULL) 216 + *queue_priority = workq->queueprio; 217 + 218 + pthread_spin_unlock(&workq->mtx); 219 + return (witem); 220 + } else { 221 + // this could happen if multiple threads raced and found the same bit with ffs() and 222 + // emptied the queue completely, so we should just bail out 223 + pthread_spin_unlock(&workq->mtx); 224 + return (NULL); 225 + } 226 + } 227 + 228 + static void _wakeup_manager(void) 229 + { 230 + dbg_puts("asking manager to wake up"); 231 + 232 + pthread_mutex_lock(&scoreboard.sb_wake_mtx); 233 + scoreboard.sb_wake_pending = 1; 234 + pthread_cond_signal(&scoreboard.sb_wake_cond); 235 + pthread_mutex_unlock(&scoreboard.sb_wake_mtx); 236 + return; 237 + } 238 + 239 + static void * 240 + overcommit_worker_main(void *arg) 241 + { 242 + struct timespec ts; 243 + pthread_workqueue_t workq; 244 + void (*func)(void *); 245 + void *func_arg; 246 + struct work *witem; 247 + int rv, idx; 248 + 249 + (void)arg; 250 + 251 + pthread_mutex_lock(&ocwq_mtx); 252 + 253 + for (;;) { 254 + /* Find the highest priority workqueue that is non-empty */ 255 + idx = ffs(ocwq_mask); 256 + if (idx > 0) { 257 + workq = ocwq[idx - 1]; 258 + witem = STAILQ_FIRST(&workq->item_listhead); 259 + if (witem != NULL) { 260 + /* Remove the first work item */ 261 + STAILQ_REMOVE_HEAD(&workq->item_listhead, item_entry); 262 + if (STAILQ_EMPTY(&workq->item_listhead)) 263 + ocwq_mask &= ~(0x1 << workq->wqlist_index); 264 + /* Execute the work item */ 265 + pthread_mutex_unlock(&ocwq_mtx); 266 + func = witem->func; 267 + func_arg = witem->func_arg; 268 + witem_free(witem); 269 + func(func_arg); 270 + pthread_mutex_lock(&ocwq_mtx); 271 + continue; 272 + } 273 + } 274 + 275 + /* Wait for more work to be available. */ 276 + clock_gettime(CLOCK_REALTIME, &ts); 277 + ts.tv_sec += 15; 278 + ocwq_idle_threads++; 279 + dbg_printf("waiting for work (idle=%d)", ocwq_idle_threads); 280 + rv = pthread_cond_timedwait(&ocwq_has_work, &ocwq_mtx, &ts); 281 + if (rv != 0) { 282 + /* Normally, the signaler will decrement the idle counter, 283 + but this path is not taken in response to a signaler. 284 + */ 285 + ocwq_idle_threads--; 286 + pthread_mutex_unlock(&ocwq_mtx); 287 + 288 + if (rv == ETIMEDOUT) { 289 + dbg_puts("timeout, no work available"); 290 + break; 291 + } else { 292 + dbg_perror("pthread_cond_timedwait"); 293 + //TODO: some kind of crash mechanism 294 + break; 295 + } 296 + } 297 + } 298 + 299 + dbg_printf("worker exiting (idle=%d)", ocwq_idle_threads); 300 + pthread_exit(NULL); 301 + } 302 + 303 + static void * 304 + worker_main(void *arg) 305 + { 306 + struct work *witem; 307 + void (*func)(void *); 308 + void *func_arg; 309 + int queue_priority = 0; 310 + struct timespec ts_start, ts_now; 311 + 312 + (void) arg; 313 + dbg_puts("worker thread started"); 314 + 315 + if (PWQ_RT_THREADS) 316 + ptwq_set_current_thread_priority(WORKQ_HIGH_PRIOQUEUE); // start at highest priority possible 317 + 318 + for (;;) { 319 + 320 + witem = wqlist_scan(&queue_priority); 321 + 322 + // Only take overhead of sleeping and/or spinning if we 323 + // could not get a witem cheaply using the spinlock above 324 + if (slowpath(!witem)) 325 + { 326 + // Optional busy loop for getting the next item for a while if so configured 327 + // We'll only spin limited thread at a time (this is really mostly useful when running 328 + // in low latency configurations using dedicated processor sets) 329 + if ((PWQ_SPIN_THREADS > 0) && (current_threads_spinning <= PWQ_SPIN_THREADS)) 330 + { 331 + atomic_inc(&current_threads_spinning); 332 + 333 + // If we are racing with another thread, let's skip 334 + // spinning and instead go through the slowpath below 335 + 336 + if (current_threads_spinning <= PWQ_SPIN_THREADS) 337 + { 338 + clock_gettime(CLOCK_REALTIME, &ts_start); 339 + ts_now.tv_sec = ts_start.tv_sec; 340 + ts_now.tv_nsec = ts_start.tv_nsec; 341 + 342 + // Spin until we get an item or PWQ_SPIN_USEC microseconds passes 343 + while (!witem && (((ts_now.tv_sec - ts_start.tv_sec) * 1000000) + (((ts_now.tv_nsec - ts_start.tv_nsec) / 1000)) <= PWQ_SPIN_USEC)) 344 + { 345 + witem = wqlist_scan(&queue_priority); 346 + if (!witem) 347 + { 348 + // Perhaps a hardware pause 349 + // instruction could be used here to keep the pace down, probably not needed though 350 + clock_gettime(CLOCK_REALTIME, &ts_now); 351 + } 352 + } 353 + } 354 + 355 + atomic_dec(&current_threads_spinning); 356 + } 357 + 358 + // No witem from the busy loop, let's wait for wakeup 359 + if (!witem) 360 + { 361 + pthread_mutex_lock(&wqlist_mtx); 362 + 363 + /* 364 + TODO: Consider using pthread_cond_timedwait() so that 365 + workers can self-terminate if they are idle too long. 366 + This would also be a failsafe in case there are bugs 367 + with the scoreboard that cause us to "leak" workers. 368 + */ 369 + while ((witem = wqlist_scan(&queue_priority)) == NULL) 370 + pthread_cond_wait(&wqlist_has_work, &wqlist_mtx); 371 + 372 + pthread_mutex_unlock(&wqlist_mtx); 373 + } 374 + } 375 + 376 + atomic_dec(&scoreboard.idle); 377 + 378 + if (slowpath(witem->func == NULL)) { 379 + dbg_puts("worker exiting.."); 380 + atomic_dec(&scoreboard.count); 381 + witem_free(witem); 382 + pthread_exit(0); 383 + } 384 + 385 + dbg_printf("count=%u idle=%u wake_pending=%u", 386 + scoreboard.count, scoreboard.idle, scoreboard.sb_wake_pending); 387 + 388 + /* Force the manager thread to wakeup if all workers are busy */ 389 + if (slowpath(scoreboard.idle == 0 && !scoreboard.sb_wake_pending)) 390 + _wakeup_manager(); 391 + 392 + // If using RT threads, decrease thread prio if we aren't a high prio queue 393 + if (PWQ_RT_THREADS && (queue_priority != WORKQ_HIGH_PRIOQUEUE)) 394 + ptwq_set_current_thread_priority(queue_priority); 395 + 396 + /* Invoke the callback function, free witem first for possible reuse */ 397 + func = witem->func; 398 + func_arg = witem->func_arg; 399 + witem_free(witem); 400 + 401 + func(func_arg); 402 + 403 + atomic_inc(&scoreboard.idle); // initial inc was one in worker_start, this is to avoid a race 404 + 405 + // Only take the overhead and change RT priority back if it was not a high priority queue being serviced 406 + if (PWQ_RT_THREADS && (queue_priority != WORKQ_HIGH_PRIOQUEUE)) 407 + ptwq_set_current_thread_priority(WORKQ_HIGH_PRIOQUEUE); 408 + } 409 + 410 + /* NOTREACHED */ 411 + return (NULL); 412 + } 413 + 414 + static int 415 + worker_start(void) 416 + { 417 + pthread_t tid; 418 + 419 + dbg_puts("Spawning another worker"); 420 + 421 + atomic_inc(&scoreboard.idle); 422 + atomic_inc(&scoreboard.count); 423 + 424 + if (pthread_create(&tid, &detached_attr, worker_main, NULL) != 0) { 425 + dbg_perror("pthread_create(3)"); 426 + atomic_dec(&scoreboard.idle); 427 + atomic_dec(&scoreboard.count); 428 + return (-1); 429 + } 430 + 431 + return (0); 432 + } 433 + 434 + static int 435 + worker_stop(void) 436 + { 437 + struct work *witem; 438 + pthread_workqueue_t workq; 439 + int i; 440 + unsigned int wqlist_index_bit, new_mask; 441 + 442 + witem = witem_alloc(NULL, NULL); 443 + 444 + pthread_mutex_lock(&wqlist_mtx); 445 + for (i = 0; i < PTHREAD_WORKQUEUE_MAX; i++) { 446 + workq = wqlist[i]; 447 + if (workq == NULL) 448 + continue; 449 + 450 + wqlist_index_bit = (0x1 << workq->wqlist_index); 451 + 452 + pthread_spin_lock(&workq->mtx); 453 + 454 + do 455 + { 456 + new_mask = atomic_or(&wqlist_mask, wqlist_index_bit); 457 + } while (!(new_mask & wqlist_index_bit)); 458 + 459 + STAILQ_INSERT_TAIL(&workq->item_listhead, witem, item_entry); 460 + 461 + pthread_spin_unlock(&workq->mtx); 462 + 463 + pthread_cond_signal(&wqlist_has_work); 464 + pthread_mutex_unlock(&wqlist_mtx); 465 + 466 + return (0); 467 + } 468 + 469 + /* FIXME: this means there are no workqueues.. should never happen */ 470 + dbg_puts("Attempting to add a workitem without a workqueue"); 471 + abort(); 472 + 473 + return (-1); 474 + } 475 + 476 + static void * 477 + manager_main(void *unused __attribute__ ((unused))) 478 + { 479 + unsigned int load_max = cpu_count; 480 + unsigned int worker_max, current_thread_count = 0; 481 + unsigned int worker_idle_seconds_accumulated = 0; 482 + unsigned int max_threads_to_stop = 0; 483 + unsigned int i; 484 + int cond_wait_rv = 0; 485 + sigset_t sigmask; 486 + struct timespec ts; 487 + struct timeval tp; 488 + 489 + worker_max = get_process_limit(); 490 + scoreboard.load = get_load_average(); 491 + 492 + /* Block all signals */ 493 + sigfillset(&sigmask); 494 + pthread_sigmask(SIG_BLOCK, &sigmask, NULL); 495 + 496 + /* Create the minimum number of workers */ 497 + scoreboard.count = 0; 498 + for (i = 0; i < worker_min; i++) 499 + worker_start(); 500 + 501 + for (;;) { 502 + 503 + pthread_mutex_lock(&scoreboard.sb_wake_mtx); 504 + 505 + dbg_puts("manager is sleeping"); 506 + 507 + (void) gettimeofday(&tp, NULL); // TODO - error checking 508 + 509 + /* Convert from timeval to timespec */ 510 + ts.tv_sec = tp.tv_sec; 511 + ts.tv_nsec = tp.tv_usec * 1000; 512 + ts.tv_sec += 1; // wake once per second and check if we have too many idle threads... 513 + 514 + // We should only sleep on the condition if there are no pending signal, spurious wakeup is also ok 515 + if (scoreboard.sb_wake_pending == 0) 516 + cond_wait_rv = pthread_cond_timedwait(&scoreboard.sb_wake_cond, &scoreboard.sb_wake_mtx, &ts); 517 + 518 + scoreboard.sb_wake_pending = 0; // we must set this before spawning any new threads below, or we race... 519 + 520 + dbg_puts("manager is awake"); 521 + 522 + dbg_printf("load=%u idle=%u workers=%u max_workers=%u worker_min = %u", 523 + scoreboard.load, scoreboard.idle, scoreboard.count, worker_max, worker_min); 524 + 525 + // If no workers available, check if we should create a new one 526 + if (scoreboard.idle == 0 && (scoreboard.count > 0)) // last part required for an extremely unlikely race at startup 527 + { 528 + scoreboard.load = get_load_average(); 529 + 530 + if ((scoreboard.load < load_max) && (scoreboard.count < worker_max)) 531 + { 532 + if (scoreboard.count < worker_idle_threshold) // allow cheap rampup up to worker_idle_threshold without going to /proc 533 + { 534 + worker_start(); 535 + } 536 + else // check through /proc, will be a bit more expensive in terms of latency 537 + if (threads_runnable(&current_thread_count) == 0) 538 + { 539 + // only start thread if we have less runnable threads than cpus 540 + if (current_thread_count >= cpu_count) 541 + { 542 + dbg_printf("Not spawning worker thread, thread_runnable = %d >= cpu_count = %d", 543 + current_thread_count, cpu_count); 544 + } 545 + else 546 + { 547 + worker_start(); 548 + } 549 + } 550 + else // always start thread if we can't get runnable count 551 + { 552 + worker_start(); 553 + } 554 + } 555 + else // high load, allow rampup up to worker_idle_threshold regardless of this 556 + { 557 + if (scoreboard.count < worker_idle_threshold) 558 + { 559 + worker_start(); 560 + } 561 + } 562 + } 563 + else 564 + { 565 + if (cond_wait_rv == ETIMEDOUT) // Only check for ramp down on the 'timer tick' 566 + { 567 + if ((scoreboard.idle - worker_idle_threshold) > 0) // only accumulate if there are 'too many' idle threads 568 + { 569 + worker_idle_seconds_accumulated += scoreboard.idle; // keep track of many idle 'thread seconds' we have 570 + 571 + dbg_printf("worker_idle_seconds_accumulated = %d, scoreboard.idle = %d, scoreboard.count = %d\n", 572 + worker_idle_seconds_accumulated, scoreboard.idle, scoreboard.count); 573 + } 574 + 575 + // Only consider ramp down if we have accumulated enough thread 'idle seconds' 576 + // this logic will ensure that a large number of idle threads will ramp down faster 577 + max_threads_to_stop = worker_idle_seconds_accumulated / WORKER_IDLE_SECONDS_THRESHOLD; 578 + 579 + if (max_threads_to_stop > 0) 580 + { 581 + worker_idle_seconds_accumulated = 0; 582 + 583 + if (max_threads_to_stop > (scoreboard.idle - worker_idle_threshold)) 584 + max_threads_to_stop = (scoreboard.idle - worker_idle_threshold); 585 + 586 + // Only stop threads if we actually have 'too many' idle ones in the pool 587 + if (scoreboard.idle > worker_idle_threshold) 588 + { 589 + for (i = 0; i < max_threads_to_stop; i++) 590 + { 591 + dbg_puts("Removing one thread from the thread pool"); 592 + worker_stop(); 593 + } 594 + } 595 + } 596 + } 597 + } 598 + 599 + pthread_mutex_unlock(&scoreboard.sb_wake_mtx); 600 + } 601 + 602 + /*NOTREACHED*/ 603 + return (NULL); 604 + } 605 + 606 + static void 607 + manager_start(void) 608 + { 609 + pthread_t tid; 610 + int rv; 611 + 612 + dbg_puts("starting the manager thread"); 613 + 614 + do { 615 + rv = pthread_create(&tid, &detached_attr, manager_main, NULL); 616 + if (rv == EAGAIN) { 617 + sleep(1); 618 + } else if (rv != 0) { 619 + /* FIXME: not nice */ 620 + dbg_printf("thread creation failed, rv=%d", rv); 621 + abort(); 622 + } 623 + } while (rv != 0); 624 + 625 + wqlist_has_manager = 1; 626 + } 627 + 628 + void 629 + manager_workqueue_additem(struct _pthread_workqueue *workq, struct work *witem) 630 + { 631 + unsigned int wqlist_index_bit = (0x1 << workq->wqlist_index); 632 + 633 + if (workq->overcommit) { 634 + pthread_t tid; 635 + 636 + pthread_mutex_lock(&ocwq_mtx); 637 + pthread_spin_lock(&workq->mtx); 638 + STAILQ_INSERT_TAIL(&workq->item_listhead, witem, item_entry); 639 + pthread_spin_unlock(&workq->mtx); 640 + ocwq_mask |= wqlist_index_bit; 641 + if (ocwq_idle_threads > 0) { 642 + dbg_puts("signaling an idle worker"); 643 + pthread_cond_signal(&ocwq_has_work); 644 + ocwq_idle_threads--; 645 + } else { 646 + (void)pthread_create(&tid, &detached_attr, overcommit_worker_main, NULL); 647 + } 648 + pthread_mutex_unlock(&ocwq_mtx); 649 + } else { 650 + pthread_spin_lock(&workq->mtx); 651 + 652 + // Only set the mask for the first item added to the workqueue. 653 + if (STAILQ_EMPTY(&workq->item_listhead)) 654 + { 655 + unsigned int new_mask; 656 + 657 + // The only possible contention here are with threads performing the same 658 + // operation on another workqueue, so we will not be blocked long... 659 + // Threads operating on the same workqueue will be serialized by the spinlock so it is very unlikely. 660 + do 661 + { 662 + new_mask = atomic_or(&wqlist_mask, wqlist_index_bit); 663 + } while (!(new_mask & wqlist_index_bit)); 664 + } 665 + 666 + STAILQ_INSERT_TAIL(&workq->item_listhead, witem, item_entry); 667 + 668 + pthread_spin_unlock(&workq->mtx); 669 + 670 + // Only signal thread wakeup if there are idle threads available 671 + // and no other thread have managed to race us and empty the wqlist on our behalf already 672 + if ((scoreboard.idle > 0)) // && ((wqlist_mask & wqlist_index_bit) != 0)) // disabling this fringe optimization for now 673 + { 674 + pthread_mutex_lock(&wqlist_mtx); 675 + pthread_cond_signal(&wqlist_has_work); 676 + pthread_mutex_unlock(&wqlist_mtx); 677 + } 678 + } 679 + } 680 + 681 + 682 + static unsigned int 683 + get_process_limit(void) 684 + { 685 + #if __linux__ 686 + struct rlimit rlim; 687 + 688 + if (getrlimit(RLIMIT_NPROC, &rlim) < 0) { 689 + dbg_perror("getrlimit(2)"); 690 + return (50); 691 + } else { 692 + return (rlim.rlim_max); 693 + } 694 + #else 695 + /* Solaris doesn't define this limit anywhere I can see.. */ 696 + return (64); 697 + #endif 698 + } 699 + 700 + static unsigned int 701 + get_load_average(void) 702 + { 703 + double loadavg; 704 + 705 + /* TODO: proper error handling */ 706 + if (getloadavg(&loadavg, 1) != 1) { 707 + dbg_perror("getloadavg(3)"); 708 + return (1); 709 + } 710 + if (loadavg > INT_MAX || loadavg < 0) 711 + loadavg = 1; 712 + 713 + return ((int) loadavg); 714 + } 715 + 716 + unsigned long 717 + manager_peek(const char *key) 718 + { 719 + uint64_t rv; 720 + 721 + if (strcmp(key, "combined_idle") == 0) { 722 + rv = scoreboard.idle; 723 + if (scoreboard.idle > worker_min) 724 + rv -= worker_min; 725 + rv += ocwq_idle_threads; 726 + } else if (strcmp(key, "idle") == 0) { 727 + rv = scoreboard.idle; 728 + if (scoreboard.idle > worker_min) 729 + rv -= worker_min; 730 + } else if (strcmp(key, "ocomm_idle") == 0) { 731 + rv = ocwq_idle_threads; 732 + } else { 733 + dbg_printf("invalid key: %s", key); 734 + abort(); 735 + } 736 + 737 + return rv; 738 + }
+43
external/libpthread_workqueue-0.8.2/src/posix/platform.h
··· 1 + #ifndef _PTWQ_POSIX_PLATFORM_H 2 + #define _PTWQ_POSIX_PLATFORM_H 1 3 + 4 + /* Workaround to get visibility for _SC_NPROCESSORS_ONLN on FreeBSD */ 5 + #define __BSD_VISIBLE 1 6 + 7 + #include <sys/resource.h> 8 + #include <sys/queue.h> 9 + #include <stdint.h> 10 + #include <string.h> 11 + #include <strings.h> 12 + #include <unistd.h> 13 + #include <pthread.h> 14 + 15 + #ifdef __sun 16 + # include <sys/loadavg.h> 17 + #endif 18 + 19 + /* GCC atomic builtins. 20 + * See: http://gcc.gnu.org/onlinedocs/gcc-4.1.0/gcc/Atomic-Builtins.html 21 + */ 22 + #ifdef __sun 23 + # include <atomic.h> 24 + # define atomic_inc atomic_inc_32 25 + # define atomic_dec atomic_dec_32 26 + # define atomic_and atomic_and_uint_nv 27 + # define atomic_or atomic_or_uint_nv 28 + #else 29 + # define atomic_inc(p) __sync_add_and_fetch((p), 1) 30 + # define atomic_dec(p) __sync_sub_and_fetch((p), 1) 31 + # define atomic_and(p,v) __sync_and_and_fetch((p), (v)) 32 + # define atomic_or(p,v) __sync_or_and_fetch((p), (v)) 33 + #endif 34 + 35 + #ifdef MAKE_STATIC 36 + # define CONSTRUCTOR 37 + #else 38 + # define CONSTRUCTOR __attribute__ ((constructor)) 39 + #endif 40 + #define VISIBLE __attribute__((visibility("default"))) 41 + 42 + 43 + #endif /* _PTWQ_POSIX_PLATFORM_H */
+307
external/libpthread_workqueue-0.8.2/src/posix/thread_info.c
··· 1 + /* 2 + * Copyright (c) 2011, Joakim Johansson <jocke@tbricks.com> 3 + * 4 + * All rights reserved. 5 + * 6 + * Redistribution and use in source and binary forms, with or without 7 + * modification, are permitted provided that the following conditions 8 + * are met: 9 + * 1. Redistributions of source code must retain the above copyright 10 + * notice unmodified, this list of conditions, and the following 11 + * disclaimer. 12 + * 2. Redistributions in binary form must reproduce the above copyright 13 + * notice, this list of conditions and the following disclaimer in the 14 + * documentation and/or other materials provided with the distribution. 15 + * 16 + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 17 + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 18 + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 19 + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 20 + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 21 + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 22 + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 23 + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 24 + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 25 + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 26 + * 27 + */ 28 + 29 + #include "platform.h" 30 + #include "private.h" 31 + 32 + #if defined(__sun) 33 + 34 + #include <stdio.h> 35 + #include <procfs.h> 36 + #include <sys/types.h> 37 + #include <sys/stat.h> 38 + #include <sys/syscall.h> 39 + #include <fcntl.h> 40 + 41 + /* 42 + 43 + /proc for Solaris 44 + 45 + STRUCTURE OF /proc/pid 46 + A given directory /proc/pid contains the following entries. 47 + A process can use the invisible alias /proc/self if it 48 + wishes to open one of its own /proc files (invisible in the 49 + sense that the name ``self'' does not appear in a directory 50 + listing of /proc obtained from ls(1), getdents(2), or 51 + readdir(3C)). 52 + ... 53 + lstatus 54 + Contains a prheader structure followed by an array of 55 + lwpstatus structures, one for each active lwp in the process 56 + (see also /proc/pid/lwp/lwpid/lwpstatus, below). The 57 + prheader structure describes the number and size of the 58 + array entries that follow. 59 + 60 + typedef struct prheader { 61 + long pr_nent; // number of entries 62 + size_t pr_entsize; // size of each entry, in bytes 63 + } prheader_t; 64 + 65 + The lwpstatus structure may grow by the addition of elements 66 + at the end in future releases of the system. Programs must 67 + use pr_entsize in the file header to index through the 68 + array. These comments apply to all /proc files that include 69 + a prheader structure (lpsinfo and lusage, below). 70 + 71 + /proc/self/lstatus 72 + */ 73 + 74 + int threads_runnable(unsigned int *threads_running) 75 + { 76 + const char *path = "/proc/self/lstatus"; 77 + int read_fd, retval = -1, i; 78 + unsigned int running_count = 0; 79 + char *lwp_buffer; 80 + ssize_t actual_read; 81 + lwpstatus_t *lwpstatus; 82 + prheader_t prheader; 83 + 84 + read_fd = open(path, O_RDONLY); 85 + if (read_fd == -1) 86 + { 87 + dbg_perror("open()"); 88 + return retval; 89 + } 90 + 91 + if (fcntl(read_fd, F_SETFL, O_NONBLOCK) != 0) 92 + { 93 + dbg_perror("fcntl()"); 94 + goto errout; 95 + } 96 + 97 + actual_read = read(read_fd, &prheader, sizeof(prheader_t)); 98 + 99 + if (actual_read != sizeof(prheader_t)) 100 + { 101 + dbg_printf("read returned wrong number of bytes - %ld instead of %ld", actual_read, sizeof(prheader_t)); 102 + goto errout; 103 + } 104 + 105 + dbg_printf("read prheader, pr_nent = %ld, pr_entsize = %ld, sizeof(lwpstatus_t) = %ld",prheader.pr_nent, prheader.pr_entsize, sizeof(lwpstatus_t)); 106 + 107 + lwp_buffer = malloc(prheader.pr_nent * prheader.pr_entsize); 108 + 109 + if (!lwp_buffer) 110 + { 111 + dbg_perror("malloc(prheader.pr_nent * prheader.pr_entsize)"); 112 + goto errout; 113 + } 114 + 115 + actual_read = read(read_fd, lwp_buffer, (prheader.pr_nent * prheader.pr_entsize)); 116 + 117 + if (actual_read != (prheader.pr_nent * prheader.pr_entsize)) 118 + { 119 + dbg_printf("read returned wrong number of bytes - %ld instead of %ld", actual_read, prheader.pr_nent * prheader.pr_entsize); 120 + free(lwp_buffer); 121 + goto errout; 122 + } 123 + 124 + for (i = 0; i < prheader.pr_nent; i++) 125 + { 126 + lwpstatus = (lwpstatus_t *) (lwp_buffer + (i * prheader.pr_entsize)); 127 + dbg_printf("lwp %d, syscall = %d", lwpstatus->pr_lwpid, lwpstatus->pr_syscall); 128 + 129 + if (lwpstatus->pr_flags & PR_ASLEEP) 130 + { 131 + dbg_printf("lwp %d is sleeping",lwpstatus->pr_lwpid); 132 + } 133 + else 134 + { 135 + running_count++; 136 + dbg_printf("lwp %d is running",lwpstatus->pr_lwpid); 137 + } 138 + } 139 + 140 + free(lwp_buffer); 141 + retval = 0; 142 + *threads_running = running_count; 143 + 144 + errout: 145 + if (close(read_fd) != 0) 146 + { 147 + dbg_perror("close()"); 148 + } 149 + 150 + return retval; 151 + } 152 + 153 + #elif defined(__linux__) 154 + 155 + /* 156 + 157 + /proc for Linux 158 + 159 + /proc/self 160 + 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. 161 + 162 + ������� 163 + 164 + /proc/[number]/stat 165 + Status information about the process. This is used by ps(1). It is defined in /usr/src/linux/fs/proc/array.c. 166 + The fields, in order, with their proper scanf(3) format specifiers, are: 167 + 168 + pid %d 169 + The process ID. 170 + 171 + comm %s 172 + The filename of the executable, in parentheses. This is visible whether or not the executable is swapped out. 173 + 174 + state %c 175 + 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. 176 + 177 + --------------- 178 + 179 + /proc/[number]/task (since kernel 2.6.0-test6) 180 + 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). 181 + 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)). 182 + 183 + --------------- 184 + 185 + Example: 186 + 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 187 + 188 + */ 189 + 190 + #include <stdio.h> 191 + #include <sys/types.h> 192 + #include <dirent.h> 193 + #include <errno.h> 194 + #include <fcntl.h> 195 + 196 + #define MAX_RESULT_SIZE 4096 197 + 198 + static int _read_file(const char *path, char *result) 199 + { 200 + int read_fd, retval = -1; 201 + ssize_t actual_read; 202 + 203 + read_fd = open(path, O_RDONLY); 204 + if (read_fd == -1) 205 + { 206 + dbg_perror("open()"); 207 + return retval; 208 + } 209 + 210 + if (fcntl(read_fd, F_SETFL, O_NONBLOCK) != 0) 211 + { 212 + dbg_perror("fcntl()"); 213 + goto errout; 214 + } 215 + 216 + 217 + actual_read = read(read_fd, result, MAX_RESULT_SIZE); 218 + 219 + # ifdef __ia64__ 220 + dbg_printf("read %ld from %s", actual_read, path); 221 + # else 222 + dbg_printf("read %zd from %s", actual_read, path); 223 + #endif 224 + 225 + if (actual_read == 0) 226 + { 227 + goto errout; 228 + } 229 + 230 + retval = 0; 231 + 232 + errout: 233 + if (close(read_fd) != 0) 234 + { 235 + dbg_perror("close()"); 236 + } 237 + 238 + return retval; 239 + } 240 + 241 + 242 + int threads_runnable(unsigned int *threads_running) 243 + { 244 + DIR *dip; 245 + struct dirent *dit; 246 + const char *task_path = "/proc/self/task"; 247 + char thread_path[1024]; 248 + char thread_data[MAX_RESULT_SIZE+1]; 249 + char dummy[MAX_RESULT_SIZE+1]; 250 + char state; 251 + int pid; 252 + unsigned int running_count = 0; 253 + 254 + dbg_puts("Checking threads_runnable()"); 255 + 256 + if ((dip = opendir(task_path)) == NULL) 257 + { 258 + dbg_perror("opendir"); 259 + return -1; 260 + } 261 + 262 + while ((dit = readdir(dip)) != NULL) 263 + { 264 + memset(thread_data, 0, sizeof(thread_data)); 265 + 266 + sprintf(thread_path, "%s/%s/stat",task_path, dit->d_name); 267 + 268 + if (_read_file(thread_path, thread_data) == 0) 269 + { 270 + if (sscanf(thread_data, "%d %s %c", &pid, dummy, &state) == 3) 271 + { 272 + dbg_printf("The state for thread %s is %c", dit->d_name, state); 273 + switch (state) 274 + { 275 + case 'R': 276 + running_count++; 277 + break; 278 + default: 279 + break; 280 + } 281 + } 282 + else 283 + { 284 + dbg_printf("Failed to scan state for thread %s (%s)", dit->d_name, thread_data); 285 + } 286 + } 287 + } 288 + 289 + if (closedir(dip) == -1) 290 + { 291 + perror("closedir"); 292 + } 293 + 294 + dbg_printf("Running count is %d", running_count); 295 + *threads_running = running_count; 296 + 297 + return 0; 298 + } 299 + 300 + #else 301 + 302 + int threads_runnable(unsigned int *threads_running) 303 + { 304 + return -1; 305 + } 306 + 307 + #endif
+85
external/libpthread_workqueue-0.8.2/src/posix/thread_rt.c
··· 1 + /* 2 + * Copyright (c) 2011, Joakim Johansson <jocke@tbricks.com> 3 + * 4 + * All rights reserved. 5 + * 6 + * Redistribution and use in source and binary forms, with or without 7 + * modification, are permitted provided that the following conditions 8 + * are met: 9 + * 1. Redistributions of source code must retain the above copyright 10 + * notice unmodified, this list of conditions, and the following 11 + * disclaimer. 12 + * 2. Redistributions in binary form must reproduce the above copyright 13 + * notice, this list of conditions and the following disclaimer in the 14 + * documentation and/or other materials provided with the distribution. 15 + * 16 + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 17 + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 18 + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 19 + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 20 + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 21 + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 22 + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 23 + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 24 + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 25 + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 26 + * 27 + */ 28 + 29 + #include "platform.h" 30 + #include "private.h" 31 + 32 + #if defined(__sun) 33 + 34 + #include <stdio.h> 35 + #include <pthread.h> 36 + #include <sys/types.h> 37 + #include <sys/signal.h> 38 + #include <sys/procset.h> 39 + #include <sys/priocntl.h> 40 + #include <sys/rtpriocntl.h> 41 + #include <sys/tspriocntl.h> 42 + #include <sys/iapriocntl.h> 43 + #include <sys/fsspriocntl.h> 44 + #include <sys/fxpriocntl.h> 45 + 46 + // Set the RT priority - it is inveresed from the queue priorities, higher is better 47 + // We give '0' to low prio queues and the highest possible for the 'high' prio queue (currently 2) 48 + 49 + void ptwq_set_current_thread_priority(int priority) 50 + { 51 + long retval = 0; 52 + 53 + dbg_printf("reconfiguring thread for priority level=%u", priority); 54 + 55 + switch (priority) 56 + { 57 + case WORKQ_LOW_PRIOQUEUE: 58 + retval = priocntl(P_LWPID, P_MYID, PC_SETXPARMS, "TS", 0); // run low prio queues as time sharing 59 + break; 60 + case WORKQ_DEFAULT_PRIOQUEUE: 61 + retval = priocntl(P_LWPID, P_MYID, PC_SETXPARMS, "RT", RT_KY_PRI, WORKQ_NUM_PRIOQUEUE - priority - 1, 0); 62 + break; 63 + case WORKQ_HIGH_PRIOQUEUE: 64 + retval = priocntl(P_LWPID, P_MYID, PC_SETXPARMS, "RT", RT_KY_PRI, WORKQ_NUM_PRIOQUEUE - priority - 1, 0); 65 + break; 66 + default: 67 + dbg_printf("Unknown priority level = %u", priority); 68 + break; 69 + } 70 + 71 + 72 + if (retval != 0) 73 + dbg_perror("priocntl()"); 74 + 75 + return; 76 + } 77 + 78 + #else 79 + 80 + void ptwq_set_current_thread_priority(int priority __attribute__ ((unused))) 81 + { 82 + return; 83 + } 84 + 85 + #endif
+127
external/libpthread_workqueue-0.8.2/src/private.h
··· 1 + /*- 2 + * Copyright (c) 2011, Mark Heily <mark@heily.com> 3 + * Copyright (c) 2009, Stacey Son <sson@freebsd.org> 4 + * Copyright (c) 2000-2008, Apple Inc. 5 + * All rights reserved. 6 + * 7 + * Redistribution and use in source and binary forms, with or without 8 + * modification, are permitted provided that the following conditions 9 + * are met: 10 + * 1. Redistributions of source code must retain the above copyright 11 + * notice unmodified, this list of conditions, and the following 12 + * disclaimer. 13 + * 2. Redistributions in binary form must reproduce the above copyright 14 + * notice, this list of conditions and the following disclaimer in the 15 + * documentation and/or other materials provided with the distribution. 16 + * 17 + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 18 + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 19 + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 20 + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 21 + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 22 + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 23 + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 24 + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 25 + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 26 + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27 + * 28 + */ 29 + 30 + #ifndef _PTWQ_PRIVATE_H 31 + #define _PTWQ_PRIVATE_H 1 32 + 33 + #include <errno.h> 34 + #include <limits.h> 35 + #include <signal.h> 36 + #include <stdlib.h> 37 + #include <stdio.h> 38 + #include <string.h> 39 + 40 + #if defined(_WIN32) 41 + # include "windows/platform.h" 42 + #else 43 + # include "posix/platform.h" 44 + #endif 45 + 46 + #include "pthread_workqueue.h" 47 + #include "debug.h" 48 + 49 + /* The maximum number of workqueues that can be created. 50 + This is based on libdispatch only needing 6 workqueues. 51 + */ 52 + #define PTHREAD_WORKQUEUE_MAX 31 53 + 54 + /* The total number of priority levels. */ 55 + #define WORKQ_NUM_PRIOQUEUE 3 56 + 57 + /* Signatures/magic numbers. */ 58 + #define PTHREAD_WORKQUEUE_SIG 0xBEBEBEBE 59 + #define PTHREAD_WORKQUEUE_ATTR_SIG 0xBEBEBEBE 60 + 61 + /* Whether to use real-time threads for the workers if available */ 62 + 63 + extern unsigned int PWQ_RT_THREADS; 64 + extern time_t PWQ_SPIN_USEC; 65 + extern unsigned int PWQ_SPIN_THREADS; 66 + 67 + /* A limit of the number of cpu:s that we view as available, useful when e.g. using processor sets */ 68 + extern unsigned int PWQ_ACTIVE_CPU; 69 + 70 + #if __GNUC__ 71 + #define fastpath(x) ((__typeof__(x))__builtin_expect((long)(x), ~0l)) 72 + #define slowpath(x) ((__typeof__(x))__builtin_expect((long)(x), 0l)) 73 + #else 74 + #define fastpath(x) (x) 75 + #define slowpath(x) (x) 76 + #endif 77 + 78 + #define CACHELINE_SIZE 64 79 + #define ROUND_UP_TO_CACHELINE_SIZE(x) (((x) + (CACHELINE_SIZE - 1)) & ~(CACHELINE_SIZE - 1)) 80 + 81 + /* 82 + * The work item cache, has three different optional implementations: 83 + * 1. No cache, just normal malloc/free using the standard malloc library in use 84 + * 2. Libumem based object cache, requires linkage with libumem - for non-Solaris see http://labs.omniti.com/labs/portableumem 85 + * this is the most balanced cache supporting migration across threads of allocated/freed witems 86 + * 3. TSD based cache, modelled on libdispatch continuation implementation, can lead to imbalance with assymetric 87 + * producer/consumer threads as allocated memory is cached by the thread freeing it 88 + */ 89 + 90 + #define WITEM_CACHE_TYPE 1 // Set to 1, 2 or 3 to specify witem cache implementation to use 91 + 92 + struct work { 93 + STAILQ_ENTRY(work) item_entry; 94 + void (*func)(void *); 95 + void *func_arg; 96 + unsigned int flags; 97 + unsigned int gencount; 98 + #if (WITEM_CACHE_TYPE == 3) 99 + struct work *volatile wi_next; 100 + #endif 101 + }; 102 + 103 + struct _pthread_workqueue { 104 + unsigned int sig; /* Unique signature for this structure */ 105 + unsigned int flags; 106 + int queueprio; 107 + int overcommit; 108 + unsigned int wqlist_index; 109 + STAILQ_HEAD(,work) item_listhead; 110 + pthread_spinlock_t mtx; 111 + #ifdef WORKQUEUE_PLATFORM_SPECIFIC 112 + WORKQUEUE_PLATFORM_SPECIFIC; 113 + #endif 114 + }; 115 + 116 + /* manager.c */ 117 + int manager_init(void); 118 + unsigned long manager_peek(const char *); 119 + void manager_workqueue_create(struct _pthread_workqueue *); 120 + void manager_workqueue_additem(struct _pthread_workqueue *, struct work *); 121 + 122 + struct work *witem_alloc(void (*func)(void *), void *func_arg); // returns a properly initialized witem 123 + void witem_free(struct work *wi); 124 + int witem_cache_init(void); 125 + void witem_cache_cleanup(void *value); 126 + 127 + #endif /* _PTWQ_PRIVATE_H */
+34
external/libpthread_workqueue-0.8.2/src/thread_info.h
··· 1 + /* 2 + * Copyright (c) 2011, Joakim Johansson <jocke@tbricks.com> 3 + * 4 + * All rights reserved. 5 + * 6 + * Redistribution and use in source and binary forms, with or without 7 + * modification, are permitted provided that the following conditions 8 + * are met: 9 + * 1. Redistributions of source code must retain the above copyright 10 + * notice unmodified, this list of conditions, and the following 11 + * disclaimer. 12 + * 2. Redistributions in binary form must reproduce the above copyright 13 + * notice, this list of conditions and the following disclaimer in the 14 + * documentation and/or other materials provided with the distribution. 15 + * 16 + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 17 + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 18 + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 19 + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 20 + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 21 + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 22 + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 23 + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 24 + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 25 + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 26 + * 27 + */ 28 + 29 + #ifndef _PTWQ_POSIX_THREAD_INFO_H 30 + #define _PTWQ_POSIX_THREAD_INFO_H 1 31 + 32 + int threads_runnable(unsigned int *threads_running); 33 + 34 + #endif /* _PTWQ_POSIX_THREAD_INFO_H */
+34
external/libpthread_workqueue-0.8.2/src/thread_rt.h
··· 1 + /* 2 + * Copyright (c) 2011, Joakim Johansson <jocke@tbricks.com> 3 + * 4 + * All rights reserved. 5 + * 6 + * Redistribution and use in source and binary forms, with or without 7 + * modification, are permitted provided that the following conditions 8 + * are met: 9 + * 1. Redistributions of source code must retain the above copyright 10 + * notice unmodified, this list of conditions, and the following 11 + * disclaimer. 12 + * 2. Redistributions in binary form must reproduce the above copyright 13 + * notice, this list of conditions and the following disclaimer in the 14 + * documentation and/or other materials provided with the distribution. 15 + * 16 + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 17 + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 18 + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 19 + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 20 + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 21 + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 22 + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 23 + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 24 + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 25 + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 26 + * 27 + */ 28 + 29 + #ifndef _PTWQ_THREAD_RT_H 30 + #define _PTWQ_THREAD_RT_H 1 31 + 32 + void ptwq_set_current_thread_priority(int priority); // higher is better 33 + 34 + #endif /* _PTWQ_THREAD_RT_H */
+198
external/libpthread_workqueue-0.8.2/src/windows/manager.c
··· 1 + /*- 2 + * Copyright (c) 2011, Mark Heily <mark@heily.com> 3 + * All rights reserved. 4 + * 5 + * Redistribution and use in source and binary forms, with or without 6 + * modification, are permitted provided that the following conditions 7 + * are met: 8 + * 1. Redistributions of source code must retain the above copyright 9 + * notice unmodified, this list of conditions, and the following 10 + * disclaimer. 11 + * 2. Redistributions in binary form must reproduce the above copyright 12 + * notice, this list of conditions and the following disclaimer in the 13 + * documentation and/or other materials provided with the distribution. 14 + * 15 + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 16 + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 17 + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 18 + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 19 + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 20 + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 21 + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 22 + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 23 + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 24 + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25 + * 26 + */ 27 + 28 + #include "platform.h" 29 + #include "../private.h" 30 + #include "pthread_workqueue.h" 31 + 32 + #ifdef PROVIDE_LEGACY_XP_SUPPORT 33 + 34 + static LIST_HEAD(, _pthread_workqueue) wqlist[WORKQ_NUM_PRIOQUEUE]; 35 + static pthread_rwlock_t wqlist_mtx; 36 + 37 + int 38 + manager_init(void) 39 + { 40 + pthread_rwlock_init(&wqlist_mtx, NULL); 41 + return (0); 42 + } 43 + 44 + void 45 + manager_workqueue_create(struct _pthread_workqueue *workq) 46 + { 47 + pthread_rwlock_wrlock(&wqlist_mtx); 48 + LIST_INSERT_HEAD(&wqlist[workq->queueprio], workq, wqlist_entry); 49 + pthread_rwlock_unlock(&wqlist_mtx); 50 + 51 + pthread_spin_init(&workq->mtx, PTHREAD_PROCESS_PRIVATE); 52 + } 53 + 54 + /* The caller must hold the wqlist_mtx. */ 55 + static struct work * 56 + wqlist_scan(void) 57 + { 58 + pthread_workqueue_t workq; 59 + struct work *witem = NULL; 60 + int i; 61 + 62 + pthread_rwlock_rdlock(&wqlist_mtx); 63 + for (i = 0; i < WORKQ_NUM_PRIOQUEUE; i++) { 64 + LIST_FOREACH(workq, &wqlist[i], wqlist_entry) { 65 + pthread_spin_lock(&workq->mtx); 66 + 67 + if (STAILQ_EMPTY(&workq->item_listhead)) { 68 + pthread_spin_unlock(&workq->mtx); 69 + continue; 70 + } 71 + 72 + witem = STAILQ_FIRST(&workq->item_listhead); 73 + if (witem != NULL) 74 + STAILQ_REMOVE_HEAD(&workq->item_listhead, item_entry); 75 + 76 + pthread_spin_unlock(&workq->mtx); 77 + goto out; 78 + } 79 + } 80 + 81 + out: 82 + pthread_rwlock_unlock(&wqlist_mtx); 83 + return (witem); 84 + } 85 + 86 + DWORD WINAPI 87 + worker_main(LPVOID arg) 88 + { 89 + struct work *witem; 90 + 91 + witem = wqlist_scan(); 92 + if (witem == NULL) 93 + return (0); 94 + 95 + witem->func(witem->func_arg); 96 + free(witem); 97 + return (0); 98 + } 99 + 100 + void 101 + manager_workqueue_additem(struct _pthread_workqueue *workq, struct work *witem) 102 + { 103 + pthread_spin_lock(&workq->mtx); 104 + STAILQ_INSERT_TAIL(&workq->item_listhead, witem, item_entry); 105 + pthread_spin_unlock(&workq->mtx); 106 + if (!QueueUserWorkItem(worker_main, NULL, WT_EXECUTELONGFUNCTION)) 107 + abort(); 108 + } 109 + 110 + #else 111 + 112 + int 113 + manager_init(void) 114 + { 115 + return (0); 116 + } 117 + 118 + void 119 + manager_workqueue_create(struct _pthread_workqueue *workq) 120 + { 121 + PTP_POOL pool; 122 + PTP_CALLBACK_ENVIRON callback; 123 + SYSTEM_INFO sysinfo; 124 + 125 + pool = CreateThreadpool(NULL); 126 + if(pool == NULL){ 127 + dbg_lasterror("CreateThreadpool()"); 128 + return; 129 + } 130 + 131 + InitializeThreadpoolEnvironment(&workq->win_callback_env); 132 + callback = &workq->win_callback_env; 133 + SetThreadpoolCallbackPool(callback, pool); 134 + 135 + switch(workq->queueprio){ 136 + case WORKQ_HIGH_PRIOQUEUE: 137 + // weird but this seems the only valid solution !? 138 + SetThreadpoolCallbackPriority(callback, TP_CALLBACK_PRIORITY_LOW); 139 + break; 140 + case WORKQ_LOW_PRIOQUEUE: 141 + // see above 142 + SetThreadpoolCallbackPriority(callback, TP_CALLBACK_PRIORITY_HIGH); 143 + break; 144 + default: 145 + SetThreadpoolCallbackPriority(callback, TP_CALLBACK_PRIORITY_NORMAL); 146 + break; 147 + } 148 + 149 + // we need a proper way to implement overcommitting on windows 150 + if(workq->overcommit){ 151 + GetSystemInfo(&sysinfo); 152 + SetThreadpoolThreadMaximum(pool, sysinfo.dwNumberOfProcessors * 2); 153 + } 154 + 155 + workq->win_thread_pool = pool; 156 + } 157 + 158 + VOID CALLBACK 159 + worker_main( PTP_CALLBACK_INSTANCE instance, PVOID Parameter, PTP_WORK work ) 160 + { 161 + struct work* witem = (struct work*)Parameter; 162 + 163 + assert(witem); 164 + witem->func(witem->func_arg); 165 + free(witem); 166 + CloseThreadpoolWork(work); 167 + } 168 + 169 + void 170 + manager_workqueue_additem(struct _pthread_workqueue *workq, struct work *witem) 171 + { 172 + PTP_WORK work = CreateThreadpoolWork(worker_main, witem, &workq->win_callback_env); 173 + if(work == NULL) { 174 + dbg_lasterror("CreateThreadpoolWork()"); 175 + return; 176 + } 177 + SubmitThreadpoolWork(work); 178 + } 179 + 180 + // TODO: We need to cleanly close the environment and threadpools! 181 + 182 + #endif 183 + 184 + unsigned long 185 + manager_peek(const char *key) 186 + { 187 + unsigned long rv; 188 + 189 + if (strcmp(key, "combined_idle") == 0) { 190 + dbg_puts("TODO"); 191 + abort(); 192 + } else { 193 + dbg_printf("invalid key: ", key); 194 + abort(); 195 + } 196 + 197 + return rv; 198 + }
+56
external/libpthread_workqueue-0.8.2/src/windows/platform.c
··· 1 + /*- 2 + * Copyright (c) 2011, Mark Heily <mark@heily.com> 3 + * All rights reserved. 4 + * 5 + * Redistribution and use in source and binary forms, with or without 6 + * modification, are permitted provided that the following conditions 7 + * are met: 8 + * 1. Redistributions of source code must retain the above copyright 9 + * notice unmodified, this list of conditions, and the following 10 + * disclaimer. 11 + * 2. Redistributions in binary form must reproduce the above copyright 12 + * notice, this list of conditions and the following disclaimer in the 13 + * documentation and/or other materials provided with the distribution. 14 + * 15 + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 16 + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 17 + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 18 + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 19 + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 20 + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 21 + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 22 + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 23 + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 24 + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25 + * 26 + */ 27 + 28 + #include "platform.h" 29 + #include "../private.h" 30 + #include "pthread_workqueue.h" 31 + 32 + #ifndef MAKE_STATIC 33 + 34 + // The constructor to be called 35 + int VISIBLE CONSTRUCTOR pthread_workqueue_init_np(void); 36 + 37 + BOOL WINAPI DllMain( 38 + HINSTANCE hinstDLL, // handle to DLL module 39 + DWORD fdwReason, // reason for calling function 40 + LPVOID lpReserved ) // reserved 41 + { 42 + // Perform actions based on the reason for calling. 43 + switch( fdwReason ) 44 + { 45 + case DLL_PROCESS_ATTACH: 46 + // Initialize once for each new process. 47 + // Return FALSE to fail DLL load. 48 + if( pthread_workqueue_init_np() < 0) 49 + return FALSE; 50 + break; 51 + 52 + } 53 + return TRUE; // Successful DLL_PROCESS_ATTACH. 54 + } 55 + 56 + #endif
+42
external/libpthread_workqueue-0.8.2/src/windows/platform.h
··· 1 + #ifndef _PTWQ_WINDOWS_PLATFORM_H 2 + #define _PTWQ_WINDOWS_PLATFORM_H 1 3 + 4 + #define PROVIDE_LEGACY_XP_SUPPORT 1 5 + 6 + #ifdef PROVIDE_LEGACY_XP_SUPPORT 7 + # define _WIN32_WINNT 0x0500 8 + #else 9 + # define _WIN32_WINNT 0x0610 10 + #endif 11 + #define WIN32_LEAN_AND_MEAN 12 + 13 + #include <windows.h> 14 + #include <string.h> 15 + #include "winpthreads.h" 16 + 17 + /* Instead of __attribute__ ((constructor)), use DllMain() */ 18 + #define CONSTRUCTOR /* */ 19 + 20 + #define VISIBLE __declspec(dllexport) 21 + 22 + # define __func__ __FUNCTION__ 23 + 24 + #undef LIST_HEAD 25 + #include "queue.h" 26 + 27 + #define sleep(sec) Sleep(1000*sec) 28 + #define strdup(p) _strdup(p) 29 + #define random() rand() 30 + 31 + #ifdef PROVIDE_LEGACY_XP_SUPPORT 32 + # define WORKQUEUE_PLATFORM_SPECIFIC \ 33 + LIST_ENTRY(_pthread_workqueue) wqlist_entry 34 + #else 35 + /* Specific workqueue items */ 36 + # define WORKQUEUE_PLATFORM_SPECIFIC \ 37 + PTP_POOL win_thread_pool; \ 38 + TP_CALLBACK_ENVIRON win_callback_env 39 + #endif 40 + 41 + 42 + #endif /* _PTWQ_WINDOWS_PLATFORM_H */
+58
external/libpthread_workqueue-0.8.2/src/windows/pthread_cond.h
··· 1 + /*- 2 + * Copyright (c) 2011, Mark Heily <mark@heily.com> 3 + * All rights reserved. 4 + * 5 + * Redistribution and use in source and binary forms, with or without 6 + * modification, are permitted provided that the following conditions 7 + * are met: 8 + * 1. Redistributions of source code must retain the above copyright 9 + * notice unmodified, this list of conditions, and the following 10 + * disclaimer. 11 + * 2. Redistributions in binary form must reproduce the above copyright 12 + * notice, this list of conditions and the following disclaimer in the 13 + * documentation and/or other materials provided with the distribution. 14 + * 15 + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 16 + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 17 + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 18 + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 19 + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 20 + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 21 + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 22 + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 23 + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 24 + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25 + * 26 + */ 27 + 28 + /* 29 + * Windows condition variables 30 + */ 31 + #if WINVER >= 0x0600 32 + 33 + typedef CONDITION_VARIABLE pthread_cond_t; 34 + typedef int pthread_condattr_t; 35 + 36 + static inline int 37 + pthread_cond_init(pthread_cond_t *cond, pthread_condattr_t *cond_attr) 38 + { 39 + InitializeConditionVariable(cond); 40 + return (0); 41 + } 42 + 43 + static inline int 44 + pthread_cond_wait(pthread_cond_t *cond, pthread_mutex_t *mutex) 45 + { 46 + return (SleepConditionVariableCS(cond, mutex, INFINITE) == 0); 47 + } 48 + 49 + static inline int 50 + pthread_cond_signal(pthread_cond_t *cond) 51 + { 52 + WakeConditionVariable(cond); 53 + return (0); 54 + } 55 + 56 + #else 57 + # error Conditional variables require Vista or newer 58 + #endif
+624
external/libpthread_workqueue-0.8.2/src/windows/queue.h
··· 1 + /*- 2 + * Copyright (c) 1991, 1993 3 + * The Regents of the University of California. All rights reserved. 4 + * 5 + * Redistribution and use in source and binary forms, with or without 6 + * modification, are permitted provided that the following conditions 7 + * are met: 8 + * 1. Redistributions of source code must retain the above copyright 9 + * notice, this list of conditions and the following disclaimer. 10 + * 2. Redistributions in binary form must reproduce the above copyright 11 + * notice, this list of conditions and the following disclaimer in the 12 + * documentation and/or other materials provided with the distribution. 13 + * 4. Neither the name of the University nor the names of its contributors 14 + * may be used to endorse or promote products derived from this software 15 + * without specific prior written permission. 16 + * 17 + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 18 + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 19 + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 20 + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 21 + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 22 + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 23 + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 24 + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 25 + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 26 + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 27 + * SUCH DAMAGE. 28 + * 29 + * @(#)queue.h 8.5 (Berkeley) 8/20/94 30 + * $FreeBSD: src/sys/sys/queue.h,v 1.72.2.1.2.1 2009/10/25 01:10:29 kensmith Exp $ 31 + */ 32 + 33 + #ifndef _SYS_QUEUE_H_ 34 + #define _SYS_QUEUE_H_ 35 + 36 + /* 37 + * This file defines four types of data structures: singly-linked lists, 38 + * singly-linked tail queues, lists and tail queues. 39 + * 40 + * A singly-linked list is headed by a single forward pointer. The elements 41 + * are singly linked for minimum space and pointer manipulation overhead at 42 + * the expense of O(n) removal for arbitrary elements. New elements can be 43 + * added to the list after an existing element or at the head of the list. 44 + * Elements being removed from the head of the list should use the explicit 45 + * macro for this purpose for optimum efficiency. A singly-linked list may 46 + * only be traversed in the forward direction. Singly-linked lists are ideal 47 + * for applications with large datasets and few or no removals or for 48 + * implementing a LIFO queue. 49 + * 50 + * A singly-linked tail queue is headed by a pair of pointers, one to the 51 + * head of the list and the other to the tail of the list. The elements are 52 + * singly linked for minimum space and pointer manipulation overhead at the 53 + * expense of O(n) removal for arbitrary elements. New elements can be added 54 + * to the list after an existing element, at the head of the list, or at the 55 + * end of the list. Elements being removed from the head of the tail queue 56 + * should use the explicit macro for this purpose for optimum efficiency. 57 + * A singly-linked tail queue may only be traversed in the forward direction. 58 + * Singly-linked tail queues are ideal for applications with large datasets 59 + * and few or no removals or for implementing a FIFO queue. 60 + * 61 + * A list is headed by a single forward pointer (or an array of forward 62 + * pointers for a hash table header). The elements are doubly linked 63 + * so that an arbitrary element can be removed without a need to 64 + * traverse the list. New elements can be added to the list before 65 + * or after an existing element or at the head of the list. A list 66 + * may only be traversed in the forward direction. 67 + * 68 + * A tail queue is headed by a pair of pointers, one to the head of the 69 + * list and the other to the tail of the list. The elements are doubly 70 + * linked so that an arbitrary element can be removed without a need to 71 + * traverse the list. New elements can be added to the list before or 72 + * after an existing element, at the head of the list, or at the end of 73 + * the list. A tail queue may be traversed in either direction. 74 + * 75 + * For details on the use of these macros, see the queue(3) manual page. 76 + * 77 + * 78 + * SLIST LIST STAILQ TAILQ 79 + * _HEAD + + + + 80 + * _HEAD_INITIALIZER + + + + 81 + * _ENTRY + + + + 82 + * _INIT + + + + 83 + * _EMPTY + + + + 84 + * _FIRST + + + + 85 + * _NEXT + + + + 86 + * _PREV - - - + 87 + * _LAST - - + + 88 + * _FOREACH + + + + 89 + * _FOREACH_SAFE + + + + 90 + * _FOREACH_REVERSE - - - + 91 + * _FOREACH_REVERSE_SAFE - - - + 92 + * _INSERT_HEAD + + + + 93 + * _INSERT_BEFORE - + - + 94 + * _INSERT_AFTER + + + + 95 + * _INSERT_TAIL - - + + 96 + * _CONCAT - - + + 97 + * _REMOVE_AFTER + - + - 98 + * _REMOVE_HEAD + - + - 99 + * _REMOVE + + + + 100 + * 101 + */ 102 + #ifdef QUEUE_MACRO_DEBUG 103 + /* Store the last 2 places the queue element or head was altered */ 104 + struct qm_trace { 105 + char * lastfile; 106 + int lastline; 107 + char * prevfile; 108 + int prevline; 109 + }; 110 + 111 + #define TRACEBUF struct qm_trace trace; 112 + #define TRASHIT(x) do {(x) = (void *)-1;} while (0) 113 + 114 + #define QMD_TRACE_HEAD(head) do { \ 115 + (head)->trace.prevline = (head)->trace.lastline; \ 116 + (head)->trace.prevfile = (head)->trace.lastfile; \ 117 + (head)->trace.lastline = __LINE__; \ 118 + (head)->trace.lastfile = __FILE__; \ 119 + } while (0) 120 + 121 + #define QMD_TRACE_ELEM(elem) do { \ 122 + (elem)->trace.prevline = (elem)->trace.lastline; \ 123 + (elem)->trace.prevfile = (elem)->trace.lastfile; \ 124 + (elem)->trace.lastline = __LINE__; \ 125 + (elem)->trace.lastfile = __FILE__; \ 126 + } while (0) 127 + 128 + #else 129 + #define QMD_TRACE_ELEM(elem) 130 + #define QMD_TRACE_HEAD(head) 131 + #define TRACEBUF 132 + #define TRASHIT(x) 133 + #endif /* QUEUE_MACRO_DEBUG */ 134 + 135 + #ifndef _WIN32 136 + /* 137 + * Singly-linked List declarations. 138 + */ 139 + #define SLIST_HEAD(name, type) \ 140 + struct name { \ 141 + struct type *slh_first; /* first element */ \ 142 + } 143 + 144 + #define SLIST_HEAD_INITIALIZER(head) \ 145 + { NULL } 146 + 147 + #define SLIST_ENTRY(type) \ 148 + struct { \ 149 + struct type *sle_next; /* next element */ \ 150 + } 151 + 152 + /* 153 + * Singly-linked List functions. 154 + */ 155 + #define SLIST_EMPTY(head) ((head)->slh_first == NULL) 156 + 157 + #define SLIST_FIRST(head) ((head)->slh_first) 158 + 159 + #define SLIST_FOREACH(var, head, field) \ 160 + for ((var) = SLIST_FIRST((head)); \ 161 + (var); \ 162 + (var) = SLIST_NEXT((var), field)) 163 + 164 + #define SLIST_FOREACH_SAFE(var, head, field, tvar) \ 165 + for ((var) = SLIST_FIRST((head)); \ 166 + (var) && ((tvar) = SLIST_NEXT((var), field), 1); \ 167 + (var) = (tvar)) 168 + 169 + #define SLIST_FOREACH_PREVPTR(var, varp, head, field) \ 170 + for ((varp) = &SLIST_FIRST((head)); \ 171 + ((var) = *(varp)) != NULL; \ 172 + (varp) = &SLIST_NEXT((var), field)) 173 + 174 + #define SLIST_INIT(head) do { \ 175 + SLIST_FIRST((head)) = NULL; \ 176 + } while (0) 177 + 178 + #define SLIST_INSERT_AFTER(slistelm, elm, field) do { \ 179 + SLIST_NEXT((elm), field) = SLIST_NEXT((slistelm), field); \ 180 + SLIST_NEXT((slistelm), field) = (elm); \ 181 + } while (0) 182 + 183 + #define SLIST_INSERT_HEAD(head, elm, field) do { \ 184 + SLIST_NEXT((elm), field) = SLIST_FIRST((head)); \ 185 + SLIST_FIRST((head)) = (elm); \ 186 + } while (0) 187 + 188 + #define SLIST_NEXT(elm, field) ((elm)->field.sle_next) 189 + 190 + #define SLIST_REMOVE(head, elm, type, field) do { \ 191 + if (SLIST_FIRST((head)) == (elm)) { \ 192 + SLIST_REMOVE_HEAD((head), field); \ 193 + } \ 194 + else { \ 195 + struct type *curelm = SLIST_FIRST((head)); \ 196 + while (SLIST_NEXT(curelm, field) != (elm)) \ 197 + curelm = SLIST_NEXT(curelm, field); \ 198 + SLIST_REMOVE_AFTER(curelm, field); \ 199 + } \ 200 + TRASHIT((elm)->field.sle_next); \ 201 + } while (0) 202 + 203 + #define SLIST_REMOVE_AFTER(elm, field) do { \ 204 + SLIST_NEXT(elm, field) = \ 205 + SLIST_NEXT(SLIST_NEXT(elm, field), field); \ 206 + } while (0) 207 + 208 + #define SLIST_REMOVE_HEAD(head, field) do { \ 209 + SLIST_FIRST((head)) = SLIST_NEXT(SLIST_FIRST((head)), field); \ 210 + } while (0) 211 + 212 + #endif /* defined(_WIN32) */ 213 + 214 + /* 215 + * Singly-linked Tail queue declarations. 216 + */ 217 + #define STAILQ_HEAD(name, type) \ 218 + struct name { \ 219 + struct type *stqh_first;/* first element */ \ 220 + struct type **stqh_last;/* addr of last next element */ \ 221 + } 222 + 223 + #define STAILQ_HEAD_INITIALIZER(head) \ 224 + { NULL, &(head).stqh_first } 225 + 226 + #define STAILQ_ENTRY(type) \ 227 + struct { \ 228 + struct type *stqe_next; /* next element */ \ 229 + } 230 + 231 + /* 232 + * Singly-linked Tail queue functions. 233 + */ 234 + #define STAILQ_CONCAT(head1, head2) do { \ 235 + if (!STAILQ_EMPTY((head2))) { \ 236 + *(head1)->stqh_last = (head2)->stqh_first; \ 237 + (head1)->stqh_last = (head2)->stqh_last; \ 238 + STAILQ_INIT((head2)); \ 239 + } \ 240 + } while (0) 241 + 242 + #define STAILQ_EMPTY(head) ((head)->stqh_first == NULL) 243 + 244 + #define STAILQ_FIRST(head) ((head)->stqh_first) 245 + 246 + #define STAILQ_FOREACH(var, head, field) \ 247 + for((var) = STAILQ_FIRST((head)); \ 248 + (var); \ 249 + (var) = STAILQ_NEXT((var), field)) 250 + 251 + 252 + #define STAILQ_FOREACH_SAFE(var, head, field, tvar) \ 253 + for ((var) = STAILQ_FIRST((head)); \ 254 + (var) && ((tvar) = STAILQ_NEXT((var), field), 1); \ 255 + (var) = (tvar)) 256 + 257 + #define STAILQ_INIT(head) do { \ 258 + STAILQ_FIRST((head)) = NULL; \ 259 + (head)->stqh_last = &STAILQ_FIRST((head)); \ 260 + } while (0) 261 + 262 + #define STAILQ_INSERT_AFTER(head, tqelm, elm, field) do { \ 263 + if ((STAILQ_NEXT((elm), field) = STAILQ_NEXT((tqelm), field)) == NULL)\ 264 + (head)->stqh_last = &STAILQ_NEXT((elm), field); \ 265 + STAILQ_NEXT((tqelm), field) = (elm); \ 266 + } while (0) 267 + 268 + #define STAILQ_INSERT_HEAD(head, elm, field) do { \ 269 + if ((STAILQ_NEXT((elm), field) = STAILQ_FIRST((head))) == NULL) \ 270 + (head)->stqh_last = &STAILQ_NEXT((elm), field); \ 271 + STAILQ_FIRST((head)) = (elm); \ 272 + } while (0) 273 + 274 + #define STAILQ_INSERT_TAIL(head, elm, field) do { \ 275 + STAILQ_NEXT((elm), field) = NULL; \ 276 + *(head)->stqh_last = (elm); \ 277 + (head)->stqh_last = &STAILQ_NEXT((elm), field); \ 278 + } while (0) 279 + 280 + #define STAILQ_LAST(head, type, field) \ 281 + (STAILQ_EMPTY((head)) ? \ 282 + NULL : \ 283 + ((struct type *)(void *) \ 284 + ((char *)((head)->stqh_last) - __offsetof(struct type, field)))) 285 + 286 + #define STAILQ_NEXT(elm, field) ((elm)->field.stqe_next) 287 + 288 + #define STAILQ_REMOVE(head, elm, type, field) do { \ 289 + if (STAILQ_FIRST((head)) == (elm)) { \ 290 + STAILQ_REMOVE_HEAD((head), field); \ 291 + } \ 292 + else { \ 293 + struct type *curelm = STAILQ_FIRST((head)); \ 294 + while (STAILQ_NEXT(curelm, field) != (elm)) \ 295 + curelm = STAILQ_NEXT(curelm, field); \ 296 + STAILQ_REMOVE_AFTER(head, curelm, field); \ 297 + } \ 298 + TRASHIT((elm)->field.stqe_next); \ 299 + } while (0) 300 + 301 + #define STAILQ_REMOVE_HEAD(head, field) do { \ 302 + if ((STAILQ_FIRST((head)) = \ 303 + STAILQ_NEXT(STAILQ_FIRST((head)), field)) == NULL) \ 304 + (head)->stqh_last = &STAILQ_FIRST((head)); \ 305 + } while (0) 306 + 307 + #define STAILQ_REMOVE_AFTER(head, elm, field) do { \ 308 + if ((STAILQ_NEXT(elm, field) = \ 309 + STAILQ_NEXT(STAILQ_NEXT(elm, field), field)) == NULL) \ 310 + (head)->stqh_last = &STAILQ_NEXT((elm), field); \ 311 + } while (0) 312 + 313 + #define STAILQ_SWAP(head1, head2, type) do { \ 314 + struct type *swap_first = STAILQ_FIRST(head1); \ 315 + struct type **swap_last = (head1)->stqh_last; \ 316 + STAILQ_FIRST(head1) = STAILQ_FIRST(head2); \ 317 + (head1)->stqh_last = (head2)->stqh_last; \ 318 + STAILQ_FIRST(head2) = swap_first; \ 319 + (head2)->stqh_last = swap_last; \ 320 + if (STAILQ_EMPTY(head1)) \ 321 + (head1)->stqh_last = &STAILQ_FIRST(head1); \ 322 + if (STAILQ_EMPTY(head2)) \ 323 + (head2)->stqh_last = &STAILQ_FIRST(head2); \ 324 + } while (0) 325 + 326 + 327 + /* 328 + * List declarations. 329 + * NOTE: LIST_HEAD conflicts with a Linux macro. 330 + */ 331 + #define LIST_HEAD(name, type) \ 332 + struct name { \ 333 + struct type *lh_first; /* first element */ \ 334 + } 335 + 336 + #define LIST_HEAD_INITIALIZER(head) \ 337 + { NULL } 338 + 339 + #define LIST_ENTRY(type) \ 340 + struct { \ 341 + struct type *le_next; /* next element */ \ 342 + struct type **le_prev; /* address of previous next element */ \ 343 + } 344 + 345 + /* 346 + * List functions. 347 + */ 348 + 349 + #if (defined(_KERNEL) && defined(INVARIANTS)) 350 + #define QMD_LIST_CHECK_HEAD(head, field) do { \ 351 + if (LIST_FIRST((head)) != NULL && \ 352 + LIST_FIRST((head))->field.le_prev != \ 353 + &LIST_FIRST((head))) \ 354 + panic("Bad list head %p first->prev != head", (head)); \ 355 + } while (0) 356 + 357 + #define QMD_LIST_CHECK_NEXT(elm, field) do { \ 358 + if (LIST_NEXT((elm), field) != NULL && \ 359 + LIST_NEXT((elm), field)->field.le_prev != \ 360 + &((elm)->field.le_next)) \ 361 + panic("Bad link elm %p next->prev != elm", (elm)); \ 362 + } while (0) 363 + 364 + #define QMD_LIST_CHECK_PREV(elm, field) do { \ 365 + if (*(elm)->field.le_prev != (elm)) \ 366 + panic("Bad link elm %p prev->next != elm", (elm)); \ 367 + } while (0) 368 + #else 369 + #define QMD_LIST_CHECK_HEAD(head, field) 370 + #define QMD_LIST_CHECK_NEXT(elm, field) 371 + #define QMD_LIST_CHECK_PREV(elm, field) 372 + #endif /* (_KERNEL && INVARIANTS) */ 373 + 374 + #define LIST_EMPTY(head) ((head)->lh_first == NULL) 375 + 376 + #define LIST_FIRST(head) ((head)->lh_first) 377 + 378 + #define LIST_FOREACH(var, head, field) \ 379 + for ((var) = LIST_FIRST((head)); \ 380 + (var); \ 381 + (var) = LIST_NEXT((var), field)) 382 + 383 + #define LIST_FOREACH_SAFE(var, head, field, tvar) \ 384 + for ((var) = LIST_FIRST((head)); \ 385 + (var) && ((tvar) = LIST_NEXT((var), field), 1); \ 386 + (var) = (tvar)) 387 + 388 + #define LIST_INIT(head) do { \ 389 + LIST_FIRST((head)) = NULL; \ 390 + } while (0) 391 + 392 + #define LIST_INSERT_AFTER(listelm, elm, field) do { \ 393 + QMD_LIST_CHECK_NEXT(listelm, field); \ 394 + if ((LIST_NEXT((elm), field) = LIST_NEXT((listelm), field)) != NULL)\ 395 + LIST_NEXT((listelm), field)->field.le_prev = \ 396 + &LIST_NEXT((elm), field); \ 397 + LIST_NEXT((listelm), field) = (elm); \ 398 + (elm)->field.le_prev = &LIST_NEXT((listelm), field); \ 399 + } while (0) 400 + 401 + #define LIST_INSERT_BEFORE(listelm, elm, field) do { \ 402 + QMD_LIST_CHECK_PREV(listelm, field); \ 403 + (elm)->field.le_prev = (listelm)->field.le_prev; \ 404 + LIST_NEXT((elm), field) = (listelm); \ 405 + *(listelm)->field.le_prev = (elm); \ 406 + (listelm)->field.le_prev = &LIST_NEXT((elm), field); \ 407 + } while (0) 408 + 409 + #define LIST_INSERT_HEAD(head, elm, field) do { \ 410 + QMD_LIST_CHECK_HEAD((head), field); \ 411 + if ((LIST_NEXT((elm), field) = LIST_FIRST((head))) != NULL) \ 412 + LIST_FIRST((head))->field.le_prev = &LIST_NEXT((elm), field);\ 413 + LIST_FIRST((head)) = (elm); \ 414 + (elm)->field.le_prev = &LIST_FIRST((head)); \ 415 + } while (0) 416 + 417 + #define LIST_NEXT(elm, field) ((elm)->field.le_next) 418 + 419 + #define LIST_REMOVE(elm, field) do { \ 420 + QMD_LIST_CHECK_NEXT(elm, field); \ 421 + QMD_LIST_CHECK_PREV(elm, field); \ 422 + if (LIST_NEXT((elm), field) != NULL) \ 423 + LIST_NEXT((elm), field)->field.le_prev = \ 424 + (elm)->field.le_prev; \ 425 + *(elm)->field.le_prev = LIST_NEXT((elm), field); \ 426 + TRASHIT((elm)->field.le_next); \ 427 + TRASHIT((elm)->field.le_prev); \ 428 + } while (0) 429 + 430 + #define LIST_SWAP(head1, head2, type, field) do { \ 431 + struct type *swap_tmp = LIST_FIRST((head1)); \ 432 + LIST_FIRST((head1)) = LIST_FIRST((head2)); \ 433 + LIST_FIRST((head2)) = swap_tmp; \ 434 + if ((swap_tmp = LIST_FIRST((head1))) != NULL) \ 435 + swap_tmp->field.le_prev = &LIST_FIRST((head1)); \ 436 + if ((swap_tmp = LIST_FIRST((head2))) != NULL) \ 437 + swap_tmp->field.le_prev = &LIST_FIRST((head2)); \ 438 + } while (0) 439 + 440 + /* 441 + * Tail queue declarations. 442 + */ 443 + #define TAILQ_HEAD(name, type) \ 444 + struct name { \ 445 + struct type *tqh_first; /* first element */ \ 446 + struct type **tqh_last; /* addr of last next element */ \ 447 + TRACEBUF \ 448 + } 449 + 450 + #define TAILQ_HEAD_INITIALIZER(head) \ 451 + { NULL, &(head).tqh_first } 452 + 453 + #define TAILQ_ENTRY(type) \ 454 + struct { \ 455 + struct type *tqe_next; /* next element */ \ 456 + struct type **tqe_prev; /* address of previous next element */ \ 457 + TRACEBUF \ 458 + } 459 + 460 + /* 461 + * Tail queue functions. 462 + */ 463 + #if (defined(_KERNEL) && defined(INVARIANTS)) 464 + #define QMD_TAILQ_CHECK_HEAD(head, field) do { \ 465 + if (!TAILQ_EMPTY(head) && \ 466 + TAILQ_FIRST((head))->field.tqe_prev != \ 467 + &TAILQ_FIRST((head))) \ 468 + panic("Bad tailq head %p first->prev != head", (head)); \ 469 + } while (0) 470 + 471 + #define QMD_TAILQ_CHECK_TAIL(head, field) do { \ 472 + if (*(head)->tqh_last != NULL) \ 473 + panic("Bad tailq NEXT(%p->tqh_last) != NULL", (head)); \ 474 + } while (0) 475 + 476 + #define QMD_TAILQ_CHECK_NEXT(elm, field) do { \ 477 + if (TAILQ_NEXT((elm), field) != NULL && \ 478 + TAILQ_NEXT((elm), field)->field.tqe_prev != \ 479 + &((elm)->field.tqe_next)) \ 480 + panic("Bad link elm %p next->prev != elm", (elm)); \ 481 + } while (0) 482 + 483 + #define QMD_TAILQ_CHECK_PREV(elm, field) do { \ 484 + if (*(elm)->field.tqe_prev != (elm)) \ 485 + panic("Bad link elm %p prev->next != elm", (elm)); \ 486 + } while (0) 487 + #else 488 + #define QMD_TAILQ_CHECK_HEAD(head, field) 489 + #define QMD_TAILQ_CHECK_TAIL(head, headname) 490 + #define QMD_TAILQ_CHECK_NEXT(elm, field) 491 + #define QMD_TAILQ_CHECK_PREV(elm, field) 492 + #endif /* (_KERNEL && INVARIANTS) */ 493 + 494 + #define TAILQ_CONCAT(head1, head2, field) do { \ 495 + if (!TAILQ_EMPTY(head2)) { \ 496 + *(head1)->tqh_last = (head2)->tqh_first; \ 497 + (head2)->tqh_first->field.tqe_prev = (head1)->tqh_last; \ 498 + (head1)->tqh_last = (head2)->tqh_last; \ 499 + TAILQ_INIT((head2)); \ 500 + QMD_TRACE_HEAD(head1); \ 501 + QMD_TRACE_HEAD(head2); \ 502 + } \ 503 + } while (0) 504 + 505 + #define TAILQ_EMPTY(head) ((head)->tqh_first == NULL) 506 + 507 + #define TAILQ_FIRST(head) ((head)->tqh_first) 508 + 509 + #define TAILQ_FOREACH(var, head, field) \ 510 + for ((var) = TAILQ_FIRST((head)); \ 511 + (var); \ 512 + (var) = TAILQ_NEXT((var), field)) 513 + 514 + #define TAILQ_FOREACH_SAFE(var, head, field, tvar) \ 515 + for ((var) = TAILQ_FIRST((head)); \ 516 + (var) && ((tvar) = TAILQ_NEXT((var), field), 1); \ 517 + (var) = (tvar)) 518 + 519 + #define TAILQ_FOREACH_REVERSE(var, head, headname, field) \ 520 + for ((var) = TAILQ_LAST((head), headname); \ 521 + (var); \ 522 + (var) = TAILQ_PREV((var), headname, field)) 523 + 524 + #define TAILQ_FOREACH_REVERSE_SAFE(var, head, headname, field, tvar) \ 525 + for ((var) = TAILQ_LAST((head), headname); \ 526 + (var) && ((tvar) = TAILQ_PREV((var), headname, field), 1); \ 527 + (var) = (tvar)) 528 + 529 + #define TAILQ_INIT(head) do { \ 530 + TAILQ_FIRST((head)) = NULL; \ 531 + (head)->tqh_last = &TAILQ_FIRST((head)); \ 532 + QMD_TRACE_HEAD(head); \ 533 + } while (0) 534 + 535 + #define TAILQ_INSERT_AFTER(head, listelm, elm, field) do { \ 536 + QMD_TAILQ_CHECK_NEXT(listelm, field); \ 537 + if ((TAILQ_NEXT((elm), field) = TAILQ_NEXT((listelm), field)) != NULL)\ 538 + TAILQ_NEXT((elm), field)->field.tqe_prev = \ 539 + &TAILQ_NEXT((elm), field); \ 540 + else { \ 541 + (head)->tqh_last = &TAILQ_NEXT((elm), field); \ 542 + QMD_TRACE_HEAD(head); \ 543 + } \ 544 + TAILQ_NEXT((listelm), field) = (elm); \ 545 + (elm)->field.tqe_prev = &TAILQ_NEXT((listelm), field); \ 546 + QMD_TRACE_ELEM(&(elm)->field); \ 547 + QMD_TRACE_ELEM(&listelm->field); \ 548 + } while (0) 549 + 550 + #define TAILQ_INSERT_BEFORE(listelm, elm, field) do { \ 551 + QMD_TAILQ_CHECK_PREV(listelm, field); \ 552 + (elm)->field.tqe_prev = (listelm)->field.tqe_prev; \ 553 + TAILQ_NEXT((elm), field) = (listelm); \ 554 + *(listelm)->field.tqe_prev = (elm); \ 555 + (listelm)->field.tqe_prev = &TAILQ_NEXT((elm), field); \ 556 + QMD_TRACE_ELEM(&(elm)->field); \ 557 + QMD_TRACE_ELEM(&listelm->field); \ 558 + } while (0) 559 + 560 + #define TAILQ_INSERT_HEAD(head, elm, field) do { \ 561 + QMD_TAILQ_CHECK_HEAD(head, field); \ 562 + if ((TAILQ_NEXT((elm), field) = TAILQ_FIRST((head))) != NULL) \ 563 + TAILQ_FIRST((head))->field.tqe_prev = \ 564 + &TAILQ_NEXT((elm), field); \ 565 + else \ 566 + (head)->tqh_last = &TAILQ_NEXT((elm), field); \ 567 + TAILQ_FIRST((head)) = (elm); \ 568 + (elm)->field.tqe_prev = &TAILQ_FIRST((head)); \ 569 + QMD_TRACE_HEAD(head); \ 570 + QMD_TRACE_ELEM(&(elm)->field); \ 571 + } while (0) 572 + 573 + #define TAILQ_INSERT_TAIL(head, elm, field) do { \ 574 + QMD_TAILQ_CHECK_TAIL(head, field); \ 575 + TAILQ_NEXT((elm), field) = NULL; \ 576 + (elm)->field.tqe_prev = (head)->tqh_last; \ 577 + *(head)->tqh_last = (elm); \ 578 + (head)->tqh_last = &TAILQ_NEXT((elm), field); \ 579 + QMD_TRACE_HEAD(head); \ 580 + QMD_TRACE_ELEM(&(elm)->field); \ 581 + } while (0) 582 + 583 + #define TAILQ_LAST(head, headname) \ 584 + (*(((struct headname *)((head)->tqh_last))->tqh_last)) 585 + 586 + #define TAILQ_NEXT(elm, field) ((elm)->field.tqe_next) 587 + 588 + #define TAILQ_PREV(elm, headname, field) \ 589 + (*(((struct headname *)((elm)->field.tqe_prev))->tqh_last)) 590 + 591 + #define TAILQ_REMOVE(head, elm, field) do { \ 592 + QMD_TAILQ_CHECK_NEXT(elm, field); \ 593 + QMD_TAILQ_CHECK_PREV(elm, field); \ 594 + if ((TAILQ_NEXT((elm), field)) != NULL) \ 595 + TAILQ_NEXT((elm), field)->field.tqe_prev = \ 596 + (elm)->field.tqe_prev; \ 597 + else { \ 598 + (head)->tqh_last = (elm)->field.tqe_prev; \ 599 + QMD_TRACE_HEAD(head); \ 600 + } \ 601 + *(elm)->field.tqe_prev = TAILQ_NEXT((elm), field); \ 602 + TRASHIT((elm)->field.tqe_next); \ 603 + TRASHIT((elm)->field.tqe_prev); \ 604 + QMD_TRACE_ELEM(&(elm)->field); \ 605 + } while (0) 606 + 607 + #define TAILQ_SWAP(head1, head2, type, field) do { \ 608 + struct type *swap_first = (head1)->tqh_first; \ 609 + struct type **swap_last = (head1)->tqh_last; \ 610 + (head1)->tqh_first = (head2)->tqh_first; \ 611 + (head1)->tqh_last = (head2)->tqh_last; \ 612 + (head2)->tqh_first = swap_first; \ 613 + (head2)->tqh_last = swap_last; \ 614 + if ((swap_first = (head1)->tqh_first) != NULL) \ 615 + swap_first->field.tqe_prev = &(head1)->tqh_first; \ 616 + else \ 617 + (head1)->tqh_last = &(head1)->tqh_first; \ 618 + if ((swap_first = (head2)->tqh_first) != NULL) \ 619 + swap_first->field.tqe_prev = &(head2)->tqh_first; \ 620 + else \ 621 + (head2)->tqh_last = &(head2)->tqh_first; \ 622 + } while (0) 623 + 624 + #endif /* !_SYS_QUEUE_H_ */
+32
external/libpthread_workqueue-0.8.2/src/windows/thread_info.c
··· 1 + /* 2 + * Copyright (c) 2011, Joakim Johansson <jocke@tbricks.com> 3 + * 4 + * All rights reserved. 5 + * 6 + * Redistribution and use in source and binary forms, with or without 7 + * modification, are permitted provided that the following conditions 8 + * are met: 9 + * 1. Redistributions of source code must retain the above copyright 10 + * notice unmodified, this list of conditions, and the following 11 + * disclaimer. 12 + * 2. Redistributions in binary form must reproduce the above copyright 13 + * notice, this list of conditions and the following disclaimer in the 14 + * documentation and/or other materials provided with the distribution. 15 + * 16 + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 17 + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 18 + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 19 + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 20 + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 21 + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 22 + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 23 + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 24 + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 25 + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 26 + * 27 + */ 28 + 29 + int threads_runnable(unsigned int *threads_running) 30 + { 31 + return -1; 32 + }
+32
external/libpthread_workqueue-0.8.2/src/windows/thread_rt.c
··· 1 + /* 2 + * Copyright (c) 2011, Joakim Johansson <jocke@tbricks.com> 3 + * 4 + * All rights reserved. 5 + * 6 + * Redistribution and use in source and binary forms, with or without 7 + * modification, are permitted provided that the following conditions 8 + * are met: 9 + * 1. Redistributions of source code must retain the above copyright 10 + * notice unmodified, this list of conditions, and the following 11 + * disclaimer. 12 + * 2. Redistributions in binary form must reproduce the above copyright 13 + * notice, this list of conditions and the following disclaimer in the 14 + * documentation and/or other materials provided with the distribution. 15 + * 16 + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 17 + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 18 + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 19 + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 20 + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 21 + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 22 + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 23 + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 24 + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 25 + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 26 + * 27 + */ 28 + 29 + void ptwq_set_current_thread_priority(int priority) 30 + { 31 + return; 32 + }
+1353
external/libpthread_workqueue-0.8.2/src/windows/winpthreads.h
··· 1 + /* 2 + * Posix Threads library for Microsoft Windows 3 + * 4 + * Use at own risk, there is no implied warranty to this code. 5 + * It uses undocumented features of Microsoft Windows that can change 6 + * at any time in the future. 7 + * 8 + * (C) 2010 Lockless Inc. 9 + * All rights reserved. 10 + * 11 + * Redistribution and use in source and binary forms, with or without modification, 12 + * are permitted provided that the following conditions are met: 13 + * 14 + * 15 + * * Redistributions of source code must retain the above copyright notice, 16 + * this list of conditions and the following disclaimer. 17 + * * Redistributions in binary form must reproduce the above copyright notice, 18 + * this list of conditions and the following disclaimer in the documentation 19 + * and/or other materials provided with the distribution. 20 + * * Neither the name of Lockless Inc. nor the names of its contributors may be 21 + * used to endorse or promote products derived from this software without 22 + * specific prior written permission. 23 + * 24 + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AN 25 + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 26 + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 27 + * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, 28 + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 29 + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 30 + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 31 + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE 32 + * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED 33 + * OF THE POSSIBILITY OF SUCH DAMAGE. 34 + */ 35 + 36 + #ifndef WIN_PTHREADS 37 + #define WIN_PTHREADS 38 + 39 + #include <stdlib.h> 40 + #include <malloc.h> 41 + #include <errno.h> 42 + #include <process.h> 43 + #include <windows.h> 44 + #include <setjmp.h> 45 + #include <errno.h> 46 + #include <sys/timeb.h> 47 + 48 + # 49 + #define PTHREAD_CANCEL_DISABLE 0 50 + #define PTHREAD_CANCEL_ENABLE 0x01 51 + 52 + #define PTHREAD_CANCEL_DEFERRED 0 53 + #define PTHREAD_CANCEL_ASYNCHRONOUS 0x02 54 + 55 + #define PTHREAD_CREATE_JOINABLE 0 56 + #define PTHREAD_CREATE_DETACHED 0x04 57 + 58 + #define PTHREAD_EXPLICT_SCHED 0 59 + #define PTHREAD_INHERIT_SCHED 0x08 60 + 61 + #define PTHREAD_SCOPE_PROCESS 0 62 + #define PTHREAD_SCOPE_SYSTEM 0x10 63 + 64 + #define PTHREAD_DEFAULT_ATTR (PTHREAD_CANCEL_ENABLE) 65 + 66 + #define PTHREAD_CANCELED ((void *) 0xDEADBEEF) 67 + 68 + #define PTHREAD_ONCE_INIT 0 69 + #define PTHREAD_MUTEX_INITIALIZER {(void*)-1,-1,0,0,0,0} 70 + #define PTHREAD_RWLOCK_INITIALIZER {0} 71 + #define PTHREAD_COND_INITIALIZER {0} 72 + #define PTHREAD_BARRIER_INITIALIZER \ 73 + {0,0,PTHREAD_MUTEX_INITIALIZER,PTHREAD_COND_INITIALIZER} 74 + #define PTHREAD_SPINLOCK_INITIALIZER 0 75 + 76 + #define PTHREAD_DESTRUCTOR_ITERATIONS 256 77 + #define PTHREAD_KEYS_MAX (1<<20) 78 + 79 + #define PTHREAD_MUTEX_NORMAL 0 80 + #define PTHREAD_MUTEX_ERRORCHECK 1 81 + #define PTHREAD_MUTEX_RECURSIVE 2 82 + #define PTHREAD_MUTEX_DEFAULT 3 83 + #define PTHREAD_MUTEX_SHARED 4 84 + #define PTHREAD_MUTEX_PRIVATE 0 85 + #define PTHREAD_PRIO_NONE 0 86 + #define PTHREAD_PRIO_INHERIT 8 87 + #define PTHREAD_PRIO_PROTECT 16 88 + #define PTHREAD_PRIO_MULT 32 89 + #define PTHREAD_PROCESS_SHARED 0 90 + #define PTHREAD_PROCESS_PRIVATE 1 91 + 92 + #define PTHREAD_BARRIER_SERIAL_THREAD 1 93 + 94 + 95 + /* Windows doesn't have this, so declare it ourselves. */ 96 + struct timespec 97 + { 98 + /* long long in windows is the same as long in unix for 64bit */ 99 + long long tv_sec; 100 + long long tv_nsec; 101 + }; 102 + 103 + typedef struct _pthread_cleanup _pthread_cleanup; 104 + struct _pthread_cleanup 105 + { 106 + void (*func)(void *); 107 + void *arg; 108 + _pthread_cleanup *next; 109 + }; 110 + 111 + struct _pthread_v 112 + { 113 + void *ret_arg; 114 + void *(* func)(void *); 115 + _pthread_cleanup *clean; 116 + HANDLE h; 117 + int cancelled; 118 + unsigned p_state; 119 + unsigned int keymax; 120 + void **keyval; 121 + 122 + jmp_buf jb; 123 + }; 124 + 125 + typedef struct _pthread_v *pthread_t; 126 + 127 + typedef struct pthread_barrier_t pthread_barrier_t; 128 + struct pthread_barrier_t 129 + { 130 + int count; 131 + int total; 132 + CRITICAL_SECTION m; 133 + CONDITION_VARIABLE cv; 134 + }; 135 + 136 + typedef struct pthread_attr_t pthread_attr_t; 137 + struct pthread_attr_t 138 + { 139 + unsigned p_state; 140 + void *stack; 141 + size_t s_size; 142 + }; 143 + 144 + typedef long pthread_once_t; 145 + typedef unsigned pthread_mutexattr_t; 146 + typedef SRWLOCK pthread_rwlock_t; 147 + typedef CRITICAL_SECTION pthread_mutex_t; 148 + typedef unsigned pthread_key_t; 149 + typedef void *pthread_barrierattr_t; 150 + typedef long pthread_spinlock_t; 151 + typedef int pthread_condattr_t; 152 + typedef CONDITION_VARIABLE pthread_cond_t; 153 + typedef int pthread_rwlockattr_t; 154 + 155 + volatile long _pthread_cancelling; 156 + 157 + int _pthread_concur; 158 + 159 + /* Will default to zero as needed */ 160 + pthread_once_t _pthread_tls_once; 161 + DWORD _pthread_tls; 162 + 163 + /* Note initializer is zero, so this works */ 164 + pthread_rwlock_t _pthread_key_lock; 165 + unsigned int _pthread_key_max; 166 + unsigned int _pthread_key_sch; 167 + void (**_pthread_key_dest)(void *); 168 + 169 + /* Prototypes */ 170 + static int pthread_rwlock_unlock(pthread_rwlock_t *l); 171 + 172 + 173 + #define pthread_cleanup_push(F, A)\ 174 + {\ 175 + const _pthread_cleanup _pthread_cup = {(F), (A), pthread_self()->clean};\ 176 + _ReadWriteBarrier();\ 177 + pthread_self()->clean = (_pthread_cleanup *) &_pthread_cup;\ 178 + _ReadWriteBarrier() 179 + 180 + /* Note that if async cancelling is used, then there is a race here */ 181 + #define pthread_cleanup_pop(E)\ 182 + (pthread_self()->clean = _pthread_cup.next, (E?_pthread_cup.func(_pthread_cup.arg):0));} 183 + 184 + static void _pthread_once_cleanup(pthread_once_t *o) 185 + { 186 + *o = 0; 187 + } 188 + 189 + static pthread_t pthread_self(void); 190 + static int pthread_once(pthread_once_t *o, void (*func)(void)) 191 + { 192 + long state = *o; 193 + 194 + _ReadWriteBarrier(); 195 + 196 + while (state != 1) 197 + { 198 + if (!state) 199 + { 200 + if (!_InterlockedCompareExchange(o, 2, 0)) 201 + { 202 + /* Success */ 203 + pthread_cleanup_push(_pthread_once_cleanup, o); 204 + func(); 205 + pthread_cleanup_pop(0); 206 + 207 + /* Mark as done */ 208 + *o = 1; 209 + 210 + return 0; 211 + } 212 + } 213 + 214 + YieldProcessor(); 215 + 216 + _ReadWriteBarrier(); 217 + 218 + state = *o; 219 + } 220 + 221 + /* Done */ 222 + return 0; 223 + 224 + } 225 + 226 + static int _pthread_once_raw(pthread_once_t *o, void (*func)(void)) 227 + { 228 + long state = *o; 229 + 230 + _ReadWriteBarrier(); 231 + 232 + while (state != 1) 233 + { 234 + if (!state) 235 + { 236 + if (!_InterlockedCompareExchange(o, 2, 0)) 237 + { 238 + /* Success */ 239 + func(); 240 + 241 + /* Mark as done */ 242 + *o = 1; 243 + 244 + return 0; 245 + } 246 + } 247 + 248 + YieldProcessor(); 249 + 250 + _ReadWriteBarrier(); 251 + 252 + state = *o; 253 + } 254 + 255 + /* Done */ 256 + return 0; 257 + } 258 + 259 + static int pthread_mutex_lock(pthread_mutex_t *m) 260 + { 261 + EnterCriticalSection(m); 262 + return 0; 263 + } 264 + 265 + static int pthread_mutex_unlock(pthread_mutex_t *m) 266 + { 267 + LeaveCriticalSection(m); 268 + return 0; 269 + } 270 + 271 + static int pthread_mutex_trylock(pthread_mutex_t *m) 272 + { 273 + return TryEnterCriticalSection(m) ? 0 : EBUSY; 274 + } 275 + 276 + static int pthread_mutex_init(pthread_mutex_t *m, pthread_mutexattr_t *a) 277 + { 278 + (void) a; 279 + InitializeCriticalSection(m); 280 + 281 + return 0; 282 + } 283 + 284 + static int pthread_mutex_destroy(pthread_mutex_t *m) 285 + { 286 + DeleteCriticalSection(m); 287 + return 0; 288 + } 289 + 290 + #define pthread_mutex_getprioceiling(M, P) ENOTSUP 291 + #define pthread_mutex_setprioceiling(M, P) ENOTSUP 292 + 293 + static int pthread_equal(pthread_t t1, pthread_t t2) 294 + { 295 + return t1 == t2; 296 + } 297 + 298 + static void pthread_testcancel(void); 299 + 300 + static int pthread_rwlock_init(pthread_rwlock_t *l, pthread_rwlockattr_t *a) 301 + { 302 + (void) a; 303 + InitializeSRWLock(l); 304 + 305 + return 0; 306 + } 307 + 308 + static int pthread_rwlock_destroy(pthread_rwlock_t *l) 309 + { 310 + (void) *l; 311 + return 0; 312 + } 313 + 314 + static int pthread_rwlock_rdlock(pthread_rwlock_t *l) 315 + { 316 + pthread_testcancel(); 317 + AcquireSRWLockShared(l); 318 + 319 + return 0; 320 + } 321 + 322 + static int pthread_rwlock_wrlock(pthread_rwlock_t *l) 323 + { 324 + pthread_testcancel(); 325 + AcquireSRWLockExclusive(l); 326 + 327 + return 0; 328 + } 329 + 330 + static void pthread_tls_init(void) 331 + { 332 + _pthread_tls = TlsAlloc(); 333 + 334 + /* Cannot continue if out of indexes */ 335 + if (_pthread_tls == TLS_OUT_OF_INDEXES) abort(); 336 + } 337 + 338 + static void _pthread_cleanup_dest(pthread_t t) 339 + { 340 + unsigned int i, j; 341 + 342 + for (j = 0; j < PTHREAD_DESTRUCTOR_ITERATIONS; j++) 343 + { 344 + int flag = 0; 345 + 346 + for (i = 0; i < t->keymax; i++) 347 + { 348 + void *val = t->keyval[i]; 349 + 350 + if (val) 351 + { 352 + pthread_rwlock_rdlock(&_pthread_key_lock); 353 + if ((uintptr_t) _pthread_key_dest[i] > 1) 354 + { 355 + /* Call destructor */ 356 + t->keyval[i] = NULL; 357 + _pthread_key_dest[i](val); 358 + flag = 1; 359 + } 360 + pthread_rwlock_unlock(&_pthread_key_lock); 361 + } 362 + } 363 + 364 + /* Nothing to do? */ 365 + if (!flag) return; 366 + } 367 + } 368 + 369 + static pthread_t pthread_self(void) 370 + { 371 + pthread_t t; 372 + 373 + _pthread_once_raw(&_pthread_tls_once, pthread_tls_init); 374 + 375 + t = TlsGetValue(_pthread_tls); 376 + 377 + /* Main thread? */ 378 + if (!t) 379 + { 380 + t = malloc(sizeof(struct _pthread_v)); 381 + 382 + /* If cannot initialize main thread, then the only thing we can do is abort */ 383 + if (!t) abort(); 384 + 385 + t->ret_arg = NULL; 386 + t->func = NULL; 387 + t->clean = NULL; 388 + t->cancelled = 0; 389 + t->p_state = PTHREAD_DEFAULT_ATTR; 390 + t->keymax = 0; 391 + t->keyval = NULL; 392 + t->h = GetCurrentThread(); 393 + 394 + /* Save for later */ 395 + TlsSetValue(_pthread_tls, t); 396 + 397 + if (setjmp(t->jb)) 398 + { 399 + /* Make sure we free ourselves if we are detached */ 400 + if (!t->h) free(t); 401 + 402 + /* Time to die */ 403 + _endthreadex(0); 404 + } 405 + } 406 + 407 + return t; 408 + } 409 + 410 + static int pthread_rwlock_unlock(pthread_rwlock_t *l) 411 + { 412 + void *state = *(void **)l; 413 + 414 + if (state == (void *) 1) 415 + { 416 + /* Known to be an exclusive lock */ 417 + ReleaseSRWLockExclusive(l); 418 + } 419 + else 420 + { 421 + /* A shared unlock will work */ 422 + ReleaseSRWLockShared(l); 423 + } 424 + 425 + return 0; 426 + } 427 + 428 + 429 + static int pthread_rwlock_tryrdlock(pthread_rwlock_t *l) 430 + { 431 + /* Get the current state of the lock */ 432 + void *state = *(void **) l; 433 + 434 + if (!state) 435 + { 436 + /* Unlocked to locked */ 437 + if (!InterlockedCompareExchangePointer((void *) l, (void *)0x11, NULL)) return 0; 438 + return EBUSY; 439 + } 440 + 441 + /* A single writer exists */ 442 + if (state == (void *) 1) return EBUSY; 443 + 444 + /* Multiple writers exist? */ 445 + if ((uintptr_t) state & 14) return EBUSY; 446 + 447 + if (InterlockedCompareExchangePointer((void *) l, (void *) ((uintptr_t)state + 16), state) == state) return 0; 448 + 449 + return EBUSY; 450 + } 451 + 452 + static int pthread_rwlock_trywrlock(pthread_rwlock_t *l) 453 + { 454 + /* Try to grab lock if it has no users */ 455 + if (!InterlockedCompareExchangePointer((void *) l, (void *)1, NULL)) return 0; 456 + 457 + return EBUSY; 458 + } 459 + 460 + static unsigned long long _pthread_time_in_ms(void) 461 + { 462 + struct __timeb64 tb; 463 + 464 + _ftime64_s(&tb); 465 + 466 + return tb.time * 1000 + tb.millitm; 467 + } 468 + 469 + static unsigned long long _pthread_time_in_ms_from_timespec(const struct timespec *ts) 470 + { 471 + unsigned long long t = ts->tv_sec * 1000; 472 + t += ts->tv_nsec / 1000000; 473 + 474 + return t; 475 + } 476 + 477 + static unsigned long long _pthread_rel_time_in_ms(const struct timespec *ts) 478 + { 479 + unsigned long long t1 = _pthread_time_in_ms_from_timespec(ts); 480 + unsigned long long t2 = _pthread_time_in_ms(); 481 + 482 + /* Prevent underflow */ 483 + if (t1 < t2) return 1; 484 + return t1 - t2; 485 + } 486 + 487 + static int pthread_rwlock_timedrdlock(pthread_rwlock_t *l, const struct timespec *ts) 488 + { 489 + unsigned long long ct = _pthread_time_in_ms(); 490 + unsigned long long t = _pthread_time_in_ms_from_timespec(ts); 491 + 492 + pthread_testcancel(); 493 + 494 + /* Use a busy-loop */ 495 + while (1) 496 + { 497 + /* Try to grab lock */ 498 + if (!pthread_rwlock_tryrdlock(l)) return 0; 499 + 500 + /* Get current time */ 501 + ct = _pthread_time_in_ms(); 502 + 503 + /* Have we waited long enough? */ 504 + if (ct > t) return ETIMEDOUT; 505 + } 506 + } 507 + 508 + static int pthread_rwlock_timedwrlock(pthread_rwlock_t *l, const struct timespec *ts) 509 + { 510 + unsigned long long ct = _pthread_time_in_ms(); 511 + unsigned long long t = _pthread_time_in_ms_from_timespec(ts); 512 + 513 + pthread_testcancel(); 514 + 515 + /* Use a busy-loop */ 516 + while (1) 517 + { 518 + /* Try to grab lock */ 519 + if (!pthread_rwlock_trywrlock(l)) return 0; 520 + 521 + /* Get current time */ 522 + ct = _pthread_time_in_ms(); 523 + 524 + /* Have we waited long enough? */ 525 + if (ct > t) return ETIMEDOUT; 526 + } 527 + } 528 + 529 + static int pthread_get_concurrency(int *val) 530 + { 531 + *val = _pthread_concur; 532 + return 0; 533 + } 534 + 535 + static int pthread_set_concurrency(int val) 536 + { 537 + _pthread_concur = val; 538 + return 0; 539 + } 540 + 541 + #define pthread_getschedparam(T, P, S) ENOTSUP 542 + #define pthread_setschedparam(T, P, S) ENOTSUP 543 + #define pthread_getcpuclockid(T, C) ENOTSUP 544 + 545 + static int pthread_exit(void *res) 546 + { 547 + pthread_t t = pthread_self(); 548 + 549 + t->ret_arg = res; 550 + 551 + _pthread_cleanup_dest(t); 552 + 553 + longjmp(t->jb, 1); 554 + } 555 + 556 + 557 + static void _pthread_invoke_cancel(void) 558 + { 559 + _pthread_cleanup *pcup; 560 + 561 + _InterlockedDecrement(&_pthread_cancelling); 562 + 563 + /* Call cancel queue */ 564 + for (pcup = pthread_self()->clean; pcup; pcup = pcup->next) 565 + { 566 + pcup->func(pcup->arg); 567 + } 568 + 569 + pthread_exit(PTHREAD_CANCELED); 570 + } 571 + 572 + static void pthread_testcancel(void) 573 + { 574 + if (_pthread_cancelling) 575 + { 576 + pthread_t t = pthread_self(); 577 + 578 + if (t->cancelled && (t->p_state & PTHREAD_CANCEL_ENABLE)) 579 + { 580 + _pthread_invoke_cancel(); 581 + } 582 + } 583 + } 584 + 585 + 586 + static int pthread_cancel(pthread_t t) 587 + { 588 + if (t->p_state & PTHREAD_CANCEL_ASYNCHRONOUS) 589 + { 590 + /* Dangerous asynchronous cancelling */ 591 + CONTEXT ctxt; 592 + 593 + /* Already done? */ 594 + if (t->cancelled) return ESRCH; 595 + 596 + ctxt.ContextFlags = CONTEXT_CONTROL; 597 + 598 + SuspendThread(t->h); 599 + GetThreadContext(t->h, &ctxt); 600 + #ifdef _M_X64 601 + ctxt.Rip = (uintptr_t) _pthread_invoke_cancel; 602 + #else 603 + ctxt.Eip = (uintptr_t) _pthread_invoke_cancel; 604 + #endif 605 + SetThreadContext(t->h, &ctxt); 606 + 607 + /* Also try deferred Cancelling */ 608 + t->cancelled = 1; 609 + 610 + /* Notify everyone to look */ 611 + _InterlockedIncrement(&_pthread_cancelling); 612 + 613 + ResumeThread(t->h); 614 + } 615 + else 616 + { 617 + /* Safe deferred Cancelling */ 618 + t->cancelled = 1; 619 + 620 + /* Notify everyone to look */ 621 + _InterlockedIncrement(&_pthread_cancelling); 622 + } 623 + 624 + return 0; 625 + } 626 + 627 + static unsigned _pthread_get_state(pthread_attr_t *attr, unsigned flag) 628 + { 629 + return attr->p_state & flag; 630 + } 631 + 632 + static int _pthread_set_state(pthread_attr_t *attr, unsigned flag, unsigned val) 633 + { 634 + if (~flag & val) return EINVAL; 635 + attr->p_state &= ~flag; 636 + attr->p_state |= val; 637 + 638 + return 0; 639 + } 640 + 641 + static int pthread_attr_init(pthread_attr_t *attr) 642 + { 643 + attr->p_state = PTHREAD_DEFAULT_ATTR; 644 + attr->stack = NULL; 645 + attr->s_size = 0; 646 + return 0; 647 + } 648 + 649 + static int pthread_attr_destroy(pthread_attr_t *attr) 650 + { 651 + /* No need to do anything */ 652 + return 0; 653 + } 654 + 655 + 656 + static int pthread_attr_setdetachstate(pthread_attr_t *a, int flag) 657 + { 658 + return _pthread_set_state(a, PTHREAD_CREATE_DETACHED, flag); 659 + } 660 + 661 + static int pthread_attr_getdetachstate(pthread_attr_t *a, int *flag) 662 + { 663 + *flag = _pthread_get_state(a, PTHREAD_CREATE_DETACHED); 664 + return 0; 665 + } 666 + 667 + static int pthread_attr_setinheritsched(pthread_attr_t *a, int flag) 668 + { 669 + return _pthread_set_state(a, PTHREAD_INHERIT_SCHED, flag); 670 + } 671 + 672 + static int pthread_attr_getinheritsched(pthread_attr_t *a, int *flag) 673 + { 674 + *flag = _pthread_get_state(a, PTHREAD_INHERIT_SCHED); 675 + return 0; 676 + } 677 + 678 + static int pthread_attr_setscope(pthread_attr_t *a, int flag) 679 + { 680 + return _pthread_set_state(a, PTHREAD_SCOPE_SYSTEM, flag); 681 + } 682 + 683 + static int pthread_attr_getscope(pthread_attr_t *a, int *flag) 684 + { 685 + *flag = _pthread_get_state(a, PTHREAD_SCOPE_SYSTEM); 686 + return 0; 687 + } 688 + 689 + static int pthread_attr_getstackaddr(pthread_attr_t *attr, void **stack) 690 + { 691 + *stack = attr->stack; 692 + return 0; 693 + } 694 + 695 + static int pthread_attr_setstackaddr(pthread_attr_t *attr, void *stack) 696 + { 697 + attr->stack = stack; 698 + return 0; 699 + } 700 + 701 + static int pthread_attr_getstacksize(pthread_attr_t *attr, size_t *size) 702 + { 703 + *size = attr->s_size; 704 + return 0; 705 + } 706 + 707 + static int pthread_attr_setstacksize(pthread_attr_t *attr, size_t size) 708 + { 709 + attr->s_size = size; 710 + return 0; 711 + } 712 + 713 + #define pthread_attr_getguardsize(A, S) ENOTSUP 714 + #define pthread_attr_setgaurdsize(A, S) ENOTSUP 715 + #define pthread_attr_getschedparam(A, S) ENOTSUP 716 + #define pthread_attr_setschedparam(A, S) ENOTSUP 717 + #define pthread_attr_getschedpolicy(A, S) ENOTSUP 718 + #define pthread_attr_setschedpolicy(A, S) ENOTSUP 719 + 720 + 721 + static int pthread_setcancelstate(int state, int *oldstate) 722 + { 723 + pthread_t t = pthread_self(); 724 + 725 + if ((state & PTHREAD_CANCEL_ENABLE) != state) return EINVAL; 726 + if (oldstate) *oldstate = t->p_state & PTHREAD_CANCEL_ENABLE; 727 + t->p_state &= ~PTHREAD_CANCEL_ENABLE; 728 + t->p_state |= state; 729 + 730 + return 0; 731 + } 732 + 733 + static int pthread_setcanceltype(int type, int *oldtype) 734 + { 735 + pthread_t t = pthread_self(); 736 + 737 + if ((type & PTHREAD_CANCEL_ASYNCHRONOUS) != type) return EINVAL; 738 + if (oldtype) *oldtype = t->p_state & PTHREAD_CANCEL_ASYNCHRONOUS; 739 + t->p_state &= ~PTHREAD_CANCEL_ASYNCHRONOUS; 740 + t->p_state |= type; 741 + 742 + return 0; 743 + } 744 + 745 + static int __stdcall pthread_create_wrapper(void *args) 746 + { 747 + struct _pthread_v *tv = args; 748 + 749 + _pthread_once_raw(&_pthread_tls_once, pthread_tls_init); 750 + 751 + TlsSetValue(_pthread_tls, tv); 752 + 753 + if (!setjmp(tv->jb)) 754 + { 755 + /* Call function and save return value */ 756 + tv->ret_arg = tv->func(tv->ret_arg); 757 + 758 + /* Clean up destructors */ 759 + _pthread_cleanup_dest(tv); 760 + } 761 + 762 + /* If we exit too early, then we can race with create */ 763 + while (tv->h == (HANDLE) -1) 764 + { 765 + YieldProcessor(); 766 + _ReadWriteBarrier(); 767 + } 768 + 769 + /* Make sure we free ourselves if we are detached */ 770 + if (!tv->h) free(tv); 771 + 772 + return 0; 773 + } 774 + 775 + static int pthread_create(pthread_t *th, pthread_attr_t *attr, void *(* func)(void *), void *arg) 776 + { 777 + struct _pthread_v *tv = malloc(sizeof(struct _pthread_v)); 778 + unsigned ssize = 0; 779 + 780 + if (!tv) return 1; 781 + 782 + *th = tv; 783 + 784 + /* Save data in pthread_t */ 785 + tv->ret_arg = arg; 786 + tv->func = func; 787 + tv->clean = NULL; 788 + tv->cancelled = 0; 789 + tv->p_state = PTHREAD_DEFAULT_ATTR; 790 + tv->keymax = 0; 791 + tv->keyval = NULL; 792 + tv->h = (HANDLE) -1; 793 + 794 + if (attr) 795 + { 796 + tv->p_state = attr->p_state; 797 + ssize = (unsigned int)attr->s_size; 798 + } 799 + 800 + /* Make sure tv->h has value of -1 */ 801 + _ReadWriteBarrier(); 802 + 803 + tv->h = (HANDLE) _beginthreadex(NULL, ssize, pthread_create_wrapper, tv, 0, NULL); 804 + 805 + /* Failed */ 806 + if (!tv->h) return 1; 807 + 808 + 809 + if (tv->p_state & PTHREAD_CREATE_DETACHED) 810 + { 811 + CloseHandle(tv->h); 812 + _ReadWriteBarrier(); 813 + tv->h = 0; 814 + } 815 + 816 + return 0; 817 + } 818 + 819 + static int pthread_join(pthread_t t, void **res) 820 + { 821 + struct _pthread_v *tv = t; 822 + 823 + pthread_testcancel(); 824 + 825 + WaitForSingleObject(tv->h, INFINITE); 826 + CloseHandle(tv->h); 827 + 828 + /* Obtain return value */ 829 + if (res) *res = tv->ret_arg; 830 + 831 + free(tv); 832 + 833 + return 0; 834 + } 835 + 836 + static int pthread_detach(pthread_t t) 837 + { 838 + struct _pthread_v *tv = t; 839 + 840 + /* 841 + * This can't race with thread exit because 842 + * our call would be undefined if called on a dead thread. 843 + */ 844 + 845 + CloseHandle(tv->h); 846 + _ReadWriteBarrier(); 847 + tv->h = 0; 848 + 849 + return 0; 850 + } 851 + 852 + static int pthread_mutexattr_init(pthread_mutexattr_t *a) 853 + { 854 + *a = 0; 855 + return 0; 856 + } 857 + 858 + static int pthread_mutexattr_destroy(pthread_mutexattr_t *a) 859 + { 860 + (void) a; 861 + return 0; 862 + } 863 + 864 + static int pthread_mutexattr_gettype(pthread_mutexattr_t *a, int *type) 865 + { 866 + *type = *a & 3; 867 + 868 + return 0; 869 + } 870 + 871 + static int pthread_mutexattr_settype(pthread_mutexattr_t *a, int type) 872 + { 873 + if ((unsigned) type > 3) return EINVAL; 874 + *a &= ~3; 875 + *a |= type; 876 + 877 + return 0; 878 + } 879 + 880 + static int pthread_mutexattr_getpshared(pthread_mutexattr_t *a, int *type) 881 + { 882 + *type = *a & 4; 883 + 884 + return 0; 885 + } 886 + 887 + static int pthread_mutexattr_setpshared(pthread_mutexattr_t * a, int type) 888 + { 889 + if ((type & 4) != type) return EINVAL; 890 + 891 + *a &= ~4; 892 + *a |= type; 893 + 894 + return 0; 895 + } 896 + 897 + static int pthread_mutexattr_getprotocol(pthread_mutexattr_t *a, int *type) 898 + { 899 + *type = *a & (8 + 16); 900 + 901 + return 0; 902 + } 903 + 904 + static int pthread_mutexattr_setprotocol(pthread_mutexattr_t *a, int type) 905 + { 906 + if ((type & (8 + 16)) != 8 + 16) return EINVAL; 907 + 908 + *a &= ~(8 + 16); 909 + *a |= type; 910 + 911 + return 0; 912 + } 913 + 914 + static int pthread_mutexattr_getprioceiling(pthread_mutexattr_t *a, int * prio) 915 + { 916 + *prio = *a / PTHREAD_PRIO_MULT; 917 + return 0; 918 + } 919 + 920 + static int pthread_mutexattr_setprioceiling(pthread_mutexattr_t *a, int prio) 921 + { 922 + *a &= (PTHREAD_PRIO_MULT - 1); 923 + *a += prio * PTHREAD_PRIO_MULT; 924 + 925 + return 0; 926 + } 927 + 928 + static int pthread_mutex_timedlock(pthread_mutex_t *m, struct timespec *ts) 929 + { 930 + unsigned long long t, ct; 931 + 932 + struct _pthread_crit_t 933 + { 934 + void *debug; 935 + LONG count; 936 + LONG r_count; 937 + HANDLE owner; 938 + HANDLE sem; 939 + ULONG_PTR spin; 940 + }; 941 + 942 + /* Try to lock it without waiting */ 943 + if (!pthread_mutex_trylock(m)) return 0; 944 + 945 + ct = _pthread_time_in_ms(); 946 + t = _pthread_time_in_ms_from_timespec(ts); 947 + 948 + while (1) 949 + { 950 + /* Have we waited long enough? */ 951 + if (ct > t) return ETIMEDOUT; 952 + 953 + /* Wait on semaphore within critical section */ 954 + WaitForSingleObject(((struct _pthread_crit_t *)m)->sem, (DWORD)(t - ct)); 955 + 956 + /* Try to grab lock */ 957 + if (!pthread_mutex_trylock(m)) return 0; 958 + 959 + /* Get current time */ 960 + ct = _pthread_time_in_ms(); 961 + } 962 + } 963 + 964 + static int pthread_barrier_destroy(pthread_barrier_t *b) 965 + { 966 + DeleteCriticalSection(&b->m); 967 + 968 + return 0; 969 + 970 + } 971 + 972 + static int pthread_barrier_init(pthread_barrier_t *b, void *attr, int count) 973 + { 974 + /* Ignore attr */ 975 + (void) attr; 976 + 977 + InitializeCriticalSection(&b->m); 978 + InitializeConditionVariable(&b->cv); 979 + b->count = count; 980 + b->total = 0; 981 + 982 + return 0; 983 + } 984 + 985 + #define _PTHREAD_BARRIER_FLAG (1<<30) 986 + static int pthread_barrier_wait(pthread_barrier_t *b) 987 + { 988 + EnterCriticalSection(&b->m); 989 + 990 + while (b->total > _PTHREAD_BARRIER_FLAG) 991 + { 992 + /* Wait until everyone exits the barrier */ 993 + SleepConditionVariableCS(&b->cv, &b->m, INFINITE); 994 + } 995 + 996 + /* Are we the first to enter? */ 997 + if (b->total == _PTHREAD_BARRIER_FLAG) b->total = 0; 998 + 999 + b->total++; 1000 + 1001 + if (b->total == b->count) 1002 + { 1003 + b->total += _PTHREAD_BARRIER_FLAG - 1; 1004 + WakeAllConditionVariable(&b->cv); 1005 + 1006 + LeaveCriticalSection(&b->m); 1007 + 1008 + return 1; 1009 + } 1010 + else 1011 + { 1012 + while (b->total < _PTHREAD_BARRIER_FLAG) 1013 + { 1014 + /* Wait until enough threads enter the barrier */ 1015 + SleepConditionVariableCS(&b->cv, &b->m, INFINITE); 1016 + } 1017 + 1018 + b->total--; 1019 + 1020 + /* Get entering threads to wake up */ 1021 + if (b->total == _PTHREAD_BARRIER_FLAG) WakeAllConditionVariable(&b->cv); 1022 + 1023 + LeaveCriticalSection(&b->m); 1024 + 1025 + return 0; 1026 + } 1027 + } 1028 + 1029 + static int pthread_barrierattr_init(void **attr) 1030 + { 1031 + *attr = NULL; 1032 + return 0; 1033 + } 1034 + 1035 + static int pthread_barrierattr_destroy(void **attr) 1036 + { 1037 + /* Ignore attr */ 1038 + (void) attr; 1039 + 1040 + return 0; 1041 + } 1042 + 1043 + static int pthread_barrierattr_setpshared(void **attr, int s) 1044 + { 1045 + *attr = (void *) s; 1046 + return 0; 1047 + } 1048 + 1049 + static int pthread_barrierattr_getpshared(void **attr, int *s) 1050 + { 1051 + *s = (int) (size_t) *attr; 1052 + 1053 + return 0; 1054 + } 1055 + 1056 + static int pthread_key_create(pthread_key_t *key, void (* dest)(void *)) 1057 + { 1058 + unsigned int i; 1059 + long nmax; 1060 + void (**d)(void *); 1061 + 1062 + if (!key) return EINVAL; 1063 + 1064 + pthread_rwlock_wrlock(&_pthread_key_lock); 1065 + 1066 + for (i = _pthread_key_sch; i < _pthread_key_max; i++) 1067 + { 1068 + if (!_pthread_key_dest[i]) 1069 + { 1070 + *key = i; 1071 + if (dest) 1072 + { 1073 + _pthread_key_dest[i] = dest; 1074 + } 1075 + else 1076 + { 1077 + _pthread_key_dest[i] = (void(*)(void *))1; 1078 + } 1079 + pthread_rwlock_unlock(&_pthread_key_lock); 1080 + 1081 + return 0; 1082 + } 1083 + } 1084 + 1085 + for (i = 0; i < _pthread_key_sch; i++) 1086 + { 1087 + if (!_pthread_key_dest[i]) 1088 + { 1089 + *key = i; 1090 + if (dest) 1091 + { 1092 + _pthread_key_dest[i] = dest; 1093 + } 1094 + else 1095 + { 1096 + _pthread_key_dest[i] = (void(*)(void *))1; 1097 + } 1098 + pthread_rwlock_unlock(&_pthread_key_lock); 1099 + 1100 + return 0; 1101 + } 1102 + } 1103 + 1104 + if (!_pthread_key_max) _pthread_key_max = 1; 1105 + if (_pthread_key_max == PTHREAD_KEYS_MAX) 1106 + { 1107 + pthread_rwlock_unlock(&_pthread_key_lock); 1108 + 1109 + return ENOMEM; 1110 + } 1111 + 1112 + nmax = _pthread_key_max * 2; 1113 + if (nmax > PTHREAD_KEYS_MAX) nmax = PTHREAD_KEYS_MAX; 1114 + 1115 + /* No spare room anywhere */ 1116 + d = realloc(_pthread_key_dest, nmax * sizeof(*d)); 1117 + if (!d) 1118 + { 1119 + pthread_rwlock_unlock(&_pthread_key_lock); 1120 + 1121 + return ENOMEM; 1122 + } 1123 + 1124 + /* Clear new region */ 1125 + memset((void *) &d[_pthread_key_max], 0, (nmax-_pthread_key_max)*sizeof(void *)); 1126 + 1127 + /* Use new region */ 1128 + _pthread_key_dest = d; 1129 + _pthread_key_sch = _pthread_key_max + 1; 1130 + *key = _pthread_key_max; 1131 + _pthread_key_max = nmax; 1132 + 1133 + if (dest) 1134 + { 1135 + _pthread_key_dest[*key] = dest; 1136 + } 1137 + else 1138 + { 1139 + _pthread_key_dest[*key] = (void(*)(void *))1; 1140 + } 1141 + 1142 + pthread_rwlock_unlock(&_pthread_key_lock); 1143 + 1144 + return 0; 1145 + } 1146 + 1147 + static int pthread_key_delete(pthread_key_t key) 1148 + { 1149 + if (key > _pthread_key_max) return EINVAL; 1150 + if (!_pthread_key_dest) return EINVAL; 1151 + 1152 + pthread_rwlock_wrlock(&_pthread_key_lock); 1153 + _pthread_key_dest[key] = NULL; 1154 + 1155 + /* Start next search from our location */ 1156 + if (_pthread_key_sch > key) _pthread_key_sch = key; 1157 + 1158 + pthread_rwlock_unlock(&_pthread_key_lock); 1159 + 1160 + return 0; 1161 + } 1162 + 1163 + static void *pthread_getspecific(pthread_key_t key) 1164 + { 1165 + pthread_t t = pthread_self(); 1166 + 1167 + if (key >= t->keymax) return NULL; 1168 + 1169 + return t->keyval[key]; 1170 + 1171 + } 1172 + 1173 + static int pthread_setspecific(pthread_key_t key, const void *value) 1174 + { 1175 + pthread_t t = pthread_self(); 1176 + 1177 + if (key > t->keymax) 1178 + { 1179 + int keymax = (key + 1) * 2; 1180 + void **kv = realloc(t->keyval, keymax * sizeof(void *)); 1181 + 1182 + if (!kv) return ENOMEM; 1183 + 1184 + /* Clear new region */ 1185 + memset(&kv[t->keymax], 0, (keymax - t->keymax)*sizeof(void*)); 1186 + 1187 + t->keyval = kv; 1188 + t->keymax = keymax; 1189 + } 1190 + 1191 + t->keyval[key] = (void *) value; 1192 + 1193 + return 0; 1194 + } 1195 + 1196 + 1197 + static int pthread_spin_init(pthread_spinlock_t *l, int pshared) 1198 + { 1199 + (void) pshared; 1200 + 1201 + *l = 0; 1202 + return 0; 1203 + } 1204 + 1205 + static int pthread_spin_destroy(pthread_spinlock_t *l) 1206 + { 1207 + (void) l; 1208 + return 0; 1209 + } 1210 + 1211 + /* No-fair spinlock due to lack of knowledge of thread number */ 1212 + static int pthread_spin_lock(pthread_spinlock_t *l) 1213 + { 1214 + while (_InterlockedExchange(l, EBUSY)) 1215 + { 1216 + /* Don't lock the bus whilst waiting */ 1217 + while (*l) 1218 + { 1219 + YieldProcessor(); 1220 + 1221 + /* Compiler barrier. Prevent caching of *l */ 1222 + _ReadWriteBarrier(); 1223 + } 1224 + } 1225 + 1226 + return 0; 1227 + } 1228 + 1229 + static int pthread_spin_trylock(pthread_spinlock_t *l) 1230 + { 1231 + return _InterlockedExchange(l, EBUSY); 1232 + } 1233 + 1234 + static int pthread_spin_unlock(pthread_spinlock_t *l) 1235 + { 1236 + /* Compiler barrier. The store below acts with release symmantics */ 1237 + _ReadWriteBarrier(); 1238 + 1239 + *l = 0; 1240 + 1241 + return 0; 1242 + } 1243 + 1244 + static int pthread_cond_init(pthread_cond_t *c, pthread_condattr_t *a) 1245 + { 1246 + (void) a; 1247 + 1248 + InitializeConditionVariable(c); 1249 + return 0; 1250 + } 1251 + 1252 + static int pthread_cond_signal(pthread_cond_t *c) 1253 + { 1254 + WakeConditionVariable(c); 1255 + return 0; 1256 + } 1257 + 1258 + static int pthread_cond_broadcast(pthread_cond_t *c) 1259 + { 1260 + WakeAllConditionVariable(c); 1261 + return 0; 1262 + } 1263 + 1264 + static int pthread_cond_wait(pthread_cond_t *c, pthread_mutex_t *m) 1265 + { 1266 + pthread_testcancel(); 1267 + SleepConditionVariableCS(c, m, INFINITE); 1268 + return 0; 1269 + } 1270 + 1271 + static int pthread_cond_destroy(pthread_cond_t *c) 1272 + { 1273 + (void) c; 1274 + return 0; 1275 + } 1276 + 1277 + static int pthread_cond_timedwait(pthread_cond_t *c, pthread_mutex_t *m, struct timespec *t) 1278 + { 1279 + unsigned long long tm = _pthread_rel_time_in_ms(t); 1280 + 1281 + pthread_testcancel(); 1282 + 1283 + if (!SleepConditionVariableCS(c, m, (DWORD) tm)) return ETIMEDOUT; 1284 + 1285 + /* We can have a spurious wakeup after the timeout */ 1286 + if (!_pthread_rel_time_in_ms(t)) return ETIMEDOUT; 1287 + 1288 + return 0; 1289 + } 1290 + 1291 + static int pthread_condattr_destroy(pthread_condattr_t *a) 1292 + { 1293 + (void) a; 1294 + return 0; 1295 + } 1296 + 1297 + #define pthread_condattr_getclock(A, C) ENOTSUP 1298 + #define pthread_condattr_setclock(A, C) ENOTSUP 1299 + 1300 + static int pthread_condattr_init(pthread_condattr_t *a) 1301 + { 1302 + *a = 0; 1303 + return 0; 1304 + } 1305 + 1306 + static int pthread_condattr_getpshared(pthread_condattr_t *a, int *s) 1307 + { 1308 + *s = *a; 1309 + return 0; 1310 + } 1311 + 1312 + static int pthread_condattr_setpshared(pthread_condattr_t *a, int s) 1313 + { 1314 + *a = s; 1315 + return 0; 1316 + } 1317 + 1318 + static int pthread_rwlockattr_destroy(pthread_rwlockattr_t *a) 1319 + { 1320 + (void) a; 1321 + return 0; 1322 + } 1323 + 1324 + static int pthread_rwlockattr_init(pthread_rwlockattr_t *a) 1325 + { 1326 + *a = 0; 1327 + } 1328 + 1329 + static int pthread_rwlockattr_getpshared(pthread_rwlockattr_t *a, int *s) 1330 + { 1331 + *s = *a; 1332 + return 0; 1333 + } 1334 + 1335 + static int pthread_rwlockattr_setpshared(pthread_rwlockattr_t *a, int s) 1336 + { 1337 + *a = s; 1338 + return 0; 1339 + } 1340 + 1341 + 1342 + /* No fork() in windows - so ignore this */ 1343 + #define pthread_atfork(F1,F2,F3) 0 1344 + 1345 + /* Windows has rudimentary signals support */ 1346 + #define pthread_kill(T, S) 0 1347 + #define pthread_sigmask(H, S1, S2) 0 1348 + 1349 + 1350 + /* Wrap cancellation points */ 1351 + //FIXME: removed wrappers, some of them caused compilation errors 1352 + 1353 + #endif /* WIN_PTHREADS */
+207
external/libpthread_workqueue-0.8.2/src/witem_cache.c
··· 1 + /* 2 + * Copyright (c) 2011, Joakim Johansson <jocke@tbricks.com> 3 + * 4 + * All rights reserved. 5 + * 6 + * Redistribution and use in source and binary forms, with or without 7 + * modification, are permitted provided that the following conditions 8 + * are met: 9 + * 1. Redistributions of source code must retain the above copyright 10 + * notice unmodified, this list of conditions, and the following 11 + * disclaimer. 12 + * 2. Redistributions in binary form must reproduce the above copyright 13 + * notice, this list of conditions and the following disclaimer in the 14 + * documentation and/or other materials provided with the distribution. 15 + * 16 + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 17 + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 18 + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 19 + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 20 + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 21 + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 22 + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 23 + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 24 + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 25 + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 26 + * 27 + */ 28 + 29 + #include "private.h" 30 + 31 + 32 + /* no witem cache */ 33 + 34 + #if (WITEM_CACHE_TYPE == 1) 35 + 36 + int 37 + witem_cache_init(void) 38 + { 39 + return (0); 40 + } 41 + 42 + struct work * 43 + witem_alloc(void (*func)(void *), void *func_arg) 44 + { 45 + struct work *witem; 46 + 47 + while (!(witem = fastpath(malloc(ROUND_UP_TO_CACHELINE_SIZE(sizeof(*witem)))))) { 48 + sleep(1); 49 + } 50 + 51 + witem->gencount = 0; 52 + witem->flags = 0; 53 + witem->item_entry.stqe_next = 0; 54 + witem->func = func; 55 + witem->func_arg = func_arg; 56 + 57 + return witem; 58 + } 59 + 60 + void 61 + witem_free(struct work *wi) 62 + { 63 + dbg_printf("freed work item %p", wi); 64 + free(wi); 65 + } 66 + 67 + void 68 + witem_cache_cleanup(void *value) 69 + { 70 + (void) value; 71 + } 72 + 73 + /* libumem based object cache */ 74 + 75 + #elif (WITEM_CACHE_TYPE == 2) 76 + 77 + #include <umem.h> 78 + 79 + static umem_cache_t *witem_cache; 80 + 81 + int 82 + witem_cache_init(void) 83 + { 84 + witem_cache = umem_cache_create((char *) "witem_cache", 85 + sizeof(struct work), 86 + CACHELINE_SIZE, 87 + NULL, 88 + NULL, 89 + NULL, 90 + NULL, 91 + NULL, 92 + 0); 93 + return (0); 94 + } 95 + 96 + struct work * 97 + witem_alloc(void (*func)(void *), void *func_arg) 98 + { 99 + struct work *witem; 100 + 101 + while (!(witem = fastpath(umem_cache_alloc(witem_cache, UMEM_DEFAULT)))) { 102 + sleep(1); 103 + } 104 + 105 + witem->gencount = 0; 106 + witem->flags = 0; 107 + witem->item_entry.stqe_next = 0; 108 + witem->func = func; 109 + witem->func_arg = func_arg; 110 + 111 + return witem; 112 + } 113 + 114 + void 115 + witem_free(struct work *wi) 116 + { 117 + umem_cache_free(witem_cache, wi); 118 + return; 119 + } 120 + 121 + void 122 + witem_cache_cleanup(void *value) 123 + { 124 + void * p; 125 + p = value; 126 + } 127 + 128 + /* TSD based cacheing per thread */ 129 + 130 + #elif (WITEM_CACHE_TYPE == 3) 131 + 132 + pthread_key_t witem_cache_key; 133 + 134 + int 135 + witem_cache_init(void) 136 + { 137 + pthread_key_create(&witem_cache_key, witem_cache_cleanup); 138 + return (0); 139 + } 140 + 141 + static struct work * 142 + witem_alloc_from_heap(void) 143 + { 144 + struct work *witem; 145 + 146 + while (!(witem = fastpath(malloc(ROUND_UP_TO_CACHELINE_SIZE(sizeof(*witem)))))) { 147 + sleep(1); 148 + } 149 + 150 + witem->gencount = 0; 151 + witem->flags = 0; 152 + witem->item_entry.stqe_next = 0; 153 + 154 + return witem; 155 + } 156 + 157 + struct work * 158 + witem_alloc(void (*func)(void *), void *func_arg) 159 + { 160 + struct work *witem = fastpath(pthread_getspecific(witem_cache_key)); 161 + if (witem) 162 + { 163 + pthread_setspecific(witem_cache_key, witem->wi_next); 164 + } 165 + else 166 + { 167 + witem = witem_alloc_from_heap(); 168 + } 169 + 170 + witem->func = func; 171 + witem->func_arg = func_arg; 172 + 173 + return witem; 174 + } 175 + 176 + void 177 + witem_free(struct work *witem) 178 + { 179 + struct work *prev_wi = pthread_getspecific(witem_cache_key); 180 + 181 + witem->wi_next = prev_wi; 182 + 183 + // We need to initialize here also... 184 + witem->gencount = 0; 185 + witem->flags = 0; 186 + witem->item_entry.stqe_next = 0; 187 + witem->func = NULL; 188 + witem->func_arg = NULL; 189 + 190 + pthread_setspecific(witem_cache_key, witem); 191 + } 192 + 193 + void 194 + witem_cache_cleanup(void *value) 195 + { 196 + struct work *wi, *next_wi = value; 197 + 198 + while ((wi = next_wi)) { 199 + next_wi = wi->wi_next; 200 + free(wi); 201 + } 202 + } 203 + #else 204 + 205 + #error Invalid witem cache type specified 206 + 207 + #endif
+46
external/libpthread_workqueue-0.8.2/testing/CMakeLists.txt
··· 1 + # 2 + # Copyright (c) 2011 Marius Zwicker <marius@mlba-team.de> 3 + # 4 + # Permission to use, copy, modify, and distribute this software for any 5 + # purpose with or without fee is hereby granted, provided that the above 6 + # copyright notice and this permission notice appear in all copies. 7 + # 8 + # THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 9 + # WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 10 + # MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 11 + # ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 12 + # WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 13 + # ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 14 + # OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 15 + # 16 + 17 + #files 18 + set(API api/test.c) 19 + set(WITEM_CACHE witem_cache/test.c) 20 + set(LATENCY latency/latency.c latency/latency.h) 21 + 22 + 23 + #includes 24 + include_directories( 25 + ../include 26 + ) 27 + 28 + if(UNIX) 29 + add_definitions( 30 + -DNO_CONFIG_H 31 + ) 32 + endif() 33 + 34 + add_executable(test_api_pthread_workqueue ${API}) 35 + target_link_libraries(test_api_pthread_workqueue pthread_workqueue) 36 + set_target_properties(test_api_pthread_workqueue PROPERTIES DEBUG_POSTFIX "D") 37 + 38 + add_executable(test_latency_pthread_workqueue ${LATENCY}) 39 + target_link_libraries(test_latency_pthread_workqueue pthread_workqueue) 40 + 41 + if(NOT WIN32) 42 + 43 + #add_executable(test_witem_cache_pthread_workqueue ${WITEM_CACHE}) 44 + #target_link_libraries(test_witem_cache_pthread_workqueue pthreads_workqueue) 45 + 46 + endif()
+26
external/libpthread_workqueue-0.8.2/testing/Makefile
··· 1 + # 2 + # Copyright (c) 2011 Mark Heily <mark@heily.com> 3 + # 4 + # Permission to use, copy, modify, and distribute this software for any 5 + # purpose with or without fee is hereby granted, provided that the above 6 + # copyright notice and this permission notice appear in all copies. 7 + # 8 + # THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 9 + # WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 10 + # MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 11 + # ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 12 + # WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 13 + # ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 14 + # OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 15 + # 16 + 17 + # TODO: add libdispatch to TESTS 18 + 19 + TESTS=api latency witem_cache 20 + EXTRA_TESTS=idle 21 + 22 + all clean check: 23 + for x in $(TESTS) ; do cd $$x && make $@ && cd .. ; done 24 + 25 + extra-check: 26 + for x in $(EXTRA_TESTS) ; do cd $$x && make check && cd .. ; done
+36
external/libpthread_workqueue-0.8.2/testing/api/Makefile
··· 1 + # 2 + # Copyright (c) 2011 Mark Heily <mark@heily.com> 3 + # 4 + # Permission to use, copy, modify, and distribute this software for any 5 + # purpose with or without fee is hereby granted, provided that the above 6 + # copyright notice and this permission notice appear in all copies. 7 + # 8 + # THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 9 + # WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 10 + # MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 11 + # ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 12 + # WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 13 + # ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 14 + # OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 15 + # 16 + 17 + .PHONY :: install uninstall check dist dist-upload publish-www clean merge distclean fresh-build rpm edit cscope valgrind 18 + 19 + include ../../config.mk 20 + 21 + all: test-$(PROGRAM) 22 + 23 + test-$(PROGRAM): test.c 24 + $(CC) $(CFLAGS) -g -O0 -o test-$(PROGRAM) -I../.. -I../../include -L../.. test.c -lpthread_workqueue -lpthread 25 + 26 + check: test-$(PROGRAM) 27 + LD_LIBRARY_PATH=../..:/usr/sfw/lib/amd64 ./test-$(PROGRAM) 28 + 29 + debug: test-$(PROGRAM) 30 + LD_LIBRARY_PATH=../.. gdb ./test-$(PROGRAM) 31 + 32 + valgrind: test-$(PROGRAM) 33 + valgrind --tool=memcheck --leak-check=full --show-reachable=yes --num-callers=20 --track-fds=yes ./test-$(PROGRAM) 34 + 35 + clean: 36 + rm -f test-$(PROGRAM)
+42
external/libpthread_workqueue-0.8.2/testing/api/posix_semaphore.h
··· 1 + #ifndef DISPATCH_WIN_POSIX_SEMAPHORE_ 2 + #define DISPATCH_WIN_POSIX_SEMAPHORE_ 3 + 4 + typedef HANDLE sem_t; 5 + 6 + static int sem_init(sem_t * sem, int shared, unsigned int val) 7 + { 8 + *sem = CreateSemaphore(0, val, 1, 0); 9 + // TODO: Proper error handling 10 + return *sem == 0; 11 + } 12 + 13 + static inline int sem_destroy(sem_t* s) 14 + { 15 + return CloseHandle(s) != 1; 16 + } 17 + 18 + static inline int sem_post(sem_t* s) 19 + { 20 + return !ReleaseSemaphore(s, 1, 0); 21 + } 22 + 23 + static inline int sem_wait(sem_t* s) 24 + { 25 + return WaitForSingleObject(s, INFINITE) == WAIT_FAILED; 26 + } 27 + 28 + static int sem_timedwait(sem_t * sem, const struct timespec * timeout) 29 + { 30 + DWORD duration = (DWORD)(timeout->tv_nsec / 1000000) + (DWORD)(timeout->tv_sec * 1000); 31 + 32 + switch(WaitForSingleObject(sem,duration) ){ 33 + case WAIT_TIMEOUT: 34 + return ETIMEDOUT; 35 + case WAIT_FAILED: 36 + return EINVAL; 37 + default: 38 + return 0; 39 + } 40 + } 41 + 42 + #endif /* DISPATCH_WIN_POSIX_SEMAPHORE_ */
+292
external/libpthread_workqueue-0.8.2/testing/api/test.c
··· 1 + #include <limits.h> 2 + #include <stdlib.h> 3 + #include <stdio.h> 4 + #include <string.h> 5 + 6 + #if !defined(_WIN32) 7 + # include <sys/wait.h> 8 + # if !defined(NO_CONFIG_H) 9 + # include "config.h" 10 + # endif 11 + # include <semaphore.h> 12 + #else 13 + # define inline _inline 14 + # include "../../src/windows/platform.h" 15 + # include "posix_semaphore.h" 16 + #endif 17 + #include "../../src/private.h" 18 + 19 + #if HAVE_ERR_H 20 + # include <err.h> 21 + #else 22 + # define err(rc,msg,...) do { perror(msg); exit(rc); } while (0) 23 + # define errx(rc,msg,...) do { puts(msg); exit(rc); } while (0) 24 + #endif 25 + 26 + #include <pthread_workqueue.h> 27 + 28 + static int work_cnt; 29 + 30 + /* If non-zero, extra debugging statements will be printed */ 31 + static int dbg = 0; 32 + 33 + static sem_t test_complete; 34 + static int test_rounds; 35 + #undef dbg_puts 36 + #define dbg_puts(s) if (dbg) puts(s) 37 + #undef dbg_printf 38 + #define dbg_printf(fmt,...) if (dbg) fprintf(stderr, fmt, __VA_ARGS__) 39 + 40 + void additem(pthread_workqueue_t wq, void (*func)(void *), 41 + void * arg) 42 + { 43 + 44 + int rv; 45 + 46 + rv = pthread_workqueue_additem_np(wq, *func, arg, NULL, NULL); 47 + if (rv != 0) 48 + errx(1, "unable to add item: %s", strerror(rv)); 49 + dbg_puts("added item\n"); 50 + } 51 + 52 + void 53 + mark_progress(void) 54 + { 55 + static pthread_mutex_t mtx = PTHREAD_MUTEX_INITIALIZER; 56 + 57 + pthread_mutex_lock(&mtx); 58 + test_rounds--; 59 + pthread_mutex_unlock(&mtx); 60 + 61 + dbg_printf("rounds = %d\n", test_rounds); 62 + if (test_rounds == 0) { 63 + sem_post(&test_complete); 64 + } 65 + } 66 + 67 + void 68 + sem_up(void *arg) 69 + { 70 + dbg_puts("semaphore UP\n"); 71 + sem_post((sem_t *) arg); 72 + mark_progress(); 73 + } 74 + 75 + void 76 + sem_down(void *arg) 77 + { 78 + dbg_puts("semaphore DOWN\n"); 79 + sem_wait((sem_t *) arg); 80 + dbg_puts("semaphore UP\n"); 81 + sem_post((sem_t *) arg); 82 + mark_progress(); 83 + } 84 + 85 + void 86 + compute(void *arg) 87 + { 88 + int *count = (int *) arg; 89 + #define nval 5000 90 + int val[nval]; 91 + int i,j; 92 + 93 + /* Do some useless computation */ 94 + for (i = 0; i < nval; i++) { 95 + val[i] = INT_MAX; 96 + } 97 + for (j = 0; j < nval; j++) { 98 + for (i = 0; i < nval; i++) { 99 + val[i] /= 3; 100 + val[i] *= 2; 101 + val[i] /= 4; 102 + val[i] *= 5; 103 + } 104 + } 105 + 106 + if (count != NULL) 107 + (*count)--; 108 + } 109 + 110 + 111 + void 112 + sleepy(void *msg) 113 + { 114 + printf("%s\n", (char *) msg); 115 + if (strcmp(msg, "done") == 0) 116 + exit(0); 117 + sleep(random() % 6); 118 + } 119 + 120 + void 121 + lazy(void *arg) 122 + { 123 + sleep(3); 124 + dbg_printf("item %lu complete\n", (unsigned long) arg); 125 + work_cnt--; 126 + } 127 + 128 + void 129 + run_blocking_test(pthread_workqueue_t wq, int rounds) 130 + { 131 + long i = 0; 132 + work_cnt = rounds; 133 + for (i = 0; i < rounds; i++) { 134 + additem(wq, lazy, (void *) i); 135 + } 136 + while (work_cnt > 0) 137 + sleep(1); 138 + } 139 + 140 + void 141 + run_cond_wait_test(pthread_workqueue_t wq) 142 + { 143 + const int rounds = 10; 144 + long i = 0; 145 + 146 + sleep(3); /* Allow time for the workers to enter pthread_cond_wait() */ 147 + work_cnt = rounds; 148 + for (i = 0; i < rounds; i++) { 149 + additem(wq, lazy, (void *) i); 150 + sleep(1); 151 + } 152 + while (work_cnt > 0) 153 + sleep(1); 154 + } 155 + 156 + void 157 + run_load_test(pthread_workqueue_t wq) 158 + { 159 + char buf[16]; 160 + int i = 0; 161 + for (i = 0; i < 1024; i++) { 162 + sprintf(buf, "%d", i); 163 + additem(wq, sleepy, strdup(buf)); 164 + additem(wq, compute, NULL); 165 + } 166 + additem(wq, sleepy, "done"); 167 + } 168 + 169 + /* Try to overwhelm the CPU with computation requests */ 170 + void 171 + run_stress_test(pthread_workqueue_t wq, int rounds) 172 + { 173 + int i = 0; 174 + work_cnt = rounds; 175 + for (i = 0; i < rounds; i++) { 176 + additem(wq, compute, &work_cnt); 177 + } 178 + while (work_cnt > 0) 179 + sleep(1); 180 + } 181 + 182 + /* 183 + * Ensure that the library is reinitialized after fork(2) is called. 184 + */ 185 + void 186 + run_fork_test(pthread_workqueue_t wq) 187 + { 188 + #if !defined(_WIN32) 189 + pid_t pid; 190 + int rv, status, timeout; 191 + 192 + puts("fork test... "); 193 + pid = fork(); 194 + if (pid < 0) 195 + err(1, "fork"); 196 + 197 + if (pid == 0) { 198 + /* Child */ 199 + wq = NULL; 200 + rv = pthread_workqueue_create_np(&wq, NULL); 201 + if (rv < 0) 202 + errx(1, "pthread_workqueue_create_np"); 203 + work_cnt = 1; 204 + timeout = 5; 205 + additem(wq, compute, &work_cnt); 206 + while (work_cnt > 0) { 207 + sleep(1); 208 + if (--timeout == 0) 209 + errx(1, "work was not completed"); 210 + } 211 + exit(0); 212 + } else { 213 + /* Parent */ 214 + if (wait(&status) != pid) 215 + err(1, "waitpid"); 216 + if (WEXITSTATUS(status) != 0) 217 + errx(1, "fork test failed"); 218 + puts("ok\n"); 219 + } 220 + #else 221 + puts("fork test... N/A\n"); 222 + #endif 223 + } 224 + 225 + void 226 + run_overcommit_test(pthread_workqueue_t wq) 227 + { 228 + sem_t sem; 229 + pthread_workqueue_t ocwq; 230 + pthread_workqueue_attr_t attr; 231 + int i, rv; 232 + 233 + (void)wq; 234 + sem_init(&sem, 0, 0); 235 + 236 + printf("pthread_workqueue_create_np() - overcommit enabled "); 237 + pthread_workqueue_attr_init_np(&attr); 238 + pthread_workqueue_attr_setovercommit_np(&attr, 1); 239 + rv = pthread_workqueue_create_np(&ocwq, &attr); 240 + if (rv != 0) 241 + err(1, "failed"); 242 + 243 + puts("ok\n"); 244 + 245 + printf("stress test - overcommit enabled "); 246 + run_stress_test(ocwq, 25); 247 + puts("ok\n"); 248 + 249 + /* FIXME: should use a multiple of the number of CPUs instead of magic number */ 250 + printf("deadlock test - overcommit enabled "); 251 + test_rounds = 41; 252 + for (i = 0; i < 40; i++) { 253 + additem(ocwq, sem_down, &sem); 254 + } 255 + additem(ocwq, sem_up, &sem); 256 + sem_wait(&test_complete); 257 + puts("ok\n"); 258 + } 259 + 260 + int main() { 261 + pthread_workqueue_t wq; 262 + int rv; 263 + 264 + #ifdef MAKE_STATIC 265 + pthread_workqueue_init_np(); 266 + #endif 267 + 268 + sem_init(&test_complete, 0, 0); 269 + 270 + run_overcommit_test(NULL); 271 + 272 + printf("pthread_workqueue_create_np().. "); 273 + rv = pthread_workqueue_create_np(&wq, NULL); 274 + if (rv != 0) 275 + err(1, "failed"); 276 + printf("ok\n"); 277 + 278 + printf("stress test.. "); 279 + run_stress_test(wq, 25); 280 + printf("ok\n"); 281 + 282 + run_fork_test(wq); 283 + 284 + //run_deadlock_test(); 285 + // run_cond_wait_test(); 286 + // run_blocking_test(); 287 + //run_load_test(); 288 + 289 + 290 + puts("All tests completed.\n"); 291 + exit(0); 292 + }
+86
external/libpthread_workqueue-0.8.2/testing/api/test_api.vcxproj
··· 1 + <?xml version="1.0" encoding="utf-8"?> 2 + <Project DefaultTargets="Build" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> 3 + <ItemGroup Label="ProjectConfigurations"> 4 + <ProjectConfiguration Include="Debug|Win32"> 5 + <Configuration>Debug</Configuration> 6 + <Platform>Win32</Platform> 7 + </ProjectConfiguration> 8 + <ProjectConfiguration Include="Release|Win32"> 9 + <Configuration>Release</Configuration> 10 + <Platform>Win32</Platform> 11 + </ProjectConfiguration> 12 + </ItemGroup> 13 + <ItemGroup> 14 + <ClCompile Include="test.c" /> 15 + </ItemGroup> 16 + <ItemGroup> 17 + <ProjectReference Include="..\..\libpthread_workqueue.vcxproj"> 18 + <Project>{c8953032-a7fd-b3b1-6606-8dd078518b9a}</Project> 19 + </ProjectReference> 20 + </ItemGroup> 21 + <PropertyGroup Label="Globals"> 22 + <ProjectGuid>{6D7A0EA0-AE20-4584-AEE6-25B49823073A}</ProjectGuid> 23 + <Keyword>Win32Proj</Keyword> 24 + <RootNamespace>test_api</RootNamespace> 25 + </PropertyGroup> 26 + <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" /> 27 + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration"> 28 + <ConfigurationType>Application</ConfigurationType> 29 + <UseDebugLibraries>true</UseDebugLibraries> 30 + <CharacterSet>Unicode</CharacterSet> 31 + </PropertyGroup> 32 + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration"> 33 + <ConfigurationType>Application</ConfigurationType> 34 + <UseDebugLibraries>false</UseDebugLibraries> 35 + <WholeProgramOptimization>true</WholeProgramOptimization> 36 + <CharacterSet>Unicode</CharacterSet> 37 + </PropertyGroup> 38 + <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" /> 39 + <ImportGroup Label="ExtensionSettings"> 40 + </ImportGroup> 41 + <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'"> 42 + <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" /> 43 + </ImportGroup> 44 + <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'"> 45 + <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" /> 46 + </ImportGroup> 47 + <PropertyGroup Label="UserMacros" /> 48 + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'"> 49 + <LinkIncremental>true</LinkIncremental> 50 + <IncludePath>..\..\include;$(IncludePath)</IncludePath> 51 + </PropertyGroup> 52 + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'"> 53 + <LinkIncremental>false</LinkIncremental> 54 + </PropertyGroup> 55 + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'"> 56 + <ClCompile> 57 + <PrecompiledHeader>NotUsing</PrecompiledHeader> 58 + <WarningLevel>Level3</WarningLevel> 59 + <Optimization>Disabled</Optimization> 60 + <PreprocessorDefinitions>WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions> 61 + </ClCompile> 62 + <Link> 63 + <SubSystem>Console</SubSystem> 64 + <GenerateDebugInformation>true</GenerateDebugInformation> 65 + </Link> 66 + </ItemDefinitionGroup> 67 + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'"> 68 + <ClCompile> 69 + <WarningLevel>Level3</WarningLevel> 70 + <PrecompiledHeader>Use</PrecompiledHeader> 71 + <Optimization>MaxSpeed</Optimization> 72 + <FunctionLevelLinking>true</FunctionLevelLinking> 73 + <IntrinsicFunctions>true</IntrinsicFunctions> 74 + <PreprocessorDefinitions>WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions> 75 + </ClCompile> 76 + <Link> 77 + <SubSystem>Console</SubSystem> 78 + <GenerateDebugInformation>true</GenerateDebugInformation> 79 + <EnableCOMDATFolding>true</EnableCOMDATFolding> 80 + <OptimizeReferences>true</OptimizeReferences> 81 + </Link> 82 + </ItemDefinitionGroup> 83 + <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" /> 84 + <ImportGroup Label="ExtensionTargets"> 85 + </ImportGroup> 86 + </Project>
+28
external/libpthread_workqueue-0.8.2/testing/idle/Makefile
··· 1 + # 2 + # Copyright (c) 2011 Mark Heily <mark@heily.com> 3 + # 4 + # Permission to use, copy, modify, and distribute this software for any 5 + # purpose with or without fee is hereby granted, provided that the above 6 + # copyright notice and this permission notice appear in all copies. 7 + # 8 + # THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 9 + # WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 10 + # MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 11 + # ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 12 + # WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 13 + # ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 14 + # OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 15 + # 16 + 17 + include ../../config.mk 18 + 19 + all: idle 20 + 21 + idle: main.c 22 + $(CC) $(CFLAGS) -g -O0 -o $@ -I../.. -I../../include -L../.. -Wl,-rpath,$(BASEDIR) main.c -lpthread_workqueue -lpthread 23 + 24 + check: idle 25 + LD_LIBRARY_PATH=../..:/usr/sfw/lib/amd64 PWQ_DEBUG=yes ./idle 26 + 27 + clean: 28 + rm -f idle
+108
external/libpthread_workqueue-0.8.2/testing/idle/main.c
··· 1 + /*- 2 + * Copyright (c) 2011, Mark Heily <mark@heily.com> 3 + * All rights reserved. 4 + * 5 + * Redistribution and use in source and binary forms, with or without 6 + * modification, are permitted provided that the following conditions 7 + * are met: 8 + * 1. Redistributions of source code must retain the above copyright 9 + * notice unmodified, this list of conditions, and the following 10 + * disclaimer. 11 + * 2. Redistributions in binary form must reproduce the above copyright 12 + * notice, this list of conditions and the following disclaimer in the 13 + * documentation and/or other materials provided with the distribution. 14 + * 15 + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 16 + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 17 + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 18 + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 19 + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 20 + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 21 + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 22 + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 23 + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 24 + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25 + * 26 + */ 27 + 28 + #include <err.h> 29 + #include <stdio.h> 30 + #include <stdlib.h> 31 + #include <unistd.h> 32 + 33 + #include <pthread_workqueue.h> 34 + 35 + void f(void *arg) 36 + { 37 + long x = (long) arg; 38 + 39 + printf("worker %ld running\n", x); 40 + sleep(1); 41 + printf("worker %ld finished\n", x); 42 + } 43 + 44 + void run_idle_test(pthread_workqueue_t wq) 45 + { 46 + long i; 47 + int rv; 48 + 49 + for (i = 0; i < 100; i++) { 50 + rv = pthread_workqueue_additem_np(wq, f, (void *) i, NULL, NULL); 51 + if (rv != 0) abort(); 52 + } 53 + 54 + sleep(2); 55 + 56 + int rounds = 0; 57 + for (;;) { 58 + unsigned long idle = pthread_workqueue_peek_np("combined_idle"); 59 + unsigned long norml_idle = pthread_workqueue_peek_np("idle"); 60 + unsigned long ocomm_idle = pthread_workqueue_peek_np("ocomm_idle"); 61 + printf("idle = %lu (overcommit = %lu non-overcommit = %lu)\n", 62 + idle, ocomm_idle, norml_idle); 63 + if (idle == 0 || (norml_idle == 1 && ocomm_idle == 0)) 64 + break; 65 + 66 + sleep(1); 67 + if (rounds++ > 240) { 68 + printf("\n*** ERROR: idle threads were not reaped properly\n"); 69 + exit(1); 70 + } 71 + } 72 + } 73 + 74 + /* 75 + * Enqueue a large number of short-lived workitems, to allow observation 76 + * of how idle threads are terminated. 77 + */ 78 + int main(int argc, char *argv[]) 79 + { 80 + pthread_workqueue_t wq; 81 + pthread_workqueue_t ocwq; 82 + pthread_workqueue_attr_t attr; 83 + pthread_workqueue_attr_t ocattr; 84 + int i, rounds; 85 + int rv; 86 + 87 + if (argc == 2) 88 + rounds = atoi(argv[1]); 89 + else 90 + rounds = 1; 91 + 92 + pthread_workqueue_attr_init_np(&attr); 93 + pthread_workqueue_attr_setovercommit_np(&attr, 0); 94 + rv = pthread_workqueue_create_np(&wq, &attr); 95 + if (rv != 0) abort(); 96 + 97 + pthread_workqueue_attr_init_np(&ocattr); 98 + pthread_workqueue_attr_setovercommit_np(&ocattr, 1); 99 + rv = pthread_workqueue_create_np(&ocwq, &ocattr); 100 + if (rv != 0) abort(); 101 + 102 + for (i = 0; i < rounds; i++) { 103 + run_idle_test(wq); 104 + run_idle_test(ocwq); 105 + } 106 + printf("\n---\nOK: all excess idle threads have been terminated after %d rounds.\n", rounds); 107 + exit(0); 108 + }
+21
external/libpthread_workqueue-0.8.2/testing/latency/Makefile
··· 1 + CC=gcc 2 + 3 + include ../../config.mk 4 + 5 + all: latency 6 + 7 + latency: 8 + $(CC) $(CFLAGS) -I../../include -L../.. -Wl,-rpath,$(BASEDIR) -o latency latency.c -lpthread_workqueue -lpthread -lrt 9 + 10 + solaris: 11 + $(CC) $(CFLAGS) -I../../include -L../.. -R$(BASEDIR) -o latency latency.c -lpthread_workqueue -lpthread -lrt 12 + 13 + macosx: 14 + $(CC) $(CFLAGS) -I../../include -L../.. -R$(BASEDIR) -o latencym latency.c -lpthread 15 + 16 + check: latency 17 + LD_LIBRARY_PATH=../..:/usr/sfw/lib/amd64 ./latency 18 + 19 + clean: 20 + rm -f latency 21 + rm -f latencym
+393
external/libpthread_workqueue-0.8.2/testing/latency/latency.c
··· 1 + /* 2 + * Copyright (c) 2011 Joakim Johansson <jocke@tbricks.com>. 3 + * 4 + * @APPLE_APACHE_LICENSE_HEADER_START@ 5 + * 6 + * Licensed under the Apache License, Version 2.0 (the "License"); 7 + * you may not use this file except in compliance with the License. 8 + * You may obtain a copy of the License at 9 + * 10 + * http://www.apache.org/licenses/LICENSE-2.0 11 + * 12 + * Unless required by applicable law or agreed to in writing, software 13 + * distributed under the License is distributed on an "AS IS" BASIS, 14 + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 + * See the License for the specific language governing permissions and 16 + * limitations under the License. 17 + * 18 + * @APPLE_APACHE_LICENSE_HEADER_END@ 19 + */ 20 + 21 + #include <stdio.h> 22 + #include <stdlib.h> 23 + #include <ctype.h> 24 + #include <string.h> 25 + #include <errno.h> 26 + #include <time.h> 27 + 28 + #ifndef _WIN32 29 + # include <unistd.h> 30 + # include <pthread.h> 31 + # include <sys/time.h> 32 + #endif 33 + 34 + #include "latency.h" 35 + 36 + pthread_workqueue_t workqueues[WORKQUEUE_COUNT]; 37 + struct wq_statistics workqueue_statistics[WORKQUEUE_COUNT]; 38 + struct wq_event_generator workqueue_generator[GENERATOR_WORKQUEUE_COUNT]; 39 + 40 + struct wq_statistics global_statistics; 41 + unsigned int global_stats_used = 0; 42 + 43 + pthread_mutex_t generator_mutex; 44 + pthread_cond_t generator_condition; 45 + static unsigned int events_processed; 46 + 47 + #define PERCENTILE_COUNT 8 48 + double percentiles[PERCENTILE_COUNT] = {50.0, 80.0, 98.0, 99.0, 99.5, 99.8, 99.9, 99.99}; 49 + mytime_t real_start, real_end; 50 + 51 + #ifdef __APPLE__ 52 + 53 + #include <assert.h> 54 + #include <CoreServices/CoreServices.h> 55 + #include <mach/mach.h> 56 + #include <mach/mach_time.h> 57 + 58 + static mach_timebase_info_data_t sTimebaseInfo; 59 + 60 + // From http://developer.apple.com/library/mac/#qa/qa2004/qa1398.html 61 + unsigned long gettime(void) 62 + { 63 + return (mach_absolute_time() * sTimebaseInfo.numer / sTimebaseInfo.denom); 64 + } 65 + 66 + #else 67 + 68 + static mytime_t gettime(void) 69 + { 70 + #ifdef __linux__ 71 + struct timespec ts; 72 + if (clock_gettime(CLOCK_MONOTONIC, &ts) != 0) 73 + fprintf(stderr, "Failed to get high resolution clock! errno = %d\n", errno); 74 + return ((ts.tv_sec * NANOSECONDS_PER_SECOND) + ts.tv_nsec); 75 + #elif defined(_WIN32) 76 + LARGE_INTEGER now; 77 + LARGE_INTEGER freq; 78 + if (!QueryPerformanceCounter(&now) ) 79 + fprintf(stderr, "Failed to get performance counter!\n"); 80 + if (!QueryPerformanceFrequency(&freq) ) 81 + fprintf(stderr, "Failed to get performance frequency!\n"); 82 + 83 + return (mytime_t)(now.QuadPart * NANOSECONDS_PER_SECOND / freq.QuadPart); 84 + #else 85 + struct timespec ts; 86 + if (clock_gettime(CLOCK_HIGHRES, &ts) != 0) 87 + fprintf(stderr, "Failed to get high resolution clock! errno = %d\n", errno); 88 + return ((ts.tv_sec * NANOSECONDS_PER_SECOND) + ts.tv_nsec); 89 + #endif 90 + } 91 + 92 + #endif 93 + 94 + #ifdef _WIN32 95 + 96 + static void my_sleep(unsigned long nanoseconds) { 97 + LARGE_INTEGER start, end; 98 + LARGE_INTEGER freq; 99 + 100 + QueryPerformanceCounter(&start); 101 + QueryPerformanceFrequency(&freq); 102 + 103 + // sleep with ms resolution ... 104 + Sleep(nanoseconds / 1000000); 105 + 106 + // ... and busy-wait afterwards, until the requested delay was reached 107 + QueryPerformanceCounter(&end); 108 + while( (end.QuadPart - start.QuadPart) * NANOSECONDS_PER_SECOND / freq.QuadPart < nanoseconds ){ 109 + YieldProcessor(); 110 + QueryPerformanceCounter(&end); 111 + } 112 + 113 + } 114 + 115 + #else 116 + 117 + // real resolution on solaris is at best system clock tick, i.e. 100Hz unless having the 118 + // high res system clock (1000Hz in that case) 119 + 120 + static void my_sleep(unsigned long nanoseconds) 121 + { 122 + struct timespec timeout0; 123 + struct timespec timeout1; 124 + struct timespec* tmp; 125 + struct timespec* t0 = &timeout0; 126 + struct timespec* t1 = &timeout1; 127 + 128 + t0->tv_sec = nanoseconds / NANOSECONDS_PER_SECOND; 129 + t0->tv_nsec = nanoseconds % NANOSECONDS_PER_SECOND; 130 + 131 + while ((nanosleep(t0, t1) == (-1)) && (errno == EINTR)) 132 + { 133 + tmp = t0; 134 + t0 = t1; 135 + t1 = tmp; 136 + } 137 + 138 + return; 139 + } 140 + 141 + #endif 142 + 143 + static void _process_data(void* context) 144 + { 145 + struct wq_event *event = (struct wq_event *) context; 146 + mytime_t elapsed_time; 147 + 148 + elapsed_time = gettime() - event->start_time; 149 + 150 + workqueue_statistics[event->queue_index].avg = ((workqueue_statistics[event->queue_index].count * workqueue_statistics[event->queue_index].avg) + elapsed_time) / (workqueue_statistics[event->queue_index].count + 1); 151 + workqueue_statistics[event->queue_index].total += elapsed_time; 152 + workqueue_statistics[event->queue_index].count += 1; 153 + 154 + if (elapsed_time < workqueue_statistics[event->queue_index].min || 155 + workqueue_statistics[event->queue_index].min == 0) 156 + workqueue_statistics[event->queue_index].min = elapsed_time; 157 + 158 + if (elapsed_time > workqueue_statistics[event->queue_index].max) 159 + workqueue_statistics[event->queue_index].max = elapsed_time; 160 + 161 + if ((elapsed_time / 1000) < DISTRIBUTION_BUCKETS) 162 + workqueue_statistics[event->queue_index].distribution[(int)(elapsed_time / 1000)] += 1; 163 + else 164 + workqueue_statistics[event->queue_index].distribution[DISTRIBUTION_BUCKETS-1] += 1; 165 + 166 + // allow generator thread to continue when all events have been processed 167 + if (atomic_dec_nv(&events_processed) == 0) 168 + { 169 + pthread_mutex_lock(&generator_mutex); 170 + pthread_cond_signal(&generator_condition); 171 + pthread_mutex_unlock(&generator_mutex); 172 + } 173 + return; 174 + } 175 + 176 + // Perform a small microburst for this tick 177 + static void _event_tick(void* context) 178 + { 179 + struct wq_event *current_event; 180 + long i, generator_workqueue = (long) context; 181 + 182 + for (i = 0; i < EVENTS_GENERATED_PER_TICK; i++) 183 + { 184 + current_event = &workqueue_generator[generator_workqueue].wq_events[i]; 185 + current_event->start_time = gettime(); 186 + current_event->queue_index = (current_event->start_time % WORKQUEUE_COUNT); 187 + 188 + (void) pthread_workqueue_additem_np(workqueues[current_event->queue_index], _process_data, current_event, NULL, NULL); 189 + } 190 + 191 + return; 192 + } 193 + 194 + static void _generate_simulated_events() 195 + { 196 + unsigned long i = 0, tick; 197 + mytime_t overhead; 198 + mytime_t start, current, overhead_start = 0, overhead_end = 0; 199 + 200 + start = current = gettime(); 201 + 202 + for (tick = 0; tick < TOTAL_TICKS_TO_RUN; tick++) 203 + { 204 + start = current = overhead_end; 205 + overhead = overhead_end - overhead_start; 206 + 207 + // wait until we have waited proper amount of time for current rate 208 + // we should remove overhead of previous lap to not lag behind in data rate 209 + // one call to gethrtime() alone is around 211ns on Nehalem 2.93 210 + // use busy waiting in case the frequency is higher than the supported resolution of nanosleep() 211 + 212 + if (overhead > EVENT_TIME_SLICE) 213 + { 214 + printf("Warning: Event processing overhead > event time slice, readjust test parameters.\n"); 215 + } 216 + else 217 + if ((EVENT_GENERATION_FREQUENCY > SYSTEM_CLOCK_RESOLUTION) || FORCE_BUSY_LOOP) 218 + { 219 + while ((current - start) < (EVENT_TIME_SLICE - overhead)) 220 + current = gettime(); 221 + } 222 + else 223 + { 224 + my_sleep(EVENT_TIME_SLICE - overhead); 225 + } 226 + 227 + overhead_start = gettime(); 228 + 229 + events_processed = GENERATOR_WORKQUEUE_COUNT * EVENTS_GENERATED_PER_TICK; // number of items that will be processed 230 + 231 + #if (LATENCY_RUN_GENERATOR_IN_MAIN_THREAD == 0) 232 + for (i = 0; i < GENERATOR_WORKQUEUE_COUNT; i++) 233 + (void) pthread_workqueue_additem_np(workqueue_generator[i].wq, _event_tick, (void *) i, NULL, NULL); 234 + #else 235 + _event_tick((void *)i); 236 + #endif 237 + 238 + // wait for all events to be processed 239 + pthread_mutex_lock(&generator_mutex); 240 + while (events_processed > 0) 241 + pthread_cond_wait(&generator_condition, &generator_mutex); 242 + pthread_mutex_unlock(&generator_mutex); 243 + 244 + overhead_end = gettime(); 245 + } 246 + 247 + return; 248 + } 249 + 250 + static void _gather_statistics(unsigned long queue_index) 251 + { 252 + unsigned long i; 253 + 254 + if (workqueue_statistics[queue_index].count > 0) 255 + { 256 + global_stats_used ++; 257 + 258 + global_statistics.avg = ((global_statistics.count * global_statistics.avg) + (workqueue_statistics[queue_index].avg * workqueue_statistics[queue_index].count)) / (global_statistics.count + workqueue_statistics[queue_index].count); 259 + global_statistics.total += workqueue_statistics[queue_index].total; 260 + global_statistics.count += workqueue_statistics[queue_index].count; 261 + 262 + if (workqueue_statistics[queue_index].min < global_statistics.min || global_statistics.min == 0) 263 + global_statistics.min = workqueue_statistics[queue_index].min; 264 + 265 + if (workqueue_statistics[queue_index].max > global_statistics.max) 266 + global_statistics.max = workqueue_statistics[queue_index].max; 267 + 268 + for (i = 0; i < DISTRIBUTION_BUCKETS; i++) 269 + global_statistics.distribution[i] += workqueue_statistics[queue_index].distribution[i]; 270 + } 271 + 272 + return; 273 + } 274 + 275 + void _print_statistics() 276 + { 277 + unsigned long i, j, total_events = 0, last_percentile = 0, accumulated_percentile = 0; 278 + 279 + printf("Collecting statistics...\n"); 280 + 281 + for (i = 0; i < WORKQUEUE_COUNT; i++) 282 + _gather_statistics(i); 283 + 284 + printf("Test is done, run time was %.3f seconds, %.1fM events generated and processed.\n", (double)((double)(real_end - real_start) / (double) NANOSECONDS_PER_SECOND), total_events/1000000.0); 285 + 286 + //FIXME - casting from mytime_t (u_long) to int will truncate the result 287 + printf("Global dispatch queue aggregate statistics for %d queues: %dM events, min = %d ns, avg = %.1f ns, max = %d ns\n", 288 + global_stats_used, global_statistics.count/1000000, (int) global_statistics.min, global_statistics.avg, (int) global_statistics.max); 289 + 290 + printf("\nDistribution:\n"); 291 + for (i = 0; i < DISTRIBUTION_BUCKETS; i++) 292 + { 293 + printf("%3ld us: %d ", i, global_statistics.distribution[i]); 294 + for (j=0; j<(((double) global_statistics.distribution[i] / (double) global_statistics.count) * 400.0); j++) 295 + printf("*"); 296 + printf("\n"); 297 + } 298 + 299 + printf("\nPercentiles:\n"); 300 + 301 + for (i = 0; i < DISTRIBUTION_BUCKETS; i++) 302 + { 303 + while ((last_percentile < PERCENTILE_COUNT) && ((100.0 * ((double) accumulated_percentile / (double) global_statistics.count)) > percentiles[last_percentile])) 304 + { 305 + printf("%.2f < %ld us\n", percentiles[last_percentile], i-1); 306 + last_percentile++; 307 + } 308 + accumulated_percentile += global_statistics.distribution[i]; 309 + } 310 + 311 + while ((last_percentile < PERCENTILE_COUNT) && ((100.0 * ((double) accumulated_percentile / (double) global_statistics.count)) > percentiles[last_percentile])) 312 + { 313 + printf("%.2f > %d us\n", percentiles[last_percentile], DISTRIBUTION_BUCKETS-1); 314 + last_percentile++; 315 + } 316 + 317 + return; 318 + } 319 + 320 + int main(void) 321 + { 322 + int i; 323 + pthread_workqueue_attr_t attr; 324 + 325 + #ifdef __APPLE__ 326 + (void) mach_timebase_info(&sTimebaseInfo); 327 + #endif 328 + 329 + #ifdef MAKE_STATIC 330 + pthread_workqueue_init_np(); 331 + #endif 332 + 333 + memset(&workqueues, 0, sizeof(workqueues)); 334 + memset(&workqueue_statistics, 0, sizeof(workqueue_statistics)); 335 + memset(&global_statistics, 0, sizeof(global_statistics)); 336 + memset(&workqueue_generator, 0, sizeof(workqueue_generator)); 337 + 338 + pthread_mutex_init(&generator_mutex, NULL); 339 + pthread_cond_init(&generator_condition, NULL); 340 + 341 + if (pthread_workqueue_attr_init_np(&attr) != 0) 342 + fprintf(stderr, "Failed to set workqueue attributes\n"); 343 + 344 + for (i = 0; i < GENERATOR_WORKQUEUE_COUNT; i++) 345 + { 346 + if (pthread_workqueue_attr_setqueuepriority_np(&attr, i) != 0) 347 + fprintf(stderr, "Failed to set workqueue priority\n"); 348 + 349 + if (pthread_workqueue_attr_setovercommit_np(&attr, 1) != 0) 350 + fprintf(stderr, "Failed to set workqueue overcommit\n"); 351 + 352 + workqueue_generator[i].wq_events = malloc(sizeof(struct wq_event) * EVENTS_GENERATED_PER_TICK); 353 + memset(workqueue_generator[i].wq_events, 0, (sizeof(struct wq_event) * EVENTS_GENERATED_PER_TICK)); 354 + 355 + if (pthread_workqueue_create_np(&workqueue_generator[i].wq, &attr) != 0) 356 + fprintf(stderr, "Failed to create workqueue\n"); 357 + } 358 + 359 + for (i = 0; i < WORKQUEUE_COUNT; i++) 360 + { 361 + if (pthread_workqueue_attr_init_np(&attr) != 0) 362 + fprintf(stderr, "Failed to set workqueue attributes\n"); 363 + 364 + if (pthread_workqueue_attr_setqueuepriority_np(&attr, i) != 0) 365 + fprintf(stderr, "Failed to set workqueue priority\n"); 366 + 367 + if (pthread_workqueue_create_np(&workqueues[i], &attr) != 0) 368 + fprintf(stderr, "Failed to create workqueue\n"); 369 + } 370 + 371 + if (SLEEP_BEFORE_START > 0) 372 + { 373 + printf("Sleeping for %d seconds to allow for processor set configuration...\n",SLEEP_BEFORE_START); 374 + sleep(SLEEP_BEFORE_START); 375 + } 376 + 377 + printf("%d workqueues, running for %d seconds at %d Hz, %d events per tick.\n",WORKQUEUE_COUNT, SECONDS_TO_RUN, EVENT_GENERATION_FREQUENCY, EVENTS_GENERATED_PER_TICK); 378 + 379 + printf("Running %d generator threads at %dK events/s, the aggregated data rate is %dK events/s. %.2f MB is used for %.2fK events.\n", 380 + GENERATOR_WORKQUEUE_COUNT,AGGREGATE_DATA_RATE_PER_SECOND/1000, TOTAL_DATA_PER_SECOND/1000, 381 + (double) GENERATOR_WORKQUEUE_COUNT * ((sizeof(struct wq_event) * EVENTS_GENERATED_PER_TICK + sizeof(workqueues))/(1024.0*1024.0)), 382 + GENERATOR_WORKQUEUE_COUNT * EVENTS_GENERATED_PER_TICK/1000.0); 383 + 384 + real_start = gettime(); 385 + 386 + _generate_simulated_events(); 387 + 388 + real_end = gettime(); 389 + 390 + _print_statistics(); 391 + 392 + return 0; 393 + }
+95
external/libpthread_workqueue-0.8.2/testing/latency/latency.h
··· 1 + /* 2 + * Copyright (c) 2011 Joakim Johansson <jocke@tbricks.com>. 3 + * 4 + * @APPLE_APACHE_LICENSE_HEADER_START@ 5 + * 6 + * Licensed under the Apache License, Version 2.0 (the "License"); 7 + * you may not use this file except in compliance with the License. 8 + * You may obtain a copy of the License at 9 + * 10 + * http://www.apache.org/licenses/LICENSE-2.0 11 + * 12 + * Unless required by applicable law or agreed to in writing, software 13 + * distributed under the License is distributed on an "AS IS" BASIS, 14 + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 + * See the License for the specific language governing permissions and 16 + * limitations under the License. 17 + * 18 + * @APPLE_APACHE_LICENSE_HEADER_END@ 19 + */ 20 + 21 + #include "pthread_workqueue.h" 22 + 23 + #ifdef _WIN32 24 + # include "../../src/windows/platform.h" 25 + #endif 26 + 27 + // Run settings 28 + #define SECONDS_TO_RUN 10 29 + #define WORKQUEUE_COUNT 3 30 + #define GENERATOR_WORKQUEUE_COUNT 1 31 + #define SLEEP_BEFORE_START 0 32 + #define FORCE_BUSY_LOOP 0 33 + #define LATENCY_RUN_GENERATOR_IN_MAIN_THREAD 0 34 + 35 + // Data rates 36 + #define EVENTS_GENERATED_PER_TICK 100 // simulate some small bursting 37 + #define EVENT_GENERATION_FREQUENCY 100 // events/s base rate, need to use busy loop = 1 if > 100Hz due to nanosleep resolution 38 + 39 + #define AGGREGATE_DATA_RATE_PER_SECOND (EVENT_GENERATION_FREQUENCY * EVENTS_GENERATED_PER_TICK) 40 + #define EVENTS_TO_GENERATE (SECONDS_TO_RUN * AGGREGATE_DATA_RATE_PER_SECOND) 41 + #define TOTAL_DATA_PER_SECOND (AGGREGATE_DATA_RATE_PER_SECOND*GENERATOR_WORKQUEUE_COUNT) 42 + #define TOTAL_TICKS_TO_RUN (SECONDS_TO_RUN * EVENT_GENERATION_FREQUENCY) 43 + 44 + #define NANOSECONDS_PER_SECOND 1000000000 45 + #define DISTRIBUTION_BUCKETS 20 // 1us per bucket 46 + #define EVENT_TIME_SLICE (NANOSECONDS_PER_SECOND / EVENT_GENERATION_FREQUENCY) 47 + #define SYSTEM_CLOCK_RESOLUTION 100 48 + 49 + #ifdef _WIN32 50 + typedef unsigned long long mytime_t; 51 + #else 52 + typedef unsigned long mytime_t; 53 + #endif 54 + 55 + struct wq_event 56 + { 57 + unsigned int queue_index; 58 + mytime_t start_time; 59 + }; 60 + 61 + struct wq_statistics 62 + { 63 + mytime_t min; 64 + mytime_t max; 65 + double avg; 66 + mytime_t total; 67 + unsigned int count; 68 + unsigned int count_over_threshold; 69 + unsigned int distribution[DISTRIBUTION_BUCKETS]; 70 + }; 71 + 72 + // We create our own separate workqueues for event generation 73 + struct wq_event_generator 74 + { 75 + pthread_workqueue_t wq; 76 + struct wq_event *wq_events; 77 + }; 78 + 79 + #ifdef __sun 80 + # include <atomic.h> 81 + # define atomic_inc atomic_inc_32 82 + # define atomic_dec atomic_dec_32 83 + # define atomic_inc_nv atomic_inc_32_nv 84 + # define atomic_dec_nv atomic_dec_32_nv 85 + #elif defined(_WIN32) 86 + # define atomic_inc(p) (void) InterlockedIncrement((p)) 87 + # define atomic_dec(p) (void) InterlockedDecrement((p)) 88 + # define atomic_inc_nv(p) InterlockedIncrement((p)) 89 + # define atomic_dec_nv(p) InterlockedDecrement((p)) 90 + #else 91 + # define atomic_inc(p) (void) __sync_add_and_fetch((p), 1) 92 + # define atomic_dec(p) (void) __sync_sub_and_fetch((p), 1) 93 + # define atomic_inc_nv(p) __sync_add_and_fetch((p), 1) 94 + # define atomic_dec_nv(p) __sync_sub_and_fetch((p), 1) 95 + #endif
+10
external/libpthread_workqueue-0.8.2/testing/libdispatch/Makefile
··· 1 + CC=clang 2 + 3 + dispatch_api: 4 + $(CC) -o dispatch_api dispatch_api.c -lpthread -lrt -ldispatch -lBlocksRuntime -lkqueue -lpthread_workqueue 5 + 6 + check: dispatch_api 7 + ./dispatch_api 8 + 9 + clean: 10 + rm -f dispatch_api
+40
external/libpthread_workqueue-0.8.2/testing/libdispatch/dispatch_api.c
··· 1 + /* 2 + * Copyright (c) 2011 Mark Heily. 3 + * Copyright (c) 2008-2009 Apple Inc. All rights reserved. 4 + * 5 + * @APPLE_APACHE_LICENSE_HEADER_START@ 6 + * 7 + * Licensed under the Apache License, Version 2.0 (the "License"); 8 + * you may not use this file except in compliance with the License. 9 + * You may obtain a copy of the License at 10 + * 11 + * http://www.apache.org/licenses/LICENSE-2.0 12 + * 13 + * Unless required by applicable law or agreed to in writing, software 14 + * distributed under the License is distributed on an "AS IS" BASIS, 15 + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 + * See the License for the specific language governing permissions and 17 + * limitations under the License. 18 + * 19 + * @APPLE_APACHE_LICENSE_HEADER_END@ 20 + */ 21 + 22 + #include <stdio.h> 23 + #include <stdlib.h> 24 + #include <unistd.h> 25 + 26 + #include <dispatch/dispatch.h> 27 + 28 + void 29 + work(void *context __attribute__((unused))) 30 + { 31 + puts("work complete"); 32 + exit(0); 33 + } 34 + 35 + int main(void) { 36 + dispatch_queue_t q = dispatch_get_main_queue(); 37 + dispatch_sync_f(dispatch_get_main_queue(), NULL, work); 38 + dispatch_main(); 39 + return 0; 40 + }
+37
external/libpthread_workqueue-0.8.2/testing/witem_cache/Makefile
··· 1 + # 2 + # Copyright (c) 2011 Mark Heily <mark@heily.com> 3 + # 4 + # Permission to use, copy, modify, and distribute this software for any 5 + # purpose with or without fee is hereby granted, provided that the above 6 + # copyright notice and this permission notice appear in all copies. 7 + # 8 + # THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 9 + # WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 10 + # MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 11 + # ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 12 + # WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 13 + # ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 14 + # OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 15 + # 16 + 17 + .PHONY :: install uninstall check dist dist-upload publish-www clean merge distclean fresh-build rpm edit cscope valgrind 18 + 19 + include ../../config.mk 20 + 21 + all: test-$(PROGRAM) 22 + 23 + test-$(PROGRAM): test.c 24 + $(CC) $(CFLAGS) -g -O0 -o test-$(PROGRAM) -I../.. -I../../include -L../.. test.c -lpthread_workqueue -lpthread -lrt 25 + 26 + check: test-$(PROGRAM) 27 + LD_LIBRARY_PATH=../..:/usr/sfw/lib/amd64 ./test-$(PROGRAM) 28 + 29 + debug: test-$(PROGRAM) 30 + LD_LIBRARY_PATH=../.. gdb ./test-$(PROGRAM) 31 + 32 + valgrind: test-$(PROGRAM) 33 + LD_LIBRARY_PATH=../..:/usr/sfw/lib/amd64 \ 34 + valgrind --tool=memcheck --leak-check=full --show-reachable=yes --num-callers=20 --track-fds=yes ./test-$(PROGRAM) 35 + 36 + clean: 37 + rm -f test-$(PROGRAM)
+85
external/libpthread_workqueue-0.8.2/testing/witem_cache/test.c
··· 1 + /*- 2 + * Copyright (c) 2011, Mark Heily <mark@heily.com> 3 + * All rights reserved. 4 + * 5 + * Redistribution and use in source and binary forms, with or without 6 + * modification, are permitted provided that the following conditions 7 + * are met: 8 + * 1. Redistributions of source code must retain the above copyright 9 + * notice unmodified, this list of conditions, and the following 10 + * disclaimer. 11 + * 2. Redistributions in binary form must reproduce the above copyright 12 + * notice, this list of conditions and the following disclaimer in the 13 + * documentation and/or other materials provided with the distribution. 14 + * 15 + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 16 + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 17 + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 18 + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 19 + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 20 + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 21 + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 22 + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 23 + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 24 + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25 + * 26 + */ 27 + 28 + #include <limits.h> 29 + #include <stdlib.h> 30 + #include <stdio.h> 31 + #include <string.h> 32 + #include <unistd.h> 33 + 34 + #include <time.h> 35 + 36 + #include "config.h" 37 + #include "src/private.h" 38 + 39 + #if HAVE_ERR_H 40 + # include <err.h> 41 + #else 42 + # define err(rc,msg,...) do { perror(msg); exit(rc); } while (0) 43 + # define errx(rc,msg,...) do { puts(msg); exit(rc); } while (0) 44 + #endif 45 + 46 + #include "pthread_workqueue.h" 47 + 48 + pthread_workqueue_t wq; 49 + 50 + void additem(void (*func)(void *), 51 + void * arg) 52 + { 53 + int rv; 54 + 55 + rv = pthread_workqueue_additem_np(wq, *func, arg, NULL, NULL); 56 + if (rv != 0) 57 + errx(1, "unable to add item: %s", strerror(rv)); 58 + } 59 + 60 + 61 + void 62 + feedback(void *arg) 63 + { 64 + int *i = (int *) arg; 65 + struct timespec tv; 66 + 67 + (*i)--; 68 + if ((*i) <= 0) { 69 + puts("All tests completed.\n"); 70 + exit(0); 71 + } else { 72 + additem(feedback, arg); 73 + tv.tv_sec = 0; 74 + tv.tv_nsec = 750; 75 + nanosleep(&tv, NULL); 76 + } 77 + } 78 + 79 + int main() { 80 + int i = 10000; 81 + 82 + pthread_workqueue_create_np(&wq, NULL); 83 + additem(feedback, &i); 84 + pause(); 85 + }