
Security News
/Research
Fake Corepack Site Distributes Infostealer and Proxyware to Developers
A fake corepack.org site is impersonating the Node.js tool and delivers an infostealer and proxyware to developers who download it.
darvaza.org/x/syncPackage sync provides interfaces and utilities for synchronisation
primitives.
This package defines standardised interfaces for synchronisation primitives that complement the standard library while providing additional functionality.
The primitives handle panic situations that may arise from underlying mutexes. When panics occur (typically indicating development mistakes rather than runtime errors), they are aggregated while enabling proper clean-up of other locks. This approach ensures resources are properly released rather than leaked, even during panic scenarios.
Mutex and RWMutex interfaces.sync/atomic for bit-mask OR and max-value
updates.darvaza.org/x/sync: The main package namespace.
atomic: Shadows the standard library sync/atomic
package and adds helpers for bit-mask OR and monotonic max updates.cond: Contains condition-based synchronisation
primitives for coordinating goroutines.errors: Contains error types and helpers for
implementing common synchronisation primitives.mutex: Contains interfaces and utilities for mutex
operations.semaphore: Provides a cancellable read-write mutex
implementation with counting semaphore algorithms.spinlock: Contains a lightweight spinlock
implementation of mutex.Mutex.workgroup: Provides concurrent task management and
synchronisation within a shared lifecycle.The cond package complements the other synchronisation primitives in the
darvaza.org/x/sync package:
Barrier provides building blocks that other
synchronisation mechanisms like semaphore can use internally.The addition of the cond package makes the darvaza.org/x/sync package
more complete by addressing a broader range of concurrency control
scenarios beyond just mutual exclusion, enabling more sophisticated
coordination between concurrent operations.
This completes the synchronisation primitive ecosystem with:
mutex).spinlock).semaphore).cond).The core interface for mutual exclusion operations:
type Mutex interface {
// Lock acquires the mutex, blocking until it is available.
Lock()
// TryLock attempts to acquire the mutex without blocking.
// Returns true if the lock was acquired, false otherwise.
TryLock() bool
// Unlock releases the mutex.
// Calling Unlock on an unlocked mutex is expected to panic.
Unlock()
}
The standard library's sync.Mutex{} and sync.RWMutex{} implement this
interface.
Extends the Mutex interface with read-locking capabilities:
type RWMutex interface {
Mutex
// RLock acquires a read lock on the mutex, blocking until available.
RLock()
// TryRLock attempts to acquire a read lock without blocking.
// Returns true if the lock was acquired, false otherwise.
TryRLock() bool
// RUnlock releases a read lock on the mutex.
// Calling RUnlock without holding a read lock is expected to panic.
RUnlock()
}
The standard library's sync.RWMutex{} implements this interface.
The package provides context-aware interfaces extending the basic mutex interfaces:
type MutexContext interface {
Mutex
// LockContext acquires the mutex with context awareness.
// It blocks until the lock is acquired or the context is done.
// Returns an error if the context is cancelled or times out.
LockContext(context.Context) error
}
type RWMutexContext interface {
RWMutex
MutexContext
// RLockContext acquires a read lock with context awareness.
// It blocks until the read lock is acquired or the context is done.
// Returns an error if the context is cancelled or times out.
RLockContext(context.Context) error
}
These interfaces serve primarily as extension points for implementers. Although standard library mutex types don't implement them directly, the package provides helper functions to work with these interfaces. Custom mutex implementations can adopt these interfaces to provide context-aware locking capabilities that respect cancellation and timeouts.
The cond package provides a Barrier type that implements a coordination
mechanism for goroutines using a token-based approach.
type Barrier struct{}
A Barrier manages a reusable token that can be used to signal state changes
and coordinate access to shared resources. It's primarily designed to be used
by other synchronisation primitives internally.
Each Barrier instance needs to be initialised before use and closed when
no longer needed to release resources.
Broadcast(): Notifies all waiting goroutines at once.Signal() bool: Attempts to wake up a single waiting goroutine.Wait(): Blocks until the barrier is signalled.Signaled() <-chan struct{}: Returns a channel for select-based waiting.Acquire()/Release(Token): Manual token acquisition and release for
fine-grained control.The Token type is a channel-based synchronisation primitive that allows
goroutines to wait for and signal state changes:
type Token chan struct{}
Tokens can be acquired from a barrier, waited upon, signalled individually, or closed to wake up all waiters simultaneously.
errors package for common failure modes.The cond package also provides a Count type that combines features of a
condition variable and an atomic counter.
type Count struct{}
A Count allows atomic operations and waiting on an int32 value until specific
conditions are met. This enables goroutines to coordinate based on a numeric
value and user-defined conditions.
Each Count instance needs to be initialised and closed properly to avoid
resource leaks.
Add(n int) int: Atomically adds n to the counter and returns the new value.Inc() int: Atomically increments the counter by 1.Dec() int: Atomically decrements the counter by 1.Value() int: Returns the current counter value.Wait(): Blocks until the counter becomes zero.WaitFn(func(int32) bool): Blocks until the provided condition function
returns true.WaitFnContext(context.Context, func(int32) bool): Context-aware waiting
with cancellation support.Reset(n int): Resets the counter to the specified value and wakes all
waiting goroutines.Signal() bool: Wakes a single waiting goroutine.Broadcast(): Wakes all waiting goroutines.Barrier type internally for goroutine coordination.The cond package provides a specialised variant of Count called
CountZero that broadcasts specifically when the counter reaches zero.
type CountZero Count
This specialisation simplifies coordination in cases where completion is signified by a zero value, which is a common pattern in many concurrent applications.
Count.The CountZero type is implemented as a thin wrapper around Count with a
predefined condition function that checks for zero. It provides equivalent
functionality with these key differences:
CountZero provides the same atomic counter operations as Count (Add,
Inc, Dec, Value) and similar coordination methods with simpler
signatures:
Wait(): Blocks until the counter becomes zero.WaitAbort(<-chan struct{}): Blocks until zero or abort channel closes.WaitContext(context.Context): Blocks until zero or context cancellation.The CountZero type excels in scenarios such as:
// Create a counter to track 5 operations
counter := cond.NewCountZero(5)
defer counter.Close()
for i := 0; i < 5; i++ {
go func() {
// Perform work
// Decrement counter when done
counter.Dec()
}()
}
// Wait for all operations to complete.
if err := counter.Wait(); err != nil {
// Handle error.
}
// All operations complete when counter reaches zero.
CountZero provides a concise way to express the common pattern of
waiting for a counter to reach zero without the need for custom condition
functions.
The semaphore package provides a Semaphore type that implements both
exclusive and shared access patterns using a counting semaphore algorithm.
type Semaphore struct{}
The Semaphore fully implements the context-aware mutex interfaces:
sync.Lockermutex.Mutexmutex.MutexContext - supporting context cancellation and timeouts.mutex.RWMutexmutex.RWMutexContext - supporting context cancellation and timeouts.This makes it compatible with all lock operations provided by the package, with comprehensive capabilities for both exclusive and shared access patterns.
Lock(): Acquires exclusive lock, panics on error.LockContext(ctx context.Context) error: Acquires exclusive lock with
context cancellation support.TryLock() bool: Attempts non-blocking acquisition of exclusive lock.TryLockContext(ctx context.Context) (bool, error): Non-blocking attempt
with context support.Unlock(): Releases exclusive lock, panics on error.RLock(): Acquires a read lock, panics on error.RLockContext(ctx context.Context) error: Acquires read lock with context
cancellation support.TryRLock() bool: Attempts non-blocking acquisition of read lock.TryRLockContext(ctx context.Context) (bool, error): Non-blocking attempt
with context support.RUnlock(): Releases a read lock, panics on error.The semaphore provides advanced synchronisation combining features of both mutexes and traditional semaphores, with integrated context-awareness for cancellation and timeout handling.
The spinlock package provides a lightweight spinlock implementation for
scenarios where locks are held for very brief periods.
type SpinLock uint32
SpinLock is a mutual exclusion primitive that uses active spinning
(busy-waiting) instead of parking goroutines. It implements both the
sync.Locker and mutex.Mutex interfaces.
Lock(): Acquires the lock, spinning until successful.TryLock() bool: Attempts to acquire the lock without blocking.Unlock(): Releases the lock.var lock spinlock.SpinLock
// In concurrent code:
lock.Lock()
defer lock.Unlock()
// Critical section here (keep it very brief)
runtime.Gosched() while spinning to yield the processor.Benchmark testing shows SpinLock is efficient for operations that complete quickly, as it avoids the overhead of parking and unparking goroutines or using channels.
The workgroup package provides concurrent task management and synchronisation
for coordinating multiple operations within a shared lifecycle.
type Group struct{}
Unlike sync.WaitGroup, the workgroup.Group integrates with contexts for
cancellation propagation and lifecycle management of concurrent operations.
Close: cancels the Group and drains all tasks.Context() context.Context: Returns the context associated with the Group.Err() error: Returns the cancellation cause, if any.IsCancelled() bool: Reports whether the Group has been cancelled.Cancelled() <-chan struct{}: Returns a channel closed on cancellation.Done() <-chan struct{}: Returns a channel closed when all tasks complete.Wait() error: Blocks until all tasks complete.Cancel(error) bool: Cancels the Group with an optional error cause.Close() error: Cancels the Group and waits for all tasks to complete.Go(func(context.Context)) error: Spawns a new goroutine with context.GoCatch(func(context.Context) error, func(context.Context, error) error) error: Spawns a goroutine with error handling and error-triggered
cancellation.GoShutdown(func(context.Context) error, func(context.Context), time.Duration) error: Spawns a supervised task paired with a shutdown
handler that signals it to end when the Group is cancelled while it is
still running — the http.Server ListenAndServe/Shutdown pattern
for workers that cannot act on the Group's context.wg := workgroup.New(ctx)
defer wg.Close()
// Add tasks to the workgroup
wg.Go(func(ctx context.Context) {
// Task implementation with context-based cancellation
select {
case <-ctx.Done():
return // respond to cancellation
case <-time.After(1 * time.Second):
// do work
}
})
// Wait for all tasks to complete or context to be cancelled
if err := wg.Wait(); err != nil {
// Handle error.
}
OnCancel hook that fires on cancellation from any source —
an explicit Cancel/Close or the parent context. The handler receives
the cancellation cause and a live context detached from the Group's
cancellation (via context.WithoutCancel): it retains the Group context's
values but is not itself cancelled, so cleanup work can pass it along or
build its own deadline on top.GoShutdown pairs a task with a shutdown handler in a single tracked
unit. The handler's one job is to tell a worker that cannot act on the
Group's context to end: it runs at most once, only when the Group is
cancelled while the task is still running, and receives a live, detached
context bounded by the grace period (unbounded when the grace period is
zero or less). A task that ends on its own needs no signal — an error
still cancels the Group, but the handler is not invoked. With a nil
task the handler is enrolled alone as a watcher: the per-resource
counterpart to the per-Group OnCancel hook — one enrolled for each
resource to release on cancellation, grace-bounded, without the cause.
Like the OnCancel handler, a panic in the shutdown handler is
recovered and discarded.The atomic package shadows the standard library sync/atomic package and
adds helpers for patterns recurring in synchronisation primitives.
The standard-library atomic types (Bool, Int32, Int64, Uint32,
Uint64, Uintptr, Value, Pointer[T]) are re-exported as aliases so
callers using the type-based API can reach both the stdlib types and the
extension helpers through a single import of darvaza.org/x/sync/atomic.
The legacy free-function API (AddInt32, LoadInt32, ...) is intentionally
omitted; new code should use the type-based methods that supersede it since
Go 1.19. Callers that still need those functions should keep their
sync/atomic import alongside this one.
BitmaskOr(p *Uint32, mask uint32) (uint32, bool): Atomically applies a
bitwise OR of mask to *p, returning the resulting value and whether
any bits actually changed. The boolean signals first-writer semantics for
the supplied mask; callers wanting a one-shot "target reached"
notification gate on changed && result == target.UpdateMax(p *Int32, val int32) int32: Atomically raises *p to val
when val is greater than the current value; no-op otherwise. Returns
the value the caller raised *p to, or the value observed when no update
was performed. *p is guaranteed to be at least the returned value after
the call, but may already be higher under contention.First-writer notification per bit:
import "darvaza.org/x/sync/atomic"
var bits atomic.Uint32
if _, changed := atomic.BitmaskOr(&bits, 0x01); changed {
// first writer to set this bit
}
One-shot "target reached" notification when the last expected bit lands:
import "darvaza.org/x/sync/atomic"
var bits atomic.Uint32
const target = uint32(0b111) // all three bits expected
myBit := uint32(0b010) // the bit this caller is responsible for
result, changed := atomic.BitmaskOr(&bits, myBit)
if changed && result == target {
// exactly one writer reaches here: the one whose OR completed target
}
The package provides functions that make mutex operations safer by handling edge cases and panic conditions:
mutex.SafeLock[T sync.Locker](mu T) (bool, error): Safely acquires an
exclusive lock, handling nil mutexes and panics.mutex.SafeRLock[T sync.Locker](mu T) (bool, error): Safely acquires a
read lock (or normal lock if not RWMutex).mutex.SafeTryLock[T mutex.Mutex](mu T) (bool, error): Non-blocking
attempt to acquire a lock with nil and panic handling.mutex.SafeTryRLock[T mutex.Mutex](mu T) (bool, error): Non-blocking
attempt to acquire a read lock safely.mutex.SafeUnlock[T sync.Locker](mu T) error: Safely releases a lock,
handling nil mutexes and panics.mutex.SafeRUnlock[T sync.Locker](mu T) error: Safely releases a read
lock (or normal lock if not RWMutex).mutex.Lock[T mutex.Mutex](locks ...T): Acquires multiple locks in order.mutex.TryLock[T mutex.Mutex](locks ...T) bool: Non-blocking attempt to
acquire multiple locks.mutex.RLock[T mutex.Mutex](locks ...T): Acquires multiple read locks
when possible.mutex.TryRLock[T mutex.Mutex](locks ...T) bool: Non-blocking attempt to
acquire multiple read locks.mutex.Unlock(locks ...mutex.Mutex): Releases multiple locks.mutex.RUnlock(locks ...mutex.Mutex): Releases multiple read locks
safely.mutex.ReverseUnlock[T Mutex](unlock func(T) error, locks ...T) error:
Releases locks in reverse order, collecting any panics.NewSafeLockContext[T MutexContext](ctx context.Context) func(mu T) (bool, error): Creates a function for context-aware locking.NewSafeRLockContext[T MutexContext](ctx context.Context) func(mu T) (bool, error): Creates a function for context-aware read locking.SafeLockContext[T MutexContext](ctx context.Context, mu T) (bool, error):
Acquires a lock with context cancellation/timeout support.SafeRLockContext[T MutexContext](ctx context.Context, mu T) (bool, error):
Acquires a read lock with context cancellation/timeout support.These utility functions provide:
The errors sub-package defines error types for common
synchronisation issues:
ErrAlreadyInitialised: Returned when a primitive that was already
initialised is being initialised again.ErrNotInitialised: Returned when a primitive was expected to be
initialised but was not.ErrClosed: Returned when operations cannot proceed because the target is
closed.ErrNilContext: Returned when a nil context is encountered in
context-aware operations.ErrNilMutex: Returned when a Mutex was expected but none was provided.ErrNilReceiver: Returned when methods are called on a nil receiver.The package provides CompoundError, a concurrency-safe counterpart of
core.CompoundError that accumulates errors reported from several goroutines
and presents them as a single error. Errors and Unwrap return snapshot
copies so callers can iterate without holding the lock, while AsError
returns the receiver itself; the zero value is ready to use.
Internally the package uses core.CompoundError to collect and combine
multiple errors that may occur during operations on multiple mutexes. This
allows for unlocking all mutexes even when some operations fail, while still
providing comprehensive error reporting.
core.Catch() and core.PanicError convert panics into regular errors with
stack traces.
This package follows specific patterns for handling error conditions:
Panic conditions indicate programming mistakes rather than runtime conditions that should be handled differently. This approach was chosen because:
For context-aware operations (using MutexContext and RWMutexContext
interfaces), explicit error handling is provided to manage cancellation and
timeout scenarios, which are considered valid runtime conditions rather than
programming errors.
This package only depends on the standard library and
darvaza.org/core.
This project is licensed under the MIT Licence. See LICENCE.txt for details.
go get darvaza.org/x/sync
For development guidelines, architecture notes, and AI agent instructions, see AGENTS.md.
FAQs
Unknown package
Did you know?

Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.

Security News
/Research
A fake corepack.org site is impersonating the Node.js tool and delivers an infostealer and proxyware to developers who download it.

Research
/Security News
A large-scale campaign abused GitHub Actions in compromised repositories to exploit CVE-2026-41940 in cPanel and WHM and steal server credentials.

Security News
Five frontier LLMs generated the same nonexistent package names, leaving 53 available for potential slopsquatting across PyPI and npm.