Improved blocking (#513)

core: major improvements to blocking, including support for buffered channels.
This commit is contained in:
Jaden Weiss
2019-09-22 11:58:00 -04:00
committed by Ron Evans
parent d17f500c8b
commit d843ebfe40
12 changed files with 1069 additions and 486 deletions
+5 -40
View File
@@ -31,6 +31,7 @@ type task struct {
// getCoroutine returns the currently executing goroutine. It is used as an
// intrinsic when compiling channel operations, but is not necessary with the
// task-based scheduler.
//go:inline
func getCoroutine() *task {
return currentTask
}
@@ -67,15 +68,6 @@ func swapTask(oldTask, newTask *task) {
//go:linkname swapTaskLower tinygo_swapTask
func swapTaskLower(oldTask, newTask *task)
// Goexit terminates the currently running goroutine. No other goroutines are affected.
//
// Unlike the main Go implementation, no deffered calls will be run.
//export runtime.Goexit
func Goexit() {
// Swap without rescheduling first, effectively exiting the goroutine.
swapTask(currentTask, &schedulerState)
}
// startTask is a small wrapper function that sets up the first (and only)
// argument to the new goroutine and makes sure it is exited when the goroutine
// finishes.
@@ -96,40 +88,13 @@ func startGoroutine(fn, args uintptr) {
runqueuePushBack(t)
}
//go:linkname sleep time.Sleep
func sleep(d int64) {
sleepTicks(timeUnit(d / tickMicros))
}
// sleepCurrentTask suspends the current goroutine. This is a compiler
// intrinsic. It replaces calls to time.Sleep when a scheduler is in use.
func sleepCurrentTask(d int64) {
sleepTask(currentTask, d)
// yield suspends execution of the current goroutine
// any wakeups must be configured before calling yield
//export runtime.yield
func yield() {
swapTask(currentTask, &schedulerState)
}
// deadlock is called when a goroutine cannot proceed any more, but is in theory
// not exited (so deferred calls won't run). This can happen for example in code
// like this, that blocks forever:
//
// select{}
func deadlock() {
Goexit()
}
// reactivateParent reactivates the parent goroutine. It is a no-op for the task
// based scheduler.
func reactivateParent(t *task) {
// Nothing to do here, tasks don't stop automatically.
}
// chanYield exits the current goroutine. Used in the channel implementation, to
// suspend the current goroutine until it is reactivated by a channel operation
// of a different goroutine.
func chanYield() {
Goexit()
}
// getSystemStackPointer returns the current stack pointer of the system stack.
// This is not necessarily the same as the current stack pointer.
func getSystemStackPointer() uintptr {