mirror of
https://github.com/tinygo-org/tinygo.git
synced 2026-08-18 19:44:00 +00:00
runtime: make signals parallelism-safe
This commit is contained in:
@@ -362,7 +362,12 @@ func signal_enable(s uint32) {
|
|||||||
// receivedSignals into a uint32 array.
|
// receivedSignals into a uint32 array.
|
||||||
runtimePanicAt(returnAddress(0), "unsupported signal number")
|
runtimePanicAt(returnAddress(0), "unsupported signal number")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// This is intentonally a non-atomic store. This is safe, since hasSignals
|
||||||
|
// is only used in waitForEvents which is only called when there's a
|
||||||
|
// scheduler (and therefore there is no parallelism).
|
||||||
hasSignals = true
|
hasSignals = true
|
||||||
|
|
||||||
// It's easier to implement this function in C.
|
// It's easier to implement this function in C.
|
||||||
tinygo_signal_enable(s)
|
tinygo_signal_enable(s)
|
||||||
}
|
}
|
||||||
@@ -391,6 +396,9 @@ func signal_disable(s uint32) {
|
|||||||
func signal_waitUntilIdle() {
|
func signal_waitUntilIdle() {
|
||||||
// Wait until signal_recv has processed all signals.
|
// Wait until signal_recv has processed all signals.
|
||||||
for receivedSignals.Load() != 0 {
|
for receivedSignals.Load() != 0 {
|
||||||
|
// TODO: this becomes a busy loop when using threads.
|
||||||
|
// We might want to pause until signal_recv has no more incoming signals
|
||||||
|
// to process.
|
||||||
Gosched()
|
Gosched()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -434,7 +442,7 @@ func tinygo_signal_handler(s int32) {
|
|||||||
|
|
||||||
// Task waiting for a signal to arrive, or nil if it is running or there are no
|
// Task waiting for a signal to arrive, or nil if it is running or there are no
|
||||||
// signals.
|
// signals.
|
||||||
var signalRecvWaiter *task.Task
|
var signalRecvWaiter atomic.Pointer[task.Task]
|
||||||
|
|
||||||
//go:linkname signal_recv os/signal.signal_recv
|
//go:linkname signal_recv os/signal.signal_recv
|
||||||
func signal_recv() uint32 {
|
func signal_recv() uint32 {
|
||||||
@@ -443,7 +451,10 @@ func signal_recv() uint32 {
|
|||||||
val := receivedSignals.Load()
|
val := receivedSignals.Load()
|
||||||
if val == 0 {
|
if val == 0 {
|
||||||
// There are no signals to receive. Sleep until there are.
|
// There are no signals to receive. Sleep until there are.
|
||||||
signalRecvWaiter = task.Current()
|
if signalRecvWaiter.Swap(task.Current()) != nil {
|
||||||
|
// We expect only a single goroutine to call signal_recv.
|
||||||
|
runtimePanic("signal_recv called concurrently")
|
||||||
|
}
|
||||||
task.Pause()
|
task.Pause()
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
@@ -474,10 +485,11 @@ func signal_recv() uint32 {
|
|||||||
// Return true if it was reactivated (and therefore the scheduler should run
|
// Return true if it was reactivated (and therefore the scheduler should run
|
||||||
// again), and false otherwise.
|
// again), and false otherwise.
|
||||||
func checkSignals() bool {
|
func checkSignals() bool {
|
||||||
if receivedSignals.Load() != 0 && signalRecvWaiter != nil {
|
if receivedSignals.Load() != 0 {
|
||||||
scheduleTask(signalRecvWaiter)
|
if waiter := signalRecvWaiter.Swap(nil); waiter != nil {
|
||||||
signalRecvWaiter = nil
|
scheduleTask(waiter)
|
||||||
return true
|
return true
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user