예제 #1
0
파일: mainloop.c 프로젝트: sjokkis/gjs
static JSBool
gjs_main_loop_run(JSContext *context,
                     JSObject  *obj,
                     uintN      argc,
                     jsval     *argv,
                     jsval     *retval)
{
    char *cancel_id;
    GMainLoop *main_loop;

    if (!gjs_parse_args(context, "run", "s", argc, argv,
                        "cancelId", &cancel_id))
      return JS_FALSE;

    main_loop = g_hash_table_lookup(pending_main_loops, cancel_id);

    if (!main_loop) {
        main_loop = g_main_loop_new(NULL, FALSE);
        g_hash_table_replace(pending_main_loops, g_strdup(cancel_id), main_loop);
    } else {
        g_main_loop_ref(main_loop);
    }

    gjs_debug(GJS_DEBUG_MAINLOOP,
              "main loop %s being run in context %p",
              cancel_id,
              context);
    g_free(cancel_id);

    g_main_loop_run(main_loop);
    g_main_loop_unref(main_loop);
    return JS_TRUE;
}
예제 #2
0
파일: main.c 프로젝트: smart-m3/sib-nota
int main(int argc, char *argv[])
{
  g_type_init();
  g_thread_init(NULL);
  /* Set signal handlers */
  signal(SIGINT, main_signal_handler);
  signal(SIGTERM, main_signal_handler);
   
  mainloop = g_main_loop_new(NULL, FALSE);
  g_main_loop_ref(mainloop);

  maxfd = sib_maxfd_new();
  rm_handler  = nota_rm_handler_new( maxfd );

  control = create_control(rm_handler);
  if(!control)
    {
      printf("\n\nCould not create control channel to sib-daemon, daemon running properly?\n");
      exit(1);
    }
  
  g_main_loop_run(mainloop);

  g_main_loop_unref(mainloop);
  
  printf("\n\nExiting normally\n\n");
  exit (0);
}
예제 #3
0
static void
bus_acquired_cb (GDBusConnection *connection,
		 const gchar     *name,
		 gpointer         user_data)
{
	GMainLoop *loop = (GMainLoop *) user_data;
	guint      registration_id;
	GError    *error = NULL;

	if (!introspection_data)
		introspection_data = g_dbus_node_info_new_for_xml (introspection_xml, NULL);

	registration_id = g_dbus_connection_register_object (connection,
							     EV_DBUS_DAEMON_OBJECT_PATH,
							     introspection_data->interfaces[0],
							     &interface_vtable,
							     g_main_loop_ref (loop),
							     (GDestroyNotify) g_main_loop_unref,
							     &error);
	if (registration_id == 0) {
		g_printerr ("Failed to register object: %s\n", error->message);
		g_error_free (error);

		if (g_main_loop_is_running (loop))
			g_main_loop_quit (loop);
	}
}
예제 #4
0
파일: init.c 프로젝트: smokku/libgmbus
/**
\brief Initialize the main loop
\param loop If loop is not NULL the given main loop is used, otherwise this
    function will create a new one.
*/
void
mbus_init( GMainLoop * loop )
{
	if ( loop == NULL ) {
		__loop = g_main_loop_new( NULL, FALSE );
	} else {
		g_main_loop_ref( loop );
		__loop = loop;
	}
}
static inline GMainLoop *
pyg_save_current_main_loop (GMainLoop *main_loop)
{
    GMainLoop *retval = pyg_current_main_loop;

    g_return_val_if_fail(main_loop != NULL, NULL);

    pyg_current_main_loop = g_main_loop_ref(main_loop);

    return retval;
}
예제 #6
0
파일: gst-glib.c 프로젝트: tonyg/smalltalk
GMainLoop *
push_main_loop (void)
{
  loop_list = g_slist_prepend (loop_list, loop);
  loop = g_main_loop_new (NULL, TRUE);

  main_loop_poll (0);

  /* Add a second reference that is passed to Smalltalk.  */
  g_main_loop_ref (loop);
  return loop;
}
예제 #7
0
static void handle_control_c(GMainLoop* loop)
{
    sigset_t mask;
    sigemptyset(&mask);
    sigaddset(&mask, SIGINT);
    sigaddset(&mask, SIGTERM);

    if (sigprocmask(SIG_BLOCK, &mask, NULL) < 0)
    {
        LogError("Failed to set signal mask");
    }
    else
    {
        int fd = signalfd(-1, &mask, 0);
        if (fd < 0)
        {
            LogError("Failed to create signal descriptor");
        }
        else
        {
            GIOChannel *channel = g_io_channel_unix_new(fd);
            if (channel == NULL)
            {
                close(fd);
                LogError("Failed to create IO channel");
            }
            else
            {
                g_io_channel_set_close_on_unref(channel, TRUE);
                g_io_channel_set_encoding(channel, NULL, NULL);
                g_io_channel_set_buffered(channel, FALSE);

                g_event_source_id = g_io_add_watch(
                    channel,
                    G_IO_IN | G_IO_HUP | G_IO_ERR | G_IO_NVAL,
                    signal_handler,
                    loop
                );

                if (g_event_source_id == 0)
                {
                    LogError("g_io_add_watch failed");
                }

                g_main_loop_ref(loop);
                g_io_channel_unref(channel);
            }
        }
    }
}
static inline GMainLoop *
pyg_save_current_main_loop (GMainLoop *main_loop)
{
    GMainLoop *retval;

    g_return_val_if_fail(main_loop != NULL, NULL);

    if (pyg_current_main_loop_key == -1)
	pyg_current_main_loop_key = PyThread_create_key();

    retval = PyThread_get_key_value(pyg_current_main_loop_key);
    PyThread_delete_key_value(pyg_current_main_loop_key);
    PyThread_set_key_value(pyg_current_main_loop_key, 
			   g_main_loop_ref(main_loop));

    return retval;
}
/**
 * Create the SIBService singleton if it doesn't exist. Otherwise returns
 * the pointer to the service singleton.
 *
 * @return SIBService*
 */
static SIBService* sib_service_new()
{
  whiteboard_log_debug_fb();

  if (service_singleton == NULL)
    {
      service_singleton = g_new0(SIBService, 1);
      g_return_val_if_fail(service_singleton != NULL, NULL);

      service_singleton->controller = sib_service_create_controller(service_singleton);
      service_singleton->ctrl_running = FALSE;

      service_singleton->main_loop = g_main_loop_new(NULL, FALSE);
      g_main_loop_ref(service_singleton->main_loop);

      service_singleton->mutex = g_mutex_new();
    }

  whiteboard_log_debug_fe();

  return service_singleton;
}
예제 #10
0
gint
main (gint argc, gchar **argv)
{
	GMainLoop *loop;
        guint owner_id;

        g_set_prgname ("atril-daemon");

	g_type_init ();

	loop = g_main_loop_new (NULL, FALSE);

	pending_invocations = g_hash_table_new_full (g_str_hash,
						     g_str_equal,
						     (GDestroyNotify)g_free,
						     NULL);

        owner_id = g_bus_own_name (G_BUS_TYPE_SESSION,
				   EV_DBUS_DAEMON_NAME,
				   G_BUS_NAME_OWNER_FLAGS_NONE,
				   bus_acquired_cb,
				   name_acquired_cb,
				   name_lost_cb,
				   g_main_loop_ref (loop),
				   (GDestroyNotify) g_main_loop_unref);

        g_main_loop_run (loop);

        g_bus_unown_name (owner_id);

        g_main_loop_unref (loop);
	if (introspection_data)
		g_dbus_node_info_unref (introspection_data);
        g_list_foreach (ev_daemon_docs, (GFunc)ev_doc_free, NULL);
        g_list_free (ev_daemon_docs);
        g_hash_table_destroy (pending_invocations);

	return 0;
}
예제 #11
0
static gpointer
loop_thread_init (gpointer data)
{
  KmsLoop *self = KMS_LOOP (data);
  GMainLoop *loop;
  GMainContext *context;

  KMS_LOOP_LOCK (self);
  self->priv->context = g_main_context_new ();
  context = g_main_context_ref (self->priv->context);
  self->priv->loop = g_main_loop_new (context, FALSE);
  loop = g_main_loop_ref (self->priv->loop);
  KMS_LOOP_UNLOCK (self);

  /* unlock main process because context is already initialized */
  g_mutex_lock (&self->priv->mutex);
  self->priv->initialized = TRUE;
  g_cond_signal (&self->priv->cond);
  g_mutex_unlock (&self->priv->mutex);

  if (!g_main_context_acquire (context)) {
    GST_ERROR ("Can not acquire context");
    goto end;
  }

  GST_DEBUG ("Running main loop");
  g_main_loop_run (loop);
  g_main_context_release (context);

end:
  GST_DEBUG ("Thread finished");
  g_main_loop_unref (loop);
  g_main_context_unref (context);

  return NULL;
}
static gpointer
provider_thread (gpointer data)
{
  GstV4l2DeviceProvider *provider = data;
  GMainContext *context = NULL;
  GMainLoop *loop = NULL;
  GUdevClient *client;
  GList *devices;
  static const gchar *subsystems[] = { "video4linux", NULL };

  GST_OBJECT_LOCK (provider);
  if (provider->context)
    context = g_main_context_ref (provider->context);
  if (provider->loop)
    loop = g_main_loop_ref (provider->loop);

  if (context == NULL || loop == NULL) {
    provider->started = TRUE;
    g_cond_broadcast (&provider->started_cond);
    GST_OBJECT_UNLOCK (provider);
    return NULL;
  }
  GST_OBJECT_UNLOCK (provider);

  g_main_context_push_thread_default (context);

  client = g_udev_client_new (subsystems);

  g_signal_connect (client, "uevent", G_CALLBACK (uevent_cb), provider);

  devices = g_udev_client_query_by_subsystem (client, "video4linux");

  while (devices) {
    GUdevDevice *udev_device = devices->data;
    GstDevice *gstdev;

    devices = g_list_remove (devices, udev_device);

    if (g_udev_device_get_property_as_int (udev_device, "ID_V4L_VERSION") == 2) {
      gstdev =
          gst_v4l2_device_provider_device_from_udev (provider, udev_device);
      if (gstdev)
        gst_device_provider_device_add (GST_DEVICE_PROVIDER (provider), gstdev);
    }

    g_object_unref (udev_device);
  }

  GST_OBJECT_LOCK (provider);
  provider->started = TRUE;
  g_cond_broadcast (&provider->started_cond);
  GST_OBJECT_UNLOCK (provider);

  g_main_loop_run (loop);
  g_main_loop_unref (loop);

  g_object_unref (client);
  g_main_context_unref (context);

  gst_object_unref (provider);

  return NULL;
}
int
main (int    argc,
      char **argv)
{
  GError *error;
  GOptionContext *opt_context;
  GMainLoop *main_loop;
  gint ret;
  guint name_owner_id;
  GIOChannel *stdin_channel;

  ret = 1;
  opt_context = NULL;
  name_owner_id = 0;
  stdin_channel = NULL;

  introspection_data = g_dbus_node_info_new_for_xml (introspection_xml, NULL);
  g_assert (introspection_data != NULL);

  opt_context = g_option_context_new ("gnome-shell calendar server");
  g_option_context_add_main_entries (opt_context, opt_entries, NULL);
  error = NULL;
  if (!g_option_context_parse (opt_context, &argc, &argv, &error))
    {
      g_printerr ("Error parsing options: %s", error->message);
      g_error_free (error);
      goto out;
    }

  main_loop = g_main_loop_new (NULL, FALSE);

  stdin_channel = g_io_channel_unix_new (STDIN_FILENO);
  g_io_add_watch_full (stdin_channel,
                       G_PRIORITY_DEFAULT,
                       G_IO_HUP,
                       stdin_channel_io_func,
                       g_main_loop_ref (main_loop),
                       (GDestroyNotify) g_main_loop_unref);

  name_owner_id = g_bus_own_name (G_BUS_TYPE_SESSION,
                                  BUS_NAME,
                                  G_BUS_NAME_OWNER_FLAGS_ALLOW_REPLACEMENT |
                                   (opt_replace ? G_BUS_NAME_OWNER_FLAGS_REPLACE : 0),
                                  on_bus_acquired,
                                  on_name_acquired,
                                  on_name_lost,
                                  g_main_loop_ref (main_loop),
                                  (GDestroyNotify) g_main_loop_unref);

  g_main_loop_run (main_loop);

  g_main_loop_unref (main_loop);

  ret = 0;

 out:
  if (stdin_channel != NULL)
    g_io_channel_unref (stdin_channel);
  if (_global_app != NULL)
    app_free (_global_app);
  if (name_owner_id != 0)
    g_bus_unown_name (name_owner_id);
  if (opt_context != NULL)
    g_option_context_free (opt_context);
  return ret;
}
예제 #14
0
template <> GMainLoop* refGPtr(GMainLoop* ptr)
{
    if (ptr)
        g_main_loop_ref(ptr);
    return ptr;
}
예제 #15
0
MiniBrowser::MiniBrowser(GMainLoop* mainLoop, Mode mode, int width, int height, int viewportHorizontalDisplacement, int viewportVerticalDisplacement)
    : m_context(AdoptWK, WKContextCreate())
    , m_pageGroup(AdoptWK, (WKPageGroupCreateWithIdentifier(WKStringCreateWithUTF8CString("MiniBrowser"))))
    , m_window(new LinuxWindow(this, width, height))
    , m_view(0)
    , m_mainLoop(mainLoop)
    , m_lastClickTime(0)
    , m_lastClickX(0)
    , m_lastClickY(0)
    , m_lastClickButton(kWKEventMouseButtonNoButton)
    , m_clickCount(0)
    , m_touchMocker(0)
    , m_mode(mode)
    , m_displayUpdateScheduled(false)
    , m_gestureRecognizer(GestureRecognizer(this))
    , m_postponeTextInputUpdates(true)
    , m_shouldFocusEditableArea(false)
    , m_shouldRestoreViewportWhenLosingFocus(false)
    , m_pageHandlesTouchEvents(false)
    , m_viewportMinScale(0.25)
    , m_viewportMaxScale(5)
    , m_viewportUserScalable(true)
    , m_viewportInitScale(1)
{
    g_main_loop_ref(m_mainLoop);

    WKPreferencesRef preferences = WKPageGroupGetPreferences(m_pageGroup.get());
    WKPreferencesSetAcceleratedCompositingEnabled(preferences, true);
    WKPreferencesSetFrameFlatteningEnabled(preferences, true);
    WKPreferencesSetDeveloperExtrasEnabled(preferences, true);

    m_view = NIXViewCreate(m_context.get(), m_pageGroup.get());

    NIXViewClient viewClient;
    memset(&viewClient, 0, sizeof(NIXViewClient));
    viewClient.version = kNIXViewClientCurrentVersion;
    viewClient.clientInfo = this;
    viewClient.viewNeedsDisplay = MiniBrowser::viewNeedsDisplay;
    viewClient.webProcessCrashed = MiniBrowser::webProcessCrashed;
    viewClient.webProcessRelaunched = MiniBrowser::webProcessRelaunched;
    viewClient.doneWithTouchEvent = MiniBrowser::doneWithTouchEvent;
    viewClient.doneWithGestureEvent = MiniBrowser::doneWithGestureEvent;
    viewClient.pageDidRequestScroll = MiniBrowser::pageDidRequestScroll;
    viewClient.didChangeContentsSize = MiniBrowser::didChangeContentsSize;
    viewClient.didChangeViewportAttributes = MiniBrowser::didChangeViewportAttributes;
    viewClient.didFindZoomableArea = MiniBrowser::didFindZoomableArea;
    viewClient.updateTextInputState = MiniBrowser::updateTextInputState;
    NIXViewSetViewClient(m_view, &viewClient);

    NIXViewInitialize(m_view);

    WKPageLoaderClient loaderClient;
    memset(&loaderClient, 0, sizeof(loaderClient));
    loaderClient.version = kWKPageLoaderClientCurrentVersion;
    loaderClient.clientInfo = this;
    loaderClient.didStartProgress = MiniBrowser::didStartProgress;
    WKPageSetPageLoaderClient(pageRef(), &loaderClient);

    if (m_mode == MobileMode)
        WKPageSetUseFixedLayout(pageRef(), true);

    WKSize size = m_window->size();
    m_viewRect = WKRectMake(viewportHorizontalDisplacement, viewportVerticalDisplacement, size.width - viewportHorizontalDisplacement, size.height - viewportVerticalDisplacement);
    NIXViewSetSize(m_view, m_viewRect.size);

    if (viewportHorizontalDisplacement || viewportVerticalDisplacement) {
        NIXMatrix transform = NIXMatrixMakeTranslation(viewportHorizontalDisplacement, viewportVerticalDisplacement);
        NIXViewSetUserViewportTransformation(m_view, &transform);
    }

    NIXViewSetFocused(m_view, true);
    NIXViewSetVisible(m_view, true);
    NIXViewSetActive(m_view, true);
}
예제 #16
0
void main_loop_test()
{
	GMainContext *default_context;
	int depth;
	int id;
	GTimeVal time ={0,};
	int user_data = 0,fd_data = 0;
	GPollFD pollfd;
	GSource *source3;

	GSourceFuncs SourceFuncs =
	{
		prepare,
		check,
		dispatch,
		NULL
	};

	GSourceFuncs fd_SourceFuncs =
	{
		fd_prepare,
		fd_check,
		fd_dispatch,
		NULL
	};

	e1_complete = FALSE;
	e2_complete = FALSE;

	pipe(fd);

	pollfd.fd = fd[0];
	pollfd.events = G_IO_IN | G_IO_HUP | G_IO_ERR;
	pollfd.revents = 0;

	pthread_create(&thread1, NULL, thread_function, NULL);

	context = g_main_context_new();

	//g_main_context_add_poll(context,&pollfd,0);

	source1 = g_source_new(&SourceFuncs,sizeof(GSource));
	g_source_set_callback(source1,(GSourceFunc)my_callback,&user_data,NULL);

	id = g_source_attach(source1,context);

	g_assert(g_source_get_id(source1) == id);

	g_source_set_priority(source1,0);

	g_assert(g_source_get_priority(source1) == 0);

	loop = g_main_loop_new(context, FALSE);

	default_context = g_main_loop_get_context(loop);

	//checks g_main_loop_get_context
	g_assert(default_context == context);

	//checks g_main_loop_is_running
	g_assert(g_main_loop_is_running(loop) == FALSE);

	depth = g_main_depth();

	//checks g_main_depth
	g_assert(depth == 0);

	g_source_get_current_time(source1,&time);

	g_assert(time.tv_usec > 0);

	g_source_set_can_recurse(source1,TRUE);

	g_assert(g_source_get_can_recurse(source1) == TRUE);

	source2 = g_source_new(&fd_SourceFuncs,sizeof(GSource));
	g_source_set_callback(source2,(GSourceFunc)fd_callback,&fd_data,NULL);
	g_source_add_poll(source2,&pollfd);

	g_source_remove_poll(source2,&pollfd);

	// checks g_source_remove_poll
	g_assert(source2->poll_fds == NULL);

	g_source_add_poll(source2,&pollfd);

	// checks whether g_source_add_poll is successful.
	// one more check is done in fd_callback.
	// If that function is callled we are sure that add poll was successful
	g_assert(source2->poll_fds->data == &pollfd);

	source3 = g_source_ref(source2);

	g_assert(source3 == source2 && source2->ref_count == 2);

	g_source_unref(source3);

	id = g_source_attach(source2,context);

	//checks g_main_context_pending
	g_assert(g_main_context_pending(context));

	g_main_loop_run(loop);

	// ref is called here. Thats why two unrefs are called. If the 2nd unref is
	// callled with the unref, code should crash
	g_main_loop_ref(loop);

	g_main_loop_unref(loop);

	g_main_loop_unref(loop);

	//checks the number of times the call back function is called
	g_assert(user_data == 100);

	// checks whether set poll was successful and call back for the same
	// was called
	g_assert(fd_data == 1);
}
예제 #17
0
파일: gda-worker.c 프로젝트: zzeroo/libgda
/**
 * gda_worker_do_job: (skip)
 * @worker: a #GdaWorker object
 * @context: (allow-none): a #GMainContext to execute a main loop in (while waiting), or %NULL
 * @timeout_ms: the maximum number of milisecons to wait before returning, or %0 for unlimited wait
 * @out_result: (allow-none): a place to store the result, if any, of @func's execution, or %NULL
 * @out_job_id: (allow-none): a place to store the ID of the job having been submitted, or %NULL
 * @func: the function to call from the worker thread
 * @data: (allow-none): the data to pass to @func, or %NULL
 * @data_destroy_func: (allow-none): a function to destroy @data, or %NULL
 * @result_destroy_func: (allow-none): a function to destroy the result, if any, of @func's execution, or %NULL
 * @error: (allow-none): a place to store errors, or %NULL.
 *
 * Request that the worker thread call @func with the @data argument, much like gda_worker_submit_job(),
 * but waits (starting a #GMainLoop) for a maximum of @timeout_ms miliseconds for @func to be executed.
 *
 * If this function is called from within @worker's worker thread, then this function simply calls @func with @data and does not
 * use @context.
 *
 * The following cases are possible if this function is not called from within @worker's worker thread:
 * <itemizedlist>
 *  <listitem><para>the call to @func took less than @timeout_ms miliseconds: the return value is %TRUE and 
 *    @out_result contains the result of the @func's execution, and @out_job_id contains %NULL. Note in this
 *    case that @error may still contain an error code if @func's execution produced an error. Also note that in this case
 *    any setting defined by gda_worker_set_callback() is not applied (as the result is immediately returned)</para></listitem>
 *  <listitem><para>The call to @func takes more then @timeout_ms miliseconds: the return value is %TRUE and
 *    @out_result is %NULL and @out_job_id contains the ID of the job as if it had been submitted using gda_worker_submit_job().
 *    If @out_job_id is %NULL, and if no setting has been defined using gda_worker_set_callback(), then the job will be discarded
 *    (as if gda_worker_forget_job() had been called).
 *    </para></listitem>
 *  <listitem><para>The call to @func could not be done (some kind of plumbing error for instance): the returned value is %FALSE
 *    and @out_result and @out_job_id are set to %NULL (if they are not %NULL)</para></listitem>
 * </itemizedlist>
 *
 * Notes:
 * <itemizedlist>
 *  <listitem><para>@result_destroy_func is needed in case @out_result is %NULL (to avoid memory leaks)</para></listitem>
 *  <listitem><para>passing %NULL for @context is similar to passing the result of g_main_context_ref_thread_default()</para></listitem>
 * </itemizedlist>
 *
 * Returns: %TRUE if no error occurred
 *
 * Since: 6.0
 */
gboolean
gda_worker_do_job (GdaWorker *worker, GMainContext *context, gint timeout_ms,
		   gpointer *out_result, guint *out_job_id,
		   GdaWorkerFunc func, gpointer data, GDestroyNotify data_destroy_func,
		   GDestroyNotify result_destroy_func,
		   GError **error)
{
	if (out_result)
		*out_result = NULL;
	if (out_job_id)
		*out_job_id = 0;

	g_return_val_if_fail (worker, FALSE);
	g_return_val_if_fail (func, FALSE);
	if (!worker->callbacks_hash || !worker->jobs_hash) {
		g_warning ("GdaWorker has been destroyed\n");
		return FALSE;
	}

	if (gda_worker_thread_is_worker (worker)) {
		/* we are called from within the worker thread => call the function directly */
		gpointer result;
		result = func (data, error);
		if (data_destroy_func)
			data_destroy_func (data);
		if (out_result)
			*out_result = result;
		else if (result && result_destroy_func)
			result_destroy_func (result);
		return TRUE;
	}

	guint jid, itsid, timer = 0;

	/* determine which GMainContext to use */
	GMainContext *co;
	gboolean unref_co = FALSE;

	co = context;
	if (!co) {
		co = g_main_context_ref_thread_default ();
		unref_co = TRUE;
	}

	/* prepare main loop */
	GMainLoop *loop;
        loop = g_main_loop_new (co, FALSE);

	/* prepare ITSignaler to be notified */
	ITSignaler *its;
	its = itsignaler_new ();
	itsid = itsignaler_add (its, co, (ITSignalerFunc) do_itsignaler_cb,
				g_main_loop_ref (loop), (GDestroyNotify) g_main_loop_unref);

	/* push job */
	g_rec_mutex_lock (& worker->rmutex); /* required to call _gda_worker_submit_job_with_its() */
	jid = _gda_worker_submit_job_with_its (worker, its,
					       func, data, data_destroy_func, result_destroy_func, error);
	g_rec_mutex_unlock (& worker->rmutex);
	if (jid == 0) {
		/* an error occurred */
		g_assert (itsignaler_remove (its, co, itsid));
		itsignaler_unref (its);
		g_main_loop_unref (loop);

		if (unref_co)
			g_main_context_unref (co);

		return FALSE;
	}

	/* check if result is already here */
	WorkerJob *job;
	job = itsignaler_pop_notification (its, 0);
	if (!job) {
		if (timeout_ms > 0) {
			/* start timer to limit waiting time */
			GSource *timer_src;
			timer_src = g_timeout_source_new (timeout_ms);
			g_source_set_callback (timer_src, (GSourceFunc) do_timer_cb, loop, NULL);
			timer = g_source_attach (timer_src, co);
			g_source_unref (timer_src);
		}
		g_main_loop_run (loop);

		/* either timer has arrived or job has been done */
		job = itsignaler_pop_notification (its, 0);
	}
	g_main_loop_unref (loop);

	g_assert (itsignaler_remove (its, co, itsid));
	itsignaler_unref (its);

	if (job) {
		/* job done before the timer, if any, elapsed */

		if (timer > 0)
			g_assert (g_source_remove (timer));

		g_assert (gda_worker_fetch_job_result (worker, jid, out_result, error));
	}
	else {
		/* timer came first, job is not yet finished */

		/* apply settings from gda_worker_set_callback(), if any */
		g_rec_mutex_lock (&worker->rmutex);
		DeclaredCallback *dc;
		dc = g_hash_table_lookup (worker->callbacks_hash, co);
		if (dc) {
			job = g_hash_table_lookup (worker->jobs_hash, &jid);
			g_assert (job);
			g_assert (!job->reply_its);
			job->reply_its = itsignaler_ref (dc->its);
		}
		g_rec_mutex_unlock (& worker->rmutex);

		/* cleanups */
		if (out_job_id)
			*out_job_id = jid;
		else if (!dc)
			/* forget all about the job */
			gda_worker_forget_job (worker, jid);
	}

	if (unref_co)
		g_main_context_unref (co);

	return TRUE;
}