mirror of
https://github.com/tinygo-org/tinygo.git
synced 2026-07-26 06:38:42 +00:00
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.
This commit is contained in:
committed by
Ron Evans
parent
09a22ac4b4
commit
26c36d0a2e
@@ -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]
|
||||
|
||||
+10
@@ -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
|
||||
}
|
||||
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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:
|
||||
|
||||
+54
-24
@@ -1,6 +1,7 @@
|
||||
package runtime
|
||||
|
||||
import (
|
||||
"internal/task"
|
||||
"unsafe"
|
||||
)
|
||||
|
||||
@@ -8,6 +9,18 @@ type stringer interface {
|
||||
String() string
|
||||
}
|
||||
|
||||
// Lock to make sure print calls do not interleave.
|
||||
// This is a no-op lock on systems that do not have parallelism.
|
||||
var printLock task.PMutex
|
||||
|
||||
func printlock() {
|
||||
printLock.Lock()
|
||||
}
|
||||
|
||||
func printunlock() {
|
||||
printLock.Unlock()
|
||||
}
|
||||
|
||||
//go:nobounds
|
||||
func printstring(s string) {
|
||||
for i := 0; i < len(s); i++ {
|
||||
@@ -293,67 +306,84 @@ func printnl() {
|
||||
func printitf(msg interface{}) {
|
||||
switch msg := msg.(type) {
|
||||
case bool:
|
||||
print(msg)
|
||||
printbool(msg)
|
||||
case int:
|
||||
print(msg)
|
||||
switch unsafe.Sizeof(msg) {
|
||||
case 8:
|
||||
printint64(int64(msg))
|
||||
case 4:
|
||||
printint32(int32(msg))
|
||||
}
|
||||
case int8:
|
||||
print(msg)
|
||||
printint8(msg)
|
||||
case int16:
|
||||
print(msg)
|
||||
printint16(msg)
|
||||
case int32:
|
||||
print(msg)
|
||||
printint32(msg)
|
||||
case int64:
|
||||
print(msg)
|
||||
printint64(msg)
|
||||
case uint:
|
||||
print(msg)
|
||||
switch unsafe.Sizeof(msg) {
|
||||
case 8:
|
||||
printuint64(uint64(msg))
|
||||
case 4:
|
||||
printuint32(uint32(msg))
|
||||
}
|
||||
case uint8:
|
||||
print(msg)
|
||||
printuint8(msg)
|
||||
case uint16:
|
||||
print(msg)
|
||||
printuint16(msg)
|
||||
case uint32:
|
||||
print(msg)
|
||||
printuint32(msg)
|
||||
case uint64:
|
||||
print(msg)
|
||||
printuint64(msg)
|
||||
case uintptr:
|
||||
print(msg)
|
||||
printuintptr(msg)
|
||||
case float32:
|
||||
print(msg)
|
||||
printfloat32(msg)
|
||||
case float64:
|
||||
print(msg)
|
||||
printfloat64(msg)
|
||||
case complex64:
|
||||
print(msg)
|
||||
printcomplex64(msg)
|
||||
case complex128:
|
||||
print(msg)
|
||||
printcomplex128(msg)
|
||||
case string:
|
||||
print(msg)
|
||||
printstring(msg)
|
||||
case error:
|
||||
print(msg.Error())
|
||||
printstring(msg.Error())
|
||||
case stringer:
|
||||
print(msg.String())
|
||||
printstring(msg.String())
|
||||
default:
|
||||
// cast to underlying type
|
||||
itf := *(*_interface)(unsafe.Pointer(&msg))
|
||||
putchar('(')
|
||||
printuintptr(uintptr(itf.typecode))
|
||||
putchar(':')
|
||||
print(itf.value)
|
||||
printptr(uintptr(itf.value))
|
||||
putchar(')')
|
||||
}
|
||||
}
|
||||
|
||||
func printmap(m *hashmap) {
|
||||
print("map[")
|
||||
printstring("map[")
|
||||
if m == nil {
|
||||
print("nil")
|
||||
printstring("nil")
|
||||
} else {
|
||||
print(uint(m.count))
|
||||
switch unsafe.Sizeof(m.count) {
|
||||
case 8:
|
||||
printuint64(uint64(m.count))
|
||||
case 4:
|
||||
printuint32(uint32(m.count))
|
||||
case 2:
|
||||
printuint16(uint16(m.count))
|
||||
}
|
||||
}
|
||||
putchar(']')
|
||||
}
|
||||
|
||||
func printptr(ptr uintptr) {
|
||||
if ptr == 0 {
|
||||
print("nil")
|
||||
printstring("nil")
|
||||
return
|
||||
}
|
||||
putchar('0')
|
||||
|
||||
Vendored
+6
@@ -37,6 +37,12 @@ func main() {
|
||||
|
||||
// print interface
|
||||
println(interface{}(nil))
|
||||
println(interface{}(true))
|
||||
println(interface{}("foobar"))
|
||||
println(interface{}(int64(-3)))
|
||||
println(interface{}(uint64(3)))
|
||||
println(interface{}(int(-3)))
|
||||
println(interface{}(uint(3)))
|
||||
|
||||
// print map
|
||||
println(map[string]int{"three": 3, "five": 5})
|
||||
|
||||
Vendored
+6
@@ -19,6 +19,12 @@ a b c
|
||||
+3.140000e+000
|
||||
(+5.000000e+000+1.234500e+000i)
|
||||
(0:nil)
|
||||
true
|
||||
foobar
|
||||
-3
|
||||
3
|
||||
-3
|
||||
3
|
||||
map[2]
|
||||
true false
|
||||
[0/0]nil
|
||||
|
||||
Reference in New Issue
Block a user