From bf8345c09b164a26d80837271b6772823c75861a Mon Sep 17 00:00:00 2001 From: Ayke van Laethem Date: Fri, 4 Apr 2025 08:18:42 +0200 Subject: [PATCH 1/2] internal/task: rename tinygo_pause to tinygo_task_exit This is more descriptive: the call is to exit a task, not to pause it. This also makes it more obvious that there's an optimization opportunity: to free the stack explicitly after the goroutine returns (or to keep it as a cache for the next stack allocation). --- src/internal/task/task_stack.go | 5 +++-- src/internal/task/task_stack_386.S | 2 +- src/internal/task/task_stack_amd64.S | 4 ++-- src/internal/task/task_stack_amd64_windows.S | 2 +- src/internal/task/task_stack_arm.S | 2 +- src/internal/task/task_stack_arm64.S | 4 ++-- src/internal/task/task_stack_avr.S | 4 ++-- src/internal/task/task_stack_cortexm.S | 2 +- src/internal/task/task_stack_esp32.S | 2 +- src/internal/task/task_stack_esp8266.S | 2 +- src/internal/task/task_stack_mipsx.S | 2 +- src/internal/task/task_stack_tinygoriscv.S | 2 +- 12 files changed, 17 insertions(+), 16 deletions(-) diff --git a/src/internal/task/task_stack.go b/src/internal/task/task_stack.go index 88a0970685..74a0a8c7cc 100644 --- a/src/internal/task/task_stack.go +++ b/src/internal/task/task_stack.go @@ -54,8 +54,9 @@ func Pause() { currentTask.state.pause() } -//export tinygo_pause -func pause() { +//export tinygo_task_exit +func taskExit() { + // TODO: explicitly free the stack after switching back to the scheduler. Pause() } diff --git a/src/internal/task/task_stack_386.S b/src/internal/task/task_stack_386.S index c82213e98f..402e9e50f0 100644 --- a/src/internal/task/task_stack_386.S +++ b/src/internal/task/task_stack_386.S @@ -24,7 +24,7 @@ tinygo_startTask: addl $4, %esp // After return, exit this goroutine. This is a tail call. - jmp tinygo_pause + jmp tinygo_task_exit .cfi_endproc .global tinygo_swapTask diff --git a/src/internal/task/task_stack_amd64.S b/src/internal/task/task_stack_amd64.S index f9182d49ff..8a2c23f5b1 100644 --- a/src/internal/task/task_stack_amd64.S +++ b/src/internal/task/task_stack_amd64.S @@ -30,9 +30,9 @@ tinygo_startTask: // After return, exit this goroutine. This is a tail call. #ifdef __MACH__ - jmp _tinygo_pause + jmp _tinygo_task_exit #else - jmp tinygo_pause + jmp tinygo_task_exit #endif .cfi_endproc diff --git a/src/internal/task/task_stack_amd64_windows.S b/src/internal/task/task_stack_amd64_windows.S index 30654e504c..50c684121c 100644 --- a/src/internal/task/task_stack_amd64_windows.S +++ b/src/internal/task/task_stack_amd64_windows.S @@ -22,7 +22,7 @@ tinygo_startTask: // After return, exit this goroutine. // This has to be a call, not a jump, to keep the stack correctly aligned. - callq tinygo_pause + callq tinygo_task_exit .global tinygo_swapTask .section .text.tinygo_swapTask,"ax" diff --git a/src/internal/task/task_stack_arm.S b/src/internal/task/task_stack_arm.S index 81a5aa8a09..5ba9961dc2 100644 --- a/src/internal/task/task_stack_arm.S +++ b/src/internal/task/task_stack_arm.S @@ -28,7 +28,7 @@ tinygo_startTask: blx r4 // After return, exit this goroutine. This is a tail call. - bl tinygo_pause + bl tinygo_task_exit .cfi_endproc .size tinygo_startTask, .-tinygo_startTask diff --git a/src/internal/task/task_stack_arm64.S b/src/internal/task/task_stack_arm64.S index 597d342c72..924b74a662 100644 --- a/src/internal/task/task_stack_arm64.S +++ b/src/internal/task/task_stack_arm64.S @@ -27,9 +27,9 @@ tinygo_startTask: // After return, exit this goroutine. This is a tail call. #ifdef __MACH__ - b _tinygo_pause + b _tinygo_task_exit #else - b tinygo_pause + b tinygo_task_exit #endif .cfi_endproc #ifndef __MACH__ diff --git a/src/internal/task/task_stack_avr.S b/src/internal/task/task_stack_avr.S index d8aed8b96b..6b38127704 100644 --- a/src/internal/task/task_stack_avr.S +++ b/src/internal/task/task_stack_avr.S @@ -32,10 +32,10 @@ tinygo_startTask: // Note that they will probably not be able to run more than the main // goroutine anyway, but this file is compiled for all AVRs so it needs to // compile at least. - rcall tinygo_pause + rcall tinygo_task_exit #else // Other devices can (and must) use the regular call instruction. - call tinygo_pause + call tinygo_task_exit #endif .global tinygo_swapTask diff --git a/src/internal/task/task_stack_cortexm.S b/src/internal/task/task_stack_cortexm.S index dfe713552d..8e6520106e 100644 --- a/src/internal/task/task_stack_cortexm.S +++ b/src/internal/task/task_stack_cortexm.S @@ -28,7 +28,7 @@ tinygo_startTask: blx r4 // After return, exit this goroutine. This is a tail call. - bl tinygo_pause + bl tinygo_task_exit .cfi_endproc .size tinygo_startTask, .-tinygo_startTask diff --git a/src/internal/task/task_stack_esp32.S b/src/internal/task/task_stack_esp32.S index fe0afe98d6..f07f7e3ae3 100644 --- a/src/internal/task/task_stack_esp32.S +++ b/src/internal/task/task_stack_esp32.S @@ -27,7 +27,7 @@ tinygo_startTask: callx4 a3 // After return, exit this goroutine. This call never returns. - call4 tinygo_pause + call4 tinygo_task_exit .section .text.tinygo_swapTask,"ax",@progbits .global tinygo_swapTask diff --git a/src/internal/task/task_stack_esp8266.S b/src/internal/task/task_stack_esp8266.S index 07f4e26592..9dd64b1ff7 100644 --- a/src/internal/task/task_stack_esp8266.S +++ b/src/internal/task/task_stack_esp8266.S @@ -18,7 +18,7 @@ tinygo_startTask: callx0 a12 // After return, exit this goroutine. This is a tail call. - call0 tinygo_pause + call0 tinygo_task_exit .size tinygo_startTask, .-tinygo_startTask .global tinygo_swapTask diff --git a/src/internal/task/task_stack_mipsx.S b/src/internal/task/task_stack_mipsx.S index 018c63d935..afd1d7ea9a 100644 --- a/src/internal/task/task_stack_mipsx.S +++ b/src/internal/task/task_stack_mipsx.S @@ -22,7 +22,7 @@ tinygo_startTask: nop // After return, exit this goroutine. This is a tail call. - j tinygo_pause + j tinygo_task_exit nop .section .text.tinygo_swapTask diff --git a/src/internal/task/task_stack_tinygoriscv.S b/src/internal/task/task_stack_tinygoriscv.S index 5f6127427e..ae8b32b9da 100644 --- a/src/internal/task/task_stack_tinygoriscv.S +++ b/src/internal/task/task_stack_tinygoriscv.S @@ -19,7 +19,7 @@ tinygo_startTask: jalr s0 // After return, exit this goroutine. This is a tail call. - tail tinygo_pause + tail tinygo_task_exit .section .text.tinygo_swapTask .global tinygo_swapTask From 157b22bc31a5844688cf4fd7a17d1f692de79635 Mon Sep 17 00:00:00 2001 From: Ayke van Laethem Date: Mon, 7 Apr 2025 10:09:29 +0200 Subject: [PATCH 2/2] runtime: move mainExited boolean This variable is only necessary on the cooperative and none scheduler. It is not used on the threads scheduler. The reason for moving is that the upcoming multicore baremetal scheduler also needs mainExited but of a different type: an atomic variable instead of a plain boolean. --- src/runtime/scheduler.go | 2 -- src/runtime/scheduler_cooperative.go | 3 +++ src/runtime/scheduler_none.go | 3 +++ 3 files changed, 6 insertions(+), 2 deletions(-) diff --git a/src/runtime/scheduler.go b/src/runtime/scheduler.go index d3d61f48eb..9ca54e1c0d 100644 --- a/src/runtime/scheduler.go +++ b/src/runtime/scheduler.go @@ -4,8 +4,6 @@ import "internal/task" const schedulerDebug = false -var mainExited bool - var timerQueue *timerNode // Simple logging, for debugging. diff --git a/src/runtime/scheduler_cooperative.go b/src/runtime/scheduler_cooperative.go index 3cd8001c03..82ec24bee1 100644 --- a/src/runtime/scheduler_cooperative.go +++ b/src/runtime/scheduler_cooperative.go @@ -27,6 +27,9 @@ const hasScheduler = true // concurrency, it does not have parallelism. const hasParallelism = false +// Set to true after main.main returns. +var mainExited bool + // Queues used by the scheduler. var ( runqueue task.Queue diff --git a/src/runtime/scheduler_none.go b/src/runtime/scheduler_none.go index 25bd7eb9c1..82e7203930 100644 --- a/src/runtime/scheduler_none.go +++ b/src/runtime/scheduler_none.go @@ -9,6 +9,9 @@ const hasScheduler = false // No goroutines are allowed, so there's no parallelism anywhere. const hasParallelism = false +// Set to true after main.main returns. +var mainExited bool + // run is called by the program entry point to execute the go program. // With the "none" scheduler, init and the main function are invoked directly. func run() {