@@ -362,7 +362,12 @@ func signal_enable(s uint32) {
362
362
// receivedSignals into a uint32 array.
363
363
runtimePanicAt (returnAddress (0 ), "unsupported signal number" )
364
364
}
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).
365
369
hasSignals = true
370
+
366
371
// It's easier to implement this function in C.
367
372
tinygo_signal_enable (s )
368
373
}
@@ -391,6 +396,9 @@ func signal_disable(s uint32) {
391
396
func signal_waitUntilIdle () {
392
397
// Wait until signal_recv has processed all signals.
393
398
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.
394
402
Gosched ()
395
403
}
396
404
}
@@ -434,7 +442,7 @@ func tinygo_signal_handler(s int32) {
434
442
435
443
// Task waiting for a signal to arrive, or nil if it is running or there are no
436
444
// signals.
437
- var signalRecvWaiter * task.Task
445
+ var signalRecvWaiter * atomic. Pointer [ task.Task ]
438
446
439
447
//go:linkname signal_recv os/signal.signal_recv
440
448
func signal_recv () uint32 {
@@ -443,7 +451,10 @@ func signal_recv() uint32 {
443
451
val := receivedSignals .Load ()
444
452
if val == 0 {
445
453
// 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
+ }
447
458
task .Pause ()
448
459
continue
449
460
}
@@ -474,10 +485,11 @@ func signal_recv() uint32 {
474
485
// Return true if it was reactivated (and therefore the scheduler should run
475
486
// again), and false otherwise.
476
487
func 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
+ }
481
493
}
482
494
return false
483
495
}
0 commit comments