From 004c2e0cb4da35e2d26ffa30310921515bc2ee6e Mon Sep 17 00:00:00 2001 From: Timo Dritschler Date: Wed, 11 Feb 2015 16:44:53 +0100 Subject: Finished implementation of KiroSyncBuffer class --- src/kiro-sb.c | 171 ++++++++++++++++++++++++++++++++++++++++++++++++++-------- src/kiro-sb.h | 163 +++++++++++++++++++++++++++++++++++++++++++++++++++++-- 2 files changed, 306 insertions(+), 28 deletions(-) diff --git a/src/kiro-sb.c b/src/kiro-sb.c index 10a36b0..c0487e0 100644 --- a/src/kiro-sb.c +++ b/src/kiro-sb.c @@ -58,6 +58,9 @@ struct _KiroSbPrivate { GThread *main_thread; // Main thread for the main_loop GMainLoop *main_loop; // main_loop *duh* guint close_signal; // Used to signal shutdown of the main_loop + gboolean freeze; // Allows to prevent auto-sync + + GHookList callbacks; // List of registerd sync-callbacks }; @@ -91,6 +94,8 @@ kiro_sb_init (KiroSb *self) priv->trb = NULL; priv->server = NULL; priv->client = NULL; + priv->freeze = FALSE; + g_hook_list_init (&(priv->callbacks), sizeof (GHook)); } @@ -99,22 +104,8 @@ kiro_sb_finalize (GObject *object) { g_return_if_fail (object != NULL); KiroSb *self = KIRO_SB (object); - KiroSbPrivate *priv = KIRO_SB_GET_PRIVATE (self); - - if (priv->trb) { - kiro_trb_purge (priv->trb, FALSE); - kiro_trb_free (priv->trb); - } - if (priv->server) - kiro_server_free (priv->server); - - if (priv->client) - kiro_client_free (priv->client); - - priv->trb = NULL; - priv->server = NULL; - priv->client = NULL; + kiro_sb_stop (self); G_OBJECT_CLASS (kiro_sb_parent_class)->finalize (object); } @@ -130,6 +121,44 @@ kiro_sb_class_init (KiroSbClass *klass) } +void +kiro_sb_stop (KiroSb *self) +{ + g_return_if_fail (self != NULL); + KiroSbPrivate *priv = KIRO_SB_GET_PRIVATE (self); + + g_return_if_fail (priv->initialized != 0); + + if (priv->initialized == 1) { + if (priv->server) + kiro_server_free (priv->server); + } + + if (priv->initialized == 2) { + priv->close_signal = TRUE; + while (g_main_loop_is_running (priv->main_loop)) {} + g_thread_join (priv->main_thread); + g_thread_unref (priv->main_thread); + priv->main_thread = NULL; + + if (priv->client) + kiro_client_free (priv->client); + } + + g_hook_list_clear (&(priv->callbacks)); + + if (priv->trb) { + kiro_trb_purge (priv->trb, FALSE); + kiro_trb_free (priv->trb); + } + + priv->trb = NULL; + priv->server = NULL; + priv->client = NULL; + priv->initialized = 0; +} + + gpointer start_main_loop (GMainLoop *loop) { @@ -151,21 +180,43 @@ idle_func (KiroSbPrivate *priv) return G_SOURCE_REMOVE; } + if (TRUE == priv->freeze) + return G_SOURCE_CONTINUE; + struct KiroTrbInfo *header = (struct KiroTrbInfo *)kiro_trb_get_raw_buffer (priv->trb); gulong old_offset = header->offset; kiro_client_sync_partial (priv->client, 0, sizeof(struct KiroTrbInfo), 0); kiro_trb_refresh (priv->trb); - if (old_offset != header->offset) { - g_debug ("Fetching new element"); - gulong offset = (gulong) (kiro_trb_get_element (priv->trb, -1) - kiro_trb_get_raw_buffer (priv->trb)); - kiro_client_sync_partial (priv->client, offset, kiro_trb_get_element_size (priv->trb), offset); - /*INVOKE callback*/ + if ((old_offset != header->offset) && 0 < header->offset) { + gulong offset = (gulong) (kiro_trb_get_element (priv->trb, 1) - kiro_trb_get_raw_buffer (priv->trb)); + kiro_client_sync_partial (priv->client, offset, kiro_trb_get_element_size (priv->trb), offset); + g_hook_list_invoke_check (&(priv->callbacks), FALSE); } return G_SOURCE_CONTINUE; } +void +kiro_sb_freeze (KiroSb *self) +{ + g_return_if_fail (self != NULL); + KiroSbPrivate *priv = KIRO_SB_GET_PRIVATE (self); + + priv->freeze = TRUE; +} + + +void +kiro_sb_thaw (KiroSb *self) +{ + g_return_if_fail (self != NULL); + KiroSbPrivate *priv = KIRO_SB_GET_PRIVATE (self); + + priv->freeze = FALSE; +} + + gboolean kiro_sb_serve (KiroSb *self, gulong size) { @@ -176,7 +227,7 @@ kiro_sb_serve (KiroSb *self, gulong size) g_return_val_if_fail ((priv->trb = kiro_trb_new ()), FALSE); - if (0 > kiro_trb_reshape (priv->trb, size, 3)) { + if (0 > kiro_trb_reshape (priv->trb, size, 2)) { g_debug ("Failed to create KIRO ring buffer"); kiro_trb_free (priv->trb); return FALSE; @@ -200,6 +251,46 @@ kiro_sb_serve (KiroSb *self, gulong size) } +void * +kiro_sb_get_data (KiroSb *self) +{ + g_return_val_if_fail (self != NULL, NULL); + + KiroSbPrivate *priv = KIRO_SB_GET_PRIVATE (self); + g_return_val_if_fail (priv->initialized != 2, NULL); + + struct KiroTrbInfo *header = kiro_trb_get_raw_buffer (priv->trb); + if (header->offset > 1) + return kiro_trb_get_element (priv->trb, 1); + else + return kiro_trb_get_element (priv->trb, 0); +} + + +gboolean +kiro_sb_push (KiroSb *self, void *data_in) +{ + g_return_val_if_fail (self != NULL, FALSE); + + KiroSbPrivate *priv = KIRO_SB_GET_PRIVATE (self); + g_return_val_if_fail (priv->initialized != 1, FALSE); + + return kiro_trb_push (priv->trb, data_in); +} + + +void * +kiro_sb_push_dma (KiroSb *self) +{ + g_return_val_if_fail (self != NULL, FALSE); + + KiroSbPrivate *priv = KIRO_SB_GET_PRIVATE (self); + g_return_val_if_fail (priv->initialized != 1, FALSE); + + return kiro_trb_dma_push (priv->trb); +} + + gboolean kiro_sb_clone (KiroSb *self, const gchar* address, const gchar* port) { @@ -225,10 +316,46 @@ kiro_sb_clone (KiroSb *self, const gchar* address, const gchar* port) g_idle_add ((GSourceFunc)idle_func, priv); priv->main_thread = g_thread_new ("KIRO SB Main Loop", (GThreadFunc)start_main_loop, priv->main_loop); + priv->initialized = 2; return TRUE; } +gulong +kiro_sb_add_sync_callback (KiroSb *self, KiroSbSyncCallbackFunc func) +{ + g_return_val_if_fail (self != NULL, 0); + + KiroSbPrivate *priv = KIRO_SB_GET_PRIVATE (self); + + GHook *new_hook = g_hook_alloc (&(priv->callbacks)); + new_hook->data = self; + new_hook->func = (GHookCheckFunc)func; + g_hook_append (&(priv->callbacks), new_hook); + return new_hook->hook_id; +} + + +gboolean +kiro_sb_remove_sync_callback (KiroSb *self, gulong hook_id) +{ + g_return_val_if_fail (self != NULL, FALSE); + KiroSbPrivate *priv = KIRO_SB_GET_PRIVATE (self); + + return g_hook_destroy (&(priv->callbacks), hook_id); +} + + +void +kiro_sb_clear_sync_callbacks (KiroSb *self) +{ + g_return_val_if_fail (self != NULL, FALSE); + KiroSbPrivate *priv = KIRO_SB_GET_PRIVATE (self); + + g_hook_list_clear (&(priv->callbacks)); +} + + gulong kiro_sb_get_size (KiroSb *self) { @@ -239,5 +366,3 @@ kiro_sb_get_size (KiroSb *self) return kiro_trb_get_element_size (priv->trb); } -/* Privat functions */ - diff --git a/src/kiro-sb.h b/src/kiro-sb.h index 45fcf0c..a2f0148 100644 --- a/src/kiro-sb.h +++ b/src/kiro-sb.h @@ -74,7 +74,6 @@ struct _KiroSbClass { */ GType kiro_sb_get_type (void); - /** * kiro_sb_new - Creates a new #KiroSb * Returns: (transfer full): A pointer to a new #KiroSb @@ -85,7 +84,6 @@ GType kiro_sb_get_type (void); */ KiroSb* kiro_sb_new (void); - /** * kiro_sb_free - 'Destroys' the given #KiroSb * @trb: (transfer none): The #KiroSb that is to be freed @@ -101,6 +99,86 @@ KiroSb* kiro_sb_new (void); */ void kiro_sb_free (KiroSb *sb); +/** + * kiro_sb_stop - Stops the #KiroSb and clears all internal memory + * @sb: (transfer none): The #KiroSb to stop + * Description: + * The given #KiroSb is stopped and all internal memory is cleared. It is put + * back into its initial state and it can be used as if it was just created + * See also: + * kiro_sb_new, kiro_sb_serve, kiro_sb_clone + */ +void kiro_sb_stop (KiroSb *sb); + + +typedef gboolean KiroContinueFlag; +#define KIRO_CALLBACK_CONTINUE TRUE +#define KIRO_CALLBACK_REMOVE FALSE + +/** + * KiroSbSyncCallbackFunc - Function type for sync callbacks os a #KiroSb + * @sb: (transfer none): The #KiroSb which invoked this callback + * Returns: A #KiroContinueFlag + * Description: + * Defines the type of a callback function which will be invoked every time + * the #KiroSb syncs new data + * Note: + * Returning %FALSE or %KIRO_CALLBACK_REMOVE will automatically remove the callback + * from the internal callback list. Return %TRUE or %KIRO_CALLBACK_CONTINUE if you + * want to keep the callback active + * See also: + * kiro_sb_add_sync_callback, kiro_sb_remove_sync_callback, kiro_sb_clear_sync_callbacks + */ +typedef KiroContinueFlag (*KiroSbSyncCallbackFunc) (KiroSb *sb); + +/** + * kiro_sb_add_sync_callback - Add a sync callback to the #KiroSb + * @sb: (tranfer none): The #KiroSb to register this callback to + * @func: (transfer none): A function pointer to the callback function + * Returns: The internal id of the registerd callback + * Description: + * Adds a callback to the passed #KiroSbSyncCallbackFunc to this #KiroSb which + * will be invoked every time the #KiroSb syncs new data. + * Note: + * The sync callbacks will only be invoked on a 'clonig' #KiroSb. All + * registered callbacks will be invoked in the order they were added to the + * #KiroSb. + * See also: + * kiro_sb_remove_sync_callback, kiro_sb_clear_sync_callbacks + */ +gulong kiro_sb_add_sync_callback (KiroSb *sb, KiroSbSyncCallbackFunc callback); + +/** + * kiro_sb_remove_sync_callback - Remove a callback from the list + * @sb: (transfer none): The #KiroSb to remove the callback from + * @id: The id of the callback to be removed + * Returns: A #gboolean. %TRUE if the callback was found and removed. %FALSE + * otherwise + * Description: + * Removes the callback with the given @id from the internal list. If the + * callback with the given @id was not found %FALSE is returned. If the + * callback with the given @id was found, it will be removed from the callback + * list and %TRUE is returned + * Note: + * Any currently active callback will still finish before it is removed from + * the list. + * See also: + * kiro_sb_add_sync_callback, kiro_sb_clear_sync_callbacks + */ +gboolean kiro_sb_remove_sync_callback (KiroSb *sb, gulong id); + +/** + * kiro_sb_clear_sync_callbacks - Clear all sync callbacks + * @sb: (transfer none): The #KiroSb to perform this operation on + * Description: + * Removes all registerd callbacks from the internal list + * Note: + * Any currently active callbacks will still finish before they are removed + * from the list + * See also: + * kiro_sb_add_sync_callback, kiro_sb_remove_sync_callback + */ +void kiro_sb_clear_sync_callbacks (KiroSb *sb); /** * kiro_sb_serve - Allow remote KiroSbs to clone this buffers memory @@ -109,16 +187,16 @@ void kiro_sb_free (KiroSb *sb); * @size: Size in bytes of the content that will be served * Description: * Allows other remote #KiroSbs to connect to this #KiroSb and clone its - * memory. + * memory. The internal memory is initially empty. Use the kiro_sb_push or + * kiro_sb_push_dma functions to update the served data. * Note: * A #KiroSb that already 'serves' its content can no longer clone * other remote #KiroSbs. * See also: - * + * kiro_sb_push, kiro_sb_push_dma */ gboolean kiro_sb_serve (KiroSb *sb, gulong size); - /** * kiro_sb_clone - Clone the content of a remote #KiroSb * Returns: A gboolean. TRUE = connection successful. FALSE = connection failed. @@ -152,6 +230,81 @@ gboolean kiro_sb_clone (KiroSb *sb, const gchar *address, const gchar * */ gulong kiro_sb_get_size (KiroSb *sb); +/** + * kiro_sb_freeze - Stop auto syncing + * @sb: (transfer none): The #KiroSb to perform this operation on + * Description: + * Stops the given #KiroSb from automatically syncing. + * See also: + * kiro_sb_thaw + */ +void kiro_sb_freeze (KiroSb *sb); + +/** + * kiro_sb_thaw - Enable auto syncing + * @sb: (transfer none): The #KiroSb to perform this operation on + * Description: + * Enable the given #KiroSb automatic syncing. + * See also: + * kiro_sb_freeze + */ +void kiro_sb_thaw (KiroSb *sb); + +/** + * kiro_sb_get_data - Get a pointer to the stored data + * @sb: (transfer none) The #KiroSb to get the data from + * Returns: A void pointer the stored data + * Description: + * Returns a void pointer to the most current incarnation of the stored data. + * Data might either change by pushing (in case of a 'serving' #KiroSb) or + * after (automatic or manual) syncing (in case of a 'cloning' #KiroSb). + * Note: + * The returned pointer to the element might become invalid at any time by + * automatic or manual sync. Under no circumstances might the returned pointer + * be freed by the user. If you want to ensure access to the pointed-to data + * after a sync, you should use memcpy(). + * See also: + * kiro_sb_freeze, kiro_sb_serve, kiro_sb_clone, kiro_sb_push, + * kiro_sb_push_dma + */ +void* kiro_sb_get_data (KiroSb *sb); + +/** + * kiro_sb_push - Push data into the memory + * @sb: (transfer none) The #KiroSb to get the data from + * @data: (transfer none) void pointer to copy data from + * Returns: %TRUE on success %FALSE in case of error + * Desciption: + * Updates the internal memory by memcopy()-ing the given element into it. + * This operation is only valid for 'serving' #KiroSb. Calling this function + * on a 'cloning' #KiroSb will allways return %FALSE. + * Note: + * The internal memcopy() will assume an element of the correct size (given + * with the initial call to kiro_sb_serve or returned by kiro_sb_get_size) + * See also: + * kiro_sb_get_size, kiro_sb_serve + */ +gboolean kiro_sb_push (KiroSb *sb, void *data); + +/** + * kiro_sb_push_dma - Push data into the memory using memory access + * @sb: (transfer none) The #KiroSb to get the data from + * Returns: A pointer to the memory where the new data should be stored + * Desciption: + * Returns a pointer where the new data should be stored. + * This operation is only valid for a 'serving' #KiroSb. Calling this + * function on a 'cloning' #KiroSb will allways return a %NULL pointer. + * Note: + * It is the users responsibility to ensure no more data is written to the + * pointed memory then was specified with the initial call to kiro_sb_serve or + * returned by kiro_sb_get_size. Under no circumstances might the returned + * pointer be freed by the user. + * See also: + * kiro_sb_get_size, kiro_sb_serve + */ +void* kiro_sb_push_dma (KiroSb *sb); + + G_END_DECLS #endif //__kiro_sb_H -- cgit v1.2.1