1// Copyright 2023 The Go Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style
3// license that can be found in the LICENSE file.
4
5//go:build wasip1
6
7package runtime
8
9// wasm has no support for threads yet. There is no preemption.
10// See proposal: https://github.com/WebAssembly/threads
11// Waiting for a mutex or timeout is implemented as a busy loop
12// while allowing other goroutines to run.
13
14const (
15	mutex_unlocked = 0
16	mutex_locked   = 1
17
18	active_spin     = 4
19	active_spin_cnt = 30
20)
21
22func mutexContended(l *mutex) bool {
23	return false
24}
25
26func lock(l *mutex) {
27	lockWithRank(l, getLockRank(l))
28}
29
30func lock2(l *mutex) {
31	if l.key == mutex_locked {
32		// wasm is single-threaded so we should never
33		// observe this.
34		throw("self deadlock")
35	}
36	gp := getg()
37	if gp.m.locks < 0 {
38		throw("lock count")
39	}
40	gp.m.locks++
41	l.key = mutex_locked
42}
43
44func unlock(l *mutex) {
45	unlockWithRank(l)
46}
47
48func unlock2(l *mutex) {
49	if l.key == mutex_unlocked {
50		throw("unlock of unlocked lock")
51	}
52	gp := getg()
53	gp.m.locks--
54	if gp.m.locks < 0 {
55		throw("lock count")
56	}
57	l.key = mutex_unlocked
58}
59
60// One-time notifications.
61func noteclear(n *note) {
62	n.key = 0
63}
64
65func notewakeup(n *note) {
66	if n.key != 0 {
67		print("notewakeup - double wakeup (", n.key, ")\n")
68		throw("notewakeup - double wakeup")
69	}
70	n.key = 1
71}
72
73func notesleep(n *note) {
74	throw("notesleep not supported by wasi")
75}
76
77func notetsleep(n *note, ns int64) bool {
78	throw("notetsleep not supported by wasi")
79	return false
80}
81
82// same as runtime·notetsleep, but called on user g (not g0)
83func notetsleepg(n *note, ns int64) bool {
84	gp := getg()
85	if gp == gp.m.g0 {
86		throw("notetsleepg on g0")
87	}
88
89	deadline := nanotime() + ns
90	for {
91		if n.key != 0 {
92			return true
93		}
94		if sched_yield() != 0 {
95			throw("sched_yield failed")
96		}
97		Gosched()
98		if ns >= 0 && nanotime() >= deadline {
99			return false
100		}
101	}
102}
103
104func beforeIdle(int64, int64) (*g, bool) {
105	return nil, false
106}
107
108func checkTimeouts() {}
109
110//go:wasmimport wasi_snapshot_preview1 sched_yield
111func sched_yield() errno
112