[asterisk-commits] mmichelson: branch group/CCSS_Monitor_Restructure r242033 - /team/group/CCSS_...

SVN commits to the Asterisk project asterisk-commits at lists.digium.com
Thu Jan 21 13:02:10 CST 2010


Author: mmichelson
Date: Thu Jan 21 13:02:06 2010
New Revision: 242033

URL: http://svnview.digium.com/svn/asterisk?view=rev&rev=242033
Log:
Add more places to call the monitor-less destructor.


Modified:
    team/group/CCSS_Monitor_Restructure/main/ccss.c

Modified: team/group/CCSS_Monitor_Restructure/main/ccss.c
URL: http://svnview.digium.com/svn/asterisk/team/group/CCSS_Monitor_Restructure/main/ccss.c?view=diff&rev=242033&r1=242032&r2=242033
==============================================================================
--- team/group/CCSS_Monitor_Restructure/main/ccss.c (original)
+++ team/group/CCSS_Monitor_Restructure/main/ccss.c Thu Jan 21 13:02:06 2010
@@ -1582,6 +1582,29 @@
 	char dialable_name[AST_CHANNEL_NAME];
 };
 
+/*!
+ * \internal
+ * \brief  Call a monitor's destructor before the monitor has been allocated
+ * \since 1.8
+ *
+ * \param monitor_type The type of monitor callbacks to use when calling the destructor
+ * \param private_data Data allocated by a channel driver that must be freed
+ *
+ * \details
+ * I'll admit, this is a bit evil.
+ *
+ * When a channel driver determines that it can offer a call completion service to
+ * a caller, it is very likely that the channel driver will need to allocate some
+ * data so that when the time comes to request CC, the channel driver will have the
+ * necessary data at hand.
+ *
+ * The problem is that there are many places where failures may occur before the monitor
+ * has been properly allocated and had its callbacks assigned to it. If one of these
+ * failures should occur, then we still need to let the channel driver know that it
+ * must destroy the data that it allocated.
+ *
+ * \return Nothing
+ */
 static void call_destructor_with_no_monitor(const char * const monitor_type, void *private_data)
 {
 	const struct ast_cc_monitor_callbacks *monitor_callbacks = find_monitor_callbacks(monitor_type);
@@ -1729,7 +1752,7 @@
 	core_instance = find_cc_core_instance(cc_interfaces->core_id);
 	if (!core_instance) {
 		core_instance = cc_core_init_instance(inbound, cc_interfaces->interface_tree,
-			cc_interfaces->core_id);
+			cc_interfaces->core_id, cc_data);
 		if (!core_instance) {
 			cc_interfaces->ignore = 1;
 			ast_channel_unlock(inbound);
@@ -2217,57 +2240,6 @@
 	ast_free(agent_pvt);
 }
 
-
-/*!
- * \internal
- * \brief Walk the CC interface tree and destroy monitor instances.
- * \since 1.8
- *
- * \param interface_tree Interface tree to kill any monitor instances.
- * \param core_id core_id of the CC transaction.
- *
- * \details
- * I'll admit, this is a bit evil.
- *
- * Picture the following scenario: A called party can support CC, so
- * it queues an AST_CONTROL_CC frame. Now, the channel driver will likely
- * need to retain some information about the call. This information is expected
- * to be destroyed when the monitor's destructor is called.
- * However, consider that the caller never requests CC (i.e.
- * the offer timer expires). In this case, the monitor never gets created,
- * and so the retained data in the called party's channel driver is leaked.
- *
- * The way that we deal with this scenario is to traverse the list of dialed
- * devices in the agent's interface_tree. Each device will have its monitor instance
- * destructor function called directly, even though no monitor was ever created.
- *
- * \return Nothing
- */
-static void kill_interface_tree_monitors(struct ast_cc_interface_tree *interface_tree, const int core_id)
-{
-	const struct ast_cc_monitor_callbacks *monitor_callbacks;
-	struct cc_monitor *monitor_iter;
-
-	/* Locking is necessary here since a channel thread could possibly be mucking
-	 * with this list while we try to traverse it
-	 */
-	AST_DLLIST_LOCK(interface_tree);
-	AST_DLLIST_TRAVERSE(interface_tree, monitor_iter, next) {
-		if (monitor_iter->interface->monitor_class == AST_CC_DEVICE_MONITOR) {
-			monitor_callbacks =
-				find_monitor_callbacks(monitor_iter->interface->monitor_type);
-			if (!monitor_callbacks) {
-				ast_log(LOG_WARNING,
-					"We may have a memory leak here. Couldn't find callbacks for monitor type %s\n",
-					monitor_iter->interface->monitor_type);
-				continue;
-			}
-			monitor_callbacks->instance_destructor(core_id);
-		}
-	}
-	AST_DLLIST_UNLOCK(interface_tree);
-}
-
 static void cc_core_instance_destructor(void *data)
 {
 	struct cc_core_instance *core_instance = data;
@@ -2281,7 +2253,7 @@
 }
 
 static struct cc_core_instance *cc_core_init_instance(struct ast_channel *caller_chan,
-		struct ast_cc_interface_tree *called_tree, const int core_id)
+		struct ast_cc_interface_tree *called_tree, const int core_id, struct ast_control_cc_payload *cc_data)
 {
 	char caller[AST_CHANNEL_NAME];
 	struct cc_core_instance *core_instance;
@@ -2301,33 +2273,33 @@
 	if (!cc_params) {
 		ast_log_dynamic_level(cc_logger_level, "Could not get CC parameters for %s\n",
 			caller);
-		kill_interface_tree_monitors(called_tree, core_id);
+		call_destructor_with_no_monitor(cc_data->monitor_type, cc_data->private_data);
 		return NULL;
 	}
 	agent_count = count_agents(caller, recall_core_id);
 	if (agent_count >= ast_get_cc_max_agents(cc_params)) {
 		ast_log_dynamic_level(cc_logger_level, "Caller %s already has the maximum number of agents configured\n", caller);
-		kill_interface_tree_monitors(called_tree, core_id);
+		call_destructor_with_no_monitor(cc_data->monitor_type, cc_data->private_data);
 		return NULL;
 	}
 
 	/* Generic agents can only have a single outstanding CC request per caller. */
 	if (agent_count > 0 && ast_get_cc_agent_policy(cc_params) == AST_CC_AGENT_GENERIC) {
 		ast_log_dynamic_level(cc_logger_level, "Generic agents can only have a single outstanding request\n");
-		kill_interface_tree_monitors(called_tree, core_id);
+		call_destructor_with_no_monitor(cc_data->monitor_type, cc_data->private_data);
 		return NULL;
 	}
 
 	/* Next, we need to create the core instance for this call */
 	if (!(core_instance = ao2_t_alloc(sizeof(*core_instance), cc_core_instance_destructor, "Creating core instance for CC"))) {
-		kill_interface_tree_monitors(called_tree, core_id);
+		call_destructor_with_no_monitor(cc_data->monitor_type, cc_data->private_data);
 		return NULL;
 	}
 
 	core_instance->core_id = core_id;
 	if (!(core_instance->agent = cc_agent_init(caller_chan, caller, core_instance->core_id, called_tree))) {
 		cc_unref(core_instance, "Couldn't allocate agent, unref core_instance");
-		kill_interface_tree_monitors(called_tree, core_id);
+		call_destructor_with_no_monitor(cc_data->monitor_type, cc_data->private_data);
 		return NULL;
 	}
 




More information about the asterisk-commits mailing list