Skip to content

proposal: runtime: add block/wake function #46431

Closed
@GuhuangLS

Description

@GuhuangLS

Background: channel is designed to be a data transfer pipe between
go routines. A scenario in gVisor is: block/wake a G (stands for a
task) by using channel, wherein there's no need for data transfer.
Channel is relatively too heavy for this case.
Channel manages Gs in a list, and has capacity. When the channel is
full, the sender will bock, and the channel is clear, the receiver
is blocked. The receiver pushed to chan list, then schedule to run
next. The sender uses goready to wake Gs in the chan list.

A summary on our idea: introduce a new set of APIs for goroutine
wake/block.
For example, Waitlist at gVisor(such as futex.waiter:
pkg/sentry/kernel/futex/futex.go) used to task IPC; Waiter uses
GetG() to get the address of G, then saved at waiter struct; then
call BlockG to schedule the M to run next G. The coming waker
uses the G(waiter) address to wake it by WakeG(G).

Details:

We propose three new APIs:

GetG() - used to get the address of G by itself, which can be saved
at waitlist.By address, the waker find the G easier, then to wake it at
go runtime.

WakeG() - can be used to wake one G, which can be in running/blocked
status.
If the waiter has been blocked aready, then waker wakes it by
goready().
If the waiter is in waiting process, the one got sched.wakeLock first
processes first:if waiter is later, then waker wakes it by goready(). If the
waiter got the lock after the waker,then no need to block, because
"gp.wakeStatus == gStatusWaked".
If the waker coming, waiter not blocked, then if the waiter is at list, then
modifies gp.wakeStatus = gStatusWaked. when waiter coming, no need
bo block. if no waiter at the list, no need to WakeG().

BlockG() - can be used to block goroutine by itself.
modify:
GuhuangLS@109c8f5

How we use this in gVisor:

GuhuangLS/gvisor@97e0e6c

In futex()/epoll_wait(), we can modify it to use the new mechanism
for block and wake. Between sentry and go runtime, we maintain the
status of task Gs. Let's use futex as an example, add running status
at goruntime, NoWake,Waked,Blocked.

At sentry, one task/G can use BlockG() to block, like <-chan. Other
tasks/Gs can use WakeG() to wake the task/G which is blocked by BlockG()
, like chan <-. Based on a basic prototype of Go and gVisor, we use the
program in google/gvisor#2033(comment) as the test program.

We can see 22% improvement by test case:
google/gvisor#2033.
cc @prattmic @ianlewis @QinChenggang @tanjianfeng @lubinszARM

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions