/* Libvisual - The audio visualisation framework. * * Copyright (C) 2004, 2005, 2006 Dennis Smit * * Authors: Dennis Smit * * $Id: lv_thread.c,v 1.19 2006/02/13 20:54:08 synap Exp $ * * This program 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 program 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 program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include #include #include #include #include #include #include "lvconfig.h" #if defined(VISUAL_OS_WIN32) #include #endif #include "lv_log.h" #include "lv_thread.h" /* FIXME add more threading backends here: * native windows (says nuff) */ typedef struct _ThreadFuncs ThreadFuncs; typedef VisThread *(*ThreadFuncCreate)(VisThreadFunc func, void *data, int joinable); typedef int (*ThreadFuncFree)(VisThread *thread); typedef void *(*ThreadFuncJoin)(VisThread *thread); typedef void (*ThreadFuncExit)(void *retval); typedef void (*ThreadFuncYield)(void); typedef VisMutex *(*MutexFuncNew)(void); typedef int (*MutexFuncFree)(VisMutex *mutex); typedef int (*MutexFuncInit)(VisMutex *mutex); typedef int (*MutexFuncLock)(VisMutex *mutex); typedef int (*MutexFuncTrylock)(VisMutex *mutex); typedef int (*MutexFuncUnlock)(VisMutex *mutex); struct _ThreadFuncs { ThreadFuncCreate thread_create; ThreadFuncFree thread_free; ThreadFuncJoin thread_join; ThreadFuncExit thread_exit; ThreadFuncYield thread_yield; MutexFuncNew mutex_new; MutexFuncFree mutex_free; MutexFuncInit mutex_init; MutexFuncLock mutex_lock; MutexFuncTrylock mutex_trylock; MutexFuncUnlock mutex_unlock; }; /* Internal variables */ static int __lv_thread_initialized = FALSE; static int __lv_thread_supported = FALSE; static int __lv_thread_enabled = TRUE; static ThreadFuncs __lv_thread_funcs; /* Posix implementation */ static VisThread *thread_create_posix (VisThreadFunc func, void *data, int joinable); static int thread_free_posix (VisThread *thread); static void *thread_join_posix (VisThread *thread); static void thread_exit_posix (void *retval); static void thread_yield_posix (void); static VisMutex *mutex_new_posix (void); static int mutex_free_posix (VisMutex *mutex); static int mutex_init_posix (VisMutex *mutex); static int mutex_lock_posix (VisMutex *mutex); static int mutex_trylock_posix (VisMutex *mutex); static int mutex_unlock_posix (VisMutex *mutex); /* Windows32 implementation */ static VisThread *thread_create_win32 (VisThreadFunc func, void *data, int joinable); static int thread_free_win32 (VisThread *thread); static void *thread_join_win32 (VisThread *thread); static void thread_exit_win32 (void *retval); static void thread_yield_win32 (void); static VisMutex *mutex_new_win32 (void); static int mutex_free_win32 (VisMutex *mutex); static int mutex_init_win32 (VisMutex *mutex); static int mutex_lock_win32 (VisMutex *mutex); static int mutex_trylock_win32 (VisMutex *mutex); static int mutex_unlock_win32 (VisMutex *mutex); /* GThread implementation */ static VisThread *thread_create_gthread (VisThreadFunc func, void *data, int joinable); static int thread_free_gthread (VisThread *thread); static void *thread_join_gthread (VisThread *thread); static void thread_exit_gthread (void *retval); static void thread_yield_gthread (void); static VisMutex *mutex_new_gthread (void); static int mutex_free_gthread (VisMutex *mutex); static int mutex_init_gthread (VisMutex *mutex); static int mutex_lock_gthread (VisMutex *mutex); static int mutex_trylock_gthread (VisMutex *mutex); static int mutex_unlock_gthread (VisMutex *mutex); /** * @defgroup VisThread VisThread * @{ */ /** * Initializes the VisThread subsystem. This function needs to be called before VisThread can be used. Also * this function is called from within visual_init(). * * @return TRUE if initialized, FALSE if not initialized. */ int visual_thread_initialize () { __lv_thread_initialized = TRUE; #ifdef VISUAL_HAVE_THREADS #ifdef VISUAL_THREAD_MODEL_POSIX __lv_thread_supported = TRUE; __lv_thread_funcs.thread_create = thread_create_posix; __lv_thread_funcs.thread_free = thread_free_posix; __lv_thread_funcs.thread_join = thread_join_posix; __lv_thread_funcs.thread_exit = thread_exit_posix; __lv_thread_funcs.thread_yield = thread_yield_posix; __lv_thread_funcs.mutex_new = mutex_new_posix; __lv_thread_funcs.mutex_free = mutex_free_posix; __lv_thread_funcs.mutex_init = mutex_init_posix; __lv_thread_funcs.mutex_lock = mutex_lock_posix; __lv_thread_funcs.mutex_trylock = mutex_trylock_posix; __lv_thread_funcs.mutex_unlock = mutex_unlock_posix; return TRUE; #elif defined(VISUAL_THREAD_MODEL_WIN32) /* !VISUAL_THREAD_MODEL_POSIX */ __lv_thread_supported = TRUE; __lv_thread_funcs.thread_create = thread_create_win32; __lv_thread_funcs.thread_free = thread_free_win32; __lv_thread_funcs.thread_join = thread_join_win32; __lv_thread_funcs.thread_exit = thread_exit_win32; __lv_thread_funcs.thread_yield = thread_yield_win32; __lv_thread_funcs.mutex_new = mutex_new_win32; __lv_thread_funcs.mutex_free = mutex_free_win32; __lv_thread_funcs.mutex_init = mutex_init_win32; __lv_thread_funcs.mutex_lock = mutex_lock_win32; __lv_thread_funcs.mutex_trylock = mutex_trylock_win32; __lv_thread_funcs.mutex_unlock = mutex_unlock_win32; return TRUE; #elif defined(VISUAL_THREAD_MODEL_GTHREAD2) /* !VISUAL_THREAD_MODEL_WIN32 */ __lv_thread_supported = TRUE; __lv_thread_funcs.thread_create = thread_create_gthread; __lv_thread_funcs.thread_free = thread_free_gthread; __lv_thread_funcs.thread_join = thread_join_gthread; __lv_thread_funcs.thread_exit = thread_exit_gthread; __lv_thread_funcs.thread_yield = thread_yield_gthread; __lv_thread_funcs.mutex_new = mutex_new_gthread; __lv_thread_funcs.mutex_free = mutex_free_gthread; __lv_thread_funcs.mutex_init = mutex_init_gthread; __lv_thread_funcs.mutex_lock = mutex_lock_gthread; __lv_thread_funcs.mutex_trylock = mutex_trylock_gthread; __lv_thread_funcs.mutex_unlock = mutex_unlock_gthread; return TRUE; #else /* !VISUAL_THREAD_MODEL_GTHREAD2 */ return FALSE; #endif #else return FALSE; #endif /* VISUAL_HAVE_THREADS */ } /** * Request if VisThread is initialized or not. This function should not be confused with visual_thread_is_supported(). * * @return TRUE if initialized, FALSE if not initialized. */ int visual_thread_is_initialized () { return __lv_thread_initialized; } /** * Enable or disable threading support. This can be used to disallow threads, which might be needed in some environments. * * @see visual_thread_is_enabled * * @param enabled TRUE to enable threads, FALSE to disable threads. */ void visual_thread_enable (int enabled) { __lv_thread_enabled = enabled > 0 ? TRUE : FALSE; } /** * Request if threads are enabled or not. This function should not be confused with visual_thread_is_supported(). * * @return TRUE if enabled, FALSE if disabled. */ int visual_thread_is_enabled (void) { return __lv_thread_enabled; } /** * Is used to check if threading is supported. When threading is used this should always * be checked, it's possible to disable threads from within the code, so no \#ifdefs should * be used. * * @return TRUE if threading is supported or FALSE if not. */ int visual_thread_is_supported () { return __lv_thread_supported; } /** * Creates a new VisThread that is used in threading. * * @param func The threading function. * @param data The private data that is send to the threading function. * @param joinable Flag that contains whatever the thread can be joined or not. * * @return A newly allocated VisThread, or NULL on failure. */ VisThread *visual_thread_create (VisThreadFunc func, void *data, int joinable) { visual_log_return_val_if_fail (visual_thread_is_initialized () != FALSE, NULL); visual_log_return_val_if_fail (visual_thread_is_supported () != FALSE, NULL); visual_log_return_val_if_fail (visual_thread_is_enabled () != FALSE, NULL); return __lv_thread_funcs.thread_create (func, data, joinable); } /** * After a VisThread is not needed anylonger it needs to be freed using this function. * * @param thread The VisThread that needs to be freed. * * @return VISUAL_OK on succes, -VISUAL_ERROR_THREAD_NULL or * error values returned by visual_mem_free on failure. */ int visual_thread_free (VisThread *thread) { visual_log_return_val_if_fail (thread != NULL, -VISUAL_ERROR_THREAD_NULL); if (visual_thread_is_supported () == FALSE) { visual_log (VISUAL_LOG_WARNING, _("Tried freeing thread memory while threading is not supported, simply freeing mem")); return visual_mem_free (thread); } return __lv_thread_funcs.thread_free (thread); } /** * Joins a VisThread with another. * * @param thread The VisThread that is about to be joined. * * @return Possible result that was passed to visual_thread_exit as retval or * NULL. */ void *visual_thread_join (VisThread *thread) { visual_log_return_val_if_fail (thread != NULL, NULL); visual_log_return_val_if_fail (visual_thread_is_initialized () != FALSE, NULL); visual_log_return_val_if_fail (visual_thread_is_supported () != FALSE, NULL); visual_log_return_val_if_fail (visual_thread_is_enabled () != FALSE, NULL); return __lv_thread_funcs.thread_join (thread); } /** * Exits a VisThread, this will terminate the thread. * * @param retval The return value that is catched by the visual_thread_join function. */ void visual_thread_exit (void *retval) { visual_log_return_if_fail (visual_thread_is_initialized () != FALSE); visual_log_return_if_fail (visual_thread_is_supported () != FALSE); visual_log_return_if_fail (visual_thread_is_enabled () != FALSE); return __lv_thread_funcs.thread_exit (retval); } /** * Yield the current VisThread so another gets time. */ void visual_thread_yield () { visual_log_return_if_fail (visual_thread_is_initialized () != FALSE); visual_log_return_if_fail (visual_thread_is_supported () != FALSE); visual_log_return_if_fail (visual_thread_is_enabled () != FALSE); return __lv_thread_funcs.thread_yield (); } /** * Creates a new VisMutex that is used to do thread locking so data can be synchronized. * * @return A newly allocated VisMutex that can be used with the visual_mutex_lock and * visual_mutex_unlock functions or NULL on failure. */ VisMutex *visual_mutex_new () { visual_log_return_val_if_fail (visual_thread_is_initialized () != FALSE, NULL); visual_log_return_val_if_fail (visual_thread_is_supported () != FALSE, NULL); visual_log_return_val_if_fail (visual_thread_is_enabled () != FALSE, NULL); return __lv_thread_funcs.mutex_new (); } /** * A VisMutex is allocated to have more flexibility with the actual thread backend. Thus they need * to be freed as well. * * @param mutex Pointer to the VisMutex that needs to be freed. * * @return VISUAL_OK on succes, -VISUAL_ERROR_MUTEX_NULL on failure. */ int visual_mutex_free (VisMutex *mutex) { visual_log_return_val_if_fail (mutex != NULL, -VISUAL_ERROR_MUTEX_NULL); if (visual_thread_is_supported () == FALSE) { visual_log (VISUAL_LOG_WARNING, _("Tried freeing mutex memory while threading is not supported, simply freeing mem")); return visual_mem_free (mutex); } return __lv_thread_funcs.mutex_free (mutex); } /** * A VisMutex that has not been allocated using visual_mutex_new () can be initialized using this function. You can * use non allocated VisMutex variables in this context by giving a reference to them. * * @param mutex Pointer to the VisMutex which needs to be initialized. * * @return VISUAL_OK on succes, -VISUAL_ERROR_MUTEX_NULL, -VISUAL_ERROR_THREAD_NOT_INTIALIZED, * -VISUAL_ERROR_THREAD_NOT_SUPPORTED or -VISUAL_ERROR_THREAD_NOT_ENABLED on failure. */ int visual_mutex_init (VisMutex *mutex) { visual_log_return_val_if_fail (mutex != NULL, -VISUAL_ERROR_MUTEX_NULL); visual_log_return_val_if_fail (visual_thread_is_initialized () != FALSE, -VISUAL_ERROR_THREAD_NOT_INITIALIZED); visual_log_return_val_if_fail (visual_thread_is_supported () != FALSE, -VISUAL_ERROR_THREAD_NOT_SUPPORTED); visual_log_return_val_if_fail (visual_thread_is_enabled () != FALSE, -VISUAL_ERROR_THREAD_NOT_ENABLED); return __lv_thread_funcs.mutex_init (mutex); } /** * Locks a VisMutex, with the VisMutex locks checked right, only one thread can access the area at once. * This will block if the thread is already locked. * * @param mutex Pointer to the VisMutex to register the lock. * * @return VISUAL_OK on succes, -VISUAL_ERROR_MUTEX_NULL, -VISUAL_ERROR_MUTEX_LOCK_FAILURE, * -VISUAL_ERROR_THREAD_NOT_INITIALIZED, -VISUAL_ERROR_THREAD_NOT_SUPPORTED, * -VISUAL_ERROR_THREAD_NOT_ENABLED on failure. */ int visual_mutex_lock (VisMutex *mutex) { visual_log_return_val_if_fail (mutex != NULL, -VISUAL_ERROR_MUTEX_NULL); visual_log_return_val_if_fail (visual_thread_is_initialized () != FALSE, -VISUAL_ERROR_THREAD_NOT_INITIALIZED); visual_log_return_val_if_fail (visual_thread_is_supported () != FALSE, -VISUAL_ERROR_THREAD_NOT_SUPPORTED); visual_log_return_val_if_fail (visual_thread_is_enabled () != FALSE, -VISUAL_ERROR_THREAD_NOT_ENABLED); return __lv_thread_funcs.mutex_lock (mutex); } /** * Tries to lock a VisMutex, however instead of visual_mutex_lock it does not block on failure. but returns * instead with -VISUAL_ERROR_MUTEX_TRYLOCK_FAILURE as error value. * * @param mutex Pointer to the VisMutex that needs to be locked. * * @return VISUAL_OK on succes, -VISUAL_ERROR_MUTEX_NULL, -VISUAL_ERROR_MUTEX_TRYLOCK_FAILURE, * -VISUAL_ERROR_THREAD_NOT_INITIALIZED, -VISUAL_ERROR_THREAD_NOT_SUPPORTED or * -VISUAL_ERROR_THREAD_NOT_ENABLED on failure. */ int visual_mutex_trylock (VisMutex *mutex) { visual_log_return_val_if_fail (mutex != NULL, -VISUAL_ERROR_MUTEX_NULL); visual_log_return_val_if_fail (visual_thread_is_initialized () != FALSE, -VISUAL_ERROR_THREAD_NOT_INITIALIZED); visual_log_return_val_if_fail (visual_thread_is_supported () != FALSE, -VISUAL_ERROR_THREAD_NOT_SUPPORTED); visual_log_return_val_if_fail (visual_thread_is_enabled () != FALSE, -VISUAL_ERROR_THREAD_NOT_ENABLED); return __lv_thread_funcs.mutex_trylock (mutex); } /** * Unlocks a VisMutex so other threads that use the same lock can now enter the critical area. * * @param mutex Pointer to the VisMutex that is unlocked. * * @return VISUAL_OK on succes, -VISUAL_ERROR_MUTEX_NULL, -VISUAL_ERROR_MUTEX_UNLOCK_FAILURE. * -VISUAL_ERROR_THREAD_NOT_INITIALIZED, -VISUAL_ERROR_THREAD_NOT_SUPPORTED or * -VISUAL_ERROR_THREAD_NOT_ENABLED on failure. */ int visual_mutex_unlock (VisMutex *mutex) { visual_log_return_val_if_fail (mutex != NULL, -VISUAL_ERROR_MUTEX_NULL); visual_log_return_val_if_fail (visual_thread_is_initialized () != FALSE, -VISUAL_ERROR_THREAD_NOT_INITIALIZED); visual_log_return_val_if_fail (visual_thread_is_supported () != FALSE, -VISUAL_ERROR_THREAD_NOT_SUPPORTED); visual_log_return_val_if_fail (visual_thread_is_enabled () != FALSE, -VISUAL_ERROR_THREAD_NOT_ENABLED); return __lv_thread_funcs.mutex_unlock (mutex); } /** * @} */ /* Native implementations */ /* Posix implementation */ static VisThread *thread_create_posix (VisThreadFunc func, void *data, int joinable) { VisThread *thread = NULL; #ifdef VISUAL_THREAD_MODEL_POSIX pthread_attr_t attr; int res; thread = visual_mem_new0 (VisThread, 1); pthread_attr_init(&attr); if (joinable == TRUE) pthread_attr_setdetachstate (&attr, PTHREAD_CREATE_JOINABLE); else pthread_attr_setdetachstate (&attr, PTHREAD_CREATE_DETACHED); res = pthread_create (&thread->thread, &attr, func, data); pthread_attr_destroy (&attr); if (res != 0) { visual_log (VISUAL_LOG_CRITICAL, _("Error while creating thread")); visual_mem_free (thread); return NULL; } #endif return thread; } static int thread_free_posix (VisThread *thread) { return visual_mem_free (thread); } static void *thread_join_posix (VisThread *thread) { void *result = NULL; #ifdef VISUAL_THREAD_MODEL_POSIX if (pthread_join (thread->thread, &result) < 0) { visual_log (VISUAL_LOG_CRITICAL, _("Error while joining thread")); return NULL; } #endif return result; } static void thread_exit_posix (void *retval) { #ifdef VISUAL_THREAD_MODEL_POSIX pthread_exit (retval); #endif } static void thread_yield_posix () { #ifdef VISUAL_THREAD_MODEL_POSIX sched_yield (); #endif } static VisMutex *mutex_new_posix () { VisMutex *mutex; #ifdef VISUAL_THREAD_MODEL_POSIX mutex = visual_mem_new0 (VisMutex, 1); pthread_mutex_init (&mutex->mutex, NULL); #endif return mutex; } static int mutex_free_posix (VisMutex *mutex) { return visual_mem_free (mutex); } static int mutex_init_posix (VisMutex *mutex) { visual_mem_set (mutex, 0, sizeof (VisMutex)); #ifdef VISUAL_THREAD_MODEL_POSIX pthread_mutex_init (&mutex->mutex, NULL); #endif return VISUAL_OK; } static int mutex_lock_posix (VisMutex *mutex) { #ifdef VISUAL_THREAD_MODEL_POSIX if (pthread_mutex_lock (&mutex->mutex) < 0) return -VISUAL_ERROR_MUTEX_LOCK_FAILURE; #endif return VISUAL_OK; } static int mutex_trylock_posix (VisMutex *mutex) { #ifdef VISUAL_THREAD_MODEL_POSIX if (pthread_mutex_trylock (&mutex->mutex) < 0) return -VISUAL_ERROR_MUTEX_TRYLOCK_FAILURE; #endif return VISUAL_OK; } static int mutex_unlock_posix (VisMutex *mutex) { #ifdef VISUAL_THREAD_MODEL_POSIX if (pthread_mutex_unlock (&mutex->mutex) < 0) return -VISUAL_ERROR_MUTEX_UNLOCK_FAILURE; #endif return VISUAL_OK; } /* Windows32 implementation */ static VisThread *thread_create_win32 (VisThreadFunc func, void *data, int joinable) { VisThread *thread = NULL; #ifdef VISUAL_THREAD_MODEL_WIN32 thread = visual_mem_new0 (VisThread, 1); thread->thread = CreateThread (NULL, 0, func, (PVOID) data, 0, &thread->threadId); if (thread == NULL) { visual_log (VISUAL_LOG_CRITICAL, "Error while creating thread"); visual_mem_free (thread); return NULL; } /* printf("Waiting for thread to finish...\n"); if (WaitForSingleObject(a_thread, INFINITE) != WAIT_OBJECT_0) { perror("Thread join failed"); exit(EXIT_FAILURE); } */ // Retrieve the code returned by the thread. // GetExitCodeThread(a_thread, &thread_result); #endif return thread; } static int thread_free_win32 (VisThread *thread) { return visual_mem_free (thread); } static void *thread_join_win32 (VisThread *thread) { void *result = NULL; #ifdef VISUAL_THREAD_MODEL_WIN32 DWORD thread_result; if (WaitForSingleObject(thread->thread, INFINITE) != WAIT_OBJECT_0) { visual_log (VISUAL_LOG_CRITICAL, "Error while joining thread"); return NULL; } GetExitCodeThread(thread->thread, &thread_result); result = (void *) thread_result; #endif return result; } static void thread_exit_win32 (void *retval) { #ifdef VISUAL_THREAD_MODEL_WIN32 #endif } static void thread_yield_win32 () { #ifdef VISUAL_THREAD_MODEL_WIN32 #endif } static VisMutex *mutex_new_win32 () { #ifdef VISUAL_THREAD_MODEL_WIN32 #endif } static int mutex_free_win32 (VisMutex *mutex) { #ifdef VISUAL_THREAD_MODEL_WIN32 #endif } static int mutex_init_win32 (VisMutex *mutex) { #ifdef VISUAL_THREAD_MODEL_WIN32 #endif } static int mutex_lock_win32 (VisMutex *mutex) { #ifdef VISUAL_THREAD_MODEL_WIN32 #endif } static int mutex_trylock_win32 (VisMutex *mutex) { #ifdef VISUAL_THREAD_MODEL_WIN32 #endif } static int mutex_unlock_win32 (VisMutex *mutex) { #ifdef VISUAL_THREAD_MODEL_WIN32 #endif } /* GThread implementation */ static VisThread *thread_create_gthread (VisThreadFunc func, void *data, int joinable) { VisThread *thread = NULL; #ifdef VISUAL_THREAD_MODEL_GTHREAD2 thread = visual_mem_new0 (VisThread, 1); thread->thread = g_thread_create (func, data, joinable, NULL); if (thread->thread == NULL) { visual_log (VISUAL_LOG_CRITICAL, _("Error while creating thread")); visual_mem_free (thread); return NULL; } #endif return thread; } static int thread_free_gthread (VisThread *thread) { return visual_mem_free (thread); } static void *thread_join_gthread (VisThread *thread) { #ifdef VISUAL_THREAD_MODEL_GTHREAD2 gpointer result; visual_log_return_val_if_fail (thread->thread != NULL, NULL); result = g_thread_join (thread->thread); return result; #else return NULL; #endif } static void thread_exit_gthread (void *retval) { #ifdef VISUAL_THREAD_MODEL_GTHREAD2 g_thread_exit (retval); #endif } static void thread_yield_gthread () { #ifdef VISUAL_THREAD_MODEL_GTHREAD2 g_thread_yield (); #endif } static VisMutex *mutex_new_gthread () { VisMutex *mutex; mutex = visual_mem_new0 (VisMutex, 1); #ifdef VISUAL_THREAD_MODEL_GTHREAD2 mutex->static_mutex_used = FALSE; mutex->mutex = g_mutex_new (); #endif return mutex; } static int mutex_free_gthread (VisMutex *mutex) { #ifdef VISUAL_THREAD_MODEL_GTHREAD2 visual_log_return_val_if_fail (mutex->mutex != NULL, -VISUAL_ERROR_MUTEX_NULL); g_mutex_free (mutex->mutex); #endif return visual_mem_free (mutex); } static int mutex_init_gthread (VisMutex *mutex) { #ifdef VISUAL_THREAD_MODEL_GTHREAD2 mutex->static_mutex_used = TRUE; g_static_mutex_init (&mutex->static_mutex); #endif return VISUAL_OK; } static int mutex_lock_gthread (VisMutex *mutex) { #ifdef VISUAL_THREAD_MODEL_GTHREAD2 if (mutex->static_mutex_used == TRUE) g_static_mutex_lock (&mutex->static_mutex); else g_mutex_lock (mutex->mutex); #endif return VISUAL_OK; } static int mutex_trylock_gthread (VisMutex *mutex) { #ifdef VISUAL_THREAD_MODEL_GTHREAD2 if (mutex->static_mutex_used == TRUE) g_static_mutex_trylock (&mutex->static_mutex); else g_mutex_trylock (mutex->mutex); #endif return VISUAL_OK; } static int mutex_unlock_gthread (VisMutex *mutex) { #ifdef VISUAL_THREAD_MODEL_GTHREAD2 if (mutex->static_mutex_used == TRUE) g_static_mutex_unlock (&mutex->static_mutex); else g_mutex_unlock (mutex->mutex); #endif return VISUAL_OK; }