package core:sync

⌘K
Ctrl+K
or
/

    Overview

    Synchronization primitives

    This package implements various synchronization primitives that can be used to synchronize threads' access to shared memory.

    To limit or control the threads' access to shared memory typically the following approaches are used:

    Locks Lock-free

    When using locks, sections of the code that access shared memory (also known as critical sections) are guarded by locks, allowing limited access to threads and blocking the execution of any other threads.

    In lock-free programming the data itself is organized in such a way that threads don't intervene much. It can be done via segmenting the data between threads, and/or by using atomic operations.

    Index

    Variables (0)

    This section is empty.

    Procedures (104)

    Types

    Atomic_Cond ¶

    Atomic_Cond :: struct {
    	state: Futex,
    }
     

    Atomic_Cond implements a condition variable, a rendezvous point for threads waiting for signalling the occurence of an event

    An Atomic_Cond must not be copied after first use

    Related Procedures With Parameters

    Atomic_Memory_Order ¶

    Atomic_Memory_Order :: .Atomic_Memory_Order
     

    Describes memory ordering for an atomic operation.

    Modern CPU's contain multiple cores and caches specific to those cores. When a core performs a write to memory, the value is written to cache first. The issue is that a core doesn't typically see what's inside the caches of other cores. In order to make operations consistent CPU's implement mechanisms that synchronize memory operations across cores by asking other cores or by pushing data about writes to other cores.

    Due to how these algorithms are implemented, the stores and loads performed by one core may seem to happen in a different order to another core. It also may happen that a core reorders stores and loads (independent of how compiler put them into the machine code). This can cause issues when trying to synchronize multiple memory locations between two cores. Which is why CPU's allow for stronger memory ordering guarantees if certain instructions or instruction variants are used.

    In Odin there are 5 different memory ordering guaranties that can be provided to an atomic operation:

    Relaxed: The memory access (load or store) is unordered with respect to other memory accesses. This can be used to implement an atomic counter. Multiple threads access a single variable, but it doesn't matter when exactly it gets incremented, because it will become eventually consistent. Consume: No loads or stores dependent on a memory location can be reordered before a load with consume memory order. If other threads released the same memory, it becomes visible. Acquire: No loads or stores on a memory location can be reordered before a load of that memory location with acquire memory ordering. If other threads release the same memory, it becomes visible. Release: No loads or stores on a memory location can be reordered after a store of that memory location with release memory ordering. All threads that acquire the same memory location will see all writes done by the current thread. Acq_Rel: Acquire-release memory ordering: combines acquire and release memory orderings in the same operation. Seq_Cst: Sequential consistency. The strongest memory ordering. A load will always be an acquire operation, a store will always be a release operation, and in addition to that all threads observe the same order of writes.

    Non-explicit atomics will always be sequentially consistent.

    Atomic_Memory_Order :: enum {
    	Relaxed = 0, // Unordered
    	Consume = 1, // Monotonic
    	Acquire = 2,
    	Release = 3,
    	Acq_Rel = 4,
    	Seq_Cst = 5,
    }
    
    

    Note(i386, x64): x86 has a very strong memory model by default. It guarantees that all writes are ordered, stores and loads aren't reordered. In a sense, all operations are at least acquire and release operations. If lock prefix is used, all operations are sequentially consistent. If you use explicit atomics, make sure you have the correct atomic memory order, because bugs likely will not show up in x86, but may show up on e.g. arm. More on x86 memory ordering can be found here

    Atomic_Mutex ¶

    Atomic_Mutex :: struct {
    	state: Atomic_Mutex_State,
    }
     

    An Atomic_Mutex is a mutual exclusion lock The zero value for a Atomic_Mutex is an unlocked mutex

    An Atomic_Mutex must not be copied after first use

    Related Procedures With Parameters

    Atomic_Mutex_State ¶

    Atomic_Mutex_State :: enum Futex {
    	Unlocked = 0, 
    	Locked   = 1, 
    	Waiting  = 2, 
    }

    Atomic_RW_Mutex ¶

    Atomic_RW_Mutex :: struct {
    	state: Atomic_RW_Mutex_State,
    	mutex: Atomic_Mutex,
    	sema:  Atomic_Sema,
    }
     

    An Atomic_RW_Mutex is a reader/writer mutual exclusion lock The lock can be held by any arbitrary number of readers or a single writer The zero value for an Atomic_RW_Mutex is an unlocked mutex

    An Atomic_RW_Mutex must not be copied after first use

    Related Procedures With Parameters

    Atomic_Recursive_Mutex ¶

    Atomic_Recursive_Mutex :: struct {
    	owner:     int,
    	recursion: int,
    	mutex:     Mutex,
    }
     

    An Atomic_Recursive_Mutex is a recursive mutual exclusion lock The zero value for a Recursive_Mutex is an unlocked mutex

    An Atomic_Recursive_Mutex must not be copied after first use

    Related Procedures With Parameters

    Atomic_Sema ¶

    Atomic_Sema :: struct {
    	count: Futex,
    }
     

    When waited upon, blocks until the internal count is greater than zero, then subtracts one. Posting to the semaphore increases the count by one, or the provided amount.

    An Atomic_Sema must not be copied after first use

    Related Procedures With Parameters

    Auto_Reset_Event ¶

    Auto_Reset_Event :: struct {
    	// status ==  0: Event is reset and no threads are waiting
    	// status ==  1: Event is signalled
    	// status == -N: Event is reset and N threads are waiting
    	status: i32,
    	sema:   Sema,
    }
     

    Auto-reset event.

    Represents a thread synchronization primitive that, when signalled, releases one single waiting thread and then resets automatically to a state where it can be signalled again.

    When a thread calls auto_reset_event_wait, its execution will be blocked, until the event is signalled by another thread. The call to auto_reset_event_signal wakes up exactly one thread waiting for the event.

    Related Procedures With Parameters

    Barrier ¶

    Barrier :: struct {
    	mutex:         Mutex,
    	cond:          Cond,
    	index:         int,
    	generation_id: int,
    	thread_count:  int,
    }
     

    Barrier.

    A barrier is a synchronization primitive enabling multiple threads to synchronize the beginning of some computation.

    When barrier_wait procedure is called by any thread, that thread will block the execution, until all threads associated with the barrier reach the same point of execution and also call barrier_wait.

    When a barrier is initialized, a thread_count parameter is passed, signifying the amount of participant threads of the barrier. The barrier also keeps track of an internal atomic counter. When a thread calls barrier_wait, the internal counter is incremented. When the internal counter reaches thread_count, it is reset and all threads waiting on the barrier are unblocked.

    This type of synchronization primitive can be used to synchronize "staged" workloads, where the workload is split into stages, and until all threads have completed the previous threads, no thread is allowed to start work on the next stage. In this case, after each stage, a barrier_wait shall be inserted in the thread procedure.

    Example:

    THREAD_COUNT :: 4
    threads: [THREAD_COUNT]^thread.Thread
    sync.barrier_init(barrier, THREAD_COUNT)
    for _, i in threads {
    	threads[i] = thread.create_and_start(proc(t: ^thread.Thread) {
    		// Same messages will be printed together but without any interleaving
    		fmt.println("Getting ready!")
    		sync.barrier_wait(barrier)
    		fmt.println("Off their marks they go!")
    	})
    }
    for t in threads {
    	thread.destroy(t)
    }
    
    Related Procedures With Parameters

    Benaphore ¶

    Benaphore :: struct {
    	counter: i32,
    	sema:    Sema,
    }
     

    Benaphore.

    A benaphore is a combination of an atomic variable and a semaphore that can improve locking efficiency in a no-contention system. Acquiring a benaphore lock doesn't call into an internal semaphore, if no other thread is in the middle of a critical section.

    Once a lock on a benaphore is acquired by a thread, no other thread is allowed into any critical sections, associted with the same benaphore, until the lock is released.

    Related Procedures With Parameters

    Cond ¶

    Cond :: struct {
    	impl: _Cond,
    }
     

    A condition variable.

    Cond implements a condition variable, a rendezvous point for threads waiting for signalling the occurence of an event. Condition variables are used in conjuction with mutexes to provide a shared access to one or more shared variable.

    A typical usage of condition variable is as follows. A thread that intends to modify a shared variable shall:

    1. Acquire a lock on a mutex. 2. Modify the shared memory. 3. Release the lock. 3. Call cond_signal or cond_broadcast.

    A thread that intends to wait on a shared variable shall:

    1. Acquire a lock on a mutex. 2. Call cond_wait or cond_wait_with_timeout (will release the mutex). 3. Check the condition and keep waiting in a loop if not satisfied with result.

    Note: A condition variable must not be copied after first use (e.g., after waiting on it the first time). This is because, in order to coordinate with other threads, all threads must watch the same memory address to know when the lock has been released. Trying to use a copy of the lock at a different memory address will result in broken and unsafe behavior. For this reason, condition variables are marked as #no_copy.

    Related Procedures With Parameters

    Futex ¶

    Futex :: distinct u32
     

    Fast userspace mutual exclusion lock.

    Futex is a fast userspace mutual exclusion lock, that uses a pointer to a 32-bit value as an identifier of the queue of waiting threads. The value pointed to by that pointer can be used to store extra data.

    IMPORTANT: A futex must not be copied after first use (e.g., after waiting on it the first time, or signalling it). This is because, in order to coordinate with other threads, all threads must watch the same memory address. Trying to use a copy of the lock at a different memory address will result in broken and unsafe behavior.

    Related Procedures With Parameters

    Mutex ¶

    Mutex :: struct {
    	impl: _Mutex,
    }
     

    Mutual exclusion lock.

    A Mutex is a mutual exclusion lock It can be used to prevent more than one thread from entering the critical section, and thus prevent access to same piece of memory by multiple threads, at the same time.

    Mutex's zero-initializzed value represents an initial, unlocked state.

    If another thread tries to acquire the lock, while it's already held (typically by another thread), the thread's execution will be blocked, until the lock is released. Code or memory that is "surrounded" by a mutex lock and unlock operations is said to be "guarded by a mutex".

    Note: A Mutex must not be copied after first use (e.g., after locking it the first time). This is because, in order to coordinate with other threads, all threads must watch the same memory address to know when the lock has been released. Trying to use a copy of the lock at a different memory address will result in broken and unsafe behavior. For this reason, Mutexes are marked as #no_copy.

    Note: If the current thread attempts to lock a mutex, while it's already holding another lock, that will cause a trivial case of deadlock. Do not use Mutex in recursive functions. In case multiple locks by the same thread are desired, use Recursive_Mutex.

    Related Procedures With Parameters

    Once ¶

    Once :: struct {
    	m:    Mutex,
    	done: bool,
    }
     

    Once action.

    Once a synchronization primitive, that only allows a single entry into a critical section from a single thread.

    Related Procedures With Parameters

    One_Shot_Event ¶

    One_Shot_Event :: struct {
    	state: Futex,
    }
     

    One-shot event.

    A one-shot event is an associated token which is initially not present:

    The one_shot_event_wait blocks the current thread until the event is made available The one_shot_event_signal procedure automatically makes the token available if its was not already.

    Related Procedures With Parameters

    Parker ¶

    Parker :: struct {
    	state: Futex,
    }
     

    A Parker is an associated token which is initially not present:

    The park procedure blocks the current thread unless or until the token is available, at which point the token is consumed. The park_with_timeout procedures works the same as park but only blocks for the specified duration. The unpark procedure automatically makes the token available if it was not already.

    Related Procedures With Parameters

    RW_Mutex ¶

    RW_Mutex :: struct {
    	impl: _RW_Mutex,
    }
     

    Read-write mutual exclusion lock.

    An RW_Mutex is a reader/writer mutual exclusion lock. The lock can be held by any number of readers or a single writer.

    This type of synchronization primitive supports two kinds of lock operations:

    Exclusive lock (write lock) Shared lock (read lock)

    When an exclusive lock is acquired by any thread, all other threads, attempting to acquire either an exclusive or shared lock, will be blocked from entering the critical sections associated with the read-write mutex, until the exclusive owner of the lock releases the lock.

    When a shared lock is acquired by any thread, any other thread attempting to acquire a shared lock will also be able to enter all the critical sections associated with the read-write mutex. However threads attempting to acquire an exclusive lock will be blocked from entering those critical sections, until all shared locks are released.

    Note: A read-write mutex must not be copied after first use (e.g., after acquiring a lock). This is because, in order to coordinate with other threads, all threads must watch the same memory address to know when the lock has been released. Trying to use a copy of the lock at a different memory address will result in broken and unsafe behavior. For this reason, mutexes are marked as #no_copy.

    Note: A read-write mutex is not recursive. Do not attempt to acquire an exclusive lock more than once from the same thread, or an exclusive and shared lock on the same thread. Taking a shared lock multiple times is acceptable.

    Related Procedures With Parameters

    Recursive_Benaphore ¶

    Recursive_Benaphore :: struct {
    	counter:   int,
    	owner:     int,
    	recursion: i32,
    	sema:      Sema,
    }
     

    Recursive benaphore.

    A recursive benaphore is just like a plain benaphore, except it allows reentrancy into the critical section.

    When a lock is acquired on a benaphore, all other threads attempting to acquire a lock on the same benaphore will be blocked from any critical sections, associated with the same benaphore.

    When a lock is acquired on a benaphore by a thread, that thread is allowed to acquire another lock on the same benaphore. When a thread has acquired the lock on a benaphore, the benaphore will stay locked until the thread releases the lock as many times as it has been locked by the thread.

    Related Procedures With Parameters

    Recursive_Mutex ¶

    Recursive_Mutex :: struct {
    	impl: _Recursive_Mutex,
    }
     

    Recursive mutual exclusion lock.

    Recurisve mutex is just like a plain mutex, except it allows reentrancy. In order for a thread to release the mutex for other threads, the mutex needs to be unlocked as many times, as it was locked.

    When a lock is acquired on a recursive mutex, all other threads attempting to acquire a lock on the same mutex will be blocked from any critical sections, associated with the same recrusive mutex.

    When a lock is acquired on a recursive mutex by a thread, that thread is allowed to acquire another lock on the same mutex. When a thread has acquired the lock on a recursive mutex, the recursive mutex will stay locked until the thread releases the lock as many times as it has been locked by the thread.

    Note: A recursive mutex must not be copied after first use (e.g., after acquiring a lock). This is because, in order to coordinate with other threads, all threads must watch the same memory address to know when the lock has been released. Trying to use a copy of the lock at a different memory address will result in broken and unsafe behavior. For this reason, mutexes are marked as #no_copy.

    Related Procedures With Parameters

    Sema ¶

    Sema :: struct {
    	impl: _Sema,
    }
     

    Semaphore.

    When waited upon, semaphore blocks until the internal count is greater than zero, then decrements the internal counter by one. Posting to the semaphore increases the count by one, or the provided amount.

    This type of synchronization primitives can be useful for implementing queues. The internal counter of the semaphore can be thought of as the amount of items in the queue. After a data has been pushed to the queue, the thread shall call sema_post() procedure, increasing the counter. When a thread takes an item from the queue to do the job, it shall call sema_wait(), waiting on the semaphore counter to become non-zero and decreasing it, if necessary.

    Note: A semaphore must not be copied after first use (e.g., after posting to it). This is because, in order to coordinate with other threads, all threads must watch the same memory address to know when the lock has been released. Trying to use a copy of the lock at a different memory address will result in broken and unsafe behavior. For this reason, semaphores are marked as #no_copy.

    Related Procedures With Parameters

    Ticket_Mutex ¶

    Ticket_Mutex :: struct {
    	ticket:  uint,
    	serving: uint,
    }
     

    Ticket lock.

    A ticket lock is a mutual exclusion lock that uses "tickets" to control which thread is allowed into a critical section.

    This synchronization primitive works just like spinlock, except that it implements a "fairness" guarantee, making sure that each thread gets a roughly equal amount of entries into the critical section.

    This type of synchronization primitive is applicable for short critical sections in low-contention systems, as it uses a spinlock under the hood.

    Related Procedures With Parameters

    Wait_Group ¶

    Wait_Group :: struct {
    	counter: int,
    	mutex:   Mutex,
    	cond:    Cond,
    }
     

    Wait group.

    Wait group is a synchronization primitive used by the waiting thread to wait, until all working threads finish work.

    The waiting thread first sets the number of working threads it will expect to wait for using wait_group_add call, and start waiting using wait_group_wait call. When worker threads complete their work, each of them will call wait_group_done, and after all working threads have called this procedure, the waiting thread will resume execution.

    For the purpose of keeping track whether all working threads have finished their work, the wait group keeps an internal atomic counter. Initially, the waiting thread might set it to a certain non-zero amount. When each working thread completes the work, the internal counter is atomically decremented until it reaches zero. When it reaches zero, the waiting thread is unblocked. The counter is not allowed to become negative.

    Note: Just like any synchronization primitives, a wait group cannot be copied after first use. See documentation for Mutex or Cond.

    Related Procedures With Parameters

    Constants

    Atomic_RW_Mutex_State_Half_Width ¶

    Atomic_RW_Mutex_State_Half_Width :: size_of(Atomic_RW_Mutex_State) * 8 / 2

    Atomic_RW_Mutex_State_Is_Writing ¶

    Atomic_RW_Mutex_State_Is_Writing :: Atomic_RW_Mutex_State(1)

    Atomic_RW_Mutex_State_Reader ¶

    Atomic_RW_Mutex_State_Reader :: Atomic_RW_Mutex_State(1) << Atomic_RW_Mutex_State_Half_Width

    Atomic_RW_Mutex_State_Reader_Mask ¶

    Atomic_RW_Mutex_State_Reader_Mask :: Atomic_RW_Mutex_State(1 << (Atomic_RW_Mutex_State_Half_Width - 1) - 1) << Atomic_RW_Mutex_State_Half_Width

    Atomic_RW_Mutex_State_Writer ¶

    Atomic_RW_Mutex_State_Writer :: Atomic_RW_Mutex_State(1) << 1

    Atomic_RW_Mutex_State_Writer_Mask ¶

    Atomic_RW_Mutex_State_Writer_Mask :: Atomic_RW_Mutex_State(1 << (Atomic_RW_Mutex_State_Half_Width - 1) - 1) << 1

    Variables

    This section is empty.

    Procedures

    atomic_add ¶

    atomic_add :: intrinsics.atomic_add
     

    Atomically add a value to the value stored in memory.

    This procedure loads a value from memory, adds the specified value to it, and stores it back as an atomic operation. This operation is an atomic equivalent of the following:

    dst^ += val
    
    

    The memory ordering of this operation is sequentially-consistent.

    atomic_add_explicit ¶

    atomic_add_explicit :: intrinsics.atomic_add_explicit
     

    Atomically add a value to the value stored in memory.

    This procedure loads a value from memory, adds the specified value to it, and stores it back as an atomic operation. This operation is an atomic equivalent of the following:

    dst^ += val
    
    

    The memory ordering of this operation is as specified by the order parameter.

    atomic_and ¶

    atomic_and :: intrinsics.atomic_and
     

    Atomically replace the memory location with the result of AND operation with the specified value.

    This procedure loads a value from memory, calculates the result of AND operation between the loaded value and the specified value, and stores it back into the same memory location as an atomic operation. This operation is an atomic equivalent of the following:

    dst^ &= val
    
    

    The memory ordering of this operation is sequentially-consistent.

    atomic_and_explicit ¶

    atomic_and_explicit :: intrinsics.atomic_and_explicit
     

    Atomically replace the memory location with the result of AND operation with the specified value.

    This procedure loads a value from memory, calculates the result of AND operation between the loaded value and the specified value, and stores it back into the same memory location as an atomic operation. This operation is an atomic equivalent of the following:

    dst^ &= val
    
    

    The memory ordering of this operation is as specified by the order parameter.

    atomic_compare_exchange_strong ¶

    atomic_compare_exchange_strong :: intrinsics.atomic_compare_exchange_strong
     

    Atomically compare and exchange the value with a memory location.

    This procedure checks if the value pointed to by the dst parameter is equal to old, and if they are, it stores the value new into the memory location, all done in a single atomic operation. This procedure returns the old value stored in a memory location and a boolean value signifying whether old was equal to new.

    This procedure is an atomic equivalent of the following operation:

    old_dst := dst^
    if old_dst == old {
    	dst^ = new
    	return old_dst, true
    } else {
    	return old_dst, false
    }
    
    

    The strong version of compare exchange always returns true, when the returned old value stored in location pointed to by dst and the old parameter are equal.

    Atomic compare exchange has two memory orderings: One is for the read-modify-write operation, if the comparison succeeds, and the other is for the load operation, if the comparison fails. The memory ordering for both of of these operations is sequentially-consistent.

    atomic_compare_exchange_strong_explicit ¶

    atomic_compare_exchange_strong_explicit :: intrinsics.atomic_compare_exchange_strong_explicit
     

    Atomically compare and exchange the value with a memory location.

    This procedure checks if the value pointed to by the dst parameter is equal to old, and if they are, it stores the value new into the memory location, all done in a single atomic operation. This procedure returns the old value stored in a memory location and a boolean value signifying whether old was equal to new.

    This procedure is an atomic equivalent of the following operation:

    old_dst := dst^
    if old_dst == old {
    	dst^ = new
    	return old_dst, true
    } else {
    	return old_dst, false
    }
    
    

    The strong version of compare exchange always returns true, when the returned old value stored in location pointed to by dst and the old parameter are equal.

    Atomic compare exchange has two memory orderings: One is for the read-modify-write operation, if the comparison succeeds, and the other is for the load operation, if the comparison fails. The memory ordering for these operations is as specified by success and failure parameters respectively.

    atomic_compare_exchange_weak ¶

    atomic_compare_exchange_weak :: intrinsics.atomic_compare_exchange_weak
     

    Atomically compare and exchange the value with a memory location.

    This procedure checks if the value pointed to by the dst parameter is equal to old, and if they are, it stores the value new into the memory location, all done in a single atomic operation. This procedure returns the old value stored in a memory location and a boolean value signifying whether old was equal to new.

    This procedure is an atomic equivalent of the following operation:

    old_dst := dst^
    if old_dst == old {
    	// may return false here
    	dst^ = new
    	return old_dst, true
    } else {
    	return old_dst, false
    }
    
    

    The weak version of compare exchange may return false, even if dst^ == old. On some platforms running weak compare exchange in a loop is faster than a strong version.

    Atomic compare exchange has two memory orderings: One is for the read-modify-write operation, if the comparison succeeds, and the other is for the load operation, if the comparison fails. The memory ordering for both of these operations is sequentially-consistent.

    atomic_compare_exchange_weak_explicit ¶

    atomic_compare_exchange_weak_explicit :: intrinsics.atomic_compare_exchange_weak_explicit
     

    Atomically compare and exchange the value with a memory location.

    This procedure checks if the value pointed to by the dst parameter is equal to old, and if they are, it stores the value new into the memory location, all done in a single atomic operation. This procedure returns the old value stored in a memory location and a boolean value signifying whether old was equal to new.

    This procedure is an atomic equivalent of the following operation:

    old_dst := dst^
    if old_dst == old {
    	// may return false here
    	dst^ = new
    	return old_dst, true
    } else {
    	return old_dst, false
    }
    
    

    The weak version of compare exchange may return false, even if dst^ == old. On some platforms running weak compare exchange in a loop is faster than a strong version.

    Atomic compare exchange has two memory orderings: One is for the read-modify-write operation, if the comparison succeeds, and the other is for the load operation, if the comparison fails. The memory ordering for these operations is as specified by the success and failure parameters respectively.

    atomic_cond_broadcast ¶

    atomic_cond_broadcast :: proc "contextless" (c: ^Atomic_Cond) {…}

    atomic_cond_signal ¶

    atomic_cond_signal :: proc "contextless" (c: ^Atomic_Cond) {…}

    atomic_cond_wait ¶

    atomic_cond_wait :: proc "contextless" (c: ^Atomic_Cond, m: ^Atomic_Mutex) {…}

    atomic_cond_wait_with_timeout ¶

    atomic_cond_wait_with_timeout :: proc "contextless" (c: ^Atomic_Cond, m: ^Atomic_Mutex, duration: time.Duration) -> (ok: bool) {…}

    atomic_exchange ¶

    atomic_exchange :: intrinsics.atomic_exchange
     

    Atomically exchange the value in a memory location, with the specified value.

    This procedure loads a value from the specified memory location, and stores the specified value into that memory location. Then the loaded value is returned, all done in a single atomic operation. This operation is an atomic equivalent of the following:

    tmp := dst^
    dst^ = val
    return tmp
    
    

    The memory ordering of this operation is sequentially-consistent.

    atomic_exchange_explicit ¶

    atomic_exchange_explicit :: intrinsics.atomic_exchange_explicit
     

    Atomically exchange the value in a memory location, with the specified value.

    This procedure loads a value from the specified memory location, and stores the specified value into that memory location. Then the loaded value is returned, all done in a single atomic operation. This operation is an atomic equivalent of the following:

    tmp := dst^
    dst^ = val
    return tmp
    
    

    The memory ordering of this operation is as specified by the order parameter.

    atomic_load ¶

    atomic_load :: intrinsics.atomic_load
     

    Atomically load a value from memory.

    This procedure loads a value from a memory location in such a way that the received value is not a partial read. The memory ordering of this operation is sequentially-consistent.

    atomic_load_explicit ¶

    atomic_load_explicit :: intrinsics.atomic_load_explicit
     

    Atomically load a value from memory with explicit memory ordering.

    This procedure loads a value from a memory location in such a way that the received value is not a partial read. The memory ordering of this operation is as specified by the order parameter.

    atomic_mutex_guard ¶

    atomic_mutex_guard :: proc "contextless" (m: ^Atomic_Mutex) -> bool {…}
     
    Example:
    if atomic_mutex_guard(&m) {
    	...
    }
    

    atomic_mutex_lock ¶

    atomic_mutex_lock :: proc "contextless" (m: ^Atomic_Mutex) {…}
     

    atomic_mutex_lock locks m

    atomic_mutex_try_lock ¶

    atomic_mutex_try_lock :: proc "contextless" (m: ^Atomic_Mutex) -> bool {…}
     

    atomic_mutex_try_lock tries to lock m, will return true on success, and false on failure

    atomic_mutex_unlock ¶

    atomic_mutex_unlock :: proc "contextless" (m: ^Atomic_Mutex) {…}
     

    atomic_mutex_unlock unlocks m

    atomic_nand ¶

    atomic_nand :: intrinsics.atomic_nand
     

    Atomically replace the memory location with the result of NAND operation with the specified value.

    This procedure loads a value from memory, calculates the result of NAND operation between the loaded value and the specified value, and stores it back into the same memory location as an atomic operation. This operation is an atomic equivalent of the following:

    dst^ = ~(dst^ & val)
    
    

    The memory ordering of this operation is sequentially-consistent.

    atomic_nand_explicit ¶

    atomic_nand_explicit :: intrinsics.atomic_nand_explicit
     

    Atomically replace the memory location with the result of NAND operation with the specified value.

    This procedure loads a value from memory, calculates the result of NAND operation between the loaded value and the specified value, and stores it back into the same memory location as an atomic operation. This operation is an atomic equivalent of the following:

    dst^ = ~(dst^ & val)
    
    

    The memory ordering of this operation is as specified by the order parameter.

    atomic_or ¶

    atomic_or :: intrinsics.atomic_or
     

    Atomically replace the memory location with the result of OR operation with the specified value.

    This procedure loads a value from memory, calculates the result of OR operation between the loaded value and the specified value, and stores it back into the same memory location as an atomic operation. This operation is an atomic equivalent of the following:

    dst^ |= val
    
    

    The memory ordering of this operation is sequentially-consistent.

    atomic_or_explicit ¶

    atomic_or_explicit :: intrinsics.atomic_or_explicit
     

    Atomically replace the memory location with the result of OR operation with the specified value.

    This procedure loads a value from memory, calculates the result of OR operation between the loaded value and the specified value, and stores it back into the same memory location as an atomic operation. This operation is an atomic equivalent of the following:

    dst^ |= val
    
    

    The memory ordering of this operation is as specified by the order parameter.

    atomic_recursive_mutex_guard ¶

    atomic_recursive_mutex_guard :: proc "contextless" (m: ^Atomic_Recursive_Mutex) -> bool {…}
     
    Example:
    if atomic_recursive_mutex_guard(&m) {
    	...
    }
    

    atomic_recursive_mutex_lock ¶

    atomic_recursive_mutex_lock :: proc "contextless" (m: ^Atomic_Recursive_Mutex) {…}

    atomic_recursive_mutex_try_lock ¶

    atomic_recursive_mutex_try_lock :: proc "contextless" (m: ^Atomic_Recursive_Mutex) -> bool {…}

    atomic_recursive_mutex_unlock ¶

    atomic_recursive_mutex_unlock :: proc "contextless" (m: ^Atomic_Recursive_Mutex) {…}

    atomic_rw_mutex_guard ¶

    atomic_rw_mutex_guard :: proc "contextless" (m: ^Atomic_RW_Mutex) -> bool {…}
     
    Example:
    if atomic_rw_mutex_guard(&m) {
    	...
    }
    

    atomic_rw_mutex_lock ¶

    atomic_rw_mutex_lock :: proc "contextless" (rw: ^Atomic_RW_Mutex) {…}
     

    atomic_rw_mutex_lock locks rw for writing (with a single writer) If the mutex is already locked for reading or writing, the mutex blocks until the mutex is available.

    atomic_rw_mutex_shared_guard ¶

    atomic_rw_mutex_shared_guard :: proc "contextless" (m: ^Atomic_RW_Mutex) -> bool {…}
     
    Example:
    if atomic_rw_mutex_shared_guard(&m) {
    	...
    }
    

    atomic_rw_mutex_shared_lock ¶

    atomic_rw_mutex_shared_lock :: proc "contextless" (rw: ^Atomic_RW_Mutex) {…}
     

    atomic_rw_mutex_shared_lock locks rw for reading (with arbitrary number of readers)

    atomic_rw_mutex_shared_unlock ¶

    atomic_rw_mutex_shared_unlock :: proc "contextless" (rw: ^Atomic_RW_Mutex) {…}
     

    atomic_rw_mutex_shared_unlock unlocks rw for reading (with arbitrary number of readers)

    atomic_rw_mutex_try_lock ¶

    atomic_rw_mutex_try_lock :: proc "contextless" (rw: ^Atomic_RW_Mutex) -> bool {…}
     

    atomic_rw_mutex_try_lock tries to lock rw for writing (with a single writer)

    atomic_rw_mutex_try_shared_lock ¶

    atomic_rw_mutex_try_shared_lock :: proc "contextless" (rw: ^Atomic_RW_Mutex) -> bool {…}
     

    atomic_rw_mutex_try_shared_lock tries to lock rw for reading (with arbitrary number of readers)

    atomic_rw_mutex_unlock ¶

    atomic_rw_mutex_unlock :: proc "contextless" (rw: ^Atomic_RW_Mutex) {…}
     

    atomic_rw_mutex_unlock unlocks rw for writing (with a single writer)

    atomic_sema_post ¶

    atomic_sema_post :: proc "contextless" (s: ^Atomic_Sema, count: int = 1) {…}

    atomic_sema_wait ¶

    atomic_sema_wait :: proc "contextless" (s: ^Atomic_Sema) {…}

    atomic_sema_wait_with_timeout ¶

    atomic_sema_wait_with_timeout :: proc "contextless" (s: ^Atomic_Sema, duration: time.Duration) -> bool {…}

    atomic_signal_fence ¶

    atomic_signal_fence :: intrinsics.atomic_signal_fence
     

    Establish memory ordering between a current thread and a signal handler.

    This procedure establishes memory ordering between a thread and a signal handler, that run on the same thread, without an associated atomic operation. This procedure is equivalent to atomic_thread_fence, except it doesn't issue any CPU instructions for memory ordering.

    atomic_store ¶

    atomic_store :: intrinsics.atomic_store
     

    Atomically store a value into memory.

    This procedure stores a value to a memory location in such a way that no other thread is able to see partial reads. This operation is sequentially-consistent.

    atomic_store_explicit ¶

    atomic_store_explicit :: intrinsics.atomic_store_explicit
     

    Atomically store a value into memory with explicit memory ordering.

    This procedure stores a value to a memory location in such a way that no other thread is able to see partial reads. The memory ordering of this operation is as specified by the order parameter.

    atomic_sub ¶

    atomic_sub :: intrinsics.atomic_sub
     

    Atomically subtract a value from the value stored in memory.

    This procedure loads a value from memory, subtracts the specified value from it, and stores the result back as an atomic operation. This operation is an atomic equivalent of the following:

    dst^ -= val
    
    

    The memory ordering of this operation is sequentially-consistent.

    atomic_sub_explicit ¶

    atomic_sub_explicit :: intrinsics.atomic_sub_explicit
     

    Atomically subtract a value from the value stored in memory.

    This procedure loads a value from memory, subtracts the specified value from it, and stores the result back as an atomic operation. This operation is an atomic equivalent of the following:

    dst^ -= val
    
    

    The memory ordering of this operation is as specified by the order parameter.

    atomic_thread_fence ¶

    atomic_thread_fence :: intrinsics.atomic_thread_fence
     

    Establish memory ordering.

    This procedure establishes memory ordering, without an associated atomic operation.

    atomic_xor ¶

    atomic_xor :: intrinsics.atomic_xor
     

    Atomically replace the memory location with the result of XOR operation with the specified value.

    This procedure loads a value from memory, calculates the result of XOR operation between the loaded value and the specified value, and stores it back into the same memory location as an atomic operation. This operation is an atomic equivalent of the following:

    dst^ ~= val
    
    

    The memory ordering of this operation is sequentially-consistent.

    atomic_xor_explicit ¶

    atomic_xor_explicit :: intrinsics.atomic_xor_explicit
     

    Atomically replace the memory location with the result of XOR operation with the specified value.

    This procedure loads a value from memory, calculates the result of XOR operation between the loaded value and the specified value, and stores it back into the same memory location as an atomic operation. This operation is an atomic equivalent of the following:

    dst^ ~= val
    
    

    The memory ordering of this operation is as specified by the order parameter.

    auto_reset_event_signal ¶

    auto_reset_event_signal :: proc "contextless" (e: ^Auto_Reset_Event) {…}
     

    Signal an auto-reset event.

    This procedure signals an auto-reset event, waking up exactly one waiting thread.

    auto_reset_event_wait ¶

    auto_reset_event_wait :: proc "contextless" (e: ^Auto_Reset_Event) {…}
     

    Wait on an auto-reset event.

    This procedure blocks the execution of the current thread, until the event is signalled by another thread.

    barrier_init ¶

    barrier_init :: proc "contextless" (b: ^Barrier, thread_count: int) {…}
     

    Initialize a barrier.

    This procedure initializes the barrier for the specified amount of participant threads.

    barrier_wait ¶

    barrier_wait :: proc "contextless" (b: ^Barrier) -> (is_leader: bool) {…}
     

    Block the current thread until all threads have rendezvoused.

    This procedure blocks the execution of the current thread, until all threads have reached the same point in the execution of the thread proc. Multiple calls to barrier_wait are allowed within the thread procedure.

    benaphore_guard ¶

    benaphore_guard :: proc "contextless" (m: ^Benaphore) -> bool {…}
     

    Guard the current scope with a lock on a benaphore.

    This procedure acquires a lock on a benaphore. The lock is automatically released at the end of callee's scope. If the benaphore was already locked, this procedure also blocks until the lock can be acquired.

    When a lock has been acquired, all threads attempting to acquire a lock will be blocked from entering any critical sections associated with the same benaphore, until the lock is released.

    This procedure always returns true. This makes it easy to define a critical section by putting the function inside the if statement.

    Example:

    if benaphore_guard(&m) {
    	...
    }
    

    benaphore_lock ¶

    benaphore_lock :: proc "contextless" (b: ^Benaphore) {…}
     

    Acquire a lock on a benaphore.

    This procedure acquires a lock on the specified benaphore. If the lock on a benaphore is already held, this procedure also blocks the execution of the current thread, until the lock could be acquired.

    Once a lock is acquired, all threads attempting to take a lock will be blocked from entering any critical sections associated with the same benaphore, until until the lock is released.

    benaphore_try_lock ¶

    benaphore_try_lock :: proc "contextless" (b: ^Benaphore) -> bool {…}
     

    Try to acquire a lock on a benaphore.

    This procedure tries to acquire a lock on the specified benaphore. If it was already locked, then the returned value is false, otherwise the lock is acquired and the procedure returns true.

    If the lock is acquired, all threads that attempt to acquire a lock will be blocked from entering any critical sections associated with the same benaphore, until the lock is released.

    benaphore_unlock ¶

    benaphore_unlock :: proc "contextless" (b: ^Benaphore) {…}
     

    Release a lock on a benaphore.

    This procedure releases a lock on the specified benaphore. If any of the threads are waiting on the lock, exactly one thread is allowed into a critical section associated with the same benaphore.

    cond_broadcast ¶

    cond_broadcast :: proc "contextless" (c: ^Cond) {…}
     

    Wake up all threads that wait on a condition variable.

    This procedure causes all threads waiting on the condition variable to wake up.

    cond_signal ¶

    cond_signal :: proc "contextless" (c: ^Cond) {…}
     

    Wake up one thread that waits on a condition variable.

    This procedure causes exactly one thread waiting on the condition variable to wake up.

    cond_wait ¶

    cond_wait :: proc "contextless" (c: ^Cond, m: ^Mutex) {…}
     

    Wait until the condition variable is signalled and release the associated mutex.

    This procedure blocks the current thread until the specified condition variable is signalled, or until a spurious wakeup occurs. In addition, if the condition has been signalled, this procedure releases the lock on the specified mutex.

    The mutex must be held by the calling thread, before calling the procedure.

    Note: This procedure can return on a spurious wake-up, even if the condition variable was not signalled by a thread.

    cond_wait_with_timeout ¶

    cond_wait_with_timeout :: proc "contextless" (c: ^Cond, m: ^Mutex, duration: time.Duration) -> bool {…}
     

    Wait until the condition variable is signalled or timeout is reached and release the associated mutex.

    This procedure blocks the current thread until the specified condition variable is signalled, a timeout is reached, or until a spurious wakeup occurs. In addition, if the condition has been signalled, this procedure releases the lock on the specified mutex.

    If the timeout was reached, this procedure returns false. Otherwise it returns true.

    Before this procedure is called the mutex must be held by the calling thread.

    cpu_relax ¶

    cpu_relax :: intrinsics.cpu_relax
     

    This procedure may lower CPU consumption or yield to a hyperthreaded twin processor. It's exact function is architecture specific, but the intent is to say that you're not doing much on a CPU.

    current_thread_id ¶

    current_thread_id :: proc "contextless" () -> int {…}
     

    Obtain the current thread ID.

    futex_broadcast ¶

    futex_broadcast :: proc "contextless" (f: ^Futex) {…}
     

    Wake up multiple threads waiting on a futex.

    futex_signal ¶

    futex_signal :: proc "contextless" (f: ^Futex) {…}
     

    Wake up a single thread waiting on a futex.

    futex_wait ¶

    futex_wait :: proc "contextless" (f: ^Futex, expected: u32) {…}
     

    Sleep if the futex contains the expected value until it's signalled.

    If the value of the futex is expected, this procedure blocks the execution of the current thread, until the futex is woken up, or until a spurious wakeup occurs.

    futex_wait_with_timeout ¶

    futex_wait_with_timeout :: proc "contextless" (f: ^Futex, expected: u32, duration: time.Duration) -> bool {…}
     

    Sleep if the futex contains the expected value until it's signalled or the timeout is reached.

    If the value of the futex is expected, this procedure blocks the execution of the current thread, until the futex is signalled, a timeout is reached, or until a spurious wakeup occurs.

    This procedure returns false if the timeout was reached, true otherwise.

    mutex_guard ¶

    mutex_guard :: proc "contextless" (m: ^Mutex) -> bool {…}
     

    Guard the current scope with a lock on a mutex.

    This procedure acquires a mutex lock. The lock is automatically released at the end of callee's scope. If the mutex was already locked, this procedure also blocks until the lock can be acquired.

    When a lock has been acquired, all threads attempting to acquire a lock will be blocked from entering any critical sections associated with the mutex, until the lock is released.

    This procedure always returns true. This makes it easy to define a critical section by putting the function inside the if statement.

    Example:

    if mutex_guard(&m) {
    	...
    }
    

    mutex_lock ¶

    mutex_lock :: proc "contextless" (m: ^Mutex) {…}
     

    Acquire a lock on a mutex.

    This procedure acquires a lock with the specified mutex. If the mutex has been already locked by any thread, this procedure also blocks until the lock can be acquired.

    Once the lock is acquired, all other threads that attempt to acquire a lock will be blocked from entering any critical sections associated with the same mutex, until the the lock is released.

    Note: If the mutex is already locked by the current thread, a call to this procedure will block indefinately. Do not use this in recursive procedures.

    mutex_try_lock ¶

    mutex_try_lock :: proc "contextless" (m: ^Mutex) -> bool {…}
     

    Try to acquire a lock on a mutex.

    This procedure tries to acquire a lock on the specified mutex. If it was already locked, then the returned value is false, otherwise the lock is acquired and the procedure returns true.

    If the lock is acquired, all threads that attempt to acquire a lock will be blocked from entering any critical sections associated with the same mutex, until the lock is released.

    mutex_unlock ¶

    mutex_unlock :: proc "contextless" (m: ^Mutex) {…}
     

    Release a lock on a mutex.

    This procedure releases the lock associated with the specified mutex. If the mutex was not locked, this operation is a no-op.

    When the current thread, that holds a lock to the mutex calls mutex_unlock, this allows one other thread waiting on the mutex to enter any critical sections associated with the mutex. If there are no threads waiting on the mutex, the critical sections will remain open.

    once_do_with_data ¶

    once_do_with_data :: proc(o: ^Once, fn: proc(data: rawptr), data: rawptr) {…}
     

    Call a function with data once.

    once_do_with_data_contextless ¶

    once_do_with_data_contextless :: proc "contextless" (o: ^Once, fn: proc "contextless" (data: rawptr), data: rawptr) {…}
     

    Call a contextless function with data once.

    once_do_without_data ¶

    once_do_without_data :: proc(o: ^Once, fn: proc()) {…}
     

    Call a function with no data once.

    once_do_without_data_contextless ¶

    once_do_without_data_contextless :: proc(o: ^Once, fn: proc "contextless" ()) {…}
     

    Call a contextless function with no data once.

    one_shot_event_signal ¶

    one_shot_event_signal :: proc "contextless" (e: ^One_Shot_Event) {…}
     

    Make event available.

    one_shot_event_wait ¶

    one_shot_event_wait :: proc "contextless" (e: ^One_Shot_Event) {…}
     

    Block until the event is made available.

    This procedure blocks the execution of the current thread, until the event is made available.

    park ¶

    park :: proc "contextless" (p: ^Parker) {…}
     

    Blocks until the token is available.

    This procedure blocks the execution of the current thread, until a token is made available.

    Note: This procedure assumes this is only called by the thread that owns the Parker.

    park_with_timeout ¶

    park_with_timeout :: proc "contextless" (p: ^Parker, duration: time.Duration) {…}
     

    Blocks until the token is available with timeout.

    This procedure blocks the execution of the current thread until a token is made available, or until the timeout has expired, whatever happens first.

    Note: This procedure assumes this is only called by the thread that owns the Parker.

    recursive_benaphore_guard ¶

    recursive_benaphore_guard :: proc "contextless" (m: ^Recursive_Benaphore) -> bool {…}
     

    Guard the current scope with a recursive benaphore.

    This procedure acquires a lock on the specified recursive benaphores and automatically releases it at the end of the callee's scope. If the recursive benaphore was already held by a another thread, this procedure also blocks until the lock can be acquired.

    When the lock is acquired all other threads attempting to take a lock will be blocked from entering any critical sections associated with the same benaphore, until the lock is released.

    This procedure always returns true, which makes it easy to define a critical section by calling this procedure inside an if statement.

    Example:

    if recursive_benaphore_guard(&m) {
    	...
    }
    

    recursive_benaphore_lock ¶

    recursive_benaphore_lock :: proc "contextless" (b: ^Recursive_Benaphore) {…}
     

    Acquire a lock on a recursive benaphore.

    This procedure acquires a lock on a recursive benaphore. If the benaphore is held by another thread, this function blocks until the lock can be acquired.

    Once a lock is acquired, all other threads attempting to acquire a lock will be blocked from entering any critical sections associated with the same recursive benaphore, until the lock is released.

    recursive_benaphore_try_lock ¶

    recursive_benaphore_try_lock :: proc "contextless" (b: ^Recursive_Benaphore) -> bool {…}
     

    Try to acquire a lock on a recursive benaphore.

    This procedure attempts to acquire a lock on recursive benaphore. If the benaphore is already held by a different thread, this procedure returns false. Otherwise the lock is acquired and the procedure returns true.

    If the lock is acquired, all other threads attempting to acquire a lock will be blocked from entering any critical sections assciated with the same recursive benaphore, until the lock is released.

    recursive_benaphore_unlock ¶

    recursive_benaphore_unlock :: proc "contextless" (b: ^Recursive_Benaphore) {…}
     

    Release a lock on a recursive benaphore.

    This procedure releases a lock on the specified recursive benaphore. It also causes the critical sections associated with the same benaphore, to become open for other threads for entering.

    recursive_mutex_guard ¶

    recursive_mutex_guard :: proc "contextless" (m: ^Recursive_Mutex) -> bool {…}
     

    Guard the scope with a recursive mutex lock.

    This procedure acquires a lock on the specified recursive mutex and automatically releases it at the end of the callee's scope. If the recursive mutex was already held by a another thread, this procedure also blocks until the lock can be acquired.

    When the lock is acquired all other threads attempting to take a lock will be blocked from entering any critical sections associated with the same mutex, until the lock is released.

    This procedure always returns true, which makes it easy to define a critical section by calling this procedure inside an if statement.

    Example:

    if recursive_mutex_guard(&m) {
    	...
    }
    

    recursive_mutex_lock ¶

    recursive_mutex_lock :: proc "contextless" (m: ^Recursive_Mutex) {…}
     

    Acquire a lock on a recursive mutex.

    This procedure acquires a lock on the specified recursive mutex. If the lock is acquired by a different thread, this procedure also blocks until the lock can be acquired.

    When the lock is acquired, all other threads attempting to acquire a lock will be blocked from entering any critical sections associated with the same mutex, until the lock is released.

    recursive_mutex_try_lock ¶

    recursive_mutex_try_lock :: proc "contextless" (m: ^Recursive_Mutex) -> bool {…}
     

    Try to acquire a lock on a recursive mutex.

    This procedure attempts to acquire a lock on the specified recursive mutex. If the recursive mutex is locked by other threads, this procedure returns false. Otherwise it locks the mutex and returns true.

    If the lock is acquired, all other threads attempting to obtain a lock will be blocked from entering any critical sections associated with the same mutex, until the lock is released.

    recursive_mutex_unlock ¶

    recursive_mutex_unlock :: proc "contextless" (m: ^Recursive_Mutex) {…}
     

    Release a lock on a recursive mutex.

    This procedure releases a lock on the specified recursive mutex. It also causes the critical sections associated with the same mutex, to become open for other threads for entering.

    rw_mutex_guard ¶

    rw_mutex_guard :: proc "contextless" (m: ^RW_Mutex) -> bool {…}
     

    Guard the current scope with an exclusive lock on a read-write mutex.

    This procedure acquires an exclusive lock on the specified read-write mutex. This procedure automatically releases the lock at the end of the callee's scope. If the mutex was already locked by readers or a writer, this procedure blocks, until a lock can be acquired.

    When an exclusive lock is acquired, all other threads attempting to acquire an exclusive lock will be blocked from entering any critical sections associated with the same read-write mutex, until the exclusive lock is released.

    This procedure always returns true, which makes it easy to define a critical section by running this procedure inside an if statement.

    Example:

    if rw_mutex_guard(&m) {
    	...
    }
    

    rw_mutex_lock ¶

    rw_mutex_lock :: proc "contextless" (rw: ^RW_Mutex) {…}
     

    Acquire an exclusive lock.

    This procedure acquires an exclusive lock on the specified read-write mutex. If the lock is already held by any thread, this procedure also blocks until the lock can be acquired.

    After a lock has been acquired, any thread attempting to acquire any lock will be blocked from entering any critical sections associated with the same read-write mutex, until the exclusive lock is released.

    rw_mutex_shared_guard ¶

    rw_mutex_shared_guard :: proc "contextless" (m: ^RW_Mutex) -> bool {…}
     

    Guard the current scope with a shared lock on a read-write mutex.

    This procedure acquires a shared lock on the specified read-write mutex. This procedure automatically releases the lock at the end of the callee's scope. If the mutex already has an associated exclusive lock, this procedure blocks, until a lock can be acquired.

    When a shared lock is obtained, all other threads attempting to obtain an exclusive lock will be blocked from any critical sections, associated with the same read-write mutex, until all shared locks are released.

    This procedure always returns true, which makes it easy to define a critical section by running this procedure inside an if statement.

    Example:

    if rw_mutex_guard(&m) {
    	...
    }
    

    rw_mutex_shared_lock ¶

    rw_mutex_shared_lock :: proc "contextless" (rw: ^RW_Mutex) {…}
     

    Acquire a shared lock on a read-write mutex.

    This procedure acquires a shared lock on the specified read-write mutex. If the mutex already has an exclusive lock held, this procedure also blocks until the lock can be acquired.

    After the shared lock is obtained, all threads attempting to acquire an exclusive lock will be blocked from entering any critical sections associated with the same read-write mutex, until all shared locks associated with the specified read-write mutex are released.

    rw_mutex_shared_unlock ¶

    rw_mutex_shared_unlock :: proc "contextless" (rw: ^RW_Mutex) {…}
     

    Release the shared lock on a read-write mutex.

    This procedure releases shared lock on the specified read-write mutex. When all shared locks are released, all critical sections associated with the same read-write mutex become open to other threads.

    rw_mutex_try_lock ¶

    rw_mutex_try_lock :: proc "contextless" (rw: ^RW_Mutex) -> bool {…}
     

    Try to acquire an exclusive lock on a read-write mutex.

    This procedure tries to acquire an exclusive lock on the specified read-write mutex. If the mutex was already locked, the procedure returns false. Otherwise it acquires the exclusive lock and returns true.

    If the lock has been acquired, all threads attempting to acquire any lock will be blocked from entering any critical sections associated with the same read-write mutex, until the exclusive locked is released.

    rw_mutex_try_shared_lock ¶

    rw_mutex_try_shared_lock :: proc "contextless" (rw: ^RW_Mutex) -> bool {…}
     

    Try to acquire a shared lock on a read-write mutex.

    This procedure attempts to acquire a lock on the specified read-write mutex. If the mutex already has an exclusive lock held, this procedure returns false. Otherwise, it acquires the lock on the mutex and returns true.

    If the shared lock has been acquired, it causes all threads attempting to acquire the exclusive lock to be blocked from entering any critical sections associated with the same read-write mutex, until all shared locks are released.

    rw_mutex_unlock ¶

    rw_mutex_unlock :: proc "contextless" (rw: ^RW_Mutex) {…}
     

    Release an exclusive lock.

    This procedure releases an exclusive lock associated with the specified read-write mutex.

    When the exclusive lock is released, all critical sections, associated with the same read-write mutex, become open to other threads.

    sema_post ¶

    sema_post :: proc "contextless" (s: ^Sema, count: int = 1) {…}
     

    Increment the internal counter on a semaphore by the specified amount.

    This procedure increments the internal counter of the semaphore. If any of the threads were waiting on the semaphore, up to count of threads will continue the execution and enter the critical section.

    sema_wait ¶

    sema_wait :: proc "contextless" (s: ^Sema) {…}
     

    Wait on a semaphore until the internal counter is non-zero.

    This procedure blocks the execution of the current thread, until the semaphore counter is non-zero, and atomically decrements it by one, once the wait has ended.

    sema_wait_with_timeout ¶

    sema_wait_with_timeout :: proc "contextless" (s: ^Sema, duration: time.Duration) -> bool {…}
     

    Wait on a semaphore until the internal counter is non-zero or a timeout is reached.

    This procedure blocks the execution of the current thread, until the semaphore counter is non-zero, and if so atomically decrements it by one, once the wait has ended. If the specified timeout is reached, the function returns false, otherwise it returns true.

    ticket_mutex_guard ¶

    ticket_mutex_guard :: proc "contextless" (m: ^Ticket_Mutex) -> bool {…}
     

    Guard the current scope with a lock on a ticket mutex.

    This procedure acquires a lock on a ticket mutex. The lock is automatically released at the end of callee's scope. If the mutex was already locked, this procedure also blocks until the lock can be acquired.

    When a lock has been acquired, all threads attempting to acquire a lock will be blocked from entering any critical sections associated with the ticket mutex, until the lock is released.

    This procedure always returns true. This makes it easy to define a critical section by putting the function inside the if statement.

    Example:

    if ticket_mutex_guard(&m) {
    	...
    }
    

    ticket_mutex_lock ¶

    ticket_mutex_lock :: proc "contextless" (m: ^Ticket_Mutex) {…}
     

    Acquire a lock on a ticket mutex.

    This procedure acquires a lock on a ticket mutex. If the ticket mutex is held by another thread, this procedure also blocks the execution until the lock can be acquired.

    Once the lock is acquired, any thread calling ticket_mutex_lock will be blocked from entering any critical sections associated with the same ticket mutex, until the lock is released.

    ticket_mutex_unlock ¶

    ticket_mutex_unlock :: proc "contextless" (m: ^Ticket_Mutex) {…}
     

    Release a lock on a ticket mutex.

    This procedure releases the lock on a ticket mutex. If any of the threads are waiting to acquire the lock, exactly one of those threads is unblocked and allowed into the critical section.

    unpark ¶

    unpark :: proc "contextless" (p: ^Parker) {…}
     

    Make the token available.

    wait_group_add ¶

    wait_group_add :: proc "contextless" (wg: ^Wait_Group, delta: int) {…}
     

    Increment an internal counter of a wait group.

    This procedure atomically increments a number to the specified wait group's internal counter by a specified amount. This operation can be done on any thread.

    wait_group_done ¶

    wait_group_done :: proc "contextless" (wg: ^Wait_Group) {…}
     

    Signal work done by a thread in a wait group.

    This procedure decrements the internal counter of the specified wait group and wakes up the waiting thread. Once the internal counter reaches zero, the waiting thread resumes execution.

    wait_group_wait ¶

    wait_group_wait :: proc "contextless" (wg: ^Wait_Group) {…}
     

    Wait for all worker threads in the wait group.

    This procedure blocks the execution of the current thread, until the specified wait group's internal counter reaches zero.

    wait_group_wait_with_timeout ¶

    wait_group_wait_with_timeout :: proc "contextless" (wg: ^Wait_Group, duration: time.Duration) -> bool {…}
     

    Wait for all worker threads in the wait group, or until timeout is reached.

    This procedure blocks the execution of the current thread, until the specified wait group's internal counter reaches zero, or until the timeout is reached.

    This procedure returns false, if the timeout was reached, true otherwise.

    Procedure Groups

    once_do ¶

     

    Call a function once.

    The once_do procedure group calls a specified function, if it wasn't already called from the perspective of a specific Once struct.

    shared_guard ¶

     
    Example:
    if shared_guard(&m) {
    	...
    }
    

    shared_lock ¶

     

    shared_lock locks rw for reading (with arbitrary number of readers)

    shared_unlock ¶

     

    shared_unlock unlocks rw for reading (with arbitrary number of readers)

    try_shared_lock ¶

     

    try_shared_lock tries to lock rw for reading (with arbitrary number of readers)

    Source Files

    Generation Information

    Generated with odin version dev-2024-10 (vendor "odin") Windows_amd64 @ 2024-10-21 21:11:07.697086100 +0000 UTC