// Package glib was automatically generated by github.com/bnema/puregotk DO NOT EDIT package glib import ( "structs" "unsafe" "github.com/ebitengine/purego" "github.com/bnema/puregotk/pkg/core" "github.com/bnema/puregotk/v4/gobject/types" ) // Specifies the type of the @func functions passed to g_thread_new() // or g_thread_try_new(). type ThreadFunc func(uintptr) uintptr // The #GCond struct is an opaque data structure that represents a // condition. Threads can block on a #GCond if they find a certain // condition to be false. If other threads change the state of this // condition they signal the #GCond, and that causes the waiting // threads to be woken up. // // 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: // |[<!-- language="C" --> // // gpointer current_data = NULL; // GMutex data_mutex; // GCond data_cond; // // void // push_data (gpointer data) // { // g_mutex_lock (&data_mutex); // current_data = data; // g_cond_signal (&data_cond); // g_mutex_unlock (&data_mutex); // } // // gpointer // pop_data (void) // { // gpointer data; // // g_mutex_lock (&data_mutex); // while (!current_data) // g_cond_wait (&data_cond, &data_mutex); // data = current_data; // current_data = NULL; // 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(). // // 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. type Cond struct { _ structs.HostLayout P uintptr I [2]uint } func (x *Cond) GoPointer() uintptr { return uintptr(unsafe.Pointer(x)) } var xCondBroadcast func(uintptr) // If threads are waiting for @cond, all of them are unblocked. // If no threads are waiting for @cond, this function has no effect. // It is good practice to lock the same mutex as the waiting threads // while calling this function, though not required. func (x *Cond) Broadcast() { xCondBroadcast(x.GoPointer()) } var xCondClear func(uintptr) // Frees the resources allocated to a #GCond with g_cond_init(). // // This function should not be used with a #GCond that has been // statically allocated. // // Calling g_cond_clear() for a #GCond on which threads are // blocking leads to undefined behaviour. func (x *Cond) Clear() { xCondClear(x.GoPointer()) } var xCondFree func(uintptr) // Destroys a #GCond that has been created with g_cond_new(). // // Calling g_cond_free() for a #GCond on which threads are // blocking leads to undefined behaviour. func (x *Cond) Free() { xCondFree(x.GoPointer()) } var xCondInit func(uintptr) // Initialises a #GCond so that it can be used. // // This function is useful to initialise a #GCond that has been // allocated as part of a larger structure. It is not necessary to // initialise a #GCond that has been statically allocated. // // To undo the effect of g_cond_init() when a #GCond is no longer // needed, use g_cond_clear(). // // Calling g_cond_init() on an already-initialised #GCond leads // to undefined behaviour. func (x *Cond) Init() { xCondInit(x.GoPointer()) } var xCondSignal func(uintptr) // If threads are waiting for @cond, at least one of them is unblocked. // If no threads are waiting for @cond, this function has no effect. // It is good practice to hold the same lock as the waiting thread // while calling this function, though not required. func (x *Cond) Signal() { xCondSignal(x.GoPointer()) } var xCondTimedWait func(uintptr, *Mutex, *TimeVal) bool // Waits until this thread is woken up on @cond, but not longer than // until the time specified by @abs_time. The @mutex is unlocked before // falling asleep and locked again before resuming. // // If @abs_time is %NULL, g_cond_timed_wait() acts like g_cond_wait(). // // This function can be used even if g_thread_init() has not yet been // called, and, in that case, will immediately return %TRUE. // // To easily calculate @abs_time a combination of g_get_real_time() // and g_time_val_add() can be used. func (x *Cond) TimedWait(MutexVar *Mutex, AbsTimeVar *TimeVal) bool { cret := xCondTimedWait(x.GoPointer(), MutexVar, AbsTimeVar) return cret } var xCondWait func(uintptr, *Mutex) // Atomically releases @mutex and waits until @cond is signalled. // When this function returns, @mutex is locked again and owned by the // calling thread. // // When using condition variables, it is possible that a spurious wakeup // may occur (ie: g_cond_wait() returns even though g_cond_signal() was // not called). It's also possible that a stolen wakeup may occur. // This is when g_cond_signal() is called, but another thread acquires // @mutex before this thread and modifies the state of the program in // such a way that when g_cond_wait() is able to return, the expected // condition is no longer met. // // For this reason, g_cond_wait() must always be used in a loop. See // the documentation for #GCond for a complete example. func (x *Cond) Wait(MutexVar *Mutex) { xCondWait(x.GoPointer(), MutexVar) } var xCondWaitUntil func(uintptr, *Mutex, int64) bool // Waits until either @cond is signalled or @end_time has passed. // // As with g_cond_wait() it is possible that a spurious or stolen wakeup // could occur. For that reason, waiting on a condition variable should // always be in a loop, based on an explicitly-checked predicate. // // %TRUE is returned if the condition variable was signalled (or in the // case of a spurious wakeup). %FALSE is returned if @end_time has // passed. // // The following code shows how to correctly perform a timed wait on a // condition variable (extending the example presented in the // documentation for #GCond): // // |[<!-- language="C" --> // gpointer // pop_data_timed (void) // // { // gint64 end_time; // gpointer data; // // g_mutex_lock (&data_mutex); // // end_time = g_get_monotonic_time () + 5 * G_TIME_SPAN_SECOND; // while (!current_data) // if (!g_cond_wait_until (&data_cond, &data_mutex, end_time)) // { // // timeout has passed. // g_mutex_unlock (&data_mutex); // return NULL; // } // // // there is data for us // data = current_data; // current_data = NULL; // // g_mutex_unlock (&data_mutex); // // return data; // } // // ]| // // Notice that the end time is calculated once, before entering the // loop and reused. This is the motivation behind the use of absolute // time on this API -- if a relative time of 5 seconds were passed // directly to the call and a spurious wakeup occurred, the program would // have to start over waiting again (which would lead to a total wait // time of more than 5 seconds). func (x *Cond) WaitUntil(MutexVar *Mutex, EndTimeVar int64) bool { cret := xCondWaitUntil(x.GoPointer(), MutexVar, EndTimeVar) return cret } // A #GOnce struct controls a one-time initialization function. Any // one-time initialization function must have its own unique #GOnce // struct. type Once struct { _ structs.HostLayout Status OnceStatus Retval uintptr } func (x *Once) GoPointer() uintptr { return uintptr(unsafe.Pointer(x)) } var xOnceImpl func(uintptr, uintptr, uintptr) uintptr func (x *Once) Impl(FuncVar *ThreadFunc, ArgVar uintptr) uintptr { var FuncVarRef uintptr if FuncVar != nil { FuncVarPtr := uintptr(unsafe.Pointer(FuncVar)) if cbRefPtr, ok := GetCallback(FuncVarPtr); ok { FuncVarRef = cbRefPtr } else { fcb := func(arg0 uintptr) uintptr { cbFn := *FuncVar return cbFn(arg0) } FuncVarRef = purego.NewCallback(fcb) SaveCallbackWithClosure(FuncVarPtr, FuncVarRef, FuncVar) } } cret := xOnceImpl(x.GoPointer(), FuncVarRef, ArgVar) return cret } // The #GPrivate struct is an opaque data structure to represent a // thread-local data key. It is approximately equivalent to the // pthread_setspecific()/pthread_getspecific() APIs on POSIX and to // TlsSetValue()/TlsGetValue() on Windows. // // If you don't already know why you might want this functionality, // then you probably don't need it. // // #GPrivate is a very limited resource (as far as 128 per program, // shared between all libraries). It is also not possible to destroy a // #GPrivate after it has been used. As such, it is only ever acceptable // to use #GPrivate in static scope, and even then sparingly so. // // See G_PRIVATE_INIT() for a couple of examples. // // The #GPrivate structure should be considered opaque. It should only // be accessed via the g_private_ functions. type Private struct { _ structs.HostLayout P uintptr Notify DestroyNotify Future [2]uintptr } func (x *Private) GoPointer() uintptr { return uintptr(unsafe.Pointer(x)) } var xPrivateGet func(uintptr) uintptr // Returns the current value of the thread local variable @key. // // If the value has not yet been set in this thread, %NULL is returned. // Values are never copied between threads (when a new thread is // created, for example). func (x *Private) Get() uintptr { cret := xPrivateGet(x.GoPointer()) return cret } var xPrivateReplace func(uintptr, uintptr) // Sets the thread local variable @key to have the value @value in the // current thread. // // This function differs from g_private_set() in the following way: if // the previous value was non-%NULL then the #GDestroyNotify handler for // @key is run on it. func (x *Private) Replace(ValueVar uintptr) { xPrivateReplace(x.GoPointer(), ValueVar) } var xPrivateSet func(uintptr, uintptr) // Sets the thread local variable @key to have the value @value in the // current thread. // // This function differs from g_private_replace() in the following way: // the #GDestroyNotify for @key is not called on the old value. func (x *Private) Set(ValueVar uintptr) { xPrivateSet(x.GoPointer(), ValueVar) } // The GRWLock struct is an opaque data structure to represent a // reader-writer lock. It is similar to a #GMutex in that it allows // multiple threads to coordinate access to a shared resource. // // The difference to a mutex is that a reader-writer lock discriminates // between read-only ('reader') and full ('writer') access. While only // one thread at a time is allowed write access (by holding the 'writer' // lock via g_rw_lock_writer_lock()), multiple threads can gain // simultaneous read-only access (by holding the 'reader' lock via // g_rw_lock_reader_lock()). // // It is unspecified whether readers or writers have priority in acquiring the // lock when a reader already holds the lock and a writer is queued to acquire // it. // // Here is an example for an array with access functions: // |[<!-- language="C" --> // // GRWLock lock; // GPtrArray *array; // // gpointer // my_array_get (guint index) // { // gpointer retval = NULL; // // if (!array) // return NULL; // // g_rw_lock_reader_lock (&lock); // if (index < array->len) // retval = g_ptr_array_index (array, index); // g_rw_lock_reader_unlock (&lock); // // return retval; // } // // void // my_array_set (guint index, gpointer data) // { // g_rw_lock_writer_lock (&lock); // // if (!array) // 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); // } // ]| // // 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. // // 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. // // A GRWLock should only be accessed with the g_rw_lock_ functions. type RWLock struct { _ structs.HostLayout P uintptr I [2]uint } func (x *RWLock) GoPointer() uintptr { return uintptr(unsafe.Pointer(x)) } var xRWLockClear func(uintptr) // Frees the resources allocated to a lock with g_rw_lock_init(). // // This function should not be used with a #GRWLock that has been // statically allocated. // // Calling g_rw_lock_clear() when any thread holds the lock // leads to undefined behaviour. func (x *RWLock) Clear() { xRWLockClear(x.GoPointer()) } var xRWLockInit func(uintptr) // Initializes a #GRWLock so that it can be used. // // This function is useful to initialize a lock that has been // allocated on the stack, or as part of a larger structure. It is not // necessary to initialise a reader-writer lock that has been statically // allocated. // // |[<!-- language="C" --> // // typedef struct { // GRWLock l; // ... // } Blob; // // Blob *b; // // b = g_new (Blob, 1); // g_rw_lock_init (&b->l); // ]| // // To undo the effect of g_rw_lock_init() when a lock is no longer // needed, use g_rw_lock_clear(). // // Calling g_rw_lock_init() on an already initialized #GRWLock leads // to undefined behaviour. func (x *RWLock) Init() { xRWLockInit(x.GoPointer()) } var xRWLockReaderLock func(uintptr) // Obtain a read lock on @rw_lock. If another thread currently holds // the write lock on @rw_lock, the current thread will block until the // write lock was (held and) released. If another thread does not hold // the write lock, but is waiting for it, it is implementation defined // whether the reader or writer will block. Read locks can be taken // recursively. // // Calling g_rw_lock_reader_lock() while the current thread already // owns a write lock leads to undefined behaviour. Read locks however // can be taken recursively, in which case you need to make sure to // call g_rw_lock_reader_unlock() the same amount of times. // // It is implementation-defined how many read locks are allowed to be // held on the same lock simultaneously. If the limit is hit, // or if a deadlock is detected, a critical warning will be emitted. func (x *RWLock) ReaderLock() { xRWLockReaderLock(x.GoPointer()) } var xRWLockReaderTrylock func(uintptr) bool // Tries to obtain a read lock on @rw_lock and returns %TRUE if // the read lock was successfully obtained. Otherwise it // returns %FALSE. func (x *RWLock) ReaderTrylock() bool { cret := xRWLockReaderTrylock(x.GoPointer()) return cret } var xRWLockReaderUnlock func(uintptr) // Release a read lock on @rw_lock. // // Calling g_rw_lock_reader_unlock() on a lock that is not held // by the current thread leads to undefined behaviour. func (x *RWLock) ReaderUnlock() { xRWLockReaderUnlock(x.GoPointer()) } var xRWLockWriterLock func(uintptr) // Obtain a write lock on @rw_lock. If another thread currently holds // a read or write lock on @rw_lock, the current thread will block // until all other threads have dropped their locks on @rw_lock. // // Calling g_rw_lock_writer_lock() while the current thread already // owns a read or write lock on @rw_lock leads to undefined behaviour. func (x *RWLock) WriterLock() { xRWLockWriterLock(x.GoPointer()) } var xRWLockWriterTrylock func(uintptr) bool // Tries to obtain a write lock on @rw_lock. If another thread // currently holds a read or write lock on @rw_lock, it immediately // returns %FALSE. // Otherwise it locks @rw_lock and returns %TRUE. func (x *RWLock) WriterTrylock() bool { cret := xRWLockWriterTrylock(x.GoPointer()) return cret } var xRWLockWriterUnlock func(uintptr) // Release a write lock on @rw_lock. // // Calling g_rw_lock_writer_unlock() on a lock that is not held // by the current thread leads to undefined behaviour. func (x *RWLock) WriterUnlock() { xRWLockWriterUnlock(x.GoPointer()) } // The GRecMutex struct is an opaque data structure to represent a // recursive mutex. It is similar to a #GMutex with the difference // that it is possible to lock a GRecMutex multiple times in the same // thread without deadlock. When doing so, care has to be taken to // unlock the recursive mutex as often as it has been locked. // // 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. // // A GRecMutex should only be accessed with the // g_rec_mutex_ functions. type RecMutex struct { _ structs.HostLayout P uintptr I [2]uint } func (x *RecMutex) GoPointer() uintptr { return uintptr(unsafe.Pointer(x)) } var xRecMutexClear func(uintptr) // Frees the resources allocated to a recursive mutex with // g_rec_mutex_init(). // // This function should not be used with a #GRecMutex that has been // statically allocated. // // Calling g_rec_mutex_clear() on a locked recursive mutex leads // to undefined behaviour. func (x *RecMutex) Clear() { xRecMutexClear(x.GoPointer()) } var xRecMutexInit func(uintptr) // Initializes a #GRecMutex so that it can be used. // // This function is useful to initialize a recursive mutex // that has been allocated on the stack, or as part of a larger // structure. // // It is not necessary to initialise a recursive mutex that has been // statically allocated. // // |[<!-- language="C" --> // // typedef struct { // GRecMutex m; // ... // } Blob; // // Blob *b; // // b = g_new (Blob, 1); // g_rec_mutex_init (&b->m); // ]| // // Calling g_rec_mutex_init() on an already initialized #GRecMutex // leads to undefined behaviour. // // To undo the effect of g_rec_mutex_init() when a recursive mutex // is no longer needed, use g_rec_mutex_clear(). func (x *RecMutex) Init() { xRecMutexInit(x.GoPointer()) } var xRecMutexLock func(uintptr) // Locks @rec_mutex. If @rec_mutex is already locked by another // thread, the current thread will block until @rec_mutex is // unlocked by the other thread. If @rec_mutex is already locked // by the current thread, the 'lock count' of @rec_mutex is increased. // The mutex will only become available again when it is unlocked // as many times as it has been locked. func (x *RecMutex) Lock() { xRecMutexLock(x.GoPointer()) } var xRecMutexTrylock func(uintptr) bool // Tries to lock @rec_mutex. If @rec_mutex is already locked // by another thread, it immediately returns %FALSE. Otherwise // it locks @rec_mutex and returns %TRUE. func (x *RecMutex) Trylock() bool { cret := xRecMutexTrylock(x.GoPointer()) return cret } var xRecMutexUnlock func(uintptr) // Unlocks @rec_mutex. If another thread is blocked in a // g_rec_mutex_lock() call for @rec_mutex, it will become unblocked // and can lock @rec_mutex itself. // // Calling g_rec_mutex_unlock() on a recursive mutex that is not // locked by the current thread leads to undefined behaviour. func (x *RecMutex) Unlock() { xRecMutexUnlock(x.GoPointer()) } // A #GStaticMutex works like a #GMutex. // // Prior to GLib 2.32, GStaticMutex had the significant advantage // that it doesn't need to be created at run-time, but can be defined // at compile-time. Since 2.32, #GMutex can be statically allocated // as well, and GStaticMutex has been deprecated. // // Here is a version of our give_me_next_number() example using // a GStaticMutex: // |[ // // int // give_me_next_number (void) // { // static int current_number = 0; // int ret_val; // static GStaticMutex mutex = G_STATIC_MUTEX_INIT; // // g_static_mutex_lock (&mutex); // ret_val = current_number = calc_next_number (current_number); // g_static_mutex_unlock (&mutex); // // return ret_val; // } // // ]| // // Sometimes you would like to dynamically create a mutex. If you don't // want to require prior calling to g_thread_init(), because your code // should also be usable in non-threaded programs, you are not able to // use g_mutex_new() and thus #GMutex, as that requires a prior call to // g_thread_init(). In these cases you can also use a #GStaticMutex. // It must be initialized with g_static_mutex_init() before using it // and freed with with g_static_mutex_free() when not needed anymore to // free up any allocated resources. // // Even though #GStaticMutex is not opaque, it should only be used with // the following functions, as it is defined differently on different // platforms. // // All of the g_static_mutex_* functions apart from // g_static_mutex_get_mutex() can also be used even if g_thread_init() // has not yet been called. Then they do nothing, apart from // g_static_mutex_trylock() which does nothing but returning %TRUE. // // All of the g_static_mutex_* functions are actually macros. Apart from // taking their addresses, you can however use them as if they were // functions. type StaticMutex struct { _ structs.HostLayout Mutex *Mutex } func (x *StaticMutex) GoPointer() uintptr { return uintptr(unsafe.Pointer(x)) } var xStaticMutexFree func(uintptr) // Releases all resources allocated to @mutex. // // You don't have to call this functions for a #GStaticMutex with an // unbounded lifetime, i.e. objects declared 'static', but if you have // a #GStaticMutex as a member of a structure and the structure is // freed, you should also free the #GStaticMutex. // // Calling g_static_mutex_free() on a locked mutex may result in // undefined behaviour. func (x *StaticMutex) Free() { xStaticMutexFree(x.GoPointer()) } var xStaticMutexGetMutexImpl func(uintptr) *Mutex func (x *StaticMutex) GetMutexImpl() *Mutex { cret := xStaticMutexGetMutexImpl(x.GoPointer()) return cret } var xStaticMutexInit func(uintptr) // Initializes @mutex. // Alternatively you can initialize it with %G_STATIC_MUTEX_INIT. func (x *StaticMutex) Init() { xStaticMutexInit(x.GoPointer()) } // 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: // |[ // // 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; // } // // ]| type StaticPrivate struct { _ structs.HostLayout Index uint } func (x *StaticPrivate) GoPointer() uintptr { return uintptr(unsafe.Pointer(x)) } var xStaticPrivateFree func(uintptr) // Releases all resources allocated to @private_key. // // 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. func (x *StaticPrivate) Free() { xStaticPrivateFree(x.GoPointer()) } var xStaticPrivateGet func(uintptr) uintptr // Works like g_private_get() only for a #GStaticPrivate. // // This function works even if g_thread_init() has not yet been called. func (x *StaticPrivate) Get() uintptr { cret := xStaticPrivateGet(x.GoPointer()) return cret } var xStaticPrivateInit func(uintptr) // Initializes @private_key. Alternatively you can initialize it with // %G_STATIC_PRIVATE_INIT. func (x *StaticPrivate) Init() { xStaticPrivateInit(x.GoPointer()) } var xStaticPrivateSet func(uintptr, uintptr, uintptr) // 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(). func (x *StaticPrivate) Set(DataVar uintptr, NotifyVar *DestroyNotify) { var NotifyVarRef uintptr if NotifyVar != nil { NotifyVarPtr := uintptr(unsafe.Pointer(NotifyVar)) if cbRefPtr, ok := GetCallback(NotifyVarPtr); ok { NotifyVarRef = cbRefPtr } else { fcb := func(arg0 uintptr) { cbFn := *NotifyVar cbFn(arg0) } NotifyVarRef = purego.NewCallback(fcb) SaveCallbackWithClosure(NotifyVarPtr, NotifyVarRef, NotifyVar) } } xStaticPrivateSet(x.GoPointer(), DataVar, NotifyVarRef) } // The #GStaticRWLock struct represents a read-write lock. A read-write // lock can be used for protecting data that some portions of code only // read from, while others also write. In such situations it is // desirable that several readers can read at once, whereas of course // only one writer may write at a time. // // Take a look at the following example: // |[ // // GStaticRWLock rwlock = G_STATIC_RW_LOCK_INIT; // GPtrArray *array; // // gpointer // my_array_get (guint index) // { // gpointer retval = NULL; // // if (!array) // return NULL; // // g_static_rw_lock_reader_lock (&rwlock); // if (index < array->len) // retval = g_ptr_array_index (array, index); // g_static_rw_lock_reader_unlock (&rwlock); // // return retval; // } // // void // my_array_set (guint index, gpointer data) // { // g_static_rw_lock_writer_lock (&rwlock); // // if (!array) // 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_static_rw_lock_writer_unlock (&rwlock); // } // // ]| // // 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. // // Most of the time, writers should have precedence over readers. That // means, for this implementation, that as soon as a writer wants to // lock the data, no other reader is allowed to lock the data, whereas, // of course, the readers that already have locked the data are allowed // to finish their operation. As soon as the last reader unlocks the // data, the writer will lock it. // // Even though #GStaticRWLock is not opaque, it should only be used // with the following functions. // // All of the g_static_rw_lock_* functions can be used even if // g_thread_init() has not been called. Then they do nothing, apart // from g_static_rw_lock_*_trylock, which does nothing but returning %TRUE. // // A read-write lock has a higher overhead than a mutex. For example, both // g_static_rw_lock_reader_lock() and g_static_rw_lock_reader_unlock() have // to lock and unlock a #GStaticMutex, so it takes at least twice the time // to lock and unlock a #GStaticRWLock that it does to lock and unlock a // #GStaticMutex. So only data structures that are accessed by multiple // readers, and which keep the lock for a considerable time justify a // #GStaticRWLock. The above example most probably would fare better with a // #GStaticMutex. type StaticRWLock struct { _ structs.HostLayout Mutex uintptr ReadCond *Cond WriteCond *Cond ReadCounter uint HaveWriter bool WantToRead uint WantToWrite uint } func (x *StaticRWLock) GoPointer() uintptr { return uintptr(unsafe.Pointer(x)) } var xStaticRWLockFree func(uintptr) // Releases all resources allocated to @lock. // // You don't have to call this functions for a #GStaticRWLock with an // unbounded lifetime, i.e. objects declared 'static', but if you have // a #GStaticRWLock as a member of a structure, and the structure is // freed, you should also free the #GStaticRWLock. func (x *StaticRWLock) Free() { xStaticRWLockFree(x.GoPointer()) } var xStaticRWLockInit func(uintptr) // A #GStaticRWLock must be initialized with this function before it // can be used. Alternatively you can initialize it with // %G_STATIC_RW_LOCK_INIT. func (x *StaticRWLock) Init() { xStaticRWLockInit(x.GoPointer()) } var xStaticRWLockReaderLock func(uintptr) // Locks @lock for reading. There may be unlimited concurrent locks for // reading of a #GStaticRWLock at the same time. If @lock is already // locked for writing by another thread or if another thread is already // waiting to lock @lock for writing, this function will block until // @lock is unlocked by the other writing thread and no other writing // threads want to lock @lock. This lock has to be unlocked by // g_static_rw_lock_reader_unlock(). // // #GStaticRWLock is not recursive. It might seem to be possible to // recursively lock for reading, but that can result in a deadlock, due // to writer preference. func (x *StaticRWLock) ReaderLock() { xStaticRWLockReaderLock(x.GoPointer()) } var xStaticRWLockReaderTrylock func(uintptr) bool // Tries to lock @lock for reading. If @lock is already locked for // writing by another thread or if another thread is already waiting to // lock @lock for writing, immediately returns %FALSE. Otherwise locks // @lock for reading and returns %TRUE. This lock has to be unlocked by // g_static_rw_lock_reader_unlock(). func (x *StaticRWLock) ReaderTrylock() bool { cret := xStaticRWLockReaderTrylock(x.GoPointer()) return cret } var xStaticRWLockReaderUnlock func(uintptr) // Unlocks @lock. If a thread waits to lock @lock for writing and all // locks for reading have been unlocked, the waiting thread is woken up // and can lock @lock for writing. func (x *StaticRWLock) ReaderUnlock() { xStaticRWLockReaderUnlock(x.GoPointer()) } var xStaticRWLockWriterLock func(uintptr) // Locks @lock for writing. If @lock is already locked for writing or // reading by other threads, this function will block until @lock is // completely unlocked and then lock @lock for writing. While this // functions waits to lock @lock, no other thread can lock @lock for // reading. When @lock is locked for writing, no other thread can lock // @lock (neither for reading nor writing). This lock has to be // unlocked by g_static_rw_lock_writer_unlock(). func (x *StaticRWLock) WriterLock() { xStaticRWLockWriterLock(x.GoPointer()) } var xStaticRWLockWriterTrylock func(uintptr) bool // Tries to lock @lock for writing. If @lock is already locked (for // either reading or writing) by another thread, it immediately returns // %FALSE. Otherwise it locks @lock for writing and returns %TRUE. This // lock has to be unlocked by g_static_rw_lock_writer_unlock(). func (x *StaticRWLock) WriterTrylock() bool { cret := xStaticRWLockWriterTrylock(x.GoPointer()) return cret } var xStaticRWLockWriterUnlock func(uintptr) // Unlocks @lock. If a thread is waiting to lock @lock for writing and // all locks for reading have been unlocked, the waiting thread is // woken up and can lock @lock for writing. If no thread is waiting to // lock @lock for writing, and some thread or threads are waiting to // lock @lock for reading, the waiting threads are woken up and can // lock @lock for reading. func (x *StaticRWLock) WriterUnlock() { xStaticRWLockWriterUnlock(x.GoPointer()) } // A #GStaticRecMutex works like a #GStaticMutex, but it can be locked // multiple times by one thread. If you enter it n times, you have to // unlock it n times again to let other threads lock it. An exception // is the function g_static_rec_mutex_unlock_full(): that allows you to // unlock a #GStaticRecMutex completely returning the depth, (i.e. the // number of times this mutex was locked). The depth can later be used // to restore the state of the #GStaticRecMutex by calling // g_static_rec_mutex_lock_full(). In GLib 2.32, #GStaticRecMutex has // been deprecated in favor of #GRecMutex. // // Even though #GStaticRecMutex is not opaque, it should only be used // with the following functions. // // All of the g_static_rec_mutex_* functions can be used even if // g_thread_init() has not been called. Then they do nothing, apart // from g_static_rec_mutex_trylock(), which does nothing but returning // %TRUE. type StaticRecMutex struct { _ structs.HostLayout Mutex uintptr Depth uint } func (x *StaticRecMutex) GoPointer() uintptr { return uintptr(unsafe.Pointer(x)) } var xStaticRecMutexFree func(uintptr) // Releases all resources allocated to a #GStaticRecMutex. // // You don't have to call this functions for a #GStaticRecMutex with an // unbounded lifetime, i.e. objects declared 'static', but if you have // a #GStaticRecMutex as a member of a structure and the structure is // freed, you should also free the #GStaticRecMutex. func (x *StaticRecMutex) Free() { xStaticRecMutexFree(x.GoPointer()) } var xStaticRecMutexInit func(uintptr) // A #GStaticRecMutex must be initialized with this function before it // can be used. Alternatively you can initialize it with // %G_STATIC_REC_MUTEX_INIT. func (x *StaticRecMutex) Init() { xStaticRecMutexInit(x.GoPointer()) } var xStaticRecMutexLock func(uintptr) // Locks @mutex. If @mutex is already locked by another thread, the // current thread will block until @mutex is unlocked by the other // thread. If @mutex is already locked by the calling thread, this // functions increases the depth of @mutex and returns immediately. func (x *StaticRecMutex) Lock() { xStaticRecMutexLock(x.GoPointer()) } var xStaticRecMutexLockFull func(uintptr, uint) // Works like calling g_static_rec_mutex_lock() for @mutex @depth times. func (x *StaticRecMutex) LockFull(DepthVar uint) { xStaticRecMutexLockFull(x.GoPointer(), DepthVar) } var xStaticRecMutexTrylock func(uintptr) bool // Tries to lock @mutex. If @mutex is already locked by another thread, // it immediately returns %FALSE. Otherwise it locks @mutex and returns // %TRUE. If @mutex is already locked by the calling thread, this // functions increases the depth of @mutex and immediately returns // %TRUE. func (x *StaticRecMutex) Trylock() bool { cret := xStaticRecMutexTrylock(x.GoPointer()) return cret } var xStaticRecMutexUnlock func(uintptr) // Unlocks @mutex. Another thread will be allowed to lock @mutex only // when it has been unlocked as many times as it had been locked // before. If @mutex is completely unlocked and another thread is // blocked in a g_static_rec_mutex_lock() call for @mutex, it will be // woken and can lock @mutex itself. func (x *StaticRecMutex) Unlock() { xStaticRecMutexUnlock(x.GoPointer()) } var xStaticRecMutexUnlockFull func(uintptr) uint // Completely unlocks @mutex. If another thread is blocked in a // g_static_rec_mutex_lock() call for @mutex, it will be woken and can // lock @mutex itself. This function returns the number of times that // @mutex has been locked by the current thread. To restore the state // before the call to g_static_rec_mutex_unlock_full() you can call // g_static_rec_mutex_lock_full() with the depth returned by this // function. func (x *StaticRecMutex) UnlockFull() uint { cret := xStaticRecMutexUnlockFull(x.GoPointer()) return cret } // 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. // // The structure is opaque -- none of its fields may be directly // accessed. type Thread struct { _ structs.HostLayout Func ThreadFunc Data uintptr Joinable bool Priority ThreadPriority } var xThreadGLibType func() types.GType func ThreadGLibType() types.GType { return xThreadGLibType() } func (x *Thread) GoPointer() uintptr { return uintptr(unsafe.Pointer(x)) } var xNewThread func(uintptr, uintptr, uintptr) *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(). // // 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. // // If the thread can not be created the program aborts. See // g_thread_try_new() if you want to attempt to deal with failures. // // If you are using threads to offload (potentially many) short-lived tasks, // #GThreadPool may be more appropriate than manually spawning and tracking // multiple #GThreads. // // To free the struct returned by this function, use g_thread_unref(). // Note that g_thread_join() implicitly unrefs the #GThread as well. // // New threads by default inherit their scheduler policy (POSIX) or thread // priority (Windows) of the thread creating the new thread. // // This behaviour changed in GLib 2.64: before threads on Windows were not // inheriting the thread priority but were spawned with the default priority. // Starting with GLib 2.64 the behaviour is now consistent between Windows and // POSIX and all threads inherit their parent thread's priority. func NewThread(NameVar *string, FuncVar *ThreadFunc, DataVar uintptr) *Thread { var FuncVarRef uintptr if FuncVar != nil { FuncVarPtr := uintptr(unsafe.Pointer(FuncVar)) if cbRefPtr, ok := GetCallback(FuncVarPtr); ok { FuncVarRef = cbRefPtr } else { fcb := func(arg0 uintptr) uintptr { cbFn := *FuncVar return cbFn(arg0) } FuncVarRef = purego.NewCallback(fcb) SaveCallbackWithClosure(FuncVarPtr, FuncVarRef, FuncVar) } } NameVarPtr := core.GStrdupNullable(NameVar) defer core.GFreeNullable(NameVarPtr) cret := xNewThread(NameVarPtr, FuncVarRef, DataVar) return cret } var xThreadTryNew func(uintptr, uintptr, uintptr, **Error) *Thread // This function is the same as g_thread_new() except that // it allows for the possibility of failure. // // If a thread can not be created (due to resource limits), // @error is set and %NULL is returned. func ThreadTryNew(NameVar *string, FuncVar *ThreadFunc, DataVar uintptr) (*Thread, error) { var cerr *Error var FuncVarRef uintptr if FuncVar != nil { FuncVarPtr := uintptr(unsafe.Pointer(FuncVar)) if cbRefPtr, ok := GetCallback(FuncVarPtr); ok { FuncVarRef = cbRefPtr } else { fcb := func(arg0 uintptr) uintptr { cbFn := *FuncVar return cbFn(arg0) } FuncVarRef = purego.NewCallback(fcb) SaveCallbackWithClosure(FuncVarPtr, FuncVarRef, FuncVar) } } NameVarPtr := core.GStrdupNullable(NameVar) defer core.GFreeNullable(NameVarPtr) cret := xThreadTryNew(NameVarPtr, FuncVarRef, DataVar, &cerr) if cerr == nil { return cret, nil } return cret, cerr } var xThreadGetName func(uintptr) string // Gets the name of the thread. // // This function is intended for debugging purposes. func (x *Thread) GetName() string { cret := xThreadGetName(x.GoPointer()) return cret } var xThreadJoin func(uintptr) uintptr // 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. // // 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. func (x *Thread) Join() uintptr { cret := xThreadJoin(x.GoPointer()) return cret } var xThreadRef func(uintptr) *Thread // Increase the reference count on @thread. func (x *Thread) Ref() *Thread { cret := xThreadRef(x.GoPointer()) return cret } var xThreadSetPriority func(uintptr, ThreadPriority) // This function does nothing. func (x *Thread) SetPriority(PriorityVar ThreadPriority) { xThreadSetPriority(x.GoPointer(), PriorityVar) } var xThreadUnref func(uintptr) // Decrease the reference count on @thread, possibly freeing all // resources associated with it. // // 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. func (x *Thread) Unref() { xThreadUnref(x.GoPointer()) } // This function table is no longer used by g_thread_init() // to initialize the thread system. type ThreadFunctions struct { _ structs.HostLayout xMutexNew uintptr xMutexLock uintptr xMutexTrylock uintptr xMutexUnlock uintptr xMutexFree uintptr xCondNew uintptr xCondSignal uintptr xCondBroadcast uintptr xCondWait uintptr xCondTimedWait uintptr xCondFree uintptr xPrivateNew uintptr xPrivateGet uintptr xPrivateSet uintptr xThreadCreate uintptr xThreadYield uintptr xThreadJoin uintptr xThreadExit uintptr xThreadSetPriority uintptr xThreadSelf uintptr xThreadEqual uintptr } func (x *ThreadFunctions) GoPointer() uintptr { return uintptr(unsafe.Pointer(x)) } // OverrideMutexNew sets the "mutex_new" callback function. // virtual function pointer for g_mutex_new() func (x *ThreadFunctions) OverrideMutexNew(cb func() *Mutex) { if cb == nil { x.xMutexNew = 0 } else { x.xMutexNew = purego.NewCallback(func() *Mutex { return cb() }) } } // GetMutexNew gets the "mutex_new" callback function. // virtual function pointer for g_mutex_new() func (x *ThreadFunctions) GetMutexNew() func() *Mutex { if x.xMutexNew == 0 { return nil } var rawCallback func() *Mutex purego.RegisterFunc(&rawCallback, x.xMutexNew) return func() *Mutex { return rawCallback() } } // OverrideMutexLock sets the "mutex_lock" callback function. // virtual function pointer for g_mutex_lock() func (x *ThreadFunctions) OverrideMutexLock(cb func(*Mutex)) { if cb == nil { x.xMutexLock = 0 } else { x.xMutexLock = purego.NewCallback(func(MutexVarp *Mutex) { cb(MutexVarp) }) } } // GetMutexLock gets the "mutex_lock" callback function. // virtual function pointer for g_mutex_lock() func (x *ThreadFunctions) GetMutexLock() func(*Mutex) { if x.xMutexLock == 0 { return nil } var rawCallback func(MutexVarp *Mutex) purego.RegisterFunc(&rawCallback, x.xMutexLock) return func(MutexVar *Mutex) { rawCallback(MutexVar) } } // OverrideMutexTrylock sets the "mutex_trylock" callback function. // virtual function pointer for g_mutex_trylock() func (x *ThreadFunctions) OverrideMutexTrylock(cb func(*Mutex) bool) { if cb == nil { x.xMutexTrylock = 0 } else { x.xMutexTrylock = purego.NewCallback(func(MutexVarp *Mutex) bool { return cb(MutexVarp) }) } } // GetMutexTrylock gets the "mutex_trylock" callback function. // virtual function pointer for g_mutex_trylock() func (x *ThreadFunctions) GetMutexTrylock() func(*Mutex) bool { if x.xMutexTrylock == 0 { return nil } var rawCallback func(MutexVarp *Mutex) bool purego.RegisterFunc(&rawCallback, x.xMutexTrylock) return func(MutexVar *Mutex) bool { return rawCallback(MutexVar) } } // OverrideMutexUnlock sets the "mutex_unlock" callback function. // virtual function pointer for g_mutex_unlock() func (x *ThreadFunctions) OverrideMutexUnlock(cb func(*Mutex)) { if cb == nil { x.xMutexUnlock = 0 } else { x.xMutexUnlock = purego.NewCallback(func(MutexVarp *Mutex) { cb(MutexVarp) }) } } // GetMutexUnlock gets the "mutex_unlock" callback function. // virtual function pointer for g_mutex_unlock() func (x *ThreadFunctions) GetMutexUnlock() func(*Mutex) { if x.xMutexUnlock == 0 { return nil } var rawCallback func(MutexVarp *Mutex) purego.RegisterFunc(&rawCallback, x.xMutexUnlock) return func(MutexVar *Mutex) { rawCallback(MutexVar) } } // OverrideMutexFree sets the "mutex_free" callback function. // virtual function pointer for g_mutex_free() func (x *ThreadFunctions) OverrideMutexFree(cb func(*Mutex)) { if cb == nil { x.xMutexFree = 0 } else { x.xMutexFree = purego.NewCallback(func(MutexVarp *Mutex) { cb(MutexVarp) }) } } // GetMutexFree gets the "mutex_free" callback function. // virtual function pointer for g_mutex_free() func (x *ThreadFunctions) GetMutexFree() func(*Mutex) { if x.xMutexFree == 0 { return nil } var rawCallback func(MutexVarp *Mutex) purego.RegisterFunc(&rawCallback, x.xMutexFree) return func(MutexVar *Mutex) { rawCallback(MutexVar) } } // OverrideCondNew sets the "cond_new" callback function. // virtual function pointer for g_cond_new() func (x *ThreadFunctions) OverrideCondNew(cb func() *Cond) { if cb == nil { x.xCondNew = 0 } else { x.xCondNew = purego.NewCallback(func() *Cond { return cb() }) } } // GetCondNew gets the "cond_new" callback function. // virtual function pointer for g_cond_new() func (x *ThreadFunctions) GetCondNew() func() *Cond { if x.xCondNew == 0 { return nil } var rawCallback func() *Cond purego.RegisterFunc(&rawCallback, x.xCondNew) return func() *Cond { return rawCallback() } } // OverrideCondSignal sets the "cond_signal" callback function. // virtual function pointer for g_cond_signal() func (x *ThreadFunctions) OverrideCondSignal(cb func(*Cond)) { if cb == nil { x.xCondSignal = 0 } else { x.xCondSignal = purego.NewCallback(func(CondVarp *Cond) { cb(CondVarp) }) } } // GetCondSignal gets the "cond_signal" callback function. // virtual function pointer for g_cond_signal() func (x *ThreadFunctions) GetCondSignal() func(*Cond) { if x.xCondSignal == 0 { return nil } var rawCallback func(CondVarp *Cond) purego.RegisterFunc(&rawCallback, x.xCondSignal) return func(CondVar *Cond) { rawCallback(CondVar) } } // OverrideCondBroadcast sets the "cond_broadcast" callback function. // virtual function pointer for g_cond_broadcast() func (x *ThreadFunctions) OverrideCondBroadcast(cb func(*Cond)) { if cb == nil { x.xCondBroadcast = 0 } else { x.xCondBroadcast = purego.NewCallback(func(CondVarp *Cond) { cb(CondVarp) }) } } // GetCondBroadcast gets the "cond_broadcast" callback function. // virtual function pointer for g_cond_broadcast() func (x *ThreadFunctions) GetCondBroadcast() func(*Cond) { if x.xCondBroadcast == 0 { return nil } var rawCallback func(CondVarp *Cond) purego.RegisterFunc(&rawCallback, x.xCondBroadcast) return func(CondVar *Cond) { rawCallback(CondVar) } } // OverrideCondWait sets the "cond_wait" callback function. // virtual function pointer for g_cond_wait() func (x *ThreadFunctions) OverrideCondWait(cb func(*Cond, *Mutex)) { if cb == nil { x.xCondWait = 0 } else { x.xCondWait = purego.NewCallback(func(CondVarp *Cond, MutexVarp *Mutex) { cb(CondVarp, MutexVarp) }) } } // GetCondWait gets the "cond_wait" callback function. // virtual function pointer for g_cond_wait() func (x *ThreadFunctions) GetCondWait() func(*Cond, *Mutex) { if x.xCondWait == 0 { return nil } var rawCallback func(CondVarp *Cond, MutexVarp *Mutex) purego.RegisterFunc(&rawCallback, x.xCondWait) return func(CondVar *Cond, MutexVar *Mutex) { rawCallback(CondVar, MutexVar) } } // OverrideCondTimedWait sets the "cond_timed_wait" callback function. // virtual function pointer for g_cond_timed_wait() func (x *ThreadFunctions) OverrideCondTimedWait(cb func(*Cond, *Mutex, *TimeVal) bool) { if cb == nil { x.xCondTimedWait = 0 } else { x.xCondTimedWait = purego.NewCallback(func(CondVarp *Cond, MutexVarp *Mutex, EndTimeVarp *TimeVal) bool { return cb(CondVarp, MutexVarp, EndTimeVarp) }) } } // GetCondTimedWait gets the "cond_timed_wait" callback function. // virtual function pointer for g_cond_timed_wait() func (x *ThreadFunctions) GetCondTimedWait() func(*Cond, *Mutex, *TimeVal) bool { if x.xCondTimedWait == 0 { return nil } var rawCallback func(CondVarp *Cond, MutexVarp *Mutex, EndTimeVarp *TimeVal) bool purego.RegisterFunc(&rawCallback, x.xCondTimedWait) return func(CondVar *Cond, MutexVar *Mutex, EndTimeVar *TimeVal) bool { return rawCallback(CondVar, MutexVar, EndTimeVar) } } // OverrideCondFree sets the "cond_free" callback function. // virtual function pointer for g_cond_free() func (x *ThreadFunctions) OverrideCondFree(cb func(*Cond)) { if cb == nil { x.xCondFree = 0 } else { x.xCondFree = purego.NewCallback(func(CondVarp *Cond) { cb(CondVarp) }) } } // GetCondFree gets the "cond_free" callback function. // virtual function pointer for g_cond_free() func (x *ThreadFunctions) GetCondFree() func(*Cond) { if x.xCondFree == 0 { return nil } var rawCallback func(CondVarp *Cond) purego.RegisterFunc(&rawCallback, x.xCondFree) return func(CondVar *Cond) { rawCallback(CondVar) } } // OverridePrivateNew sets the "private_new" callback function. // virtual function pointer for g_private_new() func (x *ThreadFunctions) OverridePrivateNew(cb func(*DestroyNotify) *Private) { if cb == nil { x.xPrivateNew = 0 } else { x.xPrivateNew = purego.NewCallback(func(DestructorVarp uintptr) *Private { return cb((*DestroyNotify)(unsafe.Pointer(DestructorVarp))) }) } } // GetPrivateNew gets the "private_new" callback function. // virtual function pointer for g_private_new() func (x *ThreadFunctions) GetPrivateNew() func(*DestroyNotify) *Private { if x.xPrivateNew == 0 { return nil } var rawCallback func(DestructorVarp uintptr) *Private purego.RegisterFunc(&rawCallback, x.xPrivateNew) return func(DestructorVar *DestroyNotify) *Private { return rawCallback(NewCallback(DestructorVar)) } } // OverridePrivateGet sets the "private_get" callback function. // virtual function pointer for g_private_get() func (x *ThreadFunctions) OverridePrivateGet(cb func(*Private) uintptr) { if cb == nil { x.xPrivateGet = 0 } else { x.xPrivateGet = purego.NewCallback(func(PrivateKeyVarp *Private) uintptr { return cb(PrivateKeyVarp) }) } } // GetPrivateGet gets the "private_get" callback function. // virtual function pointer for g_private_get() func (x *ThreadFunctions) GetPrivateGet() func(*Private) uintptr { if x.xPrivateGet == 0 { return nil } var rawCallback func(PrivateKeyVarp *Private) uintptr purego.RegisterFunc(&rawCallback, x.xPrivateGet) return func(PrivateKeyVar *Private) uintptr { return rawCallback(PrivateKeyVar) } } // OverridePrivateSet sets the "private_set" callback function. // virtual function pointer for g_private_set() func (x *ThreadFunctions) OverridePrivateSet(cb func(*Private, uintptr)) { if cb == nil { x.xPrivateSet = 0 } else { x.xPrivateSet = purego.NewCallback(func(PrivateKeyVarp *Private, DataVarp uintptr) { cb(PrivateKeyVarp, DataVarp) }) } } // GetPrivateSet gets the "private_set" callback function. // virtual function pointer for g_private_set() func (x *ThreadFunctions) GetPrivateSet() func(*Private, uintptr) { if x.xPrivateSet == 0 { return nil } var rawCallback func(PrivateKeyVarp *Private, DataVarp uintptr) purego.RegisterFunc(&rawCallback, x.xPrivateSet) return func(PrivateKeyVar *Private, DataVar uintptr) { rawCallback(PrivateKeyVar, DataVar) } } // OverrideThreadCreate sets the "thread_create" callback function. // virtual function pointer for g_thread_create() func (x *ThreadFunctions) OverrideThreadCreate(cb func(*ThreadFunc, uintptr, uint, bool, bool, ThreadPriority, uintptr)) { if cb == nil { x.xThreadCreate = 0 } else { x.xThreadCreate = purego.NewCallback(func(FuncVarp uintptr, DataVarp uintptr, StackSizeVarp uint, JoinableVarp bool, BoundVarp bool, PriorityVarp ThreadPriority, ThreadVarp uintptr) { cb((*ThreadFunc)(unsafe.Pointer(FuncVarp)), DataVarp, StackSizeVarp, JoinableVarp, BoundVarp, PriorityVarp, ThreadVarp) }) } } // GetThreadCreate gets the "thread_create" callback function. // virtual function pointer for g_thread_create() func (x *ThreadFunctions) GetThreadCreate() func(*ThreadFunc, uintptr, uint, bool, bool, ThreadPriority, uintptr) { if x.xThreadCreate == 0 { return nil } var rawCallback func(FuncVarp uintptr, DataVarp uintptr, StackSizeVarp uint, JoinableVarp bool, BoundVarp bool, PriorityVarp ThreadPriority, ThreadVarp uintptr) purego.RegisterFunc(&rawCallback, x.xThreadCreate) return func(FuncVar *ThreadFunc, DataVar uintptr, StackSizeVar uint, JoinableVar bool, BoundVar bool, PriorityVar ThreadPriority, ThreadVar uintptr) { rawCallback(NewCallback(FuncVar), DataVar, StackSizeVar, JoinableVar, BoundVar, PriorityVar, ThreadVar) } } // OverrideThreadYield sets the "thread_yield" callback function. // virtual function pointer for g_thread_yield() func (x *ThreadFunctions) OverrideThreadYield(cb func()) { if cb == nil { x.xThreadYield = 0 } else { x.xThreadYield = purego.NewCallback(func() { cb() }) } } // GetThreadYield gets the "thread_yield" callback function. // virtual function pointer for g_thread_yield() func (x *ThreadFunctions) GetThreadYield() func() { if x.xThreadYield == 0 { return nil } var rawCallback func() purego.RegisterFunc(&rawCallback, x.xThreadYield) return func() { rawCallback() } } // OverrideThreadJoin sets the "thread_join" callback function. // virtual function pointer for g_thread_join() func (x *ThreadFunctions) OverrideThreadJoin(cb func(uintptr)) { if cb == nil { x.xThreadJoin = 0 } else { x.xThreadJoin = purego.NewCallback(func(ThreadVarp uintptr) { cb(ThreadVarp) }) } } // GetThreadJoin gets the "thread_join" callback function. // virtual function pointer for g_thread_join() func (x *ThreadFunctions) GetThreadJoin() func(uintptr) { if x.xThreadJoin == 0 { return nil } var rawCallback func(ThreadVarp uintptr) purego.RegisterFunc(&rawCallback, x.xThreadJoin) return func(ThreadVar uintptr) { rawCallback(ThreadVar) } } // OverrideThreadExit sets the "thread_exit" callback function. // virtual function pointer for g_thread_exit() func (x *ThreadFunctions) OverrideThreadExit(cb func()) { if cb == nil { x.xThreadExit = 0 } else { x.xThreadExit = purego.NewCallback(func() { cb() }) } } // GetThreadExit gets the "thread_exit" callback function. // virtual function pointer for g_thread_exit() func (x *ThreadFunctions) GetThreadExit() func() { if x.xThreadExit == 0 { return nil } var rawCallback func() purego.RegisterFunc(&rawCallback, x.xThreadExit) return func() { rawCallback() } } // OverrideThreadSetPriority sets the "thread_set_priority" callback function. // virtual function pointer for // // g_thread_set_priority() func (x *ThreadFunctions) OverrideThreadSetPriority(cb func(uintptr, ThreadPriority)) { if cb == nil { x.xThreadSetPriority = 0 } else { x.xThreadSetPriority = purego.NewCallback(func(ThreadVarp uintptr, PriorityVarp ThreadPriority) { cb(ThreadVarp, PriorityVarp) }) } } // GetThreadSetPriority gets the "thread_set_priority" callback function. // virtual function pointer for // // g_thread_set_priority() func (x *ThreadFunctions) GetThreadSetPriority() func(uintptr, ThreadPriority) { if x.xThreadSetPriority == 0 { return nil } var rawCallback func(ThreadVarp uintptr, PriorityVarp ThreadPriority) purego.RegisterFunc(&rawCallback, x.xThreadSetPriority) return func(ThreadVar uintptr, PriorityVar ThreadPriority) { rawCallback(ThreadVar, PriorityVar) } } // OverrideThreadSelf sets the "thread_self" callback function. // virtual function pointer for g_thread_self() func (x *ThreadFunctions) OverrideThreadSelf(cb func(uintptr)) { if cb == nil { x.xThreadSelf = 0 } else { x.xThreadSelf = purego.NewCallback(func(ThreadVarp uintptr) { cb(ThreadVarp) }) } } // GetThreadSelf gets the "thread_self" callback function. // virtual function pointer for g_thread_self() func (x *ThreadFunctions) GetThreadSelf() func(uintptr) { if x.xThreadSelf == 0 { return nil } var rawCallback func(ThreadVarp uintptr) purego.RegisterFunc(&rawCallback, x.xThreadSelf) return func(ThreadVar uintptr) { rawCallback(ThreadVar) } } // OverrideThreadEqual sets the "thread_equal" callback function. // used internally by recursive mutex locks and by some // // assertion checks func (x *ThreadFunctions) OverrideThreadEqual(cb func(uintptr, uintptr) bool) { if cb == nil { x.xThreadEqual = 0 } else { x.xThreadEqual = purego.NewCallback(func(Thread1Varp uintptr, Thread2Varp uintptr) bool { return cb(Thread1Varp, Thread2Varp) }) } } // GetThreadEqual gets the "thread_equal" callback function. // used internally by recursive mutex locks and by some // // assertion checks func (x *ThreadFunctions) GetThreadEqual() func(uintptr, uintptr) bool { if x.xThreadEqual == 0 { return nil } var rawCallback func(Thread1Varp uintptr, Thread2Varp uintptr) bool purego.RegisterFunc(&rawCallback, x.xThreadEqual) return func(Thread1Var uintptr, Thread2Var uintptr) bool { return rawCallback(Thread1Var, Thread2Var) } } // 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: // |[<!-- language="C" --> // // 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 // 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 #GMutex can be used as a solution to this problem: // |[<!-- language="C" --> // // int // give_me_next_number (void) // { // static GMutex mutex; // static int current_number = 0; // int ret_val; // // g_mutex_lock (&mutex); // ret_val = current_number = calc_next_number (current_number); // g_mutex_unlock (&mutex); // // return ret_val; // } // // ]| // 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. // // 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. type Mutex = uintptr // Opaque type. See g_mutex_locker_new() for details. type MutexLocker = uintptr // Opaque type. See g_rw_lock_reader_locker_new() for details. type RWLockReaderLocker = uintptr // Opaque type. See g_rw_lock_writer_locker_new() for details. type RWLockWriterLocker = uintptr // Opaque type. See g_rec_mutex_locker_new() for details. type RecMutexLocker = uintptr // The possible statuses of a one-time initialization function // controlled by a #GOnce struct. type OnceStatus int const ( // the function has not been called yet. GOnceStatusNotcalledValue OnceStatus = 0 // the function call is currently in progress. GOnceStatusProgressValue OnceStatus = 1 // the function has been called. GOnceStatusReadyValue OnceStatus = 2 ) // Possible errors of thread related functions. type ThreadError int const ( // a thread couldn't be created due to resource // shortage. Try again later. GThreadErrorAgainValue ThreadError = 0 ) // Thread priorities. type ThreadPriority int const ( // a priority lower than normal GThreadPriorityLowValue ThreadPriority = 0 // the default priority GThreadPriorityNormalValue ThreadPriority = 1 // a priority higher than normal GThreadPriorityHighValue ThreadPriority = 2 // the highest priority GThreadPriorityUrgentValue ThreadPriority = 3 ) var xCondNew func() *Cond // Allocates and initializes a new #GCond. func CondNew() *Cond { cret := xCondNew() return cret } var xGetNumProcessors func() uint // 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. func GetNumProcessors() uint { cret := xGetNumProcessors() return cret } var xMutexNew func() *Mutex // Allocates and initializes a new #GMutex. func MutexNew() *Mutex { cret := xMutexNew() return cret } var xOnceInitEnter func(*uintptr) bool // Function to be called when starting a critical initialization // 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 // be ensured that an initialization section will be executed only once // during a program's life time, and that concurrent threads are // blocked until initialization completed. To be used in constructs // like this: // // |[<!-- language="C" --> // // static gsize initialization_value = 0; // // if (g_once_init_enter (&initialization_value)) // { // gsize setup_value = 42; // initialization code here // // g_once_init_leave (&initialization_value, setup_value); // } // // // use initialization_value here // // ]| // // While @location has a `volatile` qualifier, this is a historical artifact and // the pointer passed to it should not be `volatile`. func OnceInitEnter(LocationVar *uintptr) bool { cret := xOnceInitEnter(LocationVar) return cret } var xOnceInitEnterImpl func(uint) bool func OnceInitEnterImpl(LocationVar uint) bool { cret := xOnceInitEnterImpl(LocationVar) return cret } var xOnceInitEnterPointer func(uintptr) bool // This functions behaves in the same way as g_once_init_enter(), but can // can be used to initialize pointers (or #guintptr) instead of #gsize. // // |[<!-- language="C" --> // // static MyStruct *interesting_struct = NULL; // // if (g_once_init_enter_pointer (&interesting_struct)) // { // MyStruct *setup_value = allocate_my_struct (); // initialization code here // // g_once_init_leave_pointer (&interesting_struct, g_steal_pointer (&setup_value)); // } // // // use interesting_struct here // // ]| func OnceInitEnterPointer(LocationVar uintptr) bool { cret := xOnceInitEnterPointer(LocationVar) return cret } var xOnceInitLeave func(*uintptr, uint) // Counterpart to g_once_init_enter(). Expects a location of a static // 0-initialized initialization variable, and an initialization value // other than 0. Sets the variable to the initialization value, and // releases concurrent threads blocking in g_once_init_enter() on this // initialization variable. // // While @location has a `volatile` qualifier, this is a historical artifact and // the pointer passed to it should not be `volatile`. func OnceInitLeave(LocationVar *uintptr, ResultVar uint) { xOnceInitLeave(LocationVar, ResultVar) } var xOnceInitLeavePointer func(uintptr, uintptr) // Counterpart to g_once_init_enter_pointer(). Expects a location of a static // `NULL`-initialized initialization variable, and an initialization value // other than `NULL`. Sets the variable to the initialization value, and // releases concurrent threads blocking in g_once_init_enter_pointer() on this // initialization variable. // // This functions behaves in the same way as g_once_init_leave(), but // can be used to initialize pointers (or #guintptr) instead of #gsize. func OnceInitLeavePointer(LocationVar uintptr, ResultVar uintptr) { xOnceInitLeavePointer(LocationVar, ResultVar) } var xPrivateNew func(uintptr) *Private // Creates a new #GPrivate. func PrivateNew(NotifyVar *DestroyNotify) *Private { var NotifyVarRef uintptr if NotifyVar != nil { NotifyVarPtr := uintptr(unsafe.Pointer(NotifyVar)) if cbRefPtr, ok := GetCallback(NotifyVarPtr); ok { NotifyVarRef = cbRefPtr } else { fcb := func(arg0 uintptr) { cbFn := *NotifyVar cbFn(arg0) } NotifyVarRef = purego.NewCallback(fcb) SaveCallbackWithClosure(NotifyVarPtr, NotifyVarRef, NotifyVar) } } cret := xPrivateNew(NotifyVarRef) return cret } var xThreadCreate func(uintptr, uintptr, bool, **Error) *Thread // This function creates a new thread. // // The new thread executes the function @func with the argument @data. // If the thread was created successfully, it is returned. // // @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 returns a reference to the created thread only if // @joinable is %TRUE. In that case, you must free this reference by // calling g_thread_unref() or g_thread_join(). If @joinable is %FALSE // then you should probably not touch the return value. func ThreadCreate(FuncVar *ThreadFunc, DataVar uintptr, JoinableVar bool) (*Thread, error) { var cerr *Error var FuncVarRef uintptr if FuncVar != nil { FuncVarPtr := uintptr(unsafe.Pointer(FuncVar)) if cbRefPtr, ok := GetCallback(FuncVarPtr); ok { FuncVarRef = cbRefPtr } else { fcb := func(arg0 uintptr) uintptr { cbFn := *FuncVar return cbFn(arg0) } FuncVarRef = purego.NewCallback(fcb) SaveCallbackWithClosure(FuncVarPtr, FuncVarRef, FuncVar) } } cret := xThreadCreate(FuncVarRef, DataVar, JoinableVar, &cerr) if cerr == nil { return cret, nil } return cret, cerr } var xThreadCreateFull func(uintptr, uintptr, uint, bool, bool, ThreadPriority, **Error) *Thread // This function creates a new thread. func ThreadCreateFull(FuncVar *ThreadFunc, DataVar uintptr, StackSizeVar uint, JoinableVar bool, BoundVar bool, PriorityVar ThreadPriority) (*Thread, error) { var cerr *Error var FuncVarRef uintptr if FuncVar != nil { FuncVarPtr := uintptr(unsafe.Pointer(FuncVar)) if cbRefPtr, ok := GetCallback(FuncVarPtr); ok { FuncVarRef = cbRefPtr } else { fcb := func(arg0 uintptr) uintptr { cbFn := *FuncVar return cbFn(arg0) } FuncVarRef = purego.NewCallback(fcb) SaveCallbackWithClosure(FuncVarPtr, FuncVarRef, FuncVar) } } cret := xThreadCreateFull(FuncVarRef, DataVar, StackSizeVar, JoinableVar, BoundVar, PriorityVar, &cerr) if cerr == nil { return cret, nil } return cret, cerr } var xThreadExit func(uintptr) // Terminates the current thread. // // 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(). // // Calling g_thread_exit() with a parameter @retval is equivalent to // returning @retval from the function @func, as given to g_thread_new(). // // 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. func ThreadExit(RetvalVar uintptr) { xThreadExit(RetvalVar) } var xThreadForeach func(uintptr, uintptr) // Call @thread_func on all #GThreads that have been // created with g_thread_create(). // // 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. // // Due to thread lifetime checks, this function has an execution complexity // which is quadratic in the number of existing threads. func ThreadForeach(ThreadFuncVar *Func, UserDataVar uintptr) { var ThreadFuncVarRef uintptr if ThreadFuncVar != nil { ThreadFuncVarPtr := uintptr(unsafe.Pointer(ThreadFuncVar)) if cbRefPtr, ok := GetCallback(ThreadFuncVarPtr); ok { ThreadFuncVarRef = cbRefPtr } else { fcb := func(arg0 uintptr, arg1 uintptr) { cbFn := *ThreadFuncVar cbFn(arg0, arg1) } ThreadFuncVarRef = purego.NewCallback(fcb) SaveCallbackWithClosure(ThreadFuncVarPtr, ThreadFuncVarRef, ThreadFuncVar) } } xThreadForeach(ThreadFuncVarRef, UserDataVar) } var xThreadGetInitialized func() bool // Indicates if g_thread_init() has been called. func ThreadGetInitialized() bool { cret := xThreadGetInitialized() return cret } var xThreadInit func(uintptr) // 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. // // ::: note // // 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(). // // ::: note // // 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. func ThreadInit(VtableVar uintptr) { xThreadInit(VtableVar) } var xThreadInitWithErrorcheckMutexes func(uintptr) func ThreadInitWithErrorcheckMutexes(VtableVar uintptr) { xThreadInitWithErrorcheckMutexes(VtableVar) } var xThreadSelf func() *Thread // This function 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. func ThreadSelf() *Thread { cret := xThreadSelf() return cret } var xThreadYield func() // Causes the calling thread to voluntarily relinquish the CPU, so // that other threads can run. // // This function is often used as a method to make busy wait less evil. func ThreadYield() { xThreadYield() } func init() { core.SetPackageName("GLIB", "glib-2.0") core.SetSharedLibraries("GLIB", []string{"libgobject-2.0.so.0", "libglib-2.0.so.0"}) var libs []uintptr for _, libPath := range core.GetPaths("GLIB") { lib, err := purego.Dlopen(libPath, purego.RTLD_NOW|purego.RTLD_GLOBAL) if err != nil { panic(err) } libs = append(libs, lib) } core.PuregoSafeRegister(&xCondNew, libs, "g_cond_new") core.PuregoSafeRegister(&xGetNumProcessors, libs, "g_get_num_processors") core.PuregoSafeRegister(&xMutexNew, libs, "g_mutex_new") core.PuregoSafeRegister(&xOnceInitEnter, libs, "g_once_init_enter") core.PuregoSafeRegister(&xOnceInitEnterImpl, libs, "g_once_init_enter_impl") core.PuregoSafeRegister(&xOnceInitEnterPointer, libs, "g_once_init_enter_pointer") core.PuregoSafeRegister(&xOnceInitLeave, libs, "g_once_init_leave") core.PuregoSafeRegister(&xOnceInitLeavePointer, libs, "g_once_init_leave_pointer") core.PuregoSafeRegister(&xPrivateNew, libs, "g_private_new") core.PuregoSafeRegister(&xThreadCreate, libs, "g_thread_create") core.PuregoSafeRegister(&xThreadCreateFull, libs, "g_thread_create_full") core.PuregoSafeRegister(&xThreadExit, libs, "g_thread_exit") core.PuregoSafeRegister(&xThreadForeach, libs, "g_thread_foreach") core.PuregoSafeRegister(&xThreadGetInitialized, libs, "g_thread_get_initialized") core.PuregoSafeRegister(&xThreadInit, libs, "g_thread_init") core.PuregoSafeRegister(&xThreadInitWithErrorcheckMutexes, libs, "g_thread_init_with_errorcheck_mutexes") core.PuregoSafeRegister(&xThreadSelf, libs, "g_thread_self") core.PuregoSafeRegister(&xThreadYield, libs, "g_thread_yield") core.PuregoSafeRegister(&xCondBroadcast, libs, "g_cond_broadcast") core.PuregoSafeRegister(&xCondClear, libs, "g_cond_clear") core.PuregoSafeRegister(&xCondFree, libs, "g_cond_free") core.PuregoSafeRegister(&xCondInit, libs, "g_cond_init") core.PuregoSafeRegister(&xCondSignal, libs, "g_cond_signal") core.PuregoSafeRegister(&xCondTimedWait, libs, "g_cond_timed_wait") core.PuregoSafeRegister(&xCondWait, libs, "g_cond_wait") core.PuregoSafeRegister(&xCondWaitUntil, libs, "g_cond_wait_until") core.PuregoSafeRegister(&xOnceImpl, libs, "g_once_impl") core.PuregoSafeRegister(&xPrivateGet, libs, "g_private_get") core.PuregoSafeRegister(&xPrivateReplace, libs, "g_private_replace") core.PuregoSafeRegister(&xPrivateSet, libs, "g_private_set") core.PuregoSafeRegister(&xRWLockClear, libs, "g_rw_lock_clear") core.PuregoSafeRegister(&xRWLockInit, libs, "g_rw_lock_init") core.PuregoSafeRegister(&xRWLockReaderLock, libs, "g_rw_lock_reader_lock") core.PuregoSafeRegister(&xRWLockReaderTrylock, libs, "g_rw_lock_reader_trylock") core.PuregoSafeRegister(&xRWLockReaderUnlock, libs, "g_rw_lock_reader_unlock") core.PuregoSafeRegister(&xRWLockWriterLock, libs, "g_rw_lock_writer_lock") core.PuregoSafeRegister(&xRWLockWriterTrylock, libs, "g_rw_lock_writer_trylock") core.PuregoSafeRegister(&xRWLockWriterUnlock, libs, "g_rw_lock_writer_unlock") core.PuregoSafeRegister(&xRecMutexClear, libs, "g_rec_mutex_clear") core.PuregoSafeRegister(&xRecMutexInit, libs, "g_rec_mutex_init") core.PuregoSafeRegister(&xRecMutexLock, libs, "g_rec_mutex_lock") core.PuregoSafeRegister(&xRecMutexTrylock, libs, "g_rec_mutex_trylock") core.PuregoSafeRegister(&xRecMutexUnlock, libs, "g_rec_mutex_unlock") core.PuregoSafeRegister(&xStaticMutexFree, libs, "g_static_mutex_free") core.PuregoSafeRegister(&xStaticMutexGetMutexImpl, libs, "g_static_mutex_get_mutex_impl") core.PuregoSafeRegister(&xStaticMutexInit, libs, "g_static_mutex_init") core.PuregoSafeRegister(&xStaticPrivateFree, libs, "g_static_private_free") core.PuregoSafeRegister(&xStaticPrivateGet, libs, "g_static_private_get") core.PuregoSafeRegister(&xStaticPrivateInit, libs, "g_static_private_init") core.PuregoSafeRegister(&xStaticPrivateSet, libs, "g_static_private_set") core.PuregoSafeRegister(&xStaticRWLockFree, libs, "g_static_rw_lock_free") core.PuregoSafeRegister(&xStaticRWLockInit, libs, "g_static_rw_lock_init") core.PuregoSafeRegister(&xStaticRWLockReaderLock, libs, "g_static_rw_lock_reader_lock") core.PuregoSafeRegister(&xStaticRWLockReaderTrylock, libs, "g_static_rw_lock_reader_trylock") core.PuregoSafeRegister(&xStaticRWLockReaderUnlock, libs, "g_static_rw_lock_reader_unlock") core.PuregoSafeRegister(&xStaticRWLockWriterLock, libs, "g_static_rw_lock_writer_lock") core.PuregoSafeRegister(&xStaticRWLockWriterTrylock, libs, "g_static_rw_lock_writer_trylock") core.PuregoSafeRegister(&xStaticRWLockWriterUnlock, libs, "g_static_rw_lock_writer_unlock") core.PuregoSafeRegister(&xStaticRecMutexFree, libs, "g_static_rec_mutex_free") core.PuregoSafeRegister(&xStaticRecMutexInit, libs, "g_static_rec_mutex_init") core.PuregoSafeRegister(&xStaticRecMutexLock, libs, "g_static_rec_mutex_lock") core.PuregoSafeRegister(&xStaticRecMutexLockFull, libs, "g_static_rec_mutex_lock_full") core.PuregoSafeRegister(&xStaticRecMutexTrylock, libs, "g_static_rec_mutex_trylock") core.PuregoSafeRegister(&xStaticRecMutexUnlock, libs, "g_static_rec_mutex_unlock") core.PuregoSafeRegister(&xStaticRecMutexUnlockFull, libs, "g_static_rec_mutex_unlock_full") core.PuregoSafeRegister(&xThreadGLibType, libs, "g_thread_get_type") core.PuregoSafeRegister(&xNewThread, libs, "g_thread_new") core.PuregoSafeRegister(&xThreadTryNew, libs, "g_thread_try_new") core.PuregoSafeRegister(&xThreadGetName, libs, "g_thread_get_name") core.PuregoSafeRegister(&xThreadJoin, libs, "g_thread_join") core.PuregoSafeRegister(&xThreadRef, libs, "g_thread_ref") core.PuregoSafeRegister(&xThreadSetPriority, libs, "g_thread_set_priority") core.PuregoSafeRegister(&xThreadUnref, libs, "g_thread_unref") }