/* SPDX-FileCopyrightText: 2006 Blender Authors * * SPDX-License-Identifier: GPL-2.0-or-later */ #pragma once /** \file * \ingroup bli */ #include #include "BLI_listbase.h" #include "BLI_sys_types.h" namespace blender { /** For tables, button in UI, etc. */ #define BLENDER_MAX_THREADS 1024 struct ThreadSlot; /* Threading API */ /** * This is run once at startup. */ void BLI_threadapi_init(); void BLI_threadapi_exit(); /** * \param tot: When 0 only initializes `malloc` mutex in a safe way (see sequence.c) * problem otherwise: scene render will kill of the mutex! */ void BLI_threadpool_init(ListBaseT *threadbase, void *(*do_thread)(void *), int tot); /** * Amount of available threads. */ int BLI_available_threads(ListBaseT *threadbase); /** * Returns thread number, for sample patterns or threadsafe tables. */ int BLI_threadpool_available_thread_index(ListBaseT *threadbase); void BLI_threadpool_insert(ListBaseT *threadbase, void *callerdata); void BLI_threadpool_remove(ListBaseT *threadbase, void *callerdata); void BLI_threadpool_remove_index(ListBaseT *threadbase, int index); void BLI_threadpool_clear(ListBaseT *threadbase); void BLI_threadpool_end(ListBaseT *threadbase); int BLI_thread_is_main(); /* System Information */ /** * \return the number of threads the system can make use of. */ int BLI_system_thread_count(); void BLI_system_num_threads_override_set(int num); int BLI_system_num_threads_override_get(); /** * Global Mutex Locks * * One custom lock available now. can be extended. */ enum { LOCK_IMAGE = 0, LOCK_DRAW_IMAGE, LOCK_VIEWER, LOCK_CUSTOM1, LOCK_NODES, LOCK_MOVIECLIP, LOCK_FFTW, LOCK_VIEW3D, }; void BLI_thread_lock(int type); void BLI_thread_unlock(int type); /* Mutex Lock */ typedef pthread_mutex_t ThreadMutex; #define BLI_MUTEX_INITIALIZER PTHREAD_MUTEX_INITIALIZER void BLI_mutex_init(ThreadMutex *mutex); void BLI_mutex_end(ThreadMutex *mutex); ThreadMutex *BLI_mutex_alloc(); void BLI_mutex_free(ThreadMutex *mutex); void BLI_mutex_lock(ThreadMutex *mutex); bool BLI_mutex_trylock(ThreadMutex *mutex); void BLI_mutex_unlock(ThreadMutex *mutex); /* Spin Lock */ /* By default we use TBB for spin lock on all platforms. When building without * TBB fall-back to spin lock implementation which is native to the platform. * * On macOS we use mutex lock instead of spin since the spin lock has been * deprecated in SDK 10.12 and is discouraged from use. */ #ifdef WITH_TBB typedef uint32_t SpinLock; #elif defined(__APPLE__) typedef ThreadMutex SpinLock; #elif defined(_MSC_VER) typedef volatile unsigned int SpinLock; #else typedef pthread_spinlock_t SpinLock; #endif void BLI_spin_init(SpinLock *spin); void BLI_spin_lock(SpinLock *spin); void BLI_spin_unlock(SpinLock *spin); void BLI_spin_end(SpinLock *spin); /* Read/Write Mutex Lock */ #define THREAD_LOCK_READ 1 #define THREAD_LOCK_WRITE 2 #define BLI_RWLOCK_INITIALIZER PTHREAD_RWLOCK_INITIALIZER typedef pthread_rwlock_t ThreadRWMutex; void BLI_rw_mutex_init(ThreadRWMutex *mutex); void BLI_rw_mutex_end(ThreadRWMutex *mutex); ThreadRWMutex *BLI_rw_mutex_alloc(); void BLI_rw_mutex_free(ThreadRWMutex *mutex); void BLI_rw_mutex_lock(ThreadRWMutex *mutex, int mode); void BLI_rw_mutex_unlock(ThreadRWMutex *mutex); /* Ticket Mutex Lock * * This is a 'fair' mutex in that it will grant the lock to the first thread * that requests it. */ struct TicketMutex; TicketMutex *BLI_ticket_mutex_alloc(); void BLI_ticket_mutex_free(TicketMutex *ticket); void BLI_ticket_mutex_lock(TicketMutex *ticket); bool BLI_ticket_mutex_lock_check_recursive(TicketMutex *ticket); void BLI_ticket_mutex_unlock(TicketMutex *ticket); /* Condition */ typedef pthread_cond_t ThreadCondition; void BLI_condition_init(ThreadCondition *cond); void BLI_condition_wait(ThreadCondition *cond, ThreadMutex *mutex); void BLI_condition_wait_global_mutex(ThreadCondition *cond, int type); void BLI_condition_notify_one(ThreadCondition *cond); void BLI_condition_notify_all(ThreadCondition *cond); void BLI_condition_end(ThreadCondition *cond); /* ThreadWorkQueue * * Thread-safe work queue to push work/pointers between threads. */ struct ThreadQueue; enum ThreadQueueWorkPriority { BLI_THREAD_QUEUE_WORK_PRIORITY_LOW, BLI_THREAD_QUEUE_WORK_PRIORITY_NORMAL, BLI_THREAD_QUEUE_WORK_PRIORITY_HIGH, }; /** * Allocate a new ThreadQueue. */ ThreadQueue *BLI_thread_queue_init(); /** * Deallocate the ThreadQueue. * Assumes no one is using the queue anymore. */ void BLI_thread_queue_free(ThreadQueue *queue); /** * Push one work pointer to the queue. * Higher priority works always take priority over lower priority ones, regardless of their * insertion order. Works within the same priority follow FIFO order. * * \returns a unique work_id that can be used later for canceling the work before it's popped out * from the queue. */ uint64_t BLI_thread_queue_push(ThreadQueue *queue, void *work, ThreadQueueWorkPriority priority); /** * Remove the corresponding work from the queue. * * \returns true if the work_id was still in the queue. */ bool BLI_thread_queue_cancel_work(ThreadQueue *queue, uint64_t work_id); /** * Pop the oldest, highest priority work from the queue. * Blocks the calling thread unless BLI_thread_queue_nowait has been called for this queue. * * \returns nullptr if nowait has been set and the queue is empty. Otherwise returns a work * pointer. */ void *BLI_thread_queue_pop(ThreadQueue *queue); /** * Try to pop the oldest, highest priority work from the queue. * Blocks the calling thread unless BLI_thread_queue_nowait has been called for this queue. * * \returns nullptr if time runs out, or if nowait has been set and the queue is empty. Otherwise * returns a work pointer. */ void *BLI_thread_queue_pop_timeout(ThreadQueue *queue, int ms); /** * \returns the total amount of pending works still in the queue. */ int BLI_thread_queue_len(ThreadQueue *queue); /** * \returns true if there are no pending works in the queue. */ bool BLI_thread_queue_is_empty(ThreadQueue *queue); /** * Blocks the calling thread until the queue is empty. */ void BLI_thread_queue_wait_finish(ThreadQueue *queue); /** * After calling this function, BLI_thread_queue_pop and BLI_thread_queue_pop_timeout won't block * the calling thread even when the queue is empty. */ void BLI_thread_queue_nowait(ThreadQueue *queue); /* Thread local storage */ #if defined(__APPLE__) # define ThreadLocal(type) pthread_key_t # define BLI_thread_local_create(name) pthread_key_create(&name, NULL) # define BLI_thread_local_delete(name) pthread_key_delete(name) # define BLI_thread_local_get(name) pthread_getspecific(name) # define BLI_thread_local_set(name, value) pthread_setspecific(name, value) #else /* defined(__APPLE__) */ # ifdef _MSC_VER # define ThreadLocal(type) __declspec(thread) type # else # define ThreadLocal(type) __thread type # endif # define BLI_thread_local_create(name) # define BLI_thread_local_delete(name) # define BLI_thread_local_get(name) name # define BLI_thread_local_set(name, value) name = value #endif /* defined(__APPLE__) */ } // namespace blender