From 471bd6df1ae73ca410f0b4051ee050e21401b17b Mon Sep 17 00:00:00 2001 From: Marc Olivier Chouinard Date: Fri, 18 Mar 2011 16:41:27 -0400 Subject: [PATCH] switch_xml: reloadxml will(should) never lock again. It will load the XML structure into a new XML structure, and just replace the currently available ROOT XML. It then the job of the last user of the switch_xml structure to free it. --- src/switch_xml.c | 100 ++++++++++++++++++++++++++++++++++------------- 1 file changed, 73 insertions(+), 27 deletions(-) diff --git a/src/switch_xml.c b/src/switch_xml.c index 4c30d986a6..1aa91cc076 100644 --- a/src/switch_xml.c +++ b/src/switch_xml.c @@ -124,6 +124,11 @@ struct switch_xml_root { /* additional data for the root tag */ char ***pi; /* processing instructions */ short standalone; /* non-zero if */ char err[SWITCH_XML_ERRL]; /* error string */ + /*! is_main_xml_root */ + switch_bool_t is_main_xml_root; + /*! rwlock */ + switch_thread_rwlock_t *rwlock; + }; char *SWITCH_XML_NIL[] = { NULL }; /* empty, null terminated array of strings */ @@ -139,11 +144,11 @@ struct switch_xml_binding { static switch_xml_binding_t *BINDINGS = NULL; static switch_xml_t MAIN_XML_ROOT = NULL; static switch_memory_pool_t *XML_MEMORY_POOL = NULL; -static switch_thread_rwlock_t *RWLOCK = NULL; static switch_thread_rwlock_t *B_RWLOCK = NULL; -static switch_mutex_t *XML_LOCK = NULL; +static switch_thread_rwlock_t *XML_RWLOCK = NULL; static switch_mutex_t *XML_GEN_LOCK = NULL; - +static switch_mutex_t *XML_FREE_LOCK = NULL; +static switch_mutex_t *XML_RWFILE_LOCK = NULL; struct xml_section_t { const char *name; @@ -1542,9 +1547,11 @@ SWITCH_DECLARE(switch_xml_t) switch_xml_parse_file(const char *file) } else { abs = file; } + /* Protection against running this code twice on the same filename */ + switch_mutex_lock(XML_RWFILE_LOCK); if (!(new_file = switch_mprintf("%s%s%s.fsxml", SWITCH_GLOBAL_dirs.log_dir, SWITCH_PATH_SEPARATOR, abs))) { - return NULL; + goto done; } if ((write_fd = open(new_file, O_WRONLY | O_CREAT | O_TRUNC, S_IRUSR | S_IWUSR)) < 0) { @@ -1571,6 +1578,7 @@ SWITCH_DECLARE(switch_xml_t) switch_xml_parse_file(const char *file) if (fd > -1) { close(fd); } + switch_mutex_unlock(XML_RWFILE_LOCK); switch_safe_free(new_file); return xml; } @@ -1933,8 +1941,16 @@ SWITCH_DECLARE(switch_status_t) switch_xml_locate_user(const char *key, SWITCH_DECLARE(switch_xml_t) switch_xml_root(void) { - switch_thread_rwlock_rdlock(RWLOCK); - return MAIN_XML_ROOT; + switch_xml_root_t root = NULL; + + switch_thread_rwlock_rdlock(XML_RWLOCK); + if (MAIN_XML_ROOT) { + root = (switch_xml_root_t) MAIN_XML_ROOT; + switch_thread_rwlock_rdlock(root->rwlock); + } + switch_thread_rwlock_unlock(XML_RWLOCK); + + return (switch_xml_t) root; } struct destroy_xml { @@ -1978,15 +1994,14 @@ SWITCH_DECLARE(switch_xml_t) switch_xml_open_root(uint8_t reload, const char **e { char path_buf[1024]; uint8_t errcnt = 0; - switch_xml_t new_main, r = NULL; + switch_xml_t r = NULL, new_main; - switch_mutex_lock(XML_LOCK); + if (!reload) { + r = switch_xml_root(); + } - if (MAIN_XML_ROOT) { - if (!reload) { - r = switch_xml_root(); - goto done; - } + if (r) { + goto done; } switch_snprintf(path_buf, sizeof(path_buf), "%s%s%s", SWITCH_GLOBAL_dirs.conf_dir, SWITCH_PATH_SEPARATOR, "freeswitch.xml"); @@ -1999,18 +2014,27 @@ SWITCH_DECLARE(switch_xml_t) switch_xml_open_root(uint8_t reload, const char **e new_main = NULL; errcnt++; } else { - switch_xml_t old_root; + switch_xml_t old_root = NULL; + switch_xml_root_t new_main_root = (switch_xml_root_t) new_main; + + new_main_root->is_main_xml_root = SWITCH_TRUE; + *err = "Success"; - switch_thread_rwlock_wrlock(RWLOCK); + old_root = switch_xml_root(); - old_root = MAIN_XML_ROOT; + switch_set_flag(new_main, SWITCH_XML_ROOT); + + switch_thread_rwlock_wrlock(XML_RWLOCK); MAIN_XML_ROOT = new_main; - switch_set_flag(MAIN_XML_ROOT, SWITCH_XML_ROOT); + switch_thread_rwlock_unlock(XML_RWLOCK); - switch_thread_rwlock_unlock(RWLOCK); + if (old_root) { + switch_clear_flag(old_root, SWITCH_XML_ROOT); + } switch_xml_free(old_root); + /* switch_xml_free_in_thread(old_root); */ } } else { @@ -2030,8 +2054,6 @@ SWITCH_DECLARE(switch_xml_t) switch_xml_open_root(uint8_t reload, const char **e done: - switch_mutex_unlock(XML_LOCK); - return r; } @@ -2053,10 +2075,11 @@ SWITCH_DECLARE(switch_status_t) switch_xml_init(switch_memory_pool_t *pool, cons XML_MEMORY_POOL = pool; *err = "Success"; - switch_mutex_init(&XML_LOCK, SWITCH_MUTEX_NESTED, XML_MEMORY_POOL); switch_mutex_init(&XML_GEN_LOCK, SWITCH_MUTEX_NESTED, XML_MEMORY_POOL); - switch_thread_rwlock_create(&RWLOCK, XML_MEMORY_POOL); + switch_mutex_init(&XML_FREE_LOCK, SWITCH_MUTEX_NESTED, XML_MEMORY_POOL); + switch_mutex_init(&XML_RWFILE_LOCK, SWITCH_MUTEX_NESTED, XML_MEMORY_POOL); switch_thread_rwlock_create(&B_RWLOCK, XML_MEMORY_POOL); + switch_thread_rwlock_create(&XML_RWLOCK, XML_MEMORY_POOL); assert(pool != NULL); @@ -2071,7 +2094,7 @@ SWITCH_DECLARE(switch_status_t) switch_xml_init(switch_memory_pool_t *pool, cons SWITCH_DECLARE(switch_status_t) switch_xml_destroy(void) { switch_status_t status = SWITCH_STATUS_FALSE; - switch_mutex_lock(XML_LOCK); + switch_thread_rwlock_wrlock(XML_RWLOCK); if (MAIN_XML_ROOT) { switch_xml_t xml = MAIN_XML_ROOT; @@ -2080,7 +2103,7 @@ SWITCH_DECLARE(switch_status_t) switch_xml_destroy(void) status = SWITCH_STATUS_SUCCESS; } - switch_mutex_unlock(XML_LOCK); + switch_thread_rwlock_unlock(XML_RWLOCK); return status; } @@ -2367,14 +2390,34 @@ SWITCH_DECLARE(void) switch_xml_free(switch_xml_t xml) char **a, *s; switch_xml_t orig_xml; - tailrecurse: root = (switch_xml_root_t) xml; if (!xml) { return; } - if (xml == MAIN_XML_ROOT) { - switch_thread_rwlock_unlock(RWLOCK); + /* If xml is currenly the MAIN_XML_ROOT, dont even bother to check to empty it */ + if (switch_test_flag(xml, SWITCH_XML_ROOT)) { + switch_thread_rwlock_unlock(root->rwlock); + return; + } + + /* This is a trick to find if the struct is still in use or not */ + switch_mutex_lock(XML_FREE_LOCK); + if (xml->is_switch_xml_root_t == SWITCH_TRUE && root->is_main_xml_root == SWITCH_TRUE) { + switch_thread_rwlock_unlock(root->rwlock); + if (switch_thread_rwlock_trywrlock(root->rwlock) != SWITCH_STATUS_SUCCESS) { + /* XML Struct is still in used, person who free it will clean it */ + switch_mutex_unlock(XML_FREE_LOCK); + return; + } + switch_thread_rwlock_unlock(root->rwlock); + switch_thread_rwlock_destroy(root->rwlock); + } + switch_mutex_unlock(XML_FREE_LOCK); + + tailrecurse: + root = (switch_xml_root_t) xml; + if (!xml) { return; } @@ -2427,6 +2470,7 @@ SWITCH_DECLARE(void) switch_xml_free(switch_xml_t xml) } switch_xml_free_attr(xml->attr); /* tag attributes */ + if ((xml->flags & SWITCH_XML_TXTM)) free(xml->txt); /* character content */ if ((xml->flags & SWITCH_XML_NAMEM)) @@ -2464,6 +2508,8 @@ SWITCH_DECLARE(switch_xml_t) switch_xml_new(const char *name) root->ent = (char **) memcpy(malloc(sizeof(ent)), ent, sizeof(ent)); root->attr = root->pi = (char ***) (root->xml.attr = SWITCH_XML_NIL); root->xml.is_switch_xml_root_t = SWITCH_TRUE; + root->is_main_xml_root = SWITCH_FALSE; + switch_thread_rwlock_create(&root->rwlock, XML_MEMORY_POOL); return &root->xml; }