-
Notifications
You must be signed in to change notification settings - Fork 18.4k
Description
The current runtime.lock2 implementation does a bit of spinning to try to acquire the runtime.mutex before sleeping. If a thread has gone to sleep within lock2 (via a syscall), it will eventually require another thread (in unlock2) to do another syscall to wake it. The bit of spinning allows us to avoid those syscalls in some cases. Slowing down a bit and trying again, at a high level, seems good; maybe the previous holder has exited the critical section.
The first phase of spinning involves a runtime.procyield call, which asks the processor to pause for a moment (on the scale of tens or hundreds of nanoseconds). There's some uncertainty about what that duration is and what it should be (described in part in #69232) but the idea of using this mechanism to slow down for a bit, again at a high level, seems good.
The second phase of spinning involves a runtime.osyield call. That's a syscall, implemented on Linux as a call to sched_yield(2). The discussion in CL 473656 links to https://www.realworldtech.com/forum/?threadid=189711&curpostid=189752 , which gives a perspective on why that's not a universally good idea.
- It's a syscall, so it doesn't help with avoiding syscalls. (Though a single syscall here has a chance of avoiding a pair of syscalls, one to sleep indefinitely and one to wake).
- The semantics aren't very well defined, and—very loosely speaking—don't align with our goals. We don't mean for the OS scheduler to drag a thread over from another NUMA node just because we said "we can't run at this instant".
Maybe we should delete that part of lock2. Or maybe we should replace it with an explicit nanosleep(2) call of some tiny time interval.
I don't see any urgency here. Mostly I'd like a tracking issue to reference in lock2's comments.
CC @golang/runtime
Metadata
Metadata
Assignees
Labels
Type
Projects
Status