vlc | branch: master | Thomas Guillem <[email protected]> | Fri Jun 24 18:46:15 2016 +0200| [880ade6b1164a74670753c94b341a55061ecef8a] | committer: Thomas Guillem
kwallet: make dbus messages interruptible Instead of calling dbus_connection_send_with_reply_and_block, we do: - Setup watch functions in order to get fds and poll events when a callback is triggered. - Call dbus_connection_send_with_reply() (that won't do anything because no mainloop). This will trigger watch callbacks. - In loop: call vlc_poll_i11e() with fds fetched from the watch callbacks. Call dbus_watch_handle() on the polled fds. This will do the I/O (non blocking). - Wait for reply from the pending call. > http://git.videolan.org/gitweb.cgi/vlc.git/?a=commit;h=880ade6b1164a74670753c94b341a55061ecef8a --- modules/keystore/kwallet.c | 173 +++++++++++++++++++++++++++++++++++++++----- 1 file changed, 156 insertions(+), 17 deletions(-) diff --git a/modules/keystore/kwallet.c b/modules/keystore/kwallet.c index ddd08ac..2024df0 100644 --- a/modules/keystore/kwallet.c +++ b/modules/keystore/kwallet.c @@ -27,6 +27,7 @@ #include <vlc_url.h> #include <vlc_plugin.h> #include <vlc_strings.h> +#include <vlc_interrupt.h> #include <dbus/dbus.h> @@ -35,6 +36,9 @@ #include <unistd.h> #include <stdlib.h> #include <stdbool.h> +#include <poll.h> +#include <errno.h> +#include <assert.h> static int Open( vlc_object_t * ); static void Close( vlc_object_t * ); @@ -306,32 +310,167 @@ vlc_dbus_new_method( vlc_keystore* p_keystore, const char* psz_method ) return msg; } -static DBusMessage* -vlc_dbus_send_message( vlc_keystore* p_keystore, DBusMessage* msg ) +#define MAX_WATCHES 2 +struct vlc_dbus_watch_data { - vlc_keystore_sys* p_sys = p_keystore->p_sys; - DBusMessage* repmsg; - DBusError error; + struct pollfd pollfd; + DBusWatch *p_watch; +}; - dbus_error_init( &error ); +static short +vlc_dbus_watch_get_poll_events( DBusWatch *p_watch ) +{ + unsigned int i_flags = dbus_watch_get_flags( p_watch ); + short i_events = 0; + + if( i_flags & DBUS_WATCH_READABLE ) + i_events |= POLLIN; + if( i_flags & DBUS_WATCH_WRITABLE ) + i_events |= POLLOUT; + return i_events; +} - repmsg = dbus_connection_send_with_reply_and_block( p_sys->connection, - msg, -1, - &error); - if ( !repmsg ) +static struct vlc_dbus_watch_data * +vlc_dbus_watch_get_data( DBusWatch *p_watch, + struct vlc_dbus_watch_data *p_ctx ) +{ + for( unsigned i = 0; i < MAX_WATCHES; ++i ) { - msg_Err( p_keystore, "vlc_dbus_send_message : " - "Failed dbus_connection_send_with_reply_and_block" ); + if( p_ctx[i].p_watch == NULL || p_ctx[i].p_watch == p_watch ) + return &p_ctx[i]; + } + return NULL; +} + +static dbus_bool_t +vlc_dbus_watch_add_function( DBusWatch *p_watch, void *p_data ) +{ + struct vlc_dbus_watch_data *p_ctx = vlc_dbus_watch_get_data( p_watch, p_data ); + + if( p_ctx == NULL ) + return FALSE; + + short i_events = POLLHUP | POLLERR; + + i_events |= vlc_dbus_watch_get_poll_events( p_watch ); + + p_ctx->pollfd.fd = dbus_watch_get_unix_fd( p_watch ); + p_ctx->pollfd.events = i_events; + p_ctx->p_watch = p_watch; + return TRUE; +} + +static void +vlc_dbus_watch_toggled_function( DBusWatch *p_watch, void *p_data ) +{ + struct vlc_dbus_watch_data *p_ctx = vlc_dbus_watch_get_data( p_watch, p_data ); + short i_events = vlc_dbus_watch_get_poll_events( p_watch ); + + if( dbus_watch_get_enabled( p_watch ) ) + p_ctx->pollfd.events |= i_events; + else + p_ctx->pollfd.events &= ~i_events; +} + +static void +vlc_dbus_pending_call_notify( DBusPendingCall *p_pending_call, void *p_data ) +{ + DBusMessage **pp_repmsg = p_data; + *pp_repmsg = dbus_pending_call_steal_reply( p_pending_call ); +} + +static DBusMessage* +vlc_dbus_send_message( vlc_keystore* p_keystore, DBusMessage* p_msg ) +{ + vlc_keystore_sys *p_sys = p_keystore->p_sys; + DBusMessage *p_repmsg = NULL; + DBusPendingCall *p_pending_call = NULL; + + struct vlc_dbus_watch_data watch_ctx[MAX_WATCHES] = {}; + + for( unsigned i = 0; i < MAX_WATCHES; ++i ) + watch_ctx[i].pollfd.fd = -1; + + if( !dbus_connection_set_watch_functions( p_sys->connection, + vlc_dbus_watch_add_function, + NULL, + vlc_dbus_watch_toggled_function, + watch_ctx, NULL ) ) return NULL; + + if( !dbus_connection_send_with_reply( p_sys->connection, p_msg, + &p_pending_call, + DBUS_TIMEOUT_INFINITE ) ) + goto end; + + if( !dbus_pending_call_set_notify( p_pending_call, + vlc_dbus_pending_call_notify, + &p_repmsg, NULL ) ) + goto end; + + while( p_repmsg == NULL ) + { + errno = 0; + struct pollfd pollfds[MAX_WATCHES]; + int nfds = 0; + for( unsigned i = 0; i < MAX_WATCHES; ++i ) + { + if( watch_ctx[i].pollfd.fd == -1 ) + break; + pollfds[i].fd = watch_ctx[i].pollfd.fd; + pollfds[i].events = watch_ctx[i].pollfd.events; + pollfds[i].revents = 0; + nfds++; + } + if( nfds == 0 ) + { + msg_Err( p_keystore, "vlc_dbus_send_message: watch functions not called" ); + goto end; + } + if( vlc_poll_i11e( pollfds, nfds, -1 ) <= 0 ) + { + if( errno == EINTR ) + msg_Dbg( p_keystore, "vlc_dbus_send_message: poll was interrupted" ); + else + msg_Err( p_keystore, "vlc_dbus_send_message: poll failed" ); + goto end; + } + for( int i = 0; i < nfds; ++ i ) + { + short i_events = pollfds[i].revents; + if( !i_events ) + continue; + unsigned i_flags = 0; + if( i_events & POLLIN ) + i_flags |= DBUS_WATCH_READABLE; + if( i_events & POLLOUT ) + i_flags |= DBUS_WATCH_WRITABLE; + if( i_events & POLLHUP ) + i_flags |= DBUS_WATCH_HANGUP; + if( i_events & POLLERR ) + i_flags |= DBUS_WATCH_ERROR; + if( !dbus_watch_handle( watch_ctx[i].p_watch, i_flags ) ) + goto end; + } + + DBusDispatchStatus status; + while( ( status = dbus_connection_dispatch( p_sys->connection ) ) + == DBUS_DISPATCH_DATA_REMAINS ); + if( status == DBUS_DISPATCH_NEED_MEMORY ) + goto end; } - if ( dbus_error_is_set( &error ) ) + +end: + dbus_connection_set_watch_functions( p_sys->connection, NULL, NULL, + NULL, NULL, NULL ); + if( p_pending_call != NULL ) { - msg_Err( p_keystore, "vlc_dbus_send_message : " - "dbus_connection_send_with_reply_and_block has error set" ); - return NULL; + if( p_repmsg != NULL ) + dbus_pending_call_cancel( p_pending_call ); + dbus_pending_call_unref( p_pending_call ); } + return p_repmsg; - return repmsg; } static int _______________________________________________ vlc-commits mailing list [email protected] https://mailman.videolan.org/listinfo/vlc-commits
