├── bench-sbcelt ├── common.h ├── test.dat ├── Makefile └── bench.c ├── AUTHORS ├── test ├── pdeath │ ├── clean.bash │ ├── run.bash │ └── pdeath_test.c ├── alloc-ctor │ ├── clean.bash │ ├── alloc_ctor.c │ └── run.bash ├── pdeath-racy │ ├── clean.bash │ ├── run.bash │ └── pdeath_racy.c ├── alloc-exhaust │ ├── clean.bash │ ├── run.bash │ └── alloc_exhaust.c ├── futex-timeout │ ├── clean.bash │ ├── run.bash │ └── futex_timeout.c ├── pdeath-racy2 │ ├── clean.bash │ ├── run.bash │ └── pdeath_racy2.c ├── alloc-arena-alignment │ ├── clean.bash │ ├── run.bash │ └── alloc_align.c ├── alloc-ensure-align8 │ ├── clean.bash │ ├── run.bash │ └── alloc_align8.c ├── futex-expected-value │ ├── clean.bash │ ├── futex_test.c │ └── run.bash ├── clean.bash ├── RUN └── run.bash ├── bench ├── clean.bash ├── run.bash └── crunch.py ├── bench-celt ├── test.dat ├── common.h ├── gentest.c ├── Makefile └── bench.c ├── .gitmodules ├── .gitignore ├── helper ├── pdeath.h ├── sbcelt-sandbox.h ├── pdeath-linux.c ├── sbcelt-sandbox-linux.c ├── sbcelt-sandbox-darwin.c ├── sbcelt-sandbox-freebsd.c ├── Makefile ├── seccomp-sandbox.c ├── alloc.c ├── pdeath-kqueue.c ├── seccomp-sandbox.h ├── sbcelt-helper.c └── config.h ├── lib ├── closefrom-sys.c ├── closefrom.h ├── mtime.h ├── futex.h ├── futex-stub.c ├── Makefile ├── debug.h ├── mtime.c ├── eintr.h ├── futex-linux.c ├── futex-freebsd.c ├── stub.c ├── closefrom.c └── libsbcelt.c ├── Make.conf ├── Makefile ├── INSTALL ├── Make.lib ├── Make.cmd ├── LICENSE ├── sbcelt-internal.h └── sbcelt.h /bench-sbcelt/common.h: -------------------------------------------------------------------------------- 1 | ../bench-celt/common.h -------------------------------------------------------------------------------- /bench-sbcelt/test.dat: -------------------------------------------------------------------------------- 1 | ../bench-celt/test.dat -------------------------------------------------------------------------------- /AUTHORS: -------------------------------------------------------------------------------- 1 | Mikkel Krautz 2 | -------------------------------------------------------------------------------- /test/pdeath/clean.bash: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | rm -f _test _test.core 4 | -------------------------------------------------------------------------------- /test/alloc-ctor/clean.bash: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | rm -f _test _test.core 4 | -------------------------------------------------------------------------------- /test/pdeath-racy/clean.bash: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | rm -f _test _test.core 4 | -------------------------------------------------------------------------------- /bench/clean.bash: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | rm -rf results 4 | rm -rf test.dat 5 | -------------------------------------------------------------------------------- /test/alloc-exhaust/clean.bash: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | rm -f _test _test.core 4 | -------------------------------------------------------------------------------- /test/futex-timeout/clean.bash: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | rm -f _test _test.core 4 | -------------------------------------------------------------------------------- /test/pdeath-racy2/clean.bash: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | rm -f _test _test.core 4 | -------------------------------------------------------------------------------- /test/alloc-arena-alignment/clean.bash: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | rm -f _test _test.core 4 | -------------------------------------------------------------------------------- /test/alloc-ensure-align8/clean.bash: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | rm -f _test _test.core 4 | -------------------------------------------------------------------------------- /test/futex-expected-value/clean.bash: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | rm -f _test _test.core 4 | -------------------------------------------------------------------------------- /bench-celt/test.dat: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mumble-voip/sbcelt/master/bench-celt/test.dat -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "celt-0.7.0"] 2 | path = celt-0.7.0 3 | url = https://git.xiph.org/celt.git/ 4 | -------------------------------------------------------------------------------- /test/clean.bash: -------------------------------------------------------------------------------- 1 | RUN_TESTS=$(cat RUN | grep -v "^#") 2 | 3 | for dir in ${RUN_TESTS}; do 4 | cd ${dir} 5 | ./clean.bash 6 | cd .. 7 | done 8 | -------------------------------------------------------------------------------- /bench-celt/common.h: -------------------------------------------------------------------------------- 1 | #ifndef _COMMON_H_ 2 | #define _COMMON_H_ 3 | 4 | #define SAMPLE_RATE 48000 5 | #define FRAME_SIZE (SAMPLE_RATE/100) 6 | 7 | #endif 8 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | helper/sbcelt-helper 2 | lib/libsbcelt.a 3 | *.o 4 | bench-celt/celt-bench 5 | bench-sbcelt/sbcelt-bench 6 | bench/results 7 | bench/test.dat 8 | _test 9 | -------------------------------------------------------------------------------- /test/alloc-ctor/alloc_ctor.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | int main(int argc, char *argv[]) { 5 | (void) malloc(10); 6 | return 0; 7 | } 8 | -------------------------------------------------------------------------------- /test/alloc-ctor/run.bash: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | rm -f _test 4 | cc ../../helper/alloc.c alloc_ctor.c -o _test 5 | ./_test 6 | if [ $? -eq 0 ] 7 | then 8 | exit 0 9 | else 10 | exit 1 11 | fi 12 | -------------------------------------------------------------------------------- /test/alloc-exhaust/run.bash: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | rm -f _test 4 | cc ../../helper/alloc.c alloc_exhaust.c -o _test 5 | ./_test 6 | if [ $? -eq 50 ] 7 | then 8 | exit 0 9 | else 10 | exit 1 11 | fi 12 | -------------------------------------------------------------------------------- /test/alloc-arena-alignment/run.bash: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | rm -f _test 4 | cc ../../helper/alloc.c alloc_align.c -o _test 5 | ./_test 6 | if [ $? -eq 0 ] 7 | then 8 | exit 0 9 | else 10 | exit 1 11 | fi 12 | -------------------------------------------------------------------------------- /test/alloc-ensure-align8/run.bash: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | rm -f _test 4 | cc ../../helper/alloc.c alloc_align8.c -o _test 5 | ./_test 6 | if [ $? -eq 0 ] 7 | then 8 | exit 0 9 | else 10 | exit 1 11 | fi 12 | -------------------------------------------------------------------------------- /test/RUN: -------------------------------------------------------------------------------- 1 | # This is a list of all tests to run 2 | 3 | futex-expected-value 4 | futex-timeout 5 | alloc-ensure-align8 6 | alloc-exhaust 7 | alloc-arena-alignment 8 | alloc-ctor 9 | pdeath 10 | pdeath-racy 11 | pdeath-racy2 12 | -------------------------------------------------------------------------------- /helper/pdeath.h: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2012 The SBCELT Developers. All rights reserved. 2 | // Use of this source code is governed by a BSD-style license 3 | // that can be found in the LICENSE-file. 4 | 5 | #ifndef __PDEATH_H__ 6 | #define __PDEATH_H__ 7 | 8 | int pdeath(); 9 | 10 | #endif 11 | -------------------------------------------------------------------------------- /lib/closefrom-sys.c: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2012 The SBCELT Developers. All rights reserved. 2 | // Use of this source code is governed by a BSD-style license 3 | // that can be found in the LICENSE-file. 4 | 5 | #include 6 | 7 | void xclosefrom(int lowfd) { 8 | closefrom(lowfd); 9 | } 10 | -------------------------------------------------------------------------------- /lib/closefrom.h: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2012 The SBCELT Developers. All rights reserved. 2 | // Use of this source code is governed by a BSD-style license 3 | // that can be found in the LICENSE-file. 4 | 5 | #ifndef __CLOSEFROM_H__ 6 | #define __CLOSEFROM_H__ 7 | 8 | void xclosefrom(int lowfd); 9 | 10 | #endif 11 | -------------------------------------------------------------------------------- /bench-sbcelt/Makefile: -------------------------------------------------------------------------------- 1 | include ../Make.conf 2 | 3 | CFLAGS = -O2 -I../celt-0.7.0/libcelt/ -I.. 4 | LDFLAGS = ../lib/libsbcelt.a -lm -lpthread 5 | 6 | ifeq ($(shell uname -s),Linux) 7 | LDFLAGS += -lrt 8 | endif 9 | 10 | TARGET = sbcelt-bench 11 | 12 | SOURCES = \ 13 | bench.c 14 | 15 | include ../Make.cmd 16 | -------------------------------------------------------------------------------- /helper/sbcelt-sandbox.h: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2012 The SBCELT Developers. All rights reserved. 2 | // Use of this source code is governed by a BSD-style license 3 | // that can be found in the LICENSE-file. 4 | 5 | #ifndef __SBCELT_SANDBOX_H__ 6 | #define __SBCELT_SANDBOX_H__ 7 | 8 | int SBCELT_EnterSandbox(int mode); 9 | 10 | #endif 11 | -------------------------------------------------------------------------------- /test/futex-expected-value/futex_test.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include "futex.h" 4 | 5 | int main(int argc, char *argv[]) { 6 | int ftx = 0; 7 | int err = futex_wait(&ftx, 1, NULL); 8 | if (err != 0) { 9 | fprintf(stderr, "expected 0 return value, got %i\n", err); 10 | return 1; 11 | } 12 | return 0; 13 | } 14 | -------------------------------------------------------------------------------- /lib/mtime.h: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2012 The SBCELT Developers. All rights reserved. 2 | // Use of this source code is governed by a BSD-style license 3 | // that can be found in the LICENSE-file. 4 | 5 | #ifndef __MTIME_H__ 6 | #define __MTIME_H__ 7 | 8 | #define USEC_PER_SEC 1000000 9 | #define NSEC_PER_USEC 1000 10 | 11 | uint64_t mtime(); 12 | 13 | #endif 14 | 15 | -------------------------------------------------------------------------------- /test/futex-expected-value/run.bash: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | UNAME=$(uname -s | tr [:upper:] [:lower:]) 4 | case "${UNAME}" in 5 | "linux") ;; 6 | "freebsd") ;; 7 | *) exit 2 ;; 8 | esac 9 | 10 | rm -f _test 11 | cc -I ../../lib futex_test.c ../../lib/futex-${UNAME}.c -o _test 12 | ./_test 13 | if [ $? -eq 0 ] 14 | then 15 | exit 0 16 | else 17 | exit 1 18 | fi 19 | -------------------------------------------------------------------------------- /test/futex-timeout/run.bash: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | UNAME=$(uname -s | tr [:upper:] [:lower:]) 4 | case "${UNAME}" in 5 | "linux") ;; 6 | "freebsd") ;; 7 | *) exit 2 ;; 8 | esac 9 | 10 | rm -f _test 11 | cc -I ../../lib futex_timeout.c ../../lib/futex-${UNAME}.c ../../lib/mtime.c -lpthread -o _test 12 | ./_test 13 | if [ $? -eq 0 ] 14 | then 15 | exit 0 16 | else 17 | exit 1 18 | fi 19 | -------------------------------------------------------------------------------- /test/alloc-arena-alignment/alloc_align.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | int main(int argc, char *argv[]) { 6 | uintptr_t addr = (uintptr_t) malloc(10); 7 | // compensate for size_t 8 | addr -= sizeof(size_t); 9 | if ((addr % 4096) != 0) { 10 | fprintf(stderr, "expected 4k alignment for first allocation; got addr=%p\n", (void *)addr); 11 | return 1; 12 | } 13 | return 0; 14 | } 15 | -------------------------------------------------------------------------------- /Make.conf: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2012 The SBCELT Developers. All rights reserved. 2 | # Use of this source code is governed by a BSD-style license 3 | # that can be found in the LICENSE-file. 4 | 5 | ifeq ($(shell uname -s),Darwin) 6 | CC = clang 7 | else 8 | CC = gcc 9 | endif 10 | LD = $(CC) 11 | AR = ar 12 | 13 | ifeq ($(shell uname -s),FreeBSD) 14 | MAKE = gmake 15 | else 16 | MAKE = make 17 | endif 18 | 19 | DEBUG=0 20 | PREFIX=1 21 | -------------------------------------------------------------------------------- /test/alloc-ensure-align8/alloc_align8.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | int main(int argc, char *argv[]) { 6 | size_t i; 7 | for (i = 0; i < 200; i++) { 8 | uintptr_t addr = (uintptr_t) malloc(i); 9 | if ((addr % 8) != 0) { 10 | fprintf(stderr, "allocation of size %lu not 8-byte aligned: %p\n", (unsigned long)i, (void *)addr); 11 | return 1; 12 | } 13 | } 14 | return 0; 15 | } 16 | -------------------------------------------------------------------------------- /lib/futex.h: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2012 The SBCELT Developers. All rights reserved. 2 | // Use of this source code is governed by a BSD-style license 3 | // that can be found in the LICENSE-file. 4 | 5 | #ifndef __FUTEX_H__ 6 | #define __FUTEX_H__ 7 | 8 | #define FUTEX_TIMEDOUT -2 9 | #define FUTEX_INTERRUPTED -3 10 | 11 | int futex_available(); 12 | int futex_wake(int *futex); 13 | int futex_wait(int *futex, int val, struct timespec *ts); 14 | 15 | #endif 16 | -------------------------------------------------------------------------------- /lib/futex-stub.c: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2012 The SBCELT Developers. All rights reserved. 2 | // Use of this source code is governed by a BSD-style license 3 | // that can be found in the LICENSE-file. 4 | 5 | #include 6 | 7 | #include "futex.h" 8 | 9 | int futex_available() { 10 | return 0; 11 | } 12 | 13 | int futex_wake(int *futex) { 14 | return -1; 15 | } 16 | 17 | int futex_wait(int *futex, int val, struct timespec *ts) { 18 | return -1; 19 | } 20 | -------------------------------------------------------------------------------- /test/alloc-exhaust/alloc_exhaust.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | int main(int argc, char *argv[]) { 5 | size_t i; 6 | 7 | // Try to allocate 10 chunks of 1MB each. 8 | // The current allocator is limited to 8MB per launch, 9 | // and kills itself if its allocation arena is exhausted. 10 | for (i = 0; i < 10; i++) { 11 | size_t chunk = 1024*1024; // 1MB 12 | uintptr_t val = (uintptr_t) malloc(chunk); 13 | (void) val; 14 | } 15 | 16 | return 0; 17 | } 18 | -------------------------------------------------------------------------------- /helper/pdeath-linux.c: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2012 The SBCELT Developers. All rights reserved. 2 | // Use of this source code is governed by a BSD-style license 3 | // that can be found in the LICENSE-file. 4 | 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | 11 | int pdeath() { 12 | if (prctl(PR_SET_PDEATHSIG, SIGKILL) == -1) 13 | return -1; 14 | if (getppid() <= 1) 15 | _exit(0); 16 | 17 | return 0; 18 | } 19 | -------------------------------------------------------------------------------- /lib/Makefile: -------------------------------------------------------------------------------- 1 | TARGET = libsbcelt.a 2 | 3 | CFLAGS = -O2 -I../celt-0.7.0/libcelt/ -DSBCELT_PREFIX 4 | 5 | SOURCES = \ 6 | libsbcelt.c \ 7 | mtime.c \ 8 | stub.c 9 | 10 | ifeq ($(shell uname -s),Linux) 11 | SOURCES += \ 12 | futex-linux.c \ 13 | closefrom.c 14 | endif 15 | 16 | ifeq ($(shell uname -s),Darwin) 17 | SOURCES += \ 18 | futex-stub.c \ 19 | closefrom.c 20 | endif 21 | 22 | ifeq ($(shell uname -s),FreeBSD) 23 | SOURCES += \ 24 | futex-freebsd.c \ 25 | closefrom-sys.c 26 | endif 27 | 28 | include ../Make.lib 29 | -------------------------------------------------------------------------------- /test/pdeath/run.bash: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | UNAME=$(uname -s | tr [:upper:] [:lower:]) 4 | case "${UNAME}" in 5 | "linux") KIND="linux" ;; 6 | "freebsd") KIND="kqueue" ;; 7 | "darwin") KIND="kqueue" ;; 8 | *) exit 2 ;; 9 | esac 10 | 11 | rm -f _test 12 | cc -I ../../helper -I ../../lib ../../helper/pdeath-${KIND}.c pdeath_test.c -lpthread -o _test 13 | childpid=$(./_test) 14 | sleep 1 15 | /bin/kill -0 ${childpid} 2>/dev/null 16 | 17 | if [ $? -eq 0 ] 18 | then 19 | /bin/kill -9 ${childpid} 2>/dev/null 20 | exit 1 21 | else 22 | exit 0 23 | fi 24 | -------------------------------------------------------------------------------- /test/run.bash: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | RUN_TESTS=$(cat RUN | grep -v "^#") 4 | declare -i OK=0 5 | declare -i FAIL=0 6 | declare -i SKIP=0 7 | 8 | for dir in ${RUN_TESTS}; do 9 | cd ${dir} 10 | echo -n "${dir}: " 11 | ./run.bash 12 | ret=$? 13 | if [ $ret -eq 0 ]; then 14 | echo 'ok' 15 | OK=OK+1 16 | fi 17 | if [ $ret -eq 1 ]; then 18 | echo 'fail' 19 | FAIL=FAIL+1 20 | fi 21 | if [ $ret -eq 2 ]; then 22 | echo 'skip' 23 | SKIP=SKIP+1 24 | fi 25 | cd .. 26 | done 27 | 28 | echo "" 29 | echo "${OK} ok, ${FAIL} failed, ${SKIP} skipped" 30 | -------------------------------------------------------------------------------- /test/pdeath-racy/run.bash: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | UNAME=$(uname -s | tr [:upper:] [:lower:]) 4 | case "${UNAME}" in 5 | "linux") KIND="linux" ;; 6 | "freebsd") KIND="kqueue" ;; 7 | "darwin") KIND="kqueue" ;; 8 | *) exit 2 ;; 9 | esac 10 | 11 | rm -f _test 12 | cc -I ../../helper -I ../../lib ../../helper/pdeath-${KIND}.c pdeath_racy.c -lpthread -o _test 13 | childpid=$(./_test) 14 | sleep 1 15 | /bin/kill -0 ${childpid} 2>/dev/null 16 | 17 | if [ $? -eq 0 ] 18 | then 19 | /bin/kill -9 ${childpid} 2>/dev/null 20 | exit 1 21 | else 22 | exit 0 23 | fi 24 | -------------------------------------------------------------------------------- /test/pdeath-racy2/run.bash: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | UNAME=$(uname -s | tr [:upper:] [:lower:]) 4 | case "${UNAME}" in 5 | "linux") KIND="linux" ;; 6 | "freebsd") KIND="kqueue" ;; 7 | "darwin") KIND="kqueue" ;; 8 | *) exit 2 ;; 9 | esac 10 | 11 | rm -f _test 12 | cc -I ../../helper -I ../../lib ../../helper/pdeath-${KIND}.c pdeath_racy2.c -lpthread -o _test 13 | childpid=$(./_test) 14 | sleep 1 15 | /bin/kill -0 ${childpid} 2>/dev/null 16 | 17 | if [ $? -eq 0 ] 18 | then 19 | /bin/kill -9 ${childpid} 2>/dev/null 20 | exit 1 21 | else 22 | exit 0 23 | fi 24 | -------------------------------------------------------------------------------- /lib/debug.h: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2012 The SBCELT Developers. All rights reserved. 2 | // Use of this source code is governed by a BSD-style license 3 | // that can be found in the LICENSE-file. 4 | 5 | #ifndef __DEBUG_H__ 6 | #define __DEBUG_H__ 7 | 8 | #ifdef DEBUG 9 | # define debugf(fmt, ...) \ 10 | do { \ 11 | fprintf(stderr, "libsbcelt:%s():%u: " fmt "\n", \ 12 | __FUNCTION__, __LINE__, ## __VA_ARGS__); \ 13 | fflush(stderr); \ 14 | } while (0) 15 | #else 16 | # define debugf(s, ...) do{} while (0) 17 | #endif 18 | 19 | #endif 20 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2012 The SBCELT Developers. All rights reserved. 2 | # Use of this source code is governed by a BSD-style license 3 | # that can be found in the LICENSE-file. 4 | 5 | include Make.conf 6 | 7 | .PHONY: default 8 | default: 9 | $(MAKE) -C lib 10 | $(MAKE) -C helper 11 | $(MAKE) -C bench-celt 12 | $(MAKE) -C bench-sbcelt 13 | 14 | .PHONY: clean 15 | clean: 16 | $(MAKE) -C lib clean 17 | $(MAKE) -C helper clean 18 | $(MAKE) -C bench-celt clean 19 | $(MAKE) -C bench-sbcelt clean 20 | @cd test && ./clean.bash 21 | 22 | .PHONY: test 23 | test: 24 | @cd test && ./run.bash 25 | 26 | -------------------------------------------------------------------------------- /lib/mtime.c: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2012 The SBCELT Developers. All rights reserved. 2 | // Use of this source code is governed by a BSD-style license 3 | // that can be found in the LICENSE-file. 4 | 5 | #include 6 | #include 7 | #include 8 | 9 | #include "mtime.h" 10 | 11 | // The expectation is that gettimeofday() uses 12 | // the VDSO and/or the TSC (on modern x86) to 13 | // avoid system calls. 14 | uint64_t mtime() { 15 | struct timeval tv; 16 | if (gettimeofday(&tv, NULL) == -1) { 17 | return 0; 18 | } 19 | return ((uint64_t)tv.tv_sec * USEC_PER_SEC) + (uint64_t)tv.tv_usec; 20 | } 21 | 22 | -------------------------------------------------------------------------------- /bench/run.bash: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | rm -rf results 4 | mkdir -p results 5 | 6 | export SBCELT_HELPER_BINARY=`pwd`/../helper/sbcelt-helper 7 | 8 | cp ../bench-celt/test.dat . 9 | 10 | # celt lib 11 | for i in {0..9} 12 | do 13 | ../bench-celt/celt-bench > results/celt.${i} 14 | done 15 | 16 | # sbcelt lib (futex mode) 17 | for i in {0..9} 18 | do 19 | ../bench-sbcelt/sbcelt-bench > results/sbcelt-futex.${i} 20 | done 21 | 22 | # sbcelt lib (rw mode) 23 | export SBCELT_PREFER_SECCOMP_STRICT=1 24 | for i in {0..9} 25 | do 26 | ../bench-sbcelt/sbcelt-bench > results/sbcelt-rw.${i} 27 | done 28 | unset SBCELT_PREFER_SECCOMP_STRICT 29 | 30 | ./crunch.py 31 | -------------------------------------------------------------------------------- /helper/sbcelt-sandbox-linux.c: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2012 The SBCELT Developers. All rights reserved. 2 | // Use of this source code is governed by a BSD-style license 3 | // that can be found in the LICENSE-file. 4 | 5 | #include "sbcelt-sandbox.h" 6 | #include "sbcelt-internal.h" 7 | #include "seccomp-sandbox.h" 8 | 9 | // Attempt to enter the specified sandbox mode. 10 | int SBCELT_EnterSandbox(int mode) { 11 | switch (mode) { 12 | case SBCELT_SANDBOX_NONE: 13 | return 0; 14 | case SBCELT_SANDBOX_SECCOMP_STRICT: 15 | return seccomp_sandbox_strict_init(); 16 | case SBCELT_SANDBOX_SECCOMP_BPF: 17 | return seccomp_sandbox_filter_init(); 18 | } 19 | return -1; 20 | } 21 | -------------------------------------------------------------------------------- /lib/eintr.h: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2012 The Chromium Authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style license that can be 3 | // found in the LICENSE file. 4 | 5 | // This provides a wrapper around system calls which may be interrupted by a 6 | // signal and return EINTR. See man 7 signal. 7 | 8 | #ifndef BASE_EINTR_WRAPPER_H_ 9 | #define BASE_EINTR_WRAPPER_H_ 10 | 11 | #include 12 | 13 | #define HANDLE_EINTR(x) ({ \ 14 | typeof(x) __eintr_result__; \ 15 | do { \ 16 | __eintr_result__ = (x); \ 17 | } while (__eintr_result__ == -1 && errno == EINTR); \ 18 | __eintr_result__;\ 19 | }) 20 | 21 | #endif // BASE_EINTR_WRAPPER_H_ 22 | -------------------------------------------------------------------------------- /bench-celt/gentest.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | #include 9 | #include "common.h" 10 | 11 | int gentest(unsigned char *buf, int n) { 12 | float pcm[FRAME_SIZE]; 13 | int i; 14 | 15 | for (i = 0; i < FRAME_SIZE; i++) { 16 | pcm[i] = sinf(1000.0f * M_PI_2 * i / SAMPLE_RATE); 17 | } 18 | 19 | CELTMode *m = celt_mode_create(SAMPLE_RATE, FRAME_SIZE, NULL); 20 | CELTEncoder *e = celt_encoder_create(m, 1, NULL); 21 | 22 | if (celt_encode_float(e, pcm, NULL, buf, n) != n) { 23 | return -1; 24 | } 25 | 26 | return 0; 27 | } 28 | -------------------------------------------------------------------------------- /INSTALL: -------------------------------------------------------------------------------- 1 | To install SBCELT, simply run 2 | 3 | $ make # or 'gmake' on FreeBSD to invoke GNU make 4 | 5 | in this directory. If the build succeeds, there should be 6 | a 'libsbcelt.a' file in the lib directory, and a 'sbcelt-helper' 7 | in the helper directory. Beside these two files, the only other 8 | file needed to make use of SBCELT is the 'sbcelt.h' header which 9 | lives in the root of the source tree. 10 | 11 | Proper locations for these files depend on the environment 12 | that the library is intended to run within. Currently, 13 | SBCELT is mostly meant to be embedded into other applications, 14 | and ass such, the only sane default is to delegate the 15 | installation process to the program embedding SBCELT. 16 | -------------------------------------------------------------------------------- /Make.lib: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2012 The SBCELT Developers. All rights reserved. 2 | # Use of this source code is governed by a BSD-style license 3 | # that can be found in the LICENSE-file. 4 | 5 | include ../Make.conf 6 | 7 | ASMOBJS=$(SOURCES:.S=.S.o) 8 | OBJECTS=$(ASMOBJS:.c=.c.o) 9 | 10 | ifeq ($(DEBUG),1) 11 | CFLAGS += -DDEBUG 12 | endif 13 | 14 | ifeq ($(PREFIX),1) 15 | CFLAGS += -DSBCELT_PREFIX_API 16 | endif 17 | 18 | %.S.o: %.S 19 | @echo "ASM $*.S" 20 | @$(CC) $(CFLAGS) -D__ASM__ -c $*.S -o $*.S.o 21 | 22 | %.c.o: %.c 23 | @echo "CC $*.c" 24 | @$(CC) $(CFLAGS) -c $*.c -o $*.c.o 25 | 26 | $(TARGET): $(OBJECTS) 27 | @echo "AR ${TARGET}" 28 | @$(AR) rcs $(TARGET) $(OBJECTS) 29 | 30 | clean: 31 | @rm -f $(TARGET) $(OBJECTS) 32 | -------------------------------------------------------------------------------- /bench-celt/Makefile: -------------------------------------------------------------------------------- 1 | include ../Make.conf 2 | 3 | CFLAGS = -O2 -DHAVE_CONFIG_H -I. -I../celt-0.7.0/libcelt/ -I../helper 4 | LDFLAGS = -lm 5 | 6 | CELT = ../celt-0.7.0/libcelt 7 | TARGET = celt-bench 8 | 9 | SOURCES = \ 10 | $(CELT)/bands.c \ 11 | $(CELT)/celt.c \ 12 | $(CELT)/cwrs.c \ 13 | $(CELT)/entcode.c \ 14 | $(CELT)/entdec.c \ 15 | $(CELT)/entenc.c \ 16 | $(CELT)/header.c \ 17 | $(CELT)/kiss_fft.c \ 18 | $(CELT)/kiss_fftr.c \ 19 | $(CELT)/laplace.c \ 20 | $(CELT)/mdct.c \ 21 | $(CELT)/modes.c \ 22 | $(CELT)/pitch.c \ 23 | $(CELT)/psy.c \ 24 | $(CELT)/quant_bands.c \ 25 | $(CELT)/rangedec.c \ 26 | $(CELT)/rangeenc.c \ 27 | $(CELT)/rate.c \ 28 | $(CELT)/vq.c \ 29 | gentest.c \ 30 | bench.c 31 | 32 | include ../Make.cmd 33 | -------------------------------------------------------------------------------- /test/pdeath-racy/pdeath_racy.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | #include "pdeath.h" 7 | #include "mtime.h" 8 | #include "eintr.h" 9 | 10 | int main(int argc, char *argv[]) { 11 | pid_t pid = fork(); 12 | if (pid == 0) { 13 | // Close parent's fds. 14 | (void) HANDLE_EINTR(close(0)); 15 | (void) HANDLE_EINTR(close(1)); 16 | (void) HANDLE_EINTR(close(2)); 17 | 18 | // Don't check return value. 19 | // If pdeath fails it's hard to signal to the parent, 20 | // and exitting will signal that pdeath *worked*. 21 | pdeath(); 22 | while (1) { 23 | usleep(USEC_PER_SEC*1); 24 | } 25 | } else { 26 | printf("%lu\n", (unsigned long)pid); 27 | } 28 | return 0; 29 | } 30 | -------------------------------------------------------------------------------- /test/futex-timeout/futex_timeout.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | #include "futex.h" 8 | #include "mtime.h" 9 | 10 | static int ftx = 0; 11 | 12 | void *waiter(void *udata) { 13 | (void) udata; 14 | usleep(USEC_PER_SEC*5); 15 | } 16 | 17 | int main(int argc, char *argv[]) { 18 | pthread_t thr; 19 | if (pthread_create(&thr, NULL, waiter, NULL) == -1) { 20 | return 1; 21 | } 22 | 23 | uint64_t begin = mtime(); 24 | struct timespec ts = { 0, USEC_PER_SEC*2 }; 25 | int err = futex_wait(&ftx, 0, &ts); 26 | if (err != FUTEX_TIMEDOUT) { 27 | fprintf(stderr, "expected ETIMEDOUT return value, got %i\n", err); 28 | return 1; 29 | } 30 | 31 | return 0; 32 | } 33 | -------------------------------------------------------------------------------- /test/pdeath/pdeath_test.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | #include "pdeath.h" 7 | #include "mtime.h" 8 | #include "eintr.h" 9 | 10 | int main(int argc, char *argv[]) { 11 | pid_t pid = fork(); 12 | if (pid == 0) { 13 | // Close parent's fds. 14 | (void) HANDLE_EINTR(close(0)); 15 | (void) HANDLE_EINTR(close(1)); 16 | (void) HANDLE_EINTR(close(2)); 17 | 18 | // Don't check return value. 19 | // If pdeath fails it's hard to signal to the parent, 20 | // and exitting will signal that pdeath *worked*. 21 | pdeath(); 22 | while (1) { 23 | usleep(USEC_PER_SEC*1); 24 | } 25 | } else { 26 | usleep(USEC_PER_SEC*1); 27 | printf("%lu\n", (unsigned long)pid); 28 | } 29 | return 0; 30 | } 31 | -------------------------------------------------------------------------------- /test/pdeath-racy2/pdeath_racy2.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | #include "pdeath.h" 7 | #include "mtime.h" 8 | #include "eintr.h" 9 | 10 | int main(int argc, char *argv[]) { 11 | pid_t pid = fork(); 12 | if (pid == 0) { 13 | // Close parent's fds. 14 | (void) HANDLE_EINTR(close(0)); 15 | (void) HANDLE_EINTR(close(1)); 16 | (void) HANDLE_EINTR(close(2)); 17 | 18 | usleep(USEC_PER_SEC*1); 19 | 20 | // Don't check return value. 21 | // If pdeath fails it's hard to signal to the parent, 22 | // and exitting will signal that pdeath *worked*. 23 | pdeath(); 24 | while (1) { 25 | usleep(USEC_PER_SEC*1); 26 | } 27 | } else { 28 | printf("%lu\n", (unsigned long)pid); 29 | } 30 | return 0; 31 | } 32 | -------------------------------------------------------------------------------- /helper/sbcelt-sandbox-darwin.c: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2012 The SBCELT Developers. All rights reserved. 2 | // Use of this source code is governed by a BSD-style license 3 | // that can be found in the LICENSE-file. 4 | 5 | #include 6 | #include 7 | #include 8 | 9 | #include "debug.h" 10 | #include "sandbox.h" 11 | 12 | #include "sbcelt-internal.h" 13 | 14 | // Attempt to enter the specified sandbox mode. 15 | int SBCELT_EnterSandbox(int mode) { 16 | switch (mode) { 17 | case SBCELT_SANDBOX_NONE: 18 | // No sandbox was requsted. 19 | return 0; 20 | case SBCELT_SANDBOX_SEATBELT: { 21 | char *errbuf = NULL; 22 | int retval = sandbox_init(kSBXProfilePureComputation, SANDBOX_NAMED, &errbuf); 23 | if (retval == -1) { 24 | debugf("unable to init seatbelt: %s", errbuf); 25 | } 26 | return retval; 27 | } 28 | 29 | } 30 | return -1; 31 | } 32 | -------------------------------------------------------------------------------- /helper/sbcelt-sandbox-freebsd.c: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2012 The SBCELT Developers. All rights reserved. 2 | // Use of this source code is governed by a BSD-style license 3 | // that can be found in the LICENSE-file. 4 | 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | 11 | #include "debug.h" 12 | #include "sbcelt-sandbox.h" 13 | 14 | #include "sbcelt-internal.h" 15 | 16 | // Attempt to enter the specified sandbox mode. 17 | int SBCELT_EnterSandbox(int mode) { 18 | switch (mode) { 19 | case SBCELT_SANDBOX_NONE: 20 | // No sandbox was requsted. 21 | return 0; 22 | case SBCELT_SANDBOX_CAPSICUM: { 23 | int err = cap_enter(); 24 | if (err == -1) { 25 | fprintf(stderr, "unable to cap_enter(): %s (%i)\n", strerror(errno), errno); 26 | } 27 | return err; 28 | } 29 | } 30 | return -1; 31 | } 32 | -------------------------------------------------------------------------------- /Make.cmd: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2012 The SBCELT Developers. All rights reserved. 2 | # Use of this source code is governed by a BSD-style license 3 | # that can be found in the LICENSE-file. 4 | 5 | include ../Make.conf 6 | 7 | ORIGCFLAGS := $(CFLAGS) 8 | CFLAGS = -Wall -Os $(ORIGCFLAGS) 9 | 10 | ifeq ($(DEBUG),1) 11 | CFLAGS += -DDEBUG 12 | endif 13 | 14 | ifeq ($(PREFIX),1) 15 | CFLAGS += -DSBCELT_PREFIX_API 16 | endif 17 | 18 | ORIGLDFLAGS := $(LDFLAGS) 19 | LDFLAGS = $(ORIGLDFLAGS) 20 | 21 | ASMOBJS=$(SOURCES:.S=.S.o) 22 | OBJECTS=$(ASMOBJS:.c=.c.o) 23 | 24 | %.S.o: %.S 25 | @echo "ASM $*.S" 26 | @$(CC) $(CFLAGS) -D__ASM__ -c $*.S -o $*.S.o 27 | 28 | %.c.o: %.c 29 | @echo "CC $*.c" 30 | @$(CC) $(CFLAGS) -c $*.c -o $*.c.o 31 | 32 | $(TARGET): $(OBJECTS) 33 | @echo "LD ${TARGET}" 34 | @$(LD) $(OBJECTS) $(LDFLAGS) $(LIBS) -o $(TARGET) 35 | 36 | clean: 37 | @rm -f $(TARGET) $(TARGET).list $(OBJECTS) 38 | -------------------------------------------------------------------------------- /lib/futex-linux.c: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2012 The SBCELT Developers. All rights reserved. 2 | // Use of this source code is governed by a BSD-style license 3 | // that can be found in the LICENSE-file. 4 | 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | 11 | #include "futex.h" 12 | 13 | int futex_available() { 14 | return 1; 15 | } 16 | 17 | int futex_wake(int *futex) { 18 | return syscall(SYS_futex, futex, FUTEX_WAKE, 1, NULL, NULL, 0); 19 | } 20 | 21 | int futex_wait(int *futex, int val, struct timespec *ts) { 22 | int err = syscall(SYS_futex, futex, FUTEX_WAIT, val, ts, NULL, 0); 23 | if (err == -1) { 24 | if (errno == EWOULDBLOCK) { 25 | return 0; 26 | } else if (errno == ETIMEDOUT) { 27 | return FUTEX_TIMEDOUT; 28 | } else if (errno == EINTR) { 29 | return FUTEX_INTERRUPTED; 30 | } 31 | } 32 | return err; 33 | } 34 | -------------------------------------------------------------------------------- /lib/futex-freebsd.c: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2012 The SBCELT Developers. All rights reserved. 2 | // Use of this source code is governed by a BSD-style license 3 | // that can be found in the LICENSE-file. 4 | 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | 12 | #include "debug.h" 13 | #include "futex.h" 14 | 15 | int futex_available() { 16 | return 1; 17 | } 18 | 19 | int futex_wake(int *futex) { 20 | return _umtx_op(futex, UMTX_OP_WAKE, 1, 0, 0); 21 | } 22 | 23 | int futex_wait(int *futex, int val, struct timespec *ts) { 24 | int err = _umtx_op(futex, UMTX_OP_WAIT_UINT, val, 0, (void *)ts); 25 | if (err != 0) { 26 | if (errno == ETIMEDOUT) { 27 | return FUTEX_TIMEDOUT; 28 | } else if (errno == EINTR) { // XXX: unsure if umtx can be EINTR'd. 29 | return FUTEX_INTERRUPTED; 30 | } 31 | } 32 | return err; 33 | } 34 | -------------------------------------------------------------------------------- /bench/crunch.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | import sys 4 | import json 5 | try: 6 | from numpy import array 7 | except: 8 | print 'Stat crunching requires numpy - skipping.' 9 | sys.exit(0) 10 | 11 | def load_results(kind): 12 | results = [] 13 | for i in range(0, 10): 14 | f = open('results/%s.%i' % (kind, i), 'r') 15 | s = f.read() 16 | results.append(json.loads(s)['elapsed_usec']) 17 | return results 18 | 19 | if __name__ == '__main__': 20 | celt = array(load_results('celt')) 21 | sbcelt_futex = array(load_results('sbcelt-futex')) 22 | sbcelt_rw = array(load_results('sbcelt-rw')) 23 | 24 | print '# results (niter=10000)' 25 | print 'sbcelt-futex %.2f usec (%.2f stddev)' % (sbcelt_futex.mean(), sbcelt_futex.std()) 26 | print 'sbcelt-rw %.2f usec (%.2f stddev)' % (sbcelt_rw.mean(), sbcelt_rw.std()) 27 | print 'celt %.2f usec (%.2f stddev)' % (celt.mean(), celt.std()) 28 | print '' 29 | print 'sbcelt-futex delta: %.2f usec' % (celt.mean() - sbcelt_futex.mean()) 30 | print 'sbcelt-rw detlta: %.2f usec' % (celt.mean() - sbcelt_rw.mean()) 31 | -------------------------------------------------------------------------------- /helper/Makefile: -------------------------------------------------------------------------------- 1 | include ../Make.conf 2 | 3 | CFLAGS = -O2 -DHAVE_CONFIG_H -I. -I.. -I../lib -I../celt-0.7.0/libcelt/ 4 | LDFLAGS = -lm -lpthread 5 | 6 | CELT = ../celt-0.7.0/libcelt 7 | TARGET = sbcelt-helper 8 | 9 | SOURCES = \ 10 | $(CELT)/bands.c \ 11 | $(CELT)/celt.c \ 12 | $(CELT)/cwrs.c \ 13 | $(CELT)/entcode.c \ 14 | $(CELT)/entdec.c \ 15 | $(CELT)/entenc.c \ 16 | $(CELT)/header.c \ 17 | $(CELT)/kiss_fft.c \ 18 | $(CELT)/kiss_fftr.c \ 19 | $(CELT)/laplace.c \ 20 | $(CELT)/mdct.c \ 21 | $(CELT)/modes.c \ 22 | $(CELT)/pitch.c \ 23 | $(CELT)/psy.c \ 24 | $(CELT)/quant_bands.c \ 25 | $(CELT)/rangedec.c \ 26 | $(CELT)/rangeenc.c \ 27 | $(CELT)/rate.c \ 28 | $(CELT)/vq.c \ 29 | sbcelt-helper.c \ 30 | alloc.c 31 | 32 | ifeq ($(shell uname -s),Linux) 33 | SOURCES += \ 34 | ../lib/futex-linux.c \ 35 | seccomp-sandbox.c \ 36 | sbcelt-sandbox-linux.c \ 37 | pdeath-linux.c 38 | LDFLAGS += -lrt 39 | endif 40 | 41 | ifeq ($(shell uname -s),Darwin) 42 | CFLAGS += -Wno-deprecated-declarations 43 | SOURCES += \ 44 | ../lib/futex-stub.c \ 45 | sbcelt-sandbox-darwin.c \ 46 | pdeath-kqueue.c 47 | endif 48 | 49 | ifeq ($(shell uname -s),FreeBSD) 50 | SOURCES += \ 51 | ../lib/futex-freebsd.c \ 52 | sbcelt-sandbox-freebsd.c \ 53 | pdeath-kqueue.c 54 | endif 55 | 56 | include ../Make.cmd 57 | -------------------------------------------------------------------------------- /helper/seccomp-sandbox.c: -------------------------------------------------------------------------------- 1 | // seccomp example for x86 (32-bit and 64-bit) with BPF macros 2 | // 3 | // Copyright (c) 2012 The Chromium OS Authors 4 | // Authors: 5 | // Will Drewry 6 | // Kees Cook 7 | // 8 | // The code may be used by anyone for any purpose, and can serve as a 9 | // starting point for developing applications using mode 2 seccomp. 10 | 11 | #include "seccomp-sandbox.h" 12 | 13 | int seccomp_sandbox_strict_init(void) { 14 | if (prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0)) { 15 | return -1; 16 | } 17 | if (prctl(PR_SET_SECCOMP, 1, 0, 0, 0)) { 18 | return -1; 19 | } 20 | return 0; 21 | } 22 | 23 | int seccomp_sandbox_filter_init(void) { 24 | struct sock_filter filter[] = { 25 | /* Validate architecture. */ 26 | VALIDATE_ARCHITECTURE, 27 | /* Grab the system call number. */ 28 | EXAMINE_SYSCALL, 29 | /* List allowed syscalls. */ 30 | ALLOW_SYSCALL(rt_sigreturn), 31 | #ifdef __NR_sigreturn 32 | ALLOW_SYSCALL(sigreturn), 33 | #endif 34 | ALLOW_SYSCALL(futex), 35 | #ifdef DEBUG 36 | ALLOW_SYSCALL(write), 37 | ALLOW_SYSCALL(read), 38 | ALLOW_SYSCALL(fstat), 39 | #endif 40 | ALLOW_SYSCALL(exit_group), 41 | ALLOW_SYSCALL(exit), 42 | KILL_PROCESS, 43 | }; 44 | struct sock_fprog prog = { 45 | .len = (unsigned short)(sizeof(filter)/sizeof(filter[0])), 46 | .filter = filter, 47 | }; 48 | 49 | if (prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0)) { 50 | return -1; 51 | } 52 | if (prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, &prog)) { 53 | return -1; 54 | } 55 | return 0; 56 | } 57 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (C) 2012 The SBCELT Developers 2 | 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 | 9 | - Redistributions of source code must retain the above copyright notice, 10 | this list of conditions and the following disclaimer. 11 | - Redistributions in binary form must reproduce the above copyright notice, 12 | this list of conditions and the following disclaimer in the documentation 13 | and/or other materials provided with the distribution. 14 | - Neither the name of the SBCELT Developers nor the names of its 15 | contributors may be used to endorse or promote products derived from this 16 | software without specific prior written permission. 17 | 18 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 19 | `AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 20 | LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 21 | A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR 22 | CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 23 | EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 24 | PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 25 | PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 26 | LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 27 | NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 28 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 29 | -------------------------------------------------------------------------------- /bench-sbcelt/bench.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | #include 9 | #include "common.h" 10 | #include "../sbcelt.h" 11 | 12 | #define USEC_PER_SEC 1000000 13 | #define NSEC_PER_USEC 1000 14 | 15 | // Monotonic microsecond timestamp generator. 16 | // The expectation is that gettimeofday() uses 17 | // the VDSO and/or the TSC (on modern x86) to 18 | // avoid system calls. 19 | uint64_t mymtime() { 20 | struct timeval tv; 21 | if (gettimeofday(&tv, NULL) == -1) { 22 | return 0; 23 | } 24 | return ((uint64_t)tv.tv_sec * USEC_PER_SEC) + (uint64_t)tv.tv_usec; 25 | } 26 | 27 | int main(int argc, char *argv[]) { 28 | int i; 29 | int niter = 10000; 30 | 31 | unsigned char buf[127]; 32 | FILE *f = fopen("test.dat", "r"); 33 | if (f == NULL) { 34 | fprintf(stderr, "unable to open test.dat\n"); 35 | return 1; 36 | } 37 | if (fread(buf, 1, 127, f) != 127) { 38 | fprintf(stderr, "unable to read test.dat\n"); 39 | return 1; 40 | } 41 | fclose(f); 42 | 43 | CELTMode *dm = sbcelt_mode_create(SAMPLE_RATE, SAMPLE_RATE / 100, NULL); 44 | CELTDecoder *d = sbcelt_decoder_create(dm, 1, NULL); 45 | 46 | float pcmout[FRAME_SIZE]; 47 | uint64_t begin = mymtime(); 48 | for (i = 0; i < niter; i++) { 49 | if (sbcelt_decode_float(d, buf, 127, pcmout) != CELT_OK) { 50 | fprintf(stderr, "unable to decode...\n"); 51 | return 1; 52 | } 53 | } 54 | uint64_t elapsed = mymtime() - begin; 55 | 56 | printf("{\"niter\": %i, \"elapsed_usec\": %lu}\n", niter, elapsed); 57 | 58 | return 0; 59 | } 60 | -------------------------------------------------------------------------------- /helper/alloc.c: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2012 The SBCELT Developers. All rights reserved. 2 | // Use of this source code is governed by a BSD-style license 3 | // that can be found in the LICENSE-file. 4 | 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | #define ALIGN_UP(addr,sz) (((addr)+sz-1) & ~(sz-1)) 11 | #define ARENA_SIZE 8*1024*1024 // 8MB 12 | #define ARENA_ALIGN 4096 // 4KB 13 | 14 | static unsigned char arena[ARENA_SIZE] __attribute__((aligned (ARENA_ALIGN))); 15 | static void *ptr = NULL; 16 | static void *outside = NULL; 17 | 18 | __attribute__((constructor)) 19 | static void malloc_ctor() { 20 | ptr = &arena[0]; 21 | outside = ptr + ARENA_SIZE; 22 | } 23 | 24 | void *malloc(size_t size) { 25 | // CTOR sanity checking. 26 | if (ptr == NULL || outside == NULL) { 27 | _exit(51); 28 | } 29 | 30 | // Ensure our allocations end on a 8-byte boundary. 31 | size = size + sizeof(size_t); 32 | size = ALIGN_UP(size, 8); 33 | 34 | // Atomic add; returns old value. 35 | void *incr = (void *) size; 36 | void *region = __sync_fetch_and_add(&ptr, incr); 37 | // Check whether the region we were handed by the 38 | // allocator can actually fit in the arena. 39 | if ((region+size-1) >= outside) { 40 | _exit(50); 41 | // Also check the pointer itself exceeds the arena. 42 | } else if (region >= outside) { 43 | _exit(50); 44 | } 45 | 46 | size_t *sz = (size_t *) region; 47 | *sz = size; 48 | 49 | void *ret = region + sizeof(size_t); 50 | memset(ret, 0, size); 51 | 52 | return ret; 53 | } 54 | 55 | void *calloc(size_t nmemb, size_t size) { 56 | return malloc(nmemb*size); 57 | } 58 | 59 | void *realloc(void *ptr, size_t size) { 60 | size_t *oldsz = ptr-sizeof(size_t); 61 | void *dst = malloc(size); 62 | memcpy(dst, ptr, *oldsz); 63 | return dst; 64 | } 65 | 66 | void free(void *ptr) { 67 | } 68 | -------------------------------------------------------------------------------- /lib/stub.c: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2012 The SBCELT Developers. All rights reserved. 2 | // Use of this source code is governed by a BSD-style license 3 | // that can be found in the LICENSE-file. 4 | 5 | #include 6 | 7 | #include "celt.h" 8 | #include "../sbcelt-internal.h" 9 | #include "../sbcelt.h" 10 | 11 | CELTMode *SBCELT_FUNC(celt_mode_create)(celt_int32 Fs, int frame_size, int *error) { 12 | return (CELTMode *) 0x1; 13 | } 14 | 15 | void SBCELT_FUNC(celt_mode_destroy)(CELTMode *mode) { 16 | } 17 | 18 | int SBCELT_FUNC(celt_mode_info)(const CELTMode *mode, int request, celt_int32 *value) { 19 | if (request == CELT_GET_BITSTREAM_VERSION) { 20 | *value = 0x8000000b; 21 | return CELT_OK; 22 | } 23 | return CELT_INTERNAL_ERROR; 24 | } 25 | 26 | CELTEncoder *SBCELT_FUNC(celt_encoder_create)(const CELTMode *mode, int channels, int *error) { 27 | return NULL; 28 | } 29 | 30 | void SBCELT_FUNC(celt_encoder_destroy)(CELTEncoder *st) { 31 | } 32 | 33 | int SBCELT_FUNC(celt_encode_float)(CELTEncoder *st, const float *pcm, float *optional_synthesis, 34 | unsigned char *compressed, int nbCompressedBytes) { 35 | return CELT_INTERNAL_ERROR; 36 | } 37 | 38 | int SBCELT_FUNC(celt_encode)(CELTEncoder *st, const celt_int16 *pcm, celt_int16 *optional_synthesis, 39 | unsigned char *compressed, int nbCompressedBytes) { 40 | return CELT_INTERNAL_ERROR; 41 | } 42 | 43 | int SBCELT_FUNC(celt_encoder_ctl)(CELTEncoder * st, int request, ...) { 44 | return CELT_INTERNAL_ERROR; 45 | } 46 | 47 | int SBCELT_FUNC(celt_decode)(CELTDecoder *st, const unsigned char *data, int len, celt_int16 *pcm) { 48 | return CELT_INTERNAL_ERROR; 49 | } 50 | 51 | int SBCELT_FUNC(celt_decoder_ctl)(CELTDecoder * st, int request, ...) { 52 | return CELT_INTERNAL_ERROR; 53 | } 54 | 55 | const char *SBCELT_FUNC(celt_strerror)(int error) { 56 | return "celt: unknown error"; 57 | } 58 | -------------------------------------------------------------------------------- /sbcelt-internal.h: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2012 The SBCELT Developers. All rights reserved. 2 | // Use of this source code is governed by a BSD-style license 3 | // that can be found in the LICENSE-file. 4 | 5 | #ifndef __SBCELT_INTERNAL_H__ 6 | #define __SBCELT_INTERNAL_H__ 7 | 8 | #define SBCELT_PAGES 2 9 | #define SBCELT_PAGE_SIZE 4096 10 | 11 | #define SBCELT_SLOTS 40 12 | 13 | #define SBCELT_MODE_FUTEX 1 14 | #define SBCELT_MODE_RW 2 15 | 16 | #define SBCELT_SANDBOX_NONE 0 17 | #define SBCELT_SANDBOX_SECCOMP_STRICT 1 18 | #define SBCELT_SANDBOX_SECCOMP_BPF 2 19 | #define SBCELT_SANDBOX_SEATBELT 3 20 | #define SBCELT_SANDBOX_CAPSICUM 4 21 | 22 | #define SBCELT_SANDBOX_VALID(x) \ 23 | (x >= SBCELT_SANDBOX_NONE && x <= SBCELT_SANDBOX_CAPSICUM) 24 | 25 | struct SBCELTWorkPage { 26 | int slot; // The slot that the helper process should work on. 27 | int ready; // The ready state (also used for futex synchronization). 28 | unsigned char busywait; // Determines whether libsbcelt and the helper may use busy-waiting instead of kernel synchronization. 29 | unsigned char mode; // The current operational mode (SBCELT_MODE_FUTEX or SBCELT_MODE_RW) 30 | unsigned char sandbox; // The sandbox technique that is used to jail the helper. 31 | unsigned char pingpong; // Byte-sized value used for SBCELT_MODE_RW synchronization. 32 | unsigned int len; // Specifies the length of encbuf to the helper process. 33 | unsigned char encbuf[2048]; // Holds the frame to be decoded. 34 | float decbuf[480]; // Holds the decoded PCM data. 35 | }; 36 | 37 | struct SBCELTDecoderSlot { 38 | int available; 39 | int dispose; 40 | }; 41 | 42 | struct SBCELTDecoderPage { 43 | struct SBCELTDecoderSlot slots[SBCELT_SLOTS]; 44 | }; 45 | 46 | int SBCELT_Init(); 47 | 48 | #endif 49 | -------------------------------------------------------------------------------- /helper/pdeath-kqueue.c: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2012 The SBCELT Developers. All rights reserved. 2 | // Use of this source code is governed by a BSD-style license 3 | // that can be found in the LICENSE-file. 4 | 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | 12 | #include "eintr.h" 13 | 14 | static int kqfd = -1; 15 | 16 | static void *pdeath_monitor(void *udata) { 17 | (void) udata; 18 | while (1) { 19 | struct kevent ke; 20 | int ret = HANDLE_EINTR(kevent(kqfd, NULL, 0, &ke, 1, NULL)); 21 | if (ret == 0) { 22 | // No events for us. 23 | continue; 24 | } else if (ret > 0) { 25 | // Our parent has died. 26 | _exit(0); 27 | } else if (ret == -1) { 28 | // Most of kevent()'s returned errors are programmer errors, 29 | // except ENOMEM and ESRCH. 30 | // 31 | // In case of ENOMEM, we might as well exit. It's not clear 32 | // when ESRCH is returned, but the racy case of the parent 33 | // going away before we set up our kevent struct is handled 34 | // by the pdeath function below, so it should be safe to ignore. 35 | if (errno == ENOMEM) { 36 | _exit(50); 37 | } 38 | return NULL; 39 | } 40 | } 41 | return NULL; 42 | } 43 | 44 | int pdeath() { 45 | struct kevent ke; 46 | pid_t ppid; 47 | 48 | kqfd = kqueue(); 49 | if (kqfd == -1) { 50 | return -1; 51 | } 52 | 53 | ppid = getppid(); 54 | if (ppid <= 1) { 55 | _exit(0); 56 | } 57 | 58 | EV_SET(&ke, ppid, EVFILT_PROC, EV_ADD, NOTE_EXIT, 0, NULL); 59 | if (HANDLE_EINTR(kevent(kqfd, &ke, 1, NULL, 0, NULL)) == -1) { 60 | // Parent seemingly already dead. 61 | if (errno == ESRCH) { 62 | _exit(0); 63 | } 64 | return -1; 65 | } 66 | 67 | pthread_t thr; 68 | if (pthread_create(&thr, NULL, pdeath_monitor, NULL) == -1) { 69 | return -1; 70 | } 71 | 72 | if (getppid() <= 1) { 73 | _exit(0); 74 | } 75 | 76 | return 0; 77 | } 78 | -------------------------------------------------------------------------------- /lib/closefrom.c: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2012 The SBCELT Developers. All rights reserved. 2 | // Use of this source code is governed by a BSD-style license 3 | // that can be found in the LICENSE-file. 4 | 5 | // Based on bsd-closefrom.c by: 6 | // 7 | // Copyright (c) 2004-2005 Todd C. Miller 8 | // 9 | // Permission to use, copy, modify, and distribute this software for any 10 | // purpose with or without fee is hereby granted, provided that the above 11 | // copyright notice and this permission notice appear in all copies. 12 | // 13 | // THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 14 | // WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 15 | // MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 16 | // ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 17 | // WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 18 | // ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 19 | // OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 20 | 21 | #include 22 | #include 23 | #include 24 | #include 25 | 26 | #include 27 | #include 28 | 29 | #include "eintr.h" 30 | 31 | #if defined(__APPLE__) 32 | # define FD_DIR "/dev/fd" 33 | #else 34 | # define FD_DIR "/proc/self/fd" 35 | #endif 36 | 37 | void xclosefrom(int lowfd) { 38 | struct dirent *dent; 39 | long fd, maxfd; 40 | char *endp; 41 | DIR *dirp; 42 | 43 | if ((dirp = opendir(FD_DIR))) { 44 | while ((dent = readdir(dirp)) != NULL) { 45 | fd = strtol(dent->d_name, &endp, 10); 46 | if (dent->d_name != endp && *endp == '\0' && fd >= 0 && fd < INT_MAX && fd >= lowfd && fd != dirfd(dirp)) { 47 | (void) HANDLE_EINTR(close((int)fd)); 48 | } 49 | } 50 | (void) HANDLE_EINTR(closedir(dirp)); 51 | } else { 52 | maxfd = sysconf(_SC_OPEN_MAX); 53 | for (fd = lowfd; fd < maxfd; fd++) { 54 | (void) HANDLE_EINTR(close((int)fd)); 55 | } 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /bench-celt/bench.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | #include 9 | #include "common.h" 10 | 11 | #define USEC_PER_SEC 1000000 12 | #define NSEC_PER_USEC 1000 13 | 14 | // Monotonic microsecond timestamp generator. 15 | // The expectation is that gettimeofday() uses 16 | // the VDSO and/or the TSC (on modern x86) to 17 | // avoid system calls. 18 | uint64_t mtime() { 19 | struct timeval tv; 20 | if (gettimeofday(&tv, NULL) == -1) { 21 | return 0; 22 | } 23 | return ((uint64_t)tv.tv_sec * USEC_PER_SEC) + (uint64_t)tv.tv_usec; 24 | } 25 | 26 | int gentest(unsigned char *buf, int n); // gentest.c 27 | 28 | #define GEN_TESTDATA_FILE 0 29 | 30 | int main(int argc, char *argv[]) { 31 | int i; 32 | int niter = 10000; 33 | 34 | unsigned char buf[127]; 35 | #if GEN_TESTDATA_FILE == 1 36 | if (gentest(buf, 127) == -1) { 37 | fprintf(stderr, "unable to generate testdata\n"); 38 | return 1; 39 | } 40 | 41 | FILE *f = fopen("test.dat", "w"); 42 | fwrite(buf, 127, 1, f); 43 | fclose(f); 44 | #else 45 | FILE *f = fopen("test.dat", "r"); 46 | if (f == NULL) { 47 | fprintf(stderr, "unable to open test.dat\n"); 48 | return 1; 49 | } 50 | if (fread(buf, 1, 127, f) != 127) { 51 | fprintf(stderr, "unable to read test.dat\n"); 52 | return 1; 53 | } 54 | fclose(f); 55 | #endif 56 | 57 | CELTMode *dm = celt_mode_create(SAMPLE_RATE, SAMPLE_RATE / 100, NULL); 58 | CELTDecoder *d = celt_decoder_create(dm, 1, NULL); 59 | 60 | float pcmout[FRAME_SIZE]; 61 | uint64_t begin = mtime(); 62 | for (i = 0; i < niter; i++) { 63 | if (celt_decode_float(d, buf, 127, pcmout) != CELT_OK) { 64 | fprintf(stderr, "unable to decode...\n"); 65 | return 1; 66 | } 67 | } 68 | uint64_t elapsed = mtime() - begin; 69 | 70 | printf("{\"niter\": %i, \"elapsed_usec\": %lu}\n", niter, elapsed); 71 | 72 | return 0; 73 | } 74 | -------------------------------------------------------------------------------- /helper/seccomp-sandbox.h: -------------------------------------------------------------------------------- 1 | // seccomp example for x86 (32-bit and 64-bit) with BPF macros 2 | // 3 | // Copyright (c) 2012 The Chromium OS Authors 4 | // Authors: 5 | // Will Drewry 6 | // Kees Cook 7 | // 8 | // The code may be used by anyone for any purpose, and can serve as a 9 | // starting point for developing applications using mode 2 seccomp. 10 | 11 | #ifndef _SECCOMP_BPF_H_ 12 | #define _SECCOMP_BPF_H_ 13 | 14 | #define _GNU_SOURCE 1 15 | #include 16 | #include 17 | #include 18 | #include 19 | #include 20 | #include 21 | #include 22 | 23 | #include 24 | #ifndef PR_SET_NO_NEW_PRIVS 25 | # define PR_SET_NO_NEW_PRIVS 38 26 | #endif 27 | 28 | #include 29 | #include 30 | #include 31 | #ifdef HAVE_LINUX_SECCOMP_H 32 | # include 33 | #endif 34 | #ifndef SECCOMP_MODE_FILTER 35 | # define SECCOMP_MODE_FILTER 2 /* uses user-supplied filter. */ 36 | # define SECCOMP_RET_KILL 0x00000000U /* kill the task immediately */ 37 | # define SECCOMP_RET_TRAP 0x00030000U /* disallow and force a SIGSYS */ 38 | # define SECCOMP_RET_ALLOW 0x7fff0000U /* allow */ 39 | struct seccomp_data { 40 | int nr; 41 | __u32 arch; 42 | __u64 instruction_pointer; 43 | __u64 args[6]; 44 | }; 45 | #endif 46 | #ifndef SYS_SECCOMP 47 | # define SYS_SECCOMP 1 48 | #endif 49 | 50 | #define syscall_nr (offsetof(struct seccomp_data, nr)) 51 | #define arch_nr (offsetof(struct seccomp_data, arch)) 52 | 53 | #if defined(__i386__) 54 | # define REG_SYSCALL REG_EAX 55 | # define ARCH_NR AUDIT_ARCH_I386 56 | #elif defined(__x86_64__) 57 | # define REG_SYSCALL REG_RAX 58 | # define ARCH_NR AUDIT_ARCH_X86_64 59 | #else 60 | # warning "Platform does not support seccomp filter yet" 61 | # define REG_SYSCALL 0 62 | # define ARCH_NR 0 63 | #endif 64 | 65 | #define VALIDATE_ARCHITECTURE \ 66 | BPF_STMT(BPF_LD+BPF_W+BPF_ABS, arch_nr), \ 67 | BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, ARCH_NR, 1, 0), \ 68 | BPF_STMT(BPF_RET+BPF_K, SECCOMP_RET_KILL) 69 | 70 | #define EXAMINE_SYSCALL \ 71 | BPF_STMT(BPF_LD+BPF_W+BPF_ABS, syscall_nr) 72 | 73 | #define ALLOW_SYSCALL(name) \ 74 | BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, __NR_##name, 0, 1), \ 75 | BPF_STMT(BPF_RET+BPF_K, SECCOMP_RET_ALLOW) 76 | 77 | #define KILL_PROCESS \ 78 | BPF_STMT(BPF_RET+BPF_K, SECCOMP_RET_KILL) 79 | 80 | int seccomp_sandbox_strict_init(); 81 | int seccomp_sandbox_filter_init(); 82 | 83 | #endif /* _SECCOMP_BPF_H_ */ 84 | -------------------------------------------------------------------------------- /sbcelt.h: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2012 The SBCELT Developers. All rights reserved. 2 | // Use of this source code is governed by a BSD-style license 3 | // that can be found in the LICENSE-file. 4 | 5 | #ifndef __SBCELT_H__ 6 | #define __SBCELT_H__ 7 | 8 | #ifdef __cplusplus 9 | extern "C" { 10 | #endif 11 | 12 | // Define SBCELT_PREFIX_API to prefix all exported 13 | // symbols with 'sb'. 14 | #ifdef SBCELT_PREFIX_API 15 | # define SBCELT_FUNC(x) sb ## x 16 | // Define SBCELT_COMPAT_API to have the preprocessor 17 | // replace all occurrences of calls to vanilla CELT 18 | // functions with calls to their SBCELT 'sb'-prefixed 19 | // counter-parts. 20 | # ifdef SBCELT_COMPAT_API 21 | # define celt_mode_create sbcelt_mode_create 22 | # define celt_mode_destroy sbcelt_mode_destroy 23 | # define celt_mode_info sbcelt_mode_info 24 | # define celt_encoder_create sbcelt_encoder_create 25 | # define celt_encoder_destroy sbcelt_encoder_destroy 26 | # define celt_encode_float sbcelt_encode_float 27 | # define celt_encode sbcelt_encode 28 | # define celt_encoder_ctl sbcelt_encoder_ctl 29 | # define celt_decoder_create sbcelt_decoder_create 30 | # define celt_decoder_destroy sbcelt_decoder_destroy 31 | # define celt_decode_float sbcelt_decode_float 32 | # define celt_decode sbcelt_decode 33 | # define celt_decoder_ctl sbcelt_decoder_ctl 34 | # define celt_strerror sbcelt_strerror 35 | # endif 36 | #else 37 | # define SBCELT_FUNC(x) x 38 | #endif 39 | 40 | CELTMode *SBCELT_FUNC(celt_mode_create)(celt_int32 Fs, int frame_size, int *error); 41 | void SBCELT_FUNC(celt_mode_destroy)(CELTMode *mode); 42 | int SBCELT_FUNC(celt_mode_info)(const CELTMode *mode, int request, celt_int32 *value); 43 | CELTEncoder *SBCELT_FUNC(celt_encoder_create)(const CELTMode *mode, int channels, int *error); 44 | void SBCELT_FUNC(celt_encoder_destroy)(CELTEncoder *st); 45 | int SBCELT_FUNC(celt_encode_float)(CELTEncoder *st, const float *pcm, float *optional_synthesis, 46 | unsigned char *compressed, int nbCompressedBytes); 47 | int SBCELT_FUNC(celt_encode)(CELTEncoder *st, const celt_int16 *pcm, celt_int16 *optional_synthesis, 48 | unsigned char *compressed, int nbCompressedBytes); 49 | int SBCELT_FUNC(celt_encoder_ctl)(CELTEncoder * st, int request, ...); 50 | CELTDecoder *SBCELT_FUNC(celt_decoder_create)(const CELTMode *mode, int channels, int *error); 51 | void SBCELT_FUNC(celt_decoder_destroy)(CELTDecoder *st); 52 | extern int (*SBCELT_FUNC(celt_decode_float))(CELTDecoder *st, const unsigned char *data, int len, float *pcm); 53 | int SBCELT_FUNC(celt_decode)(CELTDecoder *st, const unsigned char *data, int len, celt_int16 *pcm); 54 | int SBCELT_FUNC(celt_decoder_ctl)(CELTDecoder * st, int request, ...); 55 | const char *SBCELT_FUNC(celt_strerror)(int error); 56 | 57 | #ifdef __cplusplus 58 | } 59 | #endif 60 | 61 | #endif 62 | -------------------------------------------------------------------------------- /helper/sbcelt-helper.c: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2012 The SBCELT Developers. All rights reserved. 2 | // Use of this source code is governed by a BSD-style license 3 | // that can be found in the LICENSE-file. 4 | 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | 17 | #include 18 | #include 19 | 20 | #include "celt.h" 21 | #include "../sbcelt-internal.h" 22 | 23 | #include "pdeath.h" 24 | #include "eintr.h" 25 | #include "futex.h" 26 | #include "sbcelt-sandbox.h" 27 | 28 | #define SAMPLE_RATE 48000 29 | 30 | #ifdef DEBUG 31 | # define debugf(fmt, ...) \ 32 | do { \ 33 | fprintf(stderr, "sbcelt-helper:%s():%u: " fmt "\n", \ 34 | __FUNCTION__, __LINE__, ## __VA_ARGS__); \ 35 | fflush(stderr); \ 36 | } while (0) 37 | #else 38 | #define debugf(s, ...) do{} while (0) 39 | #endif 40 | 41 | static struct SBCELTWorkPage *workpage = NULL; 42 | static struct SBCELTDecoderPage *decpage = NULL; 43 | static CELTMode *modes[SBCELT_SLOTS]; 44 | static CELTDecoder *decoders[SBCELT_SLOTS]; 45 | 46 | static void SBCELT_DecodeSingleFrame() { 47 | unsigned char *src = &workpage->encbuf[0]; 48 | float *dst = &workpage->decbuf[0]; 49 | 50 | int idx = workpage->slot; 51 | struct SBCELTDecoderSlot *slot = &decpage->slots[idx]; 52 | CELTMode *m = modes[idx]; 53 | CELTDecoder *d = decoders[idx]; 54 | 55 | if (slot->dispose && m != NULL && d != NULL) { 56 | debugf("disposed of mode & decoder for slot=%i", idx); 57 | celt_mode_destroy(m); 58 | celt_decoder_destroy(d); 59 | m = modes[idx] = celt_mode_create(SAMPLE_RATE, SAMPLE_RATE / 100, NULL); 60 | d = decoders[idx] = celt_decoder_create(m, 1, NULL); 61 | slot->dispose = 0; 62 | } 63 | 64 | if (m == NULL && d == NULL) { 65 | debugf("created mode & decoder for slot=%i", idx); 66 | m = modes[idx] = celt_mode_create(SAMPLE_RATE, SAMPLE_RATE / 100, NULL); 67 | d = decoders[idx] = celt_decoder_create(m, 1, NULL); 68 | } 69 | 70 | debugf("got work for slot=%i", idx); 71 | unsigned int len = workpage->len; 72 | debugf("to decode: %p, %p, %u, %p", d, src, len, dst); 73 | if (len == 0) { 74 | celt_decode_float(d, NULL, 0, dst); 75 | } else { 76 | celt_decode_float(d, src, len, dst); 77 | } 78 | 79 | debugf("decoded len=%u", len); 80 | } 81 | 82 | static int SBCELT_FutexHelper() { 83 | while (1) { 84 | // Wait for the lib to signal us. 85 | while (workpage->ready == 1) { 86 | int err = futex_wait(&workpage->ready, 1, NULL); 87 | if (err == 0) { 88 | break; 89 | } 90 | } 91 | 92 | SBCELT_DecodeSingleFrame(); 93 | 94 | workpage->ready = 1; 95 | 96 | if (!workpage->busywait) { 97 | futex_wake(&workpage->ready); 98 | } 99 | } 100 | 101 | return -2; 102 | } 103 | 104 | static int SBCELT_RWHelper() { 105 | while (1) { 106 | // Wait for the lib to signal us. 107 | if (HANDLE_EINTR(read(0, &workpage->pingpong, 1)) == -1) { 108 | return -2; 109 | } 110 | 111 | SBCELT_DecodeSingleFrame(); 112 | 113 | if (HANDLE_EINTR(write(1, &workpage->pingpong, 1)) == -1) { 114 | return -3; 115 | } 116 | } 117 | } 118 | 119 | int main(int argc, char *argv[]) { 120 | if (argc >= 2 && !strcmp(argv[1], "detect")) { 121 | debugf("in seccomp-detect mode"); 122 | if (SBCELT_EnterSandbox(SBCELT_SANDBOX_CAPSICUM) == 0) { 123 | _exit(SBCELT_SANDBOX_CAPSICUM); 124 | } 125 | if (SBCELT_EnterSandbox(SBCELT_SANDBOX_SEATBELT) == 0) { 126 | _exit(SBCELT_SANDBOX_SEATBELT); 127 | } 128 | if (SBCELT_EnterSandbox(SBCELT_SANDBOX_SECCOMP_BPF) == 0) { 129 | _exit(SBCELT_SANDBOX_SECCOMP_BPF); 130 | } 131 | if (SBCELT_EnterSandbox(SBCELT_SANDBOX_SECCOMP_STRICT) == 0) { 132 | _exit(SBCELT_SANDBOX_SECCOMP_STRICT); 133 | } 134 | _exit(SBCELT_SANDBOX_NONE); 135 | } 136 | 137 | debugf("helper running"); 138 | 139 | if (pdeath() == -1) { 140 | return 1; 141 | } 142 | 143 | char shmfn[50]; 144 | if (snprintf(&shmfn[0], 50, "/sbcelt-%lu", (unsigned long) getppid()) < 0) { 145 | return 2; 146 | } 147 | 148 | int fd = shm_open(&shmfn[0], O_RDWR, 0600); 149 | if (fd == -1) { 150 | debugf("unable to open shm: %s (%i)", strerror(errno), errno); 151 | return 3; 152 | } 153 | 154 | void *addr = mmap(NULL, SBCELT_PAGES*SBCELT_PAGE_SIZE, PROT_READ|PROT_WRITE, MAP_FILE|MAP_SHARED, fd, 0); 155 | if (addr == MAP_FAILED) { 156 | debugf("unable to mmap: %s (%i)", strerror(errno), errno); 157 | return 5; 158 | } 159 | workpage = addr; 160 | decpage = addr+SBCELT_PAGE_SIZE; 161 | 162 | debugf("workpage=%p, decpage=%p", workpage, decpage); 163 | 164 | if (SBCELT_EnterSandbox(workpage->sandbox) == -1) { 165 | return 6; 166 | } 167 | 168 | switch (workpage->mode) { 169 | case SBCELT_MODE_FUTEX: 170 | return SBCELT_FutexHelper(); 171 | case SBCELT_MODE_RW: 172 | return SBCELT_RWHelper(); 173 | } 174 | 175 | return 7; 176 | } 177 | -------------------------------------------------------------------------------- /helper/config.h: -------------------------------------------------------------------------------- 1 | /* config.h. Generated from config.h.in by configure. */ 2 | /* config.h.in. Generated from configure.ac by autoheader. */ 3 | 4 | /* Define if building universal (internal helper macro) */ 5 | /* #undef AC_APPLE_UNIVERSAL_BUILD */ 6 | 7 | /* This is a build of CELT */ 8 | #define CELT_BUILD /**/ 9 | 10 | /* Version extra */ 11 | #define CELT_EXTRA_VERSION "" 12 | 13 | /* Version major */ 14 | #define CELT_MAJOR_VERSION 0 15 | 16 | /* Version micro */ 17 | #define CELT_MICRO_VERSION 0 18 | 19 | /* Version minor */ 20 | #define CELT_MINOR_VERSION 7 21 | 22 | /* Complete version string */ 23 | #define CELT_VERSION "0.7.0" 24 | 25 | /* Compile as fixed-point */ 26 | /* #undef DOUBLE_PRECISION */ 27 | 28 | /* Assertions */ 29 | /* #undef ENABLE_ASSERTIONS */ 30 | 31 | /* Debug fixed-point implementation */ 32 | /* #undef FIXED_DEBUG */ 33 | 34 | /* Compile as fixed-point */ 35 | /* #undef FIXED_POINT */ 36 | 37 | /* Compile as floating-point */ 38 | #define FLOATING_POINT /**/ 39 | 40 | /* Define to 1 if you have the header file. */ 41 | #define HAVE_ALLOCA_H 1 42 | 43 | /* Define to 1 if you have the header file. */ 44 | #define HAVE_DLFCN_H 1 45 | 46 | /* Define to 1 if you have the header file. */ 47 | #define HAVE_GETOPT_H 1 48 | 49 | /* Define to 1 if you have the `getopt_long' function. */ 50 | #define HAVE_GETOPT_LONG 1 51 | 52 | /* Define to 1 if you have the header file. */ 53 | #define HAVE_INTTYPES_H 1 54 | 55 | /* Define to 1 if you have the `m' library (-lm). */ 56 | #define HAVE_LIBM 1 57 | 58 | /* Define to 1 if you have the `winmm' library (-lwinmm). */ 59 | /* #undef HAVE_LIBWINMM */ 60 | 61 | /* Define if you have C99's lrint function. */ 62 | #define HAVE_LRINT 1 63 | 64 | /* Define if you have C99's lrintf function. */ 65 | #define HAVE_LRINTF 1 66 | 67 | /* Define to 1 if you have the header file. */ 68 | #define HAVE_MEMORY_H 1 69 | 70 | /* Define to 1 if you have the header file. */ 71 | #define HAVE_STDINT_H 1 72 | 73 | /* Define to 1 if you have the header file. */ 74 | #define HAVE_STDLIB_H 1 75 | 76 | /* Define to 1 if you have the header file. */ 77 | #define HAVE_STRINGS_H 1 78 | 79 | /* Define to 1 if you have the header file. */ 80 | #define HAVE_STRING_H 1 81 | 82 | /* Define to 1 if you have the header file. */ 83 | /* #undef HAVE_SYS_AUDIOIO_H */ 84 | 85 | /* Define to 1 if you have the header file. */ 86 | #define HAVE_SYS_SOUNDCARD_H 1 87 | 88 | /* Define to 1 if you have the header file. */ 89 | #define HAVE_SYS_STAT_H 1 90 | 91 | /* Define to 1 if you have the header file. */ 92 | #define HAVE_SYS_TYPES_H 1 93 | 94 | /* Define to 1 if you have the header file. */ 95 | #define HAVE_UNISTD_H 1 96 | 97 | /* Define to the sub-directory in which libtool stores uninstalled libraries. 98 | */ 99 | #define LT_OBJDIR ".libs/" 100 | 101 | /* Compile as fixed-point */ 102 | /* #undef MIXED_PRECISION */ 103 | 104 | /* Define to the address where bug reports for this package should be sent. */ 105 | #define PACKAGE_BUGREPORT "" 106 | 107 | /* Define to the full name of this package. */ 108 | #define PACKAGE_NAME "" 109 | 110 | /* Define to the full name and version of this package. */ 111 | #define PACKAGE_STRING "" 112 | 113 | /* Define to the one symbol short name of this package. */ 114 | #define PACKAGE_TARNAME "" 115 | 116 | /* Define to the version of this package. */ 117 | #define PACKAGE_VERSION "" 118 | 119 | /* The size of `int', as computed by sizeof. */ 120 | #define SIZEOF_INT 4 121 | 122 | /* The size of `long', as computed by sizeof. */ 123 | #define SIZEOF_LONG 8 124 | 125 | /* The size of `long long', as computed by sizeof. */ 126 | #define SIZEOF_LONG_LONG 8 127 | 128 | /* The size of `short', as computed by sizeof. */ 129 | #define SIZEOF_SHORT 2 130 | 131 | /* Static modes */ 132 | /* #undef STATIC_MODES */ 133 | 134 | /* Define to 1 if you have the ANSI C header files. */ 135 | #define STDC_HEADERS 1 136 | 137 | /* Make use of alloca */ 138 | /* #undef USE_ALLOCA */ 139 | 140 | /* Use C99 variable-size arrays */ 141 | #define VAR_ARRAYS /**/ 142 | 143 | /* Define WORDS_BIGENDIAN to 1 if your processor stores words with the most 144 | significant byte first (like Motorola and SPARC, unlike Intel). */ 145 | #if defined AC_APPLE_UNIVERSAL_BUILD 146 | # if defined __BIG_ENDIAN__ 147 | # define WORDS_BIGENDIAN 1 148 | # endif 149 | #else 150 | # ifndef WORDS_BIGENDIAN 151 | /* # undef WORDS_BIGENDIAN */ 152 | # endif 153 | #endif 154 | 155 | /* Define to empty if `const' does not conform to ANSI C. */ 156 | /* #undef const */ 157 | 158 | /* Define to `__inline__' or `__inline' if that's what the C compiler 159 | calls it, or to nothing if 'inline' is not supported under any name. */ 160 | #ifndef __cplusplus 161 | /* #undef inline */ 162 | #endif 163 | 164 | /* Define to the equivalent of the C99 'restrict' keyword, or to 165 | nothing if this is not supported. Do not define if restrict is 166 | supported directly. */ 167 | #define restrict __restrict 168 | /* Work around a bug in Sun C++: it does not support _Restrict, even 169 | though the corresponding Sun C compiler does, which causes 170 | "#define restrict _Restrict" in the previous line. Perhaps some future 171 | version of Sun C++ will work with _Restrict; if so, it'll probably 172 | define __RESTRICT, just as Sun C does. */ 173 | #if defined __SUNPRO_CC && !defined __RESTRICT 174 | # define _Restrict 175 | #endif 176 | -------------------------------------------------------------------------------- /lib/libsbcelt.c: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2012 The SBCELT Developers. All rights reserved. 2 | // Use of this source code is governed by a BSD-style license 3 | // that can be found in the LICENSE-file. 4 | 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | #include 19 | #include 20 | #include 21 | #include 22 | 23 | #include "celt.h" 24 | #include "../sbcelt-internal.h" 25 | #include "../sbcelt.h" 26 | 27 | #include "eintr.h" 28 | #include "futex.h" 29 | #include "mtime.h" 30 | #include "debug.h" 31 | #include "closefrom.h" 32 | 33 | static struct SBCELTWorkPage *workpage = NULL; 34 | static struct SBCELTDecoderPage *decpage = NULL; 35 | static int running = 0; 36 | static int lastslot = 0; 37 | static uint64_t lastrun = 3000; // 3 ms 38 | static int fdin = -1; 39 | static int fdout = -1; 40 | static pid_t hpid = -1; 41 | static uint64_t lastdead = 0; 42 | static pthread_t monitor; 43 | 44 | int SBCELT_FUNC(celt_decode_float_rw)(CELTDecoder *st, const unsigned char *data, int len, float *pcm); 45 | int SBCELT_FUNC(celt_decode_float_futex)(CELTDecoder *st, const unsigned char *data, int len, float *pcm); 46 | int SBCELT_FUNC(celt_decode_float_picker)(CELTDecoder *st, const unsigned char *data, int len, float *pcm); 47 | int (*SBCELT_FUNC(celt_decode_float))(CELTDecoder *, const unsigned char *, int, float *) = SBCELT_FUNC(celt_decode_float_picker); 48 | 49 | // SBELT_HelperBinary returns the path to the helper binary. 50 | static char *SBCELT_HelperBinary() { 51 | char *helper = getenv("SBCELT_HELPER_BINARY"); 52 | if (helper == NULL) { 53 | helper = "/usr/bin/sbcelt-helper"; 54 | } 55 | return helper; 56 | } 57 | 58 | // SBCELT_CheckSeccomp checks for kernel support for 59 | // SECCOMP. 60 | // 61 | // On success, the function returns a valid sandbox 62 | // mode (see SBCELT_SANDBOX_*). 63 | // 64 | // On failure, the function returns 65 | // -1 if the helper process did not execute correctly. 66 | // -2 if the fork system call failed. This signals that the 67 | // host system is running low on memory. This is a 68 | // recoverable error, and in our case we should simply 69 | // wait a bit and try again. 70 | static int SBCELT_CheckSeccomp() { 71 | int status, err; 72 | pid_t child; 73 | 74 | child = fork(); 75 | if (child == -1) { 76 | return -2; 77 | } else if (child == 0) { 78 | char *const argv[] = { 79 | SBCELT_HelperBinary(), 80 | "detect", 81 | NULL, 82 | }; 83 | execv(argv[0], argv); 84 | _exit(100); 85 | } 86 | 87 | if (HANDLE_EINTR(waitpid(child, &status, 0)) == -1) { 88 | return -1; 89 | } 90 | 91 | if (!WIFEXITED(status)) { 92 | return -1; 93 | } 94 | 95 | int code = WEXITSTATUS(status); 96 | if (!SBCELT_SANDBOX_VALID(code)) { 97 | return -1; 98 | } 99 | 100 | return code; 101 | } 102 | 103 | // SBCELT_HelperMonitor implements a monitor thread that runs 104 | // when libsbcelt decides to use SBCELT_MODE_FUTEX. It is 105 | // response for determining whether the helper process has died, 106 | // and if that happens, restart it. 107 | static void *SBCELT_HelperMonitor(void *udata) { 108 | (void) udata; 109 | 110 | while (1) { 111 | uint64_t now = mtime(); 112 | uint64_t elapsed = now - lastdead; 113 | lastdead = now; 114 | 115 | // Throttle helper re-launches to around 1 per sec. 116 | if (elapsed < 1*USEC_PER_SEC) { 117 | usleep(1*USEC_PER_SEC); 118 | } 119 | 120 | debugf("restarted sbcelt-helper; %lu usec since last death", elapsed); 121 | 122 | pid_t child = fork(); 123 | if (child == -1) { 124 | // We're memory constrained. Wait and try again... 125 | usleep(5*USEC_PER_SEC); 126 | continue; 127 | } else if (child == 0) { 128 | // For SBCELT_SANDBOX_SECCOMP_BPF, it shouldn't matter 129 | // whether the child inherits any file descriptors, since 130 | // the only useful system call the process can make is futex(2). 131 | // 132 | // However, if we're running in Futex mode without a sandbox, 133 | // closing the file descriptors is indeed a good idea, which 134 | // is why we do it unconditionally below. 135 | (void) HANDLE_EINTR(close(0)); 136 | (void) HANDLE_EINTR(close(1)); 137 | #ifndef DEBUG 138 | xclosefrom(2); 139 | #else 140 | xclosefrom(3); 141 | #endif 142 | 143 | char *const argv[] = { 144 | SBCELT_HelperBinary(), 145 | NULL, 146 | }; 147 | execv(argv[0], argv); 148 | _exit(100); 149 | } 150 | 151 | int status; 152 | int retval = HANDLE_EINTR(waitpid(child, &status, 0)); 153 | if (retval == child) { 154 | if (WIFEXITED(status)) { 155 | debugf("sbcelt-helper died with exit status: %i", WEXITSTATUS(status)); 156 | } else if (WIFSIGNALED(status)) { 157 | debugf("sbcelt-helper died with signal: %i", WTERMSIG(status)); 158 | } 159 | } else if (retval == -1 && errno == EINVAL) { 160 | fprintf(stderr, "libsbcelt: waitpid() failed with EINVAL; internal error!\n"); 161 | fflush(stderr); 162 | exit(1); 163 | } 164 | } 165 | } 166 | 167 | // SBCELT_RelaunchHelper restarts the helper process in a state which 168 | // makes it usable for SBCELT_MODE_RW. 169 | // 170 | // On success, returns 0. 171 | // On failure, returns 172 | // -1 if the system is resource exhauted (not enough memory for fork(2), 173 | // no available file descriptor slots for pipe(2), or because of 174 | // throttling of helper process launches). 175 | static int SBCELT_RelaunchHelper() { 176 | int fds[2]; 177 | int chin, chout; 178 | 179 | // Best-effort attempt to reap the previous helper process. 180 | // Perhaps the process libsbcelt is hosted in is ignoring 181 | // SIGCHLD, in which case the kernel will automatically reap 182 | // the children, making this call superfluous. 183 | int reap = (hpid != -1); 184 | if (reap) { 185 | int status; 186 | int retval = HANDLE_EINTR(waitpid(hpid, &status, WNOHANG)); 187 | if (retval == hpid) { 188 | if (WIFEXITED(status)) { 189 | debugf("sbcelt-helper died with exit status: %i", WEXITSTATUS(status)); 190 | } else if (WIFSIGNALED(status)) { 191 | debugf("sbcelt-helper died with signal: %i", WTERMSIG(status)); 192 | } 193 | } else if (retval == -1 && errno == EINVAL) { 194 | fprintf(stderr, "libsbcelt: waitpid() failed with EINVAL; internal error!\n"); 195 | fflush(stderr); 196 | exit(1); 197 | } 198 | hpid = -1; 199 | } 200 | 201 | // Throttle helper re-launches to around 1 per sec. 202 | uint64_t now = mtime(); 203 | uint64_t elapsed = now - lastdead; 204 | if (reap) { 205 | lastdead = now; 206 | } 207 | if (elapsed < 1*USEC_PER_SEC) { 208 | return -1; 209 | } 210 | 211 | if (pipe(fds) == -1) 212 | return -1; 213 | fdin = fds[0]; 214 | chout = fds[1]; 215 | 216 | if (pipe(fds) == -1) { 217 | (void) HANDLE_EINTR(close(fdin)); 218 | (void) HANDLE_EINTR(close(chout)); 219 | return -1; 220 | } 221 | fdout = fds[1]; 222 | chin = fds[0]; 223 | 224 | debugf("SBCELT_RelaunchHelper; fdin=%i, fdout=%i", fdin, fdout); 225 | 226 | pid_t child = fork(); 227 | if (child == -1) { 228 | (void) HANDLE_EINTR(close(fdin)); 229 | (void) HANDLE_EINTR(close(chout)); 230 | (void) HANDLE_EINTR(close(fdout)); 231 | (void) HANDLE_EINTR(close(chin)); 232 | return -1; 233 | } else if (child == 0) { 234 | (void) HANDLE_EINTR(close(0)); 235 | (void) HANDLE_EINTR(close(1)); 236 | if (HANDLE_EINTR(dup2(chin, 0)) == -1) 237 | _exit(101); 238 | if (HANDLE_EINTR(dup2(chout, 1)) == -1) 239 | _exit(102); 240 | 241 | // Make sure that all file descriptors, except 242 | // those strictly needed by the helper are closed. 243 | // Allow the child to inherit stderr for debugging 244 | // purposes only. 245 | #ifndef DEBUG 246 | xclosefrom(2); 247 | #else 248 | xclosefrom(3); 249 | #endif 250 | 251 | char *const argv[] = { 252 | SBCELT_HelperBinary(), 253 | NULL, 254 | }; 255 | execv(argv[0], argv); 256 | _exit(100); 257 | } 258 | 259 | (void) HANDLE_EINTR(close(chin)); 260 | (void) HANDLE_EINTR(close(chout)); 261 | 262 | hpid = child; 263 | debugf("SBCELT_RelaunchHelper; relaunched helper (pid=%li)", child); 264 | 265 | return 0; 266 | } 267 | 268 | int SBCELT_Init() { 269 | char shmfn[50]; 270 | if (snprintf(&shmfn[0], 50, "/sbcelt-%lu", (unsigned long) getpid()) < 0) { 271 | return -1; 272 | } 273 | 274 | shm_unlink(&shmfn[0]); 275 | int fd = shm_open(&shmfn[0], O_CREAT|O_RDWR, 0600); 276 | if (fd == -1) { 277 | return -1; 278 | } else { 279 | if (ftruncate(fd, SBCELT_PAGES*SBCELT_PAGE_SIZE) == -1) { 280 | debugf("unable to truncate: %s (%i)", strerror(errno), errno); 281 | return -1; 282 | } 283 | 284 | void *addr = mmap(NULL, SBCELT_PAGES*SBCELT_PAGE_SIZE, PROT_READ|PROT_WRITE, MAP_FILE|MAP_SHARED, fd, 0); 285 | if (addr == MAP_FAILED) { 286 | debugf("unable to mmap: %s (%i)", strerror(errno), errno); 287 | return -1; 288 | } 289 | memset(addr, 0, SBCELT_PAGES*SBCELT_PAGE_SIZE); 290 | 291 | workpage = addr; 292 | decpage = addr+SBCELT_PAGE_SIZE; 293 | 294 | workpage->busywait = sysconf(_SC_NPROCESSORS_ONLN) > 0; 295 | 296 | int i; 297 | for (i = 0; i < SBCELT_SLOTS; i++) { 298 | decpage->slots[i].available = 1; 299 | } 300 | } 301 | 302 | return 0; 303 | } 304 | 305 | CELTDecoder *SBCELT_FUNC(celt_decoder_create)(const CELTMode *mode, int channels, int *error) { 306 | if (!running) { 307 | SBCELT_Init(); 308 | running = 1; 309 | } 310 | 311 | // Find a free slot. 312 | int i, slot = -1; 313 | for (i = 0; i < SBCELT_SLOTS; i++) { 314 | int idx = (lastslot+i) % SBCELT_SLOTS; 315 | if (decpage->slots[idx].available) { 316 | decpage->slots[idx].available = 0; 317 | lastslot = idx; 318 | slot = idx; 319 | break; 320 | } 321 | } 322 | if (slot == -1) { 323 | debugf("decoder_create: no free slots"); 324 | return NULL; 325 | } 326 | 327 | debugf("decoder_create: slot=%i", slot); 328 | 329 | return (CELTDecoder *)((uintptr_t)slot); 330 | } 331 | 332 | void SBCELT_FUNC(celt_decoder_destroy)(CELTDecoder *st) { 333 | int slot = (int)((uintptr_t)st); 334 | decpage->slots[slot].available = 1; 335 | 336 | debugf("decoder_destroy: slot=%i", slot); 337 | } 338 | 339 | // celt_decode_float_picker is the initial value for the celt_decode_float function pointer. 340 | // It checks the available sandbox modes on the system, picks an appropriate celt_decode_float 341 | // implementation to use according to the available sandbox modes, and makes those choices 342 | // available to the helper process in the work page. 343 | int SBCELT_FUNC(celt_decode_float_picker)(CELTDecoder *st, const unsigned char *data, int len, float *pcm) { 344 | int sandbox = SBCELT_CheckSeccomp(); 345 | if (sandbox == -1) { 346 | return CELT_INTERNAL_ERROR; 347 | // If the system is memory constrained, pretend that we were able 348 | // decode a frame correctly, and delegate the seccomp availability 349 | // check to sometime in the future. 350 | } else if (sandbox == -2) { 351 | memset(pcm, 0, sizeof(float)*480); 352 | return CELT_OK; 353 | } 354 | 355 | // For benchmarking and testing purposes, it's beneficial for us 356 | // to force a SECCOMP_STRICT sandbox, and therefore be force to run 357 | // in the rw mode. 358 | if (getenv("SBCELT_PREFER_SECCOMP_STRICT") != NULL) { 359 | if (sandbox == SBCELT_SANDBOX_SECCOMP_BPF) { 360 | sandbox = SBCELT_SANDBOX_SECCOMP_STRICT; 361 | } 362 | } 363 | 364 | debugf("picker: chose sandbox=%i", sandbox); 365 | workpage->sandbox = sandbox; 366 | 367 | // If we're without a sandbox, or is able to use seccomp 368 | // with BPF filters, we can use our fast futex mode. 369 | // For seccomp strict mode, we're limited to rw mode. 370 | switch (workpage->sandbox) { 371 | case SBCELT_SANDBOX_SEATBELT: 372 | workpage->mode = SBCELT_MODE_RW; 373 | SBCELT_FUNC(celt_decode_float) = SBCELT_FUNC(celt_decode_float_rw); 374 | break; 375 | case SBCELT_SANDBOX_SECCOMP_STRICT: 376 | workpage->mode = SBCELT_MODE_RW; 377 | SBCELT_FUNC(celt_decode_float) = SBCELT_FUNC(celt_decode_float_rw); 378 | break; 379 | default: 380 | if (futex_available()) { 381 | workpage->mode = SBCELT_MODE_FUTEX; 382 | SBCELT_FUNC(celt_decode_float) = SBCELT_FUNC(celt_decode_float_futex); 383 | } else { 384 | workpage->mode = SBCELT_MODE_RW; 385 | SBCELT_FUNC(celt_decode_float) = SBCELT_FUNC(celt_decode_float_rw); 386 | } 387 | break; 388 | } 389 | 390 | debugf("picker: chose mode=%i", workpage->mode); 391 | 392 | if (workpage->mode == SBCELT_MODE_RW) { 393 | #ifndef SBCELT_NO_SIGNAL_MUCKING 394 | struct sigaction sa; 395 | memset(&sa, 0, sizeof(sa)); 396 | sa.sa_handler = SIG_IGN; 397 | sigemptyset(&sa.sa_mask); 398 | if (sigaction(SIGPIPE, &sa, NULL) == -1) { 399 | return CELT_INTERNAL_ERROR; 400 | } 401 | #endif 402 | } else if (workpage->mode == SBCELT_MODE_FUTEX) { 403 | pthread_t tmp; 404 | if (pthread_create(&monitor, NULL, SBCELT_HelperMonitor, NULL) != 0) { 405 | return CELT_INTERNAL_ERROR; 406 | } 407 | } 408 | 409 | return SBCELT_FUNC(celt_decode_float)(st, data, len, pcm); 410 | } 411 | 412 | int SBCELT_FUNC(celt_decode_float_futex)(CELTDecoder *st, const unsigned char *data, int len, float *pcm) { 413 | int slot = (int)((uintptr_t)st); 414 | 415 | debugf("decode_float; len=%i", len); 416 | 417 | workpage->slot = slot; 418 | memcpy(&workpage->encbuf[0], data, len); 419 | workpage->len = len; 420 | 421 | uint64_t begin = mtime(); 422 | 423 | // Wake up the helper, if necessary... 424 | workpage->ready = 0; 425 | futex_wake(&workpage->ready); 426 | 427 | int bad = 0; 428 | if (workpage->busywait) { 429 | while (!workpage->ready) { 430 | uint64_t elapsed = mtime() - begin; 431 | if (elapsed > lastrun*2) { 432 | bad = 1; 433 | break; 434 | } 435 | } 436 | } else { 437 | do { 438 | struct timespec ts = { 0, (lastrun*2) * NSEC_PER_USEC }; 439 | int err = futex_wait(&workpage->ready, 0, &ts); 440 | if (err == 0) { 441 | break; 442 | } else if (err == ETIMEDOUT) { 443 | bad = 1; 444 | break; 445 | } 446 | } while (!workpage->ready); 447 | } 448 | 449 | if (!bad) { 450 | uint64_t elapsed = mtime() - begin; 451 | #ifdef DYNAMIC_TIMEOUT 452 | lastrun = elapsed; 453 | #endif 454 | debugf("spent %lu usecs in decode\n", elapsed); 455 | memcpy(pcm, workpage->decbuf, sizeof(float)*480); 456 | } else { 457 | #ifdef DYNAMIC_TIMEOUT 458 | lastrun = 3000; 459 | #endif 460 | memset(pcm, 0, sizeof(float)*480); 461 | } 462 | 463 | return CELT_OK; 464 | } 465 | 466 | int SBCELT_FUNC(celt_decode_float_rw)(CELTDecoder *st, const unsigned char *data, int len, float *pcm) { 467 | int slot = (int)((uintptr_t)st); 468 | ssize_t remain; 469 | void *dst; 470 | 471 | debugf("decode_float; len=%i", len); 472 | 473 | workpage->slot = slot; 474 | memcpy(&workpage->encbuf[0], data, len); 475 | workpage->len = len; 476 | 477 | // First time the library user attempts to decode 478 | // a frame, schedule a restart. After that, restarts 479 | // should only happen when the helper dies. 480 | int restart = (hpid == -1); 481 | int attempts = 0; 482 | retry: 483 | // Limit ourselves to two attempts before giving the 484 | // caller an empty PCM frame in its buffer. We'll 485 | // try again next time celt_decode_float() is called. 486 | ++attempts; 487 | if (attempts > 2) { 488 | debugf("decode_float; too many failed attempts, returning empty frame"); 489 | memset(pcm, 0, sizeof(float)*480); 490 | return CELT_OK; 491 | } 492 | 493 | if (restart) { 494 | (void) HANDLE_EINTR(close(fdout)); 495 | (void) HANDLE_EINTR(close(fdin)); 496 | if (SBCELT_RelaunchHelper() == -1) { 497 | goto retry; 498 | } 499 | restart = 0; 500 | } 501 | 502 | // Signal to the helper that it should begin to work. 503 | if (HANDLE_EINTR(write(fdout, &workpage->pingpong, 1)) == -1) { 504 | // Only attempt to restart the helper process 505 | // if our write failed with EPIPE. That's the 506 | // only indication we have that our helper has 507 | // died. 508 | // 509 | // For other errno's, simply use another attempt. 510 | if (errno == EPIPE) { 511 | restart = 1; 512 | } 513 | goto retry; 514 | } 515 | 516 | // Wait for the helper to signal us that it has decoded 517 | // the frame we passed to it. 518 | if (HANDLE_EINTR(read(fdin, &workpage->pingpong, 1)) == -1) { 519 | // Restart helper in case of EPIPE. See comment 520 | // inside the error condition for the write(2) 521 | // call above. 522 | if (errno == EPIPE) { 523 | restart = 1; 524 | } 525 | goto retry; 526 | } 527 | 528 | debugf("decode_float; success"); 529 | 530 | memcpy(pcm, workpage->decbuf, sizeof(float)*480); 531 | 532 | return CELT_OK; 533 | } 534 | 535 | --------------------------------------------------------------------------------