[svn-commits] dvossel: branch dvossel/awesomehooks r287191 - in /team/dvossel/awesomehooks:...

SVN commits to the Digium repositories svn-commits at lists.digium.com
Thu Sep 16 15:35:57 CDT 2010


Author: dvossel
Date: Thu Sep 16 15:35:53 2010
New Revision: 287191

URL: http://svnview.digium.com/svn/asterisk?view=rev&rev=287191
Log:
awesomehooks are now represented by an id outside of the awesomehook api.

Modified:
    team/dvossel/awesomehooks/include/asterisk/awesomehook.h
    team/dvossel/awesomehooks/main/awesomehook.c

Modified: team/dvossel/awesomehooks/include/asterisk/awesomehook.h
URL: http://svnview.digium.com/svn/asterisk/team/dvossel/awesomehooks/include/asterisk/awesomehook.h?view=diff&rev=287191&r1=287190&r2=287191
==============================================================================
--- team/dvossel/awesomehooks/include/asterisk/awesomehook.h (original)
+++ team/dvossel/awesomehooks/include/asterisk/awesomehook.h Thu Sep 16 15:35:53 2010
@@ -26,25 +26,22 @@
 #include "asterisk/frame.h"
 #include "asterisk/channel.h"
 
+struct ast_awesomehook;
+
 struct ast_awesomehook_list {
+	unsigned int id_count;
 	AST_LIST_HEAD_NOLOCK(, ast_awesomehook) list;
 };
 
-enum ast_awesomehook_status {
-	AST_AWESOMEHOOK_STATUS_INIT,
-	AST_AWESOMEHOOK_STATUS_ATTACHED,
-	AST_AWESOMEHOOK_STATUS_DETACHED
-};
-
+/*!
+ * \brief These are the types of events that the awesomehook's event callback can receive
+ */
 enum ast_awesomehook_event {
-	AST_AWESOMEHOOK_EVENT_NOOP, /*!< This is a NO-OP event. It only exists to initilized the awesomehook->last_event variable*/
 	AST_AWESOMEHOOK_EVENT_READ, /*!< frame is intercepted in the read direction on the channel. */
 	AST_AWESOMEHOOK_EVENT_WRITE, /*!< frame is intercepted on the write direction on the channel. */
-	AST_AWESOMEHOOK_EVENT_ATTACHED, /*!< the awesomehook is attached and running on the channel. */
-	AST_AWESOMEHOOK_EVENT_DETACHED /*!< the awesomehook is detached from the channel. */
+	AST_AWESOMEHOOK_EVENT_ATTACHED, /*!< awesomehook is attached and running on the channel, the first message sent to event_cb. */
+	AST_AWESOMEHOOK_EVENT_DETACHED /*!< awesomehook is detached from the channel, last message sent to event_cb. */
 };
-
-struct ast_awesomehook;
 
 /*!
  * \brief This callback is called every time an event occurs on the awesomehook.
@@ -55,85 +52,84 @@
  * AST_AWESOMEHOOK_EVENT_DETACHED, which occurs right after the awesomehook is 
  * detached.
  *
- * It is _NOT_ safe to assume the channel or the frame are ever not NULL. Always perform
- * a NULL check before performing any action on either of these objects.
+ * It is completely valid for the frame variable to be set to NULL. Always do a NULL
+ * check on the frame before attempted to access it. When the frame variable is present,
+ * it is safe to view and manipulate that frame in any way possible.  It is even safe
+ * to return a completely different frame, but when that occurs this function is in
+ * charge of freeing the previous frame.
  *
- * When the channel variable is present, it is safe to assume it will always be locked.
- * Never attempt to unlock the channel variable during this callback.
+ * The ast_channel will always be locked during this callback. Never attempt to unlock the
+ * channel for any reason.
  *
- * When the frame variable is present, it is safe to view and manipulate that frame
- * in any way possible.  It is even safe to return a completely different frame, but
- * when that occurs this function is in charge of freeing the previous frame.
- *
- * \param awesomehook, The awesomehook associated with this callback.
- * \param channel, The ast_channel this awesomehook is attached to.
+ * \param channel, The ast_channel this awesomehook is attached to
  * \param frame, The ast_frame being intercepted for viewing and manipulation
  * \param event, The type of event which is occurring
+ * \param datastore, The datastore pointer provided at awesomehook initilization.
  *
  * \retval the resulting frame.
  */
-typedef struct ast_frame *(*ast_awesomehook_event_callback)(struct ast_awesomehook *awesomehook,
+typedef struct ast_frame *(*ast_awesomehook_event_callback)(
 	struct ast_channel *chan,
 	struct ast_frame *frame,
-	enum ast_awesomehook_event event);
+	enum ast_awesomehook_event event,
+	void *datastore);
 
 /*!
  * \brief This callback is called immediately before the awesomehook is destroyed.
  * \note  This function should be used to clean up any pointers pointing to the
  * awesomehook structure as the awesomehook will be freed immediately afterwards.
+ *
+ * \param datastore, The datastore pointer provided at awesomehook initilization. This
+ * is a good place to clean up any state data allocated for the awesomehook stored in this
+ * pointer.
  */
-typedef int (*ast_awesomehook_destroy_callback)(struct ast_awesomehook *awesomehook);
-
-/*!
- * \brief Initialize a new awesomehook structure.
- *
- * \param event_cb represents the function that will be called everytime an
- * event occurs on the awesomehook.
- * \param destroy_cb is option.  This function is called immediately before the
- * awesomehook is destroyed so cleanup can occur.
- *
- * \retval pointer to allocated awesomehook on Success.
- * \retval NULL on failure.
- */
-struct ast_awesomehook *ast_awesomehook_alloc(
-	ast_awesomehook_event_callback event_cb,
-	ast_awesomehook_destroy_callback destroy_cb);
+typedef void (*ast_awesomehook_destroy_callback)(void *datastore);
 
 /*!
  * \brief Attach an awesomehook onto a channel for frame interception.
  *
- * \param ast_awesomehook to attach
- * \param ast_channel to attached the awesomehook onto.
- * \retval 0 success
- * \retval -1 failure
+ * \param ast_channel, The channel to attach the hook on to.
+ * \param event_cb represents the function that will be called everytime an
+ * event occurs on the awesomehook.
+ * \param destroy_cb is optional.  This function is called immediately before the
+ * awesomehook is destroyed to allow for datastore cleanup.
+ * \param Any custom data to be stored on the awesomehook. This data pointer will
+ * be provided during each event callback which allows the awesomehook to store any
+ * stateful data associated with the application using the hook.
+ *
+ * \note XXX The Channel must be locked during this function all.
+ *
+ * \note The datastore pointer is never touched by the awesomehook API except to
+ * provide it during the event and destruction callbacks.  It is entirely up to the
+ * application using this API to manage the memory associated with the datastore pointer.
+ *
+ * \retval On success, positive id representing this hook on the channel 
+ * \retval On failure, -1
  */
-int ast_awesomehook_attach(struct ast_awesomehook *awesomehook, struct ast_channel *chan);
+int ast_awesomehook_attach(
+	struct ast_channel *chan,
+	ast_awesomehook_event_callback event_cb,
+	ast_awesomehook_destroy_callback destroy_cb,
+	void *datastore);
 
 /*!
- * \brief Mark awesomehook for channel detachment and destruction.
+ * \brief Detach an awesomehook from a channel.
+ * 
+ * \note XXX The Channel must be locked during this function all.
  *
- * \note This function is marks the awesomehook for removal and destruction
- * by the channel thread.  Once the actual destruction takes place the
- * awesomehook's destroy callback function will be called allowing for
- * any necessary cleanup to occur.
+ * \param The channel the awesomehook is attached to
+ * \param The awesomehook's id
  *
- * \note After this function is used on a awesomehook, that awesomehook
- * is effectively done.  It can never be re-attached to another channel.
- * The applications using the awesomehook will be still be notified via
- * the destroy_cb function once the actual destruction takes place.
- *
- * \param awesomehook to mark for detachment.
  * \retval 0 success
- * \retval -1 failure
+ * \retval -1 awesomehook did not exist on the channel
  */
-int ast_awesomehook_signal_destroy(struct ast_awesomehook *awesomehook);
+int ast_awesomehook_detach(struct ast_channel *chan, int awesomehook_id);
 
 /*!
  * \brief This is used by the channel API to detach and destroy all
  * awesomehooks on a channel during channel destruction.
  *
- * \note XXX READ THIS! This function should only be used by the
- * Channel API. Do not call this outside the channel API.
+ * \note XXX The Channel must be locked during this function all.
  * 
  * \param awesomehook list to destroy 
  * \retval 0 success
@@ -148,7 +144,7 @@
  * even NULL.  There is nothing to keep up with after this function. If the frame is modified, the
  * awesomehook callback is in charge of any memory management associated with that modification.
  *
- * \note the list's channel owner _MUST_ be locked while calling this function.
+ * \note XXX The Channel must be locked during this function all.
  *
  * \param awesomehook list to push event to.
  * \param frame being pushed to the awesomehook list.
@@ -164,7 +160,7 @@
  * even NULL.  There is nothing to keep up with after this function. If the frame is modified, the
  * awesomehook callback is in charge of any memory management associated with that modification.
  *
- * \note the list's channel owner _MUST_ be locked while calling this function.
+ * \note XXX The Channel must be locked during this function all.
  *
  * \param awesomehook list to push event to.
  * \param frame being pushed to the awesomehook list.
@@ -175,26 +171,12 @@
 
 /*!
  * \brief Determine if an awesomehook list is empty or not
+ *
+ * \note XXX The Channel must be locked during this function all.
+ *
  * \param the awesomehook list
  * \retval 0, not empty
  * \retval 1, is empty
  */
 int ast_awesomehook_list_is_empty(struct ast_awesomehook_list *awesomehooks);
-
-/*!
- * \brief Set the awesomehook's custom data storage pointer.
- *
- * \note A custom data pointer can be stored on an awesomehook.  This allows
- * for any stateful data the event_callback may need to be sorted directly on
- * the awesomehook.
- */
-int ast_awesomehook_set_datastore(struct ast_awesomehook *awesomehook, void *data);
-
-/*!
- * \brief Return the awesomehook's custom data storage pointer.
- *
- * \return A pointer to the awesomehook's datastore data.
- */
-void *ast_awesomehook_get_datastore(struct ast_awesomehook *awesomehook);
-
 #endif /* _AST_AWESOMEHOOK_H */

Modified: team/dvossel/awesomehooks/main/awesomehook.c
URL: http://svnview.digium.com/svn/asterisk/team/dvossel/awesomehooks/main/awesomehook.c?view=diff&rev=287191&r1=287190&r2=287191
==============================================================================
--- team/dvossel/awesomehooks/main/awesomehook.c (original)
+++ team/dvossel/awesomehooks/main/awesomehook.c Thu Sep 16 15:35:53 2010
@@ -28,24 +28,17 @@
 ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
 
 #include "asterisk/channel.h"
-#include "asterisk/lock.h"
 #include "asterisk/linkedlists.h"
 #include "asterisk/awesomehook.h"
 #include "asterisk/frame.h"
 
-#define ast_awesomehook_lock(ah) ast_mutex_lock(&(ah)->lock)
-#define ast_awesomehook_unlock(ah) ast_mutex_unlock(&(ah)->lock)
-
 struct ast_awesomehook {
-	ast_mutex_t lock;
-	/*! Current awesomehook status. */
-	enum ast_awesomehook_status status;
-	/*! The last event type that went to the awesomehook event callback */
-	enum ast_awesomehook_event last_event;
 	/*! This pointer holds any stateful data an application wishes to store. */
 	void *datastore;
 	/*! This pointer to ast_channel the awesomehook is attached to. */
 	struct ast_channel *chan;
+	/*! the id representing this awesomehook on a channel */
+	unsigned int id;
 	/*! Pointer to the registered event callback function. */
 	ast_awesomehook_event_callback event_cb;
 	/*! Pointer to the registered destruction callback function. */
@@ -54,100 +47,75 @@
 	AST_LIST_ENTRY(ast_awesomehook) list;
 };
 
-static void awesomehook_update_status(struct ast_awesomehook *awesomehook, enum ast_awesomehook_status status)
-{
-	/* once the status is set as DETACHED, it is forever detached and ready for destruction */
-	if (awesomehook->status == AST_AWESOMEHOOK_STATUS_DETACHED) {
-		return;
-	}
-	ast_awesomehook_lock(awesomehook);
-	awesomehook->status = status;
-	ast_awesomehook_unlock(awesomehook);
-}
-
-static int awesomehook_destroy(struct ast_awesomehook *awesomehook)
-{
-	if (awesomehook->destroy_cb) {
-		awesomehook->destroy_cb(awesomehook);
-	}
-	ast_mutex_destroy(&awesomehook->lock);
-	ast_free(awesomehook);
-	return 0;
-}
-
 static void awesomehook_detach_and_destroy(struct ast_awesomehook *awesomehook)
 {
 	struct ast_frame *frame;
-	awesomehook_update_status(awesomehook, AST_AWESOMEHOOK_STATUS_DETACHED);
-	frame = awesomehook->event_cb(awesomehook, awesomehook->chan, NULL, AST_AWESOMEHOOK_EVENT_DETACHED);
+	frame = awesomehook->event_cb(awesomehook->chan, NULL, AST_AWESOMEHOOK_EVENT_DETACHED, awesomehook->datastore);
 	/* never assume anything about this function. If you can return a frame during
 	 * the detached event, then assume someone will. */
 	if (frame) {
 		ast_frfree(frame);
 	}
 	awesomehook->chan = NULL;
-	awesomehook_destroy(awesomehook);
+
+	if (awesomehook->destroy_cb) {
+		awesomehook->destroy_cb(awesomehook->datastore);
+	}
+	ast_free(awesomehook);
 }
 
 static struct ast_frame *awesomehook_list_push_event(struct ast_awesomehook_list *awesomehooks, struct ast_frame *frame, enum ast_awesomehook_event event)
 {
 	struct ast_awesomehook *awesomehook;
-	AST_LIST_TRAVERSE_SAFE_BEGIN(&awesomehooks->list, awesomehook, list) {
-		/* check to see if this hook was signaled for detachment, if so do not push the
-		 * read/write event.  Instead detach from list and destroy */
-		if (awesomehook->status == AST_AWESOMEHOOK_STATUS_DETACHED) {
-			AST_LIST_REMOVE_CURRENT(list);
-			awesomehook_detach_and_destroy(awesomehook);
-			continue;
-		}
-		frame = awesomehook->event_cb(awesomehook, awesomehook->chan, frame, event);
+	AST_LIST_TRAVERSE(&awesomehooks->list, awesomehook, list) {
+		frame = awesomehook->event_cb(awesomehook->chan, frame, event, awesomehook->datastore);
 	}
-	AST_LIST_TRAVERSE_SAFE_END;
-
 	return frame;
 }
 
-struct ast_awesomehook *ast_awesomehook_alloc(ast_awesomehook_event_callback event_cb, ast_awesomehook_destroy_callback destroy_cb)
+int ast_awesomehook_attach(struct ast_channel *chan, ast_awesomehook_event_callback event_cb, ast_awesomehook_destroy_callback destroy_cb, void *data)
 {
 	struct ast_awesomehook *awesomehook;
+	struct ast_frame *frame;
 	if (!event_cb || !(awesomehook = ast_calloc(1, sizeof(*awesomehook)))) {
-		return NULL;
+		return -1;
 	}
 	awesomehook->event_cb = event_cb;
 	awesomehook->destroy_cb = destroy_cb;
-	awesomehook->status = AST_AWESOMEHOOK_STATUS_INIT;
-	awesomehook->last_event = AST_AWESOMEHOOK_EVENT_NOOP;
-	ast_mutex_init(&awesomehook->lock);
-	return awesomehook;
-}
+	awesomehook->datastore = data;
+	awesomehook->chan = chan;
+	awesomehook->id = ++chan->awesomehooks.id_count;
 
-int ast_awesomehook_attach(struct ast_awesomehook *awesomehook, struct ast_channel *chan)
-{
-	struct ast_frame *frame;
-	ast_channel_lock(chan);
 	AST_LIST_INSERT_TAIL(&chan->awesomehooks.list, awesomehook, list);
-	awesomehook->chan = chan;
-	ast_channel_unlock(chan);
 
-	awesomehook_update_status(awesomehook, AST_AWESOMEHOOK_STATUS_ATTACHED);
+	/* Tell the event callback we're live and rocking */
+	frame = awesomehook->event_cb(awesomehook->chan, NULL, AST_AWESOMEHOOK_EVENT_ATTACHED, awesomehook->datastore);
 
-	/* tell the event callback we're live and rocking */
-	frame = awesomehook->event_cb(awesomehook, awesomehook->chan, NULL, AST_AWESOMEHOOK_EVENT_ATTACHED);
-
-	/* never assume anything about this function. If you can return a frame during
+	/* Never assume anything about this function. If you can return a frame during
 	 * the attached event, then assume someone will. */
 	if (frame) {
 		ast_frfree(frame);
 	}
 
-	return 0;
+	return awesomehook->id;
 }
 
-int ast_awesomehook_signal_destroy(struct ast_awesomehook *awesomehook)
+int ast_awesomehook_detach(struct ast_channel *chan, int id)
 {
-	/* This signals to the channel to detach and destroy the hook on the next read or write */
-	awesomehook_update_status(awesomehook, AST_AWESOMEHOOK_STATUS_DETACHED);
-	return 0;
+	struct ast_awesomehook *awesomehook;
+	int res = -1;
+
+	AST_LIST_TRAVERSE_SAFE_BEGIN(&chan->awesomehooks.list, awesomehook, list) {
+		if (awesomehook->id == id) {
+			AST_LIST_REMOVE_CURRENT(list);
+			awesomehook_detach_and_destroy(awesomehook);
+			res = 0;
+			break;
+		}
+	}
+	AST_LIST_TRAVERSE_SAFE_END;
+
+	return res;
 }
 
 int ast_awesomehook_list_destroy(struct ast_awesomehook_list *awesomehooks)
@@ -163,7 +131,6 @@
 	return 0;
 }
 
-
 int ast_awesomehook_list_is_empty(struct ast_awesomehook_list *awesomehooks)
 {
 	return AST_LIST_EMPTY(&awesomehooks->list) ? 1 : 0;
@@ -178,14 +145,3 @@
 {
 	return awesomehook_list_push_event(awesomehooks, frame, AST_AWESOMEHOOK_EVENT_READ);
 }
-
-int ast_awesomehook_set_datastore(struct ast_awesomehook *awesomehook, void *data)
-{
-	awesomehook->datastore = data;
-	return 0;
-}
-
-void *ast_awesomehook_get_datastore(struct ast_awesomehook *awesomehook)
-{
-	return awesomehook->datastore;
-}




More information about the svn-commits mailing list