How to call asynchronous function synchronously

GLib provides a lot of asynchronous functions, especially to deal with I/O. Unfortunately, some functions don’t have synchronous equivalents and the code has to be split into several callbacks. This is not handy in some cases. My this year’s GSoC student recently asked me whether it is possible to create synchronous function from asynchronous. He is currently working on test suite and don’t want to split test cases into several callbacks. So I decided to write a blog spot about as it might be handy for more people. Let’s explain it with an example on how to create g_file_mount_enclosing_volume_sync () from g_file_mount_enclosing_volume ():

typedef struct
{
  GMainLoop *loop;
  GAsyncResult *res;
} MountData;

static void
mount_cb (GObject *source_object,
          GAsyncResult *res,
          gpointer user_data)
{
  MountData *data = user_data;

  data->res = g_object_ref (res);
  g_main_loop_quit (data->loop);
}

static gboolean
g_file_mount_enclosing_volume_sync (GFile *location,
                                    GMountMountFlags flags,
                                    GMountOperation *mount_operation,
                                    GCancellable *cancellable,
                                    GError **error)
{
  g_autoptr (GMainContext) context  = NULL;
  g_autoptr (GMainLoop) loop = NULL;
  MountData data;
  gboolean retval;

  context = g_main_context_new ();
  loop = g_main_loop_new (context, FALSE);
 
  g_main_context_push_thread_default (context);

  data.loop = loop;
  g_file_mount_enclosing_volume (location,
                                 flags,
                                 mount_operation,
                                 cancellable,
                                 mount_cb,
                                 &data);
  g_main_loop_run (loop);
  retval = g_file_mount_enclosing_volume_finish (location, data.res, error);
  g_object_unref (data.res);

  g_main_context_pop_thread_default (context);

  return retval;
}

A similar approach can be seen on various places of GLib and GVfs source codes.