diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml
index 15d3289..972e898 100644
--- a/.github/workflows/main.yml
+++ b/.github/workflows/main.yml
@@ -25,9 +25,12 @@ jobs:
- name: Build project
run: scripts/linux/build.sh
- - name: Run example
+ - name: Test project
run: scripts/linux/test.sh
+ - name: Run example
+ run: scripts/linux/example.sh
+
qemu-linux-x86_64:
runs-on: ubuntu-latest
strategy:
@@ -59,7 +62,7 @@ jobs:
run: scripts/qemu/build.sh ${{ matrix.kernel }}
- name: Run example
- run: scripts/qemu/test.sh
+ run: scripts/qemu/example.sh
release:
needs: [linux-x86_64, qemu-linux-x86_64]
diff --git a/.gitignore b/.gitignore
index 2afb629..5050f07 100644
--- a/.gitignore
+++ b/.gitignore
@@ -137,3 +137,4 @@ m4/*
!m4/ac_sphinx.m4
!m4/ac_docs_enable.m4
!m4/ax_pthread.m4
+!m4/ax_check_link_flag.m4
diff --git a/Makefile.am b/Makefile.am
index fc9b25c..81bf7a5 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -1,15 +1,15 @@
ACLOCAL_AMFLAGS = -I m4
if BUILD_EXAMPLES
- MAYBE_EXAMPLES = examples
+MAYBE_EXAMPLES = examples
endif
if BUILD_BENCHMARK
- MAYBE_BENCHMARK = benchmark
+MAYBE_BENCHMARK = benchmark
endif
if BUILD_DOCS
- MAYBE_DOCS = doc
+MAYBE_DOCS = doc
endif
SUBDIRS = src/module src/lib src/util $(MAYBE_EXAMPLES) $(MAYBE_BENCHMARK) $(MAYBE_DOCS)
diff --git a/README.md b/README.md
index 02b884b..50e89c9 100644
--- a/README.md
+++ b/README.md
@@ -36,15 +36,18 @@ A PDF version of the documentation is also available [here](https://github.com/M
- libtool
- pkg-config
- linux-headers
-- sphinx [1](#f1)
-- doxygen [1](#f1)
-- breathe [1](#f1)
-- sphinx_rtd_theme [1](#f1)
-- latex [2](#f2)
+- check [1](#f1)
+- sphinx [2](#f2)
+- doxygen [2](#f2)
+- breathe [2](#f2)
+- sphinx_rtd_theme [2](#f2)
+- latex [3](#f3)
-1 Optional: needed only to build the documentation
+1 Optional: needed only for userspace library tests
-2 Optional: needed only to build the pdf documentation
+2 Optional: needed only to build the documentation
+
+3 Optional: needed only to build the pdf documentation
### Minimal Build
@@ -52,7 +55,8 @@ Build the userspace library and the LKM and install them into the system with:
```
$ ./configure
$ make
-$ make install
+$ make check
+$ sudo make install
$ sudo ldconfig
$ sudo modprobe ums
```
@@ -65,9 +69,9 @@ The following dependencies are needed in case of development build:
- autoconf
- automake
- git
-- cppcheck [3](#f2)
+- cppcheck [4](#f4)
-3 Optional: needed only for userspace library static code analysis
+4 Optional: needed only for userspace library static code analysis
### Development Build
diff --git a/benchmark/configure.ac b/benchmark/configure.ac
index 60995c7..4934ef8 100644
--- a/benchmark/configure.ac
+++ b/benchmark/configure.ac
@@ -19,6 +19,11 @@ AC_PROG_CC
LT_PREREQ([2.4])
LT_INIT
+AC_PATH_PROG([CPPCHECK], [cppcheck], [true])
+AS_IF([test "x$CPPCHECK" = xtrue], [
+ AC_MSG_WARN(['cppcheck' is recommended for developing this package.])
+])
+
# Use the C language and compiler for the following checks
AC_LANG([C])
diff --git a/doc/install.rst b/doc/install.rst
index 8042181..1a93518 100644
--- a/doc/install.rst
+++ b/doc/install.rst
@@ -11,14 +11,16 @@ Minimal Requirements
- libtool
- pkg-config
- linux-headers
-- sphinx\ [#f1]_
-- doxygen\ [#f1]_
-- breathe\ [#f1]_
-- sphinx_rtd_theme\ [#f1]_
-- latex\ [#f2]_
+- check\ [#f1]_
+- sphinx\ [#f2]_
+- doxygen\ [#f2]_
+- breathe\ [#f2]_
+- sphinx_rtd_theme\ [#f2]_
+- latex\ [#f3]_
-.. [#f1] Optional: needed only to build the documentation
-.. [#f2] Optional: needed only to build the pdf documentation
+.. [#f1] Optional: needed only for userspace library tests
+.. [#f2] Optional: needed only to build the documentation
+.. [#f3] Optional: needed only to build the pdf documentation
Development Requirements
========================
@@ -29,9 +31,9 @@ The following dependencies are needed in case of development build:
- autoconf
- automake
- git
-- cppcheck\ [#f3]_
+- cppcheck\ [#f4]_
-.. [#f3] Optional: needed only for userspace library static code analysis
+.. [#f4] Optional: needed only for userspace library static code analysis
Build
=====
@@ -103,6 +105,7 @@ Targets
``html`` Build the html documentation
``pdf`` Build the pdf documentation
``install`` Install into the system
+``installcheck`` Install tests into the system
``uninstall`` Uninstall from the system
``clean`` Delete all files in the current directory that are
normally created by building the program
@@ -110,11 +113,14 @@ Targets
created by configuring or building the program
========================== ====================================================
-Install
-=======
+Minimal installation steps
+==========================
.. code::
- $ make install
+ $ ./configure
+ $ make
+ $ make check
+ $ sudo make install
$ sudo ldconfig
$ sudo modprobe ums
diff --git a/doc/userspace/internals/library_lifecycle.rst b/doc/userspace/internals/library_lifecycle.rst
index b88d0ba..d6df975 100644
--- a/doc/userspace/internals/library_lifecycle.rst
+++ b/doc/userspace/internals/library_lifecycle.rst
@@ -23,7 +23,7 @@ In particular the :c:var:`UMS_FILENO` is declared as
.. literalinclude:: /../src/lib/src/private.h
:language: c
- :lines: 18
+ :lines: 20
:lineno-match:
:dedent:
:caption: src/lib/src/private.h
diff --git a/doc/userspace/internals/scheduler.rst b/doc/userspace/internals/scheduler.rst
index d8bac39..b764283 100644
--- a/doc/userspace/internals/scheduler.rst
+++ b/doc/userspace/internals/scheduler.rst
@@ -15,7 +15,7 @@ in particular the :c:func:`enter_ums_scheduling_mode()` begins with:
.. literalinclude:: /../src/lib/src/scheduler.c
:language: c
- :lines: 13-21
+ :lines: 13-27
:lineno-match:
:dedent:
:caption: src/lib/src/scheduler.c
@@ -24,7 +24,7 @@ where the ``enter_ums_mode`` is defined at
.. literalinclude:: /../src/lib/src/private.h
:language: c
- :lines: 20-23
+ :lines: 22-25
:lineno-match:
:dedent:
:caption: src/lib/src/private.h
@@ -36,7 +36,7 @@ UMS :c:type:`ums_scheduler_entry_point_t`.
.. literalinclude:: /../src/lib/src/scheduler.c
:language: c
- :lines: 23-61
+ :lines: 29-67
:lineno-match:
:dedent:
:caption: src/lib/src/scheduler.c
@@ -48,7 +48,7 @@ The execution of a worker thread context is implemented as follows:
.. literalinclude:: /../src/lib/src/scheduler.c
:language: c
- :lines: 66-69
+ :lines: 72-75
:lineno-match:
:dedent:
:caption: src/lib/src/scheduler.c
diff --git a/doc/userspace/internals/worker.rst b/doc/userspace/internals/worker.rst
index aaffb3e..69da521 100644
--- a/doc/userspace/internals/worker.rst
+++ b/doc/userspace/internals/worker.rst
@@ -16,7 +16,7 @@ The function is implemented as follows:
.. literalinclude:: /../src/lib/src/worker.c
:language: c
- :lines: 53-70
+ :lines: 53-75
:lineno-match:
:dedent:
:caption: src/lib/src/worker.c
@@ -56,7 +56,7 @@ The yielding of a UMS worker thread is implemented as follows:
.. literalinclude:: /../src/lib/src/worker.c
:language: c
- :lines: 72-75
+ :lines: 77-80
:lineno-match:
:dedent:
:caption: src/lib/src/worker.c
diff --git a/m4/ax_check_link_flag.m4 b/m4/ax_check_link_flag.m4
new file mode 100644
index 0000000..03a30ce
--- /dev/null
+++ b/m4/ax_check_link_flag.m4
@@ -0,0 +1,53 @@
+# ===========================================================================
+# https://www.gnu.org/software/autoconf-archive/ax_check_link_flag.html
+# ===========================================================================
+#
+# SYNOPSIS
+#
+# AX_CHECK_LINK_FLAG(FLAG, [ACTION-SUCCESS], [ACTION-FAILURE], [EXTRA-FLAGS], [INPUT])
+#
+# DESCRIPTION
+#
+# Check whether the given FLAG works with the linker or gives an error.
+# (Warnings, however, are ignored)
+#
+# ACTION-SUCCESS/ACTION-FAILURE are shell commands to execute on
+# success/failure.
+#
+# If EXTRA-FLAGS is defined, it is added to the linker's default flags
+# when the check is done. The check is thus made with the flags: "LDFLAGS
+# EXTRA-FLAGS FLAG". This can for example be used to force the linker to
+# issue an error when a bad flag is given.
+#
+# INPUT gives an alternative input source to AC_LINK_IFELSE.
+#
+# NOTE: Implementation based on AX_CFLAGS_GCC_OPTION. Please keep this
+# macro in sync with AX_CHECK_{PREPROC,COMPILE}_FLAG.
+#
+# LICENSE
+#
+# Copyright (c) 2008 Guido U. Draheim
+# Copyright (c) 2011 Maarten Bosmans
+#
+# Copying and distribution of this file, with or without modification, are
+# permitted in any medium without royalty provided the copyright notice
+# and this notice are preserved. This file is offered as-is, without any
+# warranty.
+
+#serial 6
+
+AC_DEFUN([AX_CHECK_LINK_FLAG],
+[AC_PREREQ(2.64)dnl for _AC_LANG_PREFIX and AS_VAR_IF
+AS_VAR_PUSHDEF([CACHEVAR],[ax_cv_check_ldflags_$4_$1])dnl
+AC_CACHE_CHECK([whether the linker accepts $1], CACHEVAR, [
+ ax_check_save_flags=$LDFLAGS
+ LDFLAGS="$LDFLAGS $4 $1"
+ AC_LINK_IFELSE([m4_default([$5],[AC_LANG_PROGRAM()])],
+ [AS_VAR_SET(CACHEVAR,[yes])],
+ [AS_VAR_SET(CACHEVAR,[no])])
+ LDFLAGS=$ax_check_save_flags])
+AS_VAR_IF(CACHEVAR,yes,
+ [m4_default([$2], :)],
+ [m4_default([$3], :)])
+AS_VAR_POPDEF([CACHEVAR])dnl
+])dnl AX_CHECK_LINK_FLAGS
diff --git a/qemu/configs/qemu_x86_64_defconfig b/qemu/configs/qemu_x86_64_defconfig
index 84d33b0..77d176d 100755
--- a/qemu/configs/qemu_x86_64_defconfig
+++ b/qemu/configs/qemu_x86_64_defconfig
@@ -36,6 +36,12 @@ BR2_ROOTFS_OVERLAY="../rootfs_overlay"
# OpenSSH
BR2_PACKAGE_OPENSSH=y
+# check
+BR2_PACKAGE_CHECK=y
+
+# pkg-config
+BR2_PACKAGE_PKGCONF=y
+
BR2_PACKAGE_HOST_ENVIRONMENT_SETUP=y
EOF
diff --git a/scripts/build/build-sdk.sh b/scripts/build/build-sdk.sh
index b7ba6b7..6ed6d44 100755
--- a/scripts/build/build-sdk.sh
+++ b/scripts/build/build-sdk.sh
@@ -91,6 +91,7 @@ rm $SDK_NAME.tar.gz
sed -i "/alias configure=/d" $SDK_NAME/environment-setup
sed -i "/export \"KERNELDIR=/c\export \"KERNELDIR=\$(dirname \$(dirname \$SDK_PATH))/linux-$KERNEL_VERSION\"" \
$SDK_NAME/environment-setup
+echo "export \"PKG_CONFIG_SYSROOT_DIR=\$SDK_NAME\"" >> $SDK_NAME/environment-setup
rm start-qemu.sh
cd $WORKDIR && mkdir -p $OUTPUT_DIR
diff --git a/scripts/linux/build.sh b/scripts/linux/build.sh
index 190c1bb..2213df0 100755
--- a/scripts/linux/build.sh
+++ b/scripts/linux/build.sh
@@ -49,4 +49,3 @@ cd $BUILDDIR
$BASEDIR/configure CFLAGS="-ggdb3" --enable-examples
make -j $(nproc) V=1
-make -j $(nproc) V=1 check
diff --git a/scripts/linux/example.sh b/scripts/linux/example.sh
new file mode 100755
index 0000000..4362188
--- /dev/null
+++ b/scripts/linux/example.sh
@@ -0,0 +1,93 @@
+#!/usr/bin/env bash
+
+set -eo pipefail
+if [ ! -z "${CI+x}" ] || [ "$CI" = "true" ]; then
+ set -x
+fi
+
+BASEDIR=$(dirname $(dirname $(dirname $(realpath "$0"))))
+ME=$(basename "$0")
+
+usage() {
+ cat <&2
+ usage >&2
+ exit 1
+ ;;
+ :)
+ echo "missing value for option [-$OPTARG]" >&2
+ usage >&2
+ exit 1
+ ;;
+ esac
+done
+shift $(($OPTIND - 1))
+
+$BASEDIR/scripts/linux/install.sh -i $BUILDDIR
+
+mkdir -p $LOGDIR
+
+readarray -d '' examples < <(find $EXAMPLESDIR/*/.libs -type f -print0)
+
+for e in "${examples[@]}"; do
+ EXAMPLE_NAME=$(basename $e)
+ EXAMPLE_TIMESTAMP=$(date +%s)
+ LOGPREFIX=$LOGDIR/$EXAMPLE_NAME-$EXAMPLE_TIMESTAMP
+ GDB_LOGFILE=$LOGPREFIX.gdb.log
+ TEST_LOGFILE=$LOGPREFIX.out.log
+ set +e
+ printf "\033[1;32m[TEST] %s\033[0m\n" $EXAMPLE_NAME
+
+ timeout -s SIGINT $TEST_TIMEOUT gdb -batch -q -n \
+ -ex "set pagination off" \
+ -ex "set logging file $GDB_LOGFILE" \
+ -ex "set logging on" \
+ -ex "file $e" \
+ -ex "run > $TEST_LOGFILE" \
+ -ex "call setvbuf(stdout, 0, 2, 0)" \
+ -ex "thread apply all bt full" &> /dev/null
+ EXIT_STATUS=$?
+ set -e; set +x
+
+ printf "\033[1;32mOUTPUT:\033[0m\n"
+ cat $TEST_LOGFILE
+
+ if [ $EXIT_STATUS != 0 ]; then
+ printf "\n\033[1;32mGDB:\033[0m\n"
+ cat $GDB_LOGFILE
+
+ printf "\n\033[1;32mDMESG:\033[0m\n"
+ dmesg | grep ums
+
+ exit $EXIT_STATUS
+ fi
+
+ if [ ! -z "${CI+x}" ] || [ "$CI" = "true" ]; then
+ set -x
+ fi
+done
diff --git a/scripts/linux/install_deps.sh b/scripts/linux/install_deps.sh
index 6588fa5..86fe482 100755
--- a/scripts/linux/install_deps.sh
+++ b/scripts/linux/install_deps.sh
@@ -14,4 +14,5 @@ sudo apt-get install -y \
libtool \
pkg-config \
gdb \
+ check \
cppcheck
diff --git a/scripts/linux/test.sh b/scripts/linux/test.sh
index baafbac..a85b0f1 100755
--- a/scripts/linux/test.sh
+++ b/scripts/linux/test.sh
@@ -1,6 +1,6 @@
#!/usr/bin/env bash
-set -eo pipefail
+set -e
if [ ! -z "${CI+x}" ] || [ "$CI" = "true" ]; then
set -x
fi
@@ -10,30 +10,23 @@ ME=$(basename "$0")
usage() {
cat <&2
usage >&2
@@ -48,46 +41,5 @@ while getopts ":hb:l:t:" opt; do
done
shift $(($OPTIND - 1))
-$BASEDIR/scripts/linux/install.sh -i $BUILDDIR
-
-mkdir -p $LOGDIR
-
-readarray -d '' tests < <(find $TESTDIR/*/.libs -type f -print0)
-
-for t in "${tests[@]}"; do
- TEST_NAME=$(basename $t)
- TEST_TIMESTAMP=$(date +%s)
- LOGPREFIX=$LOGDIR/$TEST_NAME-$TEST_TIMESTAMP
- GDB_LOGFILE=$LOGPREFIX.gdb.log
- TEST_LOGFILE=$LOGPREFIX.out.log
- set +e
- printf "\033[1;32m[TEST] %s\033[0m\n" $TEST_NAME
-
- timeout -s SIGINT $TEST_TIMEOUT gdb -batch -q -n \
- -ex "set pagination off" \
- -ex "set logging file $GDB_LOGFILE" \
- -ex "set logging on" \
- -ex "file $t" \
- -ex "run > $TEST_LOGFILE" \
- -ex "call setvbuf(stdout, 0, 2, 0)" \
- -ex "thread apply all bt full" &> /dev/null
- EXIT_STATUS=$?
- set -e; set +x
-
- printf "\033[1;32mOUTPUT:\033[0m\n"
- cat $TEST_LOGFILE
-
- if [ $EXIT_STATUS != 0 ]; then
- printf "\n\033[1;32mGDB:\033[0m\n"
- cat $GDB_LOGFILE
-
- printf "\n\033[1;32mDMESG:\033[0m\n"
- dmesg | grep ums
-
- exit $EXIT_STATUS
- fi
-
- if [ ! -z "${CI+x}" ] || [ "$CI" = "true" ]; then
- set -x
- fi
-done
+cd $BUILDDIR
+make -j $(nproc) V=1 check
diff --git a/scripts/qemu/build.sh b/scripts/qemu/build.sh
index 3fff96d..dacc79c 100755
--- a/scripts/qemu/build.sh
+++ b/scripts/qemu/build.sh
@@ -28,7 +28,7 @@ EOF
BUILDDIR=$BASEDIR/build
-while getopts ":ho:" opt; do
+while getopts ":ho:i:" opt; do
case "$opt" in
h)
usage
@@ -72,3 +72,4 @@ cd $BUILDDIR
$BASEDIR/configure $CONFIGURE_FLAGS --enable-examples
make -j $(nproc) V=1
+make -j $(nproc) V=1 TESTS= check
diff --git a/scripts/qemu/test.sh b/scripts/qemu/example.sh
similarity index 75%
rename from scripts/qemu/test.sh
rename to scripts/qemu/example.sh
index e8652f1..6dd5755 100755
--- a/scripts/qemu/test.sh
+++ b/scripts/qemu/example.sh
@@ -13,7 +13,7 @@ usage() {
Usage: $ME [OPTIONS]...
Options:
- -b BUILD-DIR source build directory
+ -b BUILD-DIR use BUILD-DIR as input build directory
-l LOG-DIR output directory to place logfile
-t TIMEOUT test timeout in seconds
-h show this help and exit
@@ -46,13 +46,12 @@ while getopts ":hb:l:t:" opt; do
done
shift $(($OPTIND - 1))
-TESTDIR=$BUILDDIR/examples
-LOGDIR=$BUILDDIR/test
+INSTALLDIR=$BUILDDIR/install
+EXAMPLESDIR=$BUILDDIR/examples
+LOGDIR=${LOGDIR:-"$BUILDDIR/test"}
SDK_NAME=x86_64-buildroot-linux-gnu
SDK_PATH="$BUILDDIR/images/${SDK_NAME}_sdk-buildroot"
SYSROOT="$SDK_PATH/$SDK_NAME/sysroot"
-TARGET_LIBDIR="/lib64"
-TARGET_TESTDIR="/root"
export PATH="$SDK_PATH/bin:$SDK_PATH/sbin:$BASEDIR/scripts/qemu:$PATH"
@@ -62,31 +61,29 @@ trap "qemu-bridge.sh kill" EXIT
qemu-bridge.sh shell "uname -a"
-install.sh -i $BUILDDIR
+install.sh -b $BUILDDIR -i $INSTALLDIR
mkdir -p $LOGDIR
-readarray -d '' tests < <(find $TESTDIR/*/.libs -type f -print0)
+readarray -d '' examples < <(find $EXAMPLESDIR/*/.libs -type f -print0)
-for t in "${tests[@]}"; do
- TEST_NAME=$(basename $t)
- TEST_TIMESTAMP=$(date +%s)
- LOGPREFIX=$LOGDIR/$TEST_NAME-$TEST_TIMESTAMP
+for e in "${examples[@]}"; do
+ EXAMPLE_NAME=$(basename $e)
+ EXAMPLE_TIMESTAMP=$(date +%s)
+ LOGPREFIX=$LOGDIR/$EXAMPLE_NAME-$EXAMPLE_TIMESTAMP
GDB_LOGFILE=$LOGPREFIX.gdb.log
- qemu-bridge.sh push $t $TARGET_TESTDIR 1>/dev/null
-
set +e
- printf "\033[1;32m[TEST] %s\033[0m\n" $TEST_NAME
+ printf "\033[1;32m[TEST] %s\033[0m\n" $EXAMPLE_NAME
timeout -s SIGINT $TEST_TIMEOUT x86_64-buildroot-linux-gnu-gdb -batch -q -n \
- -ex "target remote | qemu-bridge.sh shell 'gdbserver - $TARGET_TESTDIR/$TEST_NAME'" \
+ -ex "target remote | qemu-bridge.sh shell 'gdbserver - $EXAMPLE_NAME'" \
-ex "set pagination off" \
-ex "set logging file $GDB_LOGFILE" \
-ex "set logging on" \
-ex "tb main" \
-ex "c" \
- -ex "set solib-search-path $BUILDDIR/src/lib/.libs" \
+ -ex "set solib-search-path $INSTALLDIR/usr/lib" \
-ex "set sysroot $SYSROOT" \
-ex "info sharedlibrary" \
-ex "show solib-search-path" \
diff --git a/scripts/qemu/install.sh b/scripts/qemu/install.sh
index 1bc9b40..3947e40 100755
--- a/scripts/qemu/install.sh
+++ b/scripts/qemu/install.sh
@@ -13,20 +13,22 @@ usage() {
Usage: $ME [OPTIONS]
Options:
- -i BUILD-DIR use BUILD-DIR as input build directory
+ -b BUILD-DIR build directory
+ -i INSTALL-DIR temporary installation directory
-h show this help and exit
EOF
}
BUILDDIR=$BASEDIR/build
-while getopts ":hi:" opt; do
+while getopts ":hb:i:" opt; do
case "$opt" in
h)
usage
exit 0
;;
- i) BUILDDIR=$OPTARG ;;
+ b) BUILDDIR=$OPTARG ;;
+ i) INSTALLDIR=$OPTARG ;;
\?)
echo "unknown option $OPTARG!" >&2
usage >&2
@@ -41,18 +43,18 @@ while getopts ":hi:" opt; do
done
shift $(($OPTIND - 1))
-SDK_NAME=x86_64-buildroot-linux-gnu
-SDK_PATH="$BUILDDIR/images/${SDK_NAME}_sdk-buildroot"
-SYSROOT="$SDK_PATH/$SDK_NAME/sysroot"
-TARGET_LIBDIR="/lib64"
-TARGET_TESTDIR="/root"
+INSTALLDIR=${INSTALLDIR:-"$BUILDDIR/install"}
+TARGET_TESTDIR="/"
-export PATH=$PATH:$BASEDIR/scripts/qemu
+cd $BUILDDIR
+make -j $(nproc) V=1 DESTDIR=$INSTALLDIR install
+make -j $(nproc) V=1 DESTDIR=$INSTALLDIR/tests installcheck
-# extract library SONAME from the symlink
-LIBUMS_SYMLINK=$(readlink $BUILDDIR/src/lib/.libs/libums.so)
-LIBUMS=$(readelf -d $BUILDDIR/src/lib/.libs/$LIBUMS_SYMLINK | grep -oP 'SONAME.*\K(?<=\[).*(?=\])')
+$BASEDIR/scripts/qemu/qemu-bridge.sh push $INSTALLDIR/usr $TARGET_TESTDIR 1>/dev/null
-qemu-bridge.sh push $BUILDDIR/src/lib/.libs/$LIBUMS $TARGET_LIBDIR 1>/dev/null
-qemu-bridge.sh push $BUILDDIR/src/module/src/ums.ko $TARGET_TESTDIR 1>/dev/null
-qemu-bridge.sh shell "insmod $TARGET_TESTDIR/ums.ko"
+if [ -d $INSTALLDIR/tests ]; then
+ $BASEDIR/scripts/qemu/qemu-bridge.sh push $INSTALLDIR/tests/usr $TARGET_TESTDIR 1>/dev/null
+fi
+
+$BASEDIR/scripts/qemu/qemu-bridge.sh push $INSTALLDIR/ums.ko $TARGET_TESTDIRums.ko 1>/dev/null
+$BASEDIR/scripts/qemu/qemu-bridge.sh shell "insmod $TARGET_TESTDIRums.ko"
diff --git a/scripts/qemu/qemu-bridge.sh b/scripts/qemu/qemu-bridge.sh
index b28adf8..f1af343 100755
--- a/scripts/qemu/qemu-bridge.sh
+++ b/scripts/qemu/qemu-bridge.sh
@@ -85,9 +85,15 @@ EOF
}
push() {
- SRCFILE=$1
+ SRC=$1
DESTDIR=$2
- scp -P $SSH_PORT $SSH_OPTS $SRCFILE $SSH_USER@$SSH_IP:$DESTDIR
+ SCP_OPTS=
+
+ if [ -d "$SRC" ]; then
+ SCP_OPTS="$SCP_OPTS -r"
+ fi
+
+ scp -P $SSH_PORT $SSH_OPTS $SCP_OPTS $SRC $SSH_USER@$SSH_IP:$DESTDIR
}
shell() {
diff --git a/src/lib/Doxyfile.in b/src/lib/Doxyfile.in
index d0c6b47..0c8a3b4 100644
--- a/src/lib/Doxyfile.in
+++ b/src/lib/Doxyfile.in
@@ -10,7 +10,7 @@ EXTRACT_STATIC = YES
ENABLE_PREPROCESSING = YES
MACRO_EXPANSION = YES
EXPAND_ONLY_PREDEF = YES
-PREDEFINED = __attribute__(x)= __BEGIN_DECLS= __THROW= __nonnull(x)= __END_DECLS=
+PREDEFINED = __attribute__(x)= __BEGIN_DECLS= __THROW= __END_DECLS=
GENERATE_XML = YES
GENERATE_HTML = NO
diff --git a/src/lib/Makefile.am b/src/lib/Makefile.am
index 1a012b9..8e0066a 100644
--- a/src/lib/Makefile.am
+++ b/src/lib/Makefile.am
@@ -14,7 +14,6 @@ EXTRA_DIST = \
src/private.h
libums_la_CFLAGS = -I$(srcdir)/include -I$(srcdir)/../module/src/uapi
-
libums_la_LDFLAGS = -version-info 0:0:0
libums_la_LIBADD = @PTHREAD_LIBS@
@@ -22,6 +21,57 @@ SUBDIRS = include
pkgconfig_DATA = libums.pc
+if BUILD_TESTS
+
+if HAVE_LD_WRAP
+lib_LTLIBRARIES += libums_mock.la
+libums_mock_la_SOURCES = $(libums_la_SOURCES) tests/mock_ums_syscalls.c
+libums_mock_la_CFLAGS = $(libums_la_CFLAGS)
+libums_mock_la_LIBADD = $(libums_la_LIBADD)
+libums_mock_la_LDFLAGS = $(libums_la_LDFLAGS) -Wl,-wrap,open -Wl,-wrap,close -Wl,-wrap,ioctl
+
+TESTS = \
+ check_ums_completion_list \
+ check_ums_worker \
+ check_ums_scheduler
+
+check_PROGRAMS = \
+ check_ums_completion_list \
+ check_ums_worker \
+ check_ums_scheduler
+
+check_ums_completion_list_SOURCES = \
+ tests/check_ums.h \
+ tests/check_ums_completion_list.c
+check_ums_completion_list_CFLAGS = -I$(srcdir)/include @CHECK_CFLAGS@
+check_ums_completion_list_LDADD = libums_mock.la @CHECK_LIBS@
+
+check_ums_worker_SOURCES = \
+ tests/check_ums.h \
+ tests/check_ums_worker.c
+check_ums_worker_CFLAGS = -I$(srcdir)/include @CHECK_CFLAGS@
+check_ums_worker_LDADD = libums_mock.la @CHECK_LIBS@
+
+check_ums_scheduler_SOURCES = \
+ tests/check_ums.h \
+ tests/check_ums_scheduler.c
+check_ums_scheduler_CFLAGS = -I$(srcdir)/include @CHECK_CFLAGS@
+check_ums_scheduler_LDADD = libums_mock.la @CHECK_LIBS@
+
+installcheck-local: $(check_PROGRAMS)
+ $(mkinstalldirs) $(DESTDIR)$(bindir)
+ @list='$(check_PROGRAMS)'; d=".libs/"; for p in $$list; do \
+ $(INSTALL_DATA) $$d$$p $(DESTDIR)$(bindir)/$$p; \
+ chmod +x $(DESTDIR)$(bindir)/$$p; \
+ done
+uninstall-hook:
+ @list='$(check_PROGRAMS)'; d=".libs/"; for p in $$list; do \
+ rm -rf $(DESTDIR)$(bindir)/$$p; \
+ done
+endif
+
+endif
+
# add static C code analysis
static-check:
-@$(CPPCHECK) -I $(srcdir)/include -I $(srcdir)/../module/src/uapi $(srcdir)
diff --git a/src/lib/configure.ac b/src/lib/configure.ac
index e14fe59..aa3a845 100644
--- a/src/lib/configure.ac
+++ b/src/lib/configure.ac
@@ -20,6 +20,9 @@ LT_PREREQ([2.4])
LT_INIT
PKG_INSTALLDIR
+PKG_CHECK_MODULES([CHECK], [check >= 0.9.6], [], [have_check=no])
+AM_CONDITIONAL([BUILD_TESTS], [test x$have_check != xno])
+
AC_PATH_PROG([CPPCHECK], [cppcheck], [true])
AS_IF([test "x$CPPCHECK" = xtrue], [
AC_MSG_WARN(['cppcheck' is recommended for developing this package.])
@@ -42,6 +45,10 @@ AC_CHECK_HEADERS_ONCE([ features.h
# Checks for pthread implementation.
AX_PTHREAD
+# Check if linker supports -wrap
+AX_CHECK_LINK_FLAG([-Wl,-wrap,open], [], [have_ld_wrap=no])
+AM_CONDITIONAL([HAVE_LD_WRAP], [test x$have_ld_wrap != xno])
+
AC_CONFIG_FILES([libums.pc
Makefile
include/Makefile])
diff --git a/src/lib/include/ums.h b/src/lib/include/ums.h
index 64b3c7b..7ffb614 100644
--- a/src/lib/include/ums.h
+++ b/src/lib/include/ums.h
@@ -35,7 +35,7 @@ __BEGIN_DECLS
* accordingly).
*/
extern int create_ums_completion_list(ums_completion_list_t *completion_list)
- __THROW __nonnull ((1));
+ __THROW;
/**
* @brief Create UMS worker thread.
@@ -87,8 +87,7 @@ extern int ums_pthread_create(pthread_t *thread, ums_attr_t *ums_attr,
* accordingly).
*/
extern int enter_ums_scheduling_mode(
- ums_scheduler_startup_info_t *scheduler_startup_info)
- __THROW __nonnull ((1));
+ ums_scheduler_startup_info_t *scheduler_startup_info) __THROW;
/**
* @brief Retrieves user-mode scheduling (UMS) worker threads from the
@@ -126,7 +125,7 @@ extern int enter_ums_scheduling_mode(
*/
extern int dequeue_ums_completion_list_items(
ums_completion_list_t completion_list, ums_context_t *ums_thread_list)
- __THROW __nonnull ((2));
+ __THROW;
/**
* @brief Returns the next user-mode scheduling (UMS) thread context in a list
@@ -198,7 +197,7 @@ extern int ums_thread_yield(void *scheduler_param) __THROW;
* accordingly).
*/
extern int delete_ums_completion_list(ums_completion_list_t *completion_list)
- __THROW __nonnull ((1));
+ __THROW;
__END_DECLS
diff --git a/src/lib/src/complist.c b/src/lib/src/complist.c
index 28d7bb8..c48c83f 100644
--- a/src/lib/src/complist.c
+++ b/src/lib/src/complist.c
@@ -4,14 +4,12 @@
int create_ums_completion_list(ums_completion_list_t *completion_list)
{
- ums_comp_list_id_t complist;
- int retval;
-
- retval = ioctl(UMS_FILENO, IOCTL_CREATE_UMS_CLIST, &complist);
- if (!retval)
- *completion_list = complist;
+ if (!completion_list) {
+ errno = EFAULT;
+ return -1;
+ }
- return retval;
+ return ioctl(UMS_FILENO, IOCTL_CREATE_UMS_CLIST, completion_list);
}
int dequeue_ums_completion_list_items(ums_completion_list_t completion_list,
@@ -22,6 +20,11 @@ int dequeue_ums_completion_list_items(ums_completion_list_t completion_list,
};
int retval;
+ if (!ums_thread_list) {
+ errno = EFAULT;
+ return -1;
+ }
+
retval = ioctl(UMS_FILENO, IOCTL_DEQUEUE_UMS_CLIST, &dequeue_args);
if (!retval)
*ums_thread_list = dequeue_args.ums_context;
@@ -50,6 +53,11 @@ int delete_ums_completion_list(ums_completion_list_t *completion_list)
{
int retval;
+ if (!completion_list) {
+ errno = EFAULT;
+ return -1;
+ }
+
retval = ioctl(UMS_FILENO,
IOCTL_DELETE_UMS_CLIST,
*completion_list);
diff --git a/src/lib/src/private.h b/src/lib/src/private.h
index b1b1d0f..1e77d82 100644
--- a/src/lib/src/private.h
+++ b/src/lib/src/private.h
@@ -3,6 +3,8 @@
#ifndef UMS_PRIVATE_H
#define UMS_PRIVATE_H
+#include
+
#include "../include/ums.h"
#include "ums/ums_ioctl.h"
diff --git a/src/lib/src/scheduler.c b/src/lib/src/scheduler.c
index 7520b8a..762ffcd 100644
--- a/src/lib/src/scheduler.c
+++ b/src/lib/src/scheduler.c
@@ -11,12 +11,18 @@ int enter_ums_scheduling_mode(
ums_scheduler_startup_info_t *scheduler_startup_info)
{
struct enter_ums_mode_args enter_args = {
- .flags = ENTER_UMS_SCHED,
- .ums_complist = scheduler_startup_info->completion_list
+ .flags = ENTER_UMS_SCHED
};
struct ums_sched_event event;
ums_activation_t scheduler_activation;
+ if (!scheduler_startup_info) {
+ errno = EFAULT;
+ return -1;
+ }
+
+ enter_args.ums_complist = scheduler_startup_info->completion_list;
+
if (enter_ums_mode(&enter_args))
return -1;
diff --git a/src/lib/src/worker.c b/src/lib/src/worker.c
index 42bea6a..e9a89ef 100644
--- a/src/lib/src/worker.c
+++ b/src/lib/src/worker.c
@@ -55,6 +55,11 @@ int ums_pthread_create(pthread_t *thread, ums_attr_t *ums_attr,
{
worker_proc_args_t *ums_args;
+ if (!ums_attr || !func) {
+ errno = EFAULT;
+ return -1;
+ }
+
ums_args = malloc(sizeof(*ums_args));
if (!ums_args)
return -1;
diff --git a/src/lib/tests/check_ums.h b/src/lib/tests/check_ums.h
new file mode 100644
index 0000000..a370a52
--- /dev/null
+++ b/src/lib/tests/check_ums.h
@@ -0,0 +1,15 @@
+/* SPDX-License-Identifier: AGPL-3.0-only */
+
+#ifndef UMS_TESTS_H
+#define UMS_TESTS_H
+
+#include
+
+#include
+#include
+
+Suite *create_ums_completion_list_suite(void);
+Suite *create_ums_scheduler_suite(void);
+Suite *create_ums_worker_suite(void);
+
+#endif /* UMS_TESTS_H */
diff --git a/src/lib/tests/check_ums_completion_list.c b/src/lib/tests/check_ums_completion_list.c
new file mode 100644
index 0000000..dbe58af
--- /dev/null
+++ b/src/lib/tests/check_ums_completion_list.c
@@ -0,0 +1,64 @@
+// SPDX-License-Identifier: AGPL-3.0-only
+
+#include
+
+#include
+#include
+
+START_TEST(test_ums_completion_list_create)
+{
+ ums_completion_list_t comp_list;
+
+ ck_assert_int_eq(create_ums_completion_list(&comp_list), 0);
+ ck_assert_int_eq(delete_ums_completion_list(&comp_list), 0);
+ ck_assert_int_eq(delete_ums_completion_list(&comp_list), -1);
+}
+END_TEST
+
+START_TEST(test_ums_completion_list_create_bad)
+{
+ ck_assert_int_eq(create_ums_completion_list(NULL), -1);
+}
+END_TEST
+
+START_TEST(test_ums_completion_list_delete_bad)
+{
+ ums_completion_list_t comp_list = -1;
+
+ ck_assert_int_eq(delete_ums_completion_list(NULL), -1);
+ ck_assert_int_eq(delete_ums_completion_list(&comp_list), -1);
+}
+END_TEST
+
+Suite *create_ums_completion_list_suite(void)
+{
+ Suite *s;
+ TCase *tc_core;
+
+ s = suite_create("UMS Completion List Suite");
+
+ tc_core = tcase_create("UMS Completion List");
+
+ tcase_add_test(tc_core, test_ums_completion_list_create);
+ tcase_add_test(tc_core, test_ums_completion_list_create_bad);
+ tcase_add_test(tc_core, test_ums_completion_list_delete_bad);
+
+ suite_add_tcase(s, tc_core);
+
+ return s;
+}
+
+int main(void)
+{
+ int number_failed;
+ Suite *s;
+ SRunner *sr;
+
+ s = create_ums_completion_list_suite();
+ sr = srunner_create(s);
+
+ srunner_run_all(sr, CK_NORMAL);
+ number_failed = srunner_ntests_failed(sr);
+ srunner_free(sr);
+ return (number_failed == 0) ? EXIT_SUCCESS : EXIT_FAILURE;
+}
diff --git a/src/lib/tests/check_ums_scheduler.c b/src/lib/tests/check_ums_scheduler.c
new file mode 100644
index 0000000..752ec76
--- /dev/null
+++ b/src/lib/tests/check_ums_scheduler.c
@@ -0,0 +1,220 @@
+// SPDX-License-Identifier: AGPL-3.0-only
+
+#include
+
+#include
+#include
+
+typedef struct ums_scheduler_startup_info_tcase_t {
+ ums_scheduler_startup_info_t *sched_info;
+ int expected_retval;
+} ums_scheduler_startup_info_tcase_t;
+
+ums_completion_list_t comp_list;
+ums_scheduler_startup_info_t sched_info;
+ums_scheduler_startup_info_tcase_t sched_info_tcase = {
+ .sched_info = &sched_info
+};
+pthread_t scheduler;
+
+ums_attr_t ums_attr = { 0 };
+
+void setup(void)
+{
+ create_ums_completion_list(&comp_list);
+ sched_info.completion_list = comp_list;
+ ums_attr.completion_list = comp_list;
+}
+
+void teardown(void)
+{
+ delete_ums_completion_list(&comp_list);
+}
+
+static void *sched_pthread_proc(void *arg)
+{
+ ums_scheduler_startup_info_tcase_t *sched_info = arg;
+
+ ck_assert_int_eq(enter_ums_scheduling_mode(sched_info->sched_info),
+ sched_info->expected_retval);
+
+ return NULL;
+}
+
+static void startup_sched_entry_proc(ums_reason_t reason,
+ ums_activation_t *activation,
+ void *args)
+{
+ pthread_exit(NULL);
+}
+
+static void dequeue_comp_list_sched_entry_proc(ums_reason_t reason,
+ ums_activation_t *activation,
+ void *args)
+{
+ ums_context_t context;
+
+ ck_assert_int_eq(
+ dequeue_ums_completion_list_items(comp_list, &context),
+ 0
+ );
+ pthread_exit(NULL);
+}
+
+static void dequeue_comp_list_sched_entry_proc_bad(ums_reason_t reason,
+ ums_activation_t *activation,
+ void *args)
+{
+ ck_assert_int_eq(
+ dequeue_ums_completion_list_items(comp_list, NULL),
+ -1
+ );
+ pthread_exit(NULL);
+}
+
+static void next_comp_list_sched_entry_proc(ums_reason_t reason,
+ ums_activation_t *activation,
+ void *args)
+{
+ ums_context_t context_list;
+
+ ck_assert_int_eq(
+ dequeue_ums_completion_list_items(comp_list, &context_list),
+ 0
+ );
+ ck_assert_int_gt(
+ get_next_ums_list_item(context_list),
+ 0
+ );
+ pthread_exit(NULL);
+}
+
+static void *work_pthread_proc(void *arg)
+{
+ return NULL;
+}
+
+START_TEST(test_enter_ums_scheduling_mode)
+{
+ sched_info.ums_scheduler_entry_point = startup_sched_entry_proc;
+ sched_info_tcase.expected_retval = 0;
+
+ pthread_create(&scheduler, NULL, sched_pthread_proc,
+ &sched_info_tcase);
+
+ pthread_join(scheduler, NULL);
+}
+END_TEST
+
+START_TEST(test_enter_ums_scheduling_mode_bad)
+{
+ ums_scheduler_startup_info_t *old = sched_info_tcase.sched_info;
+ sched_info_tcase.sched_info = NULL;
+ sched_info_tcase.expected_retval = -1;
+
+ pthread_create(&scheduler, NULL, sched_pthread_proc,
+ &sched_info_tcase);
+
+ pthread_join(scheduler, NULL);
+
+ sched_info_tcase.sched_info = old;
+}
+END_TEST
+
+START_TEST(test_ums_scheduler_dequeue_comp_list)
+{
+ pthread_t worker;
+
+ sched_info.ums_scheduler_entry_point =
+ dequeue_comp_list_sched_entry_proc;
+ sched_info_tcase.expected_retval = 0;
+
+ ck_assert_int_eq(
+ ums_pthread_create(&worker, &ums_attr, work_pthread_proc, NULL),
+ 0
+ );
+
+ pthread_create(&scheduler, NULL, sched_pthread_proc,
+ &sched_info_tcase);
+
+ pthread_join(worker, NULL);
+ pthread_join(scheduler, NULL);
+}
+END_TEST
+
+START_TEST(test_ums_scheduler_dequeue_comp_list_bad)
+{
+ sched_info.ums_scheduler_entry_point =
+ dequeue_comp_list_sched_entry_proc_bad;
+ sched_info_tcase.expected_retval = 0;
+
+ pthread_create(&scheduler, NULL, sched_pthread_proc,
+ &sched_info_tcase);
+
+ pthread_join(scheduler, NULL);
+}
+END_TEST
+
+START_TEST(test_ums_scheduler_next_comp_list)
+{
+ pthread_t worker1, worker2;
+
+ sched_info.ums_scheduler_entry_point =
+ next_comp_list_sched_entry_proc;
+ sched_info_tcase.expected_retval = 0;
+
+ ck_assert_int_eq(
+ ums_pthread_create(&worker1, &ums_attr,
+ work_pthread_proc, NULL),
+ 0
+ );
+ ck_assert_int_eq(
+ ums_pthread_create(&worker2, &ums_attr,
+ work_pthread_proc, NULL),
+ 0
+ );
+
+ pthread_create(&scheduler, NULL, sched_pthread_proc,
+ &sched_info_tcase);
+
+ pthread_join(worker1, NULL);
+ pthread_join(worker2, NULL);
+ pthread_join(scheduler, NULL);
+}
+END_TEST
+
+Suite *create_ums_scheduler_suite(void)
+{
+ Suite *s;
+ TCase *tc_core;
+
+ s = suite_create("UMS Scheduler Suite");
+
+ tc_core = tcase_create("UMS Scheduler");
+
+ tcase_add_checked_fixture(tc_core, setup, teardown);
+ tcase_add_test(tc_core, test_enter_ums_scheduling_mode);
+ tcase_add_test(tc_core, test_enter_ums_scheduling_mode_bad);
+ tcase_add_test(tc_core, test_ums_scheduler_dequeue_comp_list);
+ tcase_add_test(tc_core, test_ums_scheduler_dequeue_comp_list_bad);
+ tcase_add_test(tc_core, test_ums_scheduler_next_comp_list);
+
+ suite_add_tcase(s, tc_core);
+
+ return s;
+}
+
+int main(void)
+{
+ int number_failed;
+ Suite *s;
+ SRunner *sr;
+
+ s = create_ums_scheduler_suite();
+ sr = srunner_create(s);
+
+ srunner_run_all(sr, CK_NORMAL);
+ number_failed = srunner_ntests_failed(sr);
+ srunner_free(sr);
+ return (number_failed == 0) ? EXIT_SUCCESS : EXIT_FAILURE;
+}
diff --git a/src/lib/tests/check_ums_worker.c b/src/lib/tests/check_ums_worker.c
new file mode 100644
index 0000000..44e4572
--- /dev/null
+++ b/src/lib/tests/check_ums_worker.c
@@ -0,0 +1,113 @@
+// SPDX-License-Identifier: AGPL-3.0-only
+
+#include
+
+#include
+#include
+
+ums_completion_list_t comp_list;
+pthread_t worker;
+
+void setup(void)
+{
+ create_ums_completion_list(&comp_list);
+}
+
+void teardown(void)
+{
+ delete_ums_completion_list(&comp_list);
+}
+
+static void *work_pthread_proc(void *arg)
+{
+ return NULL;
+}
+
+static void *work_pthread_yield_proc(void *arg)
+{
+ ck_assert_int_eq(ums_thread_yield(NULL), 0);
+}
+
+START_TEST(test_enter_ums_worker_mode)
+{
+ ums_attr_t ums_attr = { 0 };
+
+ ums_attr.completion_list = comp_list;
+
+ ck_assert_int_eq(
+ ums_pthread_create(&worker, &ums_attr, work_pthread_proc, NULL),
+ 0
+ );
+
+ pthread_join(worker, NULL);
+}
+END_TEST
+
+START_TEST(test_enter_ums_worker_mode_bad)
+{
+ ums_attr_t ums_attr = { 0 };
+
+ ums_attr.completion_list = comp_list;
+
+ ck_assert_int_eq(
+ ums_pthread_create(&worker, NULL, work_pthread_proc, NULL),
+ -1
+ );
+ ck_assert_int_eq(
+ ums_pthread_create(&worker, &ums_attr, NULL, NULL),
+ -1
+ );
+}
+END_TEST
+
+START_TEST(test_ums_worker_yield)
+{
+ ums_attr_t ums_attr = { 0 };
+
+ ums_attr.completion_list = comp_list;
+
+ ck_assert_int_eq(
+ ums_pthread_create(&worker,
+ &ums_attr,
+ work_pthread_yield_proc,
+ NULL),
+ 0
+ );
+
+ pthread_join(worker, NULL);
+}
+END_TEST
+
+Suite *create_ums_worker_suite(void)
+{
+ Suite *s;
+ TCase *tc_core;
+
+ s = suite_create("UMS Worker Suite");
+
+ tc_core = tcase_create("UMS Worker");
+
+ tcase_add_checked_fixture(tc_core, setup, teardown);
+ tcase_add_test(tc_core, test_enter_ums_worker_mode);
+ tcase_add_test(tc_core, test_enter_ums_worker_mode_bad);
+ tcase_add_test(tc_core, test_ums_worker_yield);
+
+ suite_add_tcase(s, tc_core);
+
+ return s;
+}
+
+int main(void)
+{
+ int number_failed;
+ Suite *s;
+ SRunner *sr;
+
+ s = create_ums_worker_suite();
+ sr = srunner_create(s);
+
+ srunner_run_all(sr, CK_NORMAL);
+ number_failed = srunner_ntests_failed(sr);
+ srunner_free(sr);
+ return (number_failed == 0) ? EXIT_SUCCESS : EXIT_FAILURE;
+}
diff --git a/src/lib/tests/mock_ums_syscalls.c b/src/lib/tests/mock_ums_syscalls.c
new file mode 100644
index 0000000..af19e6a
--- /dev/null
+++ b/src/lib/tests/mock_ums_syscalls.c
@@ -0,0 +1,120 @@
+// SPDX-License-Identifier: AGPL-3.0-only
+
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+#include "ums/ums_ioctl.h"
+
+// TODO: implement better test fixtures
+static int UMS_FILENO = (INT_MAX >> 2);
+static ums_comp_list_id_t ums_complist_id = 1;
+static pid_t ums_context = 1;
+static pid_t next_ums_context = 1;
+
+int __real_open(const char *pathname, int flags, ...);
+int __real_close(int fd);
+int __real_ioctl(int fd, unsigned long request, ...);
+
+int __wrap_open(const char *pathname, int flags, ...)
+{
+ va_list args;
+ int retval;
+
+ if (!strncmp(pathname, "/dev/ums", 8))
+ return UMS_FILENO;
+
+ va_start(args, flags);
+ retval = __real_open(pathname, flags, args);
+ va_end(args);
+
+ return retval;
+}
+
+int __wrap_close(int fd)
+{
+ if (fd == UMS_FILENO)
+ return 0;
+
+ return __real_close(fd);
+}
+
+static int ums_ioctl(int fd, unsigned long request, unsigned long arg)
+{
+ ums_comp_list_id_t comp_list;
+ ums_comp_list_id_t *comp_listp;
+ struct enter_ums_mode_args *enter_ums_args;
+ struct ums_sched_event *sched_event_args;
+ struct dequeue_ums_complist_args *dequeue_args;
+ struct ums_next_context_list_args *next_context_args;
+
+ switch (request) {
+ case IOCTL_CREATE_UMS_CLIST:
+ comp_listp = (ums_comp_list_id_t *) arg;
+ *comp_listp = ums_complist_id;
+ return 0;
+ case IOCTL_DELETE_UMS_CLIST:
+ comp_list = (ums_comp_list_id_t) arg;
+ /* completion list not found */
+ if (comp_list != ums_complist_id) {
+ errno = EINVAL;
+ return -1;
+ }
+ return 0;
+ case IOCTL_ENTER_UMS:
+ enter_ums_args = (struct enter_ums_mode_args *) arg;
+ if (enter_ums_args->flags == ENTER_UMS_SCHED)
+ return 0;
+ else if (enter_ums_args->flags == ENTER_UMS_WORK)
+ return 0;
+ break;
+ case IOCTL_UMS_SCHED_DQEVENT:
+ return 0;
+ case IOCTL_DEQUEUE_UMS_CLIST:
+ dequeue_args = (struct dequeue_ums_complist_args *) arg;
+ /* completion list not found */
+ if (dequeue_args->ums_complist != ums_complist_id) {
+ errno = EINVAL;
+ return -1;
+ }
+ dequeue_args->ums_context = ums_context;
+ return 0;
+ case IOCTL_NEXT_UMS_CTX_LIST:
+ next_context_args = (struct ums_next_context_list_args *) arg;
+
+ if (next_context_args->ums_context != ums_context)
+ next_context_args->ums_next_context = -1;
+
+ next_context_args->ums_next_context = next_ums_context;
+
+ return 0;
+ case IOCTL_UMS_YIELD:
+ return 0;
+ default:
+ errno = ENOTSUP;
+ return -1;
+ }
+
+ return -1;
+}
+
+int __wrap_ioctl(int fd, unsigned long request, ...)
+{
+ va_list args;
+ int retval;
+
+ va_start(args, request);
+
+ if (fd == UMS_FILENO)
+ retval = ums_ioctl(fd, request, va_arg(args, unsigned long));
+ else
+ retval = __real_ioctl(fd, request, args);
+
+ va_end(args);
+
+ return retval;
+}
diff --git a/src/module/Makefile.am b/src/module/Makefile.am
index f229f11..d7d1c42 100644
--- a/src/module/Makefile.am
+++ b/src/module/Makefile.am
@@ -64,15 +64,17 @@ $(module_DATA): $(automake_dummy_SOURCES) FORCE
$(MAKE) -C $(KERNELDIR) M=$(abs_builddir)/src modules
install-moduleDATA: $(module_DATA)
- @test -z $(DESTDIR)$(moduledir) || \
- $(MKDIR_P) $(DESTDIR)$(moduledir)
+ $(mkinstalldirs) $(DESTDIR)$(moduledir)
$(INSTALL_DATA) $(abs_builddir)/src/ums.ko $(DESTDIR)$(moduledir)/ums.ko
uninstall-moduleDATA:
$(RM) $(DESTDIR)$(moduledir)/ums.ko
+if SANDBOXED
+else
install-data-local: install-moduleDATA
$(DEPMOD) -a
+endif
uninstall-local: uninstall-moduleDATA
diff --git a/src/module/configure.ac b/src/module/configure.ac
index 1a504b8..6fa4783 100644
--- a/src/module/configure.ac
+++ b/src/module/configure.ac
@@ -16,6 +16,7 @@ AC_SUBST([with_kernel], [`uname -r`])
AC_ARG_VAR([KERNELDIR], ["linux kernel dir"])
+AM_CONDITIONAL([SANDBOXED], [test x$KERNELDIR != x])
AS_IF([test "x$KERNELDIR" = x], [
[KERNELDIR=/lib/modules/$with_kernel/build]
[moduledir=/lib/modules/$with_kernel/extra]