diff --git a/include/asterisk.h b/include/asterisk.h index 6543fd57ba..33298b3aed 100644 --- a/include/asterisk.h +++ b/include/asterisk.h @@ -89,6 +89,22 @@ int ast_pbx_init(void); /*!< Provided by pbx.c */ */ int ast_register_atexit(void (*func)(void)); +/*! + * \since 1.8.29 + * \brief Register a function to be executed before Asterisk gracefully exits. + * + * If Asterisk is immediately shutdown (core stop now, or sending the TERM + * signal), the callback is not run. When the callbacks are run, they are run in + * sequence with ast_register_atexit() callbacks, in the reverse order of + * registration. + * + * \param func The callback function to use. + * + * \retval 0 on success. + * \retval -1 on error. + */ +int ast_register_cleanup(void (*func)(void)); + /*! * \brief Unregister a function registered with ast_register_atexit(). * \param func The callback function to unregister. diff --git a/main/asterisk.c b/main/asterisk.c index eab4f62579..b3dc2ddcd5 100644 --- a/main/asterisk.c +++ b/main/asterisk.c @@ -209,6 +209,7 @@ struct console { struct ast_atexit { void (*func)(void); + int is_cleanup; AST_LIST_ENTRY(ast_atexit) list; }; @@ -944,13 +945,13 @@ static char *handle_show_version_files(struct ast_cli_entry *e, int cmd, struct #endif /* ! LOW_MEMORY */ -static void ast_run_atexits(void) +static void ast_run_atexits(int run_cleanups) { struct ast_atexit *ae; AST_LIST_LOCK(&atexits); while ((ae = AST_LIST_REMOVE_HEAD(&atexits, list))) { - if (ae->func) { + if (ae->func && (!ae->is_cleanup || run_cleanups)) { ae->func(); } ast_free(ae); @@ -972,7 +973,7 @@ static void __ast_unregister_atexit(void (*func)(void)) AST_LIST_TRAVERSE_SAFE_END; } -int ast_register_atexit(void (*func)(void)) +static int register_atexit(void (*func)(void), int is_cleanup) { struct ast_atexit *ae; @@ -981,6 +982,7 @@ int ast_register_atexit(void (*func)(void)) return -1; } ae->func = func; + ae->is_cleanup = is_cleanup; AST_LIST_LOCK(&atexits); __ast_unregister_atexit(func); @@ -990,6 +992,16 @@ int ast_register_atexit(void (*func)(void)) return 0; } +int ast_register_atexit(void (*func)(void)) +{ + return register_atexit(func, 0); +} + +int ast_register_cleanup(void (*func)(void)) +{ + return register_atexit(func, 1); +} + void ast_unregister_atexit(void (*func)(void)) { AST_LIST_LOCK(&atexits); @@ -1748,8 +1760,9 @@ static int can_safely_quit(shutdown_nice_t niceness, int restart) static void really_quit(int num, shutdown_nice_t niceness, int restart) { int active_channels; + int run_cleanups = niceness >= SHUTDOWN_NICE; - if (niceness >= SHUTDOWN_NICE) { + if (run_cleanups) { ast_module_shutdown(); } @@ -1791,7 +1804,7 @@ static void really_quit(int num, shutdown_nice_t niceness, int restart) if (option_verbose) ast_verbose("Executing last minute cleanups\n"); - ast_run_atexits(); + ast_run_atexits(run_cleanups); ast_debug(1, "Asterisk ending (%d).\n", num); if (ast_socket > -1) { diff --git a/main/autoservice.c b/main/autoservice.c index 4293e0b455..08a5da8e89 100644 --- a/main/autoservice.c +++ b/main/autoservice.c @@ -72,6 +72,7 @@ static AST_LIST_HEAD_STATIC(aslist, asent); static ast_cond_t as_cond; static pthread_t asthread = AST_PTHREADT_NULL; +static volatile int asexit = 0; static int as_chan_list_state; @@ -82,7 +83,7 @@ static void *autoservice_run(void *ign) .subclass.integer = AST_CONTROL_HANGUP, }; - for (;;) { + while (!asexit) { struct ast_channel *mons[MAX_AUTOMONS]; struct asent *ents[MAX_AUTOMONS]; struct ast_channel *chan; @@ -320,7 +321,19 @@ int ast_autoservice_ignore(struct ast_channel *chan, enum ast_frame_type ftype) return res; } +static void autoservice_shutdown(void) +{ + pthread_t th = asthread; + asexit = 1; + if (th != AST_PTHREADT_NULL) { + ast_cond_signal(&as_cond); + pthread_kill(th, SIGURG); + pthread_join(th, NULL); + } +} + void ast_autoservice_init(void) { + ast_register_cleanup(autoservice_shutdown); ast_cond_init(&as_cond, NULL); }