diff --git a/include/asterisk.h b/include/asterisk.h index 24e4c05128..dc1e521bc6 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 11.9 + * \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 e8f1d41d57..c2a08a62a4 100644 --- a/main/asterisk.c +++ b/main/asterisk.c @@ -228,6 +228,7 @@ struct console { struct ast_atexit { void (*func)(void); + int is_cleanup; AST_LIST_ENTRY(ast_atexit) list; }; @@ -970,13 +971,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); @@ -998,7 +999,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; @@ -1007,6 +1008,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); @@ -1016,6 +1018,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); @@ -1802,8 +1814,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(); } @@ -1861,7 +1874,7 @@ static void really_quit(int num, shutdown_nice_t niceness, int restart) active_channels ? "uncleanly" : "cleanly", num); ast_verb(0, "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/format.c b/main/format.c index d7fa744fb8..adf4151c9f 100644 --- a/main/format.c +++ b/main/format.c @@ -1128,7 +1128,7 @@ int ast_format_attr_init(void) } ast_cli_register_multiple(my_clis, ARRAY_LEN(my_clis)); - ast_register_atexit(format_attr_shutdown); + ast_register_cleanup(format_attr_shutdown); return 0; }