aboutsummaryrefslogtreecommitdiffhomepage
path: root/src
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 /src
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 'src')
-rw-r--r--src/runtime/print.go78
1 files changed, 54 insertions, 24 deletions
diff --git a/src/runtime/print.go b/src/runtime/print.go
index ef9117ff3..a4de46025 100644
--- a/src/runtime/print.go
+++ b/src/runtime/print.go
@@ -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')