]> Cypherpunks repositories - gostls13.git/commit
runtime: cleanup openbsd semasleep implementation
authorMatthew Dempsky <mdempsky@google.com>
Wed, 10 Sep 2014 00:41:48 +0000 (17:41 -0700)
committerIan Lance Taylor <iant@golang.org>
Wed, 10 Sep 2014 00:41:48 +0000 (17:41 -0700)
commitd955dfb0075addb844d1d683a96967bb7ea0dea7
tree8219f60cc4d7866e6500873d97580406405f5aad
parent9f012e100210b6fb4e9bf8972e3d3b04c44b863a
runtime: cleanup openbsd semasleep implementation

The previous implementation had several subtle issues.  It's not
clear if any of these could actually be causing the flakiness
problems on openbsd/386, but fixing them should only help.

1. thrsleep() is implemented internally as unlock, then test *abort
(if abort != nil), then tsleep().  Under the current code, that makes
it theoretically possible that semasleep()/thrsleep() could release
waitsemalock, then a racing semawakeup() could acquire the lock,
increment waitsemacount, and call thrwakeup()/wakeup() before
thrsleep() reaches tsleep().  (In practice, OpenBSD's big kernel lock
seems unlikely to let this actually happen.)

The proper way to avoid this is to pass &waitsemacount as the abort
pointer to thrsleep so thrsleep knows to re-check it before going to
sleep, and to wakeup if it's non-zero.  Then we avoid any races.
(I actually suspect openbsd's sema{sleep,wakeup}() could be further
simplified using cas/xadd instead of locks, but I don't want to be
more intrusive than necessary so late in the 1.4 release cycle.)

2. semasleep() takes a relative sleep duration, but thrsleep() needs
an absolute sleep deadline.  Instead of recomputing the deadline each
iteration, compute it once up front and use (*Timespec)(nil) to signify
no deadline.  Ensures we retry properly if there's a spurious wakeup.

3. Instead of assuming if thrsleep() woke up and waitsemacount wasn't
available that we must have hit the deadline, check that the system
call returned EWOULDBLOCK.

4. Instead of assuming that 64-bit systems are little-endian, compute
timediv() using a temporary int32 nsec and then assign it to tv_nsec.

LGTM=iant
R=jsing, iant
CC=golang-codereviews
https://golang.org/cl/137960043
src/runtime/os_openbsd.c