Re: Strange interaction between GtkDialog and a GThread



Thanks for the reply. Interesting. Replacing sleep()
with select() did return an error with errno == EINTR.
If I understand you correctly, this is a clue that
gtk_file_chooser_dialog_new is calling alarm()
somewhere.

That may indeed factor in to what I am trying to
solve. But fact is, getting a thread to sleep wasn't
really my goal, I just used that to make a simple
example that would "break." 

The real challenge I've been having for a couple weeks
is with a thread running a blocking D-Bus server. The
server works great, but if I launch a
gtk_file_chooser_dialog_new, the entire app goes very
weird! Below is as simple an example as I could make
(without the client; I could paste that code too if
wanted, but it is not needed to see the weirdness).

Basically, the inconsistent results look like some
kind of deadlock; usually on my system, it will not
open the dialog, but if the dialog does open, it is
dead. Yet normally the D-Bus thread happily continues
to serve clients. But not always. Strangest to me is
the backtrace; before the call to
gtk_file_chooser_dialog_new, the main thread has (as
one would expect) no calls to libdbus-1.so.3; after
the call to gtk_file_chooser_dialog_new, the main
thread is polluted with myriad calls to
libdbus-1.so.3., as if it merged with the other
thread. Initially, I thought this was a D-Bus problem,
so I posted to the D-Bus list; then I started to think
it was a GTK issue, so I've posted here. BTW, the
D-Bus list did offer one interesting response about
how what I see may be related to the strange code
behind gtk_dialog_run, in that it "re-enters the main
loop." I did look at it's code, and it did mystify me.
Here's the thread:
[
http://lists.freedesktop.org/archives/dbus/2007-November/008968.html
]

Any ideas?

Thanks again!

//////////////////////////////////////
/*
Demonstration of strange
gtk_file_chooser_dialog_new/dbus
interaction.
Compile with:
gcc main.c -o HelloThreadBreaker \
`pkg-config --cflags --libs \
gtk+-2.0 gthread-2.0 dbus-1`
 */

#include <unistd.h>
#include <gtk/gtk.h>
#include <dbus/dbus.h>

#define GNAURAL_DBUS_SERVER    "org.gnaural.Server"
#define GNAURAL_DBUS_INTERFACE "org.gnaural.Interface"

DBusConnection *main_remote_connection = NULL;
time_t main_startime;

/////////////////////////////
void GetBeatfreq (DBusMessage * msg, DBusConnection *
conn)
{
DBusMessage *reply;
DBusMessageIter args;
unsigned int voice = 0;

if (!dbus_message_iter_init (msg, &args))
{
fprintf (stderr, "Message has no arguments\n");
}
else if (DBUS_TYPE_UINT32 !=
dbus_message_iter_get_arg_type (&args))
{
fprintf (stderr, "Argument is not
DBUS_TYPE_UINT32\n");
}
else
{
dbus_message_iter_get_basic (&args, &voice);
}

reply = dbus_message_new_method_return (msg);

double result = (double) (time (NULL) -
main_startime);

dbus_message_iter_init_append (reply, &args);
if (!dbus_message_iter_append_basic (&args,
DBUS_TYPE_DOUBLE, &result))
{
fprintf (stderr, "Out Of Memory\n");
return;
}

if (!dbus_connection_send (conn, reply, NULL))
{
fprintf (stderr, "Out Of Memory\n");
return;
}
dbus_connection_flush (conn);
dbus_message_unref (reply);
}

/////////////////////////////
int main_init_connection (void)
{
DBusError err;
int ret;

dbus_error_init (&err);

main_remote_connection = dbus_bus_get
(DBUS_BUS_SESSION, &err);
if (dbus_error_is_set (&err))
{
fprintf (stderr, "Connection Error (%s)\n",
err.message);
dbus_error_free (&err);
}
if (NULL == main_remote_connection)
{
fprintf (stderr, "Connection Null\n");
return 1;
}

ret =
dbus_bus_request_name (main_remote_connection,
GNAURAL_DBUS_SERVER,
DBUS_NAME_FLAG_REPLACE_EXISTING, &err);
if (dbus_error_is_set (&err))
{
fprintf (stderr, "Name Error (%s)\n", err.message);
dbus_error_free (&err);
}
if (DBUS_REQUEST_NAME_REPLY_PRIMARY_OWNER != ret)
{
fprintf (stderr, "Not Primary Owner (%d)\n", ret);
return 1;
}
return 0;
}

////////////////////////////////
void main_check_for_methodcall (gpointer arg)
{
DBusMessage *msg;

if (NULL == main_remote_connection)
{
fprintf (stderr, "Connection invalid!\n");
return;
}
fprintf (stderr, "Entering blocking loop\n");
while (dbus_connection_read_write_dispatch
(main_remote_connection, -1))
{
msg = dbus_connection_pop_message
(main_remote_connection);

if (NULL == msg)
{
fprintf (stderr, "Message == NULL\n");
continue;
}
else
{
fprintf (stderr, "Got Something... ");
}

if (dbus_message_is_method_call (msg,  //DBusMessage *
msg
GNAURAL_DBUS_INTERFACE,//char * interface
"GetBeatfreq"))//char * method
{
GetBeatfreq (msg, main_remote_connection);
fprintf (stderr, "Running GetBeatfreq\n");
}
else
{
fprintf (stderr, "Call not recognized\n");
}

dbus_message_unref (msg);
}

fprintf (stderr, "Leaving wait for methodcall
loop\n");
}

//////////////////////////////////
void *sleep_for_awhile (void *args)
{
time_t t1;
time_t t2;

g_print ("Sleeping for 2 seconds\n");
time (&t1);
sleep (1);
time (&t2);
g_print ("Slept for %d seconds\n", (int) (t2 - t1));
main_init_connection ();
g_print ("Blocking forever\n");

main_check_for_methodcall (NULL);

time (&t2);
g_print ("Blocked for %d seconds\n", (int) (t2 - t1));
g_print ("Thread terminated naturally\n");
return NULL;
}

////////////////////////////////
int main (int argc, char *argv[])
{
GError *error = NULL;
GtkWidget *dialog = NULL;

time (&main_startime);

g_thread_init (NULL);
gdk_threads_init ();
gdk_threads_enter ();

gtk_init (&argc, &argv);

if (!g_thread_create (sleep_for_awhile, NULL, FALSE,
&error))
{
g_printerr ("g_thread_create failed:%s\n",
error->message);
return 1;
}

//this does not work with thread:
dialog = gtk_file_chooser_dialog_new ("Open File",
NULL,
GTK_FILE_CHOOSER_ACTION_OPEN,
GTK_STOCK_CANCEL,
GTK_RESPONSE_CANCEL,
GTK_STOCK_OPEN,
GTK_RESPONSE_ACCEPT, NULL);

if (gtk_dialog_run (GTK_DIALOG (dialog)) ==
GTK_RESPONSE_ACCEPT)
{
g_free (gtk_file_chooser_get_filename
(GTK_FILE_CHOOSER (dialog)));
}

 /* 
 //this variety does work with thread:
 dialog = gtk_message_dialog_new (NULL,
 GTK_DIALOG_MODAL,
 GTK_MESSAGE_INFO, GTK_BUTTONS_OK,
 "Message Box");
 gtk_dialog_run (GTK_DIALOG (dialog));
  */
 
gtk_widget_destroy (dialog);

gtk_main ();
gdk_threads_leave ();

return 0;
}




[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]