goroutines #
goroutines
Go-style goroutine runtime for V, implementing the GMP (Goroutine-Machine-Processor) scheduling model translated from the Go runtime (src/runtime/proc.go, runtime2.go, chan.go).
Overview
This module provides lightweight goroutines for V's go keyword, as opposed to spawn which creates OS threads.
GMP Model
- G (Goroutine): Lightweight unit of execution with its own stack (~8KB default)
- M (Machine): OS thread that executes goroutines
- P (Processor): Logical processor with a local run queue (one per CPU core)
Key Features
- Work stealing: Idle processors steal work from busy ones
- Local run queues: Lock-free per-P queues minimize contention
- Global run queue: Overflow and fairness mechanism
- Goroutine parking: Efficient blocking/unblocking for channels
- G reuse: Dead goroutines are recycled to reduce allocation
Usage
// `go` launches a goroutine (lightweight, scheduled by GMP)
go expensive_computation()
// `spawn` launches an OS thread (traditional V behavior)
spawn blocking_io_task()
Architecture
Translated from Go's runtime source:
| Go Source | V Module File | Purpose |
|---|---|---|
runtime2.go |
goroutines.v |
Core data structures (G, M, P, Sched) |
proc.go |
scheduler.v |
Scheduler loop, work stealing, run queues |
proc.go |
park.v |
gopark/goready, Sudog, WaitQ |
proc.go |
init.v |
Initialization (schedinit, procresize) |
chan.go |
chan.v |
Channel implementation |
| asm (gogo/gosave) | context_nix.c.v |
Context switching (ucontext) |
| asm (gogo/gosave) | context_windows.c.v |
Context switching (Windows fibers) |
References
fn chan_cap #
fn chan_cap(c &Chan) int
chan_cap returns the capacity of the channel buffer.
fn chan_close #
fn chan_close(c &Chan)
chan_close closes the channel. Translated from Go's closechan() in chan.go.
fn chan_len #
fn chan_len(c &Chan) int
chan_len returns the number of elements in the channel buffer.
fn chan_make #
fn chan_make(elem_size int, buf_size int) &Chan
chan_make creates a new channel. If buf_size > 0, creates a buffered channel. Translated from Go's makechan() in chan.go.
fn chan_recv #
fn chan_recv(c &Chan, ep voidptr, block bool) (bool, bool)
chan_recv receives a value from the channel. If block is true, blocks until a value is available. Returns (received, ok). ok is false if channel is closed and empty. Translated from Go's chanrecv() in chan.go.
fn chan_send #
fn chan_send(c &Chan, ep voidptr, block bool) bool
chan_send sends a value on the channel. If block is true, blocks until the send can proceed. Returns true if the value was sent. Translated from Go's chansend() in chan.go.
fn context_init #
fn context_init(mut ctx Context, stack voidptr, stack_size int, entry_fn fn (voidptr), arg voidptr)
context_init initializes a context for a new goroutine. Sets up the context to run entry_fn with arg on the given stack.
fn context_set #
fn context_set(to &Context)
context_set switches to the given context without saving.
fn context_switch #
fn context_switch(mut from Context, to &Context)
context_switch saves the current context into from and switches to to.
fn get_current_g #
fn get_current_g() &Goroutine
get_current_g returns the currently running G.
fn gopark #
fn gopark(reason string)
gopark puts the current goroutine into a waiting state. The goroutine can be made runnable again by calling goready. reason describes why the goroutine is parking (for debugging). Translated from Go's gopark() in proc.go.
fn goready #
fn goready(gp &Goroutine)
goready puts a waiting goroutine back on a run queue. Translated from Go's goready() in proc.go.
fn goroutine_create #
fn goroutine_create(f voidptr, arg voidptr, arg_size int)
goroutine_create creates a new goroutine to run f with argument arg. This is the equivalent of Go's newproc function. Called by the compiler for go expr().
fn gosched #
fn gosched()
gosched yields the processor, allowing other goroutines to run. Translated from Go's Gosched() / goschedImpl() in proc.go.
fn num_goroutine #
fn num_goroutine() int
num_goroutine returns the number of goroutines that currently exist.
fn schedule #
fn schedule()
schedule is the main scheduler entry point. Finds a runnable goroutine and executes it. Never returns. Translated from Go's schedule() in proc.go.
fn set_max_procs #
fn set_max_procs(n int) int
set_max_procs changes the number of active processors. Returns the previous value. Translated from Go's GOMAXPROCS().
fn shutdown #
fn shutdown()
shutdown gracefully shuts down the goroutine scheduler.
type GoFn #
type GoFn = fn (voidptr)
GoFn is the type for a goroutine function: takes a voidptr argument.
enum GStatus #
enum GStatus {
idle // just allocated, not yet initialized
runnable // on a run queue, not currently executing
running // executing user code on an Machine
waiting // blocked (channel, mutex, etc.)
dead // finished execution, available for reuse
copystack // stack is being moved (not used yet)
}
GStatus represents goroutine states (matches Go's runtime2.go)
enum PStatus #
enum PStatus {
idle // not being used, available on idle list
running // owned by an Machine and executing code
stopped // halted
dead // no longer used
}
PStatus represents processor states
struct Chan #
struct Chan {
pub mut:
mu SpinLock // protects all fields (spinlock is ucontext-safe)
qcount u32 // total data in the queue
dataqsiz u32 // size of the circular buffer
buf voidptr // circular buffer for buffered channels
elemsize u16 // size of each element
closed bool // true if channel is closed
sendx u32 // send index into circular buffer
recvx u32 // receive index into circular buffer
recvq WaitQ // list of recv waiters
sendq WaitQ // list of send waiters
}
Chan is a goroutine-safe channel for communication between goroutines. Translated from Go's hchan struct in chan.go.
struct Context #
struct Context {
pub mut:
uctx C.ucontext_t
}
Context wraps ucontext_t for goroutine context switching.
struct Goroutine #
struct Goroutine {
pub mut:
id u64 // unique goroutine id
status GStatus = .idle // current state
stack voidptr // stack memory (allocated)
stack_size int = default_stack_size // stack allocation size
context Context // saved CPU context for switching (ucontext_t or similar)
fn_ptr voidptr // function to execute
fn_arg voidptr // argument to the function
sched_link &Goroutine = unsafe { nil } // linked list link for run queues
m &Machine = unsafe { nil } // current Machine executing this Goroutine (nil if not running)
parent_id u64 // goroutine id of creator
wait_reason string // if status==waiting, why
preempt bool // preemption signal
}
Goroutine represents a goroutine - the fundamental unit of concurrent execution. Translated from Go's type g struct in runtime2.go.
struct GoroutineList #
struct GoroutineList {
pub mut:
head &Goroutine = unsafe { nil }
count i32
}
GoroutineList is a list of Goroutine's.
struct GoroutineQueue #
struct GoroutineQueue {
pub mut:
head &Goroutine = unsafe { nil }
tail &Goroutine = unsafe { nil }
size i32
}
GoroutineQueue is a simple linked-list queue of Goroutine's (matches Go's gQueue).
struct Machine #
struct Machine {
pub mut:
id i64
g0 &Goroutine = unsafe { nil } // goroutine with scheduling stack
curg &Goroutine = unsafe { nil } // current running goroutine
p &Processor = unsafe { nil } // attached processor (nil if not executing Go code)
spinning bool // looking for work
blocked bool // blocked on a note
park sync.Semaphore // for parking/unparking
sched_link &Machine = unsafe { nil } // linked list for idle Machine list
thread thread // underlying OS thread handle
}
Machine represents a machine (OS thread) that executes goroutines. Translated from Go's type m struct in runtime2.go.
struct Processor #
struct Processor {
pub mut:
id i32
status PStatus = .idle
m &Machine = unsafe { nil } // back-link to associated Machine
sched_tick u32 // incremented on every scheduler call
// Local run queue - lock-free SPMC ring buffer (matches Go's design)
runq_head u32 // consumer index (atomic)
runq_tail u32 // producer index (atomic)
runq [local_queue_size]&Goroutine // circular buffer
runnext &Goroutine = unsafe { nil } // next Goroutine to run (fast path, like Go's runnext)
// Free Goroutine list for reuse
g_free GoroutineList
// ID cache to avoid contention on the global counter
goid_cache u64
goid_cache_end u64
link &Processor = unsafe { nil } // linked list for idle Processor list
}
Processor represents a processor - a resource required to execute goroutines. Each Processor has a local run queue. Translated from Go's type p struct in runtime2.go.
struct Sched #
struct Sched {
pub mut:
goid_gen u64 // global goroutine ID generator (atomic)
mu SpinLock // protects idle lists, global queue (spinlock is ucontext-safe)
// Idle Machine's waiting for work
midle &Machine = unsafe { nil }
nmidle i32
// Idle Processor's
pidle &Processor = unsafe { nil }
npidle i32
// Global run queue
runq GoroutineQueue
nmspinning i32 // number of spinning Machine's (atomic)
// All Processor's (indexed by id)
allp []&Processor
// Total Machine count
mnext i64
maxmcount i32 = 10000
// Global Goroutine free list
g_free_mu SpinLock
g_free GoroutineList
g_free_count i32
// Shutdown
stopped bool
}
Sched is the global scheduler state. Translated from Go's type schedt struct in runtime2.go.
struct SpinLock #
struct SpinLock {
mut:
state i32
}
SpinLock - ucontext-safe lock (pthreads mutex breaks with swapcontext).
fn (SpinLock) acquire #
fn (mut s SpinLock) acquire()
fn (SpinLock) release #
fn (mut s SpinLock) release()
struct Sudog #
struct Sudog {
pub mut:
g &Goroutine = unsafe { nil } // the waiting goroutine
next &Sudog = unsafe { nil } // next in wait list
prev &Sudog = unsafe { nil } // prev in wait list
elem voidptr // data element (may point to stack)
success bool // true if woken by successful channel op
c voidptr // channel pointer
}
Sudog represents a G in a wait list (e.g., channel wait queue). Translated from Go's sudog struct in runtime2.go.
struct WaitQ #
struct WaitQ {
pub mut:
first &Sudog = unsafe { nil }
last &Sudog = unsafe { nil }
}
WaitQ is a wait queue of Sudogs (used by channels). Translated from Go's waitq struct in runtime2.go.
fn (WaitQ) enqueue #
fn (mut q WaitQ) enqueue(s &Sudog)
fn (WaitQ) dequeue #
fn (mut q WaitQ) dequeue() &Sudog
fn (WaitQ) empty #
fn (q &WaitQ) empty() bool
- README
- fn chan_cap
- fn chan_close
- fn chan_len
- fn chan_make
- fn chan_recv
- fn chan_send
- fn context_init
- fn context_set
- fn context_switch
- fn get_current_g
- fn gopark
- fn goready
- fn goroutine_create
- fn gosched
- fn num_goroutine
- fn schedule
- fn set_max_procs
- fn shutdown
- type GoFn
- enum GStatus
- enum PStatus
- struct Chan
- struct Context
- struct Goroutine
- struct GoroutineList
- struct GoroutineQueue
- struct Machine
- struct Processor
- struct Sched
- struct SpinLock
- struct Sudog
- struct WaitQ