internal/task: swap stack chain when switching goroutines
This change swaps the stack chain when switching goroutines, ensuring that the chain is maintained consistently. This is only really currently necessary with asyncify on wasm.
Этот коммит содержится в:
родитель
d5c0083085
коммит
e4de7b4957
10 изменённых файлов: 51 добавлений и 4 удалений
3
compiler/testdata/channel.ll
предоставленный
3
compiler/testdata/channel.ll
предоставленный
|
@ -5,7 +5,8 @@ target triple = "wasm32-unknown-wasi"
|
|||
|
||||
%runtime.channel = type { i32, i32, i8, %runtime.channelBlockedList*, i32, i32, i32, i8* }
|
||||
%runtime.channelBlockedList = type { %runtime.channelBlockedList*, %"internal/task.Task"*, %runtime.chanSelectState*, { %runtime.channelBlockedList*, i32, i32 } }
|
||||
%"internal/task.Task" = type { %"internal/task.Task"*, i8*, i64, %"internal/task.state" }
|
||||
%"internal/task.Task" = type { %"internal/task.Task"*, i8*, i64, %"internal/task.gcData", %"internal/task.state" }
|
||||
%"internal/task.gcData" = type { i8* }
|
||||
%"internal/task.state" = type { i32, i8*, %"internal/task.stackState", i1 }
|
||||
%"internal/task.stackState" = type { i32, i32 }
|
||||
%runtime.chanSelectState = type { %runtime.channel*, i8* }
|
||||
|
|
3
compiler/testdata/goroutine-cortex-m-qemu-tasks.ll
предоставленный
3
compiler/testdata/goroutine-cortex-m-qemu-tasks.ll
предоставленный
|
@ -5,7 +5,8 @@ target triple = "thumbv7m-unknown-unknown-eabi"
|
|||
|
||||
%runtime.channel = type { i32, i32, i8, %runtime.channelBlockedList*, i32, i32, i32, i8* }
|
||||
%runtime.channelBlockedList = type { %runtime.channelBlockedList*, %"internal/task.Task"*, %runtime.chanSelectState*, { %runtime.channelBlockedList*, i32, i32 } }
|
||||
%"internal/task.Task" = type { %"internal/task.Task"*, i8*, i64, %"internal/task.state" }
|
||||
%"internal/task.Task" = type { %"internal/task.Task"*, i8*, i64, %"internal/task.gcData", %"internal/task.state" }
|
||||
%"internal/task.gcData" = type {}
|
||||
%"internal/task.state" = type { i32, i32* }
|
||||
%runtime.chanSelectState = type { %runtime.channel*, i8* }
|
||||
|
||||
|
|
3
compiler/testdata/goroutine-wasm-asyncify.ll
предоставленный
3
compiler/testdata/goroutine-wasm-asyncify.ll
предоставленный
|
@ -5,7 +5,8 @@ target triple = "wasm32-unknown-wasi"
|
|||
|
||||
%runtime.channel = type { i32, i32, i8, %runtime.channelBlockedList*, i32, i32, i32, i8* }
|
||||
%runtime.channelBlockedList = type { %runtime.channelBlockedList*, %"internal/task.Task"*, %runtime.chanSelectState*, { %runtime.channelBlockedList*, i32, i32 } }
|
||||
%"internal/task.Task" = type { %"internal/task.Task"*, i8*, i64, %"internal/task.state" }
|
||||
%"internal/task.Task" = type { %"internal/task.Task"*, i8*, i64, %"internal/task.gcData", %"internal/task.state" }
|
||||
%"internal/task.gcData" = type { i8* }
|
||||
%"internal/task.state" = type { i32, i8*, %"internal/task.stackState", i1 }
|
||||
%"internal/task.stackState" = type { i32, i32 }
|
||||
%runtime.chanSelectState = type { %runtime.channel*, i8* }
|
||||
|
|
3
compiler/testdata/goroutine-wasm-coroutines.ll
предоставленный
3
compiler/testdata/goroutine-wasm-coroutines.ll
предоставленный
|
@ -6,7 +6,8 @@ target triple = "wasm32-unknown-wasi"
|
|||
%runtime.funcValueWithSignature = type { i32, i8* }
|
||||
%runtime.channel = type { i32, i32, i8, %runtime.channelBlockedList*, i32, i32, i32, i8* }
|
||||
%runtime.channelBlockedList = type { %runtime.channelBlockedList*, %"internal/task.Task"*, %runtime.chanSelectState*, { %runtime.channelBlockedList*, i32, i32 } }
|
||||
%"internal/task.Task" = type { %"internal/task.Task"*, i8*, i64, %"internal/task.state" }
|
||||
%"internal/task.Task" = type { %"internal/task.Task"*, i8*, i64, %"internal/task.gcData", %"internal/task.state" }
|
||||
%"internal/task.gcData" = type {}
|
||||
%"internal/task.state" = type { i8* }
|
||||
%runtime.chanSelectState = type { %runtime.channel*, i8* }
|
||||
|
||||
|
|
19
src/internal/task/gc_stack_chain.go
Обычный файл
19
src/internal/task/gc_stack_chain.go
Обычный файл
|
@ -0,0 +1,19 @@
|
|||
//go:build (gc.conservative || gc.extalloc) && tinygo.wasm && !scheduler.coroutines
|
||||
// +build gc.conservative gc.extalloc
|
||||
// +build tinygo.wasm
|
||||
// +build !scheduler.coroutines
|
||||
|
||||
package task
|
||||
|
||||
import "unsafe"
|
||||
|
||||
//go:linkname swapStackChain runtime.swapStackChain
|
||||
func swapStackChain(dst *unsafe.Pointer)
|
||||
|
||||
type gcData struct {
|
||||
stackChain unsafe.Pointer
|
||||
}
|
||||
|
||||
func (gcd *gcData) swap() {
|
||||
swapStackChain(&gcd.stackChain)
|
||||
}
|
9
src/internal/task/gc_stack_noop.go
Обычный файл
9
src/internal/task/gc_stack_noop.go
Обычный файл
|
@ -0,0 +1,9 @@
|
|||
//go:build (!gc.conservative && !gc.extalloc) || !tinygo.wasm || scheduler.coroutines
|
||||
// +build !gc.conservative,!gc.extalloc !tinygo.wasm scheduler.coroutines
|
||||
|
||||
package task
|
||||
|
||||
type gcData struct{}
|
||||
|
||||
func (gcd *gcData) swap() {
|
||||
}
|
|
@ -15,6 +15,9 @@ type Task struct {
|
|||
// Data is a field which can be used for storing state information.
|
||||
Data uint64
|
||||
|
||||
// gcData holds data for the GC.
|
||||
gcData gcData
|
||||
|
||||
// state is the underlying running state of the task.
|
||||
state state
|
||||
}
|
||||
|
|
|
@ -104,6 +104,7 @@ func (*stackState) unwind()
|
|||
func (t *Task) Resume() {
|
||||
// The current task must be saved and restored because this can nest on WASM with JS.
|
||||
prevTask := currentTask
|
||||
t.gcData.swap()
|
||||
currentTask = t
|
||||
if !t.state.launched {
|
||||
t.state.launch()
|
||||
|
@ -112,6 +113,7 @@ func (t *Task) Resume() {
|
|||
t.state.rewind()
|
||||
}
|
||||
currentTask = prevTask
|
||||
t.gcData.swap()
|
||||
if t.state.asyncifysp > t.state.csp {
|
||||
runtimePanic("stack overflow")
|
||||
}
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
//go:build scheduler.tasks
|
||||
// +build scheduler.tasks
|
||||
|
||||
package task
|
||||
|
@ -54,7 +55,9 @@ func pause() {
|
|||
// This may only be called from the scheduler.
|
||||
func (t *Task) Resume() {
|
||||
currentTask = t
|
||||
t.gcData.swap()
|
||||
t.state.resume()
|
||||
t.gcData.swap()
|
||||
currentTask = nil
|
||||
}
|
||||
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
//go:build (gc.conservative || gc.extalloc) && tinygo.wasm
|
||||
// +build gc.conservative gc.extalloc
|
||||
// +build tinygo.wasm
|
||||
|
||||
|
@ -37,3 +38,9 @@ func markStack() {
|
|||
// construction. Calls to it are later replaced with regular stack bookkeeping
|
||||
// code.
|
||||
func trackPointer(ptr unsafe.Pointer)
|
||||
|
||||
// swapStackChain swaps the stack chain.
|
||||
// This is called from internal/task when switching goroutines.
|
||||
func swapStackChain(dst **stackChainObject) {
|
||||
*dst, stackChainStart = stackChainStart, *dst
|
||||
}
|
||||
|
|
Загрузка…
Создание таблицы
Сослаться в новой задаче