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