From 9d5e2fd932f2b847792fa55b071a0061e1b9cd84 Mon Sep 17 00:00:00 2001 From: Andre Noll Date: Tue, 10 Jun 2025 16:06:03 +0200 Subject: [PATCH] Make struct sched private. This moves the declaration of the structure from sched.h to sched.c because the information stored in this structure has almost no users outside of the scheduler core. As a result, the size of the structure is no longer known outside of sched.c. Applications now must call the new sched_new() to obtain a pointer to an initialized scheduler structure, passing an alternative poll function if needed. We don't let applications set the default timeout anymore because the value is kind of arbitrary anyway and most applications simply specified one second. So hardcode this as the default. --- afs.c | 12 +++++------- audioc.c | 14 ++++++-------- audiod.c | 22 +++++++++++----------- client.c | 33 ++++++++++++++++----------------- filter.c | 14 ++++++-------- gui.c | 14 +++++++------- play.c | 21 ++++++++++----------- recv.c | 14 ++++++-------- sched.c | 50 ++++++++++++++++++++++++++++++++++++++++++++------ sched.h | 36 ++---------------------------------- server.c | 16 +++++++--------- write.c | 13 ++++++------- 12 files changed, 126 insertions(+), 133 deletions(-) diff --git a/afs.c b/afs.c index 32b3c5da..4424a2d4 100644 --- a/afs.c +++ b/afs.c @@ -956,10 +956,10 @@ static int afs_poll(struct pollfd *fds, nfds_t nfds, int timeout) */ __noreturn void afs_init(int socket_fd) { - static struct sched s; + struct sched *s = sched_new(afs_poll); int ret; - register_signal_task(&s); + register_signal_task(s); init_list_head(&afs_client_list); ret = open_afs_tables(); if (ret < 0) @@ -970,9 +970,7 @@ __noreturn void afs_init(int socket_fd) goto out_close; PARA_INFO_LOG("server_socket: %d\n", server_socket); init_admissible_files(OPT_STRING_VAL(AFS_INITIAL_MODE)); - register_command_task(&s); - s.default_timeout = 1000; - s.poll_function = afs_poll; + register_command_task(s); ret = write(socket_fd, "\0", 1); if (ret != 1) { if (ret == 0) @@ -980,8 +978,8 @@ __noreturn void afs_init(int socket_fd) ret = -ERRNO_TO_PARA_ERROR(errno); goto out_close; } - ret = schedule(&s); - sched_shutdown(&s); + ret = schedule(s); + sched_shutdown(s); mood_unload(NULL); playlist_unload(NULL); out_close: diff --git a/audioc.c b/audioc.c index 36f9f040..2ed3f128 100644 --- a/audioc.c +++ b/audioc.c @@ -76,7 +76,7 @@ fail: #include "buffer_tree.h" #include "interactive.h" -static struct sched sched; +static struct sched *sched; struct audioc_task { int fd; @@ -218,7 +218,7 @@ static int audioc_i9e_line_handler(char *line) .pre_monitor = audioc_pre_monitor, .post_monitor = audioc_post_monitor, .context = at, - }, &sched); + }, sched); i9e_attach_to_stdout(at->btrn); return 1; close: @@ -254,15 +254,13 @@ __noreturn static void interactive_session(void) sigemptyset(&act.sa_mask); act.sa_flags = 0; sigaction(SIGINT, &act, NULL); - sched.poll_function = i9e_poll; - - sched.default_timeout = 1000; - ret = i9e_open(&ici, &sched); + sched = sched_new(i9e_poll); + ret = i9e_open(&ici, sched); if (ret < 0) goto out; para_log = i9e_log; - ret = schedule(&sched); - sched_shutdown(&sched); + ret = schedule(sched); + sched_shutdown(sched); i9e_close(); para_log = stderr_log; out: diff --git a/audiod.c b/audiod.c index bdf8b713..7db34b90 100644 --- a/audiod.c +++ b/audiod.c @@ -119,7 +119,7 @@ enum vss_status_flags { * This is needed also in audiod_command.c (for the tasks command), so it can * not be made static. */ -struct sched sched = {.timeout = 0}; +struct sched *sched; /* The task for obtaining para_server's status (para_client stat). */ struct status_task { @@ -583,7 +583,7 @@ static void open_filters(struct slot_info *s) .pre_monitor = f->pre_monitor, .post_monitor = f->post_monitor, .context = fn, - }, &sched); + }, sched); parent = fn->btrn; PARA_NOTICE_LOG("%s filter %d/%d (%s) started in slot %d\n", audio_formats[s->format], i, nf, name, (int)(s - slot)); @@ -604,7 +604,7 @@ static void open_writers(struct slot_info *s) wn = s->wns + i; wn->wid = a->wids[i]; wn->lpr = a->writer_lpr[i]; - register_writer_node(wn, parent, &sched); + register_writer_node(wn, parent, sched); PARA_NOTICE_LOG("%s writer started in slot %d\n", writer_name(a->wids[i]), (int)(s - slot)); } @@ -647,7 +647,7 @@ static int open_receiver(int format) .pre_monitor = r->pre_monitor, .post_monitor = r->post_monitor, .context = rn, - }, &sched); + }, sched); return slot_num; } @@ -1131,7 +1131,7 @@ static void init_command_task(struct command_task *ct) .pre_monitor = command_pre_monitor, .post_monitor = command_post_monitor, .context = ct, - }, &sched); + }, sched); } static void close_stat_pipe(void) @@ -1245,7 +1245,7 @@ static void start_stop_decoders(void) sl = slot + ret; open_filters(sl); open_writers(sl); - activate_grab_clients(&sched); + activate_grab_clients(sched); btr_log_tree(sl->receiver_node->btrn, LL_NOTICE); audiod_status_dump(true); } @@ -1376,7 +1376,7 @@ static void init_status_task(struct status_task *st) .pre_monitor = status_pre_monitor, .post_monitor = status_post_monitor, .context = stat_task, - }, &sched); + }, sched); } static void set_initial_status(void) @@ -1491,6 +1491,7 @@ int main(int argc, char *argv[]) set_initial_status(); FOR_EACH_SLOT(i) clear_slot(i); + sched = sched_new(NULL); setup_signal_handling(); init_status_task(stat_task); @@ -1504,12 +1505,11 @@ int main(int argc, char *argv[]) .pre_monitor = signal_pre_monitor, .post_monitor = signal_post_monitor, .context = signal_task, - }, &sched); + }, sched); - sched.default_timeout = 2999; - ret = schedule(&sched); + ret = schedule(sched); audiod_cleanup(); - sched_shutdown(&sched); + sched_shutdown(sched); signal_shutdown(signal_task); crypt_shutdown(); out: diff --git a/client.c b/client.c index a5a8af53..1061b09c 100644 --- a/client.c +++ b/client.c @@ -20,7 +20,7 @@ /** Array of error strings. */ DEFINE_PARA_ERRLIST; -static struct sched sched; +static struct sched *sched; static struct client_task *ct; static struct stdin_task sit; static struct stdout_task sot; @@ -121,7 +121,7 @@ fail: static int execute_client_command(const char *cmd, char **result) { int ret; - struct sched command_sched = {.default_timeout = 1000}; + struct sched *command_sched = sched_new(NULL); struct exec_task exec_task = { .result_buf = para_strdup(""), .result_size = 1, @@ -139,12 +139,12 @@ static int execute_client_command(const char *cmd, char **result) .pre_monitor = exec_pre_monitor, .post_monitor = exec_post_monitor, .context = &exec_task, - }, &command_sched); - ret = client_connect(ct, &command_sched, NULL, exec_task.btrn); + }, command_sched); + ret = client_connect(ct, command_sched, NULL, exec_task.btrn); if (ret < 0) goto out; - schedule(&command_sched); - sched_shutdown(&command_sched); + schedule(command_sched); + sched_shutdown(command_sched); lls_free_parse_result(ct->lpr, CLIENT_CMD_PTR); ct->lpr = old_lpr; *result = exec_task.result_buf; @@ -498,7 +498,7 @@ static int client_i9e_line_handler(char *line) ret = create_merged_lpr(line); if (ret <= 0) return ret; - ret = client_connect(ct, &sched, NULL, NULL); + ret = client_connect(ct, sched, NULL, NULL); if (ret < 0) return ret; i9e_attach_to_stdout(ct->btrn[0]); @@ -539,14 +539,14 @@ __noreturn static void interactive_session(void) sigemptyset(&act.sa_mask); act.sa_flags = 0; sigaction(SIGINT, &act, NULL); - sched.poll_function = i9e_poll; + sched = sched_new(i9e_poll); - ret = i9e_open(&ici, &sched); + ret = i9e_open(&ici, sched); if (ret < 0) goto out; para_log = i9e_log; - ret = schedule(&sched); - sched_shutdown(&sched); + ret = schedule(sched); + sched_shutdown(sched); i9e_close(); para_log = stderr_log; out: @@ -632,8 +632,6 @@ int main(int argc, char *argv[]) int ret; crypt_init(); - sched.default_timeout = 1000; - ret = client_parse_config(argc, argv, &ct, &client_loglevel); if (ret < 0) goto out; @@ -642,6 +640,7 @@ int main(int argc, char *argv[]) if (ret == 0) interactive_session(); /* does not return */ + sched = sched_new(NULL); /* * We add buffer tree nodes for stdin and stdout even though * only one of them will be needed. This simplifies the code @@ -649,7 +648,7 @@ int main(int argc, char *argv[]) */ sit.btrn = btr_new_node(&(struct btr_node_description) EMBRACE(.name = "stdin")); - ret = client_connect(ct, &sched, sit.btrn, NULL); + ret = client_connect(ct, sched, sit.btrn, NULL); if (ret < 0) goto out; sot.btrn = btr_new_node(&(struct btr_node_description) @@ -658,9 +657,9 @@ int main(int argc, char *argv[]) .name = "supervisor", .post_monitor = supervisor_post_monitor, .context = &supervisor_task, - }, &sched); + }, sched); - ret = schedule(&sched); + ret = schedule(sched); if (ret >= 0) { ret = task_status(ct->task); if (ret < 0) { @@ -674,7 +673,7 @@ int main(int argc, char *argv[]) } } } - sched_shutdown(&sched); + sched_shutdown(sched); crypt_shutdown(); out: if (ret < 0) diff --git a/filter.c b/filter.c index a08bea51..a38ec2a0 100644 --- a/filter.c +++ b/filter.c @@ -97,7 +97,7 @@ static int parse_config(void) */ int main(int argc, char *argv[]) { - static struct sched s; + struct sched *s = sched_new(NULL); int i, ret; const struct filter *f; struct btr_node *parent; @@ -113,7 +113,7 @@ int main(int argc, char *argv[]) goto free_lpr; sit->btrn = btr_new_node(&(struct btr_node_description) EMBRACE(.name = "stdin")); - stdin_task_register(sit, &s); + stdin_task_register(sit, s); fns = arr_alloc(OPT_GIVEN(FILTER), sizeof(*fns)); for (i = 0, parent = sit->btrn; i < OPT_GIVEN(FILTER); i++) { @@ -140,17 +140,15 @@ int main(int argc, char *argv[]) ti.context = fn; if (f->open) f->open(fn); - fn->task = task_register(&ti, &s); + fn->task = task_register(&ti, s); parent = fn->btrn; } sot->btrn = btr_new_node(&(struct btr_node_description) EMBRACE(.name = "stdout", .parent = parent)); - stdout_task_register(sot, &s); - - s.default_timeout = 1000; + stdout_task_register(sot, s); btr_log_tree(sit->btrn, LL_INFO); - ret = schedule(&s); - sched_shutdown(&s); + ret = schedule(s); + sched_shutdown(s); teardown: for (i--; i >= 0; i--) { struct filter_node *fn = fns[i]; diff --git a/gui.c b/gui.c index 81385301..2586cad8 100644 --- a/gui.c +++ b/gui.c @@ -1394,28 +1394,28 @@ static int setup_tasks_and_schedule(void) struct status_task status_task = {.fd = -1}; struct input_task input_task = {.task = NULL}; struct signal_task *signal_task; - struct sched sched = {.default_timeout = 1000}; + struct sched *sched = sched_new(NULL); exec_task.task = task_register(&(struct task_info) { .name = "exec", .pre_monitor = exec_pre_monitor, .post_monitor = exec_post_monitor, .context = &exec_task, - }, &sched); + }, sched); status_task.task = task_register(&(struct task_info) { .name = "status", .pre_monitor = status_pre_monitor, .post_monitor = status_post_monitor, .context = &status_task, - }, &sched); + }, sched); input_task.task = task_register(&(struct task_info) { .name = "input", .pre_monitor = input_pre_monitor, .post_monitor = input_post_monitor, .context = &input_task, - }, &sched); + }, sched); signal_task = signal_init_or_die(); para_install_sighandler(SIGINT); @@ -1428,9 +1428,9 @@ static int setup_tasks_and_schedule(void) .pre_monitor = signal_pre_monitor, .post_monitor = signal_post_monitor, .context = signal_task, - }, &sched); - ret = schedule(&sched); - sched_shutdown(&sched); + }, sched); + ret = schedule(sched); + sched_shutdown(sched); signal_shutdown(signal_task); return ret; } diff --git a/play.c b/play.c index a43a1e53..086f43fa 100644 --- a/play.c +++ b/play.c @@ -106,7 +106,7 @@ INIT_STDERR_LOGGING(loglevel); char *stat_item_values[NUM_STAT_ITEMS] = {NULL}; -static struct sched sched; +static struct sched *sched; static struct play_task play_task, *pt = &play_task; #define AFH_RECV_CMD (lls_cmd(LSG_RECV_CMD_CMD_AFH, recv_cmd_suite)) @@ -398,7 +398,7 @@ static int load_file(void) .pre_monitor = AFH_RECV->pre_monitor, .post_monitor = AFH_RECV->post_monitor, .context = &pt->rn - }, &sched); + }, sched); sprintf(buf, "%s decoder", af); pt->fn.task = task_register( &(struct task_info) { @@ -406,8 +406,8 @@ static int load_file(void) .pre_monitor = decoder->pre_monitor, .post_monitor = decoder->post_monitor, .context = &pt->fn - }, &sched); - register_writer_node(&pt->wn, pt->fn.btrn, &sched); + }, sched); + register_writer_node(&pt->wn, pt->fn.btrn, sched); return 1; fail: wipe_receiver_node(); @@ -769,7 +769,7 @@ static int com_tasks(__a_unused struct lls_parse_result *lpr) char *buf; size_t sz; - buf = get_task_list(&sched); + buf = get_task_list(sched); btr_add_output(buf, strlen(buf), pt->btrn); state = get_playback_state(); sz = xasprintf(&buf, "state: %c\n", state); @@ -1061,12 +1061,12 @@ static void session_open(void) sigemptyset(&act.sa_mask); act.sa_flags = 0; sigaction(SIGWINCH, &act, NULL); - sched.poll_function = i9e_poll; + sched = sched_new(i9e_poll); ici.bound_keyseqs = get_mapped_keyseqs(); pt->btrn = ici.producer = btr_new_node(&(struct btr_node_description) EMBRACE(.name = __func__)); - ret = i9e_open(&ici, &sched); + ret = i9e_open(&ici, sched); if (ret < 0) goto out; para_log = i9e_log; @@ -1201,7 +1201,6 @@ int main(int argc, char *argv[]) int ret; unsigned num_inputs; - sched.default_timeout = 5000; parse_config_or_die(argc, argv); session_open(); num_inputs = lls_num_inputs(play_lpr); @@ -1214,9 +1213,9 @@ int main(int argc, char *argv[]) .pre_monitor = play_pre_monitor, .post_monitor = play_post_monitor, .context = pt, - }, &sched); - ret = schedule(&sched); - sched_shutdown(&sched); + }, sched); + ret = schedule(sched); + sched_shutdown(sched); i9e_close(); wipe_receiver_node(); para_log = stderr_log; diff --git a/recv.c b/recv.c index 0491292d..422d8c11 100644 --- a/recv.c +++ b/recv.c @@ -64,7 +64,7 @@ int main(int argc, char *argv[]) const struct receiver *r = NULL; struct receiver_node rn; struct stdout_task sot = {.btrn = NULL}; - static struct sched s; + static struct sched *s; struct task_info ti; const struct lls_command *cmd; struct lls_parse_result *lpr; /* command line */ @@ -92,17 +92,15 @@ int main(int argc, char *argv[]) goto remove_btrn; sot.btrn = btr_new_node(&(struct btr_node_description) EMBRACE(.parent = rn.btrn, .name = "stdout")); - stdout_task_register(&sot, &s); - + s = sched_new(NULL); + stdout_task_register(&sot, s); ti.name = lls_command_name(cmd); ti.pre_monitor = r->pre_monitor; ti.post_monitor = r->post_monitor; ti.context = &rn; - rn.task = task_register(&ti, &s); - - s.default_timeout = 1000; - ret = schedule(&s); - sched_shutdown(&s); + rn.task = task_register(&ti, s); + ret = schedule(s); + sched_shutdown(s); r->close(&rn); btr_remove_node(&sot.btrn); remove_btrn: diff --git a/sched.c b/sched.c index 475dead5..8a3e854f 100644 --- a/sched.c +++ b/sched.c @@ -45,6 +45,49 @@ struct task { static struct timeval now_struct; const struct timeval *now = &now_struct; +/* Internal representation of a paraslash scheduler instance. */ +struct sched { + /* Initial value (in milliseconds) before any pre_monitor call. */ + int default_timeout; + /* The timeout (also in milliseconds) for the next iteration. */ + int timeout; + /* Passed to poll(2). */ + struct pollfd *pfd; + /* Number of elements in the above array, passed to poll(2). */ + unsigned pfd_array_len; + /* Number of fds registered for monitoring so far. */ + unsigned num_pfds; + /* Maps fds to indices of the pfd array. */ + unsigned *pidx; + /* Number of elements in the above pidx array. */ + unsigned pidx_array_len; + /* Either the application-supplied function or xpoll() of fd.c. */ + int (*poll_function)(struct pollfd *fds, nfds_t nfds, int timeout); + /* Tasks which have been registered to the scheduler. */ + struct list_head task_list; +}; + +/** + * Allocate and initialize a scheduler instance. + * + * \param poll_function Optional. + * + * If NULL is passed as the poll function pointer, the \ref xpoll() wrapper + * is used to wait for events on the file descriptors passed. + * + * \return A pointer to the new instance that can be used to register tasks + * or to start scheduling. The only possible error is allocation failure, + * in which case the function aborts. Thus, it never returns NULL. + */ +struct sched *sched_new(int (*poll_function)(struct pollfd *, nfds_t, int)) +{ + struct sched *s = zalloc(sizeof(*s)); + s->default_timeout = 1000; + init_list_head(&s->task_list); + s->poll_function = poll_function? poll_function : xpoll; + return s; +} + static void sched_pre_monitor(struct sched *s) { struct task *t, *tmp; @@ -127,8 +170,6 @@ int schedule(struct sched *s) int ret; unsigned num_running_tasks; - if (!s->poll_function) - s->poll_function = xpoll; again: s->num_pfds = 0; if (s->pidx) @@ -213,6 +254,7 @@ void sched_shutdown(struct sched *s) } free(s->pfd); free(s->pidx); + free(s); } /** @@ -229,10 +271,6 @@ struct task *task_register(struct task_info *info, struct sched *s) struct task *t = alloc(sizeof(*t)); assert(info->post_monitor); - - if (!s->task_list.next) - init_list_head(&s->task_list); - t->info = *info; t->name = para_strdup(info->name); t->notification = 0; diff --git a/sched.h b/sched.h index ede5e67e..c5ce994e 100644 --- a/sched.h +++ b/sched.h @@ -2,40 +2,7 @@ /** \file sched.h Sched and task structures and exported symbols from sched.c. */ - -/** - * Paraslash's 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_monitor - * function which is called from the scheduler main loop before it calls - * poll(2). Similarly, each task must define a post_monitor function which is - * called after poll(2) returns. - * - * \sa select(2), poll(2). - */ -struct sched { - /** Initial value (in milliseconds) before any pre_monitor call. */ - int default_timeout; - /** The timeout (also in milliseconds) for the next iteration. */ - int timeout; - /** Passed to poll(2). */ - struct pollfd *pfd; - /** Number of elements in the above array, passed to poll(2). */ - unsigned pfd_array_len; - /** Number of fds registered for montitoring so far. */ - unsigned num_pfds; - /** Maps fds to indices of the pfd array. */ - unsigned *pidx; - /** Mumber of elements in the above pidx array. */ - unsigned pidx_array_len; - /** If non-NULL, use this function instead of \ref xpoll(). */ - int (*poll_function)(struct pollfd *fds, nfds_t nfds, int timeout); - /** Tasks which have been registered to the scheduler. */ - struct list_head task_list; -}; - -struct task; +struct sched; /** Information that must be supplied by callers of \ref task_register(). */ struct task_info { @@ -81,6 +48,7 @@ struct task_info { */ extern const struct timeval *now; +struct sched *sched_new(int (*poll_function)(struct pollfd *, nfds_t, int)); struct task *task_register(struct task_info *info, struct sched *s); int schedule(struct sched *s); void sched_shutdown(struct sched *s); diff --git a/server.c b/server.c index 48ada73c..3689230a 100644 --- a/server.c +++ b/server.c @@ -77,7 +77,7 @@ int mmd_mutex; /* Serializes log output. */ static int log_mutex; -static struct sched sched; +static struct sched *sched; static struct signal_task *signal_task; /** The process id of the audio file selector process. */ @@ -306,7 +306,7 @@ static void init_signal_task(void) .post_monitor = signal_post_monitor, .context = signal_task, - }, &sched); + }, sched); } static void command_pre_monitor(struct sched *s, void *context) @@ -451,7 +451,7 @@ static void init_server_command_task(struct server_command_task *sct, .pre_monitor = command_pre_monitor, .post_monitor = command_post_monitor, .context = sct, - }, &sched); + }, sched); /* * Detect whether the abstract Unix domain socket space is supported, * but do not create the socket. We check this once in server context @@ -565,7 +565,7 @@ static void server_init(int argc, char **argv, struct server_command_task *sct) init_signal_task(); para_unblock_signal(SIGCHLD); PARA_NOTICE_LOG("initializing virtual streaming system\n"); - vss_init(afs_socket, &sched); + vss_init(afs_socket, sched); init_server_command_task(sct, argc, argv); if (daemon_pipe >= 0) { if (write(daemon_pipe, "\0", 1) < 0) { @@ -647,18 +647,16 @@ int main(int argc, char *argv[]) struct server_command_task server_command_task_struct, *sct = &server_command_task_struct; - sched.default_timeout = 1000; - sched.poll_function = server_poll; - + sched = sched_new(server_poll); server_init(argc, argv, sct); mutex_lock(mmd_mutex); - ret = schedule(&sched); + ret = schedule(sched); /* * We hold the mmd lock: it was re-acquired in server_poll() * after the poll(2) call. */ mutex_unlock(mmd_mutex); - sched_shutdown(&sched); + sched_shutdown(sched); crypt_shutdown(); signal_shutdown(signal_task); if (!process_is_command_handler()) { /* parent (server) */ diff --git a/write.c b/write.c index 1cdfbc0f..91e5a971 100644 --- a/write.c +++ b/write.c @@ -69,13 +69,13 @@ static int setup_and_schedule(struct lls_parse_result *lpr) int i, n, ret, writer_given = OPT_GIVEN(WRITER, lpr); struct btr_node *cw_btrn; struct writer_node *wns; - static struct sched s; + struct sched *s = sched_new(NULL); struct wav_params wp; struct write_task wt; sit.btrn = btr_new_node(&(struct btr_node_description) EMBRACE(.name = "stdin")); - stdin_task_register(&sit, &s); + stdin_task_register(&sit, s); LLS_COPY_WAV_PARMS(&wp, LSG_WRITE_PARA_WRITE, lpr); wt.cwc = check_wav_init(sit.btrn, NULL, &wp, &cw_btrn); @@ -84,7 +84,7 @@ static int setup_and_schedule(struct lls_parse_result *lpr) .pre_monitor = write_pre_monitor, .post_monitor = write_post_monitor, .context = &wt, - }, &s); + }, s); n = writer_given? writer_given : 1; wns = arr_zalloc(n, sizeof(*wns)); @@ -92,10 +92,9 @@ static int setup_and_schedule(struct lls_parse_result *lpr) const char *arg = i < writer_given? lls_string_val(i, OPT_RESULT(WRITER, lpr)) : NULL; wns[i].wid = check_writer_arg_or_die(arg, &wns[i].lpr); - register_writer_node(wns + i, cw_btrn, &s); + register_writer_node(wns + i, cw_btrn, s); } - s.default_timeout = 10500; - ret = schedule(&s); + ret = schedule(s); if (ret >= 0) { int j, ts; for (j = 0; j < n; j++) { @@ -120,7 +119,7 @@ static int setup_and_schedule(struct lls_parse_result *lpr) } free(wns); check_wav_shutdown(wt.cwc); - sched_shutdown(&s); + sched_shutdown(s); return ret; } -- 2.39.5