aboutsummaryrefslogtreecommitdiffhomepage
path: root/compiler
diff options
context:
space:
mode:
authorAyke van Laethem <[email protected]>2024-11-07 13:38:28 +0100
committerRon Evans <[email protected]>2024-12-01 11:12:00 +0100
commit26c36d0a2e11ba6b31300881b8dd729b1ad8cfe6 (patch)
treec65ca380fe496864f5be593bebed68cc51bf7c94 /compiler
parent09a22ac4b48b5a008cedc527c70cf41117a6b338 (diff)
downloadtinygo-26c36d0a2e11ba6b31300881b8dd729b1ad8cfe6.tar.gz
tinygo-26c36d0a2e11ba6b31300881b8dd729b1ad8cfe6.zip
runtime: lock output in print/println
This ensures that calls to print/println happening in different threads are not interleaved. It's a task.PMutex, so this should only change things when threading is used. This matches the Go compiler, which does the same thing: https://godbolt.org/z/na5KzE7en The locks are not recursive, which means that we need to be careful to not call `print` or `println` inside a runtime.print* implementation, inside putchar (recursively), and inside signal handlers. Making them recursive might be useful to do in the future, but it's not really necessary.
Diffstat (limited to 'compiler')
-rw-r--r--compiler/compiler.go2
-rw-r--r--compiler/testdata/defer-cortex-m-qemu.ll10
-rw-r--r--compiler/testdata/goroutine-cortex-m-qemu-tasks.ll6
-rw-r--r--compiler/testdata/goroutine-wasm-asyncify.ll6
4 files changed, 24 insertions, 0 deletions
diff --git a/compiler/compiler.go b/compiler/compiler.go
index 8b5f0d1cb..28ec312dd 100644
--- a/compiler/compiler.go
+++ b/compiler/compiler.go
@@ -1686,6 +1686,7 @@ func (b *builder) createBuiltin(argTypes []types.Type, argValues []llvm.Value, c
b.createRuntimeInvoke("_panic", argValues, "")
return llvm.Value{}, nil
case "print", "println":
+ b.createRuntimeCall("printlock", nil, "")
for i, value := range argValues {
if i >= 1 && callName == "println" {
b.createRuntimeCall("printspace", nil, "")
@@ -1746,6 +1747,7 @@ func (b *builder) createBuiltin(argTypes []types.Type, argValues []llvm.Value, c
if callName == "println" {
b.createRuntimeCall("printnl", nil, "")
}
+ b.createRuntimeCall("printunlock", nil, "")
return llvm.Value{}, nil // print() or println() returns void
case "real":
cplx := argValues[0]
diff --git a/compiler/testdata/defer-cortex-m-qemu.ll b/compiler/testdata/defer-cortex-m-qemu.ll
index cdcfd0ea4..f1fbad7f8 100644
--- a/compiler/testdata/defer-cortex-m-qemu.ll
+++ b/compiler/testdata/defer-cortex-m-qemu.ll
@@ -122,12 +122,18 @@ declare void @runtime.destroyDeferFrame(ptr dereferenceable_or_null(24), ptr) #2
; Function Attrs: nounwind
define internal void @"main.deferSimple$1"(ptr %context) unnamed_addr #1 {
entry:
+ call void @runtime.printlock(ptr undef) #4
call void @runtime.printint32(i32 3, ptr undef) #4
+ call void @runtime.printunlock(ptr undef) #4
ret void
}
+declare void @runtime.printlock(ptr) #2
+
declare void @runtime.printint32(i32, ptr) #2
+declare void @runtime.printunlock(ptr) #2
+
; Function Attrs: nounwind
define hidden void @main.deferMultiple(ptr %context) unnamed_addr #1 {
entry:
@@ -250,14 +256,18 @@ rundefers.end7: ; preds = %rundefers.loophead1
; Function Attrs: nounwind
define internal void @"main.deferMultiple$1"(ptr %context) unnamed_addr #1 {
entry:
+ call void @runtime.printlock(ptr undef) #4
call void @runtime.printint32(i32 3, ptr undef) #4
+ call void @runtime.printunlock(ptr undef) #4
ret void
}
; Function Attrs: nounwind
define internal void @"main.deferMultiple$2"(ptr %context) unnamed_addr #1 {
entry:
+ call void @runtime.printlock(ptr undef) #4
call void @runtime.printint32(i32 5, ptr undef) #4
+ call void @runtime.printunlock(ptr undef) #4
ret void
}
diff --git a/compiler/testdata/goroutine-cortex-m-qemu-tasks.ll b/compiler/testdata/goroutine-cortex-m-qemu-tasks.ll
index a57bb20f3..819f01adb 100644
--- a/compiler/testdata/goroutine-cortex-m-qemu-tasks.ll
+++ b/compiler/testdata/goroutine-cortex-m-qemu-tasks.ll
@@ -70,7 +70,9 @@ entry:
%stacksize = call i32 @"internal/task.getGoroutineStackSize"(i32 ptrtoint (ptr @"main.closureFunctionGoroutine$1$gowrapper" to i32), ptr undef) #9
call void @"internal/task.start"(i32 ptrtoint (ptr @"main.closureFunctionGoroutine$1$gowrapper" to i32), ptr nonnull %0, i32 %stacksize, ptr undef) #9
%2 = load i32, ptr %n, align 4
+ call void @runtime.printlock(ptr undef) #9
call void @runtime.printint32(i32 %2, ptr undef) #9
+ call void @runtime.printunlock(ptr undef) #9
ret void
}
@@ -91,8 +93,12 @@ entry:
ret void
}
+declare void @runtime.printlock(ptr) #2
+
declare void @runtime.printint32(i32, ptr) #2
+declare void @runtime.printunlock(ptr) #2
+
; Function Attrs: nounwind
define hidden void @main.funcGoroutine(ptr %fn.context, ptr %fn.funcptr, ptr %context) unnamed_addr #1 {
entry:
diff --git a/compiler/testdata/goroutine-wasm-asyncify.ll b/compiler/testdata/goroutine-wasm-asyncify.ll
index c4af76037..87c7381f2 100644
--- a/compiler/testdata/goroutine-wasm-asyncify.ll
+++ b/compiler/testdata/goroutine-wasm-asyncify.ll
@@ -76,7 +76,9 @@ entry:
store ptr %n, ptr %1, align 4
call void @"internal/task.start"(i32 ptrtoint (ptr @"main.closureFunctionGoroutine$1$gowrapper" to i32), ptr nonnull %0, i32 65536, ptr undef) #9
%2 = load i32, ptr %n, align 4
+ call void @runtime.printlock(ptr undef) #9
call void @runtime.printint32(i32 %2, ptr undef) #9
+ call void @runtime.printunlock(ptr undef) #9
ret void
}
@@ -98,8 +100,12 @@ entry:
unreachable
}
+declare void @runtime.printlock(ptr) #1
+
declare void @runtime.printint32(i32, ptr) #1
+declare void @runtime.printunlock(ptr) #1
+
; Function Attrs: nounwind
define hidden void @main.funcGoroutine(ptr %fn.context, ptr %fn.funcptr, ptr %context) unnamed_addr #2 {
entry: