]> git.tuebingen.mpg.de Git - paraslash.git/commitdiff
Merge branch 't/configure_improvements'
authorAndre Noll <maan@systemlinux.org>
Sun, 3 Apr 2011 15:27:32 +0000 (17:27 +0200)
committerAndre Noll <maan@systemlinux.org>
Sun, 3 Apr 2011 15:27:32 +0000 (17:27 +0200)
35 files changed:
Makefile.in
NEWS
afs.c
aft.c
alsa_write.c
audiod.c
audiod.cmd
audiod.h
audiod_command.c
autogen.sh
command.c
error.h
fade.c
fec.c
grab_client.c
mm.c
oss_write.c
para.h
sched.c
sched.h
stdin.h
t/.gitignore [new file with mode: 0644]
t/audio_files/short-44100-2.ogg [new file with mode: 0644]
t/makefile.test [new file with mode: 0644]
t/t0000-help-output.sh [new file with mode: 0755]
t/t0001-oggdec-correctness.sh [new file with mode: 0755]
t/t0002-oggdec-performance.sh [new file with mode: 0755]
t/t0003-writer-init-error-path.sh [new file with mode: 0755]
t/test-lib.sh [new file with mode: 0644]
udp_send.c
versions/paraslash-0.4.6.tar.bz2 [new file with mode: 0644]
versions/paraslash-0.4.6.tar.bz2.asc [new file with mode: 0644]
web/index.in.html
web/manual.m4
write.c

index ff5150b6e2f1f22904665e234ffc5ace51cecf01..8963adad3b7339a1ff6b750f69b597acde1c49f6 100644 (file)
@@ -9,15 +9,19 @@ PACKAGE_VERSION := @PACKAGE_VERSION@
 PACKAGE_STRING := @PACKAGE_STRING@
 install_sh := @install_sh@
 cmdline_dir := @cmdline_dir@
+executables := @executables@
 
 build_date := $(shell date)
 uname_s := $(shell uname -s 2>/dev/null || echo "UNKNOWN_OS")
 uname_rs := $(shell uname -rs)
 cc_version := $(shell $(CC) --version | head -n 1)
-codename := deterministic entropy
+codename := infinite rollback
 
 DEBUG_CPPFLAGS += -Wno-sign-compare -g -Wunused -Wundef -W
 DEBUG_CPPFLAGS += -Wredundant-decls
+DEBUG_CPPFLAGS += -Wall
+DEBUG_CPPFLAGS += -Wformat-security
+DEBUG_CPPFLAGS += -Wmissing-format-attribute
 # produces false positives
 # DEBUG_CPPFLAGS += -Wunreachable-code
 # DEBUG_CPPFLAGS += -Wwrite-strings
@@ -37,17 +41,14 @@ ifeq ($(uname_s),Linux)
        CPPFLAGS += -Wshadow
 endif
 CPPFLAGS += -Os
-CPPFLAGS += -Wall
 CPPFLAGS += -Wuninitialized
 CPPFLAGS += -Wchar-subscripts
-CPPFLAGS += -Wformat-security
 CPPFLAGS += -DBINDIR='"$(BINDIR)"'
 CPPFLAGS += -DBUILD_DATE='"$(build_date)"'
 CPPFLAGS += -DUNAME_RS='"$(uname_rs)"'
 CPPFLAGS += -DCODENAME='"$(codename)"'
 CPPFLAGS += -DCC_VERSION='"$(cc_version)"'
 CPPFLAGS += -Werror-implicit-function-declaration
-CPPFLAGS += -Wmissing-format-attribute
 CPPFLAGS += -Wmissing-noreturn
 CPPFLAGS += -Wunused-macros
 CPPFLAGS += -Wbad-function-cast
@@ -66,6 +67,7 @@ man_pages_in := $(patsubst %, web/%.man.in.html, @executables@)
 ggo_dir := ggo
 object_dir := objects
 man_dir := man/man1
+test_dir := t
 
 m4_ggos := afh audioc audiod client filter gui recv server write
 all_ggos := $(m4_ggos) dccp_recv alsa_write oss_write fade http_recv \
@@ -92,10 +94,10 @@ endif
 ifndef BUILD_VERBOSE
        BUILD_VERBOSE = 0
 endif
-ifeq ($(BUILD_VERBOSE),1)
-       Q =
-else
+ifeq ($(BUILD_VERBOSE),0)
        Q = @
+else
+       Q =
 endif
 
 .PHONY: dep all clean distclean maintainer-clean install man tarball\
@@ -284,7 +286,7 @@ clean2: clean
        $(Q) rm -rf man $(object_dir)
        $(Q) rm -f *_command_list.*
 
-distclean: clean2
+distclean: clean2 test-clean
        @[ -z "$(Q)" ] || echo 'DISTCLEAN'
        $(Q) rm -f Makefile autoscan.log config.status config.log
        $(Q) rm -rf autom4te.cache aclocal.m4
@@ -320,3 +322,4 @@ $(tarball): $(cmdline_generated)
 %.pdf: %.ps
        ps2pdf - - < $< > $@
 
+include $(test_dir)/makefile.test
diff --git a/NEWS b/NEWS
index e6309e4a9fea5f4ec15f89a858fd9c0a0cbd4804..81fae3856a9190ed8e19a69a95c32fe504330131 100644 (file)
--- a/NEWS
+++ b/NEWS
@@ -1,9 +1,13 @@
------------------------------------------------
-0.4.6 (to be announced) "deterministic entropy"
------------------------------------------------
+-------------------------------------------
+0.4.7 (to be announced) "infinite rollback"
+-------------------------------------------
+
+------------------------------------------
+0.4.6 (2011-03-31) "deterministic entropy"
+------------------------------------------
 
-Lots of ogg/vorbis improvements, enhancements for para_gui and a fair
-amount of other bug fixes.
+Lots of ogg/vorbis improvements, the new test suite, enhancements
+for para_gui and a fair amount of other bug fixes.
 
        - For DCCP/OGG streams the audio file header is only sent once
          at the beginning of the stream rather than periodically
@@ -12,7 +16,11 @@ amount of other bug fixes.
        - The vorbis comment header is replaced by an empty dummy header
          before the header is sent over the network. This also results in
          less network traffic and smaller FEC groups.
+       - The new "test" make target allows to perform some sanity checks prior
+         to installing the package.
        - ogg timing fixes and performance improvements
+       - Scheduler improvements
+       - Proper exit codes for para_write
        - para_gui: New option --theme to select a startup theme. Several
          other improvements and fixes.
        - aacdec error message cleanups
diff --git a/afs.c b/afs.c
index c2fd6d52daa58ef4cf0a118ce855898465053f2b..0464eb77de8918f8b38d5a41c5a792212a271c5f 100644 (file)
--- a/afs.c
+++ b/afs.c
@@ -468,7 +468,6 @@ again:
        }
        ret = open_and_update_audio_file(aft_row, score, &afd);
        if (ret < 0) {
-               PARA_ERROR_LOG("%s\n", para_strerror(-ret));
                ret = score_delete(aft_row);
                if (ret < 0) {
                        PARA_ERROR_LOG("%s\n", para_strerror(-ret));
diff --git a/aft.c b/aft.c
index 266188b5b370a3e7e3e8aaa092ca093aca7c6c04..b3dde1379997bb6f69647255d0ac53fb703fce09 100644 (file)
--- a/aft.c
+++ b/aft.c
@@ -1136,6 +1136,8 @@ int open_and_update_audio_file(struct osl_row *aft_row, long score,
 err:
        free(afd->afhi.chunk_table);
        osl_close_disk_object(&chunk_table_obj);
+       if (ret < 0)
+               PARA_ERROR_LOG("%s: %s\n", path, para_strerror(-ret));
        return ret;
 }
 
index ae3bbfbab60c82ab26311c00b1d0389a7544ec5c..8cf5cfd25bf3909e0f4d338d2397ca0e017c29ab 100644 (file)
@@ -214,7 +214,7 @@ again:
        bytes = btr_next_buffer(btrn, &data);
        if (ret < 0 || bytes < wn->min_iqs) { /* eof */
                assert(btr_no_parent(btrn));
-               ret = -E_ALSA_EOF;
+               ret = -E_WRITE_COMMON_EOF;
                if (!pad)
                        goto err;
                /* wait until pending frames are played */
index 8b17d95fba692db0b2dd9126226cb8fb2cb682d5..e5db0cd2b075c726e931f22ea854d0b916b7e8ef 100644 (file)
--- a/audiod.c
+++ b/audiod.c
@@ -167,7 +167,7 @@ struct command_task {
  * \return The audio format number on success, -E_UNSUPPORTED_AUDIO_FORMAT if
  * \a name is not a supported audio format.
  */
-int get_audio_format_num(const char *name)
+static int get_audio_format_num(const char *name)
 {
        int i;
 
@@ -469,20 +469,6 @@ static int get_empty_slot(void)
        return -E_NO_MORE_SLOTS;
 }
 
-/**
- * get the number of filters
- *
- * \param audio_format_num the number identifying the audio format
- *
- * \return the number of filters for the given audio format
- *
- * \sa struct filter;
- */
-int num_filters(int audio_format_num)
-{
-       return afi[audio_format_num].num_filters;
-}
-
 static void open_filters(struct slot_info *s)
 {
        struct audio_format_info *a = afi + s->format;
@@ -1097,17 +1083,17 @@ static void try_to_close_slot(int slot_num)
 
        if (s->format < 0)
                return;
-       if (s->receiver_node && s->receiver_node->task.error != -E_TASK_UNREGISTERED)
+       if (s->receiver_node && s->receiver_node->task.error >= 0)
                return;
        for (i = 0; i < a->num_filters; i++)
-               if (s->fns && s->fns[i].task.error != -E_TASK_UNREGISTERED)
+               if (s->fns && s->fns[i].task.error >= 0)
                        return;
        if (a->num_writers > 0) {
                for (i = 0; i < a->num_writers; i++)
-                       if (s->wns && s->wns[i].task.error != -E_TASK_UNREGISTERED)
+                       if (s->wns && s->wns[i].task.error >= 0)
                                return;
        } else {
-               if (s->wns && s->wns[0].task.error != -E_TASK_UNREGISTERED)
+               if (s->wns && s->wns[0].task.error >= 0)
                        return;
        }
        PARA_INFO_LOG("closing slot %d\n", slot_num);
@@ -1188,7 +1174,7 @@ static void status_post_select(__a_unused struct sched *s, struct task *t)
                        kill_btrn(st->ct->btrn, &st->ct->task, -E_AUDIOD_OFF);
                        goto out;
                }
-               if (st->ct->task.error != -E_TASK_UNREGISTERED)
+               if (st->ct->task.error >= 0)
                        goto out;
                close_stat_pipe();
                st->clock_diff_count = conf.clock_diff_count_arg;
@@ -1199,7 +1185,7 @@ static void status_post_select(__a_unused struct sched *s, struct task *t)
                size_t sz;
                int ret;
                if (st->ct->task.error < 0) {
-                       if (st->ct->task.error != -E_TASK_UNREGISTERED)
+                       if (st->ct->task.error >= 0)
                                goto out;
                        close_stat_pipe();
                        goto out;
index 7ffe98e7d249368992568f42dcb1bc816eb7afb5..c58907448f12eeb44551b98d113c3ef52ba9979f 100644 (file)
@@ -14,7 +14,7 @@ H: on -> standby -> off -> on
 N: grab
 D: grab the audio stream
 L:
-U: -- grab [-m[{s|p|a}]] [-p=<parent>] [-n=<name>] [-o]
+U: -- grab [-m[{s|p|a}]] [-p=PARENT] [-n=NAME] [-o]
 H:
 H: grab ('splice') the audio stream at any position in the buffer
 H: tree and send that data back to the client.
@@ -35,7 +35,7 @@ H:    ready for writing (i.e. would block). Sloppy mode ignores
 H:     the write, pedantic mode aborts and aggressive mode tries
 H:     to write anyway.
 H:
-H: -p  Grab output of node <parent> of the buffer tree.
+H: -p  Grab output of node PARENT of the buffer tree.
 H:
 H: -n  Name of the new buffer tree node. Defaults to 'grab'.
 H:
@@ -49,11 +49,6 @@ H: in any way. But now these days are gone, I'm not so self assured. Now I find
 H: I've changed my mind and opened up the doors.
 H:                                                              -- Beatles: Help
 ---
-N: kill
-D: kill an active audiod task
-U: kill task_id [task_id ...]
-H: Simulate an error condition for the given task(s)
----
 N: off
 D: deactivate para_audiod
 U: off
index 94399602b22280afbe88304cad8d832349f26780..4c3212228ba5ad75dac7241d10c47ebdb0478652 100644 (file)
--- a/audiod.h
+++ b/audiod.h
@@ -7,9 +7,6 @@
 /** \file audiod.h symbols exported from audiod.c */
 
 
-int num_filters(int audio_format_num);
-int get_audio_format_num(const char *name);
-
 /** enum of audio formats supported by para_audiod */
 enum {AUDIOD_AUDIO_FORMATS_ENUM};
 
index eed9fc154c7191513c3e315a65fe552641823b1b..bfd7c4aa5df170235f24961813bc4cc2e69790fa 100644 (file)
@@ -301,21 +301,6 @@ int com_tasks(int fd, __a_unused int argc, __a_unused char **argv)
        return ret;
 }
 
-int com_kill(int fd, int argc, char **argv)
-{
-       int i, ret = 1;
-       if (argc < 2)
-               return -E_AUDIOD_SYNTAX;
-       for (i = 1; i < argc; i++) {
-               ret = kill_task(argv[i]);
-               if (ret < 0)
-                       break;
-       }
-       if (ret > 0)
-               close(fd);
-       return ret;
-}
-
 int com_stat(int fd, int argc, char **argv)
 {
        int i, ret, parser_friendly = 0;
index 76eaef2f38cad05ffd41d0bd7291f51601efcac7..a047f7c4d9f0bc704ade2ed049118c0eb3e02f7f 100755 (executable)
@@ -3,11 +3,11 @@ echo preparing...
 if test -f Makefile; then
        make maintainer-clean > /dev/null
 fi
-aclocal -I . &> /dev/null
+aclocal -I . > /dev/null 2>&1
 autoconf
 autoheader
 echo configuring...
 ./configure $@ > /dev/null
 echo compiling...
-make clean2 &> /dev/null
+make clean2 > /dev/null 2>&1
 make > /dev/null
index f9ef6cd75ab8733408d3c2542230ae806281bf85..5217f9b487cd260aebe5d5a986f4fd8e957b0270 100644 (file)
--- a/command.c
+++ b/command.c
@@ -255,7 +255,8 @@ int com_si(struct rc4_context *rc4c, int argc, __a_unused char * const * argv)
                free(info);
        }
        ut = uptime_str();
-       ret = rc4_send_va_buffer(rc4c, "up: %s\nplayed: %u\n"
+       ret = rc4_send_va_buffer(rc4c, "version: " GIT_VERSION "\n"
+               "up: %s\nplayed: %u\n"
                "server_pid: %d\n"
                "afs_pid: %d\n"
                "connections (active/accepted/total): %u/%u/%u\n"
diff --git a/error.h b/error.h
index 5a2e39b468fa58d7cb66bc3ca07f71012b02c2e2..fdd2d3b7b9b6b06f8e7ba0d6a457dc249c314b3e 100644 (file)
--- a/error.h
+++ b/error.h
@@ -103,7 +103,6 @@ extern const char **para_errlist[];
        PARA_ERROR(BAD_SAMPLE_FORMAT, "sample format not supported"), \
        PARA_ERROR(BAD_CHANNEL_COUNT, "channel count not supported"), \
        PARA_ERROR(BAD_SAMPLERATE, "sample rate not supported"), \
-       PARA_ERROR(OSS_EOF, "oss: end of file"), \
 
 
 #define COMPRESS_FILTER_ERRORS \
@@ -230,10 +229,8 @@ extern const char **para_errlist[];
 
 
 #define SCHED_ERRORS \
-       PARA_ERROR(TASK_KILLED, "task killed"), \
-       PARA_ERROR(TASK_UNREGISTERED, "task has been unscheduled"), \
-       PARA_ERROR(NO_SUCH_TASK, "task not found"), \
        PARA_ERROR(NOT_INITIALIZED, "scheduler not yet initialized"), \
+       PARA_ERROR(SCHED_SHUTDOWN, "scheduler was shut down"), \
 
 
 #define NET_ERRORS \
@@ -276,7 +273,6 @@ extern const char **para_errlist[];
 
 #define AUDIOD_COMMAND_ERRORS \
        PARA_ERROR(CLIENT_WRITE, "client write error"), \
-       PARA_ERROR(AUDIOD_SYNTAX, "syntax error"), \
        PARA_ERROR(UCRED_PERM, "permission denied"), \
        PARA_ERROR(INVALID_AUDIOD_CMD, "invalid command"), \
        PARA_ERROR(TOO_MANY_CLIENTS, "maximal number of stat clients exceeded"), \
@@ -396,7 +392,6 @@ extern const char **para_errlist[];
 
 #define WRITE_ERRORS \
        PARA_ERROR(WRITE_SYNTAX, "para_write syntax error"), \
-       PARA_ERROR(NO_WAV_HEADER, "wave header not found"), \
 
 
 #define ALSA_WRITE_ERRORS \
@@ -414,12 +409,11 @@ extern const char **para_errlist[];
        PARA_ERROR(SET_RATE, "snd_pcm_hw_params_set_rate_near failed"), \
        PARA_ERROR(START_THRESHOLD, "snd_pcm_sw_params_set_start_threshold() failed"), \
        PARA_ERROR(STOP_THRESHOLD, "snd_pcm_sw_params_set_stop_threshold() failed"), \
-       PARA_ERROR(ALSA_EOF, "alsa: end of file"), \
-
 
 
 #define WRITE_COMMON_ERRORS \
        PARA_ERROR(WRITE_COMMON_SYNTAX, "syntax error in write option"), \
+       PARA_ERROR(WRITE_COMMON_EOF, "end of file"), \
 
 
 #define AACDEC_FILTER_ERRORS \
diff --git a/fade.c b/fade.c
index 8eeb79e7d3f335b08ed1d2b8f3606e2fdec4cd6d..5fbd0dd48027ad990345aa5d8f86fa0d952e6188 100644 (file)
--- a/fade.c
+++ b/fade.c
@@ -125,6 +125,7 @@ static void fixup_mixer_channel_arg(void)
                case mixer_channel_arg_reclev: val = SOUND_MIXER_RECLEV; break;
                case mixer_channel_arg_igain: val = SOUND_MIXER_IGAIN; break;
                case mixer_channel_arg_ogain: val = SOUND_MIXER_OGAIN; break;
+               default: break;
        }
        conf.mixer_channel_arg = val;
 }
@@ -344,15 +345,15 @@ int main(int argc, char *argv[])
        }
        fixup_mixer_channel_arg();
        switch (conf.mode_arg) {
-       case mode_arg_sleep:
-               ret = sweet_dreams();
-               break;
        case mode_arg_fade:
                ret = fade(conf.fade_vol_arg, conf.fade_time_arg);
                break;
        case mode_arg_snooze:
                ret = snooze();
                break;
+       default: /* sleep mode */
+               ret = sweet_dreams();
+               break;
        }
        if (ret < 0)
                PARA_EMERG_LOG("%s\n", para_strerror(-ret));
diff --git a/fec.c b/fec.c
index dc6e75209473c3eb14c9d52324707f5329d398d0..233a87803ebcf06fe38d172473cfa15e23b17c96 100644 (file)
--- a/fec.c
+++ b/fec.c
@@ -179,14 +179,14 @@ static void generate_gf(void)
  * This is used often, so better optimize it! Currently the loop is unrolled 16
  * times. The case c=0 is also optimized, whereas c=1 is not.
  */
-static void addmul(unsigned char *dst1, const unsigned char const *src1,
+static void addmul(unsigned char *dst1, const unsigned char *src1,
        unsigned char c, int sz)
 {
        if (c == 0)
                return;
        unsigned char *dst = dst1, *lim = &dst[sz - UNROLL + 1],
                *col = gf_mul_table[c];
-       const unsigned char const *src = src1;
+       const unsigned char *src = src1;
 
        for (; dst < lim; dst += UNROLL, src += UNROLL) {
                dst[0] ^= col[src[0]];
index 8e6715036769dace2f633d867d4bdb436901b6e0..de6df6dfddae9d9f24e33323fadc762fd326acb0 100644 (file)
@@ -131,13 +131,12 @@ static void gc_activate(struct grab_client *gc)
        list_move(&gc->node, &active_grab_client_list);
        gc->btrn = btr_new_node(&(struct btr_node_description)
                EMBRACE(.name = name, .parent = parent));
-       if (!gc->task.pre_select) {
-               gc->task.pre_select = gc_pre_select;
-               gc->task.post_select = gc_post_select;
-               snprintf(gc->task.status, sizeof(gc->task.status) - 1, "%s", name);
-               gc->task.status[sizeof(gc->task.status) - 1] = '\0';
-               register_task(&gc->task);
-       }
+       gc->task.pre_select = gc_pre_select;
+       gc->task.post_select = gc_post_select;
+       snprintf(gc->task.status, sizeof(gc->task.status) - 1, "%s", name);
+       gc->task.status[sizeof(gc->task.status) - 1] = '\0';
+       gc->task.error = 0;
+       register_task(&gc->task);
 }
 
 /**
@@ -156,7 +155,7 @@ void activate_grab_clients(void)
        struct grab_client *gc, *tmp;
 
        list_for_each_entry_safe(gc, tmp, &inactive_grab_client_list, node) {
-               if (gc->task.error == -E_TASK_UNREGISTERED) {
+               if (gc->fd < 0) {
                        list_del(&gc->node);
                        free(gc);
                        continue;
@@ -179,11 +178,11 @@ static int gc_close(struct grab_client *gc, int err)
                 * post_select().
                 */
                close(gc->fd);
+               gc->fd = -1;
                free(gc->parent);
                free(gc->name);
                return 1;
        }
-       gc_activate(gc);
        return 0;
 }
 
@@ -210,7 +209,8 @@ static void gc_post_select(__a_unused struct sched *s, struct task *t)
                btr_consume(btrn, ret);
        return;
 err:
-       t->error = gc_close(gc, ret)? ret : 0;
+       gc_close(gc, ret);
+       t->error = ret;
 }
 
 static int gc_check_args(int argc, char **argv, struct grab_client *gc)
diff --git a/mm.c b/mm.c
index a9f4b9bd258f8f9e36733ea0fe295086ea0b3a49..af99a36f824ff533278ddbec219e10c6bff9a46b 100644 (file)
--- a/mm.c
+++ b/mm.c
@@ -32,7 +32,7 @@
 enum mood_comparator_id {MOOD_COMPARATORS NUM_MOOD_COMPARATORS};
 #undef MC
 #define MC(a, b) # b,
-static const char const *mood_comparators[] = {MOOD_COMPARATORS};
+static const char *mood_comparators[] = {MOOD_COMPARATORS};
 #undef MC
 
 static int parse_mood_comparator(const char *word)
index 70a58203db8a2f2e3eca5cfc12506334ed7133da..e79ea6ced6c62f3fdfe1b6ce59cf7f7784cb9614 100644 (file)
@@ -185,7 +185,7 @@ static void oss_post_select(__a_unused struct sched *s,
        bytes = btr_next_buffer(btrn, &data);
        frames = bytes / powd->bytes_per_frame;
        if (!frames) { /* eof and less than a single frame available */
-               ret = -E_OSS_EOF;
+               ret = -E_WRITE_COMMON_EOF;
                goto out;
        }
        ret = 0;
diff --git a/para.h b/para.h
index 29c5c2b89c4ac3e0ca820c26c07cd8be4755f266..08eb0ee6c20ab1a7779cc3f10de2b5fca094f44b 100644 (file)
--- a/para.h
+++ b/para.h
@@ -221,6 +221,9 @@ _static_inline_ long int para_random(unsigned max)
 /** Used to avoid a shortcoming in vim's syntax highlighting. */
 #define EMBRACE(...) { __VA_ARGS__}
 
+/** A nice cup of STFU for Mr gcc. */
+#define do_nothing do {/* nothing */} while (0)
+
 /**
  * The sample formats supported by paraslash.
  *
diff --git a/sched.c b/sched.c
index b0e9ce12f221e901d761108899d98190ccf984d6..9be3a2e83109f0db884c5fdebf3e7e62f4f9b3c5 100644 (file)
--- a/sched.c
+++ b/sched.c
@@ -38,21 +38,20 @@ static void unregister_task(struct task *t)
 {
        if (!initialized)
                return;
+       assert(t->error < 0);
        PARA_INFO_LOG("unregistering %s (%s)\n", t->status,
-               t->error <0? para_strerror(-t->error) : "shutdown");
+               para_strerror(-t->error));
        if (t->pre_select)
                list_del(&t->pre_select_node);
        if (t->post_select)
                list_del(&t->post_select_node);
-       t->error = -E_TASK_UNREGISTERED;
 }
 
-
 static void sched_preselect(struct sched *s)
 {
        struct task *t, *tmp;
        list_for_each_entry_safe(t, tmp, &pre_select_list, pre_select_node) {
-               if (t->error >= 0 && t->pre_select)
+               if (t->pre_select)
                        t->pre_select(s, t);
 //             PARA_INFO_LOG("%s \n", t->status);
                if (t->error >= 0)
@@ -207,10 +206,14 @@ void sched_shutdown(void)
 
        if (!initialized)
                return;
-       list_for_each_entry_safe(t, tmp, &pre_select_list, pre_select_node)
+       list_for_each_entry_safe(t, tmp, &pre_select_list, pre_select_node) {
+               t->error = -E_SCHED_SHUTDOWN;
                unregister_task(t);
-       list_for_each_entry_safe(t, tmp, &post_select_list, post_select_node)
+       }
+       list_for_each_entry_safe(t, tmp, &post_select_list, post_select_node) {
+               t->error = -E_SCHED_SHUTDOWN;
                unregister_task(t);
+       }
        initialized = 0;
 }
 
@@ -219,8 +222,7 @@ void sched_shutdown(void)
  *
  * \return The task list.
  *
- * Each entry of the list contains an identifier which is simply a hex number
- * that may be used in \a kill_task() to terminate the task.
+ * Each entry of the list contains an identifier which is simply a hex number.
  * The result is dynamically allocated and must be freed by the caller.
  */
 char *get_task_list(void)
@@ -248,41 +250,6 @@ char *get_task_list(void)
        return msg;
 }
 
-/**
- * Simulate an error for the given task.
- *
- * \param id The task identifier.
- *
- * Find the task identified by \a id, set the tasks' error value to
- * \p -E_TASK_KILLED and unregister the task.
- *
- * \return Positive on success, negative on errors (e.g. if \a id does not
- * correspond to a registered task).
- */
-int kill_task(char *id)
-{
-       struct task *t, *tmp;
-       char buf[20];
-
-       if (!initialized)
-               return -E_NOT_INITIALIZED;
-       list_for_each_entry_safe(t, tmp, &pre_select_list, pre_select_node) {
-               sprintf(buf, "%p", t);
-               if (strcmp(id, buf))
-                       continue;
-               t->error = -E_TASK_KILLED;
-               return 1;
-       }
-       list_for_each_entry_safe(t, tmp, &post_select_list, post_select_node) {
-               sprintf(buf, "%p", t);
-               if (strcmp(id, buf))
-                       continue;
-               t->error = -E_TASK_KILLED;
-               return 1;
-       }
-       return -E_NO_SUCH_TASK;
-}
-
 /**
  * Set the select timeout to the minimal possible value.
  *
diff --git a/sched.h b/sched.h
index 7158a8732c314b88ad1e162cbb6743c710d01240..e018c2fe9d0c35d2431b96967f97eb69f8ea0238 100644 (file)
--- a/sched.h
+++ b/sched.h
@@ -77,7 +77,6 @@ extern struct timeval *now;
 void register_task(struct task *t);
 int schedule(struct sched *s);
 char *get_task_list(void);
-int kill_task(char *id);
 void sched_shutdown(void);
 void sched_min_delay(struct sched *s);
 void sched_request_timeout(struct timeval *to, struct sched *s);
diff --git a/stdin.h b/stdin.h
index 2d279a6eada30d55efe51fce50798fdaf4700239..32a4c281b8326c6705c41d5e67c44c9e09de3434 100644 (file)
--- a/stdin.h
+++ b/stdin.h
@@ -12,7 +12,7 @@ struct stdin_task {
        struct task task;
        /** Stdin is always the root of a buffer tree. */
        struct btr_node *btrn;
-       /* Use a buffer pool to minimize memcpy due to alignment problems. */
+       /** Use a buffer pool to minimize memcpy due to alignment problems. */
        struct btr_pool *btrp;
 };
 
diff --git a/t/.gitignore b/t/.gitignore
new file mode 100644 (file)
index 0000000..e61ae9c
--- /dev/null
@@ -0,0 +1,2 @@
+/trashes
+/test-results
diff --git a/t/audio_files/short-44100-2.ogg b/t/audio_files/short-44100-2.ogg
new file mode 100644 (file)
index 0000000..91981cd
Binary files /dev/null and b/t/audio_files/short-44100-2.ogg differ
diff --git a/t/makefile.test b/t/makefile.test
new file mode 100644 (file)
index 0000000..d4aedf8
--- /dev/null
@@ -0,0 +1,32 @@
+RM ?= rm -f
+
+results_dir := $(test_dir)/test-results
+trash_dir := $(test_dir)/trashes
+
+test_options := --executables-dir $(shell pwd)
+test_options += --results-dir $(results_dir)
+test_options += --trash-dir $(trash_dir)
+test_options += --executables "$(executables)"
+test_options += --objects "$(basename $(notdir $(all_objs)))"
+
+ifdef V
+       ifeq ("$(origin V)", "command line")
+               test_options += --verbose=$(V)
+       endif
+endif
+
+tests := $(wildcard $(test_dir)/t[0-9][0-9][0-9][0-9]-*.sh)
+
+test: $(tests)
+
+$(tests): all
+       $(Q) $@ $(test_options)
+
+test-help:
+       $(Q) for t in $(tests); do $$t $(test_options) -h; done
+
+test-clean:
+       $(RM) -r $(results_dir)
+       $(RM) -r $(trash_dir)
+
+.PHONY: $(tests) test-help
diff --git a/t/t0000-help-output.sh b/t/t0000-help-output.sh
new file mode 100755 (executable)
index 0000000..fcc2c78
--- /dev/null
@@ -0,0 +1,20 @@
+#!/usr/bin/env bash
+
+test_description='Parse help output of all executables.
+
+Each paraslash executable supports the -h switch which instructs
+the program to print out all available options and to exit. This test
+checks whether this help output looks as expected.'
+
+. ${0%/*}/test-lib.sh
+
+grep_output()
+{
+       local regex='^  -h, --help'
+       $1 -h | grep "$regex"
+}
+
+for exe in $o_executables; do
+       test_expect_success "$exe" "grep_output $o_executables_dir/$exe"
+done
+test_done
diff --git a/t/t0001-oggdec-correctness.sh b/t/t0001-oggdec-correctness.sh
new file mode 100755 (executable)
index 0000000..01260e5
--- /dev/null
@@ -0,0 +1,36 @@
+#!/usr/bin/env bash
+
+test_description='Check correctness of oggdec output.
+
+Executes para_filter -f oggdec on the test files provided by the test
+suite and compares the output against the output of the reference
+implementation.'
+
+. ${0%/*}/test-lib.sh
+
+test_require_objects "oggdec_filter"
+missing_objects="$result"
+
+test_require_executables "oggdec"
+missing_executables="$result"
+
+get_audio_file_paths ogg
+oggs="$result"
+
+for ogg in $oggs; do
+       if [[ -n "$missing_objects" ]]; then
+               test_skip "${ogg##*/}" "missing object(s): $missing_objects"
+               continue
+       fi
+       if [[ -n "$missing_executables" ]]; then
+               test_skip "${ogg##*/}" \
+                       "missing executables(s): $missing_executables"
+               continue
+       fi
+       test_expect_success "${ogg##*/}" "
+               $PARA_FILTER -f oggdec < $ogg | sha1sum > filter.sha1 &&
+               oggdec --quiet --raw --output - -  < $ogg | sha1sum > oggdec.sha1 &&
+               diff -u filter.sha1 oggdec.sha1
+       "
+done
+test_done
diff --git a/t/t0002-oggdec-performance.sh b/t/t0002-oggdec-performance.sh
new file mode 100755 (executable)
index 0000000..d496a3e
--- /dev/null
@@ -0,0 +1,39 @@
+#!/usr/bin/env bash
+
+test_description='Measure time to decode ogg/vorbis files.
+
+Executes para_filter -f oggdec on the test files provided by the
+test suite and fails if it takes much longer than the reference
+implementation.'
+
+. ${0%/*}/test-lib.sh
+
+test_require_objects "oggdec_filter"
+missing_objects="$result"
+
+get_audio_file_paths ogg
+oggs="$result"
+
+test_require_executables "oggdec"
+missing_executables="$result"
+
+for ogg in $oggs; do
+       if [[ -n "$missing_objects" ]]; then
+               test_skip "${ogg##*/}" "missing object(s): $missing_objects"
+               continue
+       fi
+       if [[ -n "$missing_executables" ]]; then
+               test_skip "${ogg##*/}" \
+                       "missing executables(s): $missing_executables"
+               continue
+       fi
+       test_expect_success "${ogg##*/}" '
+               test_duration oggdec --quiet --raw --output - - < $ogg &&
+               t1=$result &&
+               test_duration $PARA_FILTER -f oggdec < $ogg &&
+               t2=$result &&
+               echo "oggdec: $t1, para_filter: $t2"
+               (($t2 <= $t1 * 3 / 2 + 100))
+       '
+done
+test_done
diff --git a/t/t0003-writer-init-error-path.sh b/t/t0003-writer-init-error-path.sh
new file mode 100755 (executable)
index 0000000..15f1dd8
--- /dev/null
@@ -0,0 +1,22 @@
+#!/usr/bin/env bash
+
+test_description='Check if alsa_init() failures are handled gracefully.
+
+Older parasslash versions contained a bug which caused para_write and para_audiod
+to abort if the alsa/oss device could not be opened. This test makes sure we
+will not introduce the same bug again.'
+
+. ${0%/*}/test-lib.sh
+
+for i in alsa oss; do
+       test_require_objects "${i}_write"
+       missing_objects="$result"
+       if [[ -n "$missing_objects" ]]; then
+               test_skip "$i" "missing object(s): $missing_objects"
+               continue
+       fi
+       test_expect_failure "$i" "
+               head -c 100 /dev/zero | $PARA_WRITE -w '$i -d /dev/non_existent'
+               "
+done
+test_done
diff --git a/t/test-lib.sh b/t/test-lib.sh
new file mode 100644 (file)
index 0000000..b7d675e
--- /dev/null
@@ -0,0 +1,323 @@
+#!/bin/bash
+
+# paraslash test suite helper functions
+# Licensed under the GPL v2. For licencing details see COPYING.
+# uses ideas and code from git's test-lib.sh, Copyright (c) 2005 Junio C Hamano
+
+
+get_audio_file_paths()
+{
+       local suffix="$1"
+
+       if (($# == 0)); then
+               result=$(find "$test_audio_file_dir" -type f)
+       else
+               result=$(find "$test_audio_file_dir" -type f -name "*.$suffix")
+       fi
+}
+
+say_color()
+{
+       if [[ "$o_nocolor" != "true" && -n "$1" ]]; then
+               export TERM=$ORIGINAL_TERM
+               case "$1" in
+                       error) tput bold; tput setaf 1;;
+                       skip)  tput setaf 5;;
+                       ok)
+                               (($o_verbose == 0)) && return
+                               tput setaf 2;;
+                       pass)  tput bold; tput setaf 2;;
+                       info)  tput setaf 3;;
+                       run)
+                               (($o_verbose == 0)) && return
+                               tput setaf 6;;
+               esac
+       fi
+       shift
+       printf "%s\n" "$*"
+       if [[ "$o_nocolor" != "true" && -n "$1" ]]; then
+               tput sgr0
+               export TERM=dumb
+       fi
+}
+
+die()
+{
+       local code=$?
+       [[ "$exit_ok" == "true" ]] && exit $code
+       say_color error "FATAL: Unexpected exit with code $code"
+       exit 1
+}
+
+error()
+{
+       say_color error "error: $*"
+       exit_ok="true"
+       exit 1
+}
+
+say()
+{
+       say_color info "$*"
+}
+
+retval_ok()
+{
+       local rv="$1" expectation="$2"
+
+       if [[ "$expectation" == "success" ]]; then
+               (($rv == 0)) && return 0 || return 1
+       fi
+       if (($rv > 129 && $rv <= 192)); then
+               echo >&2 "died by signal"
+               return 1
+       fi
+       if (($rv == 127)); then
+                echo >&2 "command not found"
+               return 1
+       fi
+       if (($rv == 0)); then
+                echo >&2 "command was supposed to fail but succeeded"
+               return 1
+       fi
+       return 0
+}
+
+_test_run()
+{
+       local f expectation="$3" ret
+
+       let test_count++
+       eval >&3 2>&4 "$2"
+       ret=$?
+       if retval_ok "$ret" "$expectation"; then
+               let test_success++
+               say_color ok "ok $test_count - $1"
+               return
+       fi
+       let test_failure++
+       say_color error "not ok - $test_count $1"
+       f="$o_results_dir/${0##*/}-$$.out"
+       if [[ -s "$f" ]]; then
+               sed -e 's/^/#   /' < "$f"
+       else
+               sed -e 's/^/#   /' <<< "$2"
+       fi
+       [[ "$o_immediate" != "true" ]] && return
+       exit_ok="true"
+       exit 1
+}
+
+test_skip()
+{
+       (($# != 2)) && error "bug: not 2 parameters to test_skip()"
+       let test_count++
+       let test_skipped++
+       say_color skip >&3 "skipping test $this_test.$test_count ($1): $2"
+       say_color skip "ok $test_count - $1 # skipped ($2)"
+}
+
+test_require_objects()
+{
+       local o1 o2 found
+
+       result=
+       # if no objects were given, we assume this test is run manually
+       # rather than via "make test". We won't check anything in this case
+       [[ -z "$o_objects" ]] && return
+
+       for o1 in $1; do
+               found=
+               for o2 in $o_objects; do
+                       [[ "$o1" != "$o2" ]] && continue
+                       found="true"
+                       break
+               done
+               [[ "$found" == "true" ]] && continue
+               [[ -n "$result" ]] && result+=" "
+               result+="$o1"
+       done
+       [[ -z "$result" ]]
+}
+
+test_require_executables()
+{
+       local i
+
+       result=
+       for i in "$@"; do
+               [[ -n "$(builtin type -t "$i")" ]] && continue
+               [[ -n "$result" ]] && result+=" "
+               result+="$i"
+       done
+       [[ -z "$result" ]]
+}
+
+test_duration()
+{
+       local t=$(exec 2>&1 1>/dev/null; time -p "$@")
+       result=$(awk '{print $2 * 1000}' <<< $t)
+}
+
+test_expect_success()
+{
+       (($# != 2)) && error "bug: not 2 parameters to test_expect_success()"
+       say >&3 "expecting success: $2"
+       _test_run "$1" "$2" "success"
+       echo >&3 ""
+}
+
+test_expect_failure()
+{
+       (($# != 2)) && error "bug: not 2 parameters to test_expect_failure()"
+       say >&3 "expecting failure: $2"
+       _test_run "$1" "$2" "failure"
+       echo >&3 ""
+}
+
+test_done()
+{
+       test_results_path="$o_results_dir/${0##*/}-$$.counts"
+       {
+               echo "total $test_count"
+               echo "success $test_success"
+               echo "failed $test_failure"
+               echo "skipped $test_skipped"
+               echo
+       } > $test_results_path
+
+       exit_ok="true"
+       msg="$test_count test(s) ($test_skipped test(s) skipped)"
+       if (($test_failure == 0)); then
+               say_color pass "# ${0##*/}: passed all $msg"
+               exit 0
+       else
+               say_color error "# ${0##*/}: failed $test_failure among $msg"
+               exit 1
+       fi
+}
+
+sanitize_environment()
+{
+       export LANG=C
+       export LC_ALL=C
+       export PAGER=cat
+       export TZ=UTC
+       export TERM=dumb
+       export EDITOR=:
+       export HOME=$(pwd)
+
+       unset VISUAL
+       unset EMAIL
+       unset CDPATH
+       unset GREP_OPTIONS
+}
+
+can_use_colors()
+{
+       result="false"
+       [[ "$TERM" == "dumb" ]] && return
+       [[ -t 1 ]] || return
+       tput bold >/dev/null 2>&1 || return
+       tput setaf 1 >/dev/null 2>&1 || return
+       tput sgr0 >/dev/null 2>&1 || return
+       result="true"
+}
+
+parse_options()
+{
+       while (($# > 0)); do
+               case "$1" in
+               -i|--immediate) o_immediate="true"; shift;;
+               -l|--long) export o_long="true"; shift;;
+               -h|--help) o_help="true"; shift;;
+               -v=0|--verbose=0) o_verbose="0"; shift;;
+               -v=1|--verbose=1) o_verbose="1"; shift;;
+               -v|--verbose|-v=2|--verbose=2) o_verbose="2"; shift;;
+               --no-color) o_nocolor="true"; shift;;
+               --results-dir) o_results_dir="$2"; shift; shift;;
+               --trash-dir) o_trash_dir="$2"; shift; shift;;
+               --executables-dir) export o_executables_dir="$2"; shift; shift;;
+               --executables) export o_executables="$2"; shift; shift;;
+               --objects) export o_objects="$2"; shift; shift;;
+               *) echo "error: unknown test option '$1'" >&2; exit 1;;
+               esac
+       done
+       [[ -z "$o_verbose" ]] && o_verbose=1
+}
+
+create_trash_dir_and_cd()
+{
+       local trash="$o_trash_dir/trash-dir.${0##*/}"
+
+       rm -rf "$trash" || error "could not remove trash dir"
+       mkdir -p "$trash" || error "could not make trash dir"
+       cd "$trash" || error "could not change to trash dir"
+}
+
+fixup_dirs()
+{
+       local wd=$(pwd)
+
+       test_dir="$wd/${0%/*}"
+       test_audio_file_dir="$test_dir/audio_files"
+
+       [[ -z "$o_results_dir" ]] && o_results_dir="$test_dir/test-results"
+       [[ -z "$o_executables_dir" ]] && o_executables_dir="$test_dir/.."
+       [[ -z "$o_trash_dir" ]] && o_trash_dir="$test_dir/trashes"
+
+       # we want alsolute paths because relative paths become invalid
+       # after changing to the trash dir
+       [[ -n "${o_results_dir##/*}" ]] && o_results_dir="$wd/$o_results_dir"
+       [[ -n "${o_executables_dir##/*}" ]] && o_executables_dir="$wd/$o_results_dir"
+       [[ -n "${o_trash_dir##/*}" ]] && o_trash_dir="$wd/$o_trash_dir"
+
+       mkdir -p "$o_results_dir"
+}
+
+parse_options "$@"
+if [[ "$o_nocolor" != "true" ]]; then
+       can_use_colors
+       [[ "$result" != "true" ]] && o_nocolor="true"
+fi
+
+# Each test must set test_description
+[[ -z "${test_description}" ]] && error "${0##*/} did not set test_description"
+if [[ "$o_help" == "true" ]]; then
+       printf "${0##*/}: "
+       sed -e '1!d' <<< "$test_description"
+       if (($o_verbose >= 2)); then
+               echo
+               sed -e '1,2d' -e 's/^/  /g' <<<"$test_description"
+               echo
+       fi
+       exit 0
+fi
+fixup_dirs
+
+[[ -z "$o_executables" ]] && o_executables="para_afh para_audioc para_audiod
+       para_client para_fade para_filter para_gui para_recv para_server
+       para_write"
+for exe in $o_executables; do
+       export $(tr 'a-z' 'A-Z' <<< $exe)="$o_executables_dir/$exe"
+done
+
+test_failure=0
+test_count=0
+test_success=0
+test_skipped=0
+
+ORIGINAL_TERM=$TERM
+sanitize_environment
+create_trash_dir_and_cd
+
+if (($o_verbose >= 2)); then
+       exec 4>&2 3>&1
+else
+       exec 4>$o_results_dir/${0##*/}-$$.out 3>&4
+fi
+
+exit_ok=
+trap 'die' EXIT
+
+say_color run "# running ${0##*/}"
index 4fb10b444be321c51e7d33da2442fd6b8a469138..b4494eb7edb9e9fd26c1f4d20e9b81b06472c625 100644 (file)
@@ -57,8 +57,13 @@ static void udp_close_target(struct sender_client *sc)
        const char *buf;
        size_t len = vss_get_fec_eof_packet(&buf);
 
-       /* ignore return value, closing the target anyway. */
-       (void)write(sc->fd, buf, len);
+       /*
+        * Ignore the return value of wirte() since we are closing the target
+        * anyway. The sole purpose of the "do_nothing" statement is to silence
+        * gcc.
+        */
+       if (write(sc->fd, buf, len))
+               do_nothing;
 }
 
 static void udp_delete_target(struct sender_client *sc, const char *msg)
diff --git a/versions/paraslash-0.4.6.tar.bz2 b/versions/paraslash-0.4.6.tar.bz2
new file mode 100644 (file)
index 0000000..de90cf1
Binary files /dev/null and b/versions/paraslash-0.4.6.tar.bz2 differ
diff --git a/versions/paraslash-0.4.6.tar.bz2.asc b/versions/paraslash-0.4.6.tar.bz2.asc
new file mode 100644 (file)
index 0000000..a5307b2
--- /dev/null
@@ -0,0 +1,7 @@
+-----BEGIN PGP SIGNATURE-----
+Version: GnuPG v1.4.10 (GNU/Linux)
+
+iEYEABECAAYFAk2UZVsACgkQWto1QDEAkw/XxQCfZ3f3JFstN47qkV1lHLpNC0ij
+woYAmwQrwy6WwMx7fttfxdou6reIrsir
+=bZsC
+-----END PGP SIGNATURE-----
index 48f5bb516a10265d559c862e8815e4c1eee42bef..f9009e4f7dcf48af389280e0a14d2b997380bfc0 100644 (file)
@@ -1,6 +1,10 @@
 <h1>Events</h1>
 <hr>
 <ul>
+       <li>2011-03-31: <a href="versions/paraslash-0.4.6.tar.bz2">paraslash-0.4.6</a>
+               <a href="versions/paraslash-0.4.6.tar.bz2.asc">(sig)</a>
+               "deterministic entropy"
+       </li>
        <li>2010-12-17: <a href="versions/paraslash-0.4.5.tar.bz2">paraslash-0.4.5</a>
                <a href="versions/paraslash-0.4.5.tar.bz2.asc">(sig)</a>
                "symmetric randomization"
index 946b9d0953621b23a3a6e30e62c211674d0c6ea5..5926b55536c736c0bd8f031bd596d51e31587fbb 100644 (file)
@@ -280,7 +280,11 @@ might need to tell the configure script where to find them. Try
        ./configure --help
 
 to see a list of options. If the paraslash package was compiled
-successfully, execute as root,
+successfully, execute (optionally)
+
+       make test
+
+to run the paraslash test suite. If all tests pass, execute as root
 
        make install
 
diff --git a/write.c b/write.c
index 2ea9d2132bee5f64224f3f9d635af8f83777a33e..b3824a081f594dee23617502caf65261717d77b9 100644 (file)
--- a/write.c
+++ b/write.c
@@ -209,6 +209,20 @@ static int main_btr(struct sched *s)
        s->default_timeout.tv_sec = 10;
        s->default_timeout.tv_usec = 50000;
        ret = schedule(s);
+       if (ret >= 0) {
+               int j;
+               for (j = 0; j < i; j++) {
+                       struct task *t = &wns[j].task;
+                       assert(t->error < 0);
+                       if (t->error != -E_WRITE_COMMON_EOF
+                                       && t->error != -E_BTR_EOF) {
+                               PARA_ERROR_LOG("%s: %s\n", t->status,
+                                       para_strerror(-t->error));
+                               if (ret >= 0)
+                                       ret = t->error;
+                       }
+               }
+       }
 out:
        for (i--; i >= 0; i--) {
                struct writer_node *wn = wns + i;