[vlc-devel] [RFC PATCH] kwallet: make dbus interruptible
Thomas Guillem
thomas at gllm.fr
Thu Jun 23 16:14:24 CEST 2016
Sorry, I didn't anything more complicated.
Instead of calling dbus_connection_send_with_reply_and_block, I 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.
Question: do we want to use this function in other dbus modules ? If so, where
should I put it ?
---
modules/keystore/kwallet.c | 185 ++++++++++++++++++++++++++++++++++++++++-----
1 file changed, 168 insertions(+), 17 deletions(-)
diff --git a/modules/keystore/kwallet.c b/modules/keystore/kwallet.c
index 76baa20..043abd0 100644
--- a/modules/keystore/kwallet.c
+++ b/modules/keystore/kwallet.c
@@ -34,6 +34,11 @@
#include <stdlib.h>
#include <stdbool.h>
+#include <vlc_interrupt.h>
+#include <poll.h>
+#include <errno.h>
+#include <assert.h>
+
static int Open( vlc_object_t* p_this);
static void Close( vlc_object_t * p_this);
@@ -321,32 +326,178 @@ 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_remove_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;
+ p_ctx->pollfd.fd = -1;
+ p_ctx->p_watch = NULL;
+}
+
+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,
+ vlc_dbus_watch_remove_function,
+ 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
--
2.8.1
More information about the vlc-devel
mailing list