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( i_watches, sizeof( struct pollfd ) ); 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; vlc_mutex_unlock( &p_sys->lock ); 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 ); int i_pollres = poll( p_fds, i_fds, i_next_timeout ); int i_errsv = errno; canc = vlc_savecancel(); msg_Dbg( p_intf, "the main loop has been woken up" ); if( -1 == i_pollres ) { /* XXX: What should we do when poll() fails ? */ char buf[64]; msg_Err( p_intf, "poll() failed: %s", strerror_r( i_errsv, buf, 64 ) ); free( p_fds ); p_fds = NULL; vlc_restorecancel( canc ); continue; } /* Was the main loop woken up manually ? */ if( 0 < i_pollres && ( p_fds[0].revents & POLLIN ) ) { char buf; msg_Dbg( p_intf, "Removing a byte from the self-pipe" ); (void)read( p_fds[0].fd, &buf, 1 ); } /* We need to lock the mutex while building lists of events, * timeouts and watches to process but we can't keep the lock while * processing them, or else we risk a deadlock: * * The signal functions could lock mutex X while p_events is locked; * While some other function in vlc (playlist) might lock mutex X * and then set a variable which would call AllCallback(), which itself * needs to lock p_events to add a new event. */ vlc_mutex_lock( &p_intf->p_sys->lock ); /* Get the list of timeouts to process */ unsigned int i_timeouts = vlc_array_count( p_sys->p_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 ); } /* Get the list of watches to process */ i_watches = vlc_array_count( p_sys->p_watches ); 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* p_info[i_events]; for( int i = i_events - 1; i >= 0; 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 ); ProcessEvents( p_intf, p_info, i_events ); ProcessWatches( p_intf, p_watches, i_watches, p_fds, i_fds ); free( p_fds ); p_fds = NULL; ProcessTimeouts( p_intf, p_timeouts, i_timeouts ); DispatchDBusMessages( p_intf ); vlc_restorecancel( canc ); } }
static void *Run( void *data ) { intf_thread_t *p_intf = data; intf_sys_t *p_sys = p_intf->p_sys; int canc = vlc_savecancel(); for( ;; ) { vlc_mutex_lock( &p_sys->lock ); int i_watches = vlc_array_count( p_sys->p_watches ); struct pollfd fds[i_watches]; memset(fds, 0, sizeof fds); int i_fds = GetPollFds( p_intf, fds ); int timeout = next_timeout(p_intf); vlc_mutex_unlock( &p_sys->lock ); /* thread cancellation is allowed while the main loop sleeps */ vlc_restorecancel( canc ); while (poll(fds, i_fds, timeout) == -1) { if (errno != EINTR) goto error; } canc = vlc_savecancel(); /* Was the main loop woken up manually ? */ if (fds[0].revents & POLLIN) { char buf; (void)read( fds[0].fd, &buf, 1 ); } /* We need to lock the mutex while building lists of events, * timeouts and watches to process but we can't keep the lock while * processing them, or else we risk a deadlock: * * The signal functions could lock mutex X while p_events is locked; * While some other function in vlc (playlist) might lock mutex X * and then set a variable which would call AllCallback(), which itself * needs to lock p_events to add a new event. */ vlc_mutex_lock( &p_intf->p_sys->lock ); process_timeouts(p_intf); /* Get the list of watches to process */ i_watches = vlc_array_count( p_sys->p_watches ); DBusWatch *p_watches[i_watches ? i_watches : 1]; 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* p_info[i_events ? i_events : 1]; for( int i = i_events - 1; i >= 0; 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 ); ProcessEvents( p_intf, p_info, i_events ); ProcessWatches( p_intf, p_watches, i_watches, fds, i_fds ); DispatchDBusMessages( p_intf ); } error: vlc_restorecancel(canc); return NULL; }