From: Andre Noll Date: Sun, 14 Sep 2014 17:01:47 +0000 (+0200) Subject: Merge branch 't/mvblob_improvement' X-Git-Tag: v0.5.4~52 X-Git-Url: http://git.tuebingen.mpg.de/?p=paraslash.git;a=commitdiff_plain;h=4d9d588c5df359c3c5f279fbfd4ea51d3a2afc87;hp=9eb3ef43535eaacd898aed907eeb2f75395af289 Merge branch 't/mvblob_improvement' Cooking for two months. * t/mvblob_improvement: mvblob: Improve error diagnostics. --- diff --git a/Doxyfile b/Doxyfile index 00cb6cc9..239cd262 100644 --- a/Doxyfile +++ b/Doxyfile @@ -619,7 +619,6 @@ EXCLUDE_SYMLINKS = NO # for example use the pattern */test/* EXCLUDE_PATTERNS = *.cmdline.* \ - gui* \ gcc-compat.h \ fade.c \ *_command_list.h \ diff --git a/INSTALL b/INSTALL index 9917afb6..4a814dc1 100644 --- a/INSTALL +++ b/INSTALL @@ -27,4 +27,6 @@ Example for cross-compiling: For details see the user manual: + http://people.tuebingen.mpg.de/maan/paraslash/manual.html +or http://paraslash.systemlinux.org/manual.html diff --git a/Makefile.in b/Makefile.in index 6762b449..a869c890 100644 --- a/Makefile.in +++ b/Makefile.in @@ -34,10 +34,12 @@ play_objs := @play_objs@ speex_cppflags := @speex_cppflags@ opus_cppflags := @opus_cppflags@ +vorbis_cppflags := @vorbis_cppflags@ arch_cppflags := @arch_cppflags@ osl_cppflags := @osl_cppflags@ id3tag_cppflags := @id3tag_cppflags@ openssl_cppflags := @openssl_cppflags@ +gcrypt_cppflags := @gcrypt_cppflags@ ogg_cppflags := @ogg_cppflags@ mad_cppflags := @mad_cppflags@ faad_cppflags := @faad_cppflags@ diff --git a/Makefile.real b/Makefile.real index 2973637e..ab238953 100644 --- a/Makefile.real +++ b/Makefile.real @@ -178,6 +178,7 @@ $(object_dir)/%.cmdline.o: CPPFLAGS += -Wno-unused-function $(object_dir)/mp3_afh.o: CPPFLAGS += $(id3tag_cppflags) $(object_dir)/crypt.o: CPPFLAGS += $(openssl_cppflags) +$(object_dir)/gcrypt.o: CPPFLAGS += $(gcrypt_cppflags) $(object_dir)/mp3dec_filter.o: CPPFLAGS += $(mad_cppflags) $(object_dir)/compress_filter.o: CPPFLAGS += -O3 $(object_dir)/ao_write.o: CPPFLAGS += $(ao_cppflags) @@ -187,12 +188,17 @@ $(object_dir)/aac_common.o \ $(object_dir)/aac_afh.o \ : CPPFLAGS += $(faad_cppflags) +$(object_dir)/ogg_afh.o \ +$(object_dir)/oggdec_filter.o \ +: CPPFLAGS += $(vorbis_cppflags) + $(object_dir)/spx_common.o \ $(object_dir)/spxdec_filter.o \ $(object_dir)/spx_afh.o \ $(object_dir)/oggdec_filter.o \ $(object_dir)/ogg_afh.o \ $(object_dir)/ogg_afh_common.o \ +$(object_dir)/opus%.o \ : CPPFLAGS += $(ogg_cppflags) $(object_dir)/%.o: %.c | $(object_dir) diff --git a/NEWS b/NEWS index f6fca566..f7158c45 100644 --- a/NEWS +++ b/NEWS @@ -1,11 +1,25 @@ NEWS ==== -------------------------------------------------- -0.5.3 (to be released) "symbolic synchronization" -------------------------------------------------- +----------------------------------------------- +0.5.4 (to be announced) "exponential alignment" +----------------------------------------------- + * Minor cleanups to daemon.c. + * New URLs for home page and git services. + * Improved error diagnostics for the mvblob commands. + +Download: ./releases/paraslash-git.tar.bz2 + +--------------------------------------------- +0.5.3 (2014-08-01) "symbolic synchronization" +--------------------------------------------- + +Not many new features, but lots of fixes and usability improvements. + + - para_gui has been converted to use the paraslash scheduler. - Various alsa-related fixes, mostly for the raspberry pi. + - Many scheduler improvements and cleanups. - The test suite has been extended to include sanity checks for the generated man pages. - ao_writer fixes. This writer was in a quite bad shape. Many @@ -15,6 +29,9 @@ NEWS - The cpsi command now prints a meaningful error message if none of the given patterns matched any audio file. +Downloads: ./releases/paraslash-0.5.3.tar.bz2 (tarball), +./releases/paraslash-0.5.3.tar.bz2.asc (signature) + ---------------------------------------- 0.5.2 (2014-04-11) "orthogonal interior" ---------------------------------------- diff --git a/README b/README index 24b971d3..0a0aae88 100644 --- a/README +++ b/README @@ -5,8 +5,10 @@ audio files. See the user manual for details. Distribution of paraslash is covered by the GNU GPL, version 2 unless otherwise stated. See file COPYING. -Web page: http://paraslash.systemlinux.org/ -Git URL: git://paraslash.systemlinux.org/git -Email: Andre Noll +Web page: http://people.tuebingen.mpg.de/maan/paraslash/ +Alternative web page: http://paraslash.systemlinux.org/ +Gitweb: http://git.tuebingen.mpg.de/paraslash.git/ +Git URL: git://git.tuebingen.mpg.de/paraslash.git +Email: Andre Noll Comments and bug reports are welcome. diff --git a/aac.h b/aac.h index 6e6c3402..5d544ff7 100644 --- a/aac.h +++ b/aac.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2006-2014 Andre Noll + * Copyright (C) 2006-2014 Andre Noll * * Licensed under the GPL v2. For licencing details see COPYING. */ diff --git a/aac_afh.c b/aac_afh.c index f354a63c..10e0a0da 100644 --- a/aac_afh.c +++ b/aac_afh.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2006-2014 Andre Noll + * Copyright (C) 2006-2014 Andre Noll * * Licensed under the GPL v2. For licencing details see COPYING. */ diff --git a/aac_common.c b/aac_common.c index ca29607a..9d566168 100644 --- a/aac_common.c +++ b/aac_common.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2006-2014 Andre Noll + * Copyright (C) 2006-2014 Andre Noll * * Licensed under the GPL v2. For licencing details see COPYING. */ diff --git a/aacdec_filter.c b/aacdec_filter.c index d63236da..c6fe4d9c 100644 --- a/aacdec_filter.c +++ b/aacdec_filter.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2006-2014 Andre Noll + * Copyright (C) 2006-2014 Andre Noll * * Licensed under the GPL v2. For licencing details see COPYING. */ @@ -80,9 +80,9 @@ static void aacdec_close(struct filter_node *fn) fn->private_data = NULL; } -static int aacdec_post_select(__a_unused struct sched *s, struct task *t) +static int aacdec_post_select(__a_unused struct sched *s, void *context) { - struct filter_node *fn = container_of(t, struct filter_node, task); + struct filter_node *fn = context; struct btr_node *btrn = fn->btrn; struct private_aacdec_data *padd = fn->private_data; int i, ret; diff --git a/acl.c b/acl.c index e1415050..2923523d 100644 --- a/acl.c +++ b/acl.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2005-2014 Andre Noll + * Copyright (C) 2005-2014 Andre Noll * * Licensed under the GPL v2. For licencing details see COPYING. */ diff --git a/acl.h b/acl.h index af68e1bc..bb9c157c 100644 --- a/acl.h +++ b/acl.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2008-2014 Andre Noll + * Copyright (C) 2008-2014 Andre Noll * * Licensed under the GPL v2. For licencing details see COPYING. */ diff --git a/afh.c b/afh.c index 15b5e6b9..f876244d 100644 --- a/afh.c +++ b/afh.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2008-2014 Andre Noll + * Copyright (C) 2008-2014 Andre Noll * * Licensed under the GPL v2. For licencing details see COPYING. */ diff --git a/afh.h b/afh.h index 2264cc61..ec1d6706 100644 --- a/afh.h +++ b/afh.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2005-2014 Andre Noll + * Copyright (C) 2005-2014 Andre Noll * * Licensed under the GPL v2. For licencing details see COPYING. */ @@ -101,6 +101,8 @@ int compute_afhi(const char *path, char *data, size_t size, const char *audio_format_name(int); void afh_get_chunk(long unsigned chunk_num, struct afh_info *afhi, void *map, const char **buf, size_t *len); +int32_t afh_get_start_chunk(int32_t approx_chunk_num, + const struct afh_info *afhi); void afh_get_header(struct afh_info *afhi, uint8_t audio_format_id, void *map, size_t mapsize, char **buf, size_t *len); void afh_free_header(char *header_buf, uint8_t audio_format_id); diff --git a/afh_common.c b/afh_common.c index cad972d9..0e9b13ca 100644 --- a/afh_common.c +++ b/afh_common.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 1997-2014 Andre Noll + * Copyright (C) 1997-2014 Andre Noll * * Licensed under the GPL v2. For licencing details see COPYING. */ @@ -230,11 +230,12 @@ success: } /** - * Deallocate contents of a filled-in ahi structure + * Deallocate the contents of an afh_info structure. * * \param afhi The structure to clear. * - * The given pointer is kept, everything else is freed. + * This only frees the memory the various pointer fields of \a afhi point to. + * It does *not* free \a afhi itself. */ void clear_afhi(struct afh_info *afhi) { @@ -264,6 +265,12 @@ const char *audio_format_name(int i) return afl[i].name; } +static inline size_t get_chunk_len(long unsigned chunk_num, + const struct afh_info *afhi) +{ + return afhi->chunk_table[chunk_num + 1] - afhi->chunk_table[chunk_num]; +} + /** * Get one chunk of audio data. * @@ -281,7 +288,28 @@ void afh_get_chunk(long unsigned chunk_num, struct afh_info *afhi, { size_t pos = afhi->chunk_table[chunk_num]; *buf = map + pos; - *len = afhi->chunk_table[chunk_num + 1] - pos; + *len = get_chunk_len(chunk_num, afhi); +} + +/** + * Find a suitable start chunk. + * + * \param approx_chunk_num Upper bound for the chunk number to return. + * \param afhi Needed for the chunk table. + * + * \return The first non-empty chunk <= \a approx_chunk_num. + * + * \sa \ref afh_get_chunk(). + */ +int32_t afh_get_start_chunk(int32_t approx_chunk_num, + const struct afh_info *afhi) +{ + int32_t k; + + for (k = PARA_MAX(0, approx_chunk_num); k >= 0; k--) + if (get_chunk_len(k, afhi) > 0) + break; + return k; } /** diff --git a/afh_recv.c b/afh_recv.c index 0c7b3946..01785d6c 100644 --- a/afh_recv.c +++ b/afh_recv.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2014 Andre Noll + * Copyright (C) 2011-2014 Andre Noll * * Licensed under the GPL v2. For licencing details see COPYING. */ @@ -59,8 +59,8 @@ static int afh_execute(struct btr_node *btrn, const char *cmd, char **result) return ret; if (x >= pard->afhi.chunks_total) return -ERRNO_TO_PARA_ERROR(EINVAL); - pard->first_chunk = pard->current_chunk = x; - rn->task.error = 0; + pard->first_chunk = afh_get_start_chunk(x, &pard->afhi); + pard->current_chunk = pard->first_chunk; return 1; } return -E_BTR_NAVAIL; @@ -110,9 +110,12 @@ static int afh_recv_open(struct receiver_node *rn) if (PARA_ABS(conf->begin_chunk_arg) >= afhi->chunks_total) goto out_clear_afhi; if (conf->begin_chunk_arg >= 0) - pard->first_chunk = conf->begin_chunk_arg; + pard->first_chunk = afh_get_start_chunk( + conf->begin_chunk_arg, &pard->afhi); else - pard->first_chunk = afhi->chunks_total + conf->begin_chunk_arg; + pard->first_chunk = afh_get_start_chunk( + afhi->chunks_total + conf->begin_chunk_arg, + &pard->afhi); if (conf->end_chunk_given) { ret = -ERRNO_TO_PARA_ERROR(EINVAL); if (PARA_ABS(conf->end_chunk_arg) > afhi->chunks_total) @@ -151,14 +154,14 @@ static void afh_recv_close(struct receiver_node *rn) freep(&rn->private_data); } -static void afh_recv_pre_select(struct sched *s, struct task *t) +static void afh_recv_pre_select(struct sched *s, void *context) { - struct receiver_node *rn = container_of(t, struct receiver_node, task); + struct receiver_node *rn = context; struct private_afh_recv_data *pard = rn->private_data; struct afh_info *afhi = &pard->afhi; struct afh_recv_args_info *conf = rn->conf; struct timeval chunk_time; - int state = generic_recv_pre_select(s, t); + int state = generic_recv_pre_select(s, rn); if (state <= 0) return; @@ -171,9 +174,9 @@ static void afh_recv_pre_select(struct sched *s, struct task *t) sched_request_barrier_or_min_delay(&chunk_time, s); } -static int afh_recv_post_select(__a_unused struct sched *s, struct task *t) +static int afh_recv_post_select(__a_unused struct sched *s, void *context) { - struct receiver_node *rn = container_of(t, struct receiver_node, task); + struct receiver_node *rn = context; struct afh_recv_args_info *conf = rn->conf; struct private_afh_recv_data *pard = rn->private_data; struct btr_node *btrn = rn->btrn; diff --git a/afs.c b/afs.c index fa4f4326..dd0d1bcd 100644 --- a/afs.c +++ b/afs.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2007-2014 Andre Noll + * Copyright (C) 2007-2014 Andre Noll * * Licensed under the GPL v2. For licencing details see COPYING. */ @@ -81,7 +81,7 @@ struct command_task { */ uint32_t cookie; /** The associated task structure. */ - struct task task; + struct task *task; }; extern int mmd_mutex; @@ -719,13 +719,13 @@ static int open_afs_tables(void) return ret; } -static void signal_pre_select(struct sched *s, struct task *t) +static void signal_pre_select(struct sched *s, void *context) { - struct signal_task *st = container_of(t, struct signal_task, task); + struct signal_task *st = context; para_fd_set(st->fd, &s->rfds, &s->max_fileno); } -static int afs_signal_post_select(struct sched *s, __a_unused struct task *t) +static int afs_signal_post_select(struct sched *s, __a_unused void *context) { int signum, ret; @@ -762,10 +762,13 @@ static void register_signal_task(struct sched *s) para_install_sighandler(SIGTERM); para_install_sighandler(SIGHUP); - st->task.pre_select = signal_pre_select; - st->task.post_select = afs_signal_post_select; - sprintf(st->task.status, "signal task"); - register_task(s, &st->task); + st->task = task_register(&(struct task_info) { + .name = "signal", + .pre_select = signal_pre_select, + .post_select = afs_signal_post_select, + .context = st, + + }, s); } static struct list_head afs_client_list; @@ -780,9 +783,9 @@ struct afs_client { struct timeval connect_time; }; -static void command_pre_select(struct sched *s, struct task *t) +static void command_pre_select(struct sched *s, void *context) { - struct command_task *ct = container_of(t, struct command_task, task); + struct command_task *ct = context; struct afs_client *client; para_fd_set(server_socket, &s->rfds, &s->max_fileno); @@ -917,14 +920,14 @@ err: /** Shutdown connection if query has not arrived until this many seconds. */ #define AFS_CLIENT_TIMEOUT 3 -static int command_post_select(struct sched *s, struct task *t) +static int command_post_select(struct sched *s, void *context) { - struct command_task *ct = container_of(t, struct command_task, task); + struct command_task *ct = context; struct sockaddr_un unix_addr; struct afs_client *client, *tmp; int fd, ret; - ret = task_get_notification(t); + ret = task_get_notification(ct->task); if (ret < 0) return ret; ret = execute_server_command(&s->rfds); @@ -972,10 +975,12 @@ static void register_command_task(uint32_t cookie, struct sched *s) ct->fd = setup_command_socket_or_die(); ct->cookie = cookie; - ct->task.pre_select = command_pre_select; - ct->task.post_select = command_post_select; - sprintf(ct->task.status, "afs command task"); - register_task(s, &ct->task); + ct->task = task_register(&(struct task_info) { + .name = "afs command", + .pre_select = command_pre_select, + .post_select = command_post_select, + .context = ct, + }, s); } /** @@ -1007,6 +1012,7 @@ __noreturn void afs_init(uint32_t cookie, int socket_fd) s.default_timeout.tv_sec = 0; s.default_timeout.tv_usec = 999 * 1000; ret = schedule(&s); + sched_shutdown(&s); out_close: close_afs_tables(); out: diff --git a/afs.h b/afs.h index 7a3f963f..9669b26d 100644 --- a/afs.h +++ b/afs.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2007-2014 Andre Noll + * Copyright (C) 2007-2014 Andre Noll * * Licensed under the GPL v2. For licencing details see COPYING. */ diff --git a/aft.c b/aft.c index 39f95ad2..3e2c3621 100644 --- a/aft.c +++ b/aft.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2007-2014 Andre Noll + * Copyright (C) 2007-2014 Andre Noll * * Licensed under the GPL v2. For licencing details see COPYING. */ diff --git a/alsa_mix.c b/alsa_mix.c index c860efc8..c44c74f9 100644 --- a/alsa_mix.c +++ b/alsa_mix.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2012-2014 Andre Noll + * Copyright (C) 2012-2014 Andre Noll * * Licensed under the GPL v2. For licencing details see COPYING. */ diff --git a/alsa_write.c b/alsa_write.c index 3759306e..7a0ee5be 100644 --- a/alsa_write.c +++ b/alsa_write.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2005-2014 Andre Noll + * Copyright (C) 2005-2014 Andre Noll * * Licensed under the GPL v2. For licencing details see COPYING. */ @@ -199,10 +199,10 @@ fail: return -E_ALSA; } -static void alsa_write_pre_select(struct sched *s, struct task *t) +static void alsa_write_pre_select(struct sched *s, void *context) { struct pollfd pfd; - struct writer_node *wn = container_of(t, struct writer_node, task); + struct writer_node *wn = context; struct private_alsa_write_data *pad = wn->private_data; int ret = btr_node_status(wn->btrn, wn->min_iqs, BTR_NT_LEAF); @@ -248,10 +248,9 @@ static void alsa_close(struct writer_node *wn) free(pad); } -static int alsa_write_post_select(__a_unused struct sched *s, - struct task *t) +static int alsa_write_post_select(__a_unused struct sched *s, void *context) { - struct writer_node *wn = container_of(t, struct writer_node, task); + struct writer_node *wn = context; struct private_alsa_write_data *pad = wn->private_data; struct btr_node *btrn = wn->btrn; char *data; @@ -259,7 +258,7 @@ static int alsa_write_post_select(__a_unused struct sched *s, snd_pcm_sframes_t frames; int ret; - ret = task_get_notification(t); + ret = task_get_notification(wn->task); if (ret < 0) goto err; again: diff --git a/amp_filter.c b/amp_filter.c index c3e55cf0..e43e45f7 100644 --- a/amp_filter.c +++ b/amp_filter.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2009-2014 Andre Noll + * Copyright (C) 2009-2014 Andre Noll * * Licensed under the GPL v2. For licencing details see COPYING. */ @@ -62,9 +62,9 @@ static void amp_open(struct filter_node *fn) pad->amp, pad->amp / 64.0 + 1.0); } -static int amp_post_select(__a_unused struct sched *s, struct task *t) +static int amp_post_select(__a_unused struct sched *s, void *context) { - struct filter_node *fn = container_of(t, struct filter_node, task); + struct filter_node *fn = context; struct private_amp_data *pad = fn->private_data; struct btr_node *btrn = fn->btrn; int ret, factor = 64 + pad->amp; diff --git a/ao_write.c b/ao_write.c index 63d18afa..6e2d9ee3 100644 --- a/ao_write.c +++ b/ao_write.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2014 Andre Noll + * Copyright (C) 2011-2014 Andre Noll * * Licensed under the GPL v2. For licencing details see COPYING. */ @@ -46,9 +46,9 @@ static void aow_close(struct writer_node *wn) wn->private_data = NULL; } -static void aow_pre_select(struct sched *s, struct task *t) +static void aow_pre_select(struct sched *s, void *context) { - struct writer_node *wn = container_of(t, struct writer_node, task); + struct writer_node *wn = context; struct private_aow_data *pawd = wn->private_data; int ret; @@ -308,10 +308,9 @@ fail: return -E_AO_PTHREAD; } -static int aow_post_select(__a_unused struct sched *s, - struct task *t) +static int aow_post_select(__a_unused struct sched *s, void *context) { - struct writer_node *wn = container_of(t, struct writer_node, task); + struct writer_node *wn = context; struct private_aow_data *pawd = wn->private_data; int ret; diff --git a/attribute.c b/attribute.c index 7777a8dd..8211cbc6 100644 --- a/attribute.c +++ b/attribute.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 1997-2014 Andre Noll + * Copyright (C) 1997-2014 Andre Noll * * Licensed under the GPL v2. For licencing details see COPYING. */ diff --git a/audioc.c b/audioc.c index fe7165ed..001619d5 100644 --- a/audioc.c +++ b/audioc.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2005-2014 Andre Noll + * Copyright (C) 2005-2014 Andre Noll * * Licensed under the GPL v2. For licencing details see COPYING. */ @@ -79,7 +79,7 @@ static struct sched sched; struct audioc_task { int fd; struct btr_node *btrn; - struct task task; + struct task *task; }; static struct i9e_completer audiod_completers[]; @@ -130,9 +130,9 @@ static struct i9e_completer audiod_completers[] = { {.name = NULL} }; -static void audioc_pre_select(struct sched *s, struct task *t) +static void audioc_pre_select(struct sched *s, void *context) { - struct audioc_task *at = container_of(t, struct audioc_task, task); + struct audioc_task *at = context; int ret = btr_node_status(at->btrn, 0, BTR_NT_ROOT); if (ret < 0) @@ -140,10 +140,10 @@ static void audioc_pre_select(struct sched *s, struct task *t) para_fd_set(at->fd, &s->rfds, &s->max_fileno); } -static int audioc_post_select(struct sched *s, struct task *t) +static int audioc_post_select(struct sched *s, void *context) { char *buf = NULL; - struct audioc_task *at = container_of(t, struct audioc_task, task); + struct audioc_task *at = context; int ret = btr_node_status(at->btrn, 0, BTR_NT_ROOT); if (ret < 0) @@ -168,13 +168,7 @@ out: return ret; } -static struct audioc_task audioc_task = { - .task = { - .pre_select = audioc_pre_select, - .post_select = audioc_post_select, - .status = "audioc task" - }, -}, *at = &audioc_task; +static struct audioc_task audioc_task, *at = &audioc_task; static int audioc_i9e_line_handler(char *line) { @@ -202,8 +196,12 @@ static int audioc_i9e_line_handler(char *line) args = NULL; at->btrn = btr_new_node(&(struct btr_node_description) EMBRACE(.name = "audioc line handler")); - at->task.error = 0; - register_task(&sched, &at->task); + at->task = task_register(&(struct task_info) { + .name = "audioc", + .pre_select = audioc_pre_select, + .post_select = audioc_post_select, + .context = at, + }, &sched); i9e_attach_to_stdout(at->btrn); return 1; close: @@ -248,6 +246,7 @@ __noreturn static void interactive_session(void) goto out; para_log = i9e_log; ret = schedule(&sched); + sched_shutdown(&sched); i9e_close(); para_log = stderr_log; out: diff --git a/audiod.c b/audiod.c index a8f40183..a072071c 100644 --- a/audiod.c +++ b/audiod.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2005-2014 Andre Noll + * Copyright (C) 2005-2014 Andre Noll * * Licensed under the GPL v2. For licencing details see COPYING. */ @@ -93,14 +93,10 @@ enum vss_status_flags { */ struct sched sched = {.max_fileno = 0}; -/** - * The task for obtaining para_server's status (para_client stat). - * - * \sa struct task, struct sched. - */ +/* The task for obtaining para_server's status (para_client stat). */ struct status_task { /** The associated task structure of audiod. */ - struct task task; + struct task *task; /** Client data associated with the stat task. */ struct client_task *ct; /** Do not restart client command until this time. */ @@ -168,7 +164,7 @@ struct command_task { /** the local listening socket */ int fd; /** the associated task structure */ - struct task task; + struct task *task; }; /** iterate over all supported audio formats */ @@ -391,6 +387,7 @@ static void close_receiver(int slot_num) audio_formats[s->format], slot_num); a->receiver->close(s->receiver_node); btr_remove_node(&s->receiver_node->btrn); + task_reap(&s->receiver_node->task); free(s->receiver_node); s->receiver_node = NULL; tv_add(now, &(struct timeval)EMBRACE(0, 200 * 1000), @@ -407,6 +404,7 @@ static void writer_cleanup(struct writer_node *wn) PARA_INFO_LOG("closing %s\n", writer_names[wn->writer_num]); w->close(wn); btr_remove_node(&wn->btrn); + task_reap(&wn->task); } static void close_writers(struct slot_info *s) @@ -444,6 +442,7 @@ static void close_filters(struct slot_info *s) if (f->close) f->close(fn); btr_remove_node(&fn->btrn); + task_reap(&fn->task); } free(s->fns); s->fns = NULL; @@ -459,7 +458,7 @@ static void notify_receivers(int error) continue; if (!s->receiver_node) continue; - task_notify(&s->receiver_node->task, error); + task_notify(s->receiver_node->task, error); } } @@ -497,22 +496,26 @@ static void open_filters(struct slot_info *s) s->fns = para_calloc(nf * sizeof(struct filter_node)); parent = s->receiver_node->btrn; for (i = 0; i < nf; i++) { + char buf[20]; struct filter *f = filters + a->filter_nums[i]; fn = s->fns + i; fn->filter_num = a->filter_nums[i]; fn->conf = a->filter_conf[i]; - fn->task.pre_select = f->pre_select; - fn->task.post_select = f->post_select; fn->btrn = btr_new_node(&(struct btr_node_description) EMBRACE(.name = f->name, .parent = parent, .handler = f->execute, .context = fn)); f->open(fn); - register_task(&sched, &fn->task); + sprintf(buf, "%s (slot %d)", f->name, (int)(s - slot)); + fn->task = task_register(&(struct task_info) { + .name = buf, + .pre_select = f->pre_select, + .post_select = f->post_select, + .context = fn, + }, &sched); parent = fn->btrn; PARA_NOTICE_LOG("%s filter %d/%d (%s) started in slot %d\n", audio_formats[s->format], i, nf, f->name, (int)(s - slot)); - sprintf(fn->task.status, "%s (slot %d)", f->name, (int)(s - slot)); } } @@ -566,10 +569,12 @@ static int open_receiver(int format) s->receiver_node = rn; PARA_NOTICE_LOG("started %s: %s receiver in slot %d\n", audio_formats[format], r->name, slot_num); - rn->task.pre_select = r->pre_select; - rn->task.post_select = r->post_select; - sprintf(rn->task.status, "%s receiver node", r->name); - register_task(&sched, &rn->task); + rn->task = task_register(&(struct task_info) { + .name = r->name, + .pre_select = r->pre_select, + .post_select = r->post_select, + .context = rn, + }, &sched); return slot_num; } @@ -584,7 +589,7 @@ static bool receiver_running(void) if (!s->receiver_node) continue; - if (s->receiver_node->task.error >= 0) + if (task_status(s->receiver_node->task) >= 0) return true; if (ss1 == ss2) return true; @@ -611,7 +616,7 @@ struct btr_node *audiod_get_btr_root(void) struct timeval rstime; if (!s->receiver_node) continue; - if (s->receiver_node->task.error < 0) + if (task_status(s->receiver_node->task) < 0) continue; btr_get_node_start(s->receiver_node->btrn, &rstime); if (newest_slot >= 0 && tv_diff(&rstime, &newest_rstime, NULL) < 0) @@ -995,16 +1000,15 @@ err: exit(EXIT_FAILURE); } -static void signal_pre_select(struct sched *s, struct task *t) +static void signal_pre_select(struct sched *s, void *context) { - struct signal_task *st = container_of(t, struct signal_task, task); + struct signal_task *st = context; para_fd_set(st->fd, &s->rfds, &s->max_fileno); } -static int signal_post_select(struct sched *s, __a_unused struct task *t) +static int signal_post_select(struct sched *s, __a_unused void *context) { int signum; - signum = para_next_signal(&s->rfds); switch (signum) { case SIGINT: @@ -1016,23 +1020,16 @@ static int signal_post_select(struct sched *s, __a_unused struct task *t) return 0; } -static void signal_setup_default(struct signal_task *st) +static void command_pre_select(struct sched *s, void *context) { - st->task.pre_select = signal_pre_select; - st->task.post_select = signal_post_select; - sprintf(st->task.status, "signal task"); -} - -static void command_pre_select(struct sched *s, struct task *t) -{ - struct command_task *ct = container_of(t, struct command_task, task); + struct command_task *ct = context; para_fd_set(ct->fd, &s->rfds, &s->max_fileno); } -static int command_post_select(struct sched *s, struct task *t) +static int command_post_select(struct sched *s, void *context) { int ret; - struct command_task *ct = container_of(t, struct command_task, task); + struct command_task *ct = context; static struct timeval last_status_dump; struct timeval tmp, delay; bool force = true; @@ -1067,17 +1064,21 @@ dump: static void init_command_task(struct command_task *ct) { - ct->task.pre_select = command_pre_select; - ct->task.post_select = command_post_select; - ct->task.error = 0; ct->fd = audiod_get_socket(); /* doesn't return on errors */ - sprintf(ct->task.status, "command task"); + + ct->task = task_register(&(struct task_info) { + .name = "command", + .pre_select = command_pre_select, + .post_select = command_post_select, + .context = ct, + }, &sched); } static void close_stat_pipe(void) { if (!stat_task->ct) return; + task_reap(&stat_task->ct->task); client_close(stat_task->ct); stat_task->ct = NULL; clear_and_dump_items(); @@ -1103,17 +1104,17 @@ static bool must_close_slot(int slot_num) if (s->format < 0) return false; - if (s->receiver_node && s->receiver_node->task.error >= 0) + if (s->receiver_node && task_status(s->receiver_node->task) >= 0) return false; for (i = 0; i < a->num_filters; i++) - if (s->fns && s->fns[i].task.error >= 0) + if (s->fns && task_status(s->fns[i].task) >= 0) return false; if (a->num_writers > 0) { for (i = 0; i < a->num_writers; i++) - if (s->wns && s->wns[i].task.error >= 0) + if (s->wns && task_status(s->wns[i].task) >= 0) return false; } else { - if (s->wns && s->wns[0].task.error >= 0) + if (s->wns && task_status(s->wns[0].task) >= 0) return false; } return true; @@ -1171,7 +1172,6 @@ static void start_stop_decoders(void) { int ret; struct slot_info *sl; - struct audio_format_info *a; close_unused_slots(); if (audiod_status != AUDIOD_ON || @@ -1185,17 +1185,15 @@ static void start_stop_decoders(void) return; } sl = slot + ret; - a = afi + sl->format; - if (a->num_filters) - open_filters(sl); + open_filters(sl); open_writers(sl); activate_grab_clients(&sched); btr_log_tree(sl->receiver_node->btrn, LL_NOTICE); } -static void status_pre_select(struct sched *s, struct task *t) +static void status_pre_select(struct sched *s, void *context) { - struct status_task *st = container_of(t, struct status_task, task); + struct status_task *st = context; int i, ret, cafn = stat_task->current_audio_format_num; if (must_start_decoder()) @@ -1225,15 +1223,15 @@ min_delay: } /* restart the client task if necessary */ -static int status_post_select(struct sched *s, struct task *t) +static int status_post_select(struct sched *s, void *context) { - struct status_task *st = container_of(t, struct status_task, task); + struct status_task *st = context; if (audiod_status == AUDIOD_OFF) { if (!st->ct) goto out; - if (st->ct->task.error >= 0) { - task_notify(&st->ct->task, E_AUDIOD_OFF); + if (task_status(st->ct->task) >= 0) { + task_notify(st->ct->task, E_AUDIOD_OFF); goto out; } close_stat_pipe(); @@ -1256,14 +1254,14 @@ static int status_post_select(struct sched *s, struct task *t) struct timeval diff; tv_diff(now, &st->last_status_read, &diff); if (diff.tv_sec > 61) - task_notify(&st->ct->task, E_STATUS_TIMEOUT); + task_notify(st->ct->task, E_STATUS_TIMEOUT); goto out; } btr_merge(st->btrn, st->min_iqs); sz = btr_next_buffer(st->btrn, &buf); ret = for_each_stat_item(buf, sz, update_item); if (ret < 0) { - task_notify(&st->ct->task, -ret); + task_notify(st->ct->task, -ret); goto out; } if (sz != ret) { @@ -1305,14 +1303,18 @@ out: static void init_status_task(struct status_task *st) { memset(st, 0, sizeof(struct status_task)); - st->task.pre_select = status_pre_select; - st->task.post_select = status_post_select; st->sa_time_diff_sign = 1; st->clock_diff_count = conf.clock_diff_count_arg; st->current_audio_format_num = -1; - sprintf(st->task.status, "stat"); st->btrn = btr_new_node(&(struct btr_node_description) EMBRACE(.name = "stat")); + + stat_task->task = task_register(&(struct task_info) { + .name = "stat", + .pre_select = status_pre_select, + .post_select = status_post_select, + .context = stat_task, + }, &sched); } static void set_initial_status(void) @@ -1392,7 +1394,7 @@ int main(int argc, char *argv[]) writer_init(); if (conf.help_given || conf.detailed_help_given) print_help_and_die(); - drop_privileges_or_die(conf.user_arg, conf.group_arg); + daemon_drop_privileges_or_die(conf.user_arg, conf.group_arg); parse_config_or_die(); init_colors_or_die(); init_random_seed_or_die(); @@ -1410,13 +1412,12 @@ int main(int argc, char *argv[]) PARA_EMERG_LOG("%s\n", para_strerror(-ret)); exit(EXIT_FAILURE); } - log_welcome("para_audiod"); - set_server_start_time(NULL); + daemon_log_welcome("para_audiod"); + daemon_set_start_time(); set_initial_status(); FOR_EACH_SLOT(i) clear_slot(i); setup_signal_handling(); - signal_setup_default(sig_task); init_status_task(stat_task); init_command_task(cmd_task); @@ -1424,12 +1425,17 @@ int main(int argc, char *argv[]) if (conf.daemon_given) daemonize(false /* parent exits immediately */); - register_task(&sched, &sig_task->task); - register_task(&sched, &cmd_task->task); - register_task(&sched, &stat_task->task); + sig_task->task = task_register(&(struct task_info) { + .name = "signal", + .pre_select = signal_pre_select, + .post_select = signal_post_select, + .context = sig_task, + }, &sched); + sched.default_timeout.tv_sec = 2; sched.default_timeout.tv_usec = 999 * 1000; ret = schedule(&sched); + sched_shutdown(&sched); PARA_EMERG_LOG("%s\n", para_strerror(-ret)); return EXIT_FAILURE; diff --git a/audiod.h b/audiod.h index aa98001c..484caa23 100644 --- a/audiod.h +++ b/audiod.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2006-2014 Andre Noll + * Copyright (C) 2006-2014 Andre Noll * * Licensed under the GPL v2. For licencing details see COPYING. */ diff --git a/audiod_command.c b/audiod_command.c index 56d922e6..d5c53bf9 100644 --- a/audiod_command.c +++ b/audiod_command.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2005-2014 Andre Noll + * Copyright (C) 2005-2014 Andre Noll * * Licensed under the GPL v2. For licencing details see COPYING. */ @@ -527,7 +527,7 @@ void audiod_status_dump(bool force) free(new); } - new = get_server_uptime_str(now); + new = daemon_get_uptime_str(now); old = stat_item_values[SI_AUDIOD_UPTIME]; if (force || !old || strcmp(old, new)) { free(old); diff --git a/bash_completion b/bash_completion index 33bf64f6..7f1aecb6 100644 --- a/bash_completion +++ b/bash_completion @@ -1,4 +1,4 @@ -# Copyright (C) 2007-2014 Andre Noll +# Copyright (C) 2007-2014 Andre Noll # # Licensed under the GPL v2. For licencing details see COPYING. diff --git a/blob.c b/blob.c index 9973de95..bdff9061 100644 --- a/blob.c +++ b/blob.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2007-2014 Andre Noll + * Copyright (C) 2007-2014 Andre Noll * * Licensed under the GPL v2. For licencing details see COPYING. */ diff --git a/buffer_tree.c b/buffer_tree.c index 44b73c94..03696b16 100644 --- a/buffer_tree.c +++ b/buffer_tree.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2009-2014 Andre Noll + * Copyright (C) 2009-2014 Andre Noll * * Licensed under the GPL v2. For licencing details see COPYING. */ diff --git a/buffer_tree.h b/buffer_tree.h index e01cb906..f69fb216 100644 --- a/buffer_tree.h +++ b/buffer_tree.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2009-2014 Andre Noll + * Copyright (C) 2009-2014 Andre Noll * * Licensed under the GPL v2. For licencing details see COPYING. */ diff --git a/check_wav.c b/check_wav.c index a36cea9a..9d6f01a0 100644 --- a/check_wav.c +++ b/check_wav.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2005-2014 Andre Noll + * Copyright (C) 2005-2014 Andre Noll * * Licensed under the GPL v2. For licencing details see COPYING. */ diff --git a/check_wav.h b/check_wav.h index 5310d170..14a8362c 100644 --- a/check_wav.h +++ b/check_wav.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2012-2014 Andre Noll + * Copyright (C) 2012-2014 Andre Noll * * Licensed under the GPL v2. For licencing details see COPYING. */ diff --git a/chunk_queue.c b/chunk_queue.c index 5328c113..672c5f02 100644 --- a/chunk_queue.c +++ b/chunk_queue.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2007-2014 Andre Noll + * Copyright (C) 2007-2014 Andre Noll * * Licensed under the GPL v2. For licencing details see COPYING. */ diff --git a/chunk_queue.h b/chunk_queue.h index 946cacda..79c57f06 100644 --- a/chunk_queue.h +++ b/chunk_queue.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2007-2014 Andre Noll + * Copyright (C) 2007-2014 Andre Noll * * Licensed under the GPL v2. For licencing details see COPYING. */ diff --git a/client.c b/client.c index b39a8b01..4c4806f9 100644 --- a/client.c +++ b/client.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 1997-2014 Andre Noll + * Copyright (C) 1997-2014 Andre Noll * * Licensed under the GPL v2. For licencing details see COPYING. */ @@ -39,24 +39,24 @@ __printf_2_3 void (*para_log)(int, const char*, ...) = stderr_log; #include "afs_completion.h" struct exec_task { - struct task task; + struct task *task; struct btr_node *btrn; char *result_buf; size_t result_size; }; -static void exec_pre_select(struct sched *s, struct task *t) +static void exec_pre_select(struct sched *s, void *context) { - struct exec_task *et = container_of(t, struct exec_task, task); + struct exec_task *et = context; int ret = btr_node_status(et->btrn, 0, BTR_NT_LEAF); if (ret != 0) sched_min_delay(s); } -static int exec_post_select(__a_unused struct sched *s, struct task *t) +static int exec_post_select(__a_unused struct sched *s, void *context) { - struct exec_task *et = container_of(t, struct exec_task, task); + struct exec_task *et = context; struct btr_node *btrn = et->btrn; char *buf; size_t sz; @@ -93,11 +93,6 @@ static int execute_client_command(const char *cmd, char **result) int ret; struct sched command_sched = {.default_timeout = {.tv_sec = 1}}; struct exec_task exec_task = { - .task = { - .pre_select = exec_pre_select, - .post_select = exec_post_select, - .status = "client exec task", - }, .result_buf = para_strdup(""), .result_size = 1, }; @@ -107,11 +102,17 @@ static int execute_client_command(const char *cmd, char **result) goto out; exec_task.btrn = btr_new_node(&(struct btr_node_description) EMBRACE(.name = "exec_collect")); - register_task(&command_sched, &exec_task.task); + exec_task.task = task_register(&(struct task_info) { + .name = "client exec", + .pre_select = exec_pre_select, + .post_select = exec_post_select, + .context = &exec_task, + }, &command_sched); ret = client_connect(ct, &command_sched, NULL, exec_task.btrn); if (ret < 0) goto out; schedule(&command_sched); + sched_shutdown(&command_sched); *result = exec_task.result_buf; btr_remove_node(&exec_task.btrn); ret = 1; @@ -495,6 +496,7 @@ __noreturn static void interactive_session(void) goto out; para_log = i9e_log; ret = schedule(&sched); + sched_shutdown(&sched); i9e_close(); para_log = stderr_log; out: @@ -528,36 +530,29 @@ __noreturn static void print_completions(void) struct supervisor_task { bool stdout_task_started; - struct task task; + struct task *task; }; -static int supervisor_post_select(struct sched *s, struct task *t) +static int supervisor_post_select(struct sched *s, void *context) { - struct supervisor_task *svt = container_of(t, struct supervisor_task, - task); + struct supervisor_task *svt = context; + int ret = task_status(ct->task); - if (ct->task.error < 0) - return ct->task.error; + if (ret < 0) + return ret; if (!svt->stdout_task_started && ct->status == CL_EXECUTING) { - stdout_set_defaults(&sot); - register_task(s, &sot.task); + stdout_task_register(&sot, s); svt->stdout_task_started = true; return 1; } if (ct->status == CL_SENDING) { - stdin_set_defaults(&sit); - register_task(s, &sit.task); + stdin_task_register(&sit, s); return -E_TASK_STARTED; } return 0; } -static struct supervisor_task supervisor_task = { - .task = { - .post_select = supervisor_post_select, - .status = "supervisor task" - } -}; +static struct supervisor_task supervisor_task; /** * The client program to connect to para_server. @@ -605,20 +600,29 @@ int main(int argc, char *argv[]) goto out; sot.btrn = btr_new_node(&(struct btr_node_description) EMBRACE(.name = "stdout", .parent = ct->btrn[0])); - register_task(&sched, &supervisor_task.task); + supervisor_task.task = task_register(&(struct task_info) { + .name = "supervisor", + .post_select = supervisor_post_select, + .context = &supervisor_task, + }, &sched); + ret = schedule(&sched); - if (ret >= 0 && ct->task.error < 0) { - switch(ct->task.error) { - /* these are not errors */ - case -E_SERVER_CMD_SUCCESS: - case -E_EOF: - case -E_SERVER_EOF: - case -E_BTR_EOF: - ret = 0; - break; - default: ret = -E_SERVER_CMD_FAILURE; + if (ret >= 0) { + ret = task_status(ct->task); + if (ret < 0) { + switch (ret) { + /* these are not errors */ + case -E_SERVER_CMD_SUCCESS: + case -E_EOF: + case -E_SERVER_EOF: + case -E_BTR_EOF: + ret = 0; + break; + default: ret = -E_SERVER_CMD_FAILURE; + } } } + sched_shutdown(&sched); out: if (ret < 0) PARA_ERROR_LOG("%s\n", para_strerror(-ret)); diff --git a/client.h b/client.h index e304f092..86148b97 100644 --- a/client.h +++ b/client.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 1997-2014 Andre Noll + * Copyright (C) 1997-2014 Andre Noll * * Licensed under the GPL v2. For licencing details see COPYING. */ @@ -47,7 +47,7 @@ struct client_task { /** Paraslash user name. */ char *user; /** The client task structure. */ - struct task task; + struct task *task; /** List of features supported by the server. */ char **features; }; diff --git a/client_common.c b/client_common.c index 8212abb1..0ae163ad 100644 --- a/client_common.c +++ b/client_common.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 1997-2014 Andre Noll + * Copyright (C) 1997-2014 Andre Noll * * Licensed under the GPL v2. For licencing details see COPYING. */ @@ -53,24 +53,19 @@ void client_close(struct client_task *ct) free(ct); } -/** +/* * The preselect hook for server commands. * - * \param s Pointer to the scheduler. - * \param t Pointer to the task struct for this command. - * * The task pointer must contain a pointer to the initialized client data * structure as it is returned by client_open(). * * This function checks the state of the connection and adds the file descriptor - * of the connection to the read or write fd set of \a s accordingly. - * - * \sa register_task() client_open(), struct sched, struct task. + * of the connection to the read or write fd set of s accordingly. */ -static void client_pre_select(struct sched *s, struct task *t) +static void client_pre_select(struct sched *s, void *context) { int ret; - struct client_task *ct = container_of(t, struct client_task, task); + struct client_task *ct = context; if (ct->scc.fd < 0) return; @@ -268,27 +263,22 @@ static int send_sb_command(struct client_task *ct) return send_sb(ct, 0, command, len, SBD_COMMAND, false); } -/** +/* * The post select hook for client commands. * - * \param s Pointer to the scheduler. - * \param t Pointer to the task struct for this command. - * * Depending on the current state of the connection and the status of the read - * and write fd sets of \a s, this function performs the necessary steps to - * authenticate the connection, to send the command given by \a t->private_data + * and write fd sets of s, this function performs the necessary steps to + * authenticate the connection, to send the command given by t->private_data * and to receive para_server's output, if any. - * - * \sa struct sched, struct task. */ -static int client_post_select(struct sched *s, struct task *t) +static int client_post_select(struct sched *s, void *context) { - struct client_task *ct = container_of(t, struct client_task, task); + struct client_task *ct = context; int ret = 0; size_t n; char buf[CLIENT_BUFSIZE]; - ret = task_get_notification(t); + ret = task_get_notification(ct->task); if (ret < 0) goto out; if (ct->scc.fd < 0) @@ -496,11 +486,13 @@ int client_connect(struct client_task *ct, struct sched *s, EMBRACE(.name = "client recv", .parent = NULL, .child = child)); ct->btrn[1] = btr_new_node(&(struct btr_node_description) EMBRACE(.name = "client send", .parent = parent, .child = NULL)); - ct->task.pre_select = client_pre_select; - ct->task.post_select = client_post_select; - ct->task.error = 0; - sprintf(ct->task.status, "client"); - register_task(s, &ct->task); + + ct->task = task_register(&(struct task_info) { + .name = "client", + .pre_select = client_pre_select, + .post_select = client_post_select, + .context = ct, + }, s); return 1; err_out: close(ct->scc.fd); diff --git a/close_on_fork.c b/close_on_fork.c index eb470cf6..0e1389a6 100644 --- a/close_on_fork.c +++ b/close_on_fork.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2005-2014 Andre Noll + * Copyright (C) 2005-2014 Andre Noll * * Licensed under the GPL v2. For licencing details see COPYING. */ diff --git a/command.c b/command.c index eb15875c..c832beea 100644 --- a/command.c +++ b/command.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 1997-2014 Andre Noll + * Copyright (C) 1997-2014 Andre Noll * * Licensed under the GPL v2. For licencing details see COPYING. */ @@ -385,7 +385,7 @@ static int com_si(struct command_context *cc) sender_info = para_strcat(sender_info, info); free(info); } - ut = get_server_uptime_str(now); + ut = daemon_get_uptime_str(now); ret = xasprintf(&msg, "version: %s\n" "up: %s\nplayed: %u\n" diff --git a/compress_filter.c b/compress_filter.c index b488f55c..edf733e3 100644 --- a/compress_filter.c +++ b/compress_filter.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2005-2014 Andre Noll + * Copyright (C) 2005-2014 Andre Noll * * Licensed under the GPL v2. For licencing details see COPYING. */ @@ -41,9 +41,9 @@ static void compress_close(struct filter_node *fn) free(fn->private_data); } -static int compress_post_select(__a_unused struct sched *s, struct task *t) +static int compress_post_select(__a_unused struct sched *s, void *context) { - struct filter_node *fn = container_of(t, struct filter_node, task); + struct filter_node *fn = context; struct private_compress_data *pcd = fn->private_data; struct btr_node *btrn = fn->btrn; bool inplace = btr_inplace_ok(btrn); diff --git a/configure.ac b/configure.ac index 30bce8ee..37f2fbc6 100644 --- a/configure.ac +++ b/configure.ac @@ -3,7 +3,7 @@ AC_PREREQ([2.61]) -AC_INIT([paraslash],[git],[maan@systemlinux.org]) +AC_INIT([paraslash],[git],[maan@tuebingen.mpg.de]) AC_CONFIG_HEADER([config.h]) AC_CONFIG_FILES([Makefile]) @@ -143,7 +143,7 @@ if test "$have_osl" = "yes"; then else AC_MSG_WARN([libosl not found, can not build para_server. Download libosl at - http://systemlinux.org/~maan/osl + http://people.tuebingen.mpg.de/maan/osl/ or execute git clone git://git.tuebingen.mpg.de/osl ]) @@ -380,11 +380,17 @@ if test -n "$with_ogg_libs"; then fi AC_CHECK_HEADERS([ogg/ogg.h], [], [ have_ogg="no"; ]) AC_CHECK_LIB([ogg], [ogg_stream_init], [], [ have_ogg="no" ]) +CPPFLAGS="$OLD_CPPFLAGS" +LDFLAGS="$OLD_LDFLAGS" +LIBS="$OLD_LIBS" have_vorbis="yes" have_speex="yes" have_opus="yes" if test "$have_ogg" = "yes"; then + OLD_CPPFLAGS="$CPPFLAGS" + OLD_LDFLAGS="$LDFLAGS" + OLD_LIBS="$LIBS" # vorbis if test -n "$with_vorbis_headers"; then vorbis_cppflags="-I$with_vorbis_headers" @@ -396,8 +402,14 @@ if test "$have_ogg" = "yes"; then fi AC_CHECK_HEADERS([vorbis/codec.h], [], [ have_vorbis="no" ]) AC_CHECK_LIB([vorbis], [vorbis_info_init], [], [ have_vorbis="no" ]) + CPPFLAGS="$OLD_CPPFLAGS" + LDFLAGS="$OLD_LDFLAGS" + LIBS="$OLD_LIBS" # speex + OLD_CPPFLAGS="$CPPFLAGS" + OLD_LDFLAGS="$LDFLAGS" + OLD_LIBS="$LIBS" if test -n "$with_speex_headers"; then speex_cppflags="-I$with_speex_headers" CPPFLAGS="$CPPFLAGS $speex_cppflags" @@ -408,8 +420,14 @@ if test "$have_ogg" = "yes"; then fi AC_CHECK_LIB([speex], [speex_decoder_init], [], [ have_speex="no" ]) AC_CHECK_HEADERS([speex/speex.h], [], [ have_speex="no" ]) + CPPFLAGS="$OLD_CPPFLAGS" + LDFLAGS="$OLD_LDFLAGS" + LIBS="$OLD_LIBS" # opus + OLD_CPPFLAGS="$CPPFLAGS" + OLD_LDFLAGS="$LDFLAGS" + OLD_LIBS="$LIBS" if test -n "$with_opus_headers"; then opus_cppflags="-I$with_opus_headers" CPPFLAGS="$CPPFLAGS $opus_cppflags" @@ -420,6 +438,9 @@ if test "$have_ogg" = "yes"; then fi AC_CHECK_LIB([opus], [opus_multistream_decode], [], [ have_opus="no" ]) AC_CHECK_HEADERS([opus/opus.h], [], [ have_opus="no" ]) + CPPFLAGS="$OLD_CPPFLAGS" + LDFLAGS="$OLD_LDFLAGS" + LIBS="$OLD_LIBS" else AC_MSG_WARN([vorbis/speex/opus depend on libogg, which was not detected]) have_vorbis="no" @@ -440,6 +461,7 @@ if test "$have_vorbis" = "yes" || \ fi if test "$have_vorbis" = "yes"; then AC_DEFINE(HAVE_OGGVORBIS, 1, define to 1 to turn on ogg/vorbis support) + AC_SUBST(vorbis_cppflags) vorbis_ldflags="$vorbis_libs -lvorbis -lvorbisfile" AC_SUBST(vorbis_ldflags) fi @@ -460,9 +482,6 @@ if test "$have_opus" = "yes"; then else AC_MSG_WARN([no ogg/opus $msg]) fi -CPPFLAGS="$OLD_CPPFLAGS" -LDFLAGS="$OLD_LDFLAGS" -LIBS="$OLD_LIBS" ########################################################################### faad have_faad=yes OLD_CPPFLAGS="$CPPFLAGS" @@ -986,7 +1005,7 @@ if test "$have_openssl" = "yes" -o "$have_gcrypt" = "yes"; then fi if test "$have_core_audio" = "yes"; then audiod_errlist_objs="$audiod_errlist_objs osx_write ipc" - audiod_cmdline_objs="$audiod_cmdline_objs osx_write.cmdline" + audiod_cmdline_objs="$audiod_cmdline_objs osx_write" fi if test "$have_vorbis" = "yes"; then audiod_errlist_objs="$audiod_errlist_objs oggdec_filter" @@ -1102,6 +1121,7 @@ if test "$have_curses" = "yes"; then gui gui_theme time + sched version ggo " @@ -1350,7 +1370,7 @@ play_cmdline_objs=" " if test "$have_core_audio" = "yes"; then play_errlist_objs="$play_errlist_objs osx_write ipc" - play_cmdline_objs="$play_cmdline_objs osx_write.cmdline" + play_cmdline_objs="$play_cmdline_objs osx_write" fi if test "$have_vorbis" = "yes" || \ test "$have_speex" = "yes" || \ @@ -1424,7 +1444,7 @@ default_writer="FILE_WRITE" if test "$have_core_audio" = "yes"; then write_errlist_objs="$write_errlist_objs osx_write ipc" - write_cmdline_objs="$write_cmdline_objs osx_write.cmdline" + write_cmdline_objs="$write_cmdline_objs osx_write" writers="$writers osx" default_writer="OSX_WRITE" fi diff --git a/crypt.c b/crypt.c index 0137e004..1678977a 100644 --- a/crypt.c +++ b/crypt.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2005-2014 Andre Noll + * Copyright (C) 2005-2014 Andre Noll * * Licensed under the GPL v2. For licencing details see COPYING. */ diff --git a/crypt.h b/crypt.h index 324a87b3..4b17b4c0 100644 --- a/crypt.h +++ b/crypt.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2005-2014 Andre Noll + * Copyright (C) 2005-2014 Andre Noll * * Licensed under the GPL v2. For licencing details see COPYING. */ diff --git a/crypt_backend.h b/crypt_backend.h index ddebe62e..040a719b 100644 --- a/crypt_backend.h +++ b/crypt_backend.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2014 Andre Noll + * Copyright (C) 2011-2014 Andre Noll * * Licensed under the GPL v2. For licencing details see COPYING. */ diff --git a/crypt_common.c b/crypt_common.c index fb6e1ef4..a6ba4f1e 100644 --- a/crypt_common.c +++ b/crypt_common.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2005-2014 Andre Noll + * Copyright (C) 2005-2014 Andre Noll * * Licensed under the GPL v2. For licencing details see COPYING. */ diff --git a/daemon.c b/daemon.c index 05002f4e..b0d8fd74 100644 --- a/daemon.c +++ b/daemon.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 1997-2014 Andre Noll + * Copyright (C) 1997-2014 Andre Noll * * Licensed under the GPL v2. For licencing details see COPYING. */ @@ -229,7 +229,7 @@ void daemon_open_log_or_die(void) /** * Log the startup message containing the paraslash version. */ -void log_welcome(const char *whoami) +void daemon_log_welcome(const char *whoami) { PARA_INFO_LOG("welcome to %s " PACKAGE_VERSION " ("BUILD_DATE")\n", whoami); @@ -249,7 +249,7 @@ void log_welcome(const char *whoami) * * \sa getpwnam(3), getuid(2), setuid(2), getgrnam(2), setgid(2) */ -void drop_privileges_or_die(const char *username, const char *groupname) +void daemon_drop_privileges_or_die(const char *username, const char *groupname) { struct passwd *p; char *tmp; @@ -290,27 +290,20 @@ void drop_privileges_or_die(const char *username, const char *groupname) } /** - * Set the server startup time. + * Set the startup time. * - * \param startuptime The value to store as the server start time. + * This should be called once on startup. It sets the start time to the + * current time. The stored time is used for retrieving the server uptime. * - * This should be called once on startup with \a startuptime either NULL or a - * pointer to a struct timeval which contains the current time. If \a - * startuptime is NULL, the server start time is set to the current time. - * - * \sa time(2), difftime(3) \ref get_server_uptime(), \ref - * get_server_uptime_str(). + * \sa time(2), \ref daemon_get_uptime(), \ref daemon_get_uptime_str(). */ -void set_server_start_time(const struct timeval *startuptime) +void daemon_set_start_time(void) { - if (startuptime) - me->startuptime = startuptime->tv_sec; - else - time(&me->startuptime); + time(&me->startuptime); } /** - * Get the server uptime. + * Get the uptime. * * \param current_time The current time. * @@ -319,9 +312,9 @@ void set_server_start_time(const struct timeval *startuptime) * * \return This returns the server uptime in seconds, i.e. the difference * between the current time and the value stored previously via \ref - * set_server_start_time(). + * daemon_set_start_time(). */ -time_t get_server_uptime(const struct timeval *current_time) +time_t daemon_get_uptime(const struct timeval *current_time) { time_t t; @@ -334,15 +327,15 @@ time_t get_server_uptime(const struct timeval *current_time) /** * Construct a string containing the current uptime. * - * \param current_time See a \ref get_server_uptime(). + * \param current_time See a \ref daemon_get_uptime(). * * \return A dynamically allocated string of the form "days:hours:minutes". * * \sa server_uptime. */ -__malloc char *get_server_uptime_str(const struct timeval *current_time) +__malloc char *daemon_get_uptime_str(const struct timeval *current_time) { - long t = get_server_uptime(current_time); + long t = daemon_get_uptime(current_time); return make_message("%li:%02li:%02li", t / 86400, (t / 3600) % 24, (t / 60) % 60); } diff --git a/daemon.h b/daemon.h index fd435577..df9de6a3 100644 --- a/daemon.h +++ b/daemon.h @@ -4,12 +4,11 @@ void daemonize(bool parent_waits); void daemon_open_log_or_die(void); void daemon_close_log(void); -void log_welcome(const char *whoami); -void drop_privileges_or_die(const char *username, const char *groupname); -/** used for server_uptime() */ -void set_server_start_time(const struct timeval *startuptime); -time_t get_server_uptime(const struct timeval *current_time); -__malloc char *get_server_uptime_str(const struct timeval *current_time); +void daemon_log_welcome(const char *whoami); +void daemon_drop_privileges_or_die(const char *username, const char *groupname); +void daemon_set_start_time(void); +time_t daemon_get_uptime(const struct timeval *current_time); +__malloc char *daemon_get_uptime_str(const struct timeval *current_time); void daemon_set_logfile(char *logfile_name); void daemon_set_flag(unsigned flag); void daemon_clear_flag(unsigned flag); diff --git a/dccp_recv.c b/dccp_recv.c index 796a7e6b..9e8f8683 100644 --- a/dccp_recv.c +++ b/dccp_recv.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2006-2014 Andre Noll + * Copyright (C) 2006-2014 Andre Noll * * Licensed under the GPL v2. For licencing details see COPYING. */ @@ -119,25 +119,24 @@ static void *dccp_recv_parse_config(int argc, char **argv) return tmp; } -static void dccp_recv_pre_select(struct sched *s, struct task *t) +static void dccp_recv_pre_select(struct sched *s, void *context) { - struct receiver_node *rn = container_of(t, struct receiver_node, task); + struct receiver_node *rn = context; - t->error = 0; - if (generic_recv_pre_select(s, t) <= 0) + if (generic_recv_pre_select(s, rn) <= 0) return; para_fd_set(rn->fd, &s->rfds, &s->max_fileno); } -static int dccp_recv_post_select(struct sched *s, struct task *t) +static int dccp_recv_post_select(struct sched *s, void *context) { - struct receiver_node *rn = container_of(t, struct receiver_node, task); + struct receiver_node *rn = context; struct btr_node *btrn = rn->btrn; struct iovec iov[2]; int ret, iovcnt; size_t num_bytes; - ret = task_get_notification(t); + ret = task_get_notification(rn->task); if (ret < 0) goto out; ret = btr_node_status(btrn, 0, BTR_NT_ROOT); diff --git a/dccp_send.c b/dccp_send.c index 1e95aac6..ed03b614 100644 --- a/dccp_send.c +++ b/dccp_send.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2006-2014 Andre Noll + * Copyright (C) 2006-2014 Andre Noll * * Licensed under the GPL v2. For licencing details see COPYING. */ diff --git a/depend.sh b/depend.sh index 746b0d2b..c6424daa 100755 --- a/depend.sh +++ b/depend.sh @@ -20,6 +20,6 @@ shift shift shift -LC_ALL=C gcc -MM -MG "$@" \ +LC_ALL=C cc -MM -MG "$@" \ | sed -e "s@^\(.*\)\.o:@$dep_dir/\1.d $object_dir/\1.o:@" \ -e "s@[ ^]\([a-zA-Z0-9_]\{1,\}\.cmdline.h\)@ $cmdline_dir/\1@g" diff --git a/error.h b/error.h index dc9385a7..05e7e57e 100644 --- a/error.h +++ b/error.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2006-2014 Andre Noll + * Copyright (C) 2006-2014 Andre Noll * * Licensed under the GPL v2. For licencing details see COPYING. */ @@ -16,7 +16,6 @@ DEFINE_ERRLIST_OBJECT_ENUM; #define TIME_ERRORS #define CLOSE_ON_FORK_ERRORS #define DAEMON_ERRORS -#define GUI_ERRORS #define GUI_THEME_ERRORS #define RINGBUFFER_ERRORS #define SCORE_ERRORS @@ -86,6 +85,8 @@ extern const char **para_errlist[]; PARA_ERROR(FLACDEC_DECODER_INIT, "could not init stream decoder"), \ PARA_ERROR(FLACDEC_EOF, "flacdec encountered end of file condition"), \ +#define GUI_ERRORS \ + PARA_ERROR(GUI_SIGCHLD, "received SIGCHLD"), \ #define FLAC_AFH_ERRORS \ PARA_ERROR(FLAC_CHAIN_ALLOC, "could not create metadata chain"), \ diff --git a/error2.c b/error2.c index 9271dadf..189a2962 100644 --- a/error2.c +++ b/error2.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2013-2014 Andre Noll + * Copyright (C) 2013-2014 Andre Noll * * Licensed under the GPL v2. For licencing details see COPYING. */ diff --git a/exec.c b/exec.c index 5f48436d..004c0437 100644 --- a/exec.c +++ b/exec.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2003-2014 Andre Noll + * Copyright (C) 2003-2014 Andre Noll * * Licensed under the GPL v2. For licencing details see COPYING. */ diff --git a/fade.c b/fade.c index 543a666d..8c488a9f 100644 --- a/fade.c +++ b/fade.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 1998-2014 Andre Noll + * Copyright (C) 1998-2014 Andre Noll * * Licensed under the GPL v2. For licencing details see COPYING. */ diff --git a/fd.c b/fd.c index b8d0d77c..1053268e 100644 --- a/fd.c +++ b/fd.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2006-2014 Andre Noll + * Copyright (C) 2006-2014 Andre Noll * * Licensed under the GPL v2. For licencing details see COPYING. */ diff --git a/fd.h b/fd.h index c8127a4a..3a3221da 100644 --- a/fd.h +++ b/fd.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2006-2014 Andre Noll + * Copyright (C) 2006-2014 Andre Noll * * Licensed under the GPL v2. For licencing details see COPYING. */ diff --git a/fecdec_filter.c b/fecdec_filter.c index b8e130d4..9edbcafe 100644 --- a/fecdec_filter.c +++ b/fecdec_filter.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2009-2014 Andre Noll + * Copyright (C) 2009-2014 Andre Noll * * Licensed under the GPL v2. For licencing details see COPYING. */ @@ -436,9 +436,9 @@ static void fecdec_close(struct filter_node *fn) fn->private_data = NULL; } -static int fecdec_post_select(__a_unused struct sched *s, struct task *t) +static int fecdec_post_select(__a_unused struct sched *s, void *context) { - struct filter_node *fn = container_of(t, struct filter_node, task); + struct filter_node *fn = context; struct btr_node *btrn = fn->btrn; int ret; struct fec_header h; diff --git a/file_write.c b/file_write.c index 7d63469f..393de379 100644 --- a/file_write.c +++ b/file_write.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2006-2014 Andre Noll + * Copyright (C) 2006-2014 Andre Noll * * Licensed under the GPL v2. For licencing details see COPYING. */ @@ -74,9 +74,9 @@ out: return ret; } -static void file_write_pre_select(struct sched *s, struct task *t) +static void file_write_pre_select(struct sched *s, void *context) { - struct writer_node *wn = container_of(t, struct writer_node, task); + struct writer_node *wn = context; struct private_file_write_data *pfwd = wn->private_data; int ret = btr_node_status(wn->btrn, wn->min_iqs, BTR_NT_LEAF); @@ -97,17 +97,16 @@ static void file_write_close(struct writer_node *wn) free(pfwd); } -static int file_write_post_select(__a_unused struct sched *s, - struct task *t) +static int file_write_post_select(__a_unused struct sched *s, void *context) { - struct writer_node *wn = container_of(t, struct writer_node, task); + struct writer_node *wn = context; struct private_file_write_data *pfwd = wn->private_data; struct btr_node *btrn = wn->btrn; int ret; char *buf; size_t bytes; - ret = task_get_notification(t); + ret = task_get_notification(wn->task); if (ret < 0) goto out; ret = btr_node_status(btrn, wn->min_iqs, BTR_NT_LEAF); diff --git a/filter.c b/filter.c index b3dc022e..79574db1 100644 --- a/filter.c +++ b/filter.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2005-2014 Andre Noll + * Copyright (C) 2005-2014 Andre Noll * * Licensed under the GPL v2. For licencing details see COPYING. */ @@ -112,13 +112,13 @@ int main(int argc, char *argv[]) goto out; sit->btrn = btr_new_node(&(struct btr_node_description) EMBRACE(.name = "stdin")); - stdin_set_defaults(sit); - register_task(&s, &sit->task); + stdin_task_register(sit, &s); fns = para_malloc(conf.filter_given * sizeof(*fns)); for (i = 0, parent = sit->btrn; i < conf.filter_given; i++) { char *fa = conf.filter_arg[i]; struct filter_node *fn; + struct task_info ti; fn = fns[i] = para_calloc(sizeof(*fn)); ret = check_filter_arg(fa, &fn->conf); @@ -128,26 +128,27 @@ int main(int argc, char *argv[]) } fn->filter_num = ret; f = filters + fn->filter_num; - sprintf(fn->task.status, "%s", f->name); PARA_DEBUG_LOG("filter #%d: %s\n", i, f->name); fn->btrn = btr_new_node(&(struct btr_node_description) EMBRACE(.name = f->name, .parent = parent, .handler = f->execute, .context = fn)); - fn->task.pre_select = f->pre_select; - fn->task.post_select = f->post_select; + ti.name = f->name; + ti.pre_select = f->pre_select; + ti.post_select = f->post_select; + ti.context = fn; f->open(fn); - register_task(&s, &fn->task); + fn->task = task_register(&ti, &s); parent = fn->btrn; } sot->btrn = btr_new_node(&(struct btr_node_description) EMBRACE(.name = "stdout", .parent = parent)); - stdout_set_defaults(sot); - register_task(&s, &sot->task); + stdout_task_register(sot, &s); s.default_timeout.tv_sec = 1; s.default_timeout.tv_usec = 0; btr_log_tree(sit->btrn, LL_INFO); ret = schedule(&s); + sched_shutdown(&s); out_cleanup: for (i--; i >= 0; i--) { struct filter_node *fn = fns[i]; diff --git a/filter.h b/filter.h index de8ce8e8..c42f121d 100644 --- a/filter.h +++ b/filter.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2005-2014 Andre Noll + * Copyright (C) 2005-2014 Andre Noll * * Licensed under the GPL v2. For licencing details see COPYING. */ @@ -27,7 +27,7 @@ struct filter_node { /** The buffer tree node. */ struct btr_node *btrn; /** The task corresponding to this filter node. */ - struct task task; + struct task *task; /** The minimal input queue size, see \ref btr_node_status(). */ size_t min_iqs; }; @@ -101,14 +101,14 @@ struct filter { * this function is to set file descriptors to be watched by the * subsequent select call to the two fd sets. */ - void (*pre_select)(struct sched *s, struct task *t); + void (*pre_select)(struct sched *s, void *context); /** * Convert (filter) the given data. * * Pointer to the converting function of the filter. On errors, the * post_select function is supposed to return a negative error code. */ - int (*post_select)(struct sched *s, struct task *t); + int (*post_select)(struct sched *s, void *context); /** * Answer a buffer tree query. * @@ -121,7 +121,7 @@ struct filter { void filter_init(void); int check_filter_arg(char *filter_arg, void **conf); void print_filter_helps(unsigned flags); -void generic_filter_pre_select(struct sched *s, struct task *t); +void generic_filter_pre_select(struct sched *s, void *context); int decoder_execute(const char *cmd, unsigned sample_rate, unsigned channels, char **result); diff --git a/filter_common.c b/filter_common.c index 8ce66ea8..6db0c57f 100644 --- a/filter_common.c +++ b/filter_common.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2005-2014 Andre Noll + * Copyright (C) 2005-2014 Andre Noll * * Licensed under the GPL v2. For licencing details see COPYING. */ @@ -132,18 +132,17 @@ void print_filter_helps(unsigned flags) * Set select timeout of the scheduler. * * \param s The scheduler. - * \param t The task struct of this filter. + * \param context Pointer to the filter node (task context). * * This looks at the status of the btr node of the filter. If data is available * in the input queue of the filter, or if an error occurred, a minimal timeout * for the next select call is requested from the scheduler. Otherwise the * scheduler timeout is left unchanged. */ -void generic_filter_pre_select(struct sched *s, struct task *t) +void generic_filter_pre_select(struct sched *s, void *context) { - struct filter_node *fn = container_of(t, struct filter_node, task); + struct filter_node *fn = context; - t->error = 0; if (btr_node_status(fn->btrn, fn->min_iqs, BTR_NT_INTERNAL) != 0) sched_min_delay(s); } diff --git a/flac_afh.c b/flac_afh.c index eeb0e86c..fd7bd24a 100644 --- a/flac_afh.c +++ b/flac_afh.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2014 Andre Noll + * Copyright (C) 2011-2014 Andre Noll * * Licensed under the GPL v2. For licencing details see COPYING. */ diff --git a/flacdec_filter.c b/flacdec_filter.c index 2a58044c..fc382a79 100644 --- a/flacdec_filter.c +++ b/flacdec_filter.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2014 Andre Noll + * Copyright (C) 2011-2014 Andre Noll * * Licensed under the GPL v2. For licencing details see COPYING. */ @@ -210,9 +210,9 @@ static bool output_queue_full(struct btr_node *btrn) return btr_get_output_queue_size(btrn) > FLACDEC_MAX_OUTPUT_SIZE; } -static void flacdec_pre_select(struct sched *s, struct task *t) +static void flacdec_pre_select(struct sched *s, void *context) { - struct filter_node *fn = container_of(t, struct filter_node, task); + struct filter_node *fn = context; struct private_flacdec_data *pfd = fn->private_data; struct btr_node *btrn = fn->btrn; int ret; @@ -226,9 +226,9 @@ static void flacdec_pre_select(struct sched *s, struct task *t) return sched_min_delay(s); } -static int flacdec_post_select(__a_unused struct sched *s, struct task *t) +static int flacdec_post_select(__a_unused struct sched *s, void *context) { - struct filter_node *fn = container_of(t, struct filter_node, task); + struct filter_node *fn = context; struct private_flacdec_data *pfd = fn->private_data; struct btr_node *btrn = fn->btrn; int ret; diff --git a/gcrypt.c b/gcrypt.c index 751c1a4a..af7f2af1 100644 --- a/gcrypt.c +++ b/gcrypt.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2014 Andre Noll + * Copyright (C) 2011-2014 Andre Noll * * Licensed under the GPL v2. For licencing details see COPYING. */ diff --git a/ggo.c b/ggo.c index deea00bb..04abf8eb 100644 --- a/ggo.c +++ b/ggo.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2008-2014 Andre Noll + * Copyright (C) 2008-2014 Andre Noll * * Licensed under the GPL v2. For licencing details see COPYING. */ diff --git a/ggo.h b/ggo.h index 9d9c5044..49bdf1d9 100644 --- a/ggo.h +++ b/ggo.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2008-2014 Andre Noll + * Copyright (C) 2008-2014 Andre Noll * * Licensed under the GPL v2. For licencing details see COPYING. */ diff --git a/grab_client.c b/grab_client.c index 672c96f1..f4bcbb79 100644 --- a/grab_client.c +++ b/grab_client.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2006-2014 Andre Noll + * Copyright (C) 2006-2014 Andre Noll * * Licensed under the GPL v2. For licencing details see COPYING. */ @@ -54,7 +54,7 @@ struct grab_client { /** The point of the grab client's node in the buffer tree. */ struct btr_node *btrn; /* The task of this grab client. */ - struct task task; + struct task *task; /** Belongs to either the active or the inactive list. */ struct list_head node; }; @@ -92,9 +92,9 @@ err: return -E_GC_WRITE; } -static void gc_pre_select(struct sched *s, struct task *t) +static void gc_pre_select(struct sched *s, void *context) { - struct grab_client *gc = container_of(t, struct grab_client, task); + struct grab_client *gc = context; int ret = btr_node_status(gc->btrn, 0, BTR_NT_LEAF); if (ret == 0) @@ -108,7 +108,7 @@ static void gc_pre_select(struct sched *s, struct task *t) * We need this forward declaration as post_select() needs * activate_grab_client and vice versa. */ -static int gc_post_select(struct sched *s, struct task *t); +static int gc_post_select(struct sched *s, void *context); /** * Move a grab client to the active list and start it. @@ -129,12 +129,13 @@ static void gc_activate(struct grab_client *gc, struct sched *s) list_move(&gc->node, &active_grab_client_list); gc->btrn = btr_new_node(&(struct btr_node_description) EMBRACE(.name = name, .parent = parent)); - 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(s, &gc->task); + + gc->task = task_register(&(struct task_info) { + .name = name, + .pre_select = gc_pre_select, + .post_select = gc_post_select, + .context = gc, + }, s); } /** @@ -184,9 +185,9 @@ static int gc_close(struct grab_client *gc, int err) return 0; } -static int gc_post_select(__a_unused struct sched *s, struct task *t) +static int gc_post_select(__a_unused struct sched *s, void *context) { - struct grab_client *gc = container_of(t, struct grab_client, task); + struct grab_client *gc = context; struct btr_node *btrn = gc->btrn; int ret; size_t sz; diff --git a/grab_client.h b/grab_client.h index 91adf2ea..f3de708f 100644 --- a/grab_client.h +++ b/grab_client.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2006-2014 Andre Noll + * Copyright (C) 2006-2014 Andre Noll * * Licensed under the GPL v2. For licencing details see COPYING. */ diff --git a/gui.c b/gui.c index 5a2e659d..61ce0432 100644 --- a/gui.c +++ b/gui.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 1998-2014 Andre Noll + * Copyright (C) 1998-2014 Andre Noll * * Licensed under the GPL v2. For licencing details see COPYING. */ @@ -30,48 +30,52 @@ INIT_GUI_ERRLISTS; static char *stat_content[NUM_STAT_ITEMS]; -#define STANDARD_STATUS_BAR "para_gui " PACKAGE_VERSION " (hit ? for help)" - -static int signal_pipe; - -static struct win_data { +static struct gui_window { WINDOW *win; - size_t begx; - size_t begy; - size_t cols; - size_t lines; + bool needs_update; } top, bot, sb, in, sep; +/** How many lines of output to remember. */ #define RINGBUFFER_SIZE 512 + struct rb_entry { char *msg; size_t len; int color; }; static struct ringbuffer *bot_win_rb; -#define NUM_LINES(len) (1 + (len) / bot.cols) static unsigned scroll_position; -static int curses_active; -static pid_t cmd_pid; +static pid_t exec_pid; -static int command_fds[2]; -static int stat_pipe = -1; +static int exec_fds[2] = {-1, -1}; static struct gui_args_info conf; +static int loglevel; -enum {GETCH_MODE, COMMAND_MODE, EXTERNAL_MODE}; - +/** Type of the process currently being executed. */ +enum exec_status { + EXEC_IDLE, /**< No process running. */ + EXEC_DCMD, /**< para or display process running. */ + EXEC_XCMD, /**< External process running. */ +}; -#define COLOR_STATUSBAR 52 -#define COLOR_COMMAND 53 -#define COLOR_OUTPUT 54 -#define COLOR_MSG 55 -#define COLOR_ERRMSG 56 -#define COLOR_WELCOME 57 -#define COLOR_SEPARATOR 58 -#define COLOR_TOP 59 -#define COLOR_BOT 60 +/** + * Codes for various colors. + * + * Each status item has its own color pair. The ones defined here start at a + * higher number so that they do not overlap with these. + */ +enum gui_color_pair { + COLOR_STATUSBAR = NUM_STAT_ITEMS + 1, + COLOR_COMMAND, + COLOR_OUTPUT, + COLOR_MSG, + COLOR_ERRMSG, + COLOR_SEPARATOR, + COLOR_TOP, + COLOR_BOT, +}; struct gui_command { const char *key; @@ -80,130 +84,66 @@ struct gui_command { void (*handler)(void); }; -struct stat_item { - char name[MAXLINE]; - char prefix[MAXLINE]; - char postfix[MAXLINE]; - unsigned y; - unsigned x; - unsigned len; - int fg, bg; - int align; - char content[MAXLINE]; +static struct gui_theme theme; + +#define GUI_COMMANDS \ + GUI_COMMAND(help, "?", "print help") \ + GUI_COMMAND(enlarge_top_win, "+", "enlarge the top window") \ + GUI_COMMAND(shrink_top_win, "-", "shrink the top window") \ + GUI_COMMAND(reread_conf, "r", "reread configuration file") \ + GUI_COMMAND(quit, "q", "exit para_gui") \ + GUI_COMMAND(refresh, "^L", "redraw the screen") \ + GUI_COMMAND(next_theme, ".", "switch to next theme") \ + GUI_COMMAND(prev_theme, ",", "switch to previous theme") \ + GUI_COMMAND(ll_incr, ">", "increase loglevel (decreases verbosity)") \ + GUI_COMMAND(ll_decr, "<", "decrease loglevel (increases verbosity)") \ + GUI_COMMAND(version, "V", "show the para_gui version") \ + GUI_COMMAND(scroll_up, "", "scroll up one line") \ + GUI_COMMAND(scroll_down, "", "scroll_down") \ + GUI_COMMAND(page_up, "", "scroll up one page") \ + GUI_COMMAND(page_down, "", "scroll down one page") \ + GUI_COMMAND(scroll_top, "", "scroll to top of buffer") \ + GUI_COMMAND(cancel_scroll, "", "deactivate scroll mode") \ + +/* declare command handlers */ +#define GUI_COMMAND(_c, _k, _d) \ + static void com_ ## _c(void); +GUI_COMMANDS + +#undef GUI_COMMAND + +/* define command array */ +#define GUI_COMMAND(_c, _k, _d) \ + { \ + .key = _k, \ + .name = #_c, \ + .description = _d, \ + .handler = com_ ## _c \ + }, + +static struct gui_command command_list[] = {GUI_COMMANDS {.name = NULL}}; + +struct input_task { + struct task *task; }; -static struct gui_theme theme; +struct status_task { + struct task *task; + pid_t pid; + char *buf; + int bufsize, loaded; + struct timeval next_exec; + int fd; +}; -static int _argc; -static char **_argv; - -static void com_help(void); -static void com_reread_conf(void); -static void com_enlarge_top_win(void); -static void com_shrink_top_win(void); -static void com_version(void); -__noreturn static void com_quit(void); -static void com_refresh(void); -static void com_ll_incr(void); -static void com_ll_decr(void); -static void com_prev_theme(void); -static void com_next_theme(void); -static void com_scroll_up(void); -static void com_scroll_down(void); -static void com_page_up(void); -static void com_page_down(void); -static void com_cancel_scrolling(void); -static void com_scroll_top(void); - -static struct gui_command command_list[] = { - { - .key = "?", - .name = "help", - .description = "print help", - .handler = com_help - }, { - .key = "+", - .name = "enlarge_win", - .description = "enlarge the top window", - .handler = com_enlarge_top_win - }, { - .key = "-", - .name = "shrink_win", - .description = "shrink the top window", - .handler = com_shrink_top_win - }, { - .key = "r", - .name = "reread_conf", - .description = "reread configuration file", - .handler = com_reread_conf - }, { - .key = "q", - .name = "quit", - .description = "exit para_gui", - .handler = com_quit - }, { - .key = "^L", - .name = "refresh", - .description = "redraw the screen", - .handler = com_refresh - }, { - .key = ".", - .name = "next_theme", - .description = "switch to next theme", - .handler = com_next_theme - }, { - .key = ",", - .name = "prev_theme", - .description = "switch to previous stream", - .handler = com_prev_theme - }, { - .key = ">", - .name = "ll_incr", - .description = "increase loglevel (decreases verbosity)", - .handler = com_ll_incr - }, { - .key = "<", - .name = "ll_decr", - .description = "decrease loglevel (increases verbosity)", - .handler = com_ll_decr - }, { - .key = "V", - .name = "version", - .description = "show the para_gui version", - .handler = com_version - }, { - .key = "", - .name = "scroll_up", - .description = "scroll up one line", - .handler = com_scroll_up - }, { - .key = "", - .name = "scroll_down", - .description = "scroll down one line", - .handler = com_scroll_down - }, { - .key = "", - .name = "page_up", - .description = "scroll up one page", - .handler = com_page_up - }, { - .key = "", - .name = "page_down", - .description = "scroll down one page", - .handler = com_page_down - }, { - .key = "", - .name = "scroll_top", - .description = "scroll to top of buffer", - .handler = com_scroll_top - }, { - .key = "", - .name = "cancel_scroll", - .description = "deactivate scroll mode", - .handler = com_cancel_scrolling - }, { - .handler = NULL - } +/** Stdout/stderr of the executing process is read in chunks of this size. */ +#define COMMAND_BUF_SIZE 32768 + +struct exec_task { + struct task *task; + char command_buf[2][COMMAND_BUF_SIZE]; /* stdout/stderr of command */ + int cbo[2]; /* command buf offsets */ + unsigned flags[2]; /* passed to for_each_line() */ }; static int find_cmd_byname(char *name) @@ -216,6 +156,37 @@ static int find_cmd_byname(char *name) return -1; } +/* + * Even though ncurses provides getmaxx and getmaxy, these functions/macros are + * not described in the XSI Curses standard. + */ +static int get_num_lines(struct gui_window *w) +{ + int lines; + __a_unused int cols; /* avoid "set but not used" warnings */ + + getmaxyx(w->win, lines, cols); + return lines; +} + +static int get_num_cols(struct gui_window *w) +{ + __a_unused int lines; /* avoid "set but not used" warnings */ + int cols; + + getmaxyx(w->win, lines, cols); + return cols; +} + +/** Number of lines of the window are occupied by an output line. */ +#define NUM_LINES(len) (1 + (len) / get_num_cols(&bot)) + +/* isendwin() returns false before initscr() was called */ +static bool curses_active(void) +{ + return top.win && !isendwin(); +} + /* taken from mutt */ static char *km_keyname(int c) { @@ -272,24 +243,6 @@ static char *km_keyname(int c) return buf; } -static char *configfile_exists(void) -{ - static char *config_file; - char *tmp; - - if (!conf.config_file_given) { - if (!config_file) { - char *home = para_homedir(); - config_file = make_message("%s/.paraslash/gui.conf", - home); - free(home); - } - tmp = config_file; - } else - tmp = conf.config_file_arg; - return file_exists(tmp)? tmp: NULL; -} - /* Print given number of spaces to curses window. */ static void add_spaces(WINDOW* win, unsigned int num) { @@ -349,59 +302,64 @@ static int align_str(WINDOW* win, char *str, unsigned int len, return 1; } +static void refresh_window(struct gui_window *gw) +{ + gw->needs_update = true; +} + +static bool window_update_needed(void) +{ + return top.needs_update || bot.needs_update || sb.needs_update || + in.needs_update || sep.needs_update; +} + __printf_2_3 static void print_in_bar(int color, const char *fmt,...) { char *msg; va_list ap; - if (!curses_active) + if (!curses_active()) return; wattron(in.win, COLOR_PAIR(color)); va_start(ap, fmt); xvasprintf(&msg, fmt, ap); va_end(ap); wmove(in.win, 0, 0); - align_str(in.win, msg, sb.cols, LEFT); + align_str(in.win, msg, get_num_cols(&in), LEFT); free(msg); - wrefresh(in.win); + refresh_window(&in); } -/* - * update the status bar - */ static void print_status_bar(void) { char *tmp; - if (!curses_active) - return; - tmp = para_strdup(STANDARD_STATUS_BAR); + tmp = para_strdup("para_gui " PACKAGE_VERSION " (hit ? for help)"); wmove(sb.win, 0, 0); - align_str(sb.win, tmp, sb.cols, CENTER); + align_str(sb.win, tmp, get_num_cols(&sb), CENTER); free(tmp); - wrefresh(sb.win); } /* * get the number of the oldest rbe that is (partially) visible. On return, - * lines contains the sum of the number of lines of all visable entries. If the + * lines contains the sum of the number of lines of all visible entries. If the * first one is only partially visible, lines is greater than bot.lines. */ static int first_visible_rbe(unsigned *lines) { - int i; + int i, bot_lines = get_num_lines(&bot); + *lines = 0; for (i = scroll_position; i < RINGBUFFER_SIZE; i++) { struct rb_entry *rbe = ringbuffer_get(bot_win_rb, i); int rbe_lines; if (!rbe) return i - 1; -// fprintf(stderr, "found: %s\n", rbe->msg); rbe_lines = NUM_LINES(rbe->len); - if (rbe_lines > bot.lines) + if (rbe_lines > bot_lines) return -1; *lines += rbe_lines; - if (*lines >= bot.lines) + if (*lines >= bot_lines) return i; } return RINGBUFFER_SIZE - 1; @@ -412,7 +370,7 @@ returns number of first visible rbe, *lines is the number of lines drawn. */ static int draw_top_rbe(unsigned *lines) { - int ret, fvr = first_visible_rbe(lines); + int bot_cols, bot_lines, ret, fvr = first_visible_rbe(lines); struct rb_entry *rbe; size_t bytes_to_skip, cells_to_skip, width; @@ -422,9 +380,10 @@ static int draw_top_rbe(unsigned *lines) rbe = ringbuffer_get(bot_win_rb, fvr); if (!rbe) return -1; - if (*lines > bot.lines) { + getmaxyx(bot.win, bot_lines, bot_cols); + if (*lines > bot_lines) { /* rbe is partially visible multi-line */ - cells_to_skip = (*lines - bot.lines) * bot.cols; + cells_to_skip = (*lines - bot_lines) * bot_cols; ret = skip_cells(rbe->msg, cells_to_skip, &bytes_to_skip); if (ret < 0) return ret; @@ -444,14 +403,14 @@ static int draw_top_rbe(unsigned *lines) static void redraw_bot_win(void) { unsigned lines; - int i; + int i, bot_lines = get_num_lines(&bot); wmove(bot.win, 0, 0); wclear(bot.win); i = draw_top_rbe(&lines); if (i <= 0) goto out; - while (i > 0 && lines < bot.lines) { + while (i > 0 && lines < bot_lines) { struct rb_entry *rbe = ringbuffer_get(bot_win_rb, --i); if (!rbe) { lines++; @@ -464,7 +423,7 @@ static void redraw_bot_win(void) waddstr(bot.win, rbe->msg); } out: - wrefresh(bot.win); + refresh_window(&bot); } static void rb_add_entry(int color, char *msg) @@ -480,7 +439,6 @@ static void rb_add_entry(int color, char *msg) new->len = len; new->msg = msg; old = ringbuffer_add(bot_win_rb, new); -// fprintf(stderr, "added: %s\n", new->msg); if (old) { free(old->msg); free(old); @@ -506,196 +464,66 @@ __printf_2_3 static void outputf(int color, const char* fmt,...) char *msg; va_list ap; - if (!curses_active) + if (!curses_active()) return; va_start(ap, fmt); xvasprintf(&msg, fmt, ap); va_end(ap); rb_add_entry(color, msg); - wrefresh(bot.win); + refresh_window(&bot); } static int add_output_line(char *line, void *data) { int color = *(int *)data? COLOR_ERRMSG : COLOR_OUTPUT; - if (!curses_active) + + if (!curses_active()) return 1; rb_add_entry(color, para_strdup(line)); return 1; } -static int loglevel; - static __printf_2_3 void curses_log(int ll, const char *fmt,...) { - int color; - char *msg; va_list ap; - if (ll < loglevel || !curses_active) + if (ll < loglevel) return; - switch (ll) { - case LL_DEBUG: - case LL_INFO: - case LL_NOTICE: - color = COLOR_MSG; - break; - default: - color = COLOR_ERRMSG; - } va_start(ap, fmt); - xvasprintf(&msg, fmt, ap); + if (curses_active()) { + int color = ll <= LL_NOTICE? COLOR_MSG : COLOR_ERRMSG; + char *msg; + unsigned bytes = xvasprintf(&msg, fmt, ap); + if (bytes > 0 && msg[bytes - 1] == '\n') + msg[bytes - 1] = '\0'; /* cut trailing newline */ + rb_add_entry(color, msg); + refresh_window(&bot); + } else if (exec_pid <= 0) /* no external command running */ + vfprintf(stderr, fmt, ap); va_end(ap); - chop(msg); - rb_add_entry(color, msg); - wrefresh(bot.win); } +/** The log function of para_gui, always set to curses_log(). */ __printf_2_3 void (*para_log)(int, const char*, ...) = curses_log; -static void setup_signal_handling(void) -{ - signal_pipe = para_signal_init(); - para_install_sighandler(SIGINT); - para_install_sighandler(SIGTERM); - para_install_sighandler(SIGCHLD); - para_install_sighandler(SIGWINCH); - para_install_sighandler(SIGUSR1); -} - -/* kill every process in the process group and exit */ -__noreturn static void kill_pg_and_die(int ret) -{ - para_sigaction(SIGTERM, SIG_IGN); - kill(0, SIGTERM); - exit(ret); -} - static void shutdown_curses(void) { - if (!curses_active) - return; def_prog_mode(); - curses_active = 0; endwin(); } -__noreturn static void finish(int ret) -{ - shutdown_curses(); - kill_pg_and_die(ret); -} - -/* - * exit curses and print given message to stdout/stderr - */ -__noreturn __printf_2_3 static void msg_n_exit(int ret, const char* fmt, ...) +/* disable curses, print a message, kill running processes and exit */ +__noreturn __printf_2_3 static void die(int exit_code, const char* fmt, ...) { va_list argp; - FILE *outfd = ret? stderr: stdout; shutdown_curses(); va_start(argp, fmt); - vfprintf(outfd, fmt, argp); + vfprintf(stderr, fmt, argp); va_end(argp); - kill_pg_and_die(ret); -} - -static void print_welcome(void) -{ - if (loglevel > LL_NOTICE) - return; - outputf(COLOR_WELCOME, "Welcome to %s. Theme: %s", - version_single_line("gui"), theme.name); - wclrtoeol(bot.win); -} - -/* - * init all windows - */ -static void init_wins(int top_lines) -{ - int i; - - top.lines = top_lines; - top.cols = COLS; - top.begy = 0; - top.begx = 0; - - bot.lines = LINES - top.lines - 3; - bot.cols = COLS; - bot.begy = top.lines + 1; - bot.begx = 0; - - sb.lines = 1; - sb.cols = COLS; - sb.begy = LINES - 2; - sb.begx = 0; - - in.lines = 1; - in.cols = COLS; - in.begy = LINES - 1; - in.begx = 0; - - sep.lines = 1; - sep.cols = COLS; - sep.begy = top.lines; - sep.begx = 0; - - assume_default_colors(theme.default_fg, theme.default_bg); - if (top.win) { - mvwin(top.win, top.begy, top.begx); - wresize(top.win, top.lines, top.cols); - - mvwin(sb.win, sb.begy, sb.begx); - wresize(sb.win, sb.lines, sb.cols); - - mvwin(sep.win, sep.begy, sep.begx); - wresize(sep.win, sep.lines, sep.cols); - - mvwin(bot.win, bot.begy, bot.begx); - wresize(bot.win, bot.lines, bot.cols); - - mvwin(in.win, in.begy, in.begx); - wresize(in.win, in.lines, in.cols); - } else { - sep.win = newwin(sep.lines, sep.cols, sep.begy, sep.begx); - top.win = newwin(top.lines, top.cols, top.begy, top.begx); - bot.win = newwin(bot.lines, bot.cols, bot.begy, bot.begx); - sb.win = newwin(sb.lines, sb.cols, sb.begy, sb.begx); - in.win = newwin(in.lines, in.cols, in.begy, in.begx); - if (!top.win || !bot.win || !sb.win || !in.win || !sep.win) - msg_n_exit(1, "Error: Cannot create curses windows\n"); - wclear(bot.win); - wclear(sb.win); - wclear(in.win); - scrollok(bot.win, 1); - wattron(sb.win, COLOR_PAIR(COLOR_STATUSBAR)); - wattron(sep.win, COLOR_PAIR(COLOR_SEPARATOR)); - wattron(bot.win, COLOR_PAIR(COLOR_BOT)); - wattron(top.win, COLOR_PAIR(COLOR_TOP)); - nodelay(top.win, 1); - nodelay(bot.win, 1); - nodelay(sb.win, 1); - nodelay(in.win, 0); - - keypad(top.win, 1); - keypad(bot.win, 1); - keypad(sb.win, 1); - keypad(in.win, 1); - print_status_bar(); - } - wmove(sep.win, 0, 0); - for (i = 1; i <= COLS; i++) - waddstr(sep.win, theme.sep_str); - wclear(top.win); - //wclear(bot.win); - wnoutrefresh(top.win); - wnoutrefresh(bot.win); - //wnoutrefresh(sb.win); - print_status_bar(); - wnoutrefresh(in.win); - wnoutrefresh(sep.win); - doupdate(); + /* kill every process in the process group and exit */ + para_sigaction(SIGTERM, SIG_IGN); + kill(0, SIGTERM); + exit(exit_code); } /* @@ -706,16 +534,16 @@ static void print_stat_item(int i) char *tmp; struct stat_item_data d = theme.data[i]; char *c = stat_content[i]; + int top_lines = get_num_lines(&top); - if (!curses_active || !d.len || !c) + if (!curses_active() || !d.len || !c) return; tmp = make_message("%s%s%s", d.prefix, c, d.postfix); - wmove(top.win, d.y * top.lines / 100, d.x * COLS / 100); - wrefresh(top.win); + wmove(top.win, d.y * top_lines / 100, d.x * COLS / 100); wattron(top.win, COLOR_PAIR(i + 1)); align_str(top.win, tmp, d.len * COLS / 100, d.align); free(tmp); - wrefresh(top.win); + refresh_window(&top); } static int update_item(int item_num, char *buf) @@ -749,44 +577,11 @@ print: return 1; } -static int read_stat_pipe(fd_set *rfds) -{ - static char *buf; - static int bufsize, loaded; - int ret, ret2; - size_t sz; - - if (stat_pipe < 0) - return 0; - if (loaded >= bufsize) { - if (bufsize > 1000 * 1000) { - loaded = 0; - return 0; - } - bufsize += bufsize + 1000; - buf = para_realloc(buf, bufsize); - } - assert(loaded < bufsize); - ret = read_nonblock(stat_pipe, buf + loaded, bufsize - loaded, - rfds, &sz); - loaded += sz; - ret2 = for_each_stat_item(buf, loaded, update_item); - if (ret < 0 || ret2 < 0) { - loaded = 0; - return ret2 < 0? ret2 : ret; - } - sz = ret2; /* what is left */ - if (sz > 0 && sz < loaded) - memmove(buf, buf + loaded - sz, sz); - loaded = sz; - return 1; -} - static void print_all_items(void) { int i; - if (!curses_active) + if (!curses_active()) return; FOR_EACH_STATUS_ITEM(i) print_stat_item(i); @@ -802,10 +597,155 @@ static void clear_all_items(void) } } +static void status_pre_select(struct sched *s, void *context) +{ + struct status_task *st = context; + + if (st->fd >= 0) + para_fd_set(st->fd, &s->rfds, &s->max_fileno); + if (task_get_notification(st->task) < 0) + return sched_min_delay(s); + if (st->fd < 0) + sched_request_barrier_or_min_delay(&st->next_exec, s); +} + +static int status_post_select(struct sched *s, void *context) +{ + struct status_task *st = context; + size_t sz; + int ret, ret2; + + ret = task_get_notification(st->task); + if (ret == -E_GUI_SIGCHLD && st->pid > 0) { + int exit_status; + if (waitpid(st->pid, &exit_status, WNOHANG) == st->pid) { + st->pid = 0; + PARA_ERROR_LOG("stat command exit status: %d", + exit_status); + } + } + if (st->fd < 0) { + int fds[3] = {0, 1, 0}; + if (st->pid > 0) + return 0; + /* Avoid busy loop */ + if (tv_diff(&st->next_exec, now, NULL) > 0) + return 0; + st->next_exec.tv_sec = now->tv_sec + 2; + ret = para_exec_cmdline_pid(&st->pid, conf.stat_cmd_arg, fds); + if (ret < 0) + return 0; + ret = mark_fd_nonblocking(fds[1]); + if (ret < 0) { + close(fds[1]); + return 0; + } + st->fd = fds[1]; + return 0; + } + + if (st->loaded >= st->bufsize) { + if (st->bufsize > 1000 * 1000) { + st->loaded = 0; + return 0; + } + st->bufsize += st->bufsize + 1000; + st->buf = para_realloc(st->buf, st->bufsize); + } + assert(st->loaded < st->bufsize); + ret = read_nonblock(st->fd, st->buf + st->loaded, + st->bufsize - st->loaded, &s->rfds, &sz); + st->loaded += sz; + ret2 = for_each_stat_item(st->buf, st->loaded, update_item); + if (ret < 0 || ret2 < 0) { + st->loaded = 0; + PARA_NOTICE_LOG("closing stat pipe: %s\n", para_strerror(-ret)); + close(st->fd); + st->fd = -1; + clear_all_items(); + free(stat_content[SI_BASENAME]); + stat_content[SI_BASENAME] = + para_strdup("stat command terminated!?"); + print_all_items(); + return 0; + } + sz = ret2; /* what is left */ + if (sz > 0 && sz < st->loaded) + memmove(st->buf, st->buf + st->loaded - sz, sz); + st->loaded = sz; + return 0; +} + +/* + * init all windows + */ +static void init_wins(int top_lines) +{ + int top_y = 0, bot_y = top_lines + 1, sb_y = LINES - 2, + in_y = LINES - 1, sep_y = top_lines; + int bot_lines = LINES - top_lines - 3, sb_lines = 1, in_lines = 1, + sep_lines = 1; + + assume_default_colors(theme.dflt.fg, theme.dflt.bg); + if (top.win) { + wresize(top.win, top_lines, COLS); + mvwin(top.win, top_y, 0); + + wresize(sb.win, sb_lines, COLS); + mvwin(sb.win, sb_y, 0); + + wresize(sep.win, sep_lines, COLS); + mvwin(sep.win, sep_y, 0); + + wresize(bot.win, bot_lines, COLS); + mvwin(bot.win, bot_y, 0); + + wresize(in.win, in_lines, COLS); + mvwin(in.win, in_y, 0); + } else { + sep.win = newwin(sep_lines, COLS, sep_y, 0); + top.win = newwin(top_lines, COLS, top_y, 0); + bot.win = newwin(bot_lines, COLS, bot_y, 0); + sb.win = newwin(sb_lines, COLS, sb_y, 0); + in.win = newwin(in_lines, COLS, in_y, 0); + if (!top.win || !bot.win || !sb.win || !in.win || !sep.win) + die(EXIT_FAILURE, "Error: Cannot create curses windows\n"); + wclear(bot.win); + wclear(sb.win); + wclear(in.win); + scrollok(bot.win, 1); + wattron(sb.win, COLOR_PAIR(COLOR_STATUSBAR)); + wattron(sep.win, COLOR_PAIR(COLOR_SEPARATOR)); + wattron(bot.win, COLOR_PAIR(COLOR_BOT)); + wattron(top.win, COLOR_PAIR(COLOR_TOP)); + nodelay(top.win, 1); + nodelay(bot.win, 1); + nodelay(sb.win, 1); + nodelay(in.win, 0); + + keypad(top.win, 1); + keypad(bot.win, 1); + keypad(sb.win, 1); + keypad(in.win, 1); + } + wmove(sep.win, 0, 0); + whline(sep.win, theme.sep_char, COLS); + wclear(top.win); + print_all_items(); + //wclear(bot.win); + wnoutrefresh(top.win); + wnoutrefresh(bot.win); + print_status_bar(); + wnoutrefresh(sb.win); + wnoutrefresh(in.win); + wnoutrefresh(sep.win); + doupdate(); +} + static void init_pair_or_die(short pair, short f, short b) { if (init_pair(pair, f, b) == ERR) - msg_n_exit(EXIT_FAILURE, "fatal: init_pair() failed\n"); + die(EXIT_FAILURE, "fatal: init_pair() failed\n"); } static void init_colors_or_die(void) @@ -813,62 +753,48 @@ static void init_colors_or_die(void) int i; if (!has_colors()) - msg_n_exit(EXIT_FAILURE, "fatal: No color term\n"); + die(EXIT_FAILURE, "fatal: No color term\n"); if (start_color() == ERR) - msg_n_exit(EXIT_FAILURE, "fatal: failed to start colors\n"); + die(EXIT_FAILURE, "fatal: failed to start colors\n"); FOR_EACH_STATUS_ITEM(i) if (theme.data[i].len) - init_pair_or_die(i + 1, theme.data[i].fg, - theme.data[i].bg); - init_pair_or_die(COLOR_STATUSBAR, theme.sb_fg, theme.sb_bg); - init_pair_or_die(COLOR_COMMAND, theme.cmd_fg, theme.cmd_bg); - init_pair_or_die(COLOR_OUTPUT, theme.output_fg, theme.output_bg); - init_pair_or_die(COLOR_MSG, theme.msg_fg, theme.msg_bg); - init_pair_or_die(COLOR_ERRMSG, theme.err_msg_fg, theme.err_msg_bg); - init_pair_or_die(COLOR_WELCOME, theme.welcome_fg, theme.welcome_bg); - init_pair_or_die(COLOR_SEPARATOR, theme.sep_fg, theme.sep_bg); - init_pair_or_die(COLOR_TOP, theme.default_fg, theme.default_bg); - init_pair_or_die(COLOR_BOT, theme.default_fg, theme.default_bg); + init_pair_or_die(i + 1, theme.data[i].color.fg, + theme.data[i].color.bg); + init_pair_or_die(COLOR_STATUSBAR, theme.sb.fg, theme.sb.bg); + init_pair_or_die(COLOR_COMMAND, theme.cmd.fg, theme.cmd.bg); + init_pair_or_die(COLOR_OUTPUT, theme.output.fg, theme.output.bg); + init_pair_or_die(COLOR_MSG, theme.msg.fg, theme.msg.bg); + init_pair_or_die(COLOR_ERRMSG, theme.err_msg.fg, theme.err_msg.bg); + init_pair_or_die(COLOR_SEPARATOR, theme.sep.fg, theme.sep.bg); + init_pair_or_die(COLOR_TOP, theme.dflt.fg, theme.dflt.bg); + init_pair_or_die(COLOR_BOT, theme.dflt.fg, theme.dflt.bg); } /* (Re-)initialize the curses library. */ static void init_curses(void) { - curses_active = 1; - if (top.win && refresh() == ERR) /* refesh is really needed */ - msg_n_exit(EXIT_FAILURE, "refresh() failed\n"); + if (curses_active()) + return; + if (top.win && refresh() == ERR) /* refresh is really needed */ + die(EXIT_FAILURE, "refresh() failed\n"); if (LINES < theme.lines_min || COLS < theme.cols_min) - msg_n_exit(EXIT_FAILURE, "Error: Terminal (%dx%d) too small" + die(EXIT_FAILURE, "Terminal (%dx%d) too small" " (need at least %dx%d)\n", COLS, LINES, theme.cols_min, theme.lines_min); curs_set(0); /* make cursor invisible, ignore errors */ nonl(); /* do not NL->CR/NL on output, always returns OK */ /* don't echo input */ if (noecho() == ERR) - msg_n_exit(EXIT_FAILURE, "fatal: noecho() failed\n"); + die(EXIT_FAILURE, "fatal: noecho() failed\n"); /* take input chars one at a time, no wait for \n */ if (cbreak() == ERR) - msg_n_exit(EXIT_FAILURE, "fatal: cbreak() failed\n"); + die(EXIT_FAILURE, "fatal: cbreak() failed\n"); init_colors_or_die(); clear(); /* ignore non-fatal errors */ init_wins(theme.top_lines_default); - print_all_items(); // noecho(); /* don't echo input */ } -static void check_sigchld(void) -{ - int ret; - pid_t pid; -reap_next_child: - ret = para_reap_child(&pid); - if (ret <= 0) - return; - if (pid == cmd_pid) - cmd_pid = 0; - goto reap_next_child; -} - /* * This sucker modifies its first argument. *handler and *arg are * pointers to 0-terminated strings (inside line). Crap. @@ -888,313 +814,347 @@ err_out: return 0; } -static int check_key_map_args(void) +static void check_key_map_args_or_die(void) { - char *s; - int i, ret = -1; - char *tmp = NULL, *handler, *arg; + int i; + char *tmp = NULL; for (i = 0; i < conf.key_map_given; ++i) { - s = conf.key_map_arg[i]; - if (!(*s)) - goto err_out; + char *handler, *arg; + free(tmp); - tmp = para_strdup(s); + tmp = para_strdup(conf.key_map_arg[i]); if (!split_key_map(tmp, &handler, &arg)) - goto err_out; + break; if (strlen(handler) != 1) - goto err_out; - if (*handler != 'x' - && *handler != 'd' - && *handler != 'i' - && *handler != 'p') - goto err_out; + break; + if (*handler != 'x' && *handler != 'd' && *handler != 'i' + && *handler != 'p') + break; if (*handler != 'i') continue; if (find_cmd_byname(arg) < 0) - goto err_out; + break; } - ret = 0; -err_out: + if (i != conf.key_map_given) + die(EXIT_FAILURE, "invalid key map: %s\n", conf.key_map_arg[i]); free(tmp); - return ret; +} + +static void parse_config_file_or_die(bool override) +{ + bool err; + char *config_file; + struct gui_cmdline_parser_params params = { + .override = override, + .initialize = 0, + .check_required = !override, + .check_ambiguity = 0, + .print_errors = 1, + }; + + if (conf.config_file_given) + config_file = para_strdup(conf.config_file_arg); + else { + char *home = para_homedir(); + config_file = make_message("%s/.paraslash/gui.conf", home); + free(home); + } + if (!file_exists(config_file)) { + if (!conf.config_file_given) + err = false; + else { + PARA_EMERG_LOG("config file %s does not exist\n", + config_file); + err = true; + } + goto out; + } + gui_cmdline_parser_config_file(config_file, &conf, ¶ms); + loglevel = get_loglevel_by_name(conf.loglevel_arg); + check_key_map_args_or_die(); + err = false; +out: + free(config_file); + if (err) + exit(EXIT_FAILURE); + theme_init(conf.theme_arg, &theme); +} + +/* reread configuration, terminate on errors */ +static void reread_conf(void) +{ + /* + * gengetopt might print to stderr and exit on errors. So we have to + * shutdown curses first. + */ + shutdown_curses(); + parse_config_file_or_die(true /* override */); + init_curses(); + print_in_bar(COLOR_MSG, "config file reloaded\n"); } /* * React to various signal-related events */ -static void handle_signal(int sig) +static int signal_post_select(struct sched *s, __a_unused void *context) { - switch (sig) { + int ret = para_next_signal(&s->rfds); + + if (ret <= 0) + return 0; + switch (ret) { case SIGTERM: - msg_n_exit(EXIT_FAILURE, - "only the good die young (caught SIGTERM))\n"); - return; - case SIGWINCH: - if (curses_active) { - shutdown_curses(); - init_curses(); - redraw_bot_win(); - } - return; + die(EXIT_FAILURE, "only the good die young (caught SIGTERM)\n"); + return 1; case SIGINT: - PARA_WARNING_LOG("caught SIGINT, reset"); + PARA_WARNING_LOG("caught SIGINT, reset\n"); /* Nothing to do. SIGINT killed our child which gets noticed * by do_select and resets everything. */ - return; + return 1; case SIGUSR1: - PARA_NOTICE_LOG("got SIGUSR1, rereading configuration"); - com_reread_conf(); - return; + PARA_NOTICE_LOG("got SIGUSR1, rereading configuration\n"); + reread_conf(); + return 1; case SIGCHLD: - check_sigchld(); - return; + task_notify_all(s, E_GUI_SIGCHLD); + return 1; } + return 1; } -static void status_pre_select(fd_set *rfds, int *max_fileno, struct timeval *tv) +static enum exec_status exec_status(void) { - static struct timeval next_exec, atm, diff; - int ret, fds[3] = {0, 1, 0}; - pid_t pid; - - if (stat_pipe >= 0) - goto success; - /* Avoid busy loop */ - gettimeofday(&atm, NULL); - if (tv_diff(&next_exec, &atm, &diff) > 0) { - if (tv_diff(&diff, tv, NULL) < 0) - *tv = diff; - return; - } - next_exec.tv_sec = atm.tv_sec + 2; - ret = para_exec_cmdline_pid(&pid, conf.stat_cmd_arg, fds); - if (ret < 0) - return; - ret = mark_fd_nonblocking(fds[1]); - if (ret < 0) { - close(fds[1]); - return; - } - stat_pipe = fds[1]; -success: - para_fd_set(stat_pipe, rfds, max_fileno); + if (exec_fds[0] >= 0 || exec_fds[1] >= 0) + return EXEC_DCMD; + if (exec_pid > 0) + return EXEC_XCMD; + return EXEC_IDLE; } -#define COMMAND_BUF_SIZE 32768 +static void exec_pre_select(struct sched *s, void *context) +{ + struct exec_task *et = context; + if (exec_fds[0] >= 0) + para_fd_set(exec_fds[0], &s->rfds, &s->max_fileno); + if (exec_fds[1] >= 0) + para_fd_set(exec_fds[1], &s->rfds, &s->max_fileno); + if (task_get_notification(et->task) < 0) + sched_min_delay(s); +} -/* - * This is the core select loop. Besides the (internal) signal - * pipe, the following other fds are checked according to the mode: - * - * GETCH_MODE: check stdin, return when key is pressed - * - * COMMAND_MODE: check command fds and stdin. Return when peer has closed both - * stdout and stderr or when any key is pressed. - * - * EXTERNAL_MODE: Check only signal pipe. Used when an external command - * is running. During that time curses is disabled. Returns when - * cmd_pid == 0. - */ -static int do_select(int mode) -{ - fd_set rfds; - int ret, i, max_fileno; - char command_buf[2][COMMAND_BUF_SIZE] = {"", ""}; - int cbo[2] = {0, 0}; /* command buf offsets */ - struct timeval tv; - unsigned flags[2] = {0, 0}; /* for for_each_line() */ - -repeat: - tv.tv_sec = conf.timeout_arg / 1000; - tv.tv_usec = (conf.timeout_arg % 1000) * 1000; -// ret = refresh_status(); - FD_ZERO(&rfds); - max_fileno = 0; - status_pre_select(&rfds, &max_fileno, &tv); - /* signal pipe */ - para_fd_set(signal_pipe, &rfds, &max_fileno); - /* command pipe only for COMMAND_MODE */ - if (mode == COMMAND_MODE) { - if (command_fds[0] >= 0) - para_fd_set(command_fds[0], &rfds, &max_fileno); - if (command_fds[1] >= 0) - para_fd_set(command_fds[1], &rfds, &max_fileno); +static int exec_post_select(struct sched *s, void *context) +{ + struct exec_task *ct = context; + int i, ret; + + ret = task_get_notification(ct->task); + if (ret == -E_GUI_SIGCHLD && exec_pid > 0) { + int exit_status; + if (waitpid(exec_pid, &exit_status, WNOHANG) == exec_pid) { + exec_pid = 0; + init_curses(); + PARA_INFO_LOG("command exit status: %d", exit_status); + print_in_bar(COLOR_MSG, " "); + } } - if (mode == GETCH_MODE || mode == COMMAND_MODE) - para_fd_set(STDIN_FILENO, &rfds, &max_fileno); - ret = para_select(max_fileno + 1, &rfds, NULL, &tv); - if (ret <= 0) - goto check_return; /* skip fd checks */ - /* signals */ - ret = para_next_signal(&rfds); - if (ret > 0) - handle_signal(ret); - /* read command pipe if ready */ - if (mode == COMMAND_MODE) { - for (i = 0; i < 2; i++) { - size_t sz; - if (command_fds[i] < 0) - continue; - ret = read_nonblock(command_fds[i], - command_buf[i] + cbo[i], - COMMAND_BUF_SIZE - 1 - cbo[i], &rfds, &sz); - cbo[i] += sz; - sz = cbo[i]; - cbo[i] = for_each_line(flags[i], command_buf[i], cbo[i], - add_output_line, &i); - if (sz != cbo[i]) { /* at least one line found */ - wrefresh(bot.win); - flags[i] = 0; - } - if (ret < 0) { + for (i = 0; i < 2; i++) { + size_t sz; + if (exec_fds[i] < 0) + continue; + ret = read_nonblock(exec_fds[i], + ct->command_buf[i] + ct->cbo[i], + COMMAND_BUF_SIZE - 1 - ct->cbo[i], &s->rfds, &sz); + ct->cbo[i] += sz; + sz = ct->cbo[i]; + ct->cbo[i] = for_each_line(ct->flags[i], ct->command_buf[i], + ct->cbo[i], add_output_line, &i); + if (sz != ct->cbo[i]) { /* at least one line found */ + refresh_window(&bot); + ct->flags[i] = 0; + } + if (ret < 0 || exec_pid == 0) { + if (ret < 0) PARA_NOTICE_LOG("closing command fd %d: %s", i, para_strerror(-ret)); - close(command_fds[i]); - command_fds[i] = -1; - flags[i] = 0; - if (command_fds[!i] < 0) /* both fds closed */ - return 0; - } - if (cbo[i] == COMMAND_BUF_SIZE - 1) { - PARA_NOTICE_LOG("discarding overlong line"); - cbo[i] = 0; - flags[i] = FELF_DISCARD_FIRST; - } + close(exec_fds[i]); + exec_fds[i] = -1; + ct->flags[i] = 0; + ct->cbo[i] = 0; + if (exec_fds[!i] < 0) /* both fds closed */ + return 1; } - } - ret = read_stat_pipe(&rfds); - if (ret < 0) { - PARA_NOTICE_LOG("closing stat pipe: %s\n", para_strerror(-ret)); - close(stat_pipe); - stat_pipe = -1; - clear_all_items(); - free(stat_content[SI_BASENAME]); - stat_content[SI_BASENAME] = - para_strdup("stat command terminated!?"); - print_all_items(); - } -check_return: - switch (mode) { - case COMMAND_MODE: - ret = wgetch(top.win); - if (ret != ERR && ret != KEY_RESIZE) { - if (command_fds[0] >= 0) { - close(command_fds[0]); - command_fds[0] = -1; - } - if (command_fds[1] >= 0) { - close(command_fds[1]); - command_fds[1] = -1; - } - if (cmd_pid) - kill(cmd_pid, SIGTERM); - return -1; + if (ct->cbo[i] == COMMAND_BUF_SIZE - 1) { + PARA_NOTICE_LOG("discarding overlong line"); + ct->cbo[i] = 0; + ct->flags[i] = FELF_DISCARD_FIRST; } - break; - case GETCH_MODE: - ret = wgetch(top.win); - if (ret != ERR && ret != KEY_RESIZE) - return ret; - break; - case EXTERNAL_MODE: - if (cmd_pid == 0) - return 0; } - goto repeat; + return 0; } -/* - * read from command pipe and print data to bot window - */ -static void send_output(void) +static void input_pre_select(struct sched *s, __a_unused void *context) { - int ret; + if (exec_status() != EXEC_XCMD) + para_fd_set(STDIN_FILENO, &s->rfds, &s->max_fileno); + if (window_update_needed()) + sched_min_delay(s); +} + +/* read from command pipe and print data to bot window */ +static void exec_and_display(const char *file_and_args) +{ + int ret, fds[3] = {0, 1, 1}; - ret = mark_fd_nonblocking(command_fds[0]); + outputf(COLOR_COMMAND, "%s", file_and_args); + ret = para_exec_cmdline_pid(&exec_pid, file_and_args, fds); + if (ret < 0) + return; + ret = mark_fd_nonblocking(fds[1]); if (ret < 0) goto fail; - ret = mark_fd_nonblocking(command_fds[1]); + ret = mark_fd_nonblocking(fds[2]); if (ret < 0) goto fail; - if (do_select(COMMAND_MODE) >= 0) - PARA_INFO_LOG("command complete"); - else - PARA_NOTICE_LOG("command aborted"); - print_in_bar(COLOR_MSG, " "); + exec_fds[0] = fds[1]; + exec_fds[1] = fds[2]; + print_in_bar(COLOR_MSG, "hit any key to abort\n"); return; fail: PARA_ERROR_LOG("%s\n", para_strerror(-ret)); - close(command_fds[0]); - close(command_fds[1]); + close(exec_fds[0]); + close(exec_fds[1]); } -static void para_cmd(char *cmd) +static void exec_para(const char *args) { - int ret, fds[3] = {0, 1, 1}; - char *c = make_message(BINDIR "/para_client -- %s", cmd); + char *file_and_args; - outputf(COLOR_COMMAND, "%s", c); - print_in_bar(COLOR_MSG, "executing client command, hit any key to abort\n"); - ret = para_exec_cmdline_pid(&cmd_pid, c, fds); - free(c); - if (ret < 0) - return; - command_fds[0] = fds[1]; - command_fds[1] = fds[2]; - send_output(); + file_and_args = make_message(BINDIR "/para_client -- %s", args); + exec_and_display(file_and_args); + free(file_and_args); } /* - * exec command and print output to bot win + * shutdown curses and stat pipe before executing external commands */ -static void display_cmd(char *cmd) +static void exec_external(char *file_and_args) { - int fds[3] = {0, 1, 1}; + int fds[3] = {-1, -1, -1}; - print_in_bar(COLOR_MSG, "executing display command, hit any key to abort"); - outputf(COLOR_COMMAND, "%s", cmd); - if (para_exec_cmdline_pid(&cmd_pid, cmd, fds) < 0) + if (exec_pid) return; - command_fds[0] = fds[1]; - command_fds[1] = fds[2]; - send_output(); + shutdown_curses(); + para_exec_cmdline_pid(&exec_pid, file_and_args, fds); } -/* - * shutdown curses and stat pipe before executing external commands - */ -static void external_cmd(char *cmd) +static void handle_command(int c) { - int fds[3] = {-1, -1, -1}; + int i; - if (cmd_pid) - return; - shutdown_curses(); - if (para_exec_cmdline_pid(&cmd_pid, cmd, fds) < 0) + /* first check user-defined key bindings */ + for (i = 0; i < conf.key_map_given; ++i) { + char *tmp, *handler, *arg; + + tmp = para_strdup(conf.key_map_arg[i]); + if (!split_key_map(tmp, &handler, &arg)) { + free(tmp); + return; + } + if (strcmp(tmp, km_keyname(c))) { + free(tmp); + continue; + } + if (*handler == 'd') + exec_and_display(arg); + else if (*handler == 'x') + exec_external(arg); + else if (*handler == 'p') + exec_para(arg); + else if (*handler == 'i') { + int num = find_cmd_byname(arg); + if (num >= 0) + command_list[num].handler(); + } + free(tmp); return; - do_select(EXTERNAL_MODE); - init_curses(); + } + /* not found, check internal key bindings */ + for (i = 0; command_list[i].handler; i++) { + if (!strcmp(km_keyname(c), command_list[i].key)) { + command_list[i].handler(); + return; + } + } + print_in_bar(COLOR_ERRMSG, "key '%s' is not bound, press ? for help", + km_keyname(c)); +} + +static int input_post_select(__a_unused struct sched *s, __a_unused void *context) +{ + int ret; + enum exec_status exs = exec_status(); + + if (exs == EXEC_XCMD) + return 0; + if (window_update_needed()) { + if (top.needs_update) + assert(wnoutrefresh(top.win) == OK); + if (bot.needs_update) + assert(wnoutrefresh(bot.win) == OK); + if (sep.needs_update) + assert(wnoutrefresh(sep.win) == OK); + if (sb.needs_update) + assert(wnoutrefresh(sb.win) == OK); + if (in.needs_update) + assert(wnoutrefresh(in.win) == OK); + doupdate(); + top.needs_update = bot.needs_update = sb.needs_update = + in.needs_update = sep.needs_update = false; + } + ret = wgetch(top.win); + if (ret == ERR) + return 0; + if (ret == KEY_RESIZE) { + if (curses_active()) { + shutdown_curses(); + init_curses(); + redraw_bot_win(); + } + return 0; + } + if (exs == EXEC_IDLE) + handle_command(ret); + else if (exec_pid > 0) + kill(exec_pid, SIGTERM); + return 0; +} + +static void signal_pre_select(struct sched *s, void *context) +{ + struct signal_task *st = context; + para_fd_set(st->fd, &s->rfds, &s->max_fileno); } static void print_scroll_msg(void) { unsigned lines_total, filled = ringbuffer_filled(bot_win_rb); int first_rbe = first_visible_rbe(&lines_total); + print_in_bar(COLOR_MSG, "scrolled view: %d-%d/%d\n", filled - first_rbe, filled - scroll_position, ringbuffer_filled(bot_win_rb)); } static void com_scroll_top(void) { - int i = RINGBUFFER_SIZE - 1; + int i = RINGBUFFER_SIZE - 1, bot_lines = get_num_lines(&bot); unsigned lines = 0; while (i > 0 && !ringbuffer_get(bot_win_rb, i)) i--; /* i is oldest entry */ - for (; lines < bot.lines && i >= 0; i--) { + for (; lines < bot_lines && i >= 0; i--) { struct rb_entry *rbe = ringbuffer_get(bot_win_rb, i); if (!rbe) break; @@ -1210,7 +1170,7 @@ static void com_scroll_top(void) print_in_bar(COLOR_ERRMSG, "top of buffer is shown\n"); } -static void com_cancel_scrolling(void) +static void com_cancel_scroll(void) { if (scroll_position == 0) { @@ -1224,8 +1184,9 @@ static void com_cancel_scrolling(void) static void com_page_down(void) { unsigned lines = 0; - int i = scroll_position; - while (lines < bot.lines && --i > 0) { + int i = scroll_position, bot_lines = get_num_lines(&bot); + + while (lines < bot_lines && --i > 0) { struct rb_entry *rbe = ringbuffer_get(bot_win_rb, i); if (!rbe) break; @@ -1243,7 +1204,7 @@ static void com_page_down(void) static void com_page_up(void) { unsigned lines; - int fvr = first_visible_rbe(&lines); + int fvr = first_visible_rbe(&lines), bot_lines = get_num_lines(&bot); if (fvr < 0 || fvr + 1 >= ringbuffer_filled(bot_win_rb)) { print_in_bar(COLOR_ERRMSG, "top of buffer is shown\n"); @@ -1252,7 +1213,7 @@ static void com_page_up(void) scroll_position = fvr + 1; for (; scroll_position > 0; scroll_position--) { first_visible_rbe(&lines); - if (lines == bot.lines) + if (lines == bot_lines) break; } redraw_bot_win(); @@ -1262,7 +1223,7 @@ static void com_page_up(void) static void com_scroll_down(void) { struct rb_entry *rbe; - int rbe_lines; + int rbe_lines, bot_lines = get_num_lines(&bot); if (!scroll_position) { print_in_bar(COLOR_ERRMSG, "bottom of buffer is shown\n"); @@ -1272,10 +1233,10 @@ static void com_scroll_down(void) rbe = ringbuffer_get(bot_win_rb, scroll_position); rbe_lines = NUM_LINES(rbe->len); wscrl(bot.win, rbe_lines); - wmove(bot.win, bot.lines - rbe_lines, 0); + wmove(bot.win, bot_lines - rbe_lines, 0); wattron(bot.win, COLOR_PAIR(rbe->color)); waddstr(bot.win, rbe->msg); - wrefresh(bot.win); + refresh_window(&bot); print_scroll_msg(); } @@ -1305,7 +1266,6 @@ static void com_scroll_up(void) break; rbe_lines = NUM_LINES(rbe->len); lines += rbe_lines; -// fprintf(stderr, "msg: %s\n", rbe->msg); wattron(bot.win, COLOR_PAIR(rbe->color)); waddstr(bot.win, "\n"); waddstr(bot.win, rbe->msg); @@ -1313,7 +1273,7 @@ static void com_scroll_up(void) break; i--; } - wrefresh(bot.win); + refresh_window(&bot); print_scroll_msg(); return; err_out: @@ -1342,30 +1302,9 @@ static void com_ll_incr(void) print_in_bar(COLOR_MSG, "loglevel set to %d\n", loglevel); } -/* - * reread configuration, terminate on errors - */ static void com_reread_conf(void) { - char *cf =configfile_exists(); - struct gui_cmdline_parser_params params = { - .override = 1, - .initialize = 1, - .check_required = 0, - .check_ambiguity = 0, - .print_errors = 0, - }; - - if (!cf) { - PARA_WARNING_LOG("there is no configuration to read"); - return; - } - PARA_INFO_LOG("rereading command line options and config file"); - gui_cmdline_parser_ext(_argc, _argv, &conf, ¶ms); - gui_cmdline_parser_config_file(cf, &conf, ¶ms); - PARA_NOTICE_LOG("config file reloaded"); - if (check_key_map_args() < 0) - finish(EXIT_FAILURE); + reread_conf(); } static void com_help(void) @@ -1407,25 +1346,25 @@ static void com_help(void) static void com_shrink_top_win(void) { - if (top.lines <= theme.top_lines_min) { - PARA_WARNING_LOG("can not decrease top window"); + int top_lines = get_num_lines(&top); + + if (top_lines <= theme.top_lines_min) { + PARA_WARNING_LOG("can not decrease top window\n"); return; } - init_wins(top.lines - 1); - wclear(top.win); - print_all_items(); + init_wins(top_lines - 1); print_in_bar(COLOR_MSG, "%s", "decreased top window"); } static void com_enlarge_top_win(void) { - if (bot.lines < 3) { - PARA_WARNING_LOG("can not increase top window"); + int top_lines = get_num_lines(&top), bot_lines = get_num_lines(&bot); + + if (bot_lines < 3) { + PARA_WARNING_LOG("can not increase top window\n"); return; } - init_wins(top.lines + 1); - wclear(top.win); - print_all_items(); + init_wins(top_lines + 1); print_in_bar(COLOR_MSG, "increased top window"); } @@ -1436,7 +1375,7 @@ static void com_version(void) __noreturn static void com_quit(void) { - finish(0); + die(EXIT_SUCCESS, "%s", ""); } static void com_refresh(void) @@ -1445,69 +1384,16 @@ static void com_refresh(void) init_curses(); } -static void change_theme(int next) -{ - if (next) - next_theme(&theme); - else - prev_theme(&theme); - /* This seems to be needed twice, why? */ - com_refresh(); - com_refresh(); - PARA_NOTICE_LOG("new theme: %s", theme.name); -} - static void com_next_theme(void) { - change_theme(1); + theme_next(&theme); + com_refresh(); } static void com_prev_theme(void) { - change_theme(0); -} - - -static void handle_command(int c) -{ - int i; - - /* first check user's key bindings */ - for (i = 0; i < conf.key_map_given; ++i) { - char *tmp, *handler, *arg; - - tmp = para_strdup(conf.key_map_arg[i]); - if (!split_key_map(tmp, &handler, &arg)) { - free(tmp); - return; - } - if (strcmp(tmp, km_keyname(c))) { - free(tmp); - continue; - } - if (*handler == 'd') - display_cmd(arg); - else if (*handler == 'x') - external_cmd(arg); - else if (*handler == 'p') - para_cmd(arg); - else if (*handler == 'i') { - int num = find_cmd_byname(arg); - if (num >= 0) - command_list[num].handler(); - } - free(tmp); - return; - } - /* not found, check internal key bindings */ - for (i = 0; command_list[i].handler; i++) { - if (!strcmp(km_keyname(c), command_list[i].key)) { - command_list[i].handler(); - return; - } - } - print_in_bar(COLOR_ERRMSG, "key '%s' is not bound, press ? for help", - km_keyname(c)); + theme_prev(&theme); + com_refresh(); } __noreturn static void print_help_and_die(void) @@ -1519,54 +1405,90 @@ __noreturn static void print_help_and_die(void) exit(0); } -int main(int argc, char *argv[]) +static int setup_tasks_and_schedule(void) { - int ret; - char *cf; + struct exec_task exec_task = {.task = NULL}; + struct status_task status_task = {.fd = -1}; + struct input_task input_task = {.task = NULL}; + struct signal_task signal_task = {.task = NULL}; + struct sched sched = { + .default_timeout = { + .tv_sec = conf.timeout_arg / 1000, + .tv_usec = (conf.timeout_arg % 1000) * 1000, + }, + }; - _argc = argc; - _argv = argv; + exec_task.task = task_register(&(struct task_info) { + .name = "exec", + .pre_select = exec_pre_select, + .post_select = exec_post_select, + .context = &exec_task, + }, &sched); + + status_task.task = task_register(&(struct task_info) { + .name = "status", + .pre_select = status_pre_select, + .post_select = status_post_select, + .context = &status_task, + }, &sched); + + input_task.task = task_register(&(struct task_info) { + .name = "input", + .pre_select = input_pre_select, + .post_select = input_post_select, + .context = &input_task, + }, &sched); + + signal_task.fd = para_signal_init(); + para_install_sighandler(SIGINT); + para_install_sighandler(SIGTERM); + para_install_sighandler(SIGCHLD); + para_install_sighandler(SIGUSR1); + signal_task.task = task_register(&(struct task_info) { + .name = "signal", + .pre_select = signal_pre_select, + .post_select = signal_post_select, + .context = &signal_task, + }, &sched); + return schedule(&sched); +} +/** + * The main function of para_gui. + * + * \param argc Usual argument count. + * \param argv Usual argument vector. + * + * After initialization para_gui registers the following tasks to the paraslash + * scheduler: status, exec, signal, input. + * + * The status task executes the para_audioc stat command to obtain the status + * of para_server and para_audiod, and displays this information in the top + * window of para_gui. + * + * The exec task is responsible for printing the output of the currently + * running executable to the bottom window. + * + * The signal task performs suitable actions according to any signals received. + * For example it refreshes all windows on terminal size changes and resets the + * terminal on \p SIGTERM. + * + * The input task reads single key strokes from stdin. For each key pressed, it + * executes the command handler associated with this key. + * + * \return \p EXIT_SUCCESS or \p EXIT_FAILURE. + */ +int main(int argc, char *argv[]) +{ gui_cmdline_parser(argc, argv, &conf); /* exits on errors */ loglevel = get_loglevel_by_name(conf.loglevel_arg); version_handle_flag("gui", conf.version_given); if (conf.help_given || conf.detailed_help_given) print_help_and_die(); - cf = configfile_exists(); - if (!cf && conf.config_file_given) { - fprintf(stderr, "can not read config file %s\n", - conf.config_file_arg); - exit(EXIT_FAILURE); - } - if (cf) { - struct gui_cmdline_parser_params params = { - .override = 0, - .initialize = 0, - .check_required = 0, - .check_ambiguity = 0, - .print_errors = 1, - }; - gui_cmdline_parser_config_file(cf, &conf, ¶ms); - loglevel = get_loglevel_by_name(conf.loglevel_arg); - } - if (check_key_map_args() < 0) { - fprintf(stderr, "invalid key map\n"); - exit(EXIT_FAILURE); - } - init_theme_or_die(conf.theme_arg, &theme); - top.lines = theme.top_lines_default; - setup_signal_handling(); + parse_config_file_or_die(false /* override */); bot_win_rb = ringbuffer_new(RINGBUFFER_SIZE); setlocale(LC_CTYPE, ""); initscr(); /* needed only once, always successful */ init_curses(); - print_welcome(); - for (;;) { - print_status_bar(); - ret = do_select(GETCH_MODE); - if (!ret) - continue; - print_in_bar(COLOR_MSG, " "); - handle_command(ret); - } + return setup_tasks_and_schedule() < 0? EXIT_FAILURE : EXIT_SUCCESS; } diff --git a/gui.h b/gui.h index 8f25c767..6e5cc3bb 100644 --- a/gui.h +++ b/gui.h @@ -1,38 +1,72 @@ /* - * Copyright (C) 2007-2014 Andre Noll + * Copyright (C) 2007-2014 Andre Noll * * Licensed under the GPL v2. For licencing details see COPYING. */ /** \file gui.h symbols used by gui and gui_theme */ +/** + * The foreground and background color of each status item, the decorations and + * all messages can be customized through an instance of this structure. + */ +struct gui_color_spec { + int fg; /**< Foreground color. */ + int bg; /**< Background color. */ +}; + +/** How to display one status item. */ struct stat_item_data { - const char *prefix, *postfix; - unsigned x, y, len; - int fg, bg, align; + const char *prefix; /**< Text to print before the item content. */ + const char *postfix; /**< Text to print after item content. */ + unsigned x; /**< Horizontal start coordinate for this item. */ + unsigned y; /**< Vertical start coordinate for this item. */ + unsigned len; /**< Item width, including \a prefix and \a postfix. */ + struct gui_color_spec color; /**< Foreground and background color. */ + int align; /**< How to align this item. */ }; +/** Theme definition. */ struct gui_theme { + /** Printed at startup. */ const char *name; + /** Also printed at startup. */ const char *author; - int sb_fg, sb_bg; - int cmd_fg, cmd_bg; - int output_fg, output_bg; - int msg_fg, msg_bg; - int err_msg_fg, err_msg_bg; - int welcome_fg, welcome_bg; - int sep_fg, sep_bg; - const char *sep_str; - int default_fg, default_bg; - - int top_lines_default, top_lines_min; - int lines_min, cols_min; + /** The character for the separator line. */ + char sep_char; + /** Default color, see assume_default_colors(3). */ + struct gui_color_spec dflt; + /** Default number of lines of the top window. */ + int top_lines_default; + /** Minimal admissible number of lines to display the top window. */ + int top_lines_min; + /** Minimal admissible number of lines to display this theme. */ + int lines_min; + /** Minimal admissible number of columns to display this theme. */ + int cols_min; + /** Individual status item properties. */ struct stat_item_data data[NUM_STAT_ITEMS]; + /** Color of the status bar. */ + struct gui_color_spec sb; + /** Color of the name and args of the executing process. */ + struct gui_color_spec cmd; + /** Color for stdout of the executing process. */ + struct gui_color_spec output; + /** Color for log messages of moderate severity. */ + struct gui_color_spec msg; + /** Color for severe log messages. */ + struct gui_color_spec err_msg; + /** Color for the separator line. */ + struct gui_color_spec sep; }; -void init_theme_or_die(const char *name, struct gui_theme *t); -void next_theme(struct gui_theme *); -void prev_theme(struct gui_theme *); +void theme_init(const char *name, struct gui_theme *t); +void theme_prev(struct gui_theme *t); +void theme_next(struct gui_theme *t); + +/** Status item text should be left-aligned. */ #define LEFT 1 +/** Status item text should be right-aligned. */ #define RIGHT 2 +/** Status item text should be displayed centered. */ #define CENTER 3 diff --git a/gui_theme.c b/gui_theme.c index fa63e909..9e90029b 100644 --- a/gui_theme.c +++ b/gui_theme.c @@ -1,9 +1,11 @@ /* - * Copyright (C) 2005-2014 Andre Noll + * Copyright (C) 2005-2014 Andre Noll * * Licensed under the GPL v2. For licencing details see COPYING. */ +/** \file gui_theme.c Theme definitions. */ + #include "para.h" #include "gui.h" #include @@ -16,28 +18,26 @@ static void init_theme_simple(struct gui_theme *t) t->top_lines_min = 2; t->cols_min = 40; t->top_lines_default = 2; - t->sb_bg = COLOR_CYAN; - t->sb_fg = COLOR_BLACK; - t->cmd_bg = COLOR_WHITE; - t->cmd_fg = COLOR_BLACK; - t->output_bg = COLOR_BLUE; - t->output_fg = COLOR_WHITE; - t->msg_bg = COLOR_BLUE; - t->msg_fg = COLOR_YELLOW; - t->err_msg_bg = COLOR_RED; - t->err_msg_fg = COLOR_WHITE; - t->welcome_bg = COLOR_BLUE; - t->welcome_fg = COLOR_WHITE; - t->sep_bg = COLOR_BLUE; - t->sep_fg = COLOR_CYAN; - t->default_fg = COLOR_WHITE; - t->default_bg = COLOR_BLUE; - t->sep_str = "*"; + t->sb.bg = COLOR_CYAN; + t->sb.fg = COLOR_BLACK; + t->cmd.bg = COLOR_WHITE; + t->cmd.fg = COLOR_BLACK; + t->output.bg = COLOR_BLUE; + t->output.fg = COLOR_WHITE; + t->msg.bg = COLOR_BLUE; + t->msg.fg = COLOR_YELLOW; + t->err_msg.bg = COLOR_RED; + t->err_msg.fg = COLOR_WHITE; + t->sep.bg = COLOR_BLUE; + t->sep.fg = COLOR_CYAN; + t->dflt.fg = COLOR_WHITE; + t->dflt.bg = COLOR_BLUE; + t->sep_char = '*'; d[SI_BASENAME].prefix = ""; d[SI_BASENAME].postfix = ""; - d[SI_BASENAME].fg = COLOR_WHITE; - d[SI_BASENAME].bg = COLOR_BLUE; + d[SI_BASENAME].color.fg = COLOR_WHITE; + d[SI_BASENAME].color.bg = COLOR_BLUE; d[SI_BASENAME].align = CENTER; d[SI_BASENAME].x = 0; d[SI_BASENAME].y = 7; @@ -45,8 +45,8 @@ static void init_theme_simple(struct gui_theme *t) d[SI_STATUS].prefix = "para_server: "; d[SI_STATUS].postfix = ""; - d[SI_STATUS].fg = COLOR_WHITE; - d[SI_STATUS].bg = COLOR_BLUE; + d[SI_STATUS].color.fg = COLOR_WHITE; + d[SI_STATUS].color.bg = COLOR_BLUE; d[SI_STATUS].align = CENTER; d[SI_STATUS].x = 0; d[SI_STATUS].y = 60; @@ -54,8 +54,8 @@ static void init_theme_simple(struct gui_theme *t) d[SI_AUDIOD_STATUS].prefix = "para_audiod: "; d[SI_AUDIOD_STATUS].postfix = ""; - d[SI_AUDIOD_STATUS].fg = COLOR_WHITE; - d[SI_AUDIOD_STATUS].bg = COLOR_BLUE; + d[SI_AUDIOD_STATUS].color.fg = COLOR_WHITE; + d[SI_AUDIOD_STATUS].color.bg = COLOR_BLUE; d[SI_AUDIOD_STATUS].align = CENTER; d[SI_AUDIOD_STATUS].x = 50; d[SI_AUDIOD_STATUS].y = 60; @@ -75,29 +75,27 @@ static void init_theme_colorful_blackness(struct gui_theme *t) t->top_lines_min = 9; t->top_lines_default = 11; /* default number of lines */ - t->sb_bg = COLOR_GREEN; /* status bar background */ - t->sb_fg = COLOR_BLACK; /* status bar foreground */ - t->cmd_bg = COLOR_BLACK; - t->cmd_fg = COLOR_YELLOW; - t->output_bg = COLOR_BLACK; - t->output_fg = COLOR_CYAN; - t->msg_bg = COLOR_BLACK; - t->msg_fg = COLOR_WHITE; - t->err_msg_bg = COLOR_RED; - t->err_msg_fg = COLOR_WHITE; - t->welcome_bg = COLOR_BLUE; - t->welcome_fg = COLOR_WHITE; - t->sep_bg = COLOR_BLACK; /* color of the separator */ - t->sep_fg = COLOR_BLUE; - t->sep_str = "-"; - t->default_bg = COLOR_BLACK; - t->default_fg = COLOR_MAGENTA; + t->sb.bg = COLOR_GREEN; /* status bar background */ + t->sb.fg = COLOR_BLACK; /* status bar foreground */ + t->cmd.bg = COLOR_BLACK; + t->cmd.fg = COLOR_YELLOW; + t->output.bg = COLOR_BLACK; + t->output.fg = COLOR_CYAN; + t->msg.bg = COLOR_BLACK; + t->msg.fg = COLOR_WHITE; + t->err_msg.bg = COLOR_RED; + t->err_msg.fg = COLOR_WHITE; + t->sep.bg = COLOR_BLACK; /* color of the separator */ + t->sep.fg = COLOR_BLUE; + t->sep_char = 0; /* default (ACS_HLINE) */ + t->dflt.bg = COLOR_BLACK; + t->dflt.fg = COLOR_MAGENTA; d[SI_PLAY_TIME].prefix = ""; d[SI_PLAY_TIME].postfix = ""; - d[SI_PLAY_TIME].fg = COLOR_CYAN; - d[SI_PLAY_TIME].bg = COLOR_BLACK; + d[SI_PLAY_TIME].color.fg = COLOR_CYAN; + d[SI_PLAY_TIME].color.bg = COLOR_BLACK; d[SI_PLAY_TIME].align = CENTER; d[SI_PLAY_TIME].x = 0; d[SI_PLAY_TIME].y = 7; @@ -105,8 +103,8 @@ static void init_theme_colorful_blackness(struct gui_theme *t) d[SI_BASENAME].prefix = ""; d[SI_BASENAME].postfix = ""; - d[SI_BASENAME].fg = COLOR_CYAN; - d[SI_BASENAME].bg = COLOR_BLACK; + d[SI_BASENAME].color.fg = COLOR_CYAN; + d[SI_BASENAME].color.bg = COLOR_BLACK; d[SI_BASENAME].align = LEFT; d[SI_BASENAME].x = 35; d[SI_BASENAME].y = 7; @@ -114,8 +112,8 @@ static void init_theme_colorful_blackness(struct gui_theme *t) d[SI_STATUS].prefix = ""; d[SI_STATUS].postfix = " "; - d[SI_STATUS].fg = COLOR_RED; - d[SI_STATUS].bg = COLOR_BLACK; + d[SI_STATUS].color.fg = COLOR_RED; + d[SI_STATUS].color.bg = COLOR_BLACK; d[SI_STATUS].align = RIGHT; d[SI_STATUS].x = 0; d[SI_STATUS].y = 17; @@ -123,8 +121,8 @@ static void init_theme_colorful_blackness(struct gui_theme *t) d[SI_STATUS_FLAGS].prefix = "("; d[SI_STATUS_FLAGS].postfix = ")"; - d[SI_STATUS_FLAGS].fg = COLOR_RED; - d[SI_STATUS_FLAGS].bg = COLOR_BLACK; + d[SI_STATUS_FLAGS].color.fg = COLOR_RED; + d[SI_STATUS_FLAGS].color.bg = COLOR_BLACK; d[SI_STATUS_FLAGS].align = LEFT; d[SI_STATUS_FLAGS].x = 11; d[SI_STATUS_FLAGS].y = 17; @@ -132,8 +130,8 @@ static void init_theme_colorful_blackness(struct gui_theme *t) d[SI_IMAGE_ID].prefix = "img: "; d[SI_IMAGE_ID].postfix = ""; - d[SI_IMAGE_ID].fg = COLOR_RED; - d[SI_IMAGE_ID].bg = COLOR_BLACK; + d[SI_IMAGE_ID].color.fg = COLOR_RED; + d[SI_IMAGE_ID].color.bg = COLOR_BLACK; d[SI_IMAGE_ID].align = CENTER; d[SI_IMAGE_ID].x = 21; d[SI_IMAGE_ID].y = 17; @@ -141,8 +139,8 @@ static void init_theme_colorful_blackness(struct gui_theme *t) d[SI_LYRICS_ID].prefix = "lyr: "; d[SI_LYRICS_ID].postfix = ""; - d[SI_LYRICS_ID].fg = COLOR_RED; - d[SI_LYRICS_ID].bg = COLOR_BLACK; + d[SI_LYRICS_ID].color.fg = COLOR_RED; + d[SI_LYRICS_ID].color.bg = COLOR_BLACK; d[SI_LYRICS_ID].align = CENTER; d[SI_LYRICS_ID].x = 31; d[SI_LYRICS_ID].y = 17; @@ -150,8 +148,8 @@ static void init_theme_colorful_blackness(struct gui_theme *t) d[SI_FORMAT].prefix = "format: "; d[SI_FORMAT].postfix = ""; - d[SI_FORMAT].fg = COLOR_RED; - d[SI_FORMAT].bg = COLOR_BLACK; + d[SI_FORMAT].color.fg = COLOR_RED; + d[SI_FORMAT].color.bg = COLOR_BLACK; d[SI_FORMAT].align = CENTER; d[SI_FORMAT].x = 42; d[SI_FORMAT].y = 17; @@ -159,8 +157,8 @@ static void init_theme_colorful_blackness(struct gui_theme *t) d[SI_NUM_PLAYED].prefix = "#"; d[SI_NUM_PLAYED].postfix = ""; - d[SI_NUM_PLAYED].fg = COLOR_RED; - d[SI_NUM_PLAYED].bg = COLOR_BLACK; + d[SI_NUM_PLAYED].color.fg = COLOR_RED; + d[SI_NUM_PLAYED].color.bg = COLOR_BLACK; d[SI_NUM_PLAYED].align = LEFT; d[SI_NUM_PLAYED].x = 60; d[SI_NUM_PLAYED].y = 17; @@ -168,8 +166,8 @@ static void init_theme_colorful_blackness(struct gui_theme *t) d[SI_BITRATE].prefix = ""; d[SI_BITRATE].postfix = ""; - d[SI_BITRATE].fg = COLOR_RED; - d[SI_BITRATE].bg = COLOR_BLACK; + d[SI_BITRATE].color.fg = COLOR_RED; + d[SI_BITRATE].color.bg = COLOR_BLACK; d[SI_BITRATE].align = CENTER; d[SI_BITRATE].x = 65; d[SI_BITRATE].y = 17; @@ -177,8 +175,8 @@ static void init_theme_colorful_blackness(struct gui_theme *t) d[SI_FREQUENCY].prefix = ""; d[SI_FREQUENCY].postfix = ""; - d[SI_FREQUENCY].fg = COLOR_RED; - d[SI_FREQUENCY].bg = COLOR_BLACK; + d[SI_FREQUENCY].color.fg = COLOR_RED; + d[SI_FREQUENCY].color.bg = COLOR_BLACK; d[SI_FREQUENCY].align = CENTER; d[SI_FREQUENCY].x = 78; d[SI_FREQUENCY].y = 17; @@ -186,8 +184,8 @@ static void init_theme_colorful_blackness(struct gui_theme *t) d[SI_SCORE].prefix = "sc: "; d[SI_SCORE].postfix = ""; - d[SI_SCORE].fg = COLOR_RED; - d[SI_SCORE].bg = COLOR_BLACK; + d[SI_SCORE].color.fg = COLOR_RED; + d[SI_SCORE].color.bg = COLOR_BLACK; d[SI_SCORE].align = CENTER; d[SI_SCORE].x = 88; d[SI_SCORE].y = 17; @@ -195,8 +193,8 @@ static void init_theme_colorful_blackness(struct gui_theme *t) d[SI_AUDIOD_STATUS].prefix = ""; d[SI_AUDIOD_STATUS].postfix = ""; - d[SI_AUDIOD_STATUS].fg = COLOR_MAGENTA; - d[SI_AUDIOD_STATUS].bg = COLOR_BLACK; + d[SI_AUDIOD_STATUS].color.fg = COLOR_MAGENTA; + d[SI_AUDIOD_STATUS].color.bg = COLOR_BLACK; d[SI_AUDIOD_STATUS].align = CENTER; d[SI_AUDIOD_STATUS].x = 0; d[SI_AUDIOD_STATUS].y = 27; @@ -204,8 +202,8 @@ static void init_theme_colorful_blackness(struct gui_theme *t) d[SI_DECODER_FLAGS].prefix = "["; d[SI_DECODER_FLAGS].postfix = "]"; - d[SI_DECODER_FLAGS].fg = COLOR_MAGENTA; - d[SI_DECODER_FLAGS].bg = COLOR_BLACK; + d[SI_DECODER_FLAGS].color.fg = COLOR_MAGENTA; + d[SI_DECODER_FLAGS].color.bg = COLOR_BLACK; d[SI_DECODER_FLAGS].align = CENTER; d[SI_DECODER_FLAGS].x = 5; d[SI_DECODER_FLAGS].y = 27; @@ -213,8 +211,8 @@ static void init_theme_colorful_blackness(struct gui_theme *t) d[SI_MTIME].prefix = "mod: "; d[SI_MTIME].postfix = ""; - d[SI_MTIME].fg = COLOR_MAGENTA; - d[SI_MTIME].bg = COLOR_BLACK; + d[SI_MTIME].color.fg = COLOR_MAGENTA; + d[SI_MTIME].color.bg = COLOR_BLACK; d[SI_MTIME].align = CENTER; d[SI_MTIME].x = 15; d[SI_MTIME].y = 27; @@ -222,8 +220,8 @@ static void init_theme_colorful_blackness(struct gui_theme *t) d[SI_FILE_SIZE].prefix = ""; d[SI_FILE_SIZE].postfix = "kb"; - d[SI_FILE_SIZE].fg = COLOR_MAGENTA; - d[SI_FILE_SIZE].bg = COLOR_BLACK; + d[SI_FILE_SIZE].color.fg = COLOR_MAGENTA; + d[SI_FILE_SIZE].color.bg = COLOR_BLACK; d[SI_FILE_SIZE].align = CENTER; d[SI_FILE_SIZE].x = 37; d[SI_FILE_SIZE].y = 27; @@ -231,8 +229,8 @@ static void init_theme_colorful_blackness(struct gui_theme *t) d[SI_CHANNELS].prefix = ""; d[SI_CHANNELS].postfix = "ch"; - d[SI_CHANNELS].fg = COLOR_MAGENTA; - d[SI_CHANNELS].bg = COLOR_BLACK; + d[SI_CHANNELS].color.fg = COLOR_MAGENTA; + d[SI_CHANNELS].color.bg = COLOR_BLACK; d[SI_CHANNELS].align = CENTER; d[SI_CHANNELS].x = 47; d[SI_CHANNELS].y = 27; @@ -240,8 +238,8 @@ static void init_theme_colorful_blackness(struct gui_theme *t) d[SI_LAST_PLAYED].prefix = "lp: "; d[SI_LAST_PLAYED].postfix = ""; - d[SI_LAST_PLAYED].fg = COLOR_MAGENTA; - d[SI_LAST_PLAYED].bg = COLOR_BLACK; + d[SI_LAST_PLAYED].color.fg = COLOR_MAGENTA; + d[SI_LAST_PLAYED].color.bg = COLOR_BLACK; d[SI_LAST_PLAYED].align = CENTER; d[SI_LAST_PLAYED].x = 52; d[SI_LAST_PLAYED].y = 27; @@ -249,8 +247,8 @@ static void init_theme_colorful_blackness(struct gui_theme *t) d[SI_NUM_CHUNKS].prefix = ""; d[SI_NUM_CHUNKS].postfix = "x"; - d[SI_NUM_CHUNKS].fg = COLOR_MAGENTA; - d[SI_NUM_CHUNKS].bg = COLOR_BLACK; + d[SI_NUM_CHUNKS].color.fg = COLOR_MAGENTA; + d[SI_NUM_CHUNKS].color.bg = COLOR_BLACK; d[SI_NUM_CHUNKS].align = RIGHT; d[SI_NUM_CHUNKS].x = 73; d[SI_NUM_CHUNKS].y = 27; @@ -258,8 +256,8 @@ static void init_theme_colorful_blackness(struct gui_theme *t) d[SI_CHUNK_TIME].prefix = ""; d[SI_CHUNK_TIME].postfix = "ms"; - d[SI_CHUNK_TIME].fg = COLOR_MAGENTA; - d[SI_CHUNK_TIME].bg = COLOR_BLACK; + d[SI_CHUNK_TIME].color.fg = COLOR_MAGENTA; + d[SI_CHUNK_TIME].color.bg = COLOR_BLACK; d[SI_CHUNK_TIME].align = LEFT; d[SI_CHUNK_TIME].x = 84; d[SI_CHUNK_TIME].y = 27; @@ -267,8 +265,8 @@ static void init_theme_colorful_blackness(struct gui_theme *t) d[SI_AMPLIFICATION].prefix = "amp:"; d[SI_AMPLIFICATION].postfix = ""; - d[SI_AMPLIFICATION].fg = COLOR_MAGENTA; - d[SI_AMPLIFICATION].bg = COLOR_BLACK; + d[SI_AMPLIFICATION].color.fg = COLOR_MAGENTA; + d[SI_AMPLIFICATION].color.bg = COLOR_BLACK; d[SI_AMPLIFICATION].align = RIGHT; d[SI_AMPLIFICATION].x = 92; d[SI_AMPLIFICATION].y = 27; @@ -276,8 +274,8 @@ static void init_theme_colorful_blackness(struct gui_theme *t) d[SI_TECHINFO].prefix = ""; d[SI_TECHINFO].postfix = ""; - d[SI_TECHINFO].fg = COLOR_GREEN; - d[SI_TECHINFO].bg = COLOR_BLACK; + d[SI_TECHINFO].color.fg = COLOR_GREEN; + d[SI_TECHINFO].color.bg = COLOR_BLACK; d[SI_TECHINFO].align = CENTER; d[SI_TECHINFO].x = 0; d[SI_TECHINFO].y = 43; @@ -285,8 +283,8 @@ static void init_theme_colorful_blackness(struct gui_theme *t) d[SI_TITLE].prefix = ""; d[SI_TITLE].postfix = ","; - d[SI_TITLE].fg = COLOR_GREEN; - d[SI_TITLE].bg = COLOR_BLACK; + d[SI_TITLE].color.fg = COLOR_GREEN; + d[SI_TITLE].color.bg = COLOR_BLACK; d[SI_TITLE].align = RIGHT; d[SI_TITLE].x = 0; d[SI_TITLE].y = 53; @@ -294,8 +292,8 @@ static void init_theme_colorful_blackness(struct gui_theme *t) d[SI_ARTIST].prefix = " by "; d[SI_ARTIST].postfix = ""; - d[SI_ARTIST].fg = COLOR_GREEN; - d[SI_ARTIST].bg = COLOR_BLACK; + d[SI_ARTIST].color.fg = COLOR_GREEN; + d[SI_ARTIST].color.bg = COLOR_BLACK; d[SI_ARTIST].align = LEFT; d[SI_ARTIST].x = 45; d[SI_ARTIST].y = 53; @@ -303,8 +301,8 @@ static void init_theme_colorful_blackness(struct gui_theme *t) d[SI_YEAR].prefix = "("; d[SI_YEAR].postfix = ")"; - d[SI_YEAR].fg = COLOR_GREEN; - d[SI_YEAR].bg = COLOR_BLACK; + d[SI_YEAR].color.fg = COLOR_GREEN; + d[SI_YEAR].color.bg = COLOR_BLACK; d[SI_YEAR].align = RIGHT; d[SI_YEAR].x = 90; d[SI_YEAR].y = 53; @@ -312,8 +310,8 @@ static void init_theme_colorful_blackness(struct gui_theme *t) d[SI_ALBUM].prefix = "A: "; d[SI_ALBUM].postfix = ","; - d[SI_ALBUM].fg = COLOR_GREEN; - d[SI_ALBUM].bg = COLOR_BLACK; + d[SI_ALBUM].color.fg = COLOR_GREEN; + d[SI_ALBUM].color.bg = COLOR_BLACK; d[SI_ALBUM].align = RIGHT; d[SI_ALBUM].x = 0; d[SI_ALBUM].y = 63; @@ -321,8 +319,8 @@ static void init_theme_colorful_blackness(struct gui_theme *t) d[SI_COMMENT].prefix = " C: "; d[SI_COMMENT].postfix = ""; - d[SI_COMMENT].fg = COLOR_GREEN; - d[SI_COMMENT].bg = COLOR_BLACK; + d[SI_COMMENT].color.fg = COLOR_GREEN; + d[SI_COMMENT].color.bg = COLOR_BLACK; d[SI_COMMENT].align = LEFT; d[SI_COMMENT].x = 50; d[SI_COMMENT].y = 63; @@ -330,8 +328,8 @@ static void init_theme_colorful_blackness(struct gui_theme *t) d[SI_AFS_MODE].prefix = ""; d[SI_AFS_MODE].postfix = ""; - d[SI_AFS_MODE].fg = COLOR_YELLOW; - d[SI_AFS_MODE].bg = COLOR_BLACK; + d[SI_AFS_MODE].color.fg = COLOR_YELLOW; + d[SI_AFS_MODE].color.bg = COLOR_BLACK; d[SI_AFS_MODE].align = CENTER; d[SI_AFS_MODE].x = 0; d[SI_AFS_MODE].y = 77; @@ -339,8 +337,8 @@ static void init_theme_colorful_blackness(struct gui_theme *t) d[SI_ATTRIBUTES_TXT].prefix = ""; d[SI_ATTRIBUTES_TXT].postfix = ""; - d[SI_ATTRIBUTES_TXT].fg = COLOR_YELLOW; - d[SI_ATTRIBUTES_TXT].bg = COLOR_BLACK; + d[SI_ATTRIBUTES_TXT].color.fg = COLOR_YELLOW; + d[SI_ATTRIBUTES_TXT].color.bg = COLOR_BLACK; d[SI_ATTRIBUTES_TXT].align = CENTER; d[SI_ATTRIBUTES_TXT].x = 0; d[SI_ATTRIBUTES_TXT].y = 87; @@ -348,8 +346,8 @@ static void init_theme_colorful_blackness(struct gui_theme *t) d[SI_DIRECTORY].prefix = "dir: "; d[SI_DIRECTORY].postfix = ""; - d[SI_DIRECTORY].fg = COLOR_YELLOW; - d[SI_DIRECTORY].bg = COLOR_BLACK; + d[SI_DIRECTORY].color.fg = COLOR_YELLOW; + d[SI_DIRECTORY].color.bg = COLOR_BLACK; d[SI_DIRECTORY].align = CENTER; d[SI_DIRECTORY].x = 0; d[SI_DIRECTORY].y = 97; @@ -372,6 +370,7 @@ static struct theme_description themes[] = { }, }; +/** Number of elements in the \a themes array. */ #define NUM_THEMES (ARRAY_SIZE(themes)) static int current_theme_num; @@ -385,9 +384,18 @@ static void set_theme(int num, struct gui_theme *t) t->name = themes[num].name; themes[num].init(t); current_theme_num = num; + PARA_NOTICE_LOG("theme: %s\n", t->name); } -void init_theme_or_die(const char *name, struct gui_theme *t) +/** + * Initialize a theme. + * + * \param name Name of the theme to be initialized. + * \param t The function fills out this structure. + * + * This function exits if there is no theme called \a name. + */ +void theme_init(const char *name, struct gui_theme *t) { int i; @@ -402,12 +410,30 @@ void init_theme_or_die(const char *name, struct gui_theme *t) exit(EXIT_FAILURE); } -void prev_theme(struct gui_theme *t) +/** + * Activate the previous available theme. + * + * \param t Theme definition is stored here. + * + * This picks the theme that comes before the currently active one, or the last + * availabe theme, if the current one is the first. + * + * \sa \ref theme_next(). + */ +void theme_prev(struct gui_theme *t) { return set_theme(++current_theme_num, t); } -void next_theme(struct gui_theme *t) +/** + * Activate the next available theme. + * + * \param t Theme definition is stored here. + * + * This works exacly as theme_prev() but cycles forwards through the list of + * available themes. + */ +void theme_next(struct gui_theme *t) { return set_theme(--current_theme_num, t); } diff --git a/http_recv.c b/http_recv.c index 1f02e48d..2c7d02bb 100644 --- a/http_recv.c +++ b/http_recv.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2005-2014 Andre Noll + * Copyright (C) 2005-2014 Andre Noll * * Licensed under the GPL v2. For licencing details see COPYING. */ @@ -60,12 +60,12 @@ static char *make_request_msg(void) return ret; } -static void http_recv_pre_select(struct sched *s, struct task *t) +static void http_recv_pre_select(struct sched *s, void *context) { - struct receiver_node *rn = container_of(t, struct receiver_node, task); + struct receiver_node *rn = context; struct private_http_recv_data *phd = rn->private_data; - if (generic_recv_pre_select(s, t) <= 0) + if (generic_recv_pre_select(s, rn) <= 0) return; if (phd->status == HTTP_CONNECTED) para_fd_set(rn->fd, &s->wfds, &s->max_fileno); @@ -78,16 +78,16 @@ static void http_recv_pre_select(struct sched *s, struct task *t) * area with data read from the socket. In any case, update the state of the * connection if necessary. */ -static int http_recv_post_select(struct sched *s, struct task *t) +static int http_recv_post_select(struct sched *s, void *context) { - struct receiver_node *rn = container_of(t, struct receiver_node, task); + struct receiver_node *rn = context; struct private_http_recv_data *phd = rn->private_data; struct btr_node *btrn = rn->btrn; int ret, iovcnt; struct iovec iov[2]; size_t num_bytes; - ret = task_get_notification(t); + ret = task_get_notification(rn->task); if (ret < 0) goto out; ret = btr_node_status(btrn, 0, BTR_NT_ROOT); diff --git a/http_send.c b/http_send.c index 3e9c9539..ce2dddfa 100644 --- a/http_send.c +++ b/http_send.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2005-2014 Andre Noll + * Copyright (C) 2005-2014 Andre Noll * * Licensed under the GPL v2. For licencing details see COPYING. */ diff --git a/interactive.c b/interactive.c index 9f2b7195..efb18cee 100644 --- a/interactive.c +++ b/interactive.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2014 Andre Noll + * Copyright (C) 2011-2014 Andre Noll * * Licensed under the GPL v2. For licencing details see COPYING. */ @@ -29,7 +29,7 @@ struct i9e_private { FILE *stderr_stream; int num_columns; char empty_line[1000]; - struct task task; + struct task *task; struct btr_node *stdout_btrn; bool last_write_was_status; bool line_handler_running; @@ -52,7 +52,7 @@ static struct i9e_private i9e_private, *i9ep = &i9e_private; */ int i9e_get_error(void) { - return i9ep->task.error; + return task_status(i9ep->task); } static bool is_prefix(const char *partial, const char *full, size_t len) @@ -314,7 +314,7 @@ free_line: free(line); } -static int i9e_post_select(__a_unused struct sched *s, __a_unused struct task *t) +static int i9e_post_select(__a_unused struct sched *s, __a_unused void *context) { int ret; struct i9e_client_info *ici = i9ep->ici; @@ -371,7 +371,7 @@ out: return ret; } -static void i9e_pre_select(struct sched *s, __a_unused struct task *t) +static void i9e_pre_select(struct sched *s, __a_unused void *context) { int ret; @@ -439,7 +439,6 @@ static int dispatch_key(__a_unused int count, int key) * The caller must allocate and initialize the structure \a ici points to. * * \return Standard. - * \sa \ref register_task(). */ int i9e_open(struct i9e_client_info *ici, struct sched *s) { @@ -453,10 +452,13 @@ int i9e_open(struct i9e_client_info *ici, struct sched *s) ret = mark_fd_nonblocking(ici->fds[1]); if (ret < 0) return ret; - i9ep->task.pre_select = i9e_pre_select; - i9ep->task.post_select = i9e_post_select; - sprintf(i9ep->task.status, "i9e"); - register_task(s, &i9ep->task); + i9ep->task = task_register(&(struct task_info) { + .name = "i9e", + .pre_select = i9e_pre_select, + .post_select = i9e_post_select, + .context = i9ep, + }, s); + rl_readline_name = "para_i9e"; rl_basic_word_break_characters = " "; rl_attempted_completion_function = i9e_completer; diff --git a/interactive.h b/interactive.h index 96401b16..2c393023 100644 --- a/interactive.h +++ b/interactive.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2014 Andre Noll + * Copyright (C) 2011-2014 Andre Noll * * Licensed under the GPL v2. For licencing details see COPYING. */ diff --git a/ipc.c b/ipc.c index b8a6fd0c..3cf705ab 100644 --- a/ipc.c +++ b/ipc.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2006-2014 Andre Noll + * Copyright (C) 2006-2014 Andre Noll * * Licensed under the GPL v2. For licencing details see COPYING. */ diff --git a/m4/gengetopt/logfile.m4 b/m4/gengetopt/logfile.m4 index bb102939..070d736b 100644 --- a/m4/gengetopt/logfile.m4 +++ b/m4/gengetopt/logfile.m4 @@ -6,6 +6,6 @@ string typestr="filename" optional details=" If this option is not given, CURRENT_PROGRAM writes the log - messages to to stderr + messages to stderr. " diff --git a/mix.h b/mix.h index cfcfd72b..1141ce59 100644 --- a/mix.h +++ b/mix.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2012-2014 Andre Noll + * Copyright (C) 2012-2014 Andre Noll * * Licensed under the GPL v2. For licencing details see COPYING. */ diff --git a/mm.c b/mm.c index 6f2c088e..82b6fe60 100644 --- a/mm.c +++ b/mm.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2007-2014 Andre Noll + * Copyright (C) 2007-2014 Andre Noll * * Licensed under the GPL v2. For licencing details see COPYING. */ diff --git a/mm.h b/mm.h index 9c64002b..b6eac2d5 100644 --- a/mm.h +++ b/mm.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2007-2014 Andre Noll + * Copyright (C) 2007-2014 Andre Noll * * Licensed under the GPL v2. For licencing details see COPYING. */ diff --git a/mood.c b/mood.c index 897c22b9..a2525a78 100644 --- a/mood.c +++ b/mood.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2007-2014 Andre Noll + * Copyright (C) 2007-2014 Andre Noll * * Licensed under the GPL v2. For licencing details see COPYING. */ diff --git a/mood.h b/mood.h index 10e2ba10..d63f8a39 100644 --- a/mood.h +++ b/mood.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2007-2014 Andre Noll + * Copyright (C) 2007-2014 Andre Noll * * Licensed under the GPL v2. For licencing details see COPYING. */ diff --git a/mp3_afh.c b/mp3_afh.c index 2b558cbb..0ca742cb 100644 --- a/mp3_afh.c +++ b/mp3_afh.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2003-2014 Andre Noll + * Copyright (C) 2003-2014 Andre Noll * * Licensed under the GPL v2. For licencing details see COPYING. */ diff --git a/mp3dec_filter.c b/mp3dec_filter.c index feaa1d1f..fd11ce1e 100644 --- a/mp3dec_filter.c +++ b/mp3dec_filter.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2005-2014 Andre Noll + * Copyright (C) 2005-2014 Andre Noll * * Licensed under the GPL v2. For licencing details see COPYING. */ @@ -77,9 +77,9 @@ static void mp3dec_close(struct filter_node *fn) #define MP3DEC_MAX_FRAME 8192 -static int mp3dec_post_select(__a_unused struct sched *s, struct task *t) +static int mp3dec_post_select(__a_unused struct sched *s, void *context) { - struct filter_node *fn = container_of(t, struct filter_node, task); + struct filter_node *fn = context; int i, ret; struct private_mp3dec_data *pmd = fn->private_data; struct btr_node *btrn = fn->btrn; diff --git a/net.c b/net.c index c11f67c4..dcadf543 100644 --- a/net.c +++ b/net.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2005-2014 Andre Noll + * Copyright (C) 2005-2014 Andre Noll * * Licensed under the GPL v2. For licencing details see COPYING. */ @@ -963,16 +963,18 @@ int recv_cred_buffer(int fd, char *buf, size_t size) return recv_buffer(fd, buf, size) > 0? 1 : -E_RECVMSG; } #else /* HAVE_UCRED */ + /** - * Send \p NULL-terminated buffer and Unix credentials of the current process. + * Send a buffer and the credentials of the current process to a socket. * - * \param sock The socket file descriptor. - * \param buf The buffer to be sent. + * \param sock The file descriptor of the sending socket. + * \param buf The zero-terminated buffer to send. * - * \return On success, this call returns the number of characters sent. On - * error, \p -E_SENDMSG is returned. + * \return On success, this call returns the number of bytes sent. On errors, + * \p -E_SENDMSG is returned. * - * \sa sendmsg(2), okir's Black Hats Manual. + * \sa \ref recv_cred_buffer, sendmsg(2), socket(7), unix(7), okir's Black Hats + * Manual. */ ssize_t send_cred_buffer(int sock, char *buf) { @@ -985,7 +987,7 @@ ssize_t send_cred_buffer(int sock, char *buf) /* Response data */ iov.iov_base = buf; - iov.iov_len = strlen(buf); + iov.iov_len = strlen(buf); c.pid = getpid(); c.uid = getuid(); c.gid = getgid(); @@ -1003,7 +1005,7 @@ ssize_t send_cred_buffer(int sock, char *buf) *(struct ucred *)CMSG_DATA(cmsg) = c; msg.msg_controllen = cmsg->cmsg_len; ret = sendmsg(sock, &msg, 0); - if (ret < 0) + if (ret < 0) ret = -E_SENDMSG; return ret; } @@ -1019,13 +1021,13 @@ static void dispose_fds(int *fds, unsigned num) /** * Receive a buffer and the Unix credentials of the sending process. * - * \param fd the socket file descriptor. - * \param buf the buffer to store the message. - * \param size the size of \a buffer. + * \param fd The file descriptor of the receiving socket. + * \param buf The buffer to store the received message. + * \param size The length of \a buf in bytes. * - * \return negative on errors, the user id on success. + * \return Negative on errors, the user id of the sending process on success. * - * \sa recvmsg(2), okir's Black Hats Manual. + * \sa \ref send_cred_buffer and the references given there. */ int recv_cred_buffer(int fd, char *buf, size_t size) { @@ -1058,7 +1060,7 @@ int recv_cred_buffer(int fd, char *buf, size_t size) } else if (cmsg->cmsg_level == SOL_SOCKET && cmsg->cmsg_type == SCM_RIGHTS) { - dispose_fds((int *) CMSG_DATA(cmsg), + dispose_fds((int *)CMSG_DATA(cmsg), (cmsg->cmsg_len - CMSG_LEN(0)) / sizeof(int)); } diff --git a/net.h b/net.h index 877d1cbb..c3dff7d8 100644 --- a/net.h +++ b/net.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2006-2014 Andre Noll + * Copyright (C) 2006-2014 Andre Noll * * Licensed under the GPL v2. For licencing details see COPYING. */ diff --git a/ogg_afh.c b/ogg_afh.c index debc0c9f..a6e58ff9 100644 --- a/ogg_afh.c +++ b/ogg_afh.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2004-2014 Andre Noll + * Copyright (C) 2004-2014 Andre Noll * * Licensed under the GPL v2. For licencing details see COPYING. */ diff --git a/ogg_afh_common.c b/ogg_afh_common.c index 21444fa3..5e75265f 100644 --- a/ogg_afh_common.c +++ b/ogg_afh_common.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2004-2014 Andre Noll + * Copyright (C) 2004-2014 Andre Noll * * Licensed under the GPL v2. For licencing details see COPYING. */ diff --git a/ogg_afh_common.h b/ogg_afh_common.h index 59a5c486..3150f745 100644 --- a/ogg_afh_common.h +++ b/ogg_afh_common.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2010-2014 Andre Noll + * Copyright (C) 2010-2014 Andre Noll * * Licensed under the GPL v2. For licencing details see COPYING. */ diff --git a/oggdec_filter.c b/oggdec_filter.c index 3222b4aa..48ac7a79 100644 --- a/oggdec_filter.c +++ b/oggdec_filter.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2005-2014 Andre Noll + * Copyright (C) 2005-2014 Andre Noll * * Licensed under the GPL v2. For licencing details see COPYING. */ @@ -181,9 +181,9 @@ out: #define OGGDEC_MAX_OUTPUT_SIZE (96 * 1024) #define OGGDEC_OUTPUT_CHUNK_SIZE (32 * 1024) -static void ogg_pre_select(struct sched *s, struct task *t) +static void ogg_pre_select(struct sched *s, void *context) { - struct filter_node *fn = container_of(t, struct filter_node, task); + struct filter_node *fn = context; struct private_oggdec_data *pod = fn->private_data; struct btr_node *btrn = fn->btrn; int ret; @@ -198,9 +198,9 @@ static void ogg_pre_select(struct sched *s, struct task *t) sched_min_delay(s); } -static int ogg_post_select(__a_unused struct sched *s, struct task *t) +static int ogg_post_select(__a_unused struct sched *s, void *context) { - struct filter_node *fn = container_of(t, struct filter_node, task); + struct filter_node *fn = context; struct private_oggdec_data *pod = fn->private_data; struct btr_node *btrn = fn->btrn; int ret, have; diff --git a/opus_afh.c b/opus_afh.c index 10fe25d8..22f14fd7 100644 --- a/opus_afh.c +++ b/opus_afh.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2012-2014 Andre Noll + * Copyright (C) 2012-2014 Andre Noll * * Licensed under the GPL v2. For licencing details see COPYING. */ diff --git a/opus_common.h b/opus_common.h index fea67274..b8d36903 100644 --- a/opus_common.h +++ b/opus_common.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2013-2014 Andre Noll + * Copyright (C) 2013-2014 Andre Noll * * Licensed under the GPL v2. For licencing details see COPYING. */ diff --git a/opusdec_filter.c b/opusdec_filter.c index 9022fbab..f84a42e5 100644 --- a/opusdec_filter.c +++ b/opusdec_filter.c @@ -2,7 +2,7 @@ * Copyright (c) 2002-2007 Jean-Marc Valin * Copyright (c) 2008 CSIRO * Copyright (c) 2007-2012 Xiph.Org Foundation - * Copyright (C) 2012-2014 Andre Noll + * Copyright (C) 2012-2014 Andre Noll * * Licensed under the GPL v2. For licencing details see COPYING. */ @@ -207,9 +207,9 @@ static int decode_packet(struct opusdec_context *ctx, ogg_packet *op, #define OPUSDEC_MAX_OUTPUT_SIZE (1024 * 1024) -static int opusdec_post_select(__a_unused struct sched *s, struct task *t) +static int opusdec_post_select(__a_unused struct sched *s, void *context) { - struct filter_node *fn = container_of(t, struct filter_node, task); + struct filter_node *fn = context; struct opusdec_context *ctx = fn->private_data; struct btr_node *btrn = fn->btrn; int ret; @@ -269,9 +269,9 @@ out: return ret; } -static void opusdec_pre_select(struct sched *s, struct task *t) +static void opusdec_pre_select(struct sched *s, void *context) { - struct filter_node *fn = container_of(t, struct filter_node, task); + struct filter_node *fn = context; struct opusdec_context *ctx = fn->private_data; int ret = btr_node_status(fn->btrn, fn->min_iqs, BTR_NT_INTERNAL); diff --git a/oss_mix.c b/oss_mix.c index 5fbfea08..cdac0773 100644 --- a/oss_mix.c +++ b/oss_mix.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 1998-2014 Andre Noll + * Copyright (C) 1998-2014 Andre Noll * * Licensed under the GPL v2. For licencing details see COPYING. */ diff --git a/oss_write.c b/oss_write.c index d547acf7..d4bfd446 100644 --- a/oss_write.c +++ b/oss_write.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2009-2014 Andre Noll + * Copyright (C) 2009-2014 Andre Noll * * Licensed under the GPL v2. For licencing details see COPYING. */ @@ -44,9 +44,9 @@ static int get_oss_format(enum sample_format sf) } } -static void oss_pre_select(struct sched *s, struct task *t) +static void oss_pre_select(struct sched *s, void *context) { - struct writer_node *wn = container_of(t, struct writer_node, task); + struct writer_node *wn = context; struct private_oss_write_data *powd = wn->private_data; int ret = btr_node_status(wn->btrn, wn->min_iqs, BTR_NT_LEAF); @@ -157,17 +157,16 @@ err_free: return ret; } -static int oss_post_select(__a_unused struct sched *s, - struct task *t) +static int oss_post_select(__a_unused struct sched *s, void *context) { - struct writer_node *wn = container_of(t, struct writer_node, task); + struct writer_node *wn = context; struct private_oss_write_data *powd = wn->private_data; struct btr_node *btrn = wn->btrn; size_t frames, bytes; int ret; char *data; - ret = task_get_notification(t); + ret = task_get_notification(wn->task); if (ret < 0) goto out; ret = btr_node_status(btrn, wn->min_iqs, BTR_NT_LEAF); diff --git a/osx_write.c b/osx_write.c index 889854c2..0a8b3d2f 100644 --- a/osx_write.c +++ b/osx_write.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2006-2014 Andre Noll + * Copyright (C) 2006-2014 Andre Noll * * Licensed under the GPL v2. For licencing details see COPYING. */ @@ -274,9 +274,9 @@ static inline bool need_drain_delay(struct private_osx_write_data *powd) return btr_get_input_queue_size(powd->callback_btrn) != 0; } -static void osx_write_pre_select(struct sched *s, struct task *t) +static void osx_write_pre_select(struct sched *s, void *context) { - struct writer_node *wn = container_of(t, struct writer_node, task); + struct writer_node *wn = context; struct private_osx_write_data *powd = wn->private_data; int ret; bool drain_delay_nec = false; @@ -301,14 +301,14 @@ static void osx_write_pre_select(struct sched *s, struct task *t) sched_request_timeout_ms(50, s); } -static int osx_write_post_select(__a_unused struct sched *s, struct task *t) +static int osx_write_post_select(__a_unused struct sched *s, void *context) { - struct writer_node *wn = container_of(t, struct writer_node, task); + struct writer_node *wn = context; struct private_osx_write_data *powd = wn->private_data; struct btr_node *btrn = wn->btrn; int ret; - ret = task_get_notification(t); + ret = task_get_notification(wn->task); if (ret < 0) goto fail; if (!powd) { diff --git a/para.h b/para.h index 6bd048d8..e8aa3e84 100644 --- a/para.h +++ b/para.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 1997-2014 Andre Noll + * Copyright (C) 1997-2014 Andre Noll * * Licensed under the GPL v2. For licencing details see COPYING. */ diff --git a/play.c b/play.c index 5736a2dd..9fc49e37 100644 --- a/play.c +++ b/play.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2012-2014 Andre Noll + * Copyright (C) 2012-2014 Andre Noll * * Licensed under the GPL v2. For licencing details see COPYING. */ @@ -57,7 +57,7 @@ enum state_change_request_type { }; struct play_task { - struct task task; + struct task *task; /* A bit array of invalid files (those will be skipped). */ bool *invalid; /* The file which is currently open. */ @@ -243,13 +243,16 @@ static void wipe_receiver_node(struct play_task *pt) /* returns: 0 not eof, 1: eof, < 0: fatal error. */ static int get_playback_error(struct play_task *pt) { - int err = pt->wn.task.error; + int err; + if (!pt->wn.task) + return 0; + err = task_status(pt->wn.task); if (err >= 0) return 0; - if (pt->fn.task.error >= 0) + if (task_status(pt->fn.task) >= 0) return 0; - if (pt->rn.task.error >= 0) + if (task_status(pt->rn.task) >= 0) return 0; if (err == -E_BTR_EOF || err == -E_RECV_EOF || err == -E_EOF || err == -E_WRITE_COMMON_EOF) @@ -267,16 +270,19 @@ static int eof_cleanup(struct play_task *pt) if (ret == 0) return ret; PARA_NOTICE_LOG("cleaning up wn/fn nodes\n"); + task_reap(&pt->wn.task); w->close(&pt->wn); btr_remove_node(&pt->wn.btrn); w->free_config(pt->wn.conf); memset(&pt->wn, 0, sizeof(struct writer_node)); + task_reap(&pt->fn.task); decoder->close(&pt->fn); btr_remove_node(&pt->fn.btrn); free(pt->fn.conf); memset(&pt->fn, 0, sizeof(struct filter_node)); + task_reap(&pt->rn.task); btr_remove_node(&pt->rn.btrn); /* * On eof (ret > 0), we do not wipe the receiver node struct until a @@ -295,7 +301,7 @@ static int shuffle_compare(__a_unused const void *a, __a_unused const void *b) static void shuffle(char **base, size_t num) { - srandom(now->tv_sec); + srandom(time(NULL)); qsort(base, num, sizeof(char *), shuffle_compare); } @@ -351,9 +357,6 @@ static int open_new_file(struct play_task *pt) free(tmp); tmp = NULL; } - pt->rn.task.pre_select = afh_recv->pre_select; - pt->rn.task.post_select = afh_recv->post_select; - sprintf(pt->rn.task.status, "%s receiver node", afh_recv->name); return 1; fail: wipe_receiver_node(pt); @@ -363,7 +366,7 @@ fail: static int load_file(struct play_task *pt) { const char *af; - char *tmp; + char *tmp, buf[20]; int ret; struct filter *decoder; @@ -373,7 +376,6 @@ static int load_file(struct play_task *pt) if (ret < 0) return ret; } else { - char buf[20]; pt->rn.btrn = new_recv_btrn(&pt->rn); sprintf(buf, "repos %lu", pt->start_chunk); ret = btr_exec_up(pt->rn.btrn, buf, &tmp); @@ -392,9 +394,6 @@ static int load_file(struct play_task *pt) goto fail; pt->fn.filter_num = ret; decoder = filters + ret; - pt->fn.task.pre_select = decoder->pre_select; - pt->fn.task.post_select = decoder->post_select; - sprintf(pt->fn.task.status, "%s decoder", af); pt->fn.btrn = btr_new_node(&(struct btr_node_description) EMBRACE(.name = decoder->name, .parent = pt->rn.btrn, .handler = decoder->execute, .context = &pt->fn)); @@ -402,11 +401,23 @@ static int load_file(struct play_task *pt) /* setup default writer */ pt->wn.conf = check_writer_arg_or_die(NULL, &pt->wn.writer_num); - pt->wn.task.error = 0; /* success, register tasks */ - register_task(&sched, &pt->rn.task); - register_task(&sched, &pt->fn.task); + pt->rn.task = task_register( + &(struct task_info) { + .name = afh_recv->name, + .pre_select = afh_recv->pre_select, + .post_select = afh_recv->post_select, + .context = &pt->rn + }, &sched); + sprintf(buf, "%s decoder", af); + pt->fn.task = task_register( + &(struct task_info) { + .name = buf, + .pre_select = decoder->pre_select, + .post_select = decoder->post_select, + .context = &pt->fn + }, &sched); register_writer_node(&pt->wn, pt->fn.btrn, &sched); return 1; fail: @@ -452,7 +463,8 @@ again: static void kill_stream(struct play_task *pt) { - task_notify(&pt->wn.task, E_EOF); + if (pt->wn.task) + task_notify(pt->wn.task, E_EOF); } #ifdef HAVE_READLINE @@ -1083,9 +1095,8 @@ static void session_update_time_string(struct play_task *pt, char *str, unsigned * terminates. Subsequent calls to i9e_get_error() then return negative and we * are allowed to call i9e_close() and terminate as well. */ -static int session_post_select(__a_unused struct sched *s, struct task *t) +static int session_post_select(__a_unused struct sched *s, struct play_task *pt) { - struct play_task *pt = container_of(t, struct play_task, task); int ret; if (pt->background) @@ -1107,9 +1118,8 @@ static int session_post_select(__a_unused struct sched *s, struct task *t) #else /* HAVE_READLINE */ -static int session_post_select(struct sched *s, struct task *t) +static int session_post_select(struct sched *s, struct play_task *pt) { - struct play_task *pt = container_of(t, struct play_task, task); char c; if (!FD_ISSET(STDIN_FILENO, &s->rfds)) @@ -1132,9 +1142,9 @@ static void session_update_time_string(__a_unused struct play_task *pt, } #endif /* HAVE_READLINE */ -static void play_pre_select(struct sched *s, struct task *t) +static void play_pre_select(struct sched *s, void *context) { - struct play_task *pt = container_of(t, struct play_task, task); + struct play_task *pt = context; char state; para_fd_set(STDIN_FILENO, &s->rfds, &s->max_fileno); @@ -1171,9 +1181,9 @@ static unsigned get_time_string(struct play_task *pt, char **result) ); } -static int play_post_select(struct sched *s, struct task *t) +static int play_post_select(struct sched *s, void *context) { - struct play_task *pt = container_of(t, struct play_task, task); + struct play_task *pt = context; int ret; ret = eof_cleanup(pt); @@ -1181,7 +1191,7 @@ static int play_post_select(struct sched *s, struct task *t) pt->rq = CRT_TERM_RQ; return 0; } - ret = session_post_select(s, t); + ret = session_post_select(s, pt); if (ret < 0) goto out; if (!pt->wn.btrn && !pt->fn.btrn) { @@ -1230,7 +1240,6 @@ int main(int argc, char *argv[]) filter_init(); writer_init(); - clock_get_realtime(now); sched.default_timeout.tv_sec = 5; parse_config_or_die(argc, argv); @@ -1245,11 +1254,14 @@ int main(int argc, char *argv[]) pt->rq = CRT_FILE_CHANGE; pt->current_file = conf.inputs_num - 1; pt->playing = true; - pt->task.pre_select = play_pre_select; - pt->task.post_select = play_post_select; - sprintf(pt->task.status, "play task"); - register_task(&sched, &pt->task); + pt->task = task_register(&(struct task_info){ + .name = "play", + .pre_select = play_pre_select, + .post_select = play_post_select, + .context = pt, + }, &sched); ret = schedule(&sched); + sched_shutdown(&sched); if (ret < 0) PARA_ERROR_LOG("%s\n", para_strerror(-ret)); return ret < 0? EXIT_FAILURE : EXIT_SUCCESS; diff --git a/playlist.c b/playlist.c index b83f8df8..4f5ed6d8 100644 --- a/playlist.c +++ b/playlist.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2007-2014 Andre Noll + * Copyright (C) 2007-2014 Andre Noll * * Licensed under the GPL v2. For licencing details see COPYING. */ diff --git a/portable_io.h b/portable_io.h index 7371038a..8231fe7b 100644 --- a/portable_io.h +++ b/portable_io.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2007-2014 Andre Noll + * Copyright (C) 2007-2014 Andre Noll * * Licensed under the GPL v2. For licencing details see COPYING. */ diff --git a/prebuffer_filter.c b/prebuffer_filter.c index 6fac4cb3..17a5b616 100644 --- a/prebuffer_filter.c +++ b/prebuffer_filter.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2009-2014 Andre Noll + * Copyright (C) 2009-2014 Andre Noll * * Licensed under the GPL v2. For licencing details see COPYING. */ @@ -28,9 +28,9 @@ struct private_prebuffer_data { struct timeval barrier; }; -static void prebuffer_pre_select(struct sched *s, struct task *t) +static void prebuffer_pre_select(struct sched *s, void *context) { - struct filter_node *fn = container_of(t, struct filter_node, task); + struct filter_node *fn = context; struct btr_node *btrn = fn->btrn; size_t iqs = btr_get_input_queue_size(btrn); struct private_prebuffer_data *ppd = fn->private_data; @@ -56,9 +56,9 @@ static void prebuffer_close(struct filter_node *fn) free(fn->private_data); } -static int prebuffer_post_select(__a_unused struct sched *s, struct task *t) +static int prebuffer_post_select(__a_unused struct sched *s, void *context) { - struct filter_node *fn = container_of(t, struct filter_node, task); + struct filter_node *fn = context; struct btr_node *btrn = fn->btrn; size_t iqs = btr_get_input_queue_size(btrn); struct private_prebuffer_data *ppd = fn->private_data; diff --git a/recv.c b/recv.c index babd1e30..b066a8e4 100644 --- a/recv.c +++ b/recv.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2005-2014 Andre Noll + * Copyright (C) 2005-2014 Andre Noll * * Licensed under the GPL v2. For licencing details see COPYING. */ @@ -63,8 +63,9 @@ int main(int argc, char *argv[]) int ret, r_opened = 0, receiver_num; struct receiver *r = NULL; struct receiver_node rn; - struct stdout_task sot; + struct stdout_task sot = {.btrn = NULL}; static struct sched s; + struct task_info ti; recv_cmdline_parser(argc, argv, &conf); loglevel = get_loglevel_by_name(conf.loglevel_arg); @@ -89,20 +90,20 @@ int main(int argc, char *argv[]) goto out; r_opened = 1; - memset(&sot, 0, sizeof(struct stdout_task)); sot.btrn = btr_new_node(&(struct btr_node_description) EMBRACE(.parent = rn.btrn, .name = "stdout")); - stdout_set_defaults(&sot); - register_task(&s, &sot.task); + stdout_task_register(&sot, &s); - rn.task.pre_select = r->pre_select; - rn.task.post_select = r->post_select; - sprintf(rn.task.status, "%s", r->name); - register_task(&s, &rn.task); + ti.name = r->name; + ti.pre_select = r->pre_select; + ti.post_select = r->post_select; + ti.context = &rn; + rn.task = task_register(&ti, &s); s.default_timeout.tv_sec = 1; s.default_timeout.tv_usec = 0; ret = schedule(&s); + sched_shutdown(&s); out: if (r_opened) r->close(&rn); diff --git a/recv.h b/recv.h index a590aabd..b17b77ab 100644 --- a/recv.h +++ b/recv.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2005-2014 Andre Noll + * Copyright (C) 2005-2014 Andre Noll * * Licensed under the GPL v2. For licencing details see COPYING. */ @@ -17,7 +17,7 @@ struct receiver_node { /** Pointer to the configuration data for this instance. */ void *conf; /** The task associated with this instance. */ - struct task task; + struct task *task; /** The receiver node is always the root of the buffer tree. */ struct btr_node *btrn; /** Each receiver node maintains a buffer pool for the received data. */ @@ -103,7 +103,7 @@ struct receiver { * * \sa select(2), time.c struct task, struct sched. */ - void (*pre_select)(struct sched *s, struct task *t); + void (*pre_select)(struct sched *s, void *context); /** * Evaluate the result from select(). * @@ -115,7 +115,7 @@ struct receiver { * * \sa select(2), struct receiver. */ - int (*post_select)(struct sched *s, struct task *t); + int (*post_select)(struct sched *s, void *context); /** The two help texts of this receiver. */ struct ggo_help help; @@ -142,7 +142,7 @@ struct receiver { void recv_init(void); void *check_receiver_arg(char *ra, int *receiver_num); void print_receiver_helps(unsigned flags); -int generic_recv_pre_select(struct sched *s, struct task *t); +int generic_recv_pre_select(struct sched *s, struct receiver_node *rn); /** \cond receiver */ extern void http_recv_init(struct receiver *r); diff --git a/recv_common.c b/recv_common.c index 2d6aa74a..02b785ff 100644 --- a/recv_common.c +++ b/recv_common.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2006-2014 Andre Noll + * Copyright (C) 2006-2014 Andre Noll * * Licensed under the GPL v2. For licencing details see COPYING. */ @@ -116,7 +116,7 @@ void print_receiver_helps(unsigned flags) * Simple pre-select hook, used by all receivers. * * \param s Scheduler info. - * \param t Determines the receiver node. + * \param rn The receiver node. * * This requests a minimal delay from the scheduler if the status of the buffer * tree node indicates an error/eof condition. No file descriptors are added to @@ -125,12 +125,10 @@ void print_receiver_helps(unsigned flags) * \return The status of the btr node of the receiver node, i.e. the return * value of the underlying call to \ref btr_node_status(). */ -int generic_recv_pre_select(struct sched *s, struct task *t) +int generic_recv_pre_select(struct sched *s, struct receiver_node *rn) { - struct receiver_node *rn = container_of(t, struct receiver_node, task); int ret = btr_node_status(rn->btrn, 0, BTR_NT_ROOT); - t->error = 0; if (ret < 0) sched_min_delay(s); return ret; diff --git a/resample_filter.c b/resample_filter.c index 2caa1e21..ef8a7011 100644 --- a/resample_filter.c +++ b/resample_filter.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2012-2014 Andre Noll + * Copyright (C) 2012-2014 Andre Noll * * Licensed under the GPL v2. For licencing details see COPYING. */ @@ -65,9 +65,9 @@ static void resample_open(struct filter_node *fn) btr_log_tree(btr_parent(btr_parent(btrn)), LL_INFO); } -static void resample_pre_select(struct sched *s, struct task *t) +static void resample_pre_select(struct sched *s, void *context) { - struct filter_node *fn = container_of(t, struct filter_node, task); + struct filter_node *fn = context; struct resample_context *ctx = fn->private_data; int ret = btr_node_status(fn->btrn, fn->min_iqs, BTR_NT_INTERNAL); @@ -202,10 +202,10 @@ static int resample_frames(int16_t *in, size_t num_frames, bool have_more, return data.input_frames_used; } -static int resample_post_select(__a_unused struct sched *s, struct task *t) +static int resample_post_select(__a_unused struct sched *s, void *context) { int ret; - struct filter_node *fn = container_of(t, struct filter_node, task); + struct filter_node *fn = context; struct resample_context *ctx = fn->private_data; struct resample_filter_args_info *conf = fn->conf; struct btr_node *btrn = fn->btrn; diff --git a/ringbuffer.c b/ringbuffer.c index e85661e4..2ea2592f 100644 --- a/ringbuffer.c +++ b/ringbuffer.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2006-2014 Andre Noll + * Copyright (C) 2006-2014 Andre Noll * * Licensed under the GPL v2. For licencing details see COPYING. */ diff --git a/ringbuffer.h b/ringbuffer.h index 075eb070..86b787be 100644 --- a/ringbuffer.h +++ b/ringbuffer.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2006-2014 Andre Noll + * Copyright (C) 2006-2014 Andre Noll * * Licensed under the GPL v2. For licencing details see COPYING. */ diff --git a/sched.c b/sched.c index 8b68667b..268ba541 100644 --- a/sched.c +++ b/sched.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2006-2014 Andre Noll + * Copyright (C) 2006-2014 Andre Noll * * Licensed under the GPL v2. For licencing details see COPYING. */ @@ -18,27 +18,38 @@ #include "time.h" #include "error.h" -static struct timeval now_struct; -struct timeval *now = &now_struct; - -/* - * Remove a task from the scheduler. - * - * \param t The task to remove. - * - * If the pre_select pointer of \a t is not \p NULL, it is removed from - * the pre_select list of the scheduler. Same goes for \a post_select. +/** + * The possible states of a task. + * + * In addition to the states listed here, a task may also enter zombie state. + * This happens when its ->post_select function returns negative, the ->status + * field is then set to this return value. Such tasks are not scheduled any + * more (i.e. ->pre_select() and ->post_select() are no longer called), but + * they stay on the scheduler task list until \ref task_reap() or + * \ref sched_shutdown() is called. */ -static void unregister_task(struct task *t) -{ - assert(t->error < 0); - PARA_INFO_LOG("unregistering %s (%s)\n", t->status, - para_strerror(-t->error)); - if (t->pre_select) - list_del(&t->pre_select_node); - if (t->post_select) - list_del(&t->post_select_node); -} +enum task_status { + /** Task has been reaped and may be removed from the task list. */ + TS_DEAD, + /** Task is active. */ + TS_RUNNING, +}; + +struct task { + /** A copy of the task name supplied when the task was registered. */ + char *name; + /** Copied during task_register(). */ + struct task_info info; + /* TS_RUNNING, TS_DEAD, or zombie (negative value). */ + int status; + /** Position of the task in the task list of the scheduler. */ + struct list_head node; + /** If less than zero, the task was notified by another task. */ + int notification; +}; + +static struct timeval now_struct; +const struct timeval *now = &now_struct; static inline bool timeout_is_zero(struct sched *s) { @@ -50,51 +61,67 @@ static void sched_preselect(struct sched *s) { struct task *t, *tmp; - list_for_each_entry_safe(t, tmp, &s->pre_select_list, pre_select_node) { + list_for_each_entry_safe(t, tmp, &s->task_list, node) { + if (t->status < 0) + continue; if (t->notification != 0) sched_min_delay(s); - if (t->pre_select) - t->pre_select(s, t); + if (t->info.pre_select) + t->info.pre_select(s, t->info.context); } } +static void unlink_and_free_task(struct task *t) +{ + PARA_INFO_LOG("freeing task %s\n", t->name); + list_del(&t->node); + free(t->name); + free(t); +} + //#define SCHED_DEBUG 1 static inline void call_post_select(struct sched *s, struct task *t) { + int ret; + #ifndef SCHED_DEBUG - t->error = t->post_select(s, t); + ret = t->info.post_select(s, t->info.context); #else struct timeval t1, t2, diff; unsigned long pst; clock_get_realtime(&t1); - t->error = t->post_select(s, t); + ret = t->info.post_select(s, t->info.context); clock_get_realtime(&t2); tv_diff(&t1, &t2, &diff); pst = tv2ms(&diff); if (pst > 50) PARA_WARNING_LOG("%s: post_select time: %lums\n", - t->status, pst); + t->name, pst); #endif + t->status = ret < 0? ret : TS_RUNNING; } -static void sched_post_select(struct sched *s) +static unsigned sched_post_select(struct sched *s) { struct task *t, *tmp; + unsigned num_running_tasks = 0; - list_for_each_entry_safe(t, tmp, &s->post_select_list, post_select_node) { - if (t->error >= 0) - call_post_select(s, t); -// PARA_INFO_LOG("%s: %d\n", t->status, t->ret); - t->notification = 0; - if (t->error >= 0) - continue; - unregister_task(t); + list_for_each_entry_safe(t, tmp, &s->task_list, node) { + if (t->status == TS_DEAD) /* task has been reaped */ + unlink_and_free_task(t); + else if (t->status == TS_RUNNING) { + call_post_select(s, t); /* sets t->status */ + t->notification = 0; + if (t->status == TS_RUNNING) + num_running_tasks++; + } } + return num_running_tasks; } /** - * The core function for all paraslash programs. + * The core function of all paraslash programs. * * \param s Pointer to the scheduler struct. * @@ -103,14 +130,15 @@ static void sched_post_select(struct sched *s) * the fd sets of \a s. Next, it calls para_select() and makes the result available * to the registered tasks by calling their post_select hook. * - * \return Zero if no more tasks are left in either of the two lists, negative - * if para_select returned an error. + * \return Zero if no more tasks are left in the task list, negative if the + * select function returned an error. * - * \sa task, now. + * \sa \ref now. */ int schedule(struct sched *s) { int ret; + unsigned num_running_tasks; if (!s->select_function) s->select_function = para_select; @@ -119,7 +147,7 @@ again: FD_ZERO(&s->wfds); s->select_timeout = s->default_timeout; s->max_fileno = -1; - clock_get_realtime(now); + clock_get_realtime(&now_struct); sched_preselect(s); ret = s->select_function(s->max_fileno + 1, &s->rfds, &s->wfds, &s->select_timeout); @@ -135,42 +163,105 @@ again: FD_ZERO(&s->rfds); FD_ZERO(&s->wfds); } - clock_get_realtime(now); - sched_post_select(s); - if (list_empty(&s->pre_select_list) && list_empty(&s->post_select_list)) + clock_get_realtime(&now_struct); + num_running_tasks = sched_post_select(s); + if (num_running_tasks == 0) return 0; goto again; } /** - * Add a task to the scheduler. + * Obtain the error status of a task and deallocate its resources. * - * \param t The task to add. - * \param s The scheduler instance to add the task to. + * \param tptr Identifies the task to reap. * - * If the pre_select pointer of \a t is not \p NULL, it is added to - * the pre_select list of the scheduler. Same goes for post_select. + * This function is similar to wait(2) in that it returns information about a + * terminated task and allows to release the resources associated with the + * task. Until this function is called, the terminated task remains in a zombie + * state. * - * \sa task::pre_select, task::post_select + * \return If \a tptr is \p NULL, or \a *tptr is \p NULL, the function does + * nothing and returns zero. Otherwise, it is checked whether the task + * identified by \a tptr is still running. If it is, the function returns zero + * and again, no action is taken. Otherwise the (negative) error code of the + * terminated task is returned and \a *tptr is set to \p NULL. The task will + * then be removed removed from the scheduler task list. + * + * \sa \ref sched_shutdown(), wait(2). */ -void register_task(struct sched *s, struct task *t) +int task_reap(struct task **tptr) { - PARA_INFO_LOG("registering %s (%p)\n", t->status, t); - t->notification = 0; - if (!s->pre_select_list.next) - INIT_LIST_HEAD(&s->pre_select_list); - if (!s->post_select_list.next) - INIT_LIST_HEAD(&s->post_select_list); - if (t->pre_select) { - PARA_DEBUG_LOG("pre_select: %p\n", &t->pre_select); - list_add_tail(&t->pre_select_node, &s->pre_select_list); - } - if (t->post_select) { - PARA_DEBUG_LOG("post_select: %p\n", &t->post_select); - list_add_tail(&t->post_select_node, &s->post_select_list); + struct task *t; + int ret; + + if (!tptr) + return 0; + t = *tptr; + if (!t) + return 0; + if (t->status >= 0) + return 0; + ret = t->status; + /* + * With list_for_each_entry_safe() it is only safe to remove the + * _current_ list item. Since we are being called from the loop in + * schedule() via some task's ->post_select() function, freeing the + * given task here would result in use-after-free bugs in schedule(). + * So we only set the task status to TS_DEAD which tells schedule() to + * free the task in the next iteration of its loop. + */ + t->status = TS_DEAD; + + *tptr = NULL; + return ret; +} + +/** + * Deallocate all resources of all tasks of a scheduler instance. + * + * \param s The scheduler instance. + * + * This should only be called after \ref schedule() has returned. + */ +void sched_shutdown(struct sched *s) +{ + struct task *t, *tmp; + + list_for_each_entry_safe(t, tmp, &s->task_list, node) { + if (t->status == TS_RUNNING) + /* The task list should contain only terminated tasks. */ + PARA_WARNING_LOG("shutting down running task %s\n", + t->name); + unlink_and_free_task(t); } } +/** + * Add a task to the scheduler task list. + * + * \param info Task information supplied by the caller. + * \param s The scheduler instance. + * + * \return A pointer to a newly allocated task structure. It will be + * freed by sched_shutdown(). + */ +struct task *task_register(struct task_info *info, struct sched *s) +{ + struct task *t = para_malloc(sizeof(*t)); + + assert(info->post_select); + + if (!s->task_list.next) + INIT_LIST_HEAD(&s->task_list); + + t->info = *info; + t->name = para_strdup(info->name); + t->notification = 0; + t->status = TS_RUNNING; + list_add_tail(&t->node, &s->task_list); + return t; +} + /** * Get the list of all registered tasks. * @@ -186,21 +277,15 @@ char *get_task_list(struct sched *s) struct task *t, *tmp; char *msg = NULL; - list_for_each_entry_safe(t, tmp, &s->pre_select_list, pre_select_node) { - char *tmp_msg; - tmp_msg = make_message("%s%p\tpre\t%s\n", msg? msg : "", t, t->status); - free(msg); - msg = tmp_msg; - } - list_for_each_entry_safe(t, tmp, &s->post_select_list, post_select_node) { + list_for_each_entry_safe(t, tmp, &s->task_list, node) { char *tmp_msg; -// if (t->pre_select) -// continue; - tmp_msg = make_message("%s%p\tpost\t%s\n", msg? msg : "", t, t->status); + tmp_msg = make_message("%s%p\t%s\t%s\n", msg? msg : "", t, + t->status == TS_DEAD? "dead" : + (t->status == TS_RUNNING? "running" : "zombie"), + t->name); free(msg); msg = tmp_msg; } - //PARA_DEBUG_LOG("task list:\n%s", msg); return msg; } @@ -228,7 +313,7 @@ void task_notify(struct task *t, int err) assert(err > 0); if (t->notification == -err) /* ignore subsequent notifications */ return; - PARA_INFO_LOG("notifying task %s: %s\n", t->status, para_strerror(err)); + PARA_INFO_LOG("notifying task %s: %s\n", t->name, para_strerror(err)); t->notification = -err; } @@ -243,11 +328,30 @@ void task_notify(struct task *t, int err) * * \sa \ref task_notify(). */ -int task_get_notification(struct task *t) +int task_get_notification(const struct task *t) { return t->notification; } +/** + * Return the status value of a task. + * + * \param t The task to get the status value from. + * + * \return Zero if task does not exist, one if task is running, negative error + * code if task has terminated. + */ +int task_status(const struct task *t) +{ + if (!t) + return 0; + if (t->status == TS_DEAD) /* pretend dead tasks don't exist */ + return 0; + if (t->status == TS_RUNNING) + return 1; + return t->status; +} + /** * Set the notification value of all tasks of a scheduler instance. * @@ -261,9 +365,7 @@ void task_notify_all(struct sched *s, int err) { struct task *t; - list_for_each_entry(t, &s->pre_select_list, pre_select_node) - task_notify(t, err); - list_for_each_entry(t, &s->post_select_list, post_select_node) + list_for_each_entry(t, &s->task_list, node) task_notify(t, err); } diff --git a/sched.h b/sched.h index f15e4efb..d7b90a45 100644 --- a/sched.h +++ b/sched.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2006-2014 Andre Noll + * Copyright (C) 2006-2014 Andre Noll * * Licensed under the GPL v2. For licencing details see COPYING. */ @@ -10,11 +10,11 @@ /** * Paraslash's scheduler. * - * Designed with KISS in mind. It manages two lists of tasks. The pre_select - * list contains pointers to functions that are called before calling select() - * from the main loop. Similarly, \a post_select_list is a list of function - * pointers each of which is called after the select call. Tasks add hooks to - * these lists by registering themselves to the scheduler. + * Designed with KISS in mind. It maintains a list of task structures which is + * extended when a new task is registered. Each task may define a pre_select + * function which is called from the scheduler main loop before it calls + * select(). Similarly, each task must define a post_select function which is + * called after the select call. */ struct sched { /** Initial value before any pre_select call. */ @@ -29,46 +29,37 @@ struct sched { int max_fileno; /** If non-NULL, use this function instead of para_select. */ int (*select_function)(int, fd_set *, fd_set *, struct timeval *); - /** Currently active pre_select functions. */ - struct list_head pre_select_list; - /** Currently active post_select functions. */ - struct list_head post_select_list; + /** Tasks which have been registered to the scheduler. */ + struct list_head task_list; }; -/** - * Paraslash's task structure. - * - * Before registering a task to the scheduler, the task structure must be - * filled in properly by the caller. - * - * \sa \ref sched. - */ -struct task { +struct task; + +/** Information that must be supplied by callers of \ref task_register(). */ +struct task_info { + /** Used for log messages and by \ref get_task_list(). */ + const char *name; /** - * The pre select hook of \a t. + * The optional pre select method. * * Its purpose is to add file descriptors to the fd sets of the * scheduler and to decrease the select timeout if necessary. */ - void (*pre_select)(struct sched *s, struct task *t); + void (*pre_select)(struct sched *s, void *context); /** - * The post select hook of \a t. + * The mandatory post select method. * * Its purpose is to evaluate and act upon the results of the previous * select call. If this function returns a negative value, the * scheduler unregisters the task. */ - int (*post_select)(struct sched *s, struct task *t); - /** Whether this task is in error state. */ - int error; - /** Position of the task in the pre_select list of the scheduler. */ - struct list_head pre_select_node; - /** Position of the task in the post_select list of the scheduler. */ - struct list_head post_select_node; - /** Descriptive text and current status of the task. */ - char status[255]; - /** If less than zero, the task was notified by another task. */ - int notification; + int (*post_select)(struct sched *s, void *context); + /** + * This pointer is saved when the task is registered. It is passed to + * ->pre_select() and ->post_select(). Usually this is a pointer to the + * struct owned by the caller which contains the task pointer. + */ + void *context; }; /** @@ -77,14 +68,17 @@ struct task { * scheduler are allowed to block, this value should be accurate enough so that * there is no need to call clock_gettime() directly. */ -extern struct timeval *now; +extern const struct timeval *now; -void register_task(struct sched *s, struct task *t); +struct task *task_register(struct task_info *info, struct sched *s); int schedule(struct sched *s); +void sched_shutdown(struct sched *s); char *get_task_list(struct sched *s); void task_notify(struct task *t, int err); void task_notify_all(struct sched *s, int err); -int task_get_notification(struct task *t); +int task_get_notification(const struct task *t); +int task_status(const struct task *t); +int task_reap(struct task **tptr); void sched_min_delay(struct sched *s); void sched_request_timeout(struct timeval *to, struct sched *s); void sched_request_timeout_ms(long unsigned ms, struct sched *s); diff --git a/score.c b/score.c index f1afd22b..53e55dae 100644 --- a/score.c +++ b/score.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2007-2014 Andre Noll + * Copyright (C) 2007-2014 Andre Noll * * Licensed under the GPL v2. For licencing details see COPYING. */ diff --git a/send.h b/send.h index 8a69cb71..e3f76caf 100644 --- a/send.h +++ b/send.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2005-2014 Andre Noll + * Copyright (C) 2005-2014 Andre Noll * * Licensed under the GPL v2. For licencing details see COPYING. */ diff --git a/send_common.c b/send_common.c index 0baac3a6..3f29fe81 100644 --- a/send_common.c +++ b/send_common.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2005-2014 Andre Noll + * Copyright (C) 2005-2014 Andre Noll * * Licensed under the GPL v2. For licencing details see COPYING. */ diff --git a/server.c b/server.c index fa19ce42..b5063e2d 100644 --- a/server.c +++ b/server.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 1997-2014 Andre Noll + * Copyright (C) 1997-2014 Andre Noll * * Licensed under the GPL v2. For licencing details see COPYING. */ @@ -110,7 +110,7 @@ struct server_command_task { /** Argument vector passed to para_server's main function. */ char **argv; /** The command task structure for scheduling. */ - struct task task; + struct task *task; }; static int want_colors(void) @@ -235,9 +235,9 @@ out: exit(EXIT_FAILURE); } -static void signal_pre_select(struct sched *s, struct task *t) +static void signal_pre_select(struct sched *s, void *context) { - struct signal_task *st = container_of(t, struct signal_task, task); + struct signal_task *st = context; para_fd_set(st->fd, &s->rfds, &s->max_fileno); } @@ -253,7 +253,7 @@ static void handle_sighup(void) kill(mmd->afs_pid, SIGHUP); } -static int signal_post_select(struct sched *s, __a_unused struct task *t) +static int signal_post_select(struct sched *s, __a_unused void *context) { int signum = para_next_signal(&s->rfds); @@ -312,10 +312,6 @@ static void init_signal_task(void) static struct signal_task signal_task_struct, *st = &signal_task_struct; - st->task.pre_select = signal_pre_select; - st->task.post_select = signal_post_select; - sprintf(st->task.status, "signal task"); - PARA_NOTICE_LOG("setting up signal handling\n"); st->fd = para_signal_init(); /* always successful */ para_install_sighandler(SIGINT); @@ -324,18 +320,24 @@ static void init_signal_task(void) para_install_sighandler(SIGCHLD); para_sigaction(SIGPIPE, SIG_IGN); add_close_on_fork_list(st->fd); - register_task(&sched, &st->task); + st->task = task_register(&(struct task_info) { + .name = "signal", + .pre_select = signal_pre_select, + .post_select = signal_post_select, + .context = st, + + }, &sched); } -static void command_pre_select(struct sched *s, struct task *t) +static void command_pre_select(struct sched *s, void *context) { - struct server_command_task *sct = container_of(t, struct server_command_task, task); + struct server_command_task *sct = context; para_fd_set(sct->listen_fd, &s->rfds, &s->max_fileno); } -static int command_post_select(struct sched *s, struct task *t) +static int command_post_select(struct sched *s, void *context) { - struct server_command_task *sct = container_of(t, struct server_command_task, task); + struct server_command_task *sct = context; int new_fd, ret, i; char *peer_name; @@ -399,8 +401,6 @@ static void init_server_command_task(int argc, char **argv) *sct = &server_command_task_struct; PARA_NOTICE_LOG("initializing tcp command socket\n"); - sct->task.pre_select = command_pre_select; - sct->task.post_select = command_post_select; sct->argc = argc; sct->argv = argv; ret = para_listen_simple(IPPROTO_TCP, conf.port_arg); @@ -411,8 +411,12 @@ static void init_server_command_task(int argc, char **argv) if (ret < 0) goto err; add_close_on_fork_list(sct->listen_fd); /* child doesn't need the listener */ - sprintf(sct->task.status, "server command task"); - register_task(&sched, &sct->task); + sct->task = task_register(&(struct task_info) { + .name = "server command", + .pre_select = command_pre_select, + .post_select = command_post_select, + .context = sct, + }, &sched); return; err: PARA_EMERG_LOG("%s\n", para_strerror(-ret)); @@ -479,14 +483,12 @@ static void server_init(int argc, char **argv) version_handle_flag("server", conf.version_given); if (conf.help_given || conf.detailed_help_given) print_help_and_die(); - drop_privileges_or_die(conf.user_arg, conf.group_arg); + daemon_drop_privileges_or_die(conf.user_arg, conf.group_arg); /* parse config file, open log and set defaults */ parse_config_or_die(0); - log_welcome("para_server"); + daemon_log_welcome("para_server"); init_ipc_or_die(); /* init mmd struct and mmd->lock */ - /* make sure, the global now pointer is uptodate */ - clock_get_realtime(now); - set_server_start_time(now); + daemon_set_start_time(); init_user_list(user_list_file); /* become daemon */ if (conf.daemon_given) @@ -524,7 +526,7 @@ static void server_init(int argc, char **argv) static void status_refresh(void) { static int prev_uptime = -1, prev_events = -1; - int uptime = get_server_uptime(now); + int uptime = daemon_get_uptime(now); if (prev_events != mmd->events) goto out; @@ -573,6 +575,7 @@ int main(int argc, char *argv[]) server_init(argc, argv); mutex_lock(mmd_mutex); ret = schedule(&sched); + sched_shutdown(&sched); if (ret < 0) { PARA_EMERG_LOG("%s\n", para_strerror(-ret)); exit(EXIT_FAILURE); diff --git a/server.h b/server.h index 64f0cc75..16449e6d 100644 --- a/server.h +++ b/server.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 1997-2014 Andre Noll + * Copyright (C) 1997-2014 Andre Noll * * Licensed under the GPL v2. For licencing details see COPYING. */ diff --git a/sideband.c b/sideband.c index a5f19161..3862d7ac 100644 --- a/sideband.c +++ b/sideband.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2012-2014 Andre Noll + * Copyright (C) 2012-2014 Andre Noll * * Licensed under the GPL v2. For licencing details see COPYING. */ diff --git a/sideband.h b/sideband.h index 4a838cee..2176cf48 100644 --- a/sideband.h +++ b/sideband.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2012-2014 Andre Noll + * Copyright (C) 2012-2014 Andre Noll * * Licensed under the GPL v2. For licencing details see COPYING. */ diff --git a/signal.c b/signal.c index 972d9d12..68db5df7 100644 --- a/signal.c +++ b/signal.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2004-2014 Andre Noll + * Copyright (C) 2004-2014 Andre Noll * * Licensed under the GPL v2. For licencing details see COPYING. */ diff --git a/signal.h b/signal.h index 526f1502..256f1067 100644 --- a/signal.h +++ b/signal.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2007-2014 Andre Noll + * Copyright (C) 2007-2014 Andre Noll * * Licensed under the GPL v2. For licencing details see COPYING. */ @@ -13,7 +13,7 @@ struct signal_task { /** The signal pipe. */ int fd; /** The associated task structure. */ - struct task task; + struct task *task; }; int para_signal_init(void); diff --git a/spx.h b/spx.h index 3ae2c87c..6c193b49 100644 --- a/spx.h +++ b/spx.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2010-2014 Andre Noll + * Copyright (C) 2010-2014 Andre Noll * * Licensed under the GPL v2. For licencing details see COPYING. */ diff --git a/spx_afh.c b/spx_afh.c index 2afebb18..c6f6a773 100644 --- a/spx_afh.c +++ b/spx_afh.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2010-2014 Andre Noll + * Copyright (C) 2010-2014 Andre Noll * * Licensed under the GPL v2. For licencing details see COPYING. */ diff --git a/spx_common.c b/spx_common.c index f770be7d..6ceeaaec 100644 --- a/spx_common.c +++ b/spx_common.c @@ -1,6 +1,6 @@ /* * Copyright (C) 2002-2006 Jean-Marc Valin - * Copyright (C) 2010-2014 Andre Noll + * Copyright (C) 2010-2014 Andre Noll * * Licensed under the GPL v2. For licencing details see COPYING. */ diff --git a/spxdec_filter.c b/spxdec_filter.c index 72ecd62a..4c7a773b 100644 --- a/spxdec_filter.c +++ b/spxdec_filter.c @@ -1,6 +1,6 @@ /* * Copyright (C) 2002-2006 Jean-Marc Valin - * Copyright (C) 2010-2014 Andre Noll + * Copyright (C) 2010-2014 Andre Noll * * Licensed under the GPL v2. For licencing details see COPYING. */ @@ -238,9 +238,9 @@ static int compute_skip_samples(ogg_page *og, struct private_spxdec_data *psd) return ret; } -static int speexdec_post_select(__a_unused struct sched *s, struct task *t) +static int speexdec_post_select(__a_unused struct sched *s, void *context) { - struct filter_node *fn = container_of(t, struct filter_node, task); + struct filter_node *fn = context; struct private_spxdec_data *psd = fn->private_data; struct btr_node *btrn = fn->btrn; int ret, ns; diff --git a/stat.c b/stat.c index afc9c389..652a749d 100644 --- a/stat.c +++ b/stat.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2005-2014 Andre Noll + * Copyright (C) 2005-2014 Andre Noll * * Licensed under the GPL v2. For licencing details see COPYING. */ diff --git a/stdin.c b/stdin.c index d5425b28..a4e81bd3 100644 --- a/stdin.c +++ b/stdin.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2006-2014 Andre Noll + * Copyright (C) 2006-2014 Andre Noll * * Licensed under the GPL v2. For licencing details see COPYING. */ @@ -18,19 +18,13 @@ #include "buffer_tree.h" #include "string.h" -/** - * The pre_select function of the stdin task. - * - * \param s The scheduler this task was registered to. - * \param t The task structure of the stdin task. - * - * This function is always successful. If there is space left in the - * buffer of the stdin task, it adds \p STDIN_FILENO to the read fd set - * of \a s. +/* + * If there is space left in the buffer of the stdin task add STDIN_FILENO to + * the read fd set of s. */ -static void stdin_pre_select(struct sched *s, struct task *t) +static void stdin_pre_select(struct sched *s, void *context) { - struct stdin_task *sit = container_of(t, struct stdin_task, task); + struct stdin_task *sit = context; int ret; ret = btr_node_status(sit->btrn, 0, BTR_NT_ROOT); @@ -43,20 +37,14 @@ static void stdin_pre_select(struct sched *s, struct task *t) sched_request_timeout_ms(100, s); } -/** - * The post select function of the stdin task. - * - * \param s The scheduler this task was registered to. - * \param t The task structure of the stdin task. - * - * This function checks if \p STDIN_FILENO was included by in the read fd set - * of \a s during the previous pre_select call. If yes, and \p STDIN_FILENO - * appears to be readable, data is read from stdin and fed into the buffer - * tree. +/* + * This function checks if STDIN_FILENO was included by in the read fd set of s + * during the previous pre_select call. If so, and if STDIN_FILENO is readable, + * data is read from stdin and fed into the buffer tree. */ -static int stdin_post_select(struct sched *s, struct task *t) +static int stdin_post_select(struct sched *s, void *context) { - struct stdin_task *sit = container_of(t, struct stdin_task, task); + struct stdin_task *sit = context; ssize_t ret; size_t sz, n; char *buf = NULL; @@ -95,21 +83,25 @@ err: } /** - * Initialize a stdin task structure with default values. + * Register a stdin task structure. * - * \param sit The stdin task structure. + * \param sit The stdin task structure to register. + * \param s The task will be added to this scheduler's task list. * - * This fills in the pre/post select function pointers of the task structure - * given by \a sit and creates a buffer tree for I/O. + * This allocates a buffer tree pool for I/O, sets up \a sit and registers a + * task with \a sit as context pointer. */ -void stdin_set_defaults(struct stdin_task *sit) +void stdin_task_register(struct stdin_task *sit, struct sched *s) { int ret; + struct task_info ti = { + .name = "stdin", + .pre_select = stdin_pre_select, + .post_select = stdin_post_select, + .context = sit, + }; - sit->task.pre_select = stdin_pre_select; - sit->task.post_select = stdin_post_select; sit->btrp = btr_pool_new("stdin", 128 * 1024); - sprintf(sit->task.status, "stdin reader"); /* * Both STDIN_FILENO and STDOUT_FILENO may refer to the same open file * description (the terminal), and thus share the same file status @@ -124,4 +116,5 @@ void stdin_set_defaults(struct stdin_task *sit) } sit->fd_flags = ret; sit->must_set_nonblock_flag = (sit->fd_flags & O_NONBLOCK) == 0; + sit->task = task_register(&ti, s); } diff --git a/stdin.h b/stdin.h index 22ea7ed6..952d4809 100644 --- a/stdin.h +++ b/stdin.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2006-2014 Andre Noll + * Copyright (C) 2006-2014 Andre Noll * * Licensed under the GPL v2. For licencing details see COPYING. */ @@ -9,7 +9,7 @@ /** The task structure used for reading from stdin. */ struct stdin_task { /** The task structure. */ - struct task 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. */ @@ -20,4 +20,4 @@ struct stdin_task { bool must_set_nonblock_flag; }; -void stdin_set_defaults(struct stdin_task *sit); +void stdin_task_register(struct stdin_task *sit, struct sched *s); diff --git a/stdout.c b/stdout.c index 4554145f..5fae20c2 100644 --- a/stdout.c +++ b/stdout.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2006-2014 Andre Noll + * Copyright (C) 2006-2014 Andre Noll * * Licensed under the GPL v2. For licencing details see COPYING. */ @@ -16,18 +16,10 @@ #include "stdout.h" #include "buffer_tree.h" -/** - * The pre_select function of the stdout task. - * - * \param s The scheduler this task was registered to. - * \param t The task structure of the stdout task. - * - * This function is always successful. If there is input data available, it - * adds \p STDOUT_FILENO to the write fd set of \a s. - */ -static void stdout_pre_select(struct sched *s, struct task *t) +/* Add STDOUT_FILENO to the write fd set if there is input data available. */ +static void stdout_pre_select(struct sched *s, void *context) { - struct stdout_task *sot = container_of(t, struct stdout_task, task); + struct stdout_task *sot = context; int ret; ret = btr_node_status(sot->btrn, 0, BTR_NT_LEAF); @@ -37,18 +29,13 @@ static void stdout_pre_select(struct sched *s, struct task *t) sched_min_delay(s); } -/** - * The post select function of the stdout task. - * - * \param s The scheduler this task was registered to. - * \param t The task structure of the stdout task. - * - * This function writes input data from the buffer tree to stdout if \p +/* + * This function writes input data from the buffer tree to stdout if * STDOUT_FILENO is writable. */ -static int stdout_post_select(struct sched *s, struct task *t) +static int stdout_post_select(struct sched *s, void *context) { - struct stdout_task *sot = container_of(t, struct stdout_task, task); + struct stdout_task *sot = context; struct btr_node *btrn = sot->btrn; int ret; char *buf; @@ -85,21 +72,24 @@ out: } return ret; } + /** - * Initialize a stdout task structure with default values. + * Register a stdout task structure. * - * \param sot The stdout task structure. + * \param sot The stdout task structure to register. + * \param s The task will be added to this scheduler's task list. * - * This fills in the pre/post select function pointers of the task structure - * given by \a sot. + * This sets up \a sot and registers a task with \a sot as context pointer. */ -void stdout_set_defaults(struct stdout_task *sot) +void stdout_task_register(struct stdout_task *sot, struct sched *s) { int ret; - - sot->task.pre_select = stdout_pre_select; - sot->task.post_select = stdout_post_select; - sprintf(sot->task.status, "stdout"); + struct task_info ti = { + .pre_select = stdout_pre_select, + .post_select = stdout_post_select, + .context = sot, + .name = "stdout", + }; /* See stdin.c for details. */ ret = fcntl(STDOUT_FILENO, F_GETFL); @@ -109,4 +99,5 @@ void stdout_set_defaults(struct stdout_task *sot) } sot->fd_flags = ret; sot->must_set_nonblock_flag = (sot->fd_flags & O_NONBLOCK) == 0; + sot->task = task_register(&ti, s); } diff --git a/stdout.h b/stdout.h index dbf8866b..57cf969d 100644 --- a/stdout.h +++ b/stdout.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2006-2014 Andre Noll + * Copyright (C) 2006-2014 Andre Noll * * Licensed under the GPL v2. For licencing details see COPYING. */ @@ -13,7 +13,7 @@ */ struct stdout_task { /** The task structure used by the scheduler. */ - struct task task; + struct task *task; /** Stdout is always a leaf node in the buffer tree. */ struct btr_node *btrn; /** The descriptor flags of STDOUT at startup. */ @@ -22,4 +22,4 @@ struct stdout_task { bool must_set_nonblock_flag; }; -void stdout_set_defaults(struct stdout_task *sot); +void stdout_task_register(struct stdout_task *sot, struct sched *s); diff --git a/string.c b/string.c index 8cc7d5d7..39d16c3a 100644 --- a/string.c +++ b/string.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2004-2014 Andre Noll + * Copyright (C) 2004-2014 Andre Noll * * Licensed under the GPL v2. For licencing details see COPYING. */ @@ -298,24 +298,6 @@ __must_check char *para_basename(const char *name) return ret; } -/** - * Cut trailing newline. - * - * \param buf The string to be chopped. - * - * Replace the last character in \p buf by zero if it is equal to - * the newline character. - */ -void chop(char *buf) -{ - int n = strlen(buf); - - if (!n) - return; - if (buf[n - 1] == '\n') - buf[n - 1] = '\0'; -} - /** * Get the logname of the current user. * diff --git a/string.h b/string.h index b13a0d86..20cf8def 100644 --- a/string.h +++ b/string.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2006-2014 Andre Noll + * Copyright (C) 2006-2014 Andre Noll * * Licensed under the GPL v2. For licencing details see COPYING. */ @@ -84,7 +84,6 @@ __must_check __malloc __printf_1_2 char *make_message(const char *fmt, ...); __must_check __malloc char *para_strcat(char *a, const char *b); __must_check __malloc char *para_dirname(const char *name); __must_check char *para_basename(const char *name); -void chop(char *buf); __must_check __malloc char *para_logname(void); __must_check __malloc char *para_homedir(void); __malloc char *para_hostname(void); diff --git a/sync_filter.c b/sync_filter.c index 379b54b1..8c3570fd 100644 --- a/sync_filter.c +++ b/sync_filter.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2013 Andre Noll + * Copyright (C) 2013 Andre Noll * * Licensed under the GPL v2. For licencing details see COPYING. */ @@ -258,10 +258,10 @@ static void sync_set_timeout(struct sync_filter_context *ctx, tv_add(now, &to, &ctx->timeout); } -static void sync_pre_select(struct sched *s, struct task *t) +static void sync_pre_select(struct sched *s, void *context) { int ret; - struct filter_node *fn = container_of(t, struct filter_node, task); + struct filter_node *fn = context; struct sync_filter_context *ctx = fn->private_data; struct sync_filter_config *sfc = fn->conf; @@ -295,10 +295,10 @@ static struct sync_buddy *sync_find_buddy(struct sockaddr *addr, return NULL; } -static int sync_post_select(__a_unused struct sched *s, struct task *t) +static int sync_post_select(__a_unused struct sched *s, void *context) { int ret; - struct filter_node *fn = container_of(t, struct filter_node, task); + struct filter_node *fn = context; struct sync_filter_context *ctx = fn->private_data; struct sync_filter_config *sfc = fn->conf; struct sync_buddy *buddy, *tmp; diff --git a/time.c b/time.c index c405351a..040053d2 100644 --- a/time.c +++ b/time.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2005-2014 Andre Noll + * Copyright (C) 2005-2014 Andre Noll * * Licensed under the GPL v2. For licencing details see COPYING. */ diff --git a/udp_recv.c b/udp_recv.c index 15cf73eb..bb4eb1db 100644 --- a/udp_recv.c +++ b/udp_recv.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2005-2014 Andre Noll + * Copyright (C) 2005-2014 Andre Noll * * Licensed under the GPL v2. For licencing details see COPYING. */ @@ -27,11 +27,11 @@ #include "net.h" #include "fd.h" -static void udp_recv_pre_select(struct sched *s, struct task *t) +static void udp_recv_pre_select(struct sched *s, void *context) { - struct receiver_node *rn = container_of(t, struct receiver_node, task); + struct receiver_node *rn = context; - if (generic_recv_pre_select(s, t) <= 0) + if (generic_recv_pre_select(s, rn) <= 0) return; para_fd_set(rn->fd, &s->rfds, &s->max_fileno); } @@ -54,15 +54,15 @@ static int udp_check_eof(size_t sz, struct iovec iov[2]) return -E_RECV_EOF; } -static int udp_recv_post_select(__a_unused struct sched *s, struct task *t) +static int udp_recv_post_select(__a_unused struct sched *s, void *context) { - struct receiver_node *rn = container_of(t, struct receiver_node, task); + struct receiver_node *rn = context; struct btr_node *btrn = rn->btrn; size_t num_bytes; struct iovec iov[2]; int ret, readv_ret, iovcnt; - ret = task_get_notification(t); + ret = task_get_notification(rn->task); if (ret < 0) goto out; ret = btr_node_status(btrn, 0, BTR_NT_ROOT); diff --git a/udp_send.c b/udp_send.c index 6ed5026a..96f12ff0 100644 --- a/udp_send.c +++ b/udp_send.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2005-2014 Andre Noll + * Copyright (C) 2005-2014 Andre Noll * * Licensed under the GPL v2. For licencing details see COPYING. */ diff --git a/user_list.c b/user_list.c index 4815e5d3..057ca6f8 100644 --- a/user_list.c +++ b/user_list.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2006-2014 Andre Noll + * Copyright (C) 2006-2014 Andre Noll * * Licensed under the GPL v2. For licencing details see COPYING. */ diff --git a/user_list.h b/user_list.h index 120b0fdb..568c643e 100644 --- a/user_list.h +++ b/user_list.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2006-2014 Andre Noll + * Copyright (C) 2006-2014 Andre Noll * * Licensed under the GPL v2. For licencing details see COPYING. */ diff --git a/version.c b/version.c index 3a190e63..151974e5 100644 --- a/version.c +++ b/version.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2013-2014 Andre Noll + * Copyright (C) 2013-2014 Andre Noll * * Licensed under the GPL v2. For licencing details see COPYING. */ @@ -8,9 +8,6 @@ #include "para.h" #include "version.h" - -/** \file version.h Macros for printing the version string. */ - #include "git-version.h" /** @@ -60,7 +57,7 @@ const char *version_text(const char *pfx) "Copyright (C) 2014 Andre Noll\n" "This is free software with ABSOLUTELY NO WARRANTY." " See COPYING for details.\n" - "Report bugs to .\n" + "Report bugs to .\n" "build date: " BUILD_DATE ",\n" "build system: " UNAME_RS ",\n" "compiler: " CC_VERSION ".\n", diff --git a/vss.c b/vss.c index 3ace49e9..8a916a2d 100644 --- a/vss.c +++ b/vss.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 1997-2014 Andre Noll + * Copyright (C) 1997-2014 Andre Noll * * Licensed under the GPL v2. For licencing details see COPYING. */ @@ -89,7 +89,7 @@ struct vss_task { /** The memory mapped audio file. */ char *map; /** Used by the scheduler. */ - struct task task; + struct task *task; /** Pointer to the header of the mapped audio file. */ char *header_buf; /** Length of the audio file header. */ @@ -885,12 +885,9 @@ static void set_mmd_offset(void) mmd->offset = tv2ms(&offset); } -/** +/* * Compute the timeout for the main select-loop of the scheduler. * - * \param s Pointer to the server scheduler. - * \param t Pointer to the vss task structure. - * * Before the timeout is computed, the current vss status flags are evaluated * and acted upon by calling appropriate functions from the lower layers. * Possible actions include @@ -899,10 +896,10 @@ static void set_mmd_offset(void) * - shutdown of all senders (stop/pause command), * - reposition the stream (ff/jmp command). */ -static void vss_pre_select(struct sched *s, struct task *t) +static void vss_pre_select(struct sched *s, void *context) { int i; - struct vss_task *vsst = container_of(t, struct vss_task, task); + struct vss_task *vsst = context; if (!vsst->map || vss_next() || vss_paused() || vss_repos()) { struct fec_client *fc, *tmp; @@ -924,7 +921,8 @@ static void vss_pre_select(struct sched *s, struct task *t) tv_add(now, &vsst->announce_tv, &vsst->data_send_barrier); set_eof_barrier(vsst); mmd->chunks_sent = 0; - mmd->current_chunk = mmd->repos_request; + mmd->current_chunk = afh_get_start_chunk(mmd->repos_request, + &mmd->afd.afhi); mmd->new_vss_status_flags &= ~VSS_REPOS; set_mmd_offset(); } @@ -1126,10 +1124,10 @@ static void vss_send(struct vss_task *vsst) } } -static int vss_post_select(struct sched *s, struct task *t) +static int vss_post_select(struct sched *s, void *context) { int ret, i; - struct vss_task *vsst = container_of(t, struct vss_task, task); + struct vss_task *vsst = context; if (mmd->sender_cmd_data.cmd_num >= 0) { int num = mmd->sender_cmd_data.cmd_num, @@ -1185,8 +1183,6 @@ void init_vss_task(int afs_socket, struct sched *s) conf.autoplay_delay_arg : 0; vsst->header_interval.tv_sec = 5; /* should this be configurable? */ vsst->afs_socket = afs_socket; - vsst->task.pre_select = vss_pre_select; - vsst->task.post_select = vss_post_select; ms2tv(announce_time, &vsst->announce_tv); PARA_INFO_LOG("announce timeval: %lums\n", tv2ms(&vsst->announce_tv)); INIT_LIST_HEAD(&fec_client_list); @@ -1206,6 +1202,10 @@ void init_vss_task(int afs_socket, struct sched *s) tv_add(&vsst->autoplay_barrier, &vsst->announce_tv, &vsst->data_send_barrier); } - sprintf(vsst->task.status, "vss task"); - register_task(s, &vsst->task); + vsst->task = task_register(&(struct task_info) { + .name = "vss task", + .pre_select = vss_pre_select, + .post_select = vss_post_select, + .context = vsst, + }, s); } diff --git a/vss.h b/vss.h index c4d6f737..33a4b09e 100644 --- a/vss.h +++ b/vss.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2005-2014 Andre Noll + * Copyright (C) 2005-2014 Andre Noll * * Licensed under the GPL v2. For licencing details see COPYING. */ diff --git a/wav_filter.c b/wav_filter.c index ea3236c7..8a1ad38b 100644 --- a/wav_filter.c +++ b/wav_filter.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2005-2014 Andre Noll + * Copyright (C) 2005-2014 Andre Noll * * Licensed under the GPL v2. For licencing details see COPYING. */ @@ -63,20 +63,19 @@ static void wav_open(struct filter_node *fn) *bof = 1; } -static void wav_pre_select(struct sched *s, struct task *t) +static void wav_pre_select(struct sched *s, void *context) { - struct filter_node *fn = container_of(t, struct filter_node, task); + struct filter_node *fn = context; size_t iqs = btr_get_input_queue_size(fn->btrn); - t->error = 0; if (iqs == 0) return; sched_min_delay(s); } -static int wav_post_select(__a_unused struct sched *s, struct task *t) +static int wav_post_select(__a_unused struct sched *s, void *context) { - struct filter_node *fn = container_of(t, struct filter_node, task); + struct filter_node *fn = context; struct btr_node *btrn = fn->btrn; size_t iqs = btr_get_input_queue_size(btrn); int ret; diff --git a/web/.htaccess b/web/.htaccess new file mode 100644 index 00000000..d6a12221 --- /dev/null +++ b/web/.htaccess @@ -0,0 +1,12 @@ + + IndexOptions FancyIndexing IconWidth=30 IconsAreLinks + IndexOrderDefault Descending Date + IndexIgnore .. + + AddIcon ../signature.png *.asc + AddDescription "Digital signature" *.asc + + AddIcon ../tar-icon.png *.tgz *.tar.bz2 + AddDescription "current master snapshot" -git.tar.bz2 + AddDescription "release tarball" *.tgz *.tar.bz2 + diff --git a/web/contact.in.html b/web/contact.in.html index 3e980db8..aeb37207 100644 --- a/web/contact.in.html +++ b/web/contact.in.html @@ -2,7 +2,7 @@

André Noll, maan@systemlinux.org

+href="mailto:maan@tuebingen.mpg.de">maan@tuebingen.mpg.de

Comments and bug reports are welcome (english, german, or spanish language). Please provide enough info such as the version of paraslash diff --git a/web/download.in.html b/web/download.in.html index 393fce93..dd0b9c78 100644 --- a/web/download.in.html +++ b/web/download.in.html @@ -9,7 +9,9 @@ provided at this point. There are several ways to download the source: Clone the git repository by executing -

  git clone git://paraslash.systemlinux.org/git paraslash  

+

 
+			git clone git://git.tuebingen.mpg.de/paraslash.git
+		 

The repository contains the full history of the project since 2006, all work in progress and the source @@ -63,7 +65,7 @@ provided at this point. There are several ways to download the source: The - gitweb + gitweb page contains a snapshot link for each revision. This allows to get a specific revision without downloading diff --git a/web/gitweb_footer.html b/web/gitweb_footer.html deleted file mode 100644 index 8beeeaf0..00000000 --- a/web/gitweb_footer.html +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/web/gitweb_header.html.in b/web/gitweb_header.html.in deleted file mode 100644 index f7b40714..00000000 --- a/web/gitweb_header.html.in +++ /dev/null @@ -1,28 +0,0 @@ - - - - - - - -
- - paraslash - - -

Paraslash network audio streaming tools

-
-
- Home
- Features
- Screenshots
- Download
- Documentation
- Changes
- Development
- License
- Contact
- Credits
-
-

Changes

-
diff --git a/web/header.html b/web/header.html index 8f7428f7..1960dc05 100644 --- a/web/header.html +++ b/web/header.html @@ -11,7 +11,7 @@ @@ -20,14 +20,13 @@ - -
- + paraslash
+
Home
Features
Screenshots
Download
Documentation
- Changes
Development
License
Contact
diff --git a/web/header2.html b/web/header2.html index 68980a86..956ca7aa 100644 --- a/web/header2.html +++ b/web/header2.html @@ -20,14 +20,13 @@
+
Home
Features
Screenshots
Download
Documentation
- Changes
Development
License
Contact
diff --git a/web/images/git-logo.png b/web/images/git-logo.png deleted file mode 100644 index 16ae8d53..00000000 Binary files a/web/images/git-logo.png and /dev/null differ diff --git a/web/images/signature.png b/web/images/signature.png new file mode 100644 index 00000000..9524182c Binary files /dev/null and b/web/images/signature.png differ diff --git a/web/images/tar-icon.png b/web/images/tar-icon.png new file mode 100644 index 00000000..4b1b472d Binary files /dev/null and b/web/images/tar-icon.png differ diff --git a/web/manual.m4 b/web/manual.m4 index 1f1c7f2a..218769ba 100644 --- a/web/manual.m4 +++ b/web/manual.m4 @@ -209,11 +209,12 @@ For the impatient: sudo apt-get install autoconf libssl-dev help2man gengetopt \ libmad0-dev libid3tag0-dev libasound2-dev libvorbis-dev \ libfaad-dev libspeex-dev libFLAC-dev libsamplerate-dev \ - libasound2-dev libao-dev libreadline-dev libncurses-dev + libasound2-dev libao-dev libreadline-dev libncurses-dev \ + libopus-dev Detailed description: In any case you'll need - - XREFERENCE(http://systemlinux.org/~maan/osl/, libosl). + - XREFERENCE(http://people.tuebingen.mpg.de/maan/osl/, libosl). The _object storage layer_ library is used by para_server. To clone the source code repository, execute @@ -667,7 +668,7 @@ known audio files to those which satisfy certain criteria. It also maintains tables containing images (e.g. album cover art) and lyrics that can be associated with one or more audio files. -AFS uses XREFERENCE(http://systemlinux.org/~maan/osl/, libosl), the +AFS uses XREFERENCE(http://people.tuebingen.mpg.de/maan/osl/, libosl), the object storage layer library, as the backend library for storing information on audio files, playlists, etc. This library offers functionality similar to a relational database, but is much more @@ -2214,7 +2215,8 @@ RFCs Application web pages ~~~~~~~~~~~~~~~~~~~~~ - - XREFERENCE(http://paraslash.systemlinux.org/, paraslash) + - XREFERENCE(http://people.tuebingen.mpg.de/maan/paraslash/, paraslash) + - XREFERENCE(http://paraslash.systemlinux.org/, paraslash (alternative page)) - XREFERENCE(http://xmms2.org/wiki/Main_Page, xmms) - XREFERENCE(http://www.mpg123.de/, mpg123) - XREFERENCE(http://gstreamer.freedesktop.org/, gstreamer) diff --git a/web/para.css b/web/para.css index 422f454e..e8c43489 100644 --- a/web/para.css +++ b/web/para.css @@ -443,320 +443,3 @@ a.text:hover { text-decoration: underline; color: #880000; } - -table.project_list { - border-spacing: 0; -} - -table.diff_tree { - border-spacing: 0; - font-family: monospace; -} - -table.combined.diff_tree th { - text-align: center; -} - -table.combined.diff_tree td { - padding-right: 24px; -} - -table.combined.diff_tree th.link, -table.combined.diff_tree td.link { - padding: 0px 2px; -} - -table.combined.diff_tree td.nochange a { - color: #6666ff; -} - -table.combined.diff_tree td.nochange a:hover, -table.combined.diff_tree td.nochange a:visited { - color: #d06666; -} - -table.blame { - border-collapse: collapse; -} - -table.blame td { - padding: 0px 5px; - font-size: 100%; - vertical-align: top; -} - -tr.light:hover { - background-color: yellow; - color: #cc3322; -} - -tr.dark { - background-color: #333333; -} - -tr.dark2 { - background-color: #333333; -} - -tr.dark:hover { - background-color: yellow; - color: #cc3322; -} - -td.link, td.selflink { - padding: 2px 5px; - font-family: sans-serif; - font-size: 70%; -} - -td.selflink { - padding-right: 0px; -} - -td.sha1 { - font-family: monospace; -} - -td.error { - color: red; - background-color: yellow; -} - -td.current_head { - text-decoration: underline; -} - -table.diff_tree span.file_status.new { - color: #008000; -} - -table.diff_tree span.file_status.deleted { - color: #c00000; -} - -table.diff_tree span.file_status.moved, -table.diff_tree span.file_status.mode_chnge { - color: #777777; -} - -table.diff_tree span.file_status.copied { - color: #70a070; -} - -/* noage: "No commits" */ -table.project_list td.noage { - color: #808080; - font-style: italic; -} - -/* age2: 60*60*24*2 <= age */ -table.project_list td.age2, table.blame td.age2 { - font-style: italic; -} - -/* age1: 60*60*2 <= age < 60*60*24*2 */ -table.project_list td.age1 { - color: #009900; - font-style: italic; -} - -table.blame td.age1 { - color: #009900; - background: transparent; -} - -/* age0: age < 60*60*2 */ -table.project_list td.age0 { - color: #009900; - font-style: italic; - font-weight: bold; -} - -table.blame td.age0 { - color: #009900; - background: transparent; - font-weight: bold; -} - -td.pre, div.pre, div.diff { - white-space: pre; -} - -td.mode { - font-family: monospace; -} - -/* styling of diffs (patchsets): commitdiff and blobdiff views */ - -div.diff.header, -div.diff.extended_header { - white-space: normal; -} - -div.diff.header { - font-weight: bold; - - background-color: #333333; - - margin-top: 4px; - padding: 4px 0px 2px 0px; - border: solid #d9d8d1; - border-width: 1px 0px 1px 0px; -} - -div.diff.header a.path { - text-decoration: underline; -} - -div.diff.extended_header, -div.diff.extended_header a.path, -div.diff.extended_header a.hash { - color: #cccccc; -} - -div.diff.extended_header .info { - color: #b0b0b0; -} - -div.diff.extended_header { - background-color: #333333; - padding: 2px 0px 2px 0px; -} - -div.diff a.list, -div.diff a.path, -div.diff a.hash { - text-decoration: none; -} - -div.diff a.list:hover, -div.diff a.path:hover, -div.diff a.hash:hover { - text-decoration: underline; -} - -div.diff.to_file a.path, -div.diff.to_file { - color: #007000; -} - -div.diff.add { - color: #008800; -} - -div.diff.from_file a.path, -div.diff.from_file { - color: #ff0000; -} - -div.diff.rem { - color: #cc0000; -} - -div.diff.chunk_header a, -div.diff.chunk_header { - color: #990099; -} - -div.diff.chunk_header { - border: dotted #ffe0ff; - border-width: 1px 0px 0px 0px; - margin-top: 2px; -} - -div.diff.chunk_header span.chunk_info { - background-color: #000000; -} - -div.diff.chunk_header span.section { - color: #aa22aa; -} - -div.diff.incomplete { - color: #cccccc; -} - -div.diff.nodifferences { - font-weight: bold; - color: #600000; -} - -div.index_include { - border: solid #d9d8d1; - border-width: 0px 0px 1px; - padding: 12px 8px; -} - -div.search { - font-size: 100%; - font-weight: normal; - margin: 4px 8px; - float: right; - top: 56px; - right: 12px -} - -td.linenr { - text-align: right; -} - -a.linenr { - color: #999999; - text-decoration: none -} - -a.rss_logo { - float: right; - padding: 3px 0px; - width: 35px; - line-height: 10px; - border: 1px solid; - border-color: #fcc7a5 #7d3302 #3e1a01 #ff954e; - color: #ffffff; - background-color: #ff6600; - font-weight: bold; - font-family: sans-serif; - font-size: 70%; - text-align: center; - text-decoration: none; -} - -a.rss_logo:hover { - background-color: #ee5500; -} - -span.refs span { - padding: 0px 4px; - font-size: 70%; - font-weight: normal; - border: 1px solid; - background-color: #222222; - border-color: #ffccff #ff00ee #ff00ee #ffccff; -} - -span.refs span.ref { - background-color: #aaaaff; - border-color: #ccccff #0033cc #0033cc #ccccff; -} - -span.refs span.tag { - background-color: #ffffaa; - border-color: #ffffcc #ffee00 #ffee00 #ffffcc; -} - -span.refs span.head { - background-color: #222222; - border-color: #ccffcc #00cc33 #00cc33 #ccffcc; -} - -span.atnight { - color: #cc0000; -} - -span.match { - color: #e00000; -} - -div.binary { - font-style: italic; -} diff --git a/wma_afh.c b/wma_afh.c index 65795fd8..cfa73040 100644 --- a/wma_afh.c +++ b/wma_afh.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2009-2014 Andre Noll + * Copyright (C) 2009-2014 Andre Noll * * Licensed under the GPL v2. For licencing details see COPYING. */ diff --git a/wma_common.c b/wma_common.c index e53cdf5e..3c775be2 100644 --- a/wma_common.c +++ b/wma_common.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2009-2014 Andre Noll + * Copyright (C) 2009-2014 Andre Noll * * Licensed under the GPL v2. For licencing details see COPYING. */ diff --git a/wmadec_filter.c b/wmadec_filter.c index fdca2814..188b0a41 100644 --- a/wmadec_filter.c +++ b/wmadec_filter.c @@ -1203,9 +1203,9 @@ static int wmadec_execute(struct btr_node *btrn, const char *cmd, char **result) #define WMA_OUTPUT_BUFFER_SIZE (128 * 1024) -static int wmadec_post_select(__a_unused struct sched *s, struct task *t) +static int wmadec_post_select(__a_unused struct sched *s, void *context) { - struct filter_node *fn = container_of(t, struct filter_node, task); + struct filter_node *fn = context; int ret, converted, out_size; struct private_wmadec_data *pwd = fn->private_data; struct btr_node *btrn = fn->btrn; diff --git a/write.c b/write.c index 4ed5f72e..ecb3887c 100644 --- a/write.c +++ b/write.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2005-2014 Andre Noll + * Copyright (C) 2005-2014 Andre Noll * * Licensed under the GPL v2. For licencing details see COPYING. */ @@ -71,19 +71,19 @@ static void setup_writer_node(const char *arg, struct btr_node *parent, } struct write_task { - struct task task; + struct task *task; struct check_wav_context *cwc; }; -static void write_pre_select(struct sched *s, struct task *t) +static void write_pre_select(struct sched *s, void *context) { - struct write_task *wt = container_of(t, struct write_task, task); + struct write_task *wt = context; check_wav_pre_select(s, wt->cwc); } -static int write_post_select(__a_unused struct sched *s, struct task *t) +static int write_post_select(__a_unused struct sched *s, void *context) { - struct write_task *wt = container_of(t, struct write_task, task); + struct write_task *wt = context; return check_wav_post_select(wt->cwc); } @@ -94,22 +94,20 @@ static int setup_and_schedule(void) struct writer_node *wns; static struct sched s; struct wav_params wp; - struct write_task wt = { - .task = { - .pre_select = write_pre_select, - .post_select = write_post_select, - .status = "write task", - }, - }; + struct write_task wt; sit.btrn = btr_new_node(&(struct btr_node_description) EMBRACE(.name = "stdin")); - stdin_set_defaults(&sit); - register_task(&s, &sit.task); + stdin_task_register(&sit, &s); COPY_WAV_PARMS(&wp, &conf); wt.cwc = check_wav_init(sit.btrn, NULL, &wp, &cw_btrn); - register_task(&s, &wt.task); + wt.task = task_register(&(struct task_info) { + .name = "write", + .pre_select = write_pre_select, + .post_select = write_post_select, + .context = &wt, + }, &s); if (!conf.writer_given) { wns = para_calloc(sizeof(*wns)); setup_writer_node(NULL, cw_btrn, wns, &s); @@ -125,16 +123,17 @@ static int setup_and_schedule(void) s.default_timeout.tv_usec = 50000; ret = schedule(&s); if (ret >= 0) { - int j; + int j, ts; 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)); + struct writer_node *wn = wns + j; + ts = task_status(wn->task); + assert(ts < 0); + if (ts != -E_WRITE_COMMON_EOF && ts != -E_BTR_EOF) { + const char *name = writer_names[wn->writer_num]; + PARA_ERROR_LOG("%s: %s\n", name, + para_strerror(-ts)); if (ret >= 0) - ret = t->error; + ret = ts; } } } @@ -149,6 +148,7 @@ static int setup_and_schedule(void) } free(wns); check_wav_shutdown(wt.cwc); + sched_shutdown(&s); return ret; } diff --git a/write.h b/write.h index 0cfcafda..6ce5c32d 100644 --- a/write.h +++ b/write.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2006-2014 Andre Noll + * Copyright (C) 2006-2014 Andre Noll * * Licensed under the GPL v2. For licencing details see COPYING. */ @@ -22,7 +22,7 @@ struct writer_node { /** The buffer tree node associated with this writer node. */ struct btr_node *btrn; /** The task of this writer node. */ - struct task task; + struct task *task; /** The minimal input queue size (size of one audio sample). */ size_t min_iqs; }; @@ -59,13 +59,13 @@ struct writer { * This is called from scheduler. It may use the sched pointer to add * any file descriptors or to decrease the select timeout. */ - void (*pre_select)(struct sched *s, struct task *t); + void (*pre_select)(struct sched *s, void *context); /** * Write audio data. * * Called from the post_select function of the writer node's task. */ - int (*post_select)(struct sched *s, struct task *t); + int (*post_select)(struct sched *s, void *context); /** * Close one instance of the writer. * diff --git a/write_common.c b/write_common.c index e191c49a..50c81d79 100644 --- a/write_common.c +++ b/write_common.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2006-2014 Andre Noll + * Copyright (C) 2006-2014 Andre Noll * * Licensed under the GPL v2. For licencing details see COPYING. */ @@ -107,16 +107,16 @@ void register_writer_node(struct writer_node *wn, struct btr_node *parent, struct sched *s) { struct writer *w = writers + wn->writer_num; - char *name = make_message("%s writer", writer_names[wn->writer_num]); wn->btrn = btr_new_node(&(struct btr_node_description) - EMBRACE(.name = name, .parent = parent, + EMBRACE(.name = writer_names[wn->writer_num], .parent = parent, .handler = w->execute, .context = wn)); - strcpy(wn->task.status, name); - free(name); - wn->task.pre_select = w->pre_select; - wn->task.post_select = w->post_select; - register_task(s, &wn->task); + wn->task = task_register(&(struct task_info) { + .name = writer_names[wn->writer_num], + .pre_select = w->pre_select, + .post_select = w->post_select, + .context = wn, + }, s); } /** diff --git a/write_common.h b/write_common.h index e0351602..d077178e 100644 --- a/write_common.h +++ b/write_common.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2006-2014 Andre Noll + * Copyright (C) 2006-2014 Andre Noll * * Licensed under the GPL v2. For licencing details see COPYING. */