/*
* libopensync - A synchronization framework
* Copyright (C) 2004-2005 Armin Bauer <armin.bauer@opensync.org>
*
* 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.1 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
*
*/
#include "opensync.h"
#include "opensync_internals.h"
/**
* @defgroup PrivateAPI Private APIs
* @brief Available private APIs
*
*/
/**
* @defgroup OSyncPrivate OpenSync Private API
* @ingroup PrivateAPI
* @brief The private API of opensync
*
* This gives you an insight in the private API of opensync.
*
*/
/**
* @defgroup OSyncEnvPrivate OpenSync Environment Internals
* @ingroup OSyncPrivate
* @brief The internals of the opensync environment
*
*/
/*@{*/
/* Get the value of a an OSyncEnv option
*
* Search order:
* - options set using osync_env_set_option()
* - OSYNC_* environment variables
*/
static const char *osync_env_query_option(OSyncEnv *env, const char *name)
{
const char *value;
value = g_hash_table_lookup(env->options, name);
if (value)
return value;
gchar *env_name = g_strdup_printf("OSYNC_%s", name);
value = getenv(env_name);
g_free(env_name);
if (value)
return value;
return NULL;
}
static osync_bool osync_env_query_option_bool(OSyncEnv *env, const char *name)
{
const char *get_value;
if (!(get_value = osync_env_query_option(env, name)))
return FALSE;
if (!strcmp(get_value, "TRUE"))
return TRUE;
return FALSE;
}
/** Export the list of loaded plugins through the OSYNC_LOADED_PLUGINS environment variable
*
*/
void osync_env_export_loaded_modules(OSyncEnv *env)
{
int num_modules = g_list_length(env->modules);
/* build an array for g_strjoinv() */
gchar **path_array = g_malloc0(sizeof(gchar*)*(num_modules + 1));
int i;
for (i = 0; i < num_modules; i++) {
GModule *module = g_list_nth_data(env->modules, i);
const gchar *path = g_module_name(module);
/*XXX: casting to non-const, here. Ugly.
*
* We know the elements pointed by path_array won't
* be touched. But isn't g_strjoinv() supposed to get a
* 'const gchar **' instead of a 'gchar **'?
*/
path_array[i] = (gchar*)path;
}
/* Build a ':'-separated list */
gchar *list_str = g_strjoinv(":", path_array);
setenv("OSYNC_FORMAT_LIST", list_str, 1);
g_free(list_str);
}
static void export_option_to_env(gpointer key, gpointer data, gpointer user_data)
{
const char *name = (const char*)key;
const char *value = (const char*)data;
gchar *env_name = g_strdup_printf("OSYNC_%s", name);
setenv(env_name, value, 1);
g_free(env_name);
}
/** Export all options set through osync_env_set_option() to environment variables
*
*/
void osync_env_export_all_options(OSyncEnv *env)
{
g_hash_table_foreach(env->options, export_option_to_env, NULL);
}
static void free_hash(char *key, char *value, void *data)
{
g_free(key);
g_free(value);
}
/*! @brief Returns the next free number for a group in the environments configdir
*
* Returns the next free number for a group in the environments configdir
*
* @param env The osync environment
* @returns The next free number
*
*/
long long int _osync_env_create_group_id(OSyncEnv *env)
{
char *filename = NULL;
long long int i = 0;
do {
i++;
if (filename)
g_free(filename);
filename = g_strdup_printf("%s/group%lli", env->groupsdir, i);
} while (g_file_test(filename, G_FILE_TEST_EXISTS));
g_free(filename);
return i;
}
/*@}*/
/**
* @defgroup PublicAPI Public APIs
* @brief Available public APIs
*
*/
/**
* @defgroup OSyncPublic OpenSync Public API
* @ingroup PublicAPI
* @brief The public API of opensync
*
* This gives you an insight in the public API of opensync.
*
*/
/**
* @defgroup OSyncEnvAPI OpenSync Environment
* @ingroup OSyncPublic
* @brief The public API of the opensync environment
*
*/
/*@{*/
/*! @brief This will create a new opensync environment
*
* The environment will hold all information about plugins, groups etc
*
* @returns A pointer to a newly allocated environment. NULL on error.
*
*/
OSyncEnv *osync_env_new(void)
{
OSyncEnv *env = g_malloc0(sizeof(OSyncEnv));
env->is_initialized = FALSE;
env->options = g_hash_table_new(g_str_hash, g_str_equal);
//Set some defaults
osync_env_set_option(env, "LOAD_GROUPS", "TRUE");
osync_env_set_option(env, "LOAD_FORMATS", "TRUE");
osync_env_set_option(env, "LOAD_PLUGINS", "TRUE");
return env;
}
/*! @brief Frees a osync environment
*
* Frees a osync environment and all resources.
*
* @param env Pointer to the environment to free
*
*/
void osync_env_free(OSyncEnv *env)
{
g_assert(env);
g_hash_table_foreach(env->options, (GHFunc)free_hash, NULL);
g_hash_table_destroy(env->options);
g_free(env);
}
/*! @brief Sets a options on the environment
*
* @param env Pointer to the environment
* @param name Name of the option to set
* @param value Value to set
*
*/
void osync_env_set_option(OSyncEnv *env, const char *name, const char *value)
{
if (value)
g_hash_table_insert(env->options, g_strdup(name), g_strdup(value));
else
g_hash_table_remove(env->options, name);
}
/*! @brief Initializes the environment (loads plugins)
*
* This will load all available plugins from disk. You can configure the location to look
* for plugins before calling this function
*
* @param env Pointer to a OSyncEnv environment
* @param error Pointer to a error struct to return a error
* @returns TRUE on success, FALSE otherwise
*
*/
osync_bool osync_env_initialize(OSyncEnv *env, OSyncError **error)
{
osync_trace(TRACE_ENTRY, "osync_env_initialize(%p, %p)", env, error);
g_assert(env);
if (env->is_initialized) {
osync_error_set(error, OSYNC_ERROR_INITIALIZATION, "Cannot initialize the same environment twice");
osync_trace(TRACE_EXIT_ERROR, "osync_env_initialize: %s", osync_error_print(error));
return FALSE;
}
//Load the normal plugins
if (osync_env_query_option_bool(env, "LOAD_PLUGINS")) {
if (!osync_env_load_plugins(env, osync_env_query_option(env, "PLUGINS_DIRECTORY"), error)) {
osync_trace(TRACE_EXIT_ERROR, "osync_env_initialize: %s", osync_error_print(error));
return FALSE;
}
}
//Load the format plugins
if (osync_env_query_option_bool(env, "LOAD_FORMATS")) {
if (!osync_env_load_formats(env, osync_env_query_option(env, "FORMATS_DIRECTORY"), error)) {
osync_trace(TRACE_EXIT_ERROR, "osync_env_initialize: %s", osync_error_print(error));
return FALSE;
}
}
//Load groups
if (osync_env_query_option_bool(env, "LOAD_GROUPS")) {
if (!osync_env_load_groups(env, osync_env_query_option(env, "GROUPS_DIRECTORY"), error)) {
osync_trace(TRACE_EXIT_ERROR, "osync_env_initialize: %s", osync_error_print(error));
return FALSE;
}
}
env->is_initialized = TRUE;
osync_trace(TRACE_EXIT, "osync_env_initialize");
return TRUE;
}
/*! @brief Finalizes the environment
*
* This will finalize the environment and unload and free all loaded plugins
*
* @param env Pointer to a OSyncEnv environment
* @param error Pointer to a error struct to return a error
* @returns TRUE on success, FALSE otherwise
*
*/
osync_bool osync_env_finalize(OSyncEnv *env, OSyncError **error)
{
osync_trace(TRACE_ENTRY, "osync_env_finalize(%p, %p)", env, error);
g_assert(env);
if (!env->is_initialized) {
osync_error_set(error, OSYNC_ERROR_INITIALIZATION, "Environment has to be initialized before");
return FALSE;
}
while (osync_env_nth_group(env, 0))
osync_group_free(osync_env_nth_group(env, 0));
GList *plugins = g_list_copy(env->plugins);
GList *p;
for (p = plugins; p; p = p->next) {
OSyncPlugin *plugin = p->data;
osync_plugin_free(plugin);
}
g_list_free(plugins);
//Unload all loaded modules
GList *modules = g_list_copy(env->modules);
for (p = modules; p; p = p->next) {
GModule *module = p->data;
osync_module_unload(env, module);
}
g_list_free(modules);
osync_trace(TRACE_EXIT, "osync_env_finalize");
return TRUE;
}
/*! @brief Loads all format and conversion plugins
*
* This command will load all plugins for the conversion system.
* If you dont change the path before it will load the plugins
* from the default location
*
* @param env The format environment
* @param path The path to load from or NULL if to load from default path
* @param error The location to return a error to
* @returns TRUE if successfull, FALSE otherwise
*
*/
osync_bool osync_env_load_formats(OSyncEnv *env, const char *path, OSyncError **error)
{
osync_trace(TRACE_ENTRY, "%s(%p, %s, %p)", __func__, env, path, error);
osync_bool must_exist = TRUE;
if (!path) {
path = OPENSYNC_FORMATSDIR;
must_exist = FALSE;
}
if (!osync_module_load_dir(env, path, must_exist, error)) {
osync_trace(TRACE_EXIT_ERROR, "%s: %s", __func__, osync_error_print(error));
return FALSE;
}
osync_trace(TRACE_EXIT, "%s", __func__);
return TRUE;
}
/*! @brief Loads the sync modules from a given directory
*
* Loads all sync modules from a directory into a osync environment
*
* @param env Pointer to a OSyncEnv environment
* @param path The path where to look for plugins
* @param error Pointer to a error struct to return a error
* @returns TRUE on success, FALSE otherwise
*
*/
osync_bool osync_env_load_plugins(OSyncEnv *env, const char *path, OSyncError **error)
{
osync_trace(TRACE_ENTRY, "%s(%p, %s, %p)", __func__, env, path, error);
osync_bool must_exist = TRUE;
if (!path) {
path = OPENSYNC_PLUGINDIR;
must_exist = FALSE;
}
if (!osync_module_load_dir(env, path, must_exist, error)) {
osync_trace(TRACE_EXIT_ERROR, "%s: %s", __func__, osync_error_print(error));
return FALSE;
}
osync_trace(TRACE_EXIT, "%s", __func__);
return TRUE;
}
/*! @brief Finds the plugin with the given name
*
* Finds the plugin with the given name
*
* @param env Pointer to a OSyncEnv environment
* @param name The name to search for
* @returns The plugin or NULL if not found
*
*/
OSyncPlugin *osync_env_find_plugin(OSyncEnv *env, const char *name)
{
g_assert(env);
OSyncPlugin *plugin;
int i;
for (i = 0; i < osync_env_num_plugins(env); i++) {
plugin = osync_env_nth_plugin(env, i);
if (g_ascii_strcasecmp(plugin->info.name, name) == 0) {
return plugin;
}
}
return NULL;
}
/*! @brief Returns the number of loaded plugins
*
* Returns the number of loaded plugins. 0 if used before initialization
*
* @param env Pointer to a OSyncEnv environment
* @returns Number of plugins
*
*/
int osync_env_num_plugins(OSyncEnv *env)
{
return g_list_length(env->plugins);
}
/*! @brief Returns pointer to nth plugin
*
* Returns pointer to nth plugin
*
* @param env Pointer to a OSyncEnv environment
* @param nth Which plugin to return
* @returns Pointer to plugin
*
*/
OSyncPlugin *osync_env_nth_plugin(OSyncEnv *env, int nth)
{
return (OSyncPlugin *)g_list_nth_data(env->plugins, nth);
}
/*! @brief Checks if a plugin is available and usable
*
* @param env The environment in which the plugin should be loaded
* @param pluginname The name of the plugin to check for
* @param error If the return was FALSE, will contain the information why the plugin is not available
* @returns TRUE if plugin was found and is usable, FALSE otherwise
*
*/
osync_bool osync_env_plugin_is_usable(OSyncEnv *env, const char *pluginname, OSyncError **error)
{
osync_trace(TRACE_ENTRY, "%s(%p, %s, %p)", __func__, env, pluginname, error);
OSyncPlugin *plugin = osync_env_find_plugin(env, pluginname);
if (!plugin) {
osync_error_set(error, OSYNC_ERROR_PLUGIN_NOT_FOUND, "Unable to find plugin \"%s\". This can be caused by unresolved symbols", pluginname);
osync_trace(TRACE_EXIT_ERROR, "%s: %s", __func__, osync_error_print(error));
return FALSE;
}
if (plugin->info.functions.is_available) {
osync_bool ret = plugin->info.functions.is_available(error);
osync_trace(ret ? TRACE_EXIT : TRACE_EXIT_ERROR, "%s: %s", __func__, osync_error_print(error));
return ret;
}
osync_trace(TRACE_EXIT, "%s: TRUE: No is_available function", __func__);
return TRUE;
}
/*! @brief Loads the plugins from a given directory
*
* Loads all plugins from a directory into a osync environment.
* The directory must exist prior to opening.
*
* @param env Pointer to a OSyncEnv environment
* @param path The path where to look for groups
* @param error Pointer to a error struct to return a error
* @returns TRUE on success, FALSE otherwise
*
*/
osync_bool osync_env_load_groups(OSyncEnv *env, const char *p, OSyncError **error)
{
GDir *dir;
GError *gerror = NULL;
char *filename = NULL;
char *real_path = NULL;
char *path = g_strdup(p);
if (!path) {
OSyncUserInfo *user = osync_user_new(error);
if (!user)
return FALSE;
path = g_strdup(osync_user_get_confdir(user));
if (!g_file_test(path, G_FILE_TEST_EXISTS)) {
if (mkdir(path, 0700) == -1) {
osync_error_set(error, OSYNC_ERROR_GENERIC, "Unable to create group directory at %s: %s", path, strerror(errno));
g_free(path);
return FALSE;
}
char *enginepath = g_strdup_printf("%s/engines", path);
if (mkdir(enginepath, 0700) == -1) {
osync_error_set(error, OSYNC_ERROR_GENERIC, "Unable to create engine group directory at %s: %s", enginepath, strerror(errno));
g_free(path);
g_free(enginepath);
return FALSE;
}
g_free(enginepath);
osync_debug("OSGRP", 3, "Created groups configdir %s\n", path);
}
osync_user_free(user);
}
if (!g_path_is_absolute(path)) {
real_path = g_strdup_printf("%s/%s", g_get_current_dir(), path);
} else {
real_path = g_strdup(path);
}
if (!g_file_test(real_path, G_FILE_TEST_IS_DIR)) {
osync_debug("OSGRP", 0, "%s exists, but is no dir", real_path);
osync_error_set(error, OSYNC_ERROR_INITIALIZATION, "%s exists, but is no dir", real_path);
g_free(real_path);
g_free(path);
return FALSE;
}
dir = g_dir_open(real_path, 0, &gerror);
if (!dir) {
osync_debug("OSGRP", 0, "Unable to open main configdir %s: %s", real_path, gerror->message);
osync_error_set(error, OSYNC_ERROR_IO_ERROR, "Unable to open main configdir %s: %s", real_path, gerror->message);
g_error_free (gerror);
g_free(real_path);
g_free(path);
return FALSE;
}
const gchar *de = NULL;
while ((de = g_dir_read_name(dir))) {
filename = g_strdup_printf ("%s/%s", real_path, de);
if (!g_file_test(filename, G_FILE_TEST_IS_DIR) || g_file_test(filename, G_FILE_TEST_IS_SYMLINK) || !g_pattern_match_simple("group*", de)) {
g_free(filename);
continue;
}
/* Try to open the confdir*/
OSyncError *error = NULL;
if (!osync_group_load(env, filename, &error)) {
osync_debug("OSGRP", 0, "Unable to load group from %s: %s", filename, error->message);
osync_error_free(&error);
}
g_free(filename);
}
g_free(real_path);
g_dir_close(dir);
env->groupsdir = path;
return TRUE;
}
/*! @brief Finds the group with the given name
*
* Finds the group with the given name
*
* @param env Pointer to a OSyncEnv environment
* @param name Name of the group to search
* @returns Pointer to group. NULL if not found
*
*/
OSyncGroup *osync_env_find_group(OSyncEnv *env, const char *name)
{
OSyncGroup *group;
int i;
for (i = 0; i < osync_env_num_groups(env); i++) {
group = osync_env_nth_group(env, i);
if (g_ascii_strcasecmp(group->name, name) == 0) {
return group;
}
}
osync_debug("OSPLG", 0, "Couldnt find the group with the name %s", name);
return NULL;
}
/*! @brief Adds the given group to the environment
*
* Adds the given group to the environment
*
* @param env Pointer to a OSyncEnv environment
* @param group The group to add
*
*/
void osync_env_append_group(OSyncEnv *env, OSyncGroup *group)
{
env->groups = g_list_append(env->groups, group);
}
/*! @brief Removes the given group from the enviroment
*
* Removes the given group from the environment
*
* @param env Pointer to a OSyncEnv environment
* @param group The group to add
*
*/
void osync_env_remove_group(OSyncEnv *env, OSyncGroup *group)
{
env->groups = g_list_remove(env->groups, group);
}
/*! @brief Counts the groups in the environment
*
* Returns the number of groups
*
* @param env Pointer to a OSyncEnv environment
* @returns Number of groups
*
*/
int osync_env_num_groups(OSyncEnv *env)
{
return g_list_length(env->groups);
}
/*! @brief Returns the nth group
*
* Returns the nth groups from the environment
*
* @param env Pointer to a OSyncEnv environment
* @param nth Which group to return
* @returns Pointer to the group
*
*/
OSyncGroup *osync_env_nth_group(OSyncEnv *env, int nth)
{
return (OSyncGroup *)g_list_nth_data(env->groups, nth);;
}
/*@}*/
/**
* @defgroup OSyncEnvAPIMisc OpenSync Misc
* @ingroup OSyncPublic
* @brief Some helper functions
*
*/
/*@{*/
/*! @brief Opens a xml document
*
* Opens a xml document
*
* @param doc Pointer to a xmldoc
* @param cur The pointer to the first node
* @param path The path of the document
* @param topentry the name of the top node
* @param error Pointer to a error struct
* @returns TRUE if successfull, FALSE otherwise
*
*/
osync_bool _osync_open_xml_file(xmlDocPtr *doc, xmlNodePtr *cur, const char *path, const char *topentry, OSyncError **error)
{
if (!g_file_test(path, G_FILE_TEST_EXISTS)) {
osync_debug("OSXML", 1, "File %s does not exist", path);
osync_error_set(error, OSYNC_ERROR_IO_ERROR, "File %s does not exist", path);
return FALSE;
}
*doc = xmlParseFile(path);
if (!*doc) {
osync_debug("OSXML", 1, "Could not open: %s", path);
osync_error_set(error, OSYNC_ERROR_IO_ERROR, "Could not open: %s", path);
return FALSE;
}
*cur = xmlDocGetRootElement(*doc);
if (!*cur) {
osync_debug("OSXML", 0, "%s seems to be empty", path);
osync_error_set(error, OSYNC_ERROR_IO_ERROR, "%s seems to be empty", path);
xmlFreeDoc(*doc);
return FALSE;
}
if (xmlStrcmp((*cur)->name, (const xmlChar *) topentry)) {
osync_debug("OSXML", 0, "%s seems not to be a valid configfile.\n", path);
osync_error_set(error, OSYNC_ERROR_IO_ERROR, "%s seems not to be a valid configfile.\n", path);
xmlFreeDoc(*doc);
return FALSE;
}
*cur = (*cur)->xmlChildrenNode;
return TRUE;
}
/*! @brief Writes data to a file
*
* Writes data to a file
*
* @param filename Where to save the data
* @param data Pointer to the data
* @param size Size of the data
* @param mode The mode to set on the file
* @param oserror Pointer to a error struct
* @returns TRUE if successfull, FALSE otherwise
*
*/
osync_bool osync_file_write(const char *filename, const char *data, int size, int mode, OSyncError **oserror)
{
osync_bool ret = FALSE;
GError *error = NULL;
GIOChannel *chan = g_io_channel_new_file(filename, "w", &error);
if (!chan) {
osync_debug("OSYNC", 3, "Unable to open file %s for writing: %s", filename, error->message);
osync_error_set(oserror, OSYNC_ERROR_IO_ERROR, "Unable to open file %s for writing: %s", filename, error->message);
return FALSE;
}
if (mode) {
int fd = g_io_channel_unix_get_fd(chan);
if (fchmod(fd, mode)) {
osync_debug("OSYNC", 3, "Unable to set file permissions %i for file %s", mode, filename);
osync_error_set(oserror, OSYNC_ERROR_IO_ERROR, "Unable to set file permissions %i for file %s", mode, filename);
return FALSE;
}
}
gsize writen;
g_io_channel_set_encoding(chan, NULL, NULL);
if (g_io_channel_write_chars(chan, data, size, &writen, &error) != G_IO_STATUS_NORMAL) {
osync_debug("OSYNC", 3, "Unable to write contents of file %s: %s", filename, error->message);
osync_error_set(oserror, OSYNC_ERROR_IO_ERROR, "Unable to write contents of file %s: %s", filename, error->message);
} else {
g_io_channel_flush(chan, NULL);
ret = TRUE;
}
g_io_channel_shutdown(chan, FALSE, NULL);
g_io_channel_unref(chan);
return ret;
}
/*! @brief Reads a file
*
* Reads a file
*
* @param filename Where to read the data from
* @param data Pointer to the data
* @param size Size of the data
* @param oserror Pointer to a error struct
* @returns TRUE if successfull, FALSE otherwise
*
*/
osync_bool osync_file_read(const char *filename, char **data, int *size, OSyncError **oserror)
{
osync_bool ret = FALSE;
GError *error = NULL;
gsize sz = 0;
if (!filename) {
osync_debug("OSYNC", 3, "No file open specified");
osync_error_set(oserror, OSYNC_ERROR_IO_ERROR, "No file to open specified");
return FALSE;
}
GIOChannel *chan = g_io_channel_new_file(filename, "r", &error);
if (!chan) {
osync_debug("OSYNC", 3, "Unable to read file %s: %s", filename, error->message);
osync_error_set(oserror, OSYNC_ERROR_IO_ERROR, "Unable to open file %s for reading: %s", filename, error->message);
return FALSE;
}
g_io_channel_set_encoding(chan, NULL, NULL);
if (g_io_channel_read_to_end(chan, data, &sz, &error) != G_IO_STATUS_NORMAL) {
osync_debug("OSYNC", 3, "Unable to read contents of file %s: %s", filename, error->message);
osync_error_set(oserror, OSYNC_ERROR_IO_ERROR, "Unable to read contents of file %s: %s", filename, error->message);
} else {
ret = TRUE;
*size = (int)sz;
}
g_io_channel_shutdown(chan, FALSE, NULL);
g_io_channel_unref(chan);
return ret;
}
/*! @brief Returns the version of opensync
*
* Returns a string identifying the major and minor version
* of opensync (something like "0.11")
*
* @returns String with version
*
*/
const char *osync_get_version(void)
{
return VERSION;
}
/*! @brief Safely tries to malloc memory
*
* Tries to malloc memory but returns an error in an OOM situation instead
* of aborting
*
* @param size The size in bytes to malloc
* @param error The error which will hold the info in case of an error
* @returns A pointer to the new memory or NULL in case of error
*
*/
void *osync_try_malloc0(unsigned int size, OSyncError **error)
{
void *result = g_try_malloc(size);
if (!result) {
osync_error_set(error, OSYNC_ERROR_GENERIC, "No memory left");
return NULL;
}
memset(result, 0, size);
return result;
}
char *osync_strreplace(const char *input, const char *delimiter, const char *replacement)
{
osync_return_val_if_fail(input != NULL, NULL);
osync_return_val_if_fail(delimiter != NULL, NULL);
osync_return_val_if_fail(replacement != NULL, NULL);
gchar **array = g_strsplit(input, delimiter, 0);
gchar *ret = g_strjoinv(replacement, array);
g_strfreev(array);
return ret;
}
/*@}*/
OSyncThread *osync_thread_new(GMainContext *context, OSyncError **error)
{
osync_trace(TRACE_ENTRY, "%s(%p, %p)", __func__, context, error);
OSyncThread *thread = osync_try_malloc0(sizeof(OSyncThread), error);
if (!thread)
goto error;
if (!g_thread_supported ()) g_thread_init (NULL);
thread->started_mutex = g_mutex_new();
thread->started = g_cond_new();
thread->context = context;
if (thread->context)
g_main_context_ref(thread->context);
thread->loop = g_main_loop_new(thread->context, FALSE);
osync_trace(TRACE_EXIT, "%s: %p", __func__, thread);
return thread;
error:
osync_trace(TRACE_EXIT_ERROR, "%s: %s", __func__, osync_error_print(error));
return NULL;
}
void osync_thread_free(OSyncThread *thread)
{
osync_trace(TRACE_ENTRY, "%s(%p)", __func__, thread);
osync_assert(thread);
if (thread->started_mutex)
g_mutex_free(thread->started_mutex);
if (thread->started)
g_cond_free(thread->started);
if (thread->loop)
g_main_loop_unref(thread->loop);
if (thread->context)
g_main_context_unref(thread->context);
g_free(thread);
osync_trace(TRACE_EXIT, "%s", __func__);
}
/*static gpointer osyncThreadStartCallback(gpointer data)
{
OSyncThread *thread = data;
g_mutex_lock(thread->started_mutex);
g_cond_signal(thread->started);
g_mutex_unlock(thread->started_mutex);
g_main_loop_run(thread->loop);
return NULL;
}*/
static gboolean osyncThreadStopCallback(gpointer data)
{
OSyncThread *thread = data;
g_main_loop_quit(thread->loop);
return FALSE;
}
/*void osync_thread_start(OSyncThread *thread)
{
osync_trace(TRACE_ENTRY, "%s(%p)", __func__, thread);
osync_assert(thread);
//Start the thread
g_mutex_lock(thread->started_mutex);
thread->thread = g_thread_create (osyncThreadStartCallback, thread, TRUE, NULL);
g_cond_wait(thread->started, thread->started_mutex);
g_mutex_unlock(thread->started_mutex);
osync_trace(TRACE_EXIT, "%s", __func__);
}*/
static gboolean osyncThreadStartCallback(gpointer data)
{
OSyncThread *thread = data;
g_mutex_lock(thread->started_mutex);
g_cond_signal(thread->started);
g_mutex_unlock(thread->started_mutex);
return FALSE;
}
void osync_thread_start(OSyncThread *thread)
{
osync_trace(TRACE_ENTRY, "%s(%p)", __func__, thread);
g_mutex_lock(thread->started_mutex);
GSource *idle = g_idle_source_new();
g_source_set_callback(idle, osyncThreadStartCallback, thread, NULL);
g_source_attach(idle, thread->context);
thread->thread = g_thread_create ((GThreadFunc)g_main_loop_run, thread->loop, TRUE, NULL);
g_cond_wait(thread->started, thread->started_mutex);
g_mutex_unlock(thread->started_mutex);
osync_trace(TRACE_EXIT, "%s", __func__);
}
void osync_thread_stop(OSyncThread *thread)
{
osync_trace(TRACE_ENTRY, "%s(%p)", __func__, thread);
osync_assert(thread);
GSource *source = g_idle_source_new();
g_source_set_callback(source, osyncThreadStopCallback, thread, NULL);
g_source_attach(source, thread->context);
g_thread_join(thread->thread);
thread->thread = NULL;
g_source_unref(source);
osync_trace(TRACE_EXIT, "%s", __func__);
}
osync_bool osync_pattern_match(const char *pattern, const char *data, int size)
{
GPatternSpec *spec = g_pattern_spec_new(pattern);
osync_bool result = g_pattern_match(spec, size, data, NULL);
g_pattern_spec_free(spec);
return result;
}
syntax highlighted by Code2HTML, v. 0.9.1