From: <svn...@op...> - 2009-03-24 12:42:03
|
Author: bellmich Date: Tue Mar 24 13:41:46 2009 New Revision: 1008 URL: http://libsyncml.opensync.org/changeset/1008 Log: added an internal function to run a function in a special thread This feature is necessary because some libaries like libsoup are only designed for single-threaded applications. This means that every function must be called from the same thread. Otherwise there is no guarantee about the behaviour of the library. Modified: trunk/libsyncml/sml_support.c trunk/libsyncml/sml_support.h Modified: trunk/libsyncml/sml_support.c ============================================================================== --- trunk/libsyncml/sml_support.c Mon Mar 23 16:55:38 2009 (r1007) +++ trunk/libsyncml/sml_support.c Tue Mar 24 13:41:46 2009 (r1008) @@ -496,6 +496,111 @@ smlTrace(TRACE_EXIT, "%s", __func__); } +/** + * This context is used to cache the environment for direct function + * calls within a special thread. + * Please see smlThreadCallFunction for more details. + */ +typedef struct SmlThreadFunctionContext { + GMutex *mutex; + GCond *cond; + SmlThreadCallFunctionType func; + gpointer data; + SmlBool result; + SmlError **error; +} SmlThreadFunctionContext; + +/** + * This callback is used to call a function within a special thread. + * Please see smlThreadCallFunction for more details. + */ +gboolean smlThreadCallFunctionCallback(gpointer data) +{ + smlTrace(TRACE_ENTRY, "%s", __func__); + smlAssert(data); + + SmlThreadFunctionContext *ctx = data; + ctx->result = ctx->func(ctx->data, ctx->error); + g_mutex_lock(ctx->mutex); + g_cond_signal(ctx->cond); + g_mutex_unlock(ctx->mutex); + + /* This function should only run once. */ + smlTrace(TRACE_EXIT, "%s", __func__); + return FALSE; +} + +/** + * This function can be used to execute a function in a special thread. + * Some libraries are designed for single-threaded applications. + * They require that a set of commands is only executed in one thread. + * These applications use g_main_loop too. So the functions must be + * executed in this loop. This will be done synchronously by this + * function. + * + * Please note: This function is blocking. + * Please note: The glib source priority is IDLE. + */ +SmlBool smlThreadCallFunction( + SmlThread *thread, + SmlThreadCallFunctionType func, + gpointer data, + SmlError **error) +{ + smlTrace(TRACE_ENTRY, "%s", __func__); + CHECK_ERROR_REF + smlAssert(func); + + /* initialize function context */ + SmlThreadFunctionContext *ctx; + ctx = smlTryMalloc0(sizeof(SmlThreadFunctionContext), error); + if (!ctx) + goto error; + ctx->mutex = g_mutex_new(); + if (!ctx->mutex) { + smlErrorSet(error, SML_ERROR_GENERIC, "Cannot create new mutex."); + goto error; + } + ctx->cond = g_cond_new(); + if (!ctx->cond) { + smlErrorSet(error, SML_ERROR_GENERIC, "Cannot create new condition."); + goto error; + } + ctx->func = func; + ctx->data = data; + ctx->error = error; + + /* prepare glib source */ + GSource *source = g_idle_source_new(); + g_source_set_callback(source, smlThreadCallFunctionCallback, ctx, NULL); + + /* call function "synchronously" */ + g_mutex_lock(ctx->mutex); + g_source_attach(source, thread->context); + g_cond_wait(ctx->cond, ctx->mutex); + g_mutex_unlock(ctx->mutex); + + /* cleanup */ + SmlBool result = ctx->result; + g_source_unref(source); + g_mutex_free(ctx->mutex); + g_cond_free(ctx->cond); + smlSafeFree((gpointer *) &ctx); + + /* return result */ + smlTrace(TRACE_EXIT, "%s - %i", __func__, result); + return result; +error: + if (ctx->cond) + g_cond_free(ctx->cond); + if (ctx->mutex) + g_mutex_free(ctx->mutex); + if (ctx) + smlSafeFree((gpointer *) &ctx); + smlTrace(TRACE_EXIT_ERROR, "%s - %s", __func__, smlErrorPrint(error)); + return FALSE; +} + void smlSafeFree(gpointer *address) { smlAssert(address); Modified: trunk/libsyncml/sml_support.h ============================================================================== --- trunk/libsyncml/sml_support.h Mon Mar 23 16:55:38 2009 (r1007) +++ trunk/libsyncml/sml_support.h Tue Mar 24 13:41:46 2009 (r1008) @@ -63,6 +63,16 @@ void smlThreadStart(SmlThread *thread); void smlThreadStop(SmlThread *thread); +typedef SmlBool (* SmlThreadCallFunctionType) ( + gpointer data, + SmlError **error); + +SmlBool smlThreadCallFunction( + SmlThread *thread, + SmlThreadCallFunctionType func, + gpointer data, + SmlError **error); + void smlSafeFree(gpointer *address); void smlSafeCFree(char **address); |