/* glib.h
 *
 * Copyright (C) 2007 Christian Bienia
 *
 * 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., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
 * USA.
 */

#ifndef __GTHREADWRAPPER_H__
#define __GTHREADWRAPPER_H__ 1

/* This file implements the user-level wrappers of the libgthread functions.
 */

/* Get dlsym and RTLD_DEFAULT */
#include <dlfcn.h>
/* Include correct header files */
#include "/usr/include/glib-2.0/glib.h"

#ifndef G_THREADS_ENABLED
# error Unable to wrap thread functions, GLib compiled without thread support.
#endif /* G_THREADS_ENABLED */

/* Control which prototypes to declare */
#define __GTHREADW__WITH_GTHREAD_STATIC_MUTEXES
#define __GTHREADW__WITH_GTHREAD_STATIC_REC_MUTEXES
#define __GTHREADW__WITH_GTHREAD_STATIC_RWLOCKS

/* Make function name available in a compiler-independent way */
#if __STDC_VERSION__ < 199901L
# if __GNUC__ >= 2
#  define __GTHREADW_FUNC__ __FUNCTION__
# else
#  define __GTHREADW_FUNC__ NULL
# endif
#else
# define __GTHREADW_FUNC__ __func__
#endif

/* Function pointer used to call _threadw_ptr_alias
 * Implemented as union because we need an ISO C99 compatible
 * way to cast an object pointer to a function pointer.
 */
static union {
  void *optr;
  void (*fptr)(void *, const char *, const char *, const char *, int);
} __GTHREADW__ptr_union;

/* Initialization routine for handler */
static gpointer __GTHREADW__init_routine(gpointer data) {
  __GTHREADW__ptr_union.optr = dlsym(RTLD_DEFAULT, "_threadw_ptr_alias");
}
static GOnce __GTHREADW__is_initialized = G_ONCE_INIT;

/* Handler which is used to pass information pertaining a synchronization
 * variable pointer to gthreadw profiling library.
 */
static inline void __GTHREADW__handle_ptr_alias(void *vptr, const char *name, const char *file, const char *func, int line) {
  /* Initialize function pointer */
  g_once(&__GTHREADW__is_initialized, &__GTHREADW__init_routine, NULL);

  /* If gthreadw could be found pass on pointer information */
  if(__GTHREADW__ptr_union.optr!=NULL) {
    (*(__GTHREADW__ptr_union.fptr))(vptr, name, file, func, line);
  }
}



/* Wrappers for mutex functions */

static inline GMutex *__GTHREADW__g_mutex_new(const char *name, const char *file, const char *func, int line) {
  GMutex *mutex = g_mutex_new();
  __GTHREADW__handle_ptr_alias((void *)mutex, name, file, func, line);
  return mutex;
}
#undef g_mutex_new
#define g_mutex_new() __GTHREADW__##g_mutex_new("N/A", __FILE__, __GTHREADW_FUNC__, __LINE__)

static inline void __GTHREADW__g_mutex_lock(const char *name, const char *file, const char *func, int line, GMutex *mutex) {
  __GTHREADW__handle_ptr_alias((void *)mutex, name, file, func, line);
  g_mutex_lock(mutex);
}
#undef g_mutex_lock
#define g_mutex_lock(m) __GTHREADW__##g_mutex_lock(#m, __FILE__, __GTHREADW_FUNC__, __LINE__, m)

static inline gboolean __GTHREADW__g_mutex_trylock(const char *name, const char *file, const char *func, int line, GMutex *mutex) {
  __GTHREADW__handle_ptr_alias((void *)mutex, name, file, func, line);
  return g_mutex_trylock(mutex);
}
#undef g_mutex_trylock
#define g_mutex_trylock(m) __GTHREADW__##g_mutex_trylock(#m, __FILE__, __GTHREADW_FUNC__, __LINE__, m)

static inline void __GTHREADW__g_mutex_unlock(const char *name, const char *file, const char *func, int line, GMutex *mutex) {
  __GTHREADW__handle_ptr_alias((void *)mutex, name, file, func, line);
  g_mutex_unlock(mutex);
}
#undef g_mutex_unlock
#define g_mutex_unlock(m) __GTHREADW__##g_mutex_unlock(#m, __FILE__, __GTHREADW_FUNC__, __LINE__, m)

static inline void __GTHREADW__g_mutex_free(const char *name, const char *file, const char *func, int line, GMutex *mutex) {
  __GTHREADW__handle_ptr_alias((void *)mutex, name, file, func, line);
  g_mutex_free(mutex);
}
#undef g_mutex_free
#define g_mutex_free(m) __GTHREADW__##g_mutex_free(#m, __FILE__, __GTHREADW_FUNC__, __LINE__, m)



/* Wrappers for static mutex functions */

#if defined(__GTHREADW__WITH_GTHREAD_STATIC_MUTEXES)
static inline void __GTHREADW__g_static_mutex_init(const char *name, const char *file, const char *func, int line, GStaticMutex *mutex) {
  __GTHREADW__handle_ptr_alias((void *)g_static_mutex_get_mutex(mutex), name, file, func, line);
  g_static_mutex_init(mutex);
}
#undef g_static_mutex_init
#define g_static_mutex_init(m) __GTHREADW__##g_static_mutex_init(#m, __FILE__, __GTHREADW_FUNC__, __LINE__, m)

static inline void __GTHREADW__g_static_mutex_lock(const char *name, const char *file, const char *func, int line, GStaticMutex *mutex) {
  __GTHREADW__handle_ptr_alias((void *)g_static_mutex_get_mutex(mutex), name, file, func, line);
  g_static_mutex_lock(mutex);
}
#undef g_static_mutex_lock
#define g_static_mutex_lock(m) __GTHREADW__##g_static_mutex_lock(#m, __FILE__, __GTHREADW_FUNC__, __LINE__, m)

static inline gboolean __GTHREADW__g_static_mutex_trylock(const char *name, const char *file, const char *func, int line, GStaticMutex *mutex) {
  __GTHREADW__handle_ptr_alias((void *)g_static_mutex_get_mutex(mutex), name, file, func, line);
  return g_static_mutex_trylock(mutex);
}
#undef g_static_mutex_trylock
#define g_static_mutex_trylock(m) __GTHREADW__##g_static_mutex_trylock(#m, __FILE__, __GTHREADW_FUNC__, __LINE__, m)

static inline void __GTHREADW__g_static_mutex_unlock(const char *name, const char *file, const char *func, int line, GStaticMutex *mutex) {
  __GTHREADW__handle_ptr_alias((void *)g_static_mutex_get_mutex(mutex), name, file, func, line);
  g_static_mutex_unlock(mutex);
}
#undef g_static_mutex_unlock
#define g_static_mutex_unlock(m) __GTHREADW__##g_static_mutex_unlock(#m, __FILE__, __GTHREADW_FUNC__, __LINE__, m)

static inline void __GTHREADW__g_static_mutex_free(const char *name, const char *file, const char *func, int line, GStaticMutex *mutex) {
  __GTHREADW__handle_ptr_alias((void *)g_static_mutex_get_mutex(mutex), name, file, func, line);
  g_static_mutex_free(mutex);
}
#undef g_static_mutex_free
#define g_static_mutex_free(m) __GTHREADW__##g_static_mutex_free(#m, __FILE__, __GTHREADW_FUNC__, __LINE__, m)
#endif /* __GTHREADW__WITH_GTHREAD_STATIC_MUTEXES */



/* Wrappers for static recursive mutex functions */

#if defined(__GTHREADW__WITH_GTHREAD_STATIC_REC_MUTEXES)
static inline void __GTHREADW__g_static_rec_mutex_init(const char *name, const char *file, const char *func, int line, GStaticRecMutex *mutex) {
  __GTHREADW__handle_ptr_alias((void *)mutex, name, file, func, line);
  g_static_rec_mutex_init(mutex);
}
#undef g_static_rec_mutex_init
#define g_static_rec_mutex_init(m) __GTHREADW__##g_static_rec_mutex_init(#m, __FILE__, __GTHREADW_FUNC__, __LINE__, m)

static inline void __GTHREADW__g_static_rec_mutex_lock(const char *name, const char *file, const char *func, int line, GStaticRecMutex *mutex) {
  __GTHREADW__handle_ptr_alias((void *)mutex, name, file, func, line);
  g_static_rec_mutex_lock(mutex);
}
#undef g_static_rec_mutex_lock
#define g_static_rec_mutex_lock(m) __GTHREADW__##g_static_rec_mutex_lock(#m, __FILE__, __GTHREADW_FUNC__, __LINE__, m)

static inline gboolean __GTHREADW__g_static_rec_mutex_trylock(const char *name, const char *file, const char *func, int line, GStaticRecMutex *mutex) {
  __GTHREADW__handle_ptr_alias((void *)mutex, name, file, func, line);
  return g_static_rec_mutex_trylock(mutex);
}
#undef g_static_rec_mutex_trylock
#define g_static_rec_mutex_trylock(m) __GTHREADW__##g_static_rec_mutex_trylock(#m, __FILE__, __GTHREADW_FUNC__, __LINE__, m)

static inline void __GTHREADW__g_static_rec_mutex_unlock(const char *name, const char *file, const char *func, int line, GStaticRecMutex *mutex) {
  __GTHREADW__handle_ptr_alias((void *)mutex, name, file, func, line);
  g_static_rec_mutex_unlock(mutex);
}
#undef g_static_rec_mutex_unlock
#define g_static_rec_mutex_unlock(m) __GTHREADW__##g_static_rec_mutex_unlock(#m, __FILE__, __GTHREADW_FUNC__, __LINE__, m)

static inline void __GTHREADW__g_static_rec_mutex_free(const char *name, const char *file, const char *func, int line, GStaticRecMutex *mutex) {
  __GTHREADW__handle_ptr_alias((void *)mutex, name, file, func, line);
  g_static_rec_mutex_free(mutex);
}
#undef g_static_rec_mutex_free
#define g_static_rec_mutex_free(m) __GTHREADW__##g_static_rec_mutex_free(#m, __FILE__, __GTHREADW_FUNC__, __LINE__, m)

static inline void __GTHREADW__g_static_rec_mutex_lock_full(const char *name, const char *file, const char *func, int line, GStaticRecMutex *mutex, guint depth) {
  __GTHREADW__handle_ptr_alias((void *)mutex, name, file, func, line);
  g_static_rec_mutex_lock_full(mutex, depth);
}
#undef g_static_rec_mutex_lock_full
#define g_static_rec_mutex_lock_full(m, d) __GTHREADW__##g_static_rec_mutex_lock_full(#m, __FILE__, __GTHREADW_FUNC__, __LINE__, m, d)

static inline guint __GTHREADW__g_static_rec_mutex_unlock_full(const char *name, const char *file, const char *func, int line, GStaticRecMutex *mutex) {
  __GTHREADW__handle_ptr_alias((void *)mutex, name, file, func, line);
  return g_static_rec_mutex_unlock_full(mutex);
}
#undef g_static_rec_mutex_unlock_full
#define g_static_rec_mutex_unlock_full(m) __GTHREADW__##g_static_rec_mutex_unlock_full(#m, __FILE__, __GTHREADW_FUNC__, __LINE__, m)
#endif /* __GTHREADW__WITH_GTHREAD_STATIC_REC_MUTEXES */



/* Wrappers for static rwlock functions */

#if defined(__GTHREADW__WITH_GTHREAD_STATIC_RWLOCKS)
static inline void __GTHREADW__g_static_rw_lock_init(const char *name, const char *file, const char *func, int line, GStaticRWLock *lock) {
  __GTHREADW__handle_ptr_alias((void *)lock, name, file, func, line);
  g_static_rw_lock_init(lock);
}
#undef g_static_rw_lock_init
#define g_static_rw_lock_init(l) __GTHREADW__##g_static_rw_lock_init(#l, __FILE__, __GTHREADW_FUNC__, __LINE__, l)

static inline void __GTHREADW__g_static_rw_lock_reader_lock(const char *name, const char *file, const char *func, int line, GStaticRWLock *lock) {
  __GTHREADW__handle_ptr_alias((void *)lock, name, file, func, line);
  g_static_rw_lock_reader_lock(lock);
}
#undef g_static_rw_lock_reader_lock
#define g_static_rw_lock_reader_lock(l) __GTHREADW__##g_static_rw_lock_reader_lock(#l, __FILE__, __GTHREADW_FUNC__, __LINE__, l)

static inline gboolean __GTHREADW__g_static_rw_lock_reader_trylock(const char *name, const char *file, const char *func, int line, GStaticRWLock *lock) {
  __GTHREADW__handle_ptr_alias((void *)lock, name, file, func, line);
  return g_static_rw_lock_reader_trylock(lock);
}
#undef g_static_rw_lock_reader_trylock
#define g_static_rw_lock_reader_trylock(l) __GTHREADW__##g_static_rw_lock_reader_trylock(#l, __FILE__, __GTHREADW_FUNC__, __LINE__, l)

static inline void __GTHREADW__g_static_rw_lock_reader_unlock(const char *name, const char *file, const char *func, int line, GStaticRWLock *lock) {
  __GTHREADW__handle_ptr_alias((void *)lock, name, file, func, line);
  g_static_rw_lock_reader_unlock(lock);
}
#undef g_static_rw_lock_reader_unlock
#define g_static_rw_lock_reader_unlock(l) __GTHREADW__##g_static_rw_lock_reader_unlock(#l, __FILE__, __GTHREADW_FUNC__, __LINE__, l)

static inline void __GTHREADW__g_static_rw_lock_writer_lock(const char *name, const char *file, const char *func, int line, GStaticRWLock *lock) {
  __GTHREADW__handle_ptr_alias((void *)lock, name, file, func, line);
  g_static_rw_lock_writer_lock(lock);
}
#undef g_static_rw_lock_writer_lock
#define g_static_rw_lock_writer_lock(l) __GTHREADW__##g_static_rw_lock_writer_lock(#l, __FILE__, __GTHREADW_FUNC__, __LINE__, l)

static inline gboolean __GTHREADW__g_static_rw_lock_writer_trylock(const char *name, const char *file, const char *func, int line, GStaticRWLock *lock) {
  __GTHREADW__handle_ptr_alias((void *)lock, name, file, func, line);
  return g_static_rw_lock_writer_trylock(lock);
}
#undef g_static_rw_lock_writer_trylock
#define g_static_rw_lock_writer_trylock(l) __GTHREADW__##g_static_rw_lock_writer_trylock(#l, __FILE__, __GTHREADW_FUNC__, __LINE__, l)

static inline void __GTHREADW__g_static_rw_lock_writer_unlock(const char *name, const char *file, const char *func, int line, GStaticRWLock *lock) {
  __GTHREADW__handle_ptr_alias((void *)lock, name, file, func, line);
  g_static_rw_lock_writer_unlock(lock);
}
#undef g_static_rw_lock_writer_unlock
#define g_static_rw_lock_writer_unlock(l) __GTHREADW__##g_static_rw_lock_writer_unlock(#l, __FILE__, __GTHREADW_FUNC__, __LINE__, l)

static inline void __GTHREADW__g_static_rw_lock_free(const char *name, const char *file, const char *func, int line, GStaticRWLock *lock) {
  __GTHREADW__handle_ptr_alias((void *)lock, name, file, func, line);
  g_static_rw_lock_free(lock);
}
#undef g_static_rw_lock_free
#define g_static_rw_lock_free(l) __GTHREADW__##g_static_mutex_free(#l, __FILE__, __GTHREADW_FUNC__, __LINE__, l)
#endif /* __GTHREADW__WITH_GTHREAD_STATIC_RWLOCKS */



/* Wrappers for mutex functions */

static inline GCond *__GTHREADW__g_cond_new(const char *name, const char *file, const char *func, int line) {
  GCond *cond = g_cond_new();
  __GTHREADW__handle_ptr_alias((void *)cond, name, file, func, line);
  return cond;
}
#undef g_cond_new
#define g_cond_new() __GTHREADW__##g_cond_new("N/A", __FILE__, __GTHREADW_FUNC__, __LINE__)

static inline void __GTHREADW__g_cond_signal(const char *name, const char *file, const char *func, int line, GCond *cond) {
  __GTHREADW__handle_ptr_alias((void *)cond, name, file, func, line);
  g_cond_signal(cond);
}
#undef g_cond_signal
#define g_cond_signal(c) __GTHREADW__##g_cond_signal(#c, __FILE__, __GTHREADW_FUNC__, __LINE__, c)

static inline void __GTHREADW__g_cond_broadcast(const char *name, const char *file, const char *func, int line, GCond *cond) {
  __GTHREADW__handle_ptr_alias((void *)cond, name, file, func, line);
  g_cond_broadcast(cond);
}
#undef g_cond_broadcast
#define g_cond_broadcast(c) __GTHREADW__##g_cond_broadcast(#c, __FILE__, __GTHREADW_FUNC__, __LINE__, c)

static inline void __GTHREADW__g_cond_wait(const char *name, const char *file, const char *func, int line, GCond *cond, GMutex *mutex) {
  __GTHREADW__handle_ptr_alias((void *)cond, name, file, func, line);
  g_cond_wait(cond, mutex);
}
#undef g_cond_wait
#define g_cond_wait(c, m) __GTHREADW__##g_cond_wait(#c, __FILE__, __GTHREADW_FUNC__, __LINE__, c, m)

static inline gboolean __GTHREADW__g_cond_timed_wait(const char *name, const char *file, const char *func, int line, GCond *cond, GMutex *mutex, GTimeVal *abs_time) {
  __GTHREADW__handle_ptr_alias((void *)cond, name, file, func, line);
  return g_cond_timed_wait(cond, mutex, abs_time);
}
#undef g_cond_timed_wait
#define g_cond_timed_wait(c, m, t) __GTHREADW__##g_cond_timed_wait(#c, __FILE__, __GTHREADW_FUNC__, __LINE__, c, m, t)

static inline void __GTHREADW__g_cond_free(const char *name, const char *file, const char *func, int line, GCond *cond) {
  __GTHREADW__handle_ptr_alias((void *)cond, name, file, func, line);
  g_cond_free(cond);
}
#undef g_cond_free
#define g_cond_free(c) __GTHREADW__##g_cond_free(#c, __FILE__, __GTHREADW_FUNC__, __LINE__, c)



/* Cleanup */
#undef __GTHREADW__WITH_GTHREAD_STATIC_MUTEXES
#undef __GTHREADW__WITH_GTHREAD_STATIC_REC_MUTEXES
#undef __GTHREADW__WITH_GTHREAD_STATIC_RWLOCKS

#endif /* __GTHREADWRAPPER_H__ */

