X-Git-Url: http://review.tizen.org/git/?a=blobdiff_plain;f=glib%2Fgthread.c;h=ea8e5f9656f55945bb365f645e25dee26b61ed6b;hb=d0083f7e2dd621c6b78496bdb6ecf5d580c5e110;hp=065d7d90cb58651964ec8ef0ca1e414202b5aaaf;hpb=b4dc4902c6b7099266985421b775084b68e5d44e;p=platform%2Fupstream%2Fglib.git diff --git a/glib/gthread.c b/glib/gthread.c index 065d7d9..ea8e5f9 100644 --- a/glib/gthread.c +++ b/glib/gthread.c @@ -16,9 +16,7 @@ * 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. + * License along with this library; if not, see . */ /* Prelude {{{1 ----------------------------------------------------------- */ @@ -40,12 +38,12 @@ #include "config.h" -#include "deprecated/gthread.h" +#include "gthread.h" #include "gthreadprivate.h" -#include "gslice.h" -#include "gmain.h" -#ifdef HAVE_UNISTD_H +#include + +#ifdef G_OS_UNIX #include #endif @@ -56,13 +54,9 @@ #include #endif /* G_OS_WIN32 */ -#include - -#include "garray.h" -#include "gbitlock.h" -#include "gslist.h" +#include "gslice.h" +#include "gstrfuncs.h" #include "gtestutils.h" -#include "gtimer.h" /** * SECTION:threads @@ -87,66 +81,84 @@ * (#GMutex, #GRecMutex and #GRWLock). There is a facility to use * individual bits for locks (g_bit_lock()). There are primitives * for condition variables to allow synchronization of threads (#GCond). - * There are primitives for thread-private data - data that every thread - * has a private instance of (#GPrivate, #GStaticPrivate). There are - * facilities for one-time initialization (#GOnce, g_once_init_enter()). - * Finally there are primitives to create and manage threads (#GThread). - * - * The threading system is initialized with g_thread_init(). - * You may call any other glib functions in the main thread before - * g_thread_init() as long as g_thread_init() is not called from - * a GLib callback, or with any locks held. However, many libraries - * above GLib does not support late initialization of threads, so - * doing this should be avoided if possible. - * - * Please note that since version 2.24 the GObject initialization - * function g_type_init() initializes threads. Since 2.32, creating - * a mainloop will do so too. As a consequence, most applications, - * including those using GTK+ will run with threads enabled. - * - * After calling g_thread_init(), GLib is completely thread safe - * (all global data is automatically locked), but individual data - * structure instances are not automatically locked for performance - * reasons. So, for example you must coordinate accesses to the same - * #GHashTable from multiple threads. The two notable exceptions from - * this rule are #GMainLoop and #GAsyncQueue, which are - * threadsafe and need no further application-level locking to be - * accessed from multiple threads. - */ - -/** - * G_THREADS_IMPL_POSIX: - * - * This macro is defined if POSIX style threads are used. - */ - -/** - * G_THREADS_IMPL_WIN32: - * - * This macro is defined if Windows style threads are used. + * There are primitives for thread-private data - data that every + * thread has a private instance of (#GPrivate). There are facilities + * for one-time initialization (#GOnce, g_once_init_enter()). Finally, + * there are primitives to create and manage threads (#GThread). + * + * The GLib threading system used to be initialized with g_thread_init(). + * This is no longer necessary. Since version 2.32, the GLib threading + * system is automatically initialized at the start of your program, + * and all thread-creation functions and synchronization primitives + * are available right away. + * + * Note that it is not safe to assume that your program has no threads + * even if you don't call g_thread_new() yourself. GLib and GIO can + * and will create threads for their own purposes in some cases, such + * as when using g_unix_signal_source_new() or when using GDBus. + * + * Originally, UNIX did not have threads, and therefore some traditional + * UNIX APIs are problematic in threaded programs. Some notable examples + * are + * + * - C library functions that return data in statically allocated + * buffers, such as strtok() or strerror(). For many of these, + * there are thread-safe variants with a _r suffix, or you can + * look at corresponding GLib APIs (like g_strsplit() or g_strerror()). + * + * - The functions setenv() and unsetenv() manipulate the process + * environment in a not thread-safe way, and may interfere with getenv() + * calls in other threads. Note that getenv() calls may be hidden behind + * other APIs. For example, GNU gettext() calls getenv() under the + * covers. In general, it is best to treat the environment as readonly. + * If you absolutely have to modify the environment, do it early in + * main(), when no other threads are around yet. + * + * - The setlocale() function changes the locale for the entire process, + * affecting all threads. Temporary changes to the locale are often made + * to change the behavior of string scanning or formatting functions + * like scanf() or printf(). GLib offers a number of string APIs + * (like g_ascii_formatd() or g_ascii_strtod()) that can often be + * used as an alternative. Or you can use the uselocale() function + * to change the locale only for the current thread. + * + * - The fork() function only takes the calling thread into the child's + * copy of the process image. If other threads were executing in critical + * sections they could have left mutexes locked which could easily + * cause deadlocks in the new child. For this reason, you should + * call exit() or exec() as soon as possible in the child and only + * make signal-safe library calls before that. + * + * - The daemon() function uses fork() in a way contrary to what is + * described above. It should not be used with GLib programs. + * + * GLib itself is internally completely thread-safe (all global data is + * automatically locked), but individual data structure instances are + * not automatically locked for performance reasons. For example, + * you must coordinate accesses to the same #GHashTable from multiple + * threads. The two notable exceptions from this rule are #GMainLoop + * and #GAsyncQueue, which are thread-safe and need no further + * application-level locking to be accessed from multiple threads. + * Most refcounting functions such as g_object_ref() are also thread-safe. */ /* G_LOCK Documentation {{{1 ---------------------------------------------- */ /** * G_LOCK_DEFINE: - * @name: the name of the lock. + * @name: the name of the lock * - * The %G_LOCK_* macros provide a convenient interface to #GMutex - * with the advantage that they will expand to nothing in programs - * compiled against a thread-disabled GLib, saving code and memory - * there. #G_LOCK_DEFINE defines a lock. It can appear anywhere + * The #G_LOCK_ macros provide a convenient interface to #GMutex. + * #G_LOCK_DEFINE defines a lock. It can appear in any place where * variable definitions may appear in programs, i.e. in the first block * of a function or outside of functions. The @name parameter will be * mangled to get the name of the #GMutex. This means that you * can use names of existing variables as the parameter - e.g. the name - * of the variable you intent to protect with the lock. Look at our - * give_me_next_number() example using the - * %G_LOCK_* macros: + * of the variable you intend to protect with the lock. Look at our + * give_me_next_number() example using the #G_LOCK macros: * - * - * Using the %G_LOCK_* convenience macros - * + * Here is an example for using the #G_LOCK convenience macros: + * |[ * G_LOCK_DEFINE (current_number); * * int @@ -161,20 +173,19 @@ * * return ret_val; * } - * - * + * ]| */ /** * G_LOCK_DEFINE_STATIC: - * @name: the name of the lock. + * @name: the name of the lock * * This works like #G_LOCK_DEFINE, but it creates a static object. */ /** * G_LOCK_EXTERN: - * @name: the name of the lock. + * @name: the name of the lock * * This declares a lock, that is defined with #G_LOCK_DEFINE in another * module. @@ -182,7 +193,7 @@ /** * G_LOCK: - * @name: the name of the lock. + * @name: the name of the lock * * Works like g_mutex_lock(), but for a lock defined with * #G_LOCK_DEFINE. @@ -190,16 +201,17 @@ /** * G_TRYLOCK: - * @name: the name of the lock. - * @Returns: %TRUE, if the lock could be locked. + * @name: the name of the lock * * Works like g_mutex_trylock(), but for a lock defined with * #G_LOCK_DEFINE. + * + * Returns: %TRUE, if the lock could be locked. */ /** * G_UNLOCK: - * @name: the name of the lock. + * @name: the name of the lock * * Works like g_mutex_unlock(), but for a lock defined with * #G_LOCK_DEFINE. @@ -212,125 +224,48 @@ * * The #GMutex struct is an opaque data structure to represent a mutex * (mutual exclusion). It can be used to protect data against shared - * access. Take for example the following function: + * access. * - * - * A function which will not work in a threaded environment - * + * Take for example the following function: + * |[ * int * give_me_next_number (void) * { * static int current_number = 0; * - * /* now do a very complicated calculation to calculate the new - * * number, this might for example be a random number generator - * */ + * // now do a very complicated calculation to calculate the new + * // number, this might for example be a random number generator * current_number = calc_next_number (current_number); * * return current_number; * } - * - * - * + * ]| * It is easy to see that this won't work in a multi-threaded * application. There current_number must be protected against shared - * access. A first naive implementation would be: - * - * - * The wrong way to write a thread-safe function - * - * int - * give_me_next_number (void) - * { - * static int current_number = 0; - * int ret_val; - * static GMutex * mutex = NULL; - * - * if (!mutex) mutex = g_mutex_new (); - * - * g_mutex_lock (mutex); - * ret_val = current_number = calc_next_number (current_number); - * g_mutex_unlock (mutex); - * - * return ret_val; - * } - * - * - * - * This looks like it would work, but there is a race condition while - * constructing the mutex and this code cannot work reliable. Please do - * not use such constructs in your own programs! One working solution - * is: - * - * - * A correct thread-safe function - * - * static GMutex *give_me_next_number_mutex = NULL; - * - * /* this function must be called before any call to - * * give_me_next_number() - * * - * * it must be called exactly once. - * */ - * void - * init_give_me_next_number (void) - * { - * g_assert (give_me_next_number_mutex == NULL); - * give_me_next_number_mutex = g_mutex_new (); - * } - * - * int - * give_me_next_number (void) - * { - * static int current_number = 0; - * int ret_val; - * - * g_mutex_lock (give_me_next_number_mutex); - * ret_val = current_number = calc_next_number (current_number); - * g_mutex_unlock (give_me_next_number_mutex); - * - * return ret_val; - * } - * - * - * - * A statically initialized #GMutex provides an even simpler and safer - * way of doing this: - * - * - * Using a statically allocated mutex - * + * access. A #GMutex can be used as a solution to this problem: + * |[ * int * give_me_next_number (void) * { - * static GMutex mutex = G_MUTEX_INIT; + * static GMutex mutex; * static int current_number = 0; * int ret_val; * - * g_mutex_lock (&mutex); + * g_mutex_lock (&mutex); * ret_val = current_number = calc_next_number (current_number); - * g_mutex_unlock (&mutex); + * g_mutex_unlock (&mutex); * * return ret_val; * } - * - * - * - * A #GMutex should only be accessed via g_mutex_ - * functions. - */ - -/** - * G_MUTEX_INIT: - * - * Initializer for statically allocated #GMutexes. - * Alternatively, g_mutex_init() can be used. - * - * |[ - * GMutex mutex = G_MUTEX_INIT; * ]| + * Notice that the #GMutex is not initialised to any particular value. + * Its placement in static storage ensures that it will be initialised + * to all-zeros, which is appropriate. * - * Since: 2.32 + * If a #GMutex is placed in other contexts (eg: embedded in a struct) + * then it must be explicitly initialised using g_mutex_init(). + * + * A #GMutex should only be accessed via g_mutex_ functions. */ /* GRecMutex Documentation {{{1 -------------------------------------- */ @@ -344,23 +279,12 @@ * thread without deadlock. When doing so, care has to be taken to * unlock the recursive mutex as often as it has been locked. * - * A GRecMutex should only be accessed with the - * g_rec_mutex_ functions. Before a GRecMutex - * can be used, it has to be initialized with #G_REC_MUTEX_INIT or - * g_rec_mutex_init(). - * - * Since: 2.32 - */ - -/** - * G_REC_MUTEX_INIT: - * - * Initializer for statically allocated #GRecMutexes. - * Alternatively, g_rec_mutex_init() can be used. + * If a #GRecMutex is allocated in static storage then it can be used + * without initialisation. Otherwise, you should call + * g_rec_mutex_init() on it and g_rec_mutex_clear() when done. * - * |[ - * GRecMutex mutex = G_REC_MUTEX_INIT; - * ]| + * A GRecMutex should only be accessed with the + * g_rec_mutex_ functions. * * Since: 2.32 */ @@ -381,10 +305,9 @@ * simultaneous read-only access (by holding the 'reader' lock via * g_rw_lock_reader_lock()). * - * - * An array with access functions - * - * GRWLock lock = G_RW_LOCK_INIT; + * Here is an example for an array with access functions: + * |[ + * GRWLock lock; * GPtrArray *array; * * gpointer @@ -395,10 +318,10 @@ * if (!array) * return NULL; * - * g_rw_lock_reader_lock (&lock); - * if (index < array->len) + * g_rw_lock_reader_lock (&lock); + * if (index < array->len) * retval = g_ptr_array_index (array, index); - * g_rw_lock_reader_unlock (&lock); + * g_rw_lock_reader_unlock (&lock); * * return retval; * } @@ -406,45 +329,30 @@ * void * my_array_set (guint index, gpointer data) * { - * g_rw_lock_writer_lock (&lock); + * g_rw_lock_writer_lock (&lock); * * if (!array) - * array = g_ptr_array_new (); + * array = g_ptr_array_new (); * * if (index >= array->len) * g_ptr_array_set_size (array, index+1); * g_ptr_array_index (array, index) = data; * - * g_rw_lock_writer_unlock (&lock); + * g_rw_lock_writer_unlock (&lock); * } - * - * - * This example shows an array which can be accessed by many readers - * (the my_array_get() function) simultaneously, - * whereas the writers (the my_array_set() - * function) will only be allowed once at a time and only if no readers - * currently access the array. This is because of the potentially - * dangerous resizing of the array. Using these functions is fully - * multi-thread safe now. - * - * - * - * A GRWLock should only be accessed with the - * g_rw_lock_ functions. Before it can be used, - * it has to be initialized with #G_RW_LOCK_INIT or g_rw_lock_init(). + * ]| + * This example shows an array which can be accessed by many readers + * (the my_array_get() function) simultaneously, whereas the writers + * (the my_array_set() function) will only be allowed one at a time + * and only if no readers currently access the array. This is because + * of the potentially dangerous resizing of the array. Using these + * functions is fully multi-thread safe now. * - * Since: 2.32 - */ - -/** - * G_RW_LOCK_INIT: + * If a #GRWLock is allocated in static storage then it can be used + * without initialisation. Otherwise, you should call + * g_rw_lock_init() on it and g_rw_lock_clear() when done. * - * Initializer for statically allocated #GRWLocks. - * Alternatively, g_rw_lock_init_init() can be used. - * - * |[ - * GRWLock lock = G_RW_LOCK_INIT; - * ]| + * A GRWLock should only be accessed with the g_rw_lock_ functions. * * Since: 2.32 */ @@ -460,22 +368,25 @@ * condition they signal the #GCond, and that causes the waiting * threads to be woken up. * - * - * - * Using GCond to block a thread until a condition is satisfied - * - * - * GCond* data_cond = NULL; /* Must be initialized somewhere */ - * GMutex* data_mutex = NULL; /* Must be initialized somewhere */ + * Consider the following example of a shared variable. One or more + * threads can wait for data to be published to the variable and when + * another thread publishes the data, it can signal one of the waiting + * threads to wake up to collect the data. + * + * Here is an example for using GCond to block a thread until a condition + * is satisfied: + * |[ * gpointer current_data = NULL; + * GMutex data_mutex; + * GCond data_cond; * * void * push_data (gpointer data) * { - * g_mutex_lock (data_mutex); + * g_mutex_lock (&data_mutex); * current_data = data; - * g_cond_signal (data_cond); - * g_mutex_unlock (data_mutex); + * g_cond_signal (&data_cond); + * g_mutex_unlock (&data_mutex); * } * * gpointer @@ -483,98 +394,39 @@ * { * gpointer data; * - * g_mutex_lock (data_mutex); + * g_mutex_lock (&data_mutex); * while (!current_data) - * g_cond_wait (data_cond, data_mutex); + * g_cond_wait (&data_cond, &data_mutex); * data = current_data; * current_data = NULL; - * g_mutex_unlock (data_mutex); + * g_mutex_unlock (&data_mutex); * * return data; * } - * - * - * + * ]| * Whenever a thread calls pop_data() now, it will wait until * current_data is non-%NULL, i.e. until some other thread * has called push_data(). * - * It is important to use the g_cond_wait() and - * g_cond_timed_wait() functions only inside a loop which checks for the - * condition to be true. It is not guaranteed that the waiting thread - * will find the condition fulfilled after it wakes up, even if the - * signaling thread left the condition in that state: another thread may - * have altered the condition before the waiting thread got the chance - * to be woken up, even if the condition itself is protected by a - * #GMutex, like above. - * - * A #GCond should only be accessed via the g_cond_ - * functions. - */ - -/** - * G_COND_INIT: - * - * Initializer for statically allocated #GConds. - * Alternatively, g_cond_init() can be used. - * - * |[ - * GCond cond = G_COND_INIT; - * ]| - * - * Since: 2.32 - */ - -/* GPrivate Documentation {{{1 --------------------------------------- */ - -/** - * GPrivate: - * - * - * #GStaticPrivate is a better choice for most uses. - * - * - * The #GPrivate struct is an opaque data structure to represent a - * thread private data key. Threads can thereby obtain and set a - * pointer which is private to the current thread. Take our - * give_me_next_number() example from - * above. Suppose we don't want current_number to be - * shared between the threads, but instead to be private to each thread. - * This can be done as follows: - * - * - * Using GPrivate for per-thread data - * - * GPrivate* current_number_key = NULL; /* Must be initialized somewhere - * with g_private_new (g_free); */ - * - * int - * give_me_next_number (void) - * { - * int *current_number = g_private_get (current_number_key); - * - * if (!current_number) - * { - * current_number = g_new (int, 1); - * *current_number = 0; - * g_private_set (current_number_key, current_number); - * } - * - * *current_number = calc_next_number (*current_number); - * - * return *current_number; - * } - * - * - * - * Here the pointer belonging to the key - * current_number_key is read. If it is %NULL, it has - * not been set yet. Then get memory for an integer value, assign this - * memory to the pointer and write the pointer back. Now we have an - * integer value that is private to the current thread. - * - * The #GPrivate struct should only be accessed via the - * g_private_ functions. + * The example shows that use of a condition variable must always be + * paired with a mutex. Without the use of a mutex, there would be a + * race between the check of @current_data by the while loop in + * pop_data() and waiting. Specifically, another thread could set + * @current_data after the check, and signal the cond (with nobody + * waiting on it) before the first thread goes to sleep. #GCond is + * specifically useful for its ability to release the mutex and go + * to sleep atomically. + * + * It is also important to use the g_cond_wait() and g_cond_wait_until() + * functions only inside a loop which checks for the condition to be + * true. See g_cond_wait() for an explanation of why the condition may + * not be true even after it returns. + * + * If a #GCond is allocated in static storage then it can be used + * without initialisation. Otherwise, you should call g_cond_init() + * on it and g_cond_clear() when done. + * + * A #GCond should only be accessed via the g_cond_ functions. */ /* GThread Documentation {{{1 ---------------------------------------- */ @@ -582,20 +434,29 @@ /** * GThread: * - * The #GThread struct represents a running thread. + * The #GThread struct represents a running thread. This struct + * is returned by g_thread_new() or g_thread_try_new(). You can + * obtain the #GThread struct representing the current thread by + * calling g_thread_self(). + * + * GThread is refcounted, see g_thread_ref() and g_thread_unref(). + * The thread represented by it holds a reference while it is running, + * and g_thread_join() consumes the reference that it is given, so + * it is normally not necessary to manage GThread references + * explicitly. * - * Resources for a joinable thread are not fully released - * until g_thread_join() is called for that thread. + * The structure is opaque -- none of its fields may be directly + * accessed. */ /** * GThreadFunc: * @data: data passed to the thread - * @Returns: the return value of the thread, which will be returned by - * g_thread_join() * - * Specifies the type of the @func functions passed to - * g_thread_create() or g_thread_create_full(). + * Specifies the type of the @func functions passed to g_thread_new() + * or g_thread_try_new(). + * + * Returns: the return value of the thread */ /** @@ -624,116 +485,18 @@ * * The error domain of the GLib thread subsystem. **/ -GQuark -g_thread_error_quark (void) -{ - return g_quark_from_static_string ("g_thread_error"); -} - -/* Miscellaneous Structures {{{1 ------------------------------------------ */ - -typedef struct _GRealThread GRealThread; -struct _GRealThread -{ - GThread thread; - /* Bit 0 protects private_data. To avoid deadlocks, - * do not block while holding this (particularly on - * the g_thread lock). - */ - volatile gint private_data_lock; - GArray *private_data; - GRealThread *next; - gpointer retval; - GSystemThread system_thread; -}; - -#define LOCK_PRIVATE_DATA(self) g_bit_lock (&(self)->private_data_lock, 0) -#define UNLOCK_PRIVATE_DATA(self) g_bit_unlock (&(self)->private_data_lock, 0) +G_DEFINE_QUARK (g_thread_error, g_thread_error) /* Local Data {{{1 -------------------------------------------------------- */ -gboolean g_threads_got_initialized = FALSE; -GSystemThread zero_thread; /* This is initialized to all zero */ -GMutex g_once_mutex = G_MUTEX_INIT; - -static GCond g_once_cond = G_COND_INIT; -static GPrivate g_thread_specific_private; -static GRealThread *g_thread_all_threads = NULL; -static GSList *g_thread_free_indices = NULL; -static GSList* g_once_init_list = NULL; - -G_LOCK_DEFINE_STATIC (g_thread); - -/* Initialisation {{{1 ---------------------------------------------------- */ - -/** - * g_thread_init: - * @vtable: a function table of type #GThreadFunctions, that provides - * the entry points to the thread system to be used. Since 2.32, - * this parameter is ignored and should always be %NULL - * - * If you use GLib from more than one thread, you must initialize the - * thread system by calling g_thread_init(). - * - * Since version 2.24, calling g_thread_init() multiple times is allowed, - * but nothing happens except for the first call. - * - * Since version 2.32, GLib does not support custom thread implementations - * anymore and the @vtable parameter is ignored and you should pass %NULL. - * - * g_thread_init() must not be called directly or indirectly - * in a callback from GLib. Also no mutexes may be currently locked while - * calling g_thread_init(). - * - * To use g_thread_init() in your program, you have to link - * with the libraries that the command pkg-config --libs - * gthread-2.0 outputs. This is not the case for all the - * other thread-related functions of GLib. Those can be used without - * having to link with the thread libraries. - */ +static GMutex g_once_mutex; +static GCond g_once_cond; +static GSList *g_once_init_list = NULL; static void g_thread_cleanup (gpointer data); +static GPrivate g_thread_specific_private = G_PRIVATE_INIT (g_thread_cleanup); -void -g_thread_init_glib (void) -{ - static gboolean already_done; - GRealThread* main_thread; - - if (already_done) - return; - - already_done = TRUE; - - /* We let the main thread (the one that calls g_thread_init) inherit - * the static_private data set before calling g_thread_init - */ - main_thread = (GRealThread*) g_thread_self (); - - /* setup the basic threading system */ - g_threads_got_initialized = TRUE; - g_private_init (&g_thread_specific_private, g_thread_cleanup); - g_private_set (&g_thread_specific_private, main_thread); - g_system_thread_self (&main_thread->system_thread); - - /* accomplish log system initialization to enable messaging */ - _g_messages_thread_init_nomessage (); -} - -/** - * g_thread_get_initialized: - * - * Indicates if g_thread_init() has been called. - * - * Returns: %TRUE if threads have been initialized. - * - * Since: 2.20 - */ -gboolean -g_thread_get_initialized (void) -{ - return g_thread_supported (); -} +G_LOCK_DEFINE_STATIC (g_thread_new); /* GOnce {{{1 ------------------------------------------------------------- */ @@ -755,7 +518,7 @@ g_thread_get_initialized (void) * * A #GOnce must be initialized with this macro before it can be used. * - * |[ + * |[ * GOnce my_once = G_ONCE_INIT; * ]| * @@ -795,7 +558,7 @@ g_thread_get_initialized (void) * Calling g_once() recursively on the same #GOnce struct in * @func will lead to a deadlock. * - * |[ + * |[ * gpointer * get_debug_flags (void) * { @@ -838,11 +601,10 @@ g_once_impl (GOnce *once, /** * g_once_init_enter: - * @value_location: location of a static initializable variable - * containing 0 + * @location: location of a static initializable variable containing 0 * * Function to be called when starting a critical initialization - * section. The argument @value_location must point to a static + * section. The argument @location must point to a static * 0-initialized variable that will be set to a value other than 0 at * the end of the initialization section. In combination with * g_once_init_leave() and the unique address @value_location, it can @@ -851,17 +613,17 @@ g_once_impl (GOnce *once, * blocked until initialization completed. To be used in constructs * like this: * - * |[ + * |[ * static gsize initialization_value = 0; * - * if (g_once_init_enter (&initialization_value)) + * if (g_once_init_enter (&initialization_value)) * { - * gsize setup_value = 42; /** initialization code here **/ + * gsize setup_value = 42; // initialization code here * - * g_once_init_leave (&initialization_value, setup_value); + * g_once_init_leave (&initialization_value, setup_value); * } * - * /** use initialization_value here **/ + * // use initialization_value here * ]| * * Returns: %TRUE if the initialization section should be entered, @@ -870,8 +632,9 @@ g_once_impl (GOnce *once, * Since: 2.14 */ gboolean -g_once_init_enter_impl (volatile gsize *value_location) +(g_once_init_enter) (volatile void *location) { + volatile gsize *value_location = location; gboolean need_init = FALSE; g_mutex_lock (&g_once_mutex); if (g_atomic_pointer_get (value_location) == NULL) @@ -892,9 +655,8 @@ g_once_init_enter_impl (volatile gsize *value_location) /** * g_once_init_leave: - * @value_location: location of a static initializable variable - * containing 0 - * @initialization_value: new non-0 value for *@value_location + * @location: location of a static initializable variable containing 0 + * @result: new non-0 value for *@value_location * * Counterpart to g_once_init_enter(). Expects a location of a static * 0-initialized initialization variable, and an initialization value @@ -905,341 +667,79 @@ g_once_init_enter_impl (volatile gsize *value_location) * Since: 2.14 */ void -g_once_init_leave (volatile gsize *value_location, - gsize initialization_value) +(g_once_init_leave) (volatile void *location, + gsize result) { + volatile gsize *value_location = location; + g_return_if_fail (g_atomic_pointer_get (value_location) == NULL); - g_return_if_fail (initialization_value != 0); + g_return_if_fail (result != 0); g_return_if_fail (g_once_init_list != NULL); - g_atomic_pointer_set (value_location, initialization_value); + g_atomic_pointer_set (value_location, result); g_mutex_lock (&g_once_mutex); g_once_init_list = g_slist_remove (g_once_init_list, (void*) value_location); g_cond_broadcast (&g_once_cond); g_mutex_unlock (&g_once_mutex); } -/* GStaticPrivate {{{1 ---------------------------------------------------- */ - -typedef struct _GStaticPrivateNode GStaticPrivateNode; -struct _GStaticPrivateNode -{ - gpointer data; - GDestroyNotify destroy; -}; - -/** - * GStaticPrivate: - * - * A #GStaticPrivate works almost like a #GPrivate, but it has one - * significant advantage. It doesn't need to be created at run-time - * like a #GPrivate, but can be defined at compile-time. This is - * similar to the difference between #GMutex and #GStaticMutex. Now - * look at our give_me_next_number() example with - * #GStaticPrivate: - * - * - * Using GStaticPrivate for per-thread data - * - * int - * give_me_next_number () - * { - * static GStaticPrivate current_number_key = G_STATIC_PRIVATE_INIT; - * int *current_number = g_static_private_get (&current_number_key); - * - * if (!current_number) - * { - * current_number = g_new (int,1); - * *current_number = 0; - * g_static_private_set (&current_number_key, current_number, g_free); - * } - * - * *current_number = calc_next_number (*current_number); - * - * return *current_number; - * } - * - * - */ - -/** - * G_STATIC_PRIVATE_INIT: - * - * Every #GStaticPrivate must be initialized with this macro, before it - * can be used. - * - * |[ - * GStaticPrivate my_private = G_STATIC_PRIVATE_INIT; - * ]| - */ - -/** - * g_static_private_init: - * @private_key: a #GStaticPrivate to be initialized - * - * Initializes @private_key. Alternatively you can initialize it with - * #G_STATIC_PRIVATE_INIT. - */ -void -g_static_private_init (GStaticPrivate *private_key) -{ - private_key->index = 0; -} +/* GThread {{{1 -------------------------------------------------------- */ /** - * g_static_private_get: - * @private_key: a #GStaticPrivate + * g_thread_ref: + * @thread: a #GThread * - * Works like g_private_get() only for a #GStaticPrivate. + * Increase the reference count on @thread. * - * This function works even if g_thread_init() has not yet been called. + * Returns: a new reference to @thread * - * Returns: the corresponding pointer - */ -gpointer -g_static_private_get (GStaticPrivate *private_key) -{ - GRealThread *self = (GRealThread*) g_thread_self (); - GArray *array; - gpointer ret = NULL; - - LOCK_PRIVATE_DATA (self); - - array = self->private_data; - - if (array && private_key->index != 0 && private_key->index <= array->len) - ret = g_array_index (array, GStaticPrivateNode, - private_key->index - 1).data; - - UNLOCK_PRIVATE_DATA (self); - return ret; -} - -/** - * g_static_private_set: - * @private_key: a #GStaticPrivate - * @data: the new pointer - * @notify: a function to be called with the pointer whenever the - * current thread ends or sets this pointer again - * - * Sets the pointer keyed to @private_key for the current thread and - * the function @notify to be called with that pointer (%NULL or - * non-%NULL), whenever the pointer is set again or whenever the - * current thread ends. - * - * This function works even if g_thread_init() has not yet been called. - * If g_thread_init() is called later, the @data keyed to @private_key - * will be inherited only by the main thread, i.e. the one that called - * g_thread_init(). - * - * @notify is used quite differently from @destructor in - * g_private_new(). + * Since: 2.32 */ -void -g_static_private_set (GStaticPrivate *private_key, - gpointer data, - GDestroyNotify notify) +GThread * +g_thread_ref (GThread *thread) { - GRealThread *self = (GRealThread*) g_thread_self (); - GArray *array; - static guint next_index = 0; - GStaticPrivateNode *node; - gpointer ddata = NULL; - GDestroyNotify ddestroy = NULL; - - if (!private_key->index) - { - G_LOCK (g_thread); - - if (!private_key->index) - { - if (g_thread_free_indices) - { - private_key->index = - GPOINTER_TO_UINT (g_thread_free_indices->data); - g_thread_free_indices = - g_slist_delete_link (g_thread_free_indices, - g_thread_free_indices); - } - else - private_key->index = ++next_index; - } - - G_UNLOCK (g_thread); - } - - LOCK_PRIVATE_DATA (self); - - array = self->private_data; - if (!array) - { - array = g_array_new (FALSE, TRUE, sizeof (GStaticPrivateNode)); - self->private_data = array; - } - - if (private_key->index > array->len) - g_array_set_size (array, private_key->index); - - node = &g_array_index (array, GStaticPrivateNode, private_key->index - 1); + GRealThread *real = (GRealThread *) thread; - ddata = node->data; - ddestroy = node->destroy; + g_atomic_int_inc (&real->ref_count); - node->data = data; - node->destroy = notify; - - UNLOCK_PRIVATE_DATA (self); - - if (ddestroy) - ddestroy (ddata); + return thread; } /** - * g_static_private_free: - * @private_key: a #GStaticPrivate to be freed + * g_thread_unref: + * @thread: a #GThread + * + * Decrease the reference count on @thread, possibly freeing all + * resources associated with it. * - * Releases all resources allocated to @private_key. + * Note that each thread holds a reference to its #GThread while + * it is running, so it is safe to drop your own reference to it + * if you don't need it anymore. * - * You don't have to call this functions for a #GStaticPrivate with an - * unbounded lifetime, i.e. objects declared 'static', but if you have - * a #GStaticPrivate as a member of a structure and the structure is - * freed, you should also free the #GStaticPrivate. + * Since: 2.32 */ void -g_static_private_free (GStaticPrivate *private_key) +g_thread_unref (GThread *thread) { - guint idx = private_key->index; - GRealThread *thread, *next; - GArray *garbage = NULL; - - if (!idx) - return; - - private_key->index = 0; - - G_LOCK (g_thread); - - thread = g_thread_all_threads; - - for (thread = g_thread_all_threads; thread; thread = next) - { - GArray *array; - - next = thread->next; - - LOCK_PRIVATE_DATA (thread); - - array = thread->private_data; - - if (array && idx <= array->len) - { - GStaticPrivateNode *node = &g_array_index (array, - GStaticPrivateNode, - idx - 1); - gpointer ddata = node->data; - GDestroyNotify ddestroy = node->destroy; + GRealThread *real = (GRealThread *) thread; - node->data = NULL; - node->destroy = NULL; - - if (ddestroy) - { - /* defer non-trivial destruction til after we've finished - * iterating, since we must continue to hold the lock */ - if (garbage == NULL) - garbage = g_array_new (FALSE, TRUE, - sizeof (GStaticPrivateNode)); - - g_array_set_size (garbage, garbage->len + 1); - - node = &g_array_index (garbage, GStaticPrivateNode, - garbage->len - 1); - node->data = ddata; - node->destroy = ddestroy; - } - } - - UNLOCK_PRIVATE_DATA (thread); - } - g_thread_free_indices = g_slist_prepend (g_thread_free_indices, - GUINT_TO_POINTER (idx)); - G_UNLOCK (g_thread); - - if (garbage) + if (g_atomic_int_dec_and_test (&real->ref_count)) { - guint i; - - for (i = 0; i < garbage->len; i++) - { - GStaticPrivateNode *node; - - node = &g_array_index (garbage, GStaticPrivateNode, i); - node->destroy (node->data); - } - - g_array_free (garbage, TRUE); + if (real->ours) + g_system_thread_free (real); + else + g_slice_free (GRealThread, real); } } -/* GThread {{{1 -------------------------------------------------------- */ - static void g_thread_cleanup (gpointer data) { - if (data) - { - GRealThread* thread = data; - GArray *array; - - LOCK_PRIVATE_DATA (thread); - array = thread->private_data; - thread->private_data = NULL; - UNLOCK_PRIVATE_DATA (thread); - - if (array) - { - guint i; - - for (i = 0; i < array->len; i++ ) - { - GStaticPrivateNode *node = - &g_array_index (array, GStaticPrivateNode, i); - if (node->destroy) - node->destroy (node->data); - } - g_array_free (array, TRUE); - } - - /* We only free the thread structure if it isn't joinable. - * If it is, the structure is freed in g_thread_join() - */ - if (!thread->thread.joinable) - { - GRealThread *t, *p; - - G_LOCK (g_thread); - for (t = g_thread_all_threads, p = NULL; t; p = t, t = t->next) - { - if (t == thread) - { - if (p) - p->next = t->next; - else - g_thread_all_threads = t->next; - break; - } - } - G_UNLOCK (g_thread); - - /* Just to make sure, this isn't used any more */ - g_system_thread_assign (thread->system_thread, zero_thread); - g_free (thread); - } - } + g_thread_unref (data); } -static gpointer -g_thread_create_proxy (gpointer data) +gpointer +g_thread_proxy (gpointer data) { GRealThread* thread = data; @@ -1248,11 +748,18 @@ g_thread_create_proxy (gpointer data) /* This has to happen before G_LOCK, as that might call g_thread_self */ g_private_set (&g_thread_specific_private, data); - /* The lock makes sure that thread->system_thread is written, - * before thread->thread.func is called. See g_thread_create(). + /* The lock makes sure that g_thread_new_internal() has a chance to + * setup 'func' and 'data' before we make the call. */ - G_LOCK (g_thread); - G_UNLOCK (g_thread); + G_LOCK (g_thread_new); + G_UNLOCK (g_thread_new); + + if (thread->name) + { + g_system_thread_set_name (thread->name); + g_free (thread->name); + thread->name = NULL; + } thread->retval = thread->thread.func (thread->thread.data); @@ -1260,130 +767,127 @@ g_thread_create_proxy (gpointer data) } /** - * g_thread_create: + * g_thread_new: + * @name: (allow-none): an (optional) name for the new thread * @func: a function to execute in the new thread * @data: an argument to supply to the new thread - * @joinable: should this thread be joinable? - * @error: return location for error, or %NULL * - * This function creates a new thread. + * This function creates a new thread. The new thread starts by invoking + * @func with the argument data. The thread will run until @func returns + * or until g_thread_exit() is called from the new thread. The return value + * of @func becomes the return value of the thread, which can be obtained + * with g_thread_join(). * - * If @joinable is %TRUE, you can wait for this threads termination - * calling g_thread_join(). Otherwise the thread will just disappear - * when it terminates. + * The @name can be useful for discriminating threads in a debugger. + * It is not used for other purposes and does not have to be unique. + * Some systems restrict the length of @name to 16 bytes. * - * The new thread executes the function @func with the argument @data. - * If the thread was created successfully, it is returned. + * If the thread can not be created the program aborts. See + * g_thread_try_new() if you want to attempt to deal with failures. * - * @error can be %NULL to ignore errors, or non-%NULL to report errors. - * The error is set, if and only if the function returns %NULL. + * To free the struct returned by this function, use g_thread_unref(). + * Note that g_thread_join() implicitly unrefs the #GThread as well. * - * Returns: the new #GThread on success + * Returns: the new #GThread + * + * Since: 2.32 */ GThread * -g_thread_create (GThreadFunc func, - gpointer data, - gboolean joinable, - GError **error) +g_thread_new (const gchar *name, + GThreadFunc func, + gpointer data) { - return g_thread_create_with_stack_size (func, data, joinable, 0, error); + GError *error = NULL; + GThread *thread; + + thread = g_thread_new_internal (name, g_thread_proxy, func, data, 0, &error); + + if G_UNLIKELY (thread == NULL) + g_error ("creating thread '%s': %s", name ? name : "", error->message); + + return thread; } /** - * g_thread_create_with_stack_size: + * g_thread_try_new: + * @name: (allow-none): an (optional) name for the new thread * @func: a function to execute in the new thread * @data: an argument to supply to the new thread - * @joinable: should this thread be joinable? - * @stack_size: a stack size for the new thread - * @error: return location for error - * - * This function creates a new thread. If the underlying thread - * implementation supports it, the thread gets a stack size of - * @stack_size or the default value for the current platform, if - * @stack_size is 0. - * - * If @joinable is %TRUE, you can wait for this threads termination - * calling g_thread_join(). Otherwise the thread will just disappear - * when it terminates. - * - * The new thread executes the function @func with the argument @data. - * If the thread was created successfully, it is returned. + * @error: return location for error, or %NULL * - * @error can be %NULL to ignore errors, or non-%NULL to report errors. - * The error is set, if and only if the function returns %NULL. + * This function is the same as g_thread_new() except that + * it allows for the possibility of failure. * - * Only use g_thread_create_with_stack_size() if you - * really can't use g_thread_create() instead. g_thread_create() - * does not take @stack_size, as it should only be used in cases - * in which it is unavoidable. + * If a thread can not be created (due to resource limits), + * @error is set and %NULL is returned. * - * Returns: the new #GThread on success + * Returns: the new #GThread, or %NULL if an error occurred * * Since: 2.32 */ -GThread* -g_thread_create_with_stack_size (GThreadFunc func, - gpointer data, - gboolean joinable, - gsize stack_size, - GError **error) +GThread * +g_thread_try_new (const gchar *name, + GThreadFunc func, + gpointer data, + GError **error) { - GRealThread* result; - GError *local_error = NULL; - g_return_val_if_fail (func, NULL); - - result = g_new0 (GRealThread, 1); - - result->thread.joinable = joinable; - result->thread.func = func; - result->thread.data = data; - result->private_data = NULL; - G_LOCK (g_thread); - g_system_thread_create (g_thread_create_proxy, result, - stack_size, joinable, - &result->system_thread, &local_error); - if (!local_error) - { - result->next = g_thread_all_threads; - g_thread_all_threads = result; - } - G_UNLOCK (g_thread); + return g_thread_new_internal (name, g_thread_proxy, func, data, 0, error); +} + +GThread * +g_thread_new_internal (const gchar *name, + GThreadFunc proxy, + GThreadFunc func, + gpointer data, + gsize stack_size, + GError **error) +{ + GRealThread *thread; + + g_return_val_if_fail (func != NULL, NULL); - if (local_error) + G_LOCK (g_thread_new); + thread = g_system_thread_new (proxy, stack_size, error); + if (thread) { - g_propagate_error (error, local_error); - g_free (result); - return NULL; + thread->ref_count = 2; + thread->ours = TRUE; + thread->thread.joinable = TRUE; + thread->thread.func = func; + thread->thread.data = data; + thread->name = g_strdup (name); } + G_UNLOCK (g_thread_new); - return (GThread*) result; + return (GThread*) thread; } /** * g_thread_exit: * @retval: the return value of this thread * - * Exits the current thread. If another thread is waiting for that - * thread using g_thread_join() and the current thread is joinable, the - * waiting thread will be woken up and get @retval as the return value - * of g_thread_join(). If the current thread is not joinable, @retval - * is ignored. Calling + * Terminates the current thread. * - * |[ - * g_thread_exit (retval); - * ]| + * If another thread is waiting for us using g_thread_join() then the + * waiting thread will be woken up and get @retval as the return value + * of g_thread_join(). * - * is equivalent to returning @retval from the function @func, as given - * to g_thread_create(). + * Calling g_thread_exit() with a parameter @retval is equivalent to + * returning @retval from the function @func, as given to g_thread_new(). * - * Never call g_thread_exit() from within a thread of a - * #GThreadPool, as that will mess up the bookkeeping and lead to funny - * and unwanted results. + * You must only call g_thread_exit() from a thread that you created + * yourself with g_thread_new() or related APIs. You must not call + * this function from a thread created with another threading library + * or or from within a #GThreadPool. */ void g_thread_exit (gpointer retval) { GRealThread* real = (GRealThread*) g_thread_self (); + + if G_UNLIKELY (!real->ours) + g_error ("attempt to g_thread_exit() a thread not created by GLib"); + real->retval = retval; g_system_thread_exit (); @@ -1391,55 +895,44 @@ g_thread_exit (gpointer retval) /** * g_thread_join: - * @thread: a #GThread to be waited for + * @thread: a #GThread + * + * Waits until @thread finishes, i.e. the function @func, as + * given to g_thread_new(), returns or g_thread_exit() is called. + * If @thread has already terminated, then g_thread_join() + * returns immediately. + * + * Any thread can wait for any other thread by calling g_thread_join(), + * not just its 'creator'. Calling g_thread_join() from multiple threads + * for the same @thread leads to undefined behaviour. * - * Waits until @thread finishes, i.e. the function @func, as given to - * g_thread_create(), returns or g_thread_exit() is called by @thread. - * All resources of @thread including the #GThread struct are released. - * @thread must have been created with @joinable=%TRUE in - * g_thread_create(). The value returned by @func or given to - * g_thread_exit() by @thread is returned by this function. + * The value returned by @func or given to g_thread_exit() is + * returned by this function. + * + * g_thread_join() consumes the reference to the passed-in @thread. + * This will usually cause the #GThread struct and associated resources + * to be freed. Use g_thread_ref() to obtain an extra reference if you + * want to keep the GThread alive beyond the g_thread_join() call. * * Returns: the return value of the thread */ gpointer -g_thread_join (GThread* thread) +g_thread_join (GThread *thread) { - GRealThread* real = (GRealThread*) thread; - GRealThread *p, *t; + GRealThread *real = (GRealThread*) thread; gpointer retval; g_return_val_if_fail (thread, NULL); - g_return_val_if_fail (thread->joinable, NULL); - g_return_val_if_fail (!g_system_thread_equal (&real->system_thread, &zero_thread), NULL); + g_return_val_if_fail (real->ours, NULL); - g_system_thread_join (&real->system_thread); + g_system_thread_wait (real); retval = real->retval; - G_LOCK (g_thread); - for (t = g_thread_all_threads, p = NULL; t; p = t, t = t->next) - { - if (t == (GRealThread*) thread) - { - if (p) - p->next = t->next; - else - g_thread_all_threads = t->next; - break; - } - } - G_UNLOCK (g_thread); - /* Just to make sure, this isn't used any more */ thread->joinable = 0; - g_system_thread_assign (real->system_thread, zero_thread); - /* the thread structure for non-joinable threads is freed upon - * thread end. We free the memory here. This will leave a loose end, - * if a joinable thread is not joined. - */ - g_free (thread); + g_thread_unref (thread); return retval; } @@ -1447,10 +940,17 @@ g_thread_join (GThread* thread) /** * g_thread_self: * - * This functions returns the #GThread corresponding to the calling - * thread. + * This functions returns the #GThread corresponding to the + * current thread. Note that this function does not increase + * the reference count of the returned struct. + * + * This function will return a #GThread even for threads that + * were not created by GLib (i.e. those created by other threading + * APIs). This may be useful for thread identification purposes + * (i.e. comparisons) but you must not use GLib functions (such + * as g_thread_join()) on these threads. * - * Returns: the current thread + * Returns: the #GThread representing the current thread */ GThread* g_thread_self (void) @@ -1463,177 +963,70 @@ g_thread_self (void) * This can happen for the main thread and for threads * that are not created by GLib. */ - thread = g_new0 (GRealThread, 1); - thread->thread.joinable = FALSE; /* This is a safe guess */ - thread->thread.func = NULL; - thread->thread.data = NULL; - thread->private_data = NULL; - - g_system_thread_self (&thread->system_thread); + thread = g_slice_new0 (GRealThread); + thread->ref_count = 1; g_private_set (&g_thread_specific_private, thread); - - G_LOCK (g_thread); - thread->next = g_thread_all_threads; - g_thread_all_threads = thread; - G_UNLOCK (g_thread); } - return (GThread*)thread; + return (GThread*) thread; } /** - * g_thread_foreach: - * @thread_func: function to call for all #GThread structures - * @user_data: second argument to @thread_func + * g_get_num_processors: * - * Call @thread_func on all existing #GThread structures. - * Note that threads may decide to exit while @thread_func is - * running, so without intimate knowledge about the lifetime of - * foreign threads, @thread_func shouldn't access the GThread* - * pointer passed in as first argument. However, @thread_func will - * not be called for threads which are known to have exited already. + * Determine the approximate number of threads that the system will + * schedule simultaneously for this process. This is intended to be + * used as a parameter to g_thread_pool_new() for CPU bound tasks and + * similar cases. * - * Due to thread lifetime checks, this function has an execution complexity - * which is quadratic in the number of existing threads. + * Returns: Number of schedulable threads, always greater than 0 * - * Since: 2.10 + * Since: 2.36 */ -void -g_thread_foreach (GFunc thread_func, - gpointer user_data) +guint +g_get_num_processors (void) { - GSList *slist = NULL; - GRealThread *thread; - g_return_if_fail (thread_func != NULL); - /* snapshot the list of threads for iteration */ - G_LOCK (g_thread); - for (thread = g_thread_all_threads; thread; thread = thread->next) - slist = g_slist_prepend (slist, thread); - G_UNLOCK (g_thread); - /* walk the list, skipping non-existent threads */ - while (slist) - { - GSList *node = slist; - slist = node->next; - /* check whether the current thread still exists */ - G_LOCK (g_thread); - for (thread = g_thread_all_threads; thread; thread = thread->next) - if (thread == node->data) - break; - G_UNLOCK (g_thread); - if (thread) - thread_func (thread, user_data); - g_slist_free_1 (node); - } -} - -/* GMutex {{{1 ------------------------------------------------------ */ - -/** - * g_mutex_new: - * - * Allocated and initializes a new #GMutex. - * - * Returns: a newly allocated #GMutex. Use g_mutex_free() to free - */ -GMutex * -g_mutex_new (void) -{ - GMutex *mutex; - - mutex = g_slice_new (GMutex); - g_mutex_init (mutex); - - return mutex; -} +#ifdef G_OS_WIN32 + DWORD_PTR process_cpus; + DWORD_PTR system_cpus; -/** - * g_mutex_free: - * @mutex: a #GMutex - * - * Destroys a @mutex that has been created with g_mutex_new(). - * - * Calling g_mutex_free() on a locked mutex may result - * in undefined behaviour. - */ -void -g_mutex_free (GMutex *mutex) -{ - g_mutex_clear (mutex); - g_slice_free (GMutex, mutex); -} - -/* GCond {{{1 ------------------------------------------------------ */ - -/** - * g_cond_new: - * - * Allocates and initializes a new #GCond. - * - * Returns: a newly allocated #GCond. Free with g_cond_free() - */ -GCond * -g_cond_new (void) -{ - GCond *cond; - - cond = g_slice_new (GCond); - g_cond_init (cond); - - return cond; -} - -/** - * g_cond_free: - * @cond: a #GCond - * - * Destroys a #GCond that has been created with g_cond_new(). - */ -void -g_cond_free (GCond *cond) -{ - g_cond_clear (cond); - g_slice_free (GCond, cond); -} - -/* GPrivate {{{1 ------------------------------------------------------ */ + if (GetProcessAffinityMask (GetCurrentProcess (), + &process_cpus, &system_cpus)) + { + unsigned int count; -/** - * g_private_new: - * @destructor: a function to destroy the data keyed to - * the #GPrivate when a thread ends - * - * Creates a new #GPrivate. If @destructor is non-%NULL, it is a - * pointer to a destructor function. Whenever a thread ends and the - * corresponding pointer keyed to this instance of #GPrivate is - * non-%NULL, the destructor is called with this pointer as the - * argument. - * - * - * #GStaticPrivate is a better choice for most uses. - * - * - * @destructor is used quite differently from @notify in - * g_static_private_set(). - * - * A #GPrivate cannot be freed. Reuse it instead, if you - * can, to avoid shortage, or use #GStaticPrivate. - * - * This function will abort if g_thread_init() has not been - * called yet. - * - * Returns: a newly allocated #GPrivate - */ -GPrivate * -g_private_new (GDestroyNotify notify) -{ - GPrivate *key; + for (count = 0; process_cpus != 0; process_cpus >>= 1) + if (process_cpus & 1) + count++; - key = g_slice_new (GPrivate); - g_private_init (key, notify); + if (count > 0) + return count; + } +#elif defined(_SC_NPROCESSORS_ONLN) + { + int count; + + count = sysconf (_SC_NPROCESSORS_ONLN); + if (count > 0) + return count; + } +#elif defined HW_NCPU + { + int mib[2], count = 0; + size_t len; + + mib[0] = CTL_HW; + mib[1] = HW_NCPU; + len = sizeof(count); + + if (sysctl (mib, 2, &count, &len, NULL, 0) == 0 && count > 0) + return count; + } +#endif - return key; + return 1; /* Fallback */ } - /* vim: set foldmethod=marker: */ +/* Epilogue {{{1 */ +/* vim: set foldmethod=marker: */