[vlc-devel] [PATCH 5/9] dbus: Split the main loop into smaller functions.

Mirsal Ennaime mirsal at mirsal.fr
Tue Feb 8 22:36:00 CET 2011


From: Mirsal Ennaime <mirsal.ennaime at gmail.com>

---
 modules/control/dbus/dbus.c |  495 +++++++++++++++++++++++++++----------------
 1 files changed, 315 insertions(+), 180 deletions(-)

diff --git a/modules/control/dbus/dbus.c b/modules/control/dbus/dbus.c
index ba3a56c..e997266 100644
--- a/modules/control/dbus/dbus.c
+++ b/modules/control/dbus/dbus.c
@@ -69,6 +69,24 @@
  * Local prototypes.
  *****************************************************************************/
 
+typedef struct
+{
+    int signal;
+    int i_node;
+} callback_info_t;
+
+typedef struct
+{
+    mtime_t      i_remaining;
+    DBusTimeout *p_timeout;
+} timeout_info_t;
+
+enum
+{
+    PIPE_OUT = 0,
+    PIPE_IN  = 1
+};
+
 static int  Open    ( vlc_object_t * );
 static void Close   ( vlc_object_t * );
 static void Run     ( intf_thread_t * );
@@ -92,23 +110,24 @@ static void watch_toggled   ( DBusWatch *p_watch, void *p_data );
 
 static void wakeup_main_loop( void *p_data );
 
-typedef struct
-{
-    int signal;
-    int i_node;
-} callback_info_t;
+static int GetPollFds( intf_thread_t *p_intf, struct pollfd *p_fds );
+static int UpdateTimeouts( intf_thread_t *p_intf, mtime_t i_lastrun );
 
-typedef struct
-{
-    mtime_t      i_remaining;
-    DBusTimeout *p_timeout;
-} timeout_info_t;
+static void ProcessEvents  ( intf_thread_t    *p_intf,
+                             callback_info_t **p_events,
+                             int               i_events );
 
-enum
-{
-    PIPE_OUT = 0,
-    PIPE_IN  = 1
-};
+static void ProcessWatches ( intf_thread_t    *p_intf,
+                             DBusWatch       **p_watches,
+                             int               i_watches,
+                             struct pollfd    *p_fds,
+                             int               i_fds );
+
+static void ProcessTimeouts( intf_thread_t    *p_intf,
+                             DBusTimeout     **p_timeouts,
+                             int               i_timeouts );
+
+static void DispatchDBusMessages( intf_thread_t *p_intf );
 
 /*****************************************************************************
  * Module descriptor
@@ -270,7 +289,7 @@ static int Open( vlc_object_t *p_this )
         return VLC_ENOMEM;
     }
 
-/*    dbus_connection_set_wakeup_main_function( p_conn,
+/*     dbus_connection_set_wakeup_main_function( p_conn,
                                               wakeup_main_loop,
                                               p_intf, NULL); */
 
@@ -343,7 +362,7 @@ static dbus_bool_t add_timeout( DBusTimeout *p_timeout, void *p_data )
     intf_sys_t    *p_sys  = (intf_sys_t*) p_intf->p_sys;
 
     timeout_info_t *p_info = calloc( sizeof( timeout_info_t ), 1 );
-    p_info->i_remaining = dbus_timeout_get_interval( p_timeout );
+    p_info->i_remaining = dbus_timeout_get_interval( p_timeout ) * 1000;/* µs */
     p_info->p_timeout = p_timeout;
 
     dbus_timeout_set_data( p_timeout, p_info, free );
@@ -436,77 +455,297 @@ static void watch_toggled( DBusWatch *p_watch, void *p_data )
     }
 }
 
-/*****************************************************************************
- * Run: main loop
- *****************************************************************************/
-
-static void Run          ( intf_thread_t *p_intf )
+/**
+ * GetPollFds() fills an array of pollfd data structures with :
+ *  - the set of enabled dbus watches
+ *  - the unix pipe which we use to manually wake up the main loop
+ *
+ * This function must be called with p_sys->lock locked
+ *
+ * @return The number of file descriptors
+ *
+ * @param intf_thread_t *p_intf this interface thread's state
+ * @param struct pollfd *p_fds a pointer to a pollfd array large enough to
+ * contain all the returned data (number of enabled dbus watches + 1)
+ */
+static int GetPollFds( intf_thread_t *p_intf, struct pollfd *p_fds )
 {
-    intf_sys_t    *p_sys = p_intf->p_sys;
-    mtime_t        i_lastrun = mdate();
-    struct pollfd *p_fds = NULL;
+    intf_sys_t *p_sys = p_intf->p_sys;
+    int i_fds = 1, i_watches = vlc_array_count( p_sys->p_watches );
 
-    for( ;; )
+    p_fds[0].fd = p_sys->p_pipe_fds[PIPE_OUT];
+    p_fds[0].events = POLLIN | POLLPRI;
+
+    for( int i = 0; i < i_watches; i++ )
     {
-        int canc = vlc_savecancel();
-        vlc_mutex_lock( &p_sys->lock );
+        DBusWatch *p_watch = NULL;
+        p_watch = vlc_array_item_at_index( p_sys->p_watches, i );
+        if( !dbus_watch_get_enabled( p_watch ) )
+            continue;
 
-        /* we build a pollfd array from:
-         *  - the set of enabled dbus watches
-         *  - the unix pipe which we use to manually wake up the main loop */
-        unsigned int i_watches = vlc_array_count( p_sys->p_watches );
-        p_fds = (struct pollfd*) calloc( sizeof( struct pollfd ), i_watches );
+        p_fds[i_fds].fd = dbus_watch_get_unix_fd( p_watch );
+        int i_flags = dbus_watch_get_flags( p_watch );
 
-        p_fds[0].fd = p_sys->p_pipe_fds[PIPE_OUT];
-        p_fds[0].events = POLLIN | POLLPRI;
+        if( i_flags & DBUS_WATCH_READABLE )
+            p_fds[i_fds].events |= POLLIN | POLLPRI;
 
-        int i_fds = 1;
-        DBusWatch *p_watch = NULL;
-        for( unsigned int i = 0; i < i_watches; i++ )
-        {
-            p_watch = vlc_array_item_at_index( p_sys->p_watches, i );
-            if( !dbus_watch_get_enabled( p_watch ) )
-                continue;
+        if( i_flags & DBUS_WATCH_WRITABLE )
+            p_fds[i_fds].events |= POLLOUT;
+
+        i_fds++;
+    }
 
-            p_fds[i_fds].fd = dbus_watch_get_unix_fd( p_watch );
-            int i_flags = dbus_watch_get_flags( p_watch );
+    return i_fds;
+}
 
-            if( i_flags & DBUS_WATCH_READABLE )
-                p_fds[i_fds].events |= POLLIN | POLLPRI;
+/**
+ * UpdateTimeouts() updates the remaining time for each timeout and
+ * returns how much time is left until the next timeout.
+ *
+ * This function must be called with p_sys->lock locked
+ *
+ * @return int The time remaining until the next timeout, in milliseconds
+ * or -1 if there are no timeouts
+ *
+ * @param intf_thread_t *p_intf This interface thread's state
+ * @param mtime_t i_loop_interval The time which has elapsed since the last
+ * call to this function
+ */
+static int UpdateTimeouts( intf_thread_t *p_intf, mtime_t i_loop_interval )
+{
+    intf_sys_t *p_sys = p_intf->p_sys;
+    mtime_t i_next_timeout = LAST_MDATE;
+    unsigned int i_timeouts = vlc_array_count( p_sys->p_timeouts );
 
-            if( i_flags & DBUS_WATCH_WRITABLE )
-                p_fds[i_fds].events |= POLLOUT;
+    if( 0 == i_timeouts )
+        return -1;
 
-            i_fds++;
-        }
+    for( unsigned int i = 0; i < i_timeouts; i++ )
+    {
+        timeout_info_t *p_info = NULL;
+        DBusTimeout    *p_timeout = NULL;
+        mtime_t         i_interval = 0;
+
+        p_timeout = vlc_array_item_at_index( p_sys->p_timeouts, i );
+        i_interval = dbus_timeout_get_interval( p_timeout ) * 1000; /* µs */
+        p_info = (timeout_info_t*) dbus_timeout_get_data( p_timeout );
+
+        p_info->i_remaining -= __MAX( 0, i_loop_interval ) % i_interval;
+
+        if( !dbus_timeout_get_enabled( p_timeout ) )
+            continue;
 
         /* The correct poll timeout value is the shortest one
          * in the dbus timeouts list */
-        mtime_t i_now = mdate(), i_next_timeout = LAST_MDATE;
-        msg_Dbg( p_intf, "%d µs elapsed since last wakeup", i_now - i_lastrun );
-        for( int i = 0; i < vlc_array_count( p_sys->p_timeouts ); i++ )
-        {
-            timeout_info_t *p_info = NULL;
-            DBusTimeout    *p_timeout = NULL;
-            mtime_t         i_interval = 0;
+        i_next_timeout = __MIN( i_next_timeout,
+                                __MAX( 0, p_info->i_remaining ) );
+    }
 
-            p_timeout = vlc_array_item_at_index( p_sys->p_timeouts, i );
-            i_interval = dbus_timeout_get_interval( p_timeout );
-            p_info = (timeout_info_t*) dbus_timeout_get_data( p_timeout );
+    /* next timeout in milliseconds */
+    return i_next_timeout / 1000;
+}
+
+/**
+ * ProcessEvents() reacts to a list of events originating from other VLC threads
+ *
+ * This function must be called with p_sys->lock unlocked
+ *
+ * @param intf_thread_t *p_intf This interface thread state
+ * @param callback_info_t *p_events the list of events to process
+ */
+static void ProcessEvents( intf_thread_t *p_intf,
+                           callback_info_t **p_events, int i_events )
+{
+    for( int i = 0; i < i_events; i++ )
+    {
+        switch( p_events[i]->signal )
+        {
+        case SIGNAL_ITEM_CURRENT:
+            TrackChange( p_intf );
+            break;
+        case SIGNAL_INTF_CHANGE:
+        case SIGNAL_PLAYLIST_ITEM_APPEND:
+        case SIGNAL_PLAYLIST_ITEM_DELETED:
+            TrackListChangeEmit( p_intf,
+                                 p_events[i]->signal,
+                                 p_events[i]->i_node );
+            break;
+        case SIGNAL_RANDOM:
+        case SIGNAL_REPEAT:
+        case SIGNAL_LOOP:
+            StatusChangeEmit( p_intf );
+            break;
+        case SIGNAL_STATE:
+            StateChange( p_intf );
+            break;
+        default:
+            assert(0);
+        }
+        free( p_events[i] );
+    }
+}
 
-            p_info->i_remaining -= __MAX( 0, i_now - i_lastrun ) % i_interval;
+/**
+ * ProcessWatches() handles a list of dbus watches after poll() has returned
+ *
+ * This function must be called with p_sys->lock unlocked
+ *
+ * @param intf_thread_t *p_intf This interface thread state
+ * @param DBusWatch **p_watches The list of dbus watches to process
+ * @param int i_watches The size of the p_watches array
+ * @param struct pollfd *p_fds The result of a poll() call
+ * @param int i_fds The number of file descriptors processed by poll()
+ */
+static void ProcessWatches( intf_thread_t *p_intf,
+                            DBusWatch **p_watches, int i_watches,
+                            struct pollfd *p_fds,  int i_fds )
+{
+    /* Process watches */
+    for( int i = 0; i < i_watches; i++ )
+    {
+        DBusWatch *p_watch = p_watches[i];
+        if( !dbus_watch_get_enabled( p_watch ) )
+            continue;
 
-            if( !dbus_timeout_get_enabled( p_timeout ) )
+        for( int j = 0; j < i_fds; j++ )
+        {
+            if( p_fds[j].fd != dbus_watch_get_unix_fd( p_watch ) )
                 continue;
 
-            i_next_timeout = __MIN( i_next_timeout,
-                                    __MAX( 0, p_info->i_remaining ) );
+            int i_flags   = 0;
+            int i_revents = p_fds[j].revents;
+            int i_fd      = p_fds[j].fd;
+
+            if( i_revents & POLLIN )
+            {
+                msg_Dbg( p_intf, "fd %d is ready for reading", i_fd );
+                i_flags |= DBUS_WATCH_READABLE;
+            }
+
+            if( i_revents & POLLOUT )
+            {
+                msg_Dbg( p_intf, "fd %d is ready for writing", i_fd );
+                i_flags |= DBUS_WATCH_WRITABLE;
+            }
+
+            if( i_revents & POLLERR )
+            {
+                msg_Dbg( p_intf, "error when polling fd %d", i_fd );
+                i_flags |= DBUS_WATCH_ERROR;
+            }
+
+            if( i_revents & POLLHUP )
+            {
+                msg_Dbg( p_intf, "Hangup signal on fd %d", i_fd );
+                i_flags |= DBUS_WATCH_HANGUP;
+            }
+
+            if( i_flags )
+            {
+                msg_Dbg( p_intf, "Handling dbus watch on fd %d", i_fd );
+                dbus_watch_handle( p_watch, i_flags );
+            }
+            else
+                msg_Dbg( p_intf, "Nothing happened on fd %d", i_fd );
         }
+    }
+}
+
+/**
+ * ProcessTimeouts() handles DBus timeouts
+ *
+ * This function must be called with p_sys->lock locked
+ *
+ * @param intf_thread_t *p_intf This interface thread state
+ * @param DBusTimeout **p_timeouts List of timeouts to process
+ * @param int i_timeouts Size of p_timeouts
+ */
+static void ProcessTimeouts( intf_thread_t *p_intf,
+                             DBusTimeout  **p_timeouts, int i_timeouts )
+{
+    VLC_UNUSED( p_intf );
+
+    for( int i = 0; i < i_timeouts; i++ )
+    {
+        timeout_info_t *p_info = NULL;
+
+        p_info = (timeout_info_t*) dbus_timeout_get_data( p_timeouts[i] );
+
+        if( !dbus_timeout_get_enabled( p_info->p_timeout ) )
+            continue;
+
+        if( p_info->i_remaining > 0 )
+            continue;
+
+        dbus_timeout_handle( p_info->p_timeout );
+        p_info->i_remaining = dbus_timeout_get_interval( p_info->p_timeout );
+    }
+}
+
+/**
+ * DispatchDBusMessages() dispatches incoming dbus messages
+ * (indirectly invoking the callbacks), then it sends outgoing
+ * messages which needs to be sent on the bus (method replies and signals)
+ *
+ * This function must be called with p_sys->lock unlocked
+ *
+ * @param intf_thread_t *p_intf This interface thread state
+ */
+static void DispatchDBusMessages( intf_thread_t *p_intf )
+{
+    DBusDispatchStatus status;
+    intf_sys_t *p_sys = p_intf->p_sys;
+
+    /* Dispatch incoming messages */
+    status = dbus_connection_get_dispatch_status( p_sys->p_conn );
+    while( status != DBUS_DISPATCH_COMPLETE )
+    {
+        msg_Dbg( p_intf, "Dispatching incoming dbus message" );
+        dbus_connection_dispatch( p_sys->p_conn );
+        status = dbus_connection_get_dispatch_status( p_sys->p_conn );
+    }
+
+    /* Send outgoing data */
+    if( dbus_connection_has_messages_to_send( p_sys->p_conn ) )
+    {
+        msg_Dbg( p_intf, "Sending outgoing data" );
+        dbus_connection_flush( p_sys->p_conn );
+    }
+}
+
+/*****************************************************************************
+ * Run: main loop
+ *****************************************************************************/
+
+static void Run          ( intf_thread_t *p_intf )
+{
+    intf_sys_t    *p_sys = p_intf->p_sys;
+    mtime_t        i_last_run = mdate();
+
+    for( ;; )
+    {
+        int canc = vlc_savecancel();
+        vlc_mutex_lock( &p_sys->lock );
+
+        int i_watches = vlc_array_count( p_sys->p_watches );
+        struct pollfd *p_fds = calloc( sizeof( struct pollfd ), i_watches );
+
+        int i_fds = GetPollFds( p_intf, p_fds );
+
+        mtime_t i_now = mdate(), i_loop_interval = i_now - i_last_run;
+
+        msg_Dbg( p_intf,
+                 "%lld µs elapsed since last wakeup",
+                 (long long) i_loop_interval );
+
+        int i_next_timeout = UpdateTimeouts( p_intf, i_loop_interval );
+        i_last_run = i_now;
 
-        i_lastrun = i_now;
         vlc_mutex_unlock( &p_sys->lock );
 
-        msg_Dbg( p_intf, "Sleeping until something happens, next timeout is in %d", i_next_timeout );
+        if( -1 != i_next_timeout )
+            msg_Dbg( p_intf, "next timeout is in %d ms", i_next_timeout );
+        msg_Dbg( p_intf, "Sleeping until something happens" );
 
         /* thread cancellation is allowed while the main loop sleeps */
         vlc_restorecancel( canc );
@@ -532,7 +771,7 @@ static void Run          ( intf_thread_t *p_intf )
         {
             char buf;
             msg_Dbg( p_intf, "Removing a byte from the self-pipe" );
-            read( p_fds[0].fd, &buf, 1 );
+            (void)read( p_fds[0].fd, &buf, 1 );
         }
 
         /* We need to lock the mutex while building lists of events,
@@ -548,7 +787,7 @@ static void Run          ( intf_thread_t *p_intf )
 
         /* Get the list of timeouts to process */
         unsigned int i_timeouts = vlc_array_count( p_sys->p_timeouts );
-        DBusTimeout **p_timeouts = calloc( sizeof( DBusTimeout* ), i_timeouts );
+        DBusTimeout *p_timeouts[i_timeouts];
         for( unsigned int i = 0; i < i_timeouts; i++ )
         {
             p_timeouts[i] = vlc_array_item_at_index( p_sys->p_timeouts, i );
@@ -556,135 +795,31 @@ static void Run          ( intf_thread_t *p_intf )
 
         /* Get the list of watches to process */
         i_watches = vlc_array_count( p_sys->p_watches );
-        DBusWatch **p_watches = calloc( sizeof( DBusWatch* ), i_watches );
-        for( unsigned int i = 0; i < i_watches; i++ )
+        DBusWatch *p_watches[i_watches];
+        for( int i = 0; i < i_watches; i++ )
         {
             p_watches[i] = vlc_array_item_at_index( p_sys->p_watches, i );
         }
 
         /* Get the list of events to process */
         int i_events = vlc_array_count( p_intf->p_sys->p_events );
-        callback_info_t* info[i_events];
+        callback_info_t* p_info[i_events];
         for( int i = i_events - 1; i >= 0; i-- )
         {
-            info[i] = vlc_array_item_at_index( p_intf->p_sys->p_events, i );
+            p_info[i] = vlc_array_item_at_index( p_intf->p_sys->p_events, i );
             vlc_array_remove( p_intf->p_sys->p_events, i );
         }
 
         /* now we can release the lock and process what's pending */
         vlc_mutex_unlock( &p_intf->p_sys->lock );
 
-        /* Process vlc events */
-        for( int i = 0; i < i_events; i++ )
-        {
-            switch( info[i]->signal )
-            {
-            case SIGNAL_ITEM_CURRENT:
-                TrackChange( p_intf );
-                break;
-            case SIGNAL_INTF_CHANGE:
-            case SIGNAL_PLAYLIST_ITEM_APPEND:
-            case SIGNAL_PLAYLIST_ITEM_DELETED:
-                TrackListChangeEmit( p_intf, info[i]->signal, info[i]->i_node );
-                break;
-            case SIGNAL_RANDOM:
-            case SIGNAL_REPEAT:
-            case SIGNAL_LOOP:
-                StatusChangeEmit( p_intf );
-                break;
-            case SIGNAL_STATE:
-                StateChange( p_intf );
-                break;
-            default:
-                assert(0);
-            }
-            free( info[i] );
-        }
-
-        /* Process watches */
-        for( unsigned int i = 0; i < i_watches; i++ )
-        {
-            DBusWatch *p_watch = p_watches[i];
-            if( !dbus_watch_get_enabled( p_watch ) )
-                continue;
+        ProcessEvents( p_intf, p_info, i_events );
+        ProcessWatches( p_intf, p_watches, i_watches, p_fds, i_fds );
 
-            for( int j = 0; j < i_fds; j++ )
-            {
-                if( p_fds[j].fd != dbus_watch_get_unix_fd( p_watch ) )
-                    continue;
-
-                int i_flags   = 0;
-                int i_revents = p_fds[j].revents;
-                int i_fd      = p_fds[j].fd;
-
-                if( i_revents & POLLIN )
-                {
-                    msg_Dbg( p_intf, "fd %d is ready for reading", i_fd );
-                    i_flags |= DBUS_WATCH_READABLE;
-                }
-
-                if( i_revents & POLLOUT )
-                {
-                    msg_Dbg( p_intf, "fd %d is ready for writing", i_fd );
-                    i_flags |= DBUS_WATCH_WRITABLE;
-                }
-
-                if( i_revents & POLLERR )
-                {
-                    msg_Dbg( p_intf, "error when polling fd %d", i_fd );
-                    i_flags |= DBUS_WATCH_ERROR;
-                }
-
-                if( i_revents & POLLHUP )
-                {
-                    msg_Dbg( p_intf, "Hangup signal on fd %d", i_fd );
-                    i_flags |= DBUS_WATCH_HANGUP;
-                }
-
-                if( i_flags )
-                {
-                    msg_Dbg( p_intf, "Handling dbus watch on fd %d", i_fd );
-                    dbus_watch_handle( p_watch, i_flags );
-                }
-                else
-                    msg_Dbg( p_intf, "Nothing happened on fd %d", i_fd );
-            }
-        }
         free( p_fds ); p_fds = NULL;
 
-        /* Process timeouts */
-        for( unsigned int i = 0; i < i_timeouts; i++ )
-        {
-            timeout_info_t *p_info = NULL;
-
-            p_info = (timeout_info_t*) dbus_timeout_get_data( p_timeouts[i] );
-
-            if( !dbus_timeout_get_enabled( p_info->p_timeout ) )
-                continue;
-
-            if( p_info->i_remaining > 0 )
-                continue;
-
-            dbus_timeout_handle( p_info->p_timeout );
-            p_info->i_remaining = dbus_timeout_get_interval( p_info->p_timeout );
-        }
-
-        /* Dispatch incoming dbus messages */
-        DBusDispatchStatus status;
-        status = dbus_connection_get_dispatch_status( p_sys->p_conn );
-        while( status != DBUS_DISPATCH_COMPLETE )
-        {
-            msg_Dbg( p_intf, "Dispatching incoming dbus messages" );
-            dbus_connection_dispatch( p_sys->p_conn );
-            status = dbus_connection_get_dispatch_status( p_sys->p_conn );
-        }
-
-        /* Send outgoing data */
-        if( dbus_connection_has_messages_to_send( p_sys->p_conn ) )
-        {
-            msg_Dbg( p_intf, "Sending outgoing data" );
-            dbus_connection_flush( p_sys->p_conn );
-        }
+        ProcessTimeouts( p_intf, p_timeouts, i_timeouts );
+        DispatchDBusMessages( p_intf );
 
         vlc_restorecancel( canc );
     }
-- 
1.7.1




More information about the vlc-devel mailing list