Count message references and get rid of the global message ring buffer
authorRémi Denis-Courmont <rdenis@simphalempin.com>
Tue, 14 Oct 2008 20:35:20 +0000 (23:35 +0300)
committerRémi Denis-Courmont <rdenis@simphalempin.com>
Tue, 14 Oct 2008 20:47:06 +0000 (23:47 +0300)
Each susbcriber has its own ring buffer already.

include/vlc_messages.h
src/libvlc.c
src/libvlc.h
src/misc/messages.c

index 4d0d507..bf8d2dd 100644 (file)
@@ -55,6 +55,7 @@ typedef struct
     char *  psz_header;                         /**< Additional header */
 
     mtime_t date;                               /**< Message date */
+    gc_object_t vlc_gc_data;
 } msg_item_t;
 
 /* Message types */
@@ -67,6 +68,17 @@ typedef struct
 /** debug messages */
 #define VLC_MSG_DBG   3
 
+static inline msg_item_t *msg_Hold (msg_item_t *msg)
+{
+    vlc_hold (&msg->vlc_gc_data);
+    return msg;
+}
+
+static inline void msg_Release (msg_item_t *msg)
+{
+    vlc_release (&msg->vlc_gc_data);
+}
+
 /**
  * Used by interface plugins which subscribe to the message bank.
  */
index f300daa..d6e6be4 100644 (file)
@@ -744,11 +744,6 @@ int libvlc_InternalInit( libvlc_int_t *p_libvlc, int i_argc,
     if( priv->b_color )
         priv->b_color = config_GetInt( p_libvlc, "color" ) > 0;
 
-    /*
-     * Output messages that may still be in the queue
-     */
-    msg_Flush( p_libvlc );
-
     if( !config_GetInt( p_libvlc, "fpu" ) )
         cpu_flags &= ~CPU_CAPABILITY_FPU;
 
@@ -1142,7 +1137,6 @@ int libvlc_InternalDestroy( libvlc_int_t *p_libvlc )
     }
     vlc_mutex_unlock( &global_lock );
 
-    msg_Flush( p_libvlc );
     msg_Destroy( p_libvlc );
 
     /* Destroy mutexes */
index ddeda34..5859ece 100644 (file)
@@ -79,12 +79,6 @@ typedef struct msg_bank_t
     vlc_mutex_t lock;
     vlc_cond_t  wait;
 
-    /* Message queue */
-    msg_item_t              msg[VLC_MSG_QSIZE];           /**< message queue */
-    int i_start;
-    int i_stop;
-    bool b_overflow;
-
     /* Subscribers */
     int i_sub;
     msg_subscription_t **pp_sub;
@@ -96,7 +90,6 @@ typedef struct msg_bank_t
 } msg_bank_t;
 
 void msg_Create  (libvlc_int_t *);
-void msg_Flush   (libvlc_int_t *);
 void msg_Destroy (libvlc_int_t *);
 
 /** Internal message stack context */
index 81c8aba..69ba876 100644 (file)
@@ -86,7 +86,6 @@ static inline msg_bank_t *libvlc_bank (libvlc_int_t *inst)
  *****************************************************************************/
 static void QueueMsg ( vlc_object_t *, int, const char *,
                        const char *, va_list );
-static void FlushMsg ( msg_bank_t * );
 static void PrintMsg ( vlc_object_t *, msg_item_t * );
 
 static vlc_mutex_t msg_stack_lock = VLC_STATIC_MUTEX;
@@ -105,11 +104,8 @@ void msg_Create (libvlc_int_t *p_libvlc)
     vlc_dictionary_init( &priv->msg_enabled_objects, 0 );
     priv->msg_all_objects_enabled = true;
 
-    QUEUE.b_overflow = false;
-    QUEUE.i_start = 0;
-    QUEUE.i_stop = 0;
     QUEUE.i_sub = 0;
-    QUEUE.pp_sub = 0;
+    QUEUE.pp_sub = NULL;
 
 #ifdef UNDER_CE
     QUEUE.logfile =
@@ -126,18 +122,6 @@ void msg_Create (libvlc_int_t *p_libvlc)
 }
 
 /**
- * Flush all message queues
- */
-void msg_Flush (libvlc_int_t *p_libvlc)
-{
-    libvlc_priv_t *priv = libvlc_priv (p_libvlc);
-    vlc_mutex_lock( &QUEUE.lock );
-    FlushMsg( &QUEUE );
-    vlc_mutex_unlock( &QUEUE.lock );
-}
-
-
-/**
  * Object Printing selection
  */
 static void const * kObjectPrintingEnabled = &kObjectPrintingEnabled;
@@ -180,8 +164,6 @@ void msg_Destroy (libvlc_int_t *p_libvlc)
     if( QUEUE.i_sub )
         msg_Err( p_libvlc, "stale interface subscribers (VLC might crash)" );
 
-    FlushMsg( &QUEUE );
-
     vlc_mutex_lock( &msg_stack_lock );
     if( --banks == 0 )
         vlc_threadvar_delete( &msg_context );
@@ -213,10 +195,7 @@ static void *msg_thread (void *data)
     msg_subscription_t *sub = data;
     msg_bank_t *bank = libvlc_bank (sub->instance);
 
-    /* TODO: finer-grained locking and/or msg_item_t refcount */
     vlc_mutex_lock (&bank->lock);
-    mutex_cleanup_push (&bank->lock);
-
     for (;;)
     {
         /* Wait for messages */
@@ -224,15 +203,24 @@ static void *msg_thread (void *data)
         assert (sub->end < VLC_MSG_QSIZE);
         while (sub->begin != sub->end)
         {
-            sub->func (sub->opaque, sub->items[sub->begin], sub->overruns);
+            msg_item_t *msg = sub->items[sub->begin];
+            unsigned overruns = sub->overruns;
+
             if (++sub->begin == VLC_MSG_QSIZE)
                 sub->begin = 0;
             sub->overruns = 0;
+            vlc_mutex_unlock (&bank->lock);
+
+            sub->func (sub->opaque, msg, overruns);
+            msg_Release (msg);
+
+            vlc_mutex_lock (&bank->lock);
         }
+
+        mutex_cleanup_push (&bank->lock);
         vlc_cond_wait (&bank->wait, &bank->lock);
+        vlc_cleanup_pop ();
     }
-
-    vlc_cleanup_pop ();
     assert (0);
 }
 
@@ -312,6 +300,19 @@ void __msg_GenericVa( vlc_object_t *p_this, int i_type, const char *psz_module,
 }
 
 /**
+ * Destroys a message.
+ */
+static void msg_Free (gc_object_t *gc)
+{
+    msg_item_t *msg = vlc_priv (gc, msg_item_t);
+
+    free (msg->psz_module);
+    free (msg->psz_msg);
+    free (msg->psz_header);
+    free (msg);
+}
+
+/**
  * Add a message to a queue
  *
  * This function provides basic functionnalities to other msg_* functions.
@@ -329,9 +330,12 @@ static void QueueMsg( vlc_object_t *p_this, int i_type, const char *psz_module,
     char *       psz_str = NULL;                 /* formatted message string */
     char *       psz_header = NULL;
     va_list      args;
-    msg_item_t * p_item = NULL;                        /* pointer to message */
-    msg_item_t   item;                    /* message in case of a full queue */
-    msg_bank_t  *p_queue;
+    msg_item_t * p_item = malloc (sizeof (*p_item));
+
+    if (p_item == NULL)
+        return; /* Uho! */
+
+    vlc_gc_init (p_item, msg_Free);
 
 #if !defined(HAVE_VASPRINTF) || defined(__APPLE__) || defined(SYS_BEOS)
     int          i_size = strlen(psz_format) + INTF_MAX_MSG_SIZE;
@@ -466,57 +470,9 @@ static void QueueMsg( vlc_object_t *p_this, int i_type, const char *psz_module,
     psz_str[ i_size - 1 ] = 0; /* Just in case */
 #endif
 
-    p_queue = &QUEUE;
+    msg_bank_t *p_queue = &QUEUE;
     vlc_mutex_lock( &p_queue->lock );
 
-    /* Check there is room in the queue for our message */
-    if( p_queue->b_overflow )
-    {
-        FlushMsg( p_queue );
-
-        if( ((p_queue->i_stop - p_queue->i_start + 1) % VLC_MSG_QSIZE) == 0 )
-        {
-            /* Still in overflow mode, print from a dummy item */
-            p_item = &item;
-        }
-        else
-        {
-            /* Pheeew, at last, there is room in the queue! */
-            p_queue->b_overflow = false;
-        }
-    }
-    else if( ((p_queue->i_stop - p_queue->i_start + 2) % VLC_MSG_QSIZE) == 0 )
-    {
-        FlushMsg( p_queue );
-
-        if( ((p_queue->i_stop - p_queue->i_start + 2) % VLC_MSG_QSIZE) == 0 )
-        {
-            p_queue->b_overflow = true;
-
-            /* Put the overflow message in the queue */
-            p_item = p_queue->msg + p_queue->i_stop;
-            p_queue->i_stop = (p_queue->i_stop + 1) % VLC_MSG_QSIZE;
-
-            p_item->i_type =        VLC_MSG_WARN;
-            p_item->i_object_id =   (uintptr_t)p_this;
-            p_item->psz_object_type = p_this->psz_object_type;
-            p_item->psz_module =    strdup( "message" );
-            p_item->psz_msg =       strdup( "message queue overflowed" );
-            p_item->psz_header =    NULL;
-
-            PrintMsg( p_this, p_item );
-            /* We print from a dummy item */
-            p_item = &item;
-        }
-    }
-
-    if( !p_queue->b_overflow )
-    {
-        /* Put the message in the queue */
-        p_item = p_queue->msg + p_queue->i_stop;
-        p_queue->i_stop = (p_queue->i_stop + 1) % VLC_MSG_QSIZE;
-    }
-
     /* Fill message information fields */
     p_item->i_type =        i_type;
     p_item->i_object_id =   (uintptr_t)p_this;
@@ -527,78 +483,22 @@ static void QueueMsg( vlc_object_t *p_this, int i_type, const char *psz_module,
 
     PrintMsg( p_this, p_item );
 #define bank p_queue
-    if( p_item == &item )
+    for (int i = 0; i < bank->i_sub; i++)
     {
-        free( p_item->psz_module );
-        free( p_item->psz_msg );
-        free( p_item->psz_header );
-        for (int i = 0; i < bank->i_sub; i++)
-            bank->pp_sub[i]->overruns++;
-    }
-    else
-    {
-        for (int i = 0; i < bank->i_sub; i++)
+        msg_subscription_t *sub = bank->pp_sub[i];
+        if ((sub->end + 1 - sub->begin) % VLC_MSG_QSIZE)
         {
-            msg_subscription_t *sub = bank->pp_sub[i];
-            if ((sub->end + 1 - sub->begin) % VLC_MSG_QSIZE)
-            {
-                sub->items[sub->end++] = p_item;
-                if (sub->end == VLC_MSG_QSIZE)
-                    sub->end = 0;
-            }
-            else
-                sub->overruns++;
+            sub->items[sub->end++] = msg_Hold (p_item);
+            if (sub->end == VLC_MSG_QSIZE)
+                sub->end = 0;
         }
-        vlc_cond_broadcast (&bank->wait);
+        else
+            sub->overruns++;
     }
+    vlc_cond_broadcast (&bank->wait);
     vlc_mutex_unlock (&bank->lock);
 }
 
-/* following functions are local */
-
-/*****************************************************************************
- * FlushMsg
- *****************************************************************************
- * Print all messages remaining in queue. MESSAGE QUEUE MUST BE LOCKED, since
- * this function does not check the lock.
- *****************************************************************************/
-static void FlushMsg ( msg_bank_t *p_queue )
-{
-    int i_index, i_start, i_stop;
-
-    /* Get the maximum message index that can be freed */
-    i_stop = p_queue->i_stop;
-
-    /* Check until which value we can free messages */
-    for( i_index = 0; i_index < p_queue->i_sub; i_index++ )
-    {
-        i_start = p_queue->pp_sub[ i_index ]->begin;
-
-        /* If this subscriber is late, we don't free messages before
-         * his i_start value, otherwise he'll miss messages */
-        if(   ( i_start < i_stop
-               && (p_queue->i_stop <= i_start || i_stop <= p_queue->i_stop) )
-           || ( i_stop < i_start
-               && (i_stop <= p_queue->i_stop && p_queue->i_stop <= i_start) ) )
-        {
-            i_stop = i_start;
-        }
-    }
-
-    /* Free message data */
-    for( i_index = p_queue->i_start;
-         i_index != i_stop;
-         i_index = (i_index+1) % VLC_MSG_QSIZE )
-    {
-        free( p_queue->msg[i_index].psz_msg );
-        free( p_queue->msg[i_index].psz_module );
-        free( p_queue->msg[i_index].psz_header );
-    }
-
-    /* Update the new start value */
-    p_queue->i_start = i_index;
-}
-
 /*****************************************************************************
  * PrintMsg: output a standard message item to stderr
  *****************************************************************************