[gtk-vnc-devel] [PATCH] Delay signal emission from coroutines
- From: Anthony Liguori <anthony codemonkey ws>
- To: gtk-vnc-devel List <gtk-vnc-devel lists sourceforge net>
- Subject: [gtk-vnc-devel] [PATCH] Delay signal emission from coroutines
- Date: Wed, 06 Feb 2008 20:16:14 -0600
This appears to fix the problem when configuring --with-coroutine=thread.
I'll push this change to the outgoing repo tomorrow after everyone's
gotten a chance to look over it.
Regards,
Anthony Liguori
# HG changeset patch
# User Anthony Liguori <anthony codemonkey ws>
# Date 1202350491 21600
# Node ID 0639b5d4ae890a163eb4cbd498c9158d9d4120d5
# Parent e270ad1c273674048ca6c2f84daf9c04c2b3e47d
Always emit signals from system coroutine.
When using threads to simulate coroutines, GTK gets very confused as signal
handlers are run in a different thread than the main loop when the signal
handlers aren't expecting it.
This patch changes all of the signals emitted from the VNC coroutine to use
a delay function to actually issue the signals. This appears to fix the
GThread coroutine issue.
diff -r e270ad1c2736 -r 0639b5d4ae89 src/vncdisplay.c
--- a/src/vncdisplay.c Wed Feb 06 19:46:02 2008 -0600
+++ b/src/vncdisplay.c Wed Feb 06 20:14:51 2008 -0600
@@ -81,6 +81,28 @@ struct _VncDisplayPrivate
gboolean read_only;
gboolean allow_lossy;
gboolean allow_scaling;
+};
+
+/* Delayed signal emmission.
+ *
+ * We want signals to be delivered in the system coroutine. This helps avoid
+ * confusing applications. This is particularily important when using
+ * GThread based coroutines since GTK gets very upset if a signal handler is
+ * run in a different thread from the main loop if that signal handler isn't
+ * written to use explicit locking.
+ */
+struct signal_data
+{
+ VncDisplay *obj;
+ struct coroutine *caller;
+
+ int signum;
+ GValueArray *cred_list;
+ int width;
+ int height;
+ const char *msg;
+ unsigned int auth_type;
+ GString *str;
};
G_DEFINE_TYPE(VncDisplay, vnc_display, GTK_TYPE_DRAWING_AREA)
@@ -788,10 +810,72 @@ static void setup_gl_image(VncDisplay *o
}
#endif
+static gboolean emit_signal_auth_cred(gpointer opaque)
+{
+ struct signal_data *s = opaque;
+
+ switch (s->signum) {
+ case VNC_AUTH_CREDENTIAL:
+ g_signal_emit(G_OBJECT(s->obj),
+ signals[VNC_AUTH_CREDENTIAL],
+ 0,
+ s->cred_list);
+ break;
+ case VNC_DESKTOP_RESIZE:
+ g_signal_emit(G_OBJECT(s->obj),
+ signals[VNC_DESKTOP_RESIZE],
+ 0,
+ s->width, s->height);
+ break;
+ case VNC_AUTH_FAILURE:
+ g_signal_emit(G_OBJECT(s->obj),
+ signals[VNC_AUTH_FAILURE],
+ 0,
+ s->msg);
+ break;
+ case VNC_AUTH_UNSUPPORTED:
+ g_signal_emit(G_OBJECT(s->obj),
+ signals[VNC_AUTH_UNSUPPORTED],
+ 0,
+ s->auth_type);
+ break;
+ case VNC_SERVER_CUT_TEXT:
+ g_signal_emit(G_OBJECT(s->obj),
+ signals[VNC_SERVER_CUT_TEXT],
+ 0,
+ s->str->str);
+ break;
+ case VNC_BELL:
+ case VNC_CONNECTED:
+ case VNC_INITIALIZED:
+ case VNC_DISCONNECTED:
+ g_signal_emit(G_OBJECT(s->obj),
+ signals[s->signum],
+ 0);
+ break;
+ }
+
+ coroutine_yieldto(s->caller, NULL);
+
+ return FALSE;
+}
+
+/* This function should be used to emit signals from gvnc callbacks */
+static void emit_signal_delayed(VncDisplay *obj, int signum,
+ struct signal_data *data)
+{
+ data->obj = obj;
+ data->caller = coroutine_self();
+ data->signum = signum;
+ g_idle_add(emit_signal_auth_cred, data);
+ coroutine_yield(NULL);
+}
+
static gboolean on_resize(void *opaque, int width, int height)
{
VncDisplay *obj = VNC_DISPLAY(opaque);
VncDisplayPrivate *priv = obj->priv;
+ struct signal_data s;
if (priv->gvnc == NULL || !gvnc_is_initialized(priv->gvnc))
return TRUE;
@@ -830,10 +914,9 @@ static gboolean on_resize(void *opaque,
gvnc_set_local(priv->gvnc, &priv->fb);
- g_signal_emit (G_OBJECT (obj),
- signals[VNC_DESKTOP_RESIZE],
- 0,
- width, height);
+ s.width = width;
+ s.height = height;
+ emit_signal_delayed(obj, VNC_DESKTOP_RESIZE, &s);
return TRUE;
}
@@ -1004,6 +1087,7 @@ static gboolean on_auth_cred(void *opaqu
VncDisplay *obj = VNC_DISPLAY(opaque);
GValueArray *cred_list;
GValue username, password, clientname;
+ struct signal_data s;
memset(&username, 0, sizeof(username));
memset(&password, 0, sizeof(password));
@@ -1026,10 +1110,8 @@ static gboolean on_auth_cred(void *opaqu
cred_list = g_value_array_append(cred_list, &clientname);
}
- g_signal_emit (G_OBJECT (obj),
- signals[VNC_AUTH_CREDENTIAL],
- 0,
- cred_list);
+ s.cred_list = cred_list;
+ emit_signal_delayed(obj, VNC_AUTH_CREDENTIAL, &s);
g_value_array_free(cred_list);
@@ -1069,11 +1151,10 @@ static gboolean on_auth_failure(void *op
static gboolean on_auth_failure(void *opaque, const char *msg)
{
VncDisplay *obj = VNC_DISPLAY(opaque);
+ struct signal_data s;
- g_signal_emit (G_OBJECT (obj),
- signals[VNC_AUTH_FAILURE],
- 0,
- msg);
+ s.msg = msg;
+ emit_signal_delayed(obj, VNC_AUTH_FAILURE, &s);
return TRUE;
}
@@ -1081,11 +1162,10 @@ static gboolean on_auth_unsupported(void
static gboolean on_auth_unsupported(void *opaque, unsigned int auth_type)
{
VncDisplay *obj = VNC_DISPLAY(opaque);
+ struct signal_data s;
- g_signal_emit (G_OBJECT (obj),
- signals[VNC_AUTH_UNSUPPORTED],
- 0,
- auth_type);
+ s.auth_type = auth_type;
+ emit_signal_delayed(obj, VNC_AUTH_UNSUPPORTED, &s);
return TRUE;
}
@@ -1094,11 +1174,10 @@ static gboolean on_server_cut_text(void
{
VncDisplay *obj = VNC_DISPLAY(opaque);
GString *str = g_string_new_len ((const gchar *)text, len);
+ struct signal_data s;
- g_signal_emit (G_OBJECT (obj),
- signals[VNC_SERVER_CUT_TEXT],
- 0,
- str->str);
+ s.str = str;
+ emit_signal_delayed(obj, VNC_SERVER_CUT_TEXT, &s);
g_string_free (str, TRUE);
return TRUE;
@@ -1107,10 +1186,9 @@ static gboolean on_bell(void *opaque)
static gboolean on_bell(void *opaque)
{
VncDisplay *obj = VNC_DISPLAY(opaque);
+ struct signal_data s;
- g_signal_emit (G_OBJECT (obj),
- signals[VNC_BELL],
- 0);
+ emit_signal_delayed(obj, VNC_BELL, &s);
return TRUE;
}
@@ -1237,8 +1315,8 @@ static void *vnc_coroutine(void *opaque)
GVNC_ENCODING_RAW };
int32_t *encodingsp;
int n_encodings;
-
int ret;
+ struct signal_data s;
if (priv->gvnc == NULL || gvnc_is_open(priv->gvnc)) {
g_idle_add(delayed_unref_object, obj);
@@ -1254,17 +1332,13 @@ static void *vnc_coroutine(void *opaque)
goto cleanup;
}
- g_signal_emit (G_OBJECT (obj),
- signals[VNC_CONNECTED],
- 0);
+ emit_signal_delayed(obj, VNC_CONNECTED, &s);
GVNC_DEBUG("Protocol initialization\n");
if (!gvnc_initialize(priv->gvnc, FALSE))
goto cleanup;
- g_signal_emit (G_OBJECT (obj),
- signals[VNC_INITIALIZED],
- 0);
+ emit_signal_delayed(obj, VNC_INITIALIZED, &s);
encodingsp = encodings;
n_encodings = ARRAY_SIZE(encodings);
@@ -1295,9 +1369,7 @@ static void *vnc_coroutine(void *opaque)
cleanup:
GVNC_DEBUG("Doing final VNC cleanup\n");
gvnc_close(priv->gvnc);
- g_signal_emit (G_OBJECT (obj),
- signals[VNC_DISCONNECTED],
- 0);
+ emit_signal_delayed(obj, VNC_DISCONNECTED, &s);
g_idle_add(delayed_unref_object, obj);
/* Co-routine exits now - the VncDisplay object may no longer exist,
so don't do anything else now unless you like SEGVs */
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]