GRand: move docs from tmpl to inline comments
[platform/upstream/glib.git] / glib / gthread.h
index e99c78d..7a0abba 100644 (file)
  * Modified by the GLib Team and others 1997-2000.  See the AUTHORS
  * file for a list of people on the GLib Team.  See the ChangeLog
  * files for a list of changes.  These files are distributed with
- * GLib at ftp://ftp.gtk.org/pub/gtk/. 
+ * GLib at ftp://ftp.gtk.org/pub/gtk/.
  */
 
+#if defined(G_DISABLE_SINGLE_INCLUDES) && !defined (__GLIB_H_INSIDE__) && !defined (GLIB_COMPILATION)
+#error "Only <glib.h> can be included directly."
+#endif
+
 #ifndef __G_THREAD_H__
 #define __G_THREAD_H__
 
-#include <gerror.h>
-#include <gmain.h>
+#include <glib/gerror.h>
+#include <glib/gtypes.h>
+#include <glib/gutils.h>        /* for G_INLINE_FUNC */
+#include <glib/gatomic.h>       /* for g_atomic_pointer_get */
 
 G_BEGIN_DECLS
 
-#ifndef GLIB_VAR
-#  ifdef G_OS_WIN32
-#    ifdef GLIB_COMPILATION
-#      define GLIB_VAR __declspec(dllexport)
-#    else /* !GLIB_COMPILATION */
-#      define GLIB_VAR extern __declspec(dllimport)
-#    endif /* !GLIB_COMPILATION */
-#  else /* !G_OS_WIN32 */
-#    define GLIB_VAR extern
-#  endif /* !G_OS_WIN32 */
-#endif /* GLIB_VAR */
-
 /* GLib Thread support
  */
 
-extern GQuark g_thread_error_quark();
-#define G_THREAD_ERROR g_thread_error_quark()
+extern GQuark g_thread_error_quark (void);
+#define G_THREAD_ERROR g_thread_error_quark ()
 
 typedef enum
 {
   G_THREAD_ERROR_AGAIN /* Resource temporarily unavailable */
 } GThreadError;
 
-typedef void            (*GThreadFunc)          (gpointer       value);
+typedef gpointer (*GThreadFunc) (gpointer data);
 
 typedef enum
 {
@@ -68,9 +62,11 @@ typedef enum
 typedef struct _GThread         GThread;
 struct  _GThread
 {
-  GThreadPriority priority;
-  gboolean bound;
+  /*< private >*/
+  GThreadFunc func;
+  gpointer data;
   gboolean joinable;
+  GThreadPriority priority;
 };
 
 typedef struct _GMutex          GMutex;
@@ -99,8 +95,8 @@ struct _GThreadFunctions
   gpointer  (*private_get)        (GPrivate             *private_key);
   void      (*private_set)        (GPrivate             *private_key,
                                    gpointer              data);
-  void      (*thread_create)      (GThreadFunc           thread_func,
-                                   gpointer              arg,
+  void      (*thread_create)      (GThreadFunc           func,
+                                   gpointer              data,
                                    gulong                stack_size,
                                    gboolean              joinable,
                                    gboolean              bound,
@@ -113,12 +109,16 @@ struct _GThreadFunctions
   void      (*thread_set_priority)(gpointer              thread,
                                    GThreadPriority       priority);
   void      (*thread_self)        (gpointer              thread);
+  gboolean  (*thread_equal)       (gpointer              thread1,
+                                  gpointer              thread2);
 };
 
 GLIB_VAR GThreadFunctions       g_thread_functions_for_glib_use;
 GLIB_VAR gboolean               g_thread_use_default_impl;
 GLIB_VAR gboolean               g_threads_got_initialized;
 
+GLIB_VAR guint64   (*g_thread_gettime) (void);
+
 /* initializes the mutex/cond/private implementation for glib, might
  * only be called once, and must not be called directly or indirectly
  * from another glib-function, e.g. as a callback.
@@ -134,6 +134,11 @@ void    g_thread_init   (GThreadFunctions       *vtable);
  */
 void    g_thread_init_with_errorcheck_mutexes (GThreadFunctions* vtable);
 
+/* Checks if thread support is initialized.  Identical to the
+ * g_thread_supported macro but provided for language bindings.
+ */
+gboolean g_thread_get_initialized (void);
+
 /* A random number to recognize debug calls to g_mutex_... */
 #define G_MUTEX_DEBUG_MAGIC 0xf8e18ad7
 
@@ -144,49 +149,61 @@ void    g_thread_init_with_errorcheck_mutexes (GThreadFunctions* vtable);
 /* internal function for fallback static mutex implementation */
 GMutex* g_static_mutex_get_mutex_impl   (GMutex **mutex);
 
+#define g_static_mutex_get_mutex_impl_shortcut(mutex) \
+  (g_atomic_pointer_get (mutex) ? *(mutex) : \
+   g_static_mutex_get_mutex_impl (mutex))
+
 /* shorthands for conditional and unconditional function calls */
 
 #define G_THREAD_UF(op, arglist)                                       \
     (*g_thread_functions_for_glib_use . op) arglist
-#define G_THREAD_CF(op, fail, arg)                                     \
+#define G_THREAD_CF(op, fail, arg)                                     \
     (g_thread_supported () ? G_THREAD_UF (op, arg) : (fail))
 #define G_THREAD_ECF(op, fail, mutex, type)                            \
-    (g_thread_supported () ? ((type(*)(GMutex*, gulong, gchar*))       \
+    (g_thread_supported () ?                                           \
+      ((type(*)(GMutex*, const gulong, gchar const*))                  \
       (*g_thread_functions_for_glib_use . op))                         \
      (mutex, G_MUTEX_DEBUG_MAGIC, G_STRLOC) : (fail))
 
 #ifndef G_ERRORCHECK_MUTEXES
-# define g_mutex_lock(mutex)                                           \
+# define g_mutex_lock(mutex)                                           \
     G_THREAD_CF (mutex_lock,     (void)0, (mutex))
-# define g_mutex_trylock(mutex)                                        \
+# define g_mutex_trylock(mutex)                                                \
     G_THREAD_CF (mutex_trylock,  TRUE,    (mutex))
-# define g_mutex_unlock(mutex)                                         \
+# define g_mutex_unlock(mutex)                                         \
     G_THREAD_CF (mutex_unlock,   (void)0, (mutex))
-# define g_cond_wait(cond, mutex)                                      \
+# define g_mutex_free(mutex)                                           \
+    G_THREAD_CF (mutex_free,     (void)0, (mutex))
+# define g_cond_wait(cond, mutex)                                      \
     G_THREAD_CF (cond_wait,      (void)0, (cond, mutex))
-# define g_cond_timed_wait(cond, mutex, abs_time)                      \
+# define g_cond_timed_wait(cond, mutex, abs_time)                      \
     G_THREAD_CF (cond_timed_wait, TRUE,   (cond, mutex, abs_time))
 #else /* G_ERRORCHECK_MUTEXES */
-# define g_mutex_lock(mutex)                                                   \
-    G_THREAD_ECF (mutex_lock,    (void)0, mutex, void)
-# define g_mutex_trylock(mutex)                                        \
-    G_THREAD_ECF (mutex_trylock, TRUE,    mutex, gboolean)
-# define g_mutex_unlock(mutex)                                         \
-    G_THREAD_ECF (mutex_unlock,  (void)0, mutex, void)
+# define g_mutex_lock(mutex)                                           \
+    G_THREAD_ECF (mutex_lock,    (void)0, (mutex), void)
+# define g_mutex_trylock(mutex)                                                \
+    G_THREAD_ECF (mutex_trylock, TRUE,    (mutex), gboolean)
+# define g_mutex_unlock(mutex)                                         \
+    G_THREAD_ECF (mutex_unlock,  (void)0, (mutex), void)
+# define g_mutex_free(mutex)                                           \
+    G_THREAD_ECF (mutex_free,    (void)0, (mutex), void)
 # define g_cond_wait(cond, mutex)                                      \
     (g_thread_supported () ? ((void(*)(GCond*, GMutex*, gulong, gchar*))\
       g_thread_functions_for_glib_use.cond_wait)                       \
         (cond, mutex, G_MUTEX_DEBUG_MAGIC, G_STRLOC) : (void) 0)
-# define g_cond_timed_wait(cond, mutex, abs_time)                      \
-    (g_thread_supported () ?                                           \
+# define g_cond_timed_wait(cond, mutex, abs_time)                      \
+    (g_thread_supported () ?                                           \
       ((gboolean(*)(GCond*, GMutex*, GTimeVal*, gulong, gchar*))       \
-        g_thread_functions_for_glib_use.cond_timed_wait)               \
+        g_thread_functions_for_glib_use.cond_timed_wait)               \
           (cond, mutex, abs_time, G_MUTEX_DEBUG_MAGIC, G_STRLOC) : TRUE)
 #endif /* G_ERRORCHECK_MUTEXES */
 
+#if defined(G_THREADS_ENABLED) && defined(G_THREADS_MANDATORY)
+#define g_thread_supported()     1
+#else
 #define g_thread_supported()    (g_threads_got_initialized)
+#endif
 #define g_mutex_new()            G_THREAD_UF (mutex_new,      ())
-#define g_mutex_free(mutex)      G_THREAD_CF (mutex_free,     (void)0, (mutex))
 #define g_cond_new()             G_THREAD_UF (cond_new,       ())
 #define g_cond_signal(cond)      G_THREAD_CF (cond_signal,    (void)0, (cond))
 #define g_cond_broadcast(cond)   G_THREAD_CF (cond_broadcast, (void)0, (cond))
@@ -200,19 +217,24 @@ GMutex* g_static_mutex_get_mutex_impl   (GMutex **mutex);
                                                         (GPrivate*) (value)), \
                                                        (private_key, value))
 #define g_thread_yield()              G_THREAD_CF (thread_yield, (void)0, ())
-#define g_thread_exit()               G_THREAD_CF (thread_exit, (void)0, ())
-
-GThread* g_thread_create (GThreadFunc            thread_func,
-                          gpointer               arg,
-                          gulong                 stack_size,
-                          gboolean               joinable,
-                          gboolean               bound,
-                          GThreadPriority        priority,
-                          GError               **error);
-GThread* g_thread_self (void);
-void g_thread_join (GThread *thread);
-void g_thread_set_priority (GThread         *thread,
-                            GThreadPriority  priority);
+
+#define g_thread_create(func, data, joinable, error)                   \
+  (g_thread_create_full (func, data, 0, joinable, FALSE,               \
+                         G_THREAD_PRIORITY_NORMAL, error))
+
+GThread* g_thread_create_full  (GThreadFunc            func,
+                                gpointer               data,
+                                gulong                 stack_size,
+                                gboolean               joinable,
+                                gboolean               bound,
+                                GThreadPriority        priority,
+                                GError               **error);
+GThread* g_thread_self         (void);
+void     g_thread_exit         (gpointer               retval);
+gpointer g_thread_join         (GThread               *thread);
+
+void     g_thread_set_priority (GThread               *thread,
+                                GThreadPriority        priority);
 
 /* GStaticMutexes can be statically initialized with the value
  * G_STATIC_MUTEX_INIT, and then they can directly be used, that is
@@ -225,59 +247,110 @@ void g_thread_set_priority (GThread         *thread,
     g_mutex_trylock (g_static_mutex_get_mutex (mutex))
 #define g_static_mutex_unlock(mutex) \
     g_mutex_unlock (g_static_mutex_get_mutex (mutex))
+void g_static_mutex_init (GStaticMutex *mutex);
+void g_static_mutex_free (GStaticMutex *mutex);
 
 struct _GStaticPrivate
 {
+  /*< private >*/
   guint index;
 };
 #define G_STATIC_PRIVATE_INIT { 0 }
-gpointer g_static_private_get (GStaticPrivate   *private_key);
-void     g_static_private_set (GStaticPrivate   *private_key,
-                               gpointer          data,
-                               GDestroyNotify    notify);
-gpointer g_static_private_get_for_thread (GStaticPrivate *private_key,
-                                          GThread        *thread);
-void g_static_private_set_for_thread (GStaticPrivate *private_key,
-                                      GThread        *thread,
-                                      gpointer        data,
-                                      GDestroyNotify  notify);
+void     g_static_private_init           (GStaticPrivate   *private_key);
+gpointer g_static_private_get            (GStaticPrivate   *private_key);
+void     g_static_private_set            (GStaticPrivate   *private_key,
+                                         gpointer          data,
+                                         GDestroyNotify    notify);
+void     g_static_private_free           (GStaticPrivate   *private_key);
 
 typedef struct _GStaticRecMutex GStaticRecMutex;
 struct _GStaticRecMutex
 {
+  /*< private >*/
   GStaticMutex mutex;
-  unsigned int depth;
+  guint depth;
   GSystemThread owner;
 };
 
 #define G_STATIC_REC_MUTEX_INIT { G_STATIC_MUTEX_INIT }
+void     g_static_rec_mutex_init        (GStaticRecMutex *mutex);
 void     g_static_rec_mutex_lock        (GStaticRecMutex *mutex);
 gboolean g_static_rec_mutex_trylock     (GStaticRecMutex *mutex);
 void     g_static_rec_mutex_unlock      (GStaticRecMutex *mutex);
 void     g_static_rec_mutex_lock_full   (GStaticRecMutex *mutex,
                                          guint            depth);
 guint    g_static_rec_mutex_unlock_full (GStaticRecMutex *mutex);
+void     g_static_rec_mutex_free        (GStaticRecMutex *mutex);
 
 typedef struct _GStaticRWLock GStaticRWLock;
 struct _GStaticRWLock
 {
+  /*< private >*/
   GStaticMutex mutex;
   GCond *read_cond;
   GCond *write_cond;
   guint read_counter;
-  gboolean write;
+  gboolean have_writer;
+  guint want_to_read;
   guint want_to_write;
 };
 
-#define G_STATIC_RW_LOCK_INIT { G_STATIC_MUTEX_INIT, NULL, NULL, 0, FALSE, FALSE }
+#define G_STATIC_RW_LOCK_INIT { G_STATIC_MUTEX_INIT, NULL, NULL, 0, FALSE, 0, 0 }
 
+void      g_static_rw_lock_init           (GStaticRWLock* lock);
 void      g_static_rw_lock_reader_lock    (GStaticRWLock* lock);
 gboolean  g_static_rw_lock_reader_trylock (GStaticRWLock* lock);
 void      g_static_rw_lock_reader_unlock  (GStaticRWLock* lock);
 void      g_static_rw_lock_writer_lock    (GStaticRWLock* lock);
 gboolean  g_static_rw_lock_writer_trylock (GStaticRWLock* lock);
 void      g_static_rw_lock_writer_unlock  (GStaticRWLock* lock);
-void      g_static_rw_lock_free (GStaticRWLock* lock);
+void      g_static_rw_lock_free           (GStaticRWLock* lock);
+
+void     g_thread_foreach                (GFunc          thread_func,
+                                          gpointer       user_data);
+
+typedef enum
+{
+  G_ONCE_STATUS_NOTCALLED,
+  G_ONCE_STATUS_PROGRESS,
+  G_ONCE_STATUS_READY  
+} GOnceStatus;
+
+typedef struct _GOnce GOnce;
+struct _GOnce
+{
+  volatile GOnceStatus status;
+  volatile gpointer retval;
+};
+
+#define G_ONCE_INIT { G_ONCE_STATUS_NOTCALLED, NULL }
+
+gpointer g_once_impl (GOnce *once, GThreadFunc func, gpointer arg);
+
+#ifdef G_ATOMIC_OP_MEMORY_BARRIER_NEEDED
+# define g_once(once, func, arg) g_once_impl ((once), (func), (arg))
+#else /* !G_ATOMIC_OP_MEMORY_BARRIER_NEEDED*/
+# define g_once(once, func, arg) \
+  (((once)->status == G_ONCE_STATUS_READY) ? \
+   (once)->retval : \
+   g_once_impl ((once), (func), (arg)))
+#endif /* G_ATOMIC_OP_MEMORY_BARRIER_NEEDED */
+
+/* initialize-once guards, keyed by value_location */
+G_INLINE_FUNC gboolean  g_once_init_enter       (volatile gsize *value_location);
+gboolean                g_once_init_enter_impl  (volatile gsize *value_location);
+void                    g_once_init_leave       (volatile gsize *value_location,
+                                                 gsize           initialization_value);
+#if defined (G_CAN_INLINE) || defined (__G_THREAD_C__)
+G_INLINE_FUNC gboolean
+g_once_init_enter (volatile gsize *value_location)
+{
+  if G_LIKELY ((gpointer) g_atomic_pointer_get (value_location) != NULL)
+    return FALSE;
+  else
+    return g_once_init_enter_impl (value_location);
+}
+#endif /* G_CAN_INLINE || __G_THREAD_C__ */
 
 /* these are some convenience macros that expand to nothing if GLib
  * was configured with --disable-threads. for using StaticMutexes,
@@ -300,21 +373,21 @@ extern void glib_dummy_decl (void);
 #    define G_LOCK(name)                G_STMT_START{             \
         g_log (G_LOG_DOMAIN, G_LOG_LEVEL_DEBUG,                   \
                "file %s: line %d (%s): locking: %s ",             \
-               __FILE__,        __LINE__, G_GNUC_PRETTY_FUNCTION, \
+               __FILE__,        __LINE__, G_STRFUNC,              \
                #name);                                            \
         g_static_mutex_lock (&G_LOCK_NAME (name));                \
      }G_STMT_END
 #    define G_UNLOCK(name)              G_STMT_START{             \
         g_log (G_LOG_DOMAIN, G_LOG_LEVEL_DEBUG,                   \
                "file %s: line %d (%s): unlocking: %s ",           \
-               __FILE__,        __LINE__, G_GNUC_PRETTY_FUNCTION, \
+               __FILE__,        __LINE__, G_STRFUNC,              \
                #name);                                            \
        g_static_mutex_unlock (&G_LOCK_NAME (name));               \
      }G_STMT_END
 #    define G_TRYLOCK(name)                                       \
         (g_log (G_LOG_DOMAIN, G_LOG_LEVEL_DEBUG,                  \
                "file %s: line %d (%s): try locking: %s ",         \
-               __FILE__,        __LINE__, G_GNUC_PRETTY_FUNCTION, \
+               __FILE__,        __LINE__, G_STRFUNC,              \
                #name), g_static_mutex_trylock (&G_LOCK_NAME (name)))
 #  else  /* !G_DEBUG_LOCKS */
 #    define G_LOCK(name) g_static_mutex_lock       (&G_LOCK_NAME (name))
@@ -333,4 +406,3 @@ extern void glib_dummy_decl (void);
 G_END_DECLS
 
 #endif /* __G_THREAD_H__ */
-