Skip to content

Commit f5a32b7

Browse files
committed
WIP map every goroutine to a new OS thread
1 parent 8166af1 commit f5a32b7

File tree

17 files changed

+1059
-3
lines changed

17 files changed

+1059
-3
lines changed

GNUmakefile

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -934,6 +934,7 @@ endif
934934
@cp -rp lib/musl/src/malloc build/release/tinygo/lib/musl/src
935935
@cp -rp lib/musl/src/mman build/release/tinygo/lib/musl/src
936936
@cp -rp lib/musl/src/math build/release/tinygo/lib/musl/src
937+
@cp -rp lib/musl/src/misc build/release/tinygo/lib/musl/src
937938
@cp -rp lib/musl/src/multibyte build/release/tinygo/lib/musl/src
938939
@cp -rp lib/musl/src/signal build/release/tinygo/lib/musl/src
939940
@cp -rp lib/musl/src/stdio build/release/tinygo/lib/musl/src

builder/musl.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -127,6 +127,7 @@ var libMusl = Library{
127127
"malloc/mallocng/*.c",
128128
"mman/*.c",
129129
"math/*.c",
130+
"misc/*.c",
130131
"multibyte/*.c",
131132
"signal/" + arch + "/*.s",
132133
"signal/*.c",

compileopts/config.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -340,6 +340,7 @@ func (c *Config) CFlags(libclang bool) []string {
340340
"-nostdlibinc",
341341
"-isystem", filepath.Join(path, "include"),
342342
"-isystem", filepath.Join(root, "lib", "musl", "arch", arch),
343+
"-isystem", filepath.Join(root, "lib", "musl", "arch", "generic"),
343344
"-isystem", filepath.Join(root, "lib", "musl", "include"),
344345
)
345346
case "wasi-libc":

compileopts/options.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ import (
1010
var (
1111
validBuildModeOptions = []string{"default", "c-shared"}
1212
validGCOptions = []string{"none", "leaking", "conservative", "custom", "precise"}
13-
validSchedulerOptions = []string{"none", "tasks", "asyncify"}
13+
validSchedulerOptions = []string{"none", "tasks", "asyncify", "threads"}
1414
validSerialOptions = []string{"none", "uart", "usb", "rtt"}
1515
validPrintSizeOptions = []string{"none", "short", "full"}
1616
validPanicStrategyOptions = []string{"print", "trap"}

compileopts/options_test.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ import (
1010
func TestVerifyOptions(t *testing.T) {
1111

1212
expectedGCError := errors.New(`invalid gc option 'incorrect': valid values are none, leaking, conservative, custom, precise`)
13-
expectedSchedulerError := errors.New(`invalid scheduler option 'incorrect': valid values are none, tasks, asyncify`)
13+
expectedSchedulerError := errors.New(`invalid scheduler option 'incorrect': valid values are none, tasks, asyncify, threads`)
1414
expectedPrintSizeError := errors.New(`invalid size option 'incorrect': valid values are none, short, full`)
1515
expectedPanicStrategyError := errors.New(`invalid panic option 'incorrect': valid values are print, trap`)
1616

compileopts/target.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -414,6 +414,7 @@ func defaultTarget(options *Options) (*TargetSpec, error) {
414414
}
415415
spec.ExtraFiles = append(spec.ExtraFiles,
416416
"src/internal/task/futex_linux.c",
417+
"src/internal/task/task_threads.c",
417418
"src/runtime/runtime_unix.c",
418419
"src/runtime/signal.c")
419420
case "windows":

src/internal/task/futex_linux.c

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55

66
#include <stdint.h>
77
#include <sys/syscall.h>
8+
#include <time.h>
89
#include <unistd.h>
910

1011
#define FUTEX_WAIT 0
@@ -15,6 +16,13 @@ void tinygo_futex_wait(uint32_t *addr, uint32_t cmp) {
1516
syscall(SYS_futex, addr, FUTEX_WAIT|FUTEX_PRIVATE, cmp, NULL, NULL, 0);
1617
}
1718

19+
void tinygo_futex_wait_timeout(uint32_t *addr, uint32_t cmp, uint64_t timeout) {
20+
struct timespec ts = {0};
21+
ts.tv_sec = timeout / 1000000000;
22+
ts.tv_nsec = timeout % 1000000000;
23+
syscall(SYS_futex, addr, FUTEX_WAIT|FUTEX_PRIVATE, cmp, &ts, NULL, 0);
24+
}
25+
1826
void tinygo_futex_wake(uint32_t *addr, uint32_t num) {
1927
syscall(SYS_futex, addr, FUTEX_WAKE|FUTEX_PRIVATE, num, NULL, NULL, 0);
2028
}

src/internal/task/futex_linux.go

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,11 @@ func (f *Futex) Wait(cmp uint32) bool {
3131
return false
3232
}
3333

34+
// Like Wait, but times out after the number of nanoseconds in timeout.
35+
func (f *Futex) WaitUntil(cmp uint32, timeout uint64) {
36+
tinygo_futex_wait_timeout((*uint32)(unsafe.Pointer(&f.Uint32)), cmp, timeout)
37+
}
38+
3439
// Wake a single waiter.
3540
func (f *Futex) Wake() {
3641
tinygo_futex_wake((*uint32)(unsafe.Pointer(&f.Uint32)), 1)
@@ -45,5 +50,8 @@ func (f *Futex) WakeAll() {
4550
//export tinygo_futex_wait
4651
func tinygo_futex_wait(addr *uint32, cmp uint32)
4752

53+
//export tinygo_futex_wait_timeout
54+
func tinygo_futex_wait_timeout(addr *uint32, cmp uint32, timeout uint64)
55+
4856
//export tinygo_futex_wake
4957
func tinygo_futex_wake(addr *uint32, num uint32)

src/internal/task/linux.go

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
//go:build linux && !baremetal
2+
3+
package task
4+
5+
import "unsafe"
6+
7+
// Musl uses a pointer (or unsigned long for C++) so unsafe.Pointer should be
8+
// fine.
9+
type threadID unsafe.Pointer

src/internal/task/semaphore.go

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
package task
2+
3+
// Barebones semaphore implementation.
4+
// The main limitation is that if there are multiple waiters, a single Post()
5+
// call won't do anything. Only when Post() has been called to awaken all
6+
// waiters will the waiters proceed.
7+
// This limitation is not a problem when there will only be a single waiter.
8+
type Semaphore struct {
9+
futex Futex
10+
}
11+
12+
// Post (unlock) the semaphore, incrementing the value in the semaphore.
13+
func (s *Semaphore) Post() {
14+
newValue := s.futex.Add(1)
15+
if newValue == 0 {
16+
s.futex.WakeAll()
17+
}
18+
}
19+
20+
// Wait (lock) the semaphore, decrementing the value in the semaphore.
21+
func (s *Semaphore) Wait() {
22+
delta := int32(-1)
23+
value := s.futex.Add(uint32(delta))
24+
for {
25+
if int32(value) >= 0 {
26+
// Semaphore unlocked!
27+
return
28+
}
29+
s.futex.Wait(value)
30+
value = s.futex.Load()
31+
}
32+
}

0 commit comments

Comments
 (0)