]> git.tuebingen.mpg.de Git - paraslash.git/commitdiff
Merge branch 't/alsa_improvements'
authorAndre Noll <maan@systemlinux.org>
Sun, 6 Nov 2011 11:14:17 +0000 (12:14 +0100)
committerAndre Noll <maan@systemlinux.org>
Sun, 6 Nov 2011 11:20:28 +0000 (12:20 +0100)
NEWS
net.h
server.c
signal.c
signal.h
t/makefile.test
t/t0001-oggdec-correctness.sh
t/t0004-server.sh [new file with mode: 0755]
t/test-lib.sh
vss.c
web/download.in.html

diff --git a/NEWS b/NEWS
index 6db7225350f014f80e3f0ad831fe60b93d2777b9..a79cc29ff044e1bd5f23b3eb5da65cb636ecad5f 100644 (file)
--- a/NEWS
+++ b/NEWS
@@ -9,6 +9,12 @@
        - Shared memory areas are no longer restricted to 64K. We now
          detect the maximal size of a shared memory area at runtime.
        - cleanup of the internal uptime API.
+       - para_server prefaults the mmapped audio file to avoid
+         delays on slow media.
+       - A new test for the test-suite that exercises the
+         communication between para_server and para_audiod.
+       - The alsa writer eats up less CPU cycles when configured to
+         use the DMIX plugin.
 
 --------------------------------------
 0.4.8 (2011-08-19) "nested assignment"
diff --git a/net.h b/net.h
index 80f5794466fe74b8dbb429ad2ae2d38415945dba..79c5994c43ec2b0b6ae8fee1933b492c9f97a20d 100644 (file)
--- a/net.h
+++ b/net.h
@@ -8,13 +8,15 @@
 /** \file net.h exported symbols from net.c */
 
 /**
- * the buffer size of the sun_path component of struct sockaddr_un
+ * The buffer size of the sun_path component of struct sockaddr_un.
  *
- * While glibc doesn't define \p UNIX_PATH_MAX, it
- * documents it has being limited to 108 bytes.
+ * While glibc doesn't define \p UNIX_PATH_MAX, it documents it has being
+ * limited to 108 bytes. On NetBSD it is only 104 bytes though. We trust \p
+ * UNIX_PATH_MAX if it is defined and use the size of the ->sun_path member
+ * otherwise. This should be safe everywhere.
  */
 #ifndef UNIX_PATH_MAX
-#define UNIX_PATH_MAX 108
+#define UNIX_PATH_MAX (sizeof(((struct sockaddr_un *)0)->sun_path))
 #endif
 
 /* Userland defines for Linux DCCP support. */
index 15ae5c9a296be654471fd1f95aa9395629fae097..0cfac60722d825fddb4714dfba651eb8265e770a 100644 (file)
--- a/server.c
+++ b/server.c
@@ -434,7 +434,7 @@ err:
        exit(EXIT_FAILURE);
 }
 
-static int init_afs(void)
+static int init_afs(int argc, char **argv)
 {
        int ret, afs_server_socket[2];
        pid_t afs_pid;
@@ -448,6 +448,10 @@ static int init_afs(void)
        if (afs_pid < 0)
                exit(EXIT_FAILURE);
        if (afs_pid == 0) { /* child (afs) */
+               int i;
+               for (i = argc - 1; i >= 0; i--)
+                       memset(argv[i], 0, strlen(argv[i]));
+               sprintf(argv[0], "para_server (afs)");
                close(afs_server_socket[0]);
                afs_init(afs_socket_cookie, afs_server_socket[1]);
        }
@@ -462,12 +466,6 @@ static int init_afs(void)
        return afs_server_socket[0];
 }
 
-__noreturn static void tmp_sigchld_handler(__a_unused int s)
-{
-       PARA_EMERG_LOG("caught early SIGCHLD\n");
-       exit(EXIT_FAILURE);
-}
-
 static void server_init(int argc, char **argv)
 {
        struct server_cmdline_parser_params params = {
@@ -493,6 +491,7 @@ static void server_init(int argc, char **argv)
        gettimeofday(now, NULL);
        set_server_start_time(now);
        init_user_list(user_list_file);
+       init_server_command_task(argc, argv);
        /* become daemon */
        if (conf.daemon_given)
                daemonize();
@@ -508,17 +507,18 @@ static void server_init(int argc, char **argv)
         */
        para_sigaction(SIGUSR1, SIG_IGN);
        /*
-        * We have to install a SIGCHLD handler before the afs process is being
-        * forked off. Otherwise, para_server does not notice if afs dies before
-        * the SIGCHLD handler has been installed by init_signal_task() below.
+        * We have to block SIGCHLD before the afs process is being forked off.
+        * Otherwise, para_server does not notice if afs dies before the
+        * SIGCHLD handler has been installed for the parent process by
+        * init_signal_task() below.
         */
-       para_sigaction(SIGCHLD, tmp_sigchld_handler);
+       para_block_signal(SIGCHLD);
        PARA_NOTICE_LOG("initializing the audio file selector\n");
-       afs_socket = init_afs();
+       afs_socket = init_afs(argc, argv);
        init_signal_task();
+       para_unblock_signal(SIGCHLD);
        PARA_NOTICE_LOG("initializing virtual streaming system\n");
        init_vss_task(afs_socket);
-       init_server_command_task(argc, argv);
        PARA_NOTICE_LOG("server init complete\n");
 }
 
index f02c453a04a02e5d3e1c8a9c791aba8275a60671..aa63c8b5461a9627c021a514b83b7c8ee1067067 100644 (file)
--- a/signal.c
+++ b/signal.c
@@ -147,10 +147,50 @@ void para_install_sighandler(int sig)
        para_sigaction(sig, &generic_signal_handler);
 }
 
+/**
+ * Block a signal for the caller.
+ *
+ * \param sig The signal to block.
+ *
+ * This sets the given signal in the current signal mask of the calling process
+ * to prevent this signal from delivery.
+ *
+ * \sa \ref para_unblock_signal(), sigprocmask(2), sigaddset(3).
+ */
+void para_block_signal(int sig)
+{
+       sigset_t set;
+
+       PARA_DEBUG_LOG("blocking signal %d\n", sig);
+       sigemptyset(&set);
+       sigaddset(&set, sig);
+       sigprocmask(SIG_BLOCK, &set, NULL);
+}
+
+/**
+ * Unblock a signal.
+ *
+ * \param sig The signal to unblock.
+ *
+ * This function removes the given signal from the current set of blocked
+ * signals.
+ *
+ * \sa \ref para_block_signal(), sigprocmask(2), sigaddset(3).
+ */
+void para_unblock_signal(int sig)
+{
+       sigset_t set;
+
+       PARA_DEBUG_LOG("unblocking signal %d\n", sig);
+       sigemptyset(&set);
+       sigaddset(&set, sig);
+       sigprocmask(SIG_UNBLOCK, &set, NULL);
+}
+
 /**
  * Return the number of the next pending signal.
  *
- * \param rfds Th fd_set containing the signal pipe.
+ * \param rfds The fd_set containing the signal pipe.
  *
  * \return On success, the number of the received signal is returned. If there
  * is no signal currently pending, the function returns zero. On read errors
index 799c317fd6114046334c8577fabbe767e20eea94..266b3aba4df97de8c4ecafbaaa03065840f99f01 100644 (file)
--- a/signal.h
+++ b/signal.h
@@ -22,3 +22,5 @@ void para_install_sighandler(int);
 int para_reap_child(pid_t *pid);
 int para_next_signal(fd_set *rfds);
 void para_signal_shutdown(void);
+void para_block_signal(int sig);
+void para_unblock_signal(int sig);
index d4aedf8035b1645da0b0fcb532e814d5d7ef10d6..4bbc5d72edb0adfd2b997d667bac2d67de2f72b6 100644 (file)
@@ -15,7 +15,7 @@ ifdef V
        endif
 endif
 
-tests := $(wildcard $(test_dir)/t[0-9][0-9][0-9][0-9]-*.sh)
+tests := $(sort $(wildcard $(test_dir)/t[0-9][0-9][0-9][0-9]-*.sh))
 
 test: $(tests)
 
index 01260e5cae1c52551cb83c7bb53b9412c82bcb67..554dfdf85dd654ef81c3114a847102ede377e6bc 100755 (executable)
@@ -11,7 +11,7 @@ implementation.'
 test_require_objects "oggdec_filter"
 missing_objects="$result"
 
-test_require_executables "oggdec"
+test_require_executables oggdec sha1sum
 missing_executables="$result"
 
 get_audio_file_paths ogg
diff --git a/t/t0004-server.sh b/t/t0004-server.sh
new file mode 100755 (executable)
index 0000000..c79ea24
--- /dev/null
@@ -0,0 +1,125 @@
+#!/usr/bin/env bash
+
+test_description='Check if server command socket works.
+
+A new ssh key pair is generated, para_server is started and some commands are
+sent to the server by executing para_client. This is an implicit check of the
+crypto functions.
+'
+
+. ${0%/*}/test-lib.sh
+
+loglevel=debug
+port=2991
+stream_port=8001
+# need absolute paths here because server cds to / in daemon mode
+db=$(pwd)/db
+sock=$(pwd)/sock
+user_list=ul
+privkey=key
+pubkey=$privkey.pub
+serverlog=server.log
+
+get_audio_file_paths ogg
+oggs="$result"
+
+declare -a commands=() cmdline=() required_objects=() good=() bad=()
+i=0
+commands[$i]="help"
+cmdline[$i]="help"
+good[$i]='help server  ----'
+
+let i++
+commands[$i]="init"
+cmdline[$i]="init"
+good[$i]='^successfully'
+bad[$i]='!^successfully'
+
+let i++
+commands[$i]="add_ogg"
+required_objects[$i]='ogg_afh'
+cmdline[$i]="add $oggs"
+bad[$i]='.'
+
+let i++
+commands[$i]="ls_ogg"
+required_objects[$i]='ogg_afh'
+cmdline[$i]="ls -lv -p $oggs"
+good[$i]='^path:'
+
+let i++
+commands[$i]="term"
+cmdline[$i]="term"
+bad[$i]='.'
+
+test_require_objects "server"
+missing_objects="$result"
+test_require_executables "ssh-keygen"
+missing_executables="$result"
+
+ssh-keygen -q -t rsa -b 2048 -N "" -f $privkey
+key_gen_result=$?
+
+read &>/dev/null < /dev/tcp/localhost/$port
+check_port_result=$?
+
+cat > $user_list << EOF
+user $LOGNAME $pubkey AFS_READ,AFS_WRITE,VSS_READ,VSS_WRITE
+EOF
+
+# para_server sends this signal to all processes in the current process group.
+trap "" SIGUSR1
+
+$PARA_SERVER \
+       --logfile "$serverlog" \
+       --config_file /dev/null \
+       --daemon \
+       --loglevel $loglevel \
+       --port $port \
+       --afs_database_dir "$db" \
+       --afs_socket "$sock" \
+       --user_list "$user_list" \
+       --http_port "$stream_port" \
+       --dccp_port "$stream_port"
+
+for ((i=0; i < ${#commands[@]}; i++)); do
+       command=${commands[$i]}
+       if [[ -n "$missing_objects" ]]; then
+               test_skip "$command" "missing object(s): $missing_objects"
+               continue
+       fi
+       if [[ -n "$missing_executables" ]]; then
+               test_skip "$command" \
+                       "missing executables(s): $missing_executables"
+               continue
+       fi
+       if (($key_gen_result != 0)); then
+               test_skip "$command" "ssh-keygen failed"
+               continue
+       fi
+       if (($check_port_result == 0)); then
+               test_skip "$command" "port $port already in use"
+               continue
+       fi
+       if [[ -n "${required_objects[$i]}" ]]; then
+               test_require_objects "${required_objects[$i]}"
+               if [[ -n "$result" ]]; then
+                       test_skip "$command" "requires object $result"
+                       continue
+               fi
+       fi
+       test_expect_success "$command" "
+       $PARA_CLIENT \
+               --loglevel $loglevel \
+               --server_port $port \
+               --key_file $privkey \
+               --config_file /dev/null \
+               -- \
+               ${cmdline[$i]} > $command.out &&
+               { [[ -z \"${good[$i]}\" ]] || grep \"${good[$i]}\"; } < $command.out &&
+               { [[ -z \"${bad[$i]}\" ]]  || ! grep \"${bad[$i]}\"; } < $command.out
+       "
+done
+
+trap SIGUSR1 # reset to the value it had upon entrance to the shell
+test_done
index b7d675ea0def671529e13732c52143bb22290288..f1bb8cf65b66ff3890659f2b6009bae08d3cbd77 100644 (file)
@@ -162,7 +162,7 @@ test_duration()
 test_expect_success()
 {
        (($# != 2)) && error "bug: not 2 parameters to test_expect_success()"
-       say >&3 "expecting success: $2"
+       echo >&3 "expecting success: $2"
        _test_run "$1" "$2" "success"
        echo >&3 ""
 }
@@ -170,7 +170,7 @@ test_expect_success()
 test_expect_failure()
 {
        (($# != 2)) && error "bug: not 2 parameters to test_expect_failure()"
-       say >&3 "expecting failure: $2"
+       echo >&3 "expecting failure: $2"
        _test_run "$1" "$2" "failure"
        echo >&3 ""
 }
diff --git a/vss.c b/vss.c
index f6da52dd6cc933f66a746095389ad1510452d0e4..e336a9e7413d469c71a6221cab0e86b0aae24867 100644 (file)
--- a/vss.c
+++ b/vss.c
@@ -953,6 +953,10 @@ static int recv_afs_msg(int afs_socket, int *fd, uint32_t *code, uint32_t *data)
        return 1;
 }
 
+#ifndef MAP_POPULATE
+#define MAP_POPULATE 0
+#endif
+
 static void recv_afs_result(struct vss_task *vsst, fd_set *rfds)
 {
        int ret, passed_fd, shmid;
@@ -987,8 +991,8 @@ static void recv_afs_result(struct vss_task *vsst, fd_set *rfds)
        }
        mmd->size = statbuf.st_size;
        mmd->mtime = statbuf.st_mtime;
-       ret = para_mmap(mmd->size, PROT_READ, MAP_PRIVATE, passed_fd,
-               0, &vsst->map);
+       ret = para_mmap(mmd->size, PROT_READ, MAP_PRIVATE | MAP_POPULATE,
+               passed_fd, 0, &vsst->map);
        if (ret < 0)
                goto err;
        close(passed_fd);
@@ -1077,6 +1081,23 @@ static void vss_send(struct vss_task *vsst)
                }
                mmd->chunks_sent++;
                mmd->current_chunk++;
+               /*
+                * Prefault next chunk(s)
+                *
+                * If the backing device of the memory-mapped audio file is
+                * slow and read-ahead is turned off or prevented for some
+                * reason, e.g. due to memory pressure, it may take much longer
+                * than the chunk interval to get the next chunk on the wire,
+                * causing buffer underruns on the client side. Mapping the
+                * file with MAP_POPULATE seems to help a bit, but it does not
+                * eliminate the delays completely. Moreover, it is supported
+                * only on Linux. So we do our own read-ahead here.
+                */
+               buf += len;
+               for (i = 0; i < 5 && buf < vsst->map + mmd->size; i++) {
+                       __a_unused volatile char x = *buf;
+                       buf += 4096;
+               }
        }
 }
 
index d735d5e8f8b2cb25d24059f0741e16f03dea3411..1da6c3639360bd3fc99226c9bf3662aff9a97516 100644 (file)
@@ -1,25 +1,13 @@
 <h1>Download</h1>
 <hr>
 
-<p> Download the latest version from the
+<p> Clone the git repository by executing </p>
 
-<a href="versions/">download directory</a>
+<p> <b> git clone git://paraslash.systemlinux.org/git paraslash </b> </p>
 
-or grab a
-
-<a href="versions/paraslash-git.tar.bz2">tarball</a>
-
-of the current master branch. This version is expected to be more
-stable than any of the released versions.
-
-All regular releases are <a href="PUBLIC_KEY">cryptographically signed</a>.
-
-Anonymous (read-only)
-
-<a href="http://www.kernel.org/pub/software/scm/git/docs/">git</a>
-
-access is also available. Check out a copy with </p>
-
-<p>
-git clone git://paraslash.systemlinux.org/git paraslash
-</p>
+<p> Or grab the <a href="versions/paraslash-git.tar.bz2">tarball</a>
+of the current master branch, or download the latest version from the
+<a href="versions/">download directory</a>. All regular releases are
+<a href="PUBLIC_KEY">cryptographically signed</a>. Since development
+takes place in separate topic branches the master branch is expected
+to be more stable than any of the released versions. </p>