Index: main/db.c =================================================================== --- main/db.c (revision 375799) +++ main/db.c (working copy) @@ -109,6 +109,8 @@ static DB *astdb; AST_MUTEX_DEFINE_STATIC(dblock); static ast_cond_t dbcond; +static pthread_t syncthread; +static int doexit; typedef int (*process_keys_cb)(DBT *key, DBT *value, const char *filter, void *data); static void db_sync(void); @@ -122,7 +124,6 @@ return 0; } - static inline int keymatch(const char *key, const char *prefix) { int preflen = strlen(prefix); @@ -813,27 +814,63 @@ ast_mutex_lock(&dblock); for (;;) { ast_cond_wait(&dbcond, &dblock); + astdb->sync(astdb, 0); + if (doexit) { + ast_mutex_unlock(&dblock); + break; + } ast_mutex_unlock(&dblock); sleep(1); ast_mutex_lock(&dblock); - astdb->sync(astdb, 0); + /* Unfortunately, it is possible for signaling to happen + * when we're not waiting: in the bit when we're unlocked + * above. Do the do-exit check here again. (We could do + * it once, but that would impose a forced delay of 1 + * second always.) */ + if (doexit) { + ast_mutex_unlock(&dblock); + break; + } } return NULL; } +static void astdb_shutdown(void) +{ + ast_cli_unregister_multiple(cli_database, ARRAY_LEN(cli_database)); + ast_manager_unregister("DBGet"); + ast_manager_unregister("DBPut"); + ast_manager_unregister("DBDel"); + ast_manager_unregister("DBDelTree"); + + doexit = 1; + ast_mutex_lock(&dblock); + db_sync(); + ast_mutex_unlock(&dblock); + + pthread_join(syncthread, NULL); + +#if defined(DEBUG_FD_LEAKS) && defined(close) +/* DEBUG_FD_LEAKS causes conflicting define of close() in asterisk.h */ +#undef close +#endif + + astdb->close(astdb); +} + int astdb_init(void) { - pthread_t dont_care; - ast_cond_init(&dbcond, NULL); - if (ast_pthread_create_background(&dont_care, NULL, db_sync_thread, NULL)) { + if (ast_pthread_create_background(&syncthread, NULL, db_sync_thread, NULL)) { return -1; } /* Ignore check_return warning from Coverity for dbinit below */ dbinit(); + ast_register_atexit(astdb_shutdown); + ast_cli_register_multiple(cli_database, ARRAY_LEN(cli_database)); ast_manager_register_xml("DBGet", EVENT_FLAG_SYSTEM | EVENT_FLAG_REPORTING, manager_dbget); ast_manager_register_xml("DBPut", EVENT_FLAG_SYSTEM, manager_dbput);