Esempio n. 1
0
int
test3 (void)
{
	g_print ("Test3 started, main thread is %p\n", g_thread_self ());
	GdaWorker *worker;
	gint nfailed = 0;

	worker = gda_worker_new ();
	guint jid;
	GError *error = NULL;
	Data3 *data;
	data = g_new (Data3, 1);
	data->counter = 5;
	jid = gda_worker_submit_job (worker, NULL,
				     (GdaWorkerFunc) test3_worker_func, data, (GDestroyNotify) data3_free, NULL, &error);
	if (jid == 0) {
		g_print ("Error in gda_worker_submit_job(): %s\n", error && error->message ? error->message : "no detail");
		g_clear_error (&error);
		nfailed++;
		goto out;
	}

	while (1) {
		gint *result;
		if (! gda_worker_fetch_job_result (worker, jid, (gpointer*) &result, &error)) {
			g_print ("Still not done, error: %s\n", error && error->message ? error->message : "no detail");
			if ((error->domain == GDA_WORKER_ERROR) && (error->code == GDA_WORKER_JOB_NOT_FOUND_ERROR)) {
				nfailed++;
				g_clear_error (&error);
				break;
			}
			g_clear_error (&error);
		}
		else {
			if (result) {
				g_print ("Got result value: %d\n", *result);
				g_free (result);
			}
			else {
				g_print ("Error: got no result value!\n");
				nfailed++;
			}
			break;
		}
		g_usleep (100000);
	}

 out:
	gda_worker_unref (worker);

	return nfailed;
}
Esempio n. 2
0
static gboolean
dc_callback (ITSignaler *its, DeclaredCallback *dc)
{
	WorkerJob *job;
	job = itsignaler_pop_notification (its, 0);
	g_assert (job);

	gpointer result;
	guint jid;
	GError *error = NULL;
	jid = job->id;
	if (gda_worker_fetch_job_result (dc->worker, jid, &result, &error)) {
		dc->callback (dc->worker, jid, result, error, dc->user_data);
		g_clear_error (&error);
	}
	return TRUE; /* don't remove the source from poll, this can be done using gda_worker_set_callback() */
}
Esempio n. 3
0
int
test8 (void)
{
	g_print ("%s started, main thread is %p\n", __FUNCTION__, g_thread_self ());
	GdaWorker *worker;
	gint nfailed = 0;

	worker = gda_worker_new ();
	GError *error = NULL;

	guint jid;
	jid = gda_worker_submit_job (worker, NULL, (GdaWorkerFunc) test8_func, worker, NULL, NULL, &error);
	if (jid == 0) {
		g_print ("gda_worker_submit_job() failed: %s\n", error && error->message ? error->message : "No detail");
		g_clear_error (&error);
		nfailed ++;
	}
	else {
		while (1) {
			gpointer out;
			g_print ("Waiting for result using gda_worker_fetch_job_result()\n");
			if (gda_worker_fetch_job_result (worker, jid, &out, &error)) {
				if (!out || strcmp (out, "test8_sub_func")) {
					g_print ("Expected out to be [test8_sub_func] and got %s\n", (gchar*) out);
					nfailed++;
				}
				if (error) {
					g_print ("Got error: %s\n", error && error->message ? error->message : "No detail");
					g_clear_error (&error);
					nfailed++;
				}
				break;
			}
			else
				g_clear_error (&error);
			g_usleep (100000);
		}
	}

	g_print ("Unref worker...\n");

	gda_worker_unref (worker);
	g_print ("%s done\n", __FUNCTION__);

	return nfailed;
}
Esempio n. 4
0
/**
 * gda_worker_wait_job: (skip)
 * @worker: a #GdaWorker object
 * @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
 * @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 (blocks) until @func has been executed.
 *
 * Note: it's up to the caller to free the result, the #GdaWorker object will not do it (ownership of the result is
 * transfered to the caller).
 *
 * Returns: (transfer full): the result of @func's execution
 *
 * Since: 6.0
 */
gpointer
gda_worker_wait_job (GdaWorker *worker, GdaWorkerFunc func, gpointer data, GDestroyNotify data_destroy_func,
		     GError **error)
{
	g_return_val_if_fail (worker, NULL);
	g_return_val_if_fail (func, NULL);

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

	guint jid;

	/* prepare ITSignaler to be notified */
	ITSignaler *its;
	its = itsignaler_new ();

	/* 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, NULL, error);
	g_rec_mutex_unlock (& worker->rmutex);

	if (jid == 0) {
		/* an error occurred */
		itsignaler_unref (its);
		return NULL;
	}

	WorkerJob *job;
	job = itsignaler_pop_notification (its, -1);
	g_assert (job);
	itsignaler_unref (its);

	gpointer result;
	g_assert (gda_worker_fetch_job_result (worker, jid, &result, error));

	return result;
}
Esempio n. 5
0
static gpointer
test8_func (GdaWorker *worker, G_GNUC_UNUSED GError **error)
{
	guint jid;
	jid = gda_worker_submit_job (worker, NULL, (GdaWorkerFunc) test8_sub_func, NULL, NULL, NULL, error);
	if (jid == 0)
		return NULL;
	else {
		g_print ("%s() submitted job %u with thread %p\n", __FUNCTION__, jid, g_thread_self ());
		while (1) {
			gpointer out;
			GError *lerror = NULL;
			g_print ("Waiting for result...\n");
			if (gda_worker_fetch_job_result (worker, jid, &out, &lerror)) {
				if (lerror)
					g_propagate_error (error, lerror);
				return out;
			}
			else
				g_clear_error (&lerror);
			g_usleep (100000);
		}
	}
}
Esempio n. 6
0
/*
 * Test 7: gda_worker_do_job()
 * - A ticker is run to make sure the events are handled while in gda_worker_do_job()
 * - a simple job is run
 * - job finishes after timer
 */
int
test7 (void)
{
	g_print ("%s started, main thread is %p\n", __FUNCTION__, g_thread_self ());
	GdaWorker *worker;
	gint nfailed = 0;

	worker = gda_worker_new ();
	GError *error = NULL;

	guint nticks = 0;
	guint timer;
	timer = g_timeout_add (10, (GSourceFunc) test6_timer_cb, &nticks);

	guint jid;
	gpointer out;
	gint wait;
	wait = 150;
	if (gda_worker_do_job (worker, NULL, 100, &out, &jid,
			       (GdaWorkerFunc) test6_worker_func, (gpointer) &wait, NULL,
			       (GDestroyNotify) test6_string_free, &error)) {
		g_print ("out: [%s], JID: %u\n", (gchar*) out, jid);
		if (out) {
			g_print ("Expected out to be NULL and got [%s]\n", (gchar*) out);
			nfailed++;
			g_free (out);
		}
		if (jid == 0) {
			g_print ("Expected JID to be > 0 and got %u\n", jid);
			nfailed++;
		}

		while (1) {
			g_print ("Waiting for result using gda_worker_fetch_job_result()\n");
			if (gda_worker_fetch_job_result (worker, jid, &out, &error)) {
				if (!out || strcmp (out, "Test6Done")) {
					g_print ("Expected out to be [Test6Done] and got [%s]\n", (gchar*) out);
					nfailed++;
				}
				g_free (out);
				break;
			}
			else
				g_clear_error (&error);
			g_usleep (100000);
		}
	}
	else {
		g_print ("gda_worker_do_job() failed: %s\n", error && error->message ? error->message : "No detail");
		g_clear_error (&error);
		nfailed ++;
	}
	g_source_remove (timer);

	if (nticks < 3) {
		g_print ("Tick timer was not called while in gda_worker_do_job()\n");
		nfailed++;
	}
	g_print ("Unref worker...\n");

	gda_worker_unref (worker);
	g_print ("%s done\n", __FUNCTION__);

	return nfailed;
}
Esempio n. 7
0
int
test4 (void)
{
	g_print ("Test4 started, main thread is %p\n", g_thread_self ());
	GdaWorker *worker;
	gint nfailed = 0;

	worker = gda_worker_new ();
	guint jid1, jid2;
	GError *error = NULL;
	jid1 = gda_worker_submit_job (worker, NULL, (GdaWorkerFunc) test4_worker_func, NULL, NULL, NULL, &error);
	if (jid1 == 0) {
		g_print ("Error in gda_worker_submit_job(): %s\n", error && error->message ? error->message : "no detail");
		g_clear_error (&error);
		nfailed++;
		goto out;
	}
	jid2 = gda_worker_submit_job (worker, NULL, (GdaWorkerFunc) test4_worker_func, NULL, NULL, NULL, &error);
	if (jid2 == 0) {
		g_print ("Error in gda_worker_submit_job(): %s\n", error && error->message ? error->message : "no detail");
		g_clear_error (&error);
		nfailed++;
		goto out;
	}

	if (! gda_worker_cancel_job (worker, jid2, &error)) {
		g_print ("Error in gda_worker_cancel_job(): %s\n", error && error->message ? error->message : "no detail");
		g_clear_error (&error);
		nfailed++;
		goto out;
	}
	if (! gda_worker_cancel_job (worker, jid2, &error)) {
		g_print ("Error in gda_worker_cancel_job(): %s\n", error && error->message ? error->message : "no detail");
		g_clear_error (&error);
		nfailed++;
		goto out;
	}
	if (gda_worker_cancel_job (worker, 10, NULL)) {
		g_print ("Error in gda_worker_cancel_job(): should have failed!\n");
		nfailed++;
		goto out;
	}

	while (1) {
		gint *result;
		if (! gda_worker_fetch_job_result (worker, jid1, (gpointer*) &result, &error)) {
			g_print ("Still not done, error: %s\n", error && error->message ? error->message : "no detail");
			if ((error->domain == GDA_WORKER_ERROR) && (error->code == GDA_WORKER_JOB_NOT_FOUND_ERROR)) {
				nfailed++;
				g_clear_error (&error);
				break;
			}
			g_clear_error (&error);
		}
		else {
			if (result) {
				g_print ("Error: got result value when expected none!\n");
				nfailed++;
			}
			break;
		}
		g_usleep (100000);
	}
 out:
	gda_worker_unref (worker);

	return nfailed;
}
Esempio n. 8
0
/**
 * 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;
}