Skip to content

Commit

Permalink
WIP runtime: lock output in print/println
Browse files Browse the repository at this point in the history
This ensures that calls to print/println happening in different threads
are not interleaved.

TODO: this lock might need to be recursive, so that signal handlers
(such as SIGSEGV) can print things when a segmentation fault happens
while the lock is held.
  • Loading branch information
aykevl committed Dec 1, 2024
1 parent 6c3cfa3 commit 9413785
Show file tree
Hide file tree
Showing 5 changed files with 47 additions and 5 deletions.
2 changes: 2 additions & 0 deletions compiler/compiler.go
Original file line number Diff line number Diff line change
Expand Up @@ -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, "")
Expand Down Expand Up @@ -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]
Expand Down
10 changes: 10 additions & 0 deletions compiler/testdata/defer-cortex-m-qemu.ll
Original file line number Diff line number Diff line change
Expand Up @@ -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:
Expand Down Expand Up @@ -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
}

Expand Down
6 changes: 6 additions & 0 deletions compiler/testdata/goroutine-cortex-m-qemu-tasks.ll
Original file line number Diff line number Diff line change
Expand Up @@ -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
}

Expand All @@ -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:
Expand Down
6 changes: 6 additions & 0 deletions compiler/testdata/goroutine-wasm-asyncify.ll
Original file line number Diff line number Diff line change
Expand Up @@ -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
}

Expand All @@ -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:
Expand Down
28 changes: 23 additions & 5 deletions src/runtime/print.go
Original file line number Diff line number Diff line change
@@ -1,13 +1,24 @@
package runtime

import (
"internal/task"
"unsafe"
)

type stringer interface {
String() string
}

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++ {
Expand Down Expand Up @@ -336,24 +347,31 @@ func printitf(msg interface{}) {
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 TargetBits {
case 64:
printuint64(uint64(m.count))
case 32:
printuint32(uint32(m.count))
case 16:
printuint16(uint16(m.count))
}
}
putchar(']')
}

func printptr(ptr uintptr) {
if ptr == 0 {
print("nil")
printstring("nil")
return
}
putchar('0')
Expand Down

0 comments on commit 9413785

Please sign in to comment.