| /* GLib testing framework examples and tests |
| * |
| * Copyright (C) 2008-2010 Red Hat, Inc. |
| * |
| * This library is free software; you can redistribute it and/or |
| * modify it under the terms of the GNU Lesser General Public |
| * License as published by the Free Software Foundation; either |
| * version 2 of the License, or (at your option) any later version. |
| * |
| * This library is distributed in the hope that it will be useful, |
| * but WITHOUT ANY WARRANTY; without even the implied warranty of |
| * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
| * Lesser General Public License for more details. |
| * |
| * You should have received a copy of the GNU Lesser General |
| * Public License along with this library; if not, write to the |
| * Free Software Foundation, Inc., 59 Temple Place, Suite 330, |
| * Boston, MA 02111-1307, USA. |
| * |
| * Author: David Zeuthen <davidz@redhat.com> |
| */ |
| |
| #include <gio/gio.h> |
| #include <unistd.h> |
| |
| #include "gdbus-tests.h" |
| |
| /* ---------------------------------------------------------------------------------------------------- */ |
| |
| typedef struct |
| { |
| GMainLoop *loop; |
| gboolean timed_out; |
| } PropertyNotifyData; |
| |
| static void |
| on_property_notify (GObject *object, |
| GParamSpec *pspec, |
| gpointer user_data) |
| { |
| PropertyNotifyData *data = user_data; |
| g_main_loop_quit (data->loop); |
| } |
| |
| static gboolean |
| on_property_notify_timeout (gpointer user_data) |
| { |
| PropertyNotifyData *data = user_data; |
| data->timed_out = TRUE; |
| g_main_loop_quit (data->loop); |
| return TRUE; |
| } |
| |
| gboolean |
| _g_assert_property_notify_run (gpointer object, |
| const gchar *property_name) |
| { |
| gchar *s; |
| gulong handler_id; |
| guint timeout_id; |
| PropertyNotifyData data; |
| |
| data.loop = g_main_loop_new (NULL, FALSE); |
| data.timed_out = FALSE; |
| s = g_strdup_printf ("notify::%s", property_name); |
| handler_id = g_signal_connect (object, |
| s, |
| G_CALLBACK (on_property_notify), |
| &data); |
| g_free (s); |
| timeout_id = g_timeout_add (30 * 1000, |
| on_property_notify_timeout, |
| &data); |
| g_main_loop_run (data.loop); |
| g_signal_handler_disconnect (object, handler_id); |
| g_source_remove (timeout_id); |
| g_main_loop_unref (data.loop); |
| |
| return data.timed_out; |
| } |
| |
| /* ---------------------------------------------------------------------------------------------------- */ |
| |
| typedef struct |
| { |
| GMainLoop *loop; |
| gboolean timed_out; |
| } SignalReceivedData; |
| |
| static void |
| on_signal_received (gpointer user_data) |
| { |
| SignalReceivedData *data = user_data; |
| g_main_loop_quit (data->loop); |
| } |
| |
| static gboolean |
| on_signal_received_timeout (gpointer user_data) |
| { |
| SignalReceivedData *data = user_data; |
| data->timed_out = TRUE; |
| g_main_loop_quit (data->loop); |
| return TRUE; |
| } |
| |
| gboolean |
| _g_assert_signal_received_run (gpointer object, |
| const gchar *signal_name) |
| { |
| gulong handler_id; |
| guint timeout_id; |
| SignalReceivedData data; |
| |
| data.loop = g_main_loop_new (NULL, FALSE); |
| data.timed_out = FALSE; |
| handler_id = g_signal_connect_swapped (object, |
| signal_name, |
| G_CALLBACK (on_signal_received), |
| &data); |
| timeout_id = g_timeout_add (30 * 1000, |
| on_signal_received_timeout, |
| &data); |
| g_main_loop_run (data.loop); |
| g_signal_handler_disconnect (object, handler_id); |
| g_source_remove (timeout_id); |
| g_main_loop_unref (data.loop); |
| |
| return data.timed_out; |
| } |
| |
| /* ---------------------------------------------------------------------------------------------------- */ |
| |
| GDBusConnection * |
| _g_bus_get_priv (GBusType bus_type, |
| GCancellable *cancellable, |
| GError **error) |
| { |
| gchar *address; |
| GDBusConnection *ret; |
| |
| ret = NULL; |
| |
| address = g_dbus_address_get_for_bus_sync (bus_type, cancellable, error); |
| if (address == NULL) |
| goto out; |
| |
| ret = g_dbus_connection_new_for_address_sync (address, |
| G_DBUS_CONNECTION_FLAGS_AUTHENTICATION_CLIENT | |
| G_DBUS_CONNECTION_FLAGS_MESSAGE_BUS_CONNECTION, |
| NULL, /* GDBusAuthObserver */ |
| cancellable, |
| error); |
| g_free (address); |
| |
| out: |
| return ret; |
| } |
| |
| /* ---------------------------------------------------------------------------------------------------- */ |
| |
| #if 1 |
| /* toggle refs are not easy to use (maybe not even safe) when multiple |
| * threads are involved so implement this by busy-waiting for now |
| */ |
| gboolean |
| _g_object_wait_for_single_ref_do (gpointer object) |
| { |
| guint num_ms_elapsed; |
| gboolean timed_out; |
| |
| timed_out = FALSE; |
| num_ms_elapsed = 0; |
| |
| while (TRUE) |
| { |
| if (G_OBJECT (object)->ref_count == 1) |
| goto out; |
| |
| if (num_ms_elapsed > 30000) |
| { |
| timed_out = TRUE; |
| goto out; |
| } |
| |
| usleep (10 * 1000); |
| num_ms_elapsed += 10; |
| } |
| |
| out: |
| return timed_out; |
| } |
| |
| #else |
| |
| typedef struct |
| { |
| GMainLoop *loop; |
| gboolean timed_out; |
| } WaitSingleRefData; |
| |
| static gboolean |
| on_wait_single_ref_timeout (gpointer user_data) |
| { |
| WaitSingleRefData *data = user_data; |
| data->timed_out = TRUE; |
| g_main_loop_quit (data->loop); |
| return TRUE; |
| } |
| |
| static void |
| on_wait_for_single_ref_toggled (gpointer user_data, |
| GObject *object, |
| gboolean is_last_ref) |
| { |
| WaitSingleRefData *data = user_data; |
| g_main_loop_quit (data->loop); |
| } |
| |
| gboolean |
| _g_object_wait_for_single_ref_do (gpointer object) |
| { |
| WaitSingleRefData data; |
| guint timeout_id; |
| |
| data.timed_out = FALSE; |
| |
| if (G_OBJECT (object)->ref_count == 1) |
| goto out; |
| |
| data.loop = g_main_loop_new (NULL, FALSE); |
| timeout_id = g_timeout_add (30 * 1000, |
| on_wait_single_ref_timeout, |
| &data); |
| |
| g_object_add_toggle_ref (G_OBJECT (object), |
| on_wait_for_single_ref_toggled, |
| &data); |
| /* the reference could have been removed between us checking the |
| * ref_count and the toggle ref being added |
| */ |
| if (G_OBJECT (object)->ref_count == 2) |
| goto single_ref_already; |
| |
| g_object_unref (object); |
| g_main_loop_run (data.loop); |
| g_object_ref (object); |
| |
| single_ref_already: |
| g_object_remove_toggle_ref (object, |
| on_wait_for_single_ref_toggled, |
| &data); |
| |
| g_source_remove (timeout_id); |
| g_main_loop_unref (data.loop); |
| |
| out: |
| if (data.timed_out) |
| { |
| g_printerr ("b ref_count is %d\n", G_OBJECT (object)->ref_count); |
| } |
| return data.timed_out; |
| } |
| #endif |
| |
| /* ---------------------------------------------------------------------------------------------------- */ |