[asterisk-commits] rmudgett: trunk r359981 - in /trunk: ./ include/asterisk/ main/

SVN commits to the Asterisk project asterisk-commits at lists.digium.com
Tue Mar 20 12:31:36 CDT 2012


Author: rmudgett
Date: Tue Mar 20 12:31:28 2012
New Revision: 359981

URL: http://svnview.digium.com/svn/asterisk?view=rev&rev=359981
Log:
Allow AMI action callback to be reentrant.

Fix AMI module reload deadlock regression from ASTERISK-18479 when it
tried to fix the race between calling an AMI action callback and
unregistering that action.  Refixes ASTERISK-13784 broken by
ASTERISK-17785 change.

Locking the ao2 object guaranteed that there were no active callbacks that
mattered when ast_manager_unregister() was called.  Unfortunately, this
causes the deadlock situation.  The patch stops locking the ao2 object to
allow multiple threads to invoke the callback re-entrantly.  There is no
way to guarantee a module unload will not crash because of an active
callback.  The code attempts to minimize the chance with the registered
flag and the maximum 5 second delay before ast_manager_unregister()
returns.

The trunk version of the patch changes the API to fix the race condition
correctly to prevent the module code from unloading from memory while an
action callback is active.

* Don't hold the lock while calling the AMI action callback.

(closes issue ASTERISK-19487)
Reported by: Philippe Lindheimer

Review: https://reviewboard.asterisk.org/r/1818/
Review: https://reviewboard.asterisk.org/r/1820/
........

Merged revisions 359979 from http://svn.asterisk.org/svn/asterisk/branches/1.8
........

Merged revisions 359980 from http://svn.asterisk.org/svn/asterisk/branches/10

Modified:
    trunk/   (props changed)
    trunk/include/asterisk/manager.h
    trunk/main/data.c
    trunk/main/db.c
    trunk/main/features.c
    trunk/main/manager.c
    trunk/main/pbx.c

Propchange: trunk/
------------------------------------------------------------------------------
Binary property 'branch-10-merged' - no diff available.

Modified: trunk/include/asterisk/manager.h
URL: http://svnview.digium.com/svn/asterisk/trunk/include/asterisk/manager.h?view=diff&rev=359981&r1=359980&r2=359981
==============================================================================
--- trunk/include/asterisk/manager.h (original)
+++ trunk/include/asterisk/manager.h Tue Mar 20 12:31:28 2012
@@ -149,6 +149,7 @@
 	int authority;
 	/*! Function to be called */
 	int (*func)(struct mansession *s, const struct message *m);
+	struct ast_module *module;		/*!< Module this action belongs to */
 	/*! Where the documentation come from. */
 	enum ast_doc_src docsrc;
 	/*! For easy linking */
@@ -164,29 +165,44 @@
 
 /*! \brief External routines may register/unregister manager callbacks this way 
  * \note  Use ast_manager_register2() to register with help text for new manager commands */
-#define ast_manager_register(a, b, c, d) ast_manager_register2(a, b, c, d, NULL)
+#define ast_manager_register(action, authority, func, synopsis) ast_manager_register2(action, authority, func, ast_module_info->self, synopsis, NULL)
 
 /*! \brief Register a manager callback using XML documentation to describe the manager. */
-#define ast_manager_register_xml(a, b, c) ast_manager_register2(a, b, c, NULL, NULL)
-
-/*! \brief Register a manager command with the manager interface 
- 	\param action Name of the requested Action:
-	\param authority Required authority for this command
-	\param func Function to call for this command
-	\param synopsis Help text (one line, up to 30 chars) for CLI manager show commands
-	\param description Help text, several lines
-*/
+#define ast_manager_register_xml(action, authority, func) ast_manager_register2(action, authority, func, ast_module_info->self, NULL, NULL)
+
+/*!
+ * \brief Register a manager callback using XML documentation to describe the manager.
+ *
+ * \note For Asterisk core modules that are not independently
+ * loadable.
+ *
+ * \warning If you use ast_manager_register_xml() instead when
+ * you need to use this function, Asterisk will crash on load.
+ */
+#define ast_manager_register_xml_core(action, authority, func) ast_manager_register2(action, authority, func, NULL, NULL, NULL)
+
+/*!
+ * \brief Register a manager command with the manager interface
+ * \param action Name of the requested Action:
+ * \param authority Required authority for this command
+ * \param func Function to call for this command
+ * \param module The module containing func.  (NULL if module is part of core and not loadable)
+ * \param synopsis Help text (one line, up to 30 chars) for CLI manager show commands
+ * \param description Help text, several lines
+ */
 int ast_manager_register2(
 	const char *action,
 	int authority,
 	int (*func)(struct mansession *s, const struct message *m),
+	struct ast_module *module,
 	const char *synopsis,
 	const char *description);
 
-/*! \brief Unregister a registered manager command 
-	\param action Name of registered Action:
-*/
-int ast_manager_unregister( char *action );
+/*!
+ * \brief Unregister a registered manager command
+ * \param action Name of registered Action:
+ */
+int ast_manager_unregister(const char *action);
 
 /*! 
  * \brief Verify a session's read permissions against a permission mask.  

Modified: trunk/main/data.c
URL: http://svnview.digium.com/svn/asterisk/trunk/main/data.c?view=diff&rev=359981&r1=359980&r2=359981
==============================================================================
--- trunk/main/data.c (original)
+++ trunk/main/data.c Tue Mar 20 12:31:28 2012
@@ -3319,7 +3319,7 @@
 
 	res |= ast_cli_register_multiple(cli_data, ARRAY_LEN(cli_data));
 
-	res |= ast_manager_register_xml("DataGet", 0, manager_data_get);
+	res |= ast_manager_register_xml_core("DataGet", 0, manager_data_get);
 
 #ifdef TEST_FRAMEWORK
 	AST_TEST_REGISTER(test_data_get);

Modified: trunk/main/db.c
URL: http://svnview.digium.com/svn/asterisk/trunk/main/db.c?view=diff&rev=359981&r1=359980&r2=359981
==============================================================================
--- trunk/main/db.c (original)
+++ trunk/main/db.c Tue Mar 20 12:31:28 2012
@@ -933,9 +933,9 @@
 
 	ast_register_atexit(astdb_atexit);
 	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);
-	ast_manager_register_xml("DBDel", EVENT_FLAG_SYSTEM, manager_dbdel);
-	ast_manager_register_xml("DBDelTree", EVENT_FLAG_SYSTEM, manager_dbdeltree);
+	ast_manager_register_xml_core("DBGet", EVENT_FLAG_SYSTEM | EVENT_FLAG_REPORTING, manager_dbget);
+	ast_manager_register_xml_core("DBPut", EVENT_FLAG_SYSTEM, manager_dbput);
+	ast_manager_register_xml_core("DBDel", EVENT_FLAG_SYSTEM, manager_dbdel);
+	ast_manager_register_xml_core("DBDelTree", EVENT_FLAG_SYSTEM, manager_dbdeltree);
 	return 0;
 }

Modified: trunk/main/features.c
URL: http://svnview.digium.com/svn/asterisk/trunk/main/features.c?view=diff&rev=359981&r1=359980&r2=359981
==============================================================================
--- trunk/main/features.c (original)
+++ trunk/main/features.c Tue Mar 20 12:31:28 2012
@@ -8193,9 +8193,9 @@
 	if (!res)
 		res = ast_register_application2(parkcall, park_call_exec, NULL, NULL, NULL);
 	if (!res) {
-		ast_manager_register_xml("ParkedCalls", 0, manager_parking_status);
-		ast_manager_register_xml("Park", EVENT_FLAG_CALL, manager_park);
-		ast_manager_register_xml("Bridge", EVENT_FLAG_CALL, action_bridge);
+		ast_manager_register_xml_core("ParkedCalls", 0, manager_parking_status);
+		ast_manager_register_xml_core("Park", EVENT_FLAG_CALL, manager_park);
+		ast_manager_register_xml_core("Bridge", EVENT_FLAG_CALL, action_bridge);
 	}
 
 	res |= ast_devstate_prov_add("Park", metermaidstate);

Modified: trunk/main/manager.c
URL: http://svnview.digium.com/svn/asterisk/trunk/main/manager.c?view=diff&rev=359981&r1=359980&r2=359981
==============================================================================
--- trunk/main/manager.c (original)
+++ trunk/main/manager.c Tue Mar 20 12:31:28 2012
@@ -1975,7 +1975,15 @@
 
 			ao2_lock(act_found);
 			if (act_found->registered && act_found->func) {
+				if (act_found->module) {
+					ast_module_ref(act_found->module);
+				}
+				ao2_unlock(act_found);
 				ret = act_found->func(&s, &m);
+				ao2_lock(act_found);
+				if (act_found->module) {
+					ast_module_unref(act_found->module);
+				}
 			} else {
 				ret = -1;
 			}
@@ -4789,8 +4797,16 @@
 			ao2_lock(act_found);
 			if (act_found->registered && act_found->func) {
 				ast_debug(1, "Running action '%s'\n", act_found->action);
+				if (act_found->module) {
+					ast_module_ref(act_found->module);
+				}
+				ao2_unlock(act_found);
 				ret = act_found->func(s, m);
 				acted = 1;
+				ao2_lock(act_found);
+				if (act_found->module) {
+					ast_module_unref(act_found->module);
+				}
 			}
 			ao2_unlock(act_found);
 		}
@@ -5283,7 +5299,7 @@
 /*! \brief
  * support functions to register/unregister AMI action handlers,
  */
-int ast_manager_unregister(char *action)
+int ast_manager_unregister(const char *action)
 {
 	struct manager_action *cur;
 
@@ -5378,7 +5394,7 @@
 
 /*! \brief register a new command with manager, including online help. This is
 	the preferred way to register a manager command */
-int ast_manager_register2(const char *action, int auth, int (*func)(struct mansession *s, const struct message *m), const char *synopsis, const char *description)
+int ast_manager_register2(const char *action, int auth, int (*func)(struct mansession *s, const struct message *m), struct ast_module *module, const char *synopsis, const char *description)
 {
 	struct manager_action *cur;
 
@@ -5394,6 +5410,7 @@
 	cur->action = action;
 	cur->authority = auth;
 	cur->func = func;
+	cur->module = module;
 #ifdef AST_XML_DOCS
 	if (ast_strlen_zero(synopsis) && ast_strlen_zero(description)) {
 		char *tmpxml;
@@ -6658,40 +6675,40 @@
 
 	if (!registered) {
 		/* Register default actions */
-		ast_manager_register_xml("Ping", 0, action_ping);
-		ast_manager_register_xml("Events", 0, action_events);
-		ast_manager_register_xml("Logoff", 0, action_logoff);
-		ast_manager_register_xml("Login", 0, action_login);
-		ast_manager_register_xml("Challenge", 0, action_challenge);
-		ast_manager_register_xml("Hangup", EVENT_FLAG_SYSTEM | EVENT_FLAG_CALL, action_hangup);
-		ast_manager_register_xml("Status", EVENT_FLAG_SYSTEM | EVENT_FLAG_CALL | EVENT_FLAG_REPORTING, action_status);
-		ast_manager_register_xml("Setvar", EVENT_FLAG_CALL, action_setvar);
-		ast_manager_register_xml("Getvar", EVENT_FLAG_CALL | EVENT_FLAG_REPORTING, action_getvar);
-		ast_manager_register_xml("GetConfig", EVENT_FLAG_SYSTEM | EVENT_FLAG_CONFIG, action_getconfig);
-		ast_manager_register_xml("GetConfigJSON", EVENT_FLAG_SYSTEM | EVENT_FLAG_CONFIG, action_getconfigjson);
-		ast_manager_register_xml("UpdateConfig", EVENT_FLAG_CONFIG, action_updateconfig);
-		ast_manager_register_xml("CreateConfig", EVENT_FLAG_CONFIG, action_createconfig);
-		ast_manager_register_xml("ListCategories", EVENT_FLAG_CONFIG, action_listcategories);
-		ast_manager_register_xml("Redirect", EVENT_FLAG_CALL, action_redirect);
-		ast_manager_register_xml("Atxfer", EVENT_FLAG_CALL, action_atxfer);
-		ast_manager_register_xml("Originate", EVENT_FLAG_ORIGINATE, action_originate);
-		ast_manager_register_xml("Command", EVENT_FLAG_COMMAND, action_command);
-		ast_manager_register_xml("ExtensionState", EVENT_FLAG_CALL | EVENT_FLAG_REPORTING, action_extensionstate);
-		ast_manager_register_xml("AbsoluteTimeout", EVENT_FLAG_SYSTEM | EVENT_FLAG_CALL, action_timeout);
-		ast_manager_register_xml("MailboxStatus", EVENT_FLAG_CALL | EVENT_FLAG_REPORTING, action_mailboxstatus);
-		ast_manager_register_xml("MailboxCount", EVENT_FLAG_CALL | EVENT_FLAG_REPORTING, action_mailboxcount);
-		ast_manager_register_xml("ListCommands", 0, action_listcommands);
-		ast_manager_register_xml("SendText", EVENT_FLAG_CALL, action_sendtext);
-		ast_manager_register_xml("UserEvent", EVENT_FLAG_USER, action_userevent);
-		ast_manager_register_xml("WaitEvent", 0, action_waitevent);
-		ast_manager_register_xml("CoreSettings", EVENT_FLAG_SYSTEM | EVENT_FLAG_REPORTING, action_coresettings);
-		ast_manager_register_xml("CoreStatus", EVENT_FLAG_SYSTEM | EVENT_FLAG_REPORTING, action_corestatus);
-		ast_manager_register_xml("Reload", EVENT_FLAG_CONFIG | EVENT_FLAG_SYSTEM, action_reload);
-		ast_manager_register_xml("CoreShowChannels", EVENT_FLAG_SYSTEM | EVENT_FLAG_REPORTING, action_coreshowchannels);
-		ast_manager_register_xml("ModuleLoad", EVENT_FLAG_SYSTEM, manager_moduleload);
-		ast_manager_register_xml("ModuleCheck", EVENT_FLAG_SYSTEM, manager_modulecheck);
-		ast_manager_register_xml("AOCMessage", EVENT_FLAG_AOC, action_aocmessage);
-		ast_manager_register_xml("Filter", EVENT_FLAG_SYSTEM, action_filter);
+		ast_manager_register_xml_core("Ping", 0, action_ping);
+		ast_manager_register_xml_core("Events", 0, action_events);
+		ast_manager_register_xml_core("Logoff", 0, action_logoff);
+		ast_manager_register_xml_core("Login", 0, action_login);
+		ast_manager_register_xml_core("Challenge", 0, action_challenge);
+		ast_manager_register_xml_core("Hangup", EVENT_FLAG_SYSTEM | EVENT_FLAG_CALL, action_hangup);
+		ast_manager_register_xml_core("Status", EVENT_FLAG_SYSTEM | EVENT_FLAG_CALL | EVENT_FLAG_REPORTING, action_status);
+		ast_manager_register_xml_core("Setvar", EVENT_FLAG_CALL, action_setvar);
+		ast_manager_register_xml_core("Getvar", EVENT_FLAG_CALL | EVENT_FLAG_REPORTING, action_getvar);
+		ast_manager_register_xml_core("GetConfig", EVENT_FLAG_SYSTEM | EVENT_FLAG_CONFIG, action_getconfig);
+		ast_manager_register_xml_core("GetConfigJSON", EVENT_FLAG_SYSTEM | EVENT_FLAG_CONFIG, action_getconfigjson);
+		ast_manager_register_xml_core("UpdateConfig", EVENT_FLAG_CONFIG, action_updateconfig);
+		ast_manager_register_xml_core("CreateConfig", EVENT_FLAG_CONFIG, action_createconfig);
+		ast_manager_register_xml_core("ListCategories", EVENT_FLAG_CONFIG, action_listcategories);
+		ast_manager_register_xml_core("Redirect", EVENT_FLAG_CALL, action_redirect);
+		ast_manager_register_xml_core("Atxfer", EVENT_FLAG_CALL, action_atxfer);
+		ast_manager_register_xml_core("Originate", EVENT_FLAG_ORIGINATE, action_originate);
+		ast_manager_register_xml_core("Command", EVENT_FLAG_COMMAND, action_command);
+		ast_manager_register_xml_core("ExtensionState", EVENT_FLAG_CALL | EVENT_FLAG_REPORTING, action_extensionstate);
+		ast_manager_register_xml_core("AbsoluteTimeout", EVENT_FLAG_SYSTEM | EVENT_FLAG_CALL, action_timeout);
+		ast_manager_register_xml_core("MailboxStatus", EVENT_FLAG_CALL | EVENT_FLAG_REPORTING, action_mailboxstatus);
+		ast_manager_register_xml_core("MailboxCount", EVENT_FLAG_CALL | EVENT_FLAG_REPORTING, action_mailboxcount);
+		ast_manager_register_xml_core("ListCommands", 0, action_listcommands);
+		ast_manager_register_xml_core("SendText", EVENT_FLAG_CALL, action_sendtext);
+		ast_manager_register_xml_core("UserEvent", EVENT_FLAG_USER, action_userevent);
+		ast_manager_register_xml_core("WaitEvent", 0, action_waitevent);
+		ast_manager_register_xml_core("CoreSettings", EVENT_FLAG_SYSTEM | EVENT_FLAG_REPORTING, action_coresettings);
+		ast_manager_register_xml_core("CoreStatus", EVENT_FLAG_SYSTEM | EVENT_FLAG_REPORTING, action_corestatus);
+		ast_manager_register_xml_core("Reload", EVENT_FLAG_CONFIG | EVENT_FLAG_SYSTEM, action_reload);
+		ast_manager_register_xml_core("CoreShowChannels", EVENT_FLAG_SYSTEM | EVENT_FLAG_REPORTING, action_coreshowchannels);
+		ast_manager_register_xml_core("ModuleLoad", EVENT_FLAG_SYSTEM, manager_moduleload);
+		ast_manager_register_xml_core("ModuleCheck", EVENT_FLAG_SYSTEM, manager_modulecheck);
+		ast_manager_register_xml_core("AOCMessage", EVENT_FLAG_AOC, action_aocmessage);
+		ast_manager_register_xml_core("Filter", EVENT_FLAG_SYSTEM, action_filter);
 
 		ast_cli_register_multiple(cli_manager, ARRAY_LEN(cli_manager));
 		ast_extension_state_add(NULL, NULL, manager_state_cb, NULL);

Modified: trunk/main/pbx.c
URL: http://svnview.digium.com/svn/asterisk/trunk/main/pbx.c?view=diff&rev=359981&r1=359980&r2=359981
==============================================================================
--- trunk/main/pbx.c (original)
+++ trunk/main/pbx.c Tue Mar 20 12:31:28 2012
@@ -10469,7 +10469,7 @@
 	}
 
 	/* Register manager application */
-	ast_manager_register_xml("ShowDialPlan", EVENT_FLAG_CONFIG | EVENT_FLAG_REPORTING, manager_show_dialplan);
+	ast_manager_register_xml_core("ShowDialPlan", EVENT_FLAG_CONFIG | EVENT_FLAG_REPORTING, manager_show_dialplan);
 
 	if (!(device_state_sub = ast_event_subscribe(AST_EVENT_DEVICE_STATE, device_state_cb, "pbx Device State Change", NULL,
 			AST_EVENT_IE_END))) {




More information about the asterisk-commits mailing list