Initial project import
This commit is contained in:
commit
23f2d29e32
11957 files changed
+1754577
No files matched your search
@@ -0,0 +1,143 @@
|
||||
// Copyright (c) 2019-2024 Alexander Medvednikov. All rights reserved.
|
||||
// Use of this source code is governed by an MIT license
|
||||
// that can be found in the LICENSE file.
|
||||
//
|
||||
// Goroutine parking (blocking/unblocking) mechanism.
|
||||
// Translated from Go's gopark/goready in proc.go.
|
||||
//
|
||||
// When a goroutine needs to block (e.g., waiting on a channel),
|
||||
// it "parks" itself - yielding its M to the scheduler.
|
||||
// When the condition is met, another goroutine "readies" it
|
||||
// by putting it back on a run queue.
|
||||
module goroutines
|
||||
|
||||
// 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.
|
||||
pub fn gopark(reason string) {
|
||||
mut mp := get_current_m()
|
||||
if mp == unsafe { nil } {
|
||||
return
|
||||
}
|
||||
mut gp := mp.curg
|
||||
if gp == unsafe { nil } {
|
||||
return
|
||||
}
|
||||
|
||||
gp.status = .waiting
|
||||
gp.wait_reason = reason
|
||||
|
||||
// Dissociate G from M
|
||||
mp.curg = unsafe { nil }
|
||||
gp.m = unsafe { nil }
|
||||
|
||||
// Switch back to the scheduler (M's g0 context)
|
||||
context_switch(mut &gp.context, &mp.g0.context)
|
||||
}
|
||||
|
||||
// goready puts a waiting goroutine back on a run queue.
|
||||
// Translated from Go's goready() in proc.go.
|
||||
pub fn goready(gp &Goroutine) {
|
||||
if gp == unsafe { nil } {
|
||||
return
|
||||
}
|
||||
mut g := unsafe { gp }
|
||||
if g.status != .waiting {
|
||||
return
|
||||
}
|
||||
g.status = .runnable
|
||||
g.wait_reason = ''
|
||||
|
||||
// Put it on the current P's local run queue, or global if no P
|
||||
mut pp := get_current_p()
|
||||
if pp != unsafe { nil } {
|
||||
runq_put(mut pp, g, true)
|
||||
} else {
|
||||
glob_runq_put(g)
|
||||
}
|
||||
|
||||
// Try to wake an idle P to run this goroutine
|
||||
wake_p()
|
||||
}
|
||||
|
||||
// gosched yields the processor, allowing other goroutines to run.
|
||||
// Translated from Go's Gosched() / goschedImpl() in proc.go.
|
||||
pub fn gosched() {
|
||||
mut mp := get_current_m()
|
||||
if mp == unsafe { nil } {
|
||||
return
|
||||
}
|
||||
mut gp := mp.curg
|
||||
if gp == unsafe { nil } {
|
||||
return
|
||||
}
|
||||
mut pp := mp.p
|
||||
if pp == unsafe { nil } {
|
||||
return
|
||||
}
|
||||
|
||||
// Put the current G back on the run queue as runnable
|
||||
gp.status = .runnable
|
||||
mp.curg = unsafe { nil }
|
||||
gp.m = unsafe { nil }
|
||||
|
||||
// Put on local queue
|
||||
runq_put(mut pp, gp, false)
|
||||
|
||||
// Switch back to scheduler
|
||||
context_switch(mut &gp.context, &mp.g0.context)
|
||||
}
|
||||
|
||||
// Sudog represents a G in a wait list (e.g., channel wait queue).
|
||||
// Translated from Go's sudog struct in runtime2.go.
|
||||
pub 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
|
||||
}
|
||||
|
||||
// WaitQ is a wait queue of Sudogs (used by channels).
|
||||
// Translated from Go's waitq struct in runtime2.go.
|
||||
pub struct WaitQ {
|
||||
pub mut:
|
||||
first &Sudog = unsafe { nil }
|
||||
last &Sudog = unsafe { nil }
|
||||
}
|
||||
|
||||
pub fn (mut q WaitQ) enqueue(s &Sudog) {
|
||||
mut sg := unsafe { s }
|
||||
sg.next = unsafe { nil }
|
||||
sg.prev = q.last
|
||||
if q.last != unsafe { nil } {
|
||||
q.last.next = sg
|
||||
} else {
|
||||
q.first = sg
|
||||
}
|
||||
q.last = sg
|
||||
}
|
||||
|
||||
pub fn (mut q WaitQ) dequeue() &Sudog {
|
||||
sg := q.first
|
||||
if sg == unsafe { nil } {
|
||||
return unsafe { nil }
|
||||
}
|
||||
q.first = sg.next
|
||||
if q.first != unsafe { nil } {
|
||||
q.first.prev = unsafe { nil }
|
||||
} else {
|
||||
q.last = unsafe { nil }
|
||||
}
|
||||
mut s := unsafe { sg }
|
||||
s.next = unsafe { nil }
|
||||
s.prev = unsafe { nil }
|
||||
return s
|
||||
}
|
||||
|
||||
pub fn (q &WaitQ) empty() bool {
|
||||
return q.first == unsafe { nil }
|
||||
}
|
||||
Reference in new issue
Block a user