153a5a1b3Sopenharmony_ci/***
253a5a1b3Sopenharmony_ci    This file is part of PulseAudio.
353a5a1b3Sopenharmony_ci
453a5a1b3Sopenharmony_ci    Copyright 2022 Craig Howard
553a5a1b3Sopenharmony_ci
653a5a1b3Sopenharmony_ci    PulseAudio is free software; you can redistribute it and/or modify
753a5a1b3Sopenharmony_ci    it under the terms of the GNU Lesser General Public License as published
853a5a1b3Sopenharmony_ci    by the Free Software Foundation; either version 2.1 of the License,
953a5a1b3Sopenharmony_ci    or (at your option) any later version.
1053a5a1b3Sopenharmony_ci
1153a5a1b3Sopenharmony_ci    PulseAudio is distributed in the hope that it will be useful, but
1253a5a1b3Sopenharmony_ci    WITHOUT ANY WARRANTY; without even the implied warranty of
1353a5a1b3Sopenharmony_ci    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
1453a5a1b3Sopenharmony_ci    General Public License for more details.
1553a5a1b3Sopenharmony_ci
1653a5a1b3Sopenharmony_ci    You should have received a copy of the GNU Lesser General Public License
1753a5a1b3Sopenharmony_ci    along with PulseAudio; if not, see <http://www.gnu.org/licenses/>.
1853a5a1b3Sopenharmony_ci***/
1953a5a1b3Sopenharmony_ci
2053a5a1b3Sopenharmony_ci#ifdef HAVE_CONFIG_H
2153a5a1b3Sopenharmony_ci#include <config.h>
2253a5a1b3Sopenharmony_ci#endif
2353a5a1b3Sopenharmony_ci
2453a5a1b3Sopenharmony_ci#include "restart-module.h"
2553a5a1b3Sopenharmony_ci
2653a5a1b3Sopenharmony_ci#include <pulse/timeval.h>
2753a5a1b3Sopenharmony_ci#include <pulse/xmalloc.h>
2853a5a1b3Sopenharmony_ci#include <pulse/mainloop.h>
2953a5a1b3Sopenharmony_ci
3053a5a1b3Sopenharmony_ci#include <pulsecore/core.h>
3153a5a1b3Sopenharmony_ci#include <pulsecore/thread-mq.h>
3253a5a1b3Sopenharmony_ci
3353a5a1b3Sopenharmony_cistruct pa_restart_data {
3453a5a1b3Sopenharmony_ci    init_cb do_init;
3553a5a1b3Sopenharmony_ci    done_cb do_done;
3653a5a1b3Sopenharmony_ci
3753a5a1b3Sopenharmony_ci    pa_usec_t restart_usec;
3853a5a1b3Sopenharmony_ci    pa_module *module;
3953a5a1b3Sopenharmony_ci    pa_time_event *time_event;
4053a5a1b3Sopenharmony_ci    pa_defer_event *defer_event;
4153a5a1b3Sopenharmony_ci};
4253a5a1b3Sopenharmony_ci
4353a5a1b3Sopenharmony_cistatic void do_reinit(pa_mainloop_api *mainloop, pa_restart_data *rd);
4453a5a1b3Sopenharmony_ci
4553a5a1b3Sopenharmony_cistatic void call_init(pa_mainloop_api *mainloop, pa_time_event *e, const struct timeval *tv, void *userdata) {
4653a5a1b3Sopenharmony_ci    pa_restart_data *rd = userdata;
4753a5a1b3Sopenharmony_ci    int ret;
4853a5a1b3Sopenharmony_ci
4953a5a1b3Sopenharmony_ci    if (rd->time_event) {
5053a5a1b3Sopenharmony_ci        mainloop->time_free(rd->time_event);
5153a5a1b3Sopenharmony_ci        rd->time_event = NULL;
5253a5a1b3Sopenharmony_ci    }
5353a5a1b3Sopenharmony_ci
5453a5a1b3Sopenharmony_ci    /* now that restart_usec has elapsed, we call do_init to restart the module */
5553a5a1b3Sopenharmony_ci    ret = rd->do_init(rd->module);
5653a5a1b3Sopenharmony_ci
5753a5a1b3Sopenharmony_ci    /* if the init failed, we got here because the caller wanted to restart, so
5853a5a1b3Sopenharmony_ci     * setup another restart */
5953a5a1b3Sopenharmony_ci    if (ret < 0)
6053a5a1b3Sopenharmony_ci        do_reinit(mainloop, rd);
6153a5a1b3Sopenharmony_ci}
6253a5a1b3Sopenharmony_ci
6353a5a1b3Sopenharmony_cistatic void defer_callback(pa_mainloop_api *mainloop, pa_defer_event *e, void *userdata) {
6453a5a1b3Sopenharmony_ci    pa_restart_data *rd = userdata;
6553a5a1b3Sopenharmony_ci
6653a5a1b3Sopenharmony_ci    pa_assert(rd->defer_event == e);
6753a5a1b3Sopenharmony_ci
6853a5a1b3Sopenharmony_ci    mainloop->defer_enable(rd->defer_event, 0);
6953a5a1b3Sopenharmony_ci    mainloop->defer_free(rd->defer_event);
7053a5a1b3Sopenharmony_ci    rd->defer_event = NULL;
7153a5a1b3Sopenharmony_ci
7253a5a1b3Sopenharmony_ci    do_reinit(mainloop, rd);
7353a5a1b3Sopenharmony_ci}
7453a5a1b3Sopenharmony_ci
7553a5a1b3Sopenharmony_cistatic void do_reinit(pa_mainloop_api *mainloop, pa_restart_data *rd) {
7653a5a1b3Sopenharmony_ci    struct timeval tv;
7753a5a1b3Sopenharmony_ci
7853a5a1b3Sopenharmony_ci    pa_assert_ctl_context();
7953a5a1b3Sopenharmony_ci
8053a5a1b3Sopenharmony_ci    /* call do_done on the module, which will effectively tear it down; all
8153a5a1b3Sopenharmony_ci     * that remains is the pa_module */
8253a5a1b3Sopenharmony_ci    rd->do_done(rd->module);
8353a5a1b3Sopenharmony_ci
8453a5a1b3Sopenharmony_ci    /* after restart_usec, call do_init to restart the module */
8553a5a1b3Sopenharmony_ci    pa_gettimeofday(&tv);
8653a5a1b3Sopenharmony_ci    pa_timeval_add(&tv, rd->restart_usec);
8753a5a1b3Sopenharmony_ci    rd->time_event = mainloop->time_new(mainloop, &tv, call_init, rd);
8853a5a1b3Sopenharmony_ci}
8953a5a1b3Sopenharmony_ci
9053a5a1b3Sopenharmony_cipa_restart_data *pa_restart_module_reinit(pa_module *m, init_cb do_init, done_cb do_done, pa_usec_t restart_usec) {
9153a5a1b3Sopenharmony_ci    pa_restart_data *rd;
9253a5a1b3Sopenharmony_ci
9353a5a1b3Sopenharmony_ci    pa_assert_ctl_context();
9453a5a1b3Sopenharmony_ci    pa_assert(do_init);
9553a5a1b3Sopenharmony_ci    pa_assert(do_done);
9653a5a1b3Sopenharmony_ci    pa_assert(restart_usec);
9753a5a1b3Sopenharmony_ci
9853a5a1b3Sopenharmony_ci    pa_log_info("Starting reinit for %s", m->name);
9953a5a1b3Sopenharmony_ci
10053a5a1b3Sopenharmony_ci    rd = pa_xnew0(pa_restart_data, 1);
10153a5a1b3Sopenharmony_ci    rd->do_init = do_init;
10253a5a1b3Sopenharmony_ci    rd->do_done = do_done;
10353a5a1b3Sopenharmony_ci    rd->restart_usec = restart_usec;
10453a5a1b3Sopenharmony_ci    rd->module = m;
10553a5a1b3Sopenharmony_ci
10653a5a1b3Sopenharmony_ci    /* defer actually doing a reinit, so that we can safely exit whatever call
10753a5a1b3Sopenharmony_ci     * chain we're in before we effectively reinit the module */
10853a5a1b3Sopenharmony_ci    rd->defer_event = m->core->mainloop->defer_new(m->core->mainloop, defer_callback, rd);
10953a5a1b3Sopenharmony_ci    m->core->mainloop->defer_enable(rd->defer_event, 1);
11053a5a1b3Sopenharmony_ci
11153a5a1b3Sopenharmony_ci    return rd;
11253a5a1b3Sopenharmony_ci}
11353a5a1b3Sopenharmony_ci
11453a5a1b3Sopenharmony_civoid pa_restart_free(pa_restart_data *rd) {
11553a5a1b3Sopenharmony_ci    pa_assert_ctl_context();
11653a5a1b3Sopenharmony_ci    pa_assert(rd);
11753a5a1b3Sopenharmony_ci
11853a5a1b3Sopenharmony_ci    if (rd->defer_event) {
11953a5a1b3Sopenharmony_ci        rd->module->core->mainloop->defer_enable(rd->defer_event, 0);
12053a5a1b3Sopenharmony_ci        rd->module->core->mainloop->defer_free(rd->defer_event);
12153a5a1b3Sopenharmony_ci    }
12253a5a1b3Sopenharmony_ci
12353a5a1b3Sopenharmony_ci    if (rd->time_event) {
12453a5a1b3Sopenharmony_ci        pa_log_info("Cancel reinit for %s", rd->module->name);
12553a5a1b3Sopenharmony_ci        rd->module->core->mainloop->time_free(rd->time_event);
12653a5a1b3Sopenharmony_ci    }
12753a5a1b3Sopenharmony_ci
12853a5a1b3Sopenharmony_ci    pa_xfree(rd);
12953a5a1b3Sopenharmony_ci}
130