@@ -362,7 +362,12 @@ func signal_enable(s uint32) {
362362 // receivedSignals into a uint32 array.
363363 runtimePanicAt (returnAddress (0 ), "unsupported signal number" )
364364 }
365+
366+ // This is intentonally a non-atomic store. This is safe, since hasSignals
367+ // is only used in waitForEvents which is only called when there's a
368+ // scheduler (and therefore there is no parallelism).
365369 hasSignals = true
370+
366371 // It's easier to implement this function in C.
367372 tinygo_signal_enable (s )
368373}
@@ -391,6 +396,9 @@ func signal_disable(s uint32) {
391396func signal_waitUntilIdle () {
392397 // Wait until signal_recv has processed all signals.
393398 for receivedSignals .Load () != 0 {
399+ // TODO: this becomes a busy loop when using threads.
400+ // We might want to pause until signal_recv has no more incoming signals
401+ // to process.
394402 Gosched ()
395403 }
396404}
@@ -434,7 +442,7 @@ func tinygo_signal_handler(s int32) {
434442
435443// Task waiting for a signal to arrive, or nil if it is running or there are no
436444// signals.
437- var signalRecvWaiter * task.Task
445+ var signalRecvWaiter * atomic. Pointer [ task.Task ]
438446
439447//go:linkname signal_recv os/signal.signal_recv
440448func signal_recv () uint32 {
@@ -443,7 +451,10 @@ func signal_recv() uint32 {
443451 val := receivedSignals .Load ()
444452 if val == 0 {
445453 // There are no signals to receive. Sleep until there are.
446- signalRecvWaiter = task .Current ()
454+ if signalRecvWaiter .Swap (task .Current ()) != nil {
455+ // We expect only a single goroutine to call signal_recv.
456+ runtimePanic ("signal_recv called concurrently" )
457+ }
447458 task .Pause ()
448459 continue
449460 }
@@ -474,10 +485,11 @@ func signal_recv() uint32 {
474485// Return true if it was reactivated (and therefore the scheduler should run
475486// again), and false otherwise.
476487func checkSignals () bool {
477- if receivedSignals .Load () != 0 && signalRecvWaiter != nil {
478- scheduleTask (signalRecvWaiter )
479- signalRecvWaiter = nil
480- return true
488+ if receivedSignals .Load () != 0 {
489+ if waiter := signalRecvWaiter .Swap (nil ); waiter != nil {
490+ scheduleTask (waiter )
491+ return true
492+ }
481493 }
482494 return false
483495}
0 commit comments