2014-08-24 02:41:23 -06:00
|
|
|
// Copyright 2009 The Go Authors. All rights reserved.
|
|
|
|
// Use of this source code is governed by a BSD-style
|
|
|
|
// license that can be found in the LICENSE file.
|
|
|
|
|
|
|
|
// Semaphore implementation exposed to Go.
|
|
|
|
// Intended use is provide a sleep and wakeup
|
|
|
|
// primitive that can be used in the contended case
|
|
|
|
// of other synchronization primitives.
|
|
|
|
// Thus it targets the same goal as Linux's futex,
|
|
|
|
// but it has much simpler semantics.
|
|
|
|
//
|
|
|
|
// That is, don't think of these as semaphores.
|
|
|
|
// Think of them as a way to implement sleep and wakeup
|
|
|
|
// such that every sleep is paired with a single wakeup,
|
|
|
|
// even if, due to races, the wakeup happens before the sleep.
|
|
|
|
//
|
|
|
|
// See Mullender and Cox, ``Semaphores in Plan 9,''
|
|
|
|
// http://swtch.com/semaphore.pdf
|
|
|
|
|
|
|
|
package runtime
|
|
|
|
|
|
|
|
import "unsafe"
|
|
|
|
|
2014-08-25 10:12:26 -06:00
|
|
|
// Asynchronous semaphore for sync.Mutex.
|
|
|
|
|
|
|
|
type semaRoot struct {
|
2014-08-27 21:32:49 -06:00
|
|
|
lock mutex
|
2014-08-25 10:12:26 -06:00
|
|
|
head *sudog
|
|
|
|
tail *sudog
|
|
|
|
nwait uint32 // Number of waiters. Read w/o the lock.
|
|
|
|
}
|
|
|
|
|
|
|
|
// Prime to not correlate with any user patterns.
|
|
|
|
const semTabSize = 251
|
|
|
|
|
|
|
|
var semtable [semTabSize]struct {
|
|
|
|
root semaRoot
|
2014-09-16 08:22:15 -06:00
|
|
|
pad [_CacheLineSize - unsafe.Sizeof(semaRoot{})]byte
|
2014-08-25 10:12:26 -06:00
|
|
|
}
|
|
|
|
|
2014-12-22 11:27:53 -07:00
|
|
|
//go:linkname sync_runtime_Semacquire sync.runtime_Semacquire
|
|
|
|
func sync_runtime_Semacquire(addr *uint32) {
|
2014-08-25 10:12:26 -06:00
|
|
|
semacquire(addr, true)
|
|
|
|
}
|
|
|
|
|
2014-12-22 11:27:53 -07:00
|
|
|
//go:linkname net_runtime_Semacquire net.runtime_Semacquire
|
|
|
|
func net_runtime_Semacquire(addr *uint32) {
|
|
|
|
semacquire(addr, true)
|
|
|
|
}
|
|
|
|
|
|
|
|
//go:linkname sync_runtime_Semrelease sync.runtime_Semrelease
|
|
|
|
func sync_runtime_Semrelease(addr *uint32) {
|
|
|
|
semrelease(addr)
|
|
|
|
}
|
|
|
|
|
|
|
|
//go:linkname net_runtime_Semrelease net.runtime_Semrelease
|
|
|
|
func net_runtime_Semrelease(addr *uint32) {
|
2014-08-25 10:12:26 -06:00
|
|
|
semrelease(addr)
|
|
|
|
}
|
|
|
|
|
|
|
|
// Called from runtime.
|
|
|
|
func semacquire(addr *uint32, profile bool) {
|
2014-09-16 18:26:16 -06:00
|
|
|
gp := getg()
|
|
|
|
if gp != gp.m.curg {
|
2014-12-27 21:58:00 -07:00
|
|
|
throw("semacquire not on the G stack")
|
2014-09-16 18:26:16 -06:00
|
|
|
}
|
|
|
|
|
2014-08-25 10:12:26 -06:00
|
|
|
// Easy case.
|
|
|
|
if cansemacquire(addr) {
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
// Harder case:
|
|
|
|
// increment waiter count
|
|
|
|
// try cansemacquire one more time, return if succeeded
|
|
|
|
// enqueue itself as a waiter
|
|
|
|
// sleep
|
|
|
|
// (waiter descriptor is dequeued by signaler)
|
|
|
|
s := acquireSudog()
|
|
|
|
root := semroot(addr)
|
|
|
|
t0 := int64(0)
|
|
|
|
s.releasetime = 0
|
|
|
|
if profile && blockprofilerate > 0 {
|
cmd/cc, runtime: preserve C runtime type names in generated Go
uintptr or uint64 in the runtime C were turning into uint in the Go,
bool was turning into uint8, and so on. Fix that.
Also delete Go wrappers for C functions.
The C functions can be called directly now
(but still eventually need to be converted to Go).
LGTM=bradfitz, minux, iant
R=golang-codereviews, bradfitz, iant, minux
CC=golang-codereviews, khr, r
https://golang.org/cl/138740043
2014-08-27 19:59:49 -06:00
|
|
|
t0 = cputicks()
|
2014-08-25 10:12:26 -06:00
|
|
|
s.releasetime = -1
|
|
|
|
}
|
|
|
|
for {
|
2014-08-27 21:32:49 -06:00
|
|
|
lock(&root.lock)
|
2014-08-25 10:12:26 -06:00
|
|
|
// Add ourselves to nwait to disable "easy case" in semrelease.
|
cmd/cc, runtime: preserve C runtime type names in generated Go
uintptr or uint64 in the runtime C were turning into uint in the Go,
bool was turning into uint8, and so on. Fix that.
Also delete Go wrappers for C functions.
The C functions can be called directly now
(but still eventually need to be converted to Go).
LGTM=bradfitz, minux, iant
R=golang-codereviews, bradfitz, iant, minux
CC=golang-codereviews, khr, r
https://golang.org/cl/138740043
2014-08-27 19:59:49 -06:00
|
|
|
xadd(&root.nwait, 1)
|
2014-08-25 10:12:26 -06:00
|
|
|
// Check cansemacquire to avoid missed wakeup.
|
|
|
|
if cansemacquire(addr) {
|
cmd/cc, runtime: preserve C runtime type names in generated Go
uintptr or uint64 in the runtime C were turning into uint in the Go,
bool was turning into uint8, and so on. Fix that.
Also delete Go wrappers for C functions.
The C functions can be called directly now
(but still eventually need to be converted to Go).
LGTM=bradfitz, minux, iant
R=golang-codereviews, bradfitz, iant, minux
CC=golang-codereviews, khr, r
https://golang.org/cl/138740043
2014-08-27 19:59:49 -06:00
|
|
|
xadd(&root.nwait, -1)
|
2014-08-27 21:32:49 -06:00
|
|
|
unlock(&root.lock)
|
2014-08-25 10:12:26 -06:00
|
|
|
break
|
|
|
|
}
|
|
|
|
// Any semrelease after the cansemacquire knows we're waiting
|
|
|
|
// (we set nwait above), so go to sleep.
|
|
|
|
root.queue(addr, s)
|
2015-02-21 11:01:40 -07:00
|
|
|
goparkunlock(&root.lock, "semacquire", traceEvGoBlockSync, 4)
|
2014-08-25 10:12:26 -06:00
|
|
|
if cansemacquire(addr) {
|
|
|
|
break
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if s.releasetime > 0 {
|
cmd/cc, runtime: preserve C runtime type names in generated Go
uintptr or uint64 in the runtime C were turning into uint in the Go,
bool was turning into uint8, and so on. Fix that.
Also delete Go wrappers for C functions.
The C functions can be called directly now
(but still eventually need to be converted to Go).
LGTM=bradfitz, minux, iant
R=golang-codereviews, bradfitz, iant, minux
CC=golang-codereviews, khr, r
https://golang.org/cl/138740043
2014-08-27 19:59:49 -06:00
|
|
|
blockevent(int64(s.releasetime)-t0, 3)
|
2014-08-25 10:12:26 -06:00
|
|
|
}
|
|
|
|
releaseSudog(s)
|
|
|
|
}
|
|
|
|
|
|
|
|
func semrelease(addr *uint32) {
|
|
|
|
root := semroot(addr)
|
cmd/cc, runtime: preserve C runtime type names in generated Go
uintptr or uint64 in the runtime C were turning into uint in the Go,
bool was turning into uint8, and so on. Fix that.
Also delete Go wrappers for C functions.
The C functions can be called directly now
(but still eventually need to be converted to Go).
LGTM=bradfitz, minux, iant
R=golang-codereviews, bradfitz, iant, minux
CC=golang-codereviews, khr, r
https://golang.org/cl/138740043
2014-08-27 19:59:49 -06:00
|
|
|
xadd(addr, 1)
|
2014-08-25 10:12:26 -06:00
|
|
|
|
|
|
|
// Easy case: no waiters?
|
|
|
|
// This check must happen after the xadd, to avoid a missed wakeup
|
|
|
|
// (see loop in semacquire).
|
cmd/cc, runtime: preserve C runtime type names in generated Go
uintptr or uint64 in the runtime C were turning into uint in the Go,
bool was turning into uint8, and so on. Fix that.
Also delete Go wrappers for C functions.
The C functions can be called directly now
(but still eventually need to be converted to Go).
LGTM=bradfitz, minux, iant
R=golang-codereviews, bradfitz, iant, minux
CC=golang-codereviews, khr, r
https://golang.org/cl/138740043
2014-08-27 19:59:49 -06:00
|
|
|
if atomicload(&root.nwait) == 0 {
|
2014-08-25 10:12:26 -06:00
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
// Harder case: search for a waiter and wake it.
|
2014-08-27 21:32:49 -06:00
|
|
|
lock(&root.lock)
|
cmd/cc, runtime: preserve C runtime type names in generated Go
uintptr or uint64 in the runtime C were turning into uint in the Go,
bool was turning into uint8, and so on. Fix that.
Also delete Go wrappers for C functions.
The C functions can be called directly now
(but still eventually need to be converted to Go).
LGTM=bradfitz, minux, iant
R=golang-codereviews, bradfitz, iant, minux
CC=golang-codereviews, khr, r
https://golang.org/cl/138740043
2014-08-27 19:59:49 -06:00
|
|
|
if atomicload(&root.nwait) == 0 {
|
2014-08-25 10:12:26 -06:00
|
|
|
// The count is already consumed by another goroutine,
|
|
|
|
// so no need to wake up another goroutine.
|
2014-08-27 21:32:49 -06:00
|
|
|
unlock(&root.lock)
|
2014-08-25 10:12:26 -06:00
|
|
|
return
|
|
|
|
}
|
|
|
|
s := root.head
|
|
|
|
for ; s != nil; s = s.next {
|
|
|
|
if s.elem == unsafe.Pointer(addr) {
|
cmd/cc, runtime: preserve C runtime type names in generated Go
uintptr or uint64 in the runtime C were turning into uint in the Go,
bool was turning into uint8, and so on. Fix that.
Also delete Go wrappers for C functions.
The C functions can be called directly now
(but still eventually need to be converted to Go).
LGTM=bradfitz, minux, iant
R=golang-codereviews, bradfitz, iant, minux
CC=golang-codereviews, khr, r
https://golang.org/cl/138740043
2014-08-27 19:59:49 -06:00
|
|
|
xadd(&root.nwait, -1)
|
2014-08-25 10:12:26 -06:00
|
|
|
root.dequeue(s)
|
|
|
|
break
|
|
|
|
}
|
|
|
|
}
|
2014-08-27 21:32:49 -06:00
|
|
|
unlock(&root.lock)
|
2014-08-25 10:12:26 -06:00
|
|
|
if s != nil {
|
|
|
|
if s.releasetime != 0 {
|
cmd/cc, runtime: preserve C runtime type names in generated Go
uintptr or uint64 in the runtime C were turning into uint in the Go,
bool was turning into uint8, and so on. Fix that.
Also delete Go wrappers for C functions.
The C functions can be called directly now
(but still eventually need to be converted to Go).
LGTM=bradfitz, minux, iant
R=golang-codereviews, bradfitz, iant, minux
CC=golang-codereviews, khr, r
https://golang.org/cl/138740043
2014-08-27 19:59:49 -06:00
|
|
|
s.releasetime = cputicks()
|
2014-08-25 10:12:26 -06:00
|
|
|
}
|
2015-02-21 11:01:40 -07:00
|
|
|
goready(s.g, 4)
|
2014-08-25 10:12:26 -06:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func semroot(addr *uint32) *semaRoot {
|
|
|
|
return &semtable[(uintptr(unsafe.Pointer(addr))>>3)%semTabSize].root
|
|
|
|
}
|
|
|
|
|
|
|
|
func cansemacquire(addr *uint32) bool {
|
|
|
|
for {
|
cmd/cc, runtime: preserve C runtime type names in generated Go
uintptr or uint64 in the runtime C were turning into uint in the Go,
bool was turning into uint8, and so on. Fix that.
Also delete Go wrappers for C functions.
The C functions can be called directly now
(but still eventually need to be converted to Go).
LGTM=bradfitz, minux, iant
R=golang-codereviews, bradfitz, iant, minux
CC=golang-codereviews, khr, r
https://golang.org/cl/138740043
2014-08-27 19:59:49 -06:00
|
|
|
v := atomicload(addr)
|
2014-08-25 10:12:26 -06:00
|
|
|
if v == 0 {
|
|
|
|
return false
|
|
|
|
}
|
cmd/cc, runtime: preserve C runtime type names in generated Go
uintptr or uint64 in the runtime C were turning into uint in the Go,
bool was turning into uint8, and so on. Fix that.
Also delete Go wrappers for C functions.
The C functions can be called directly now
(but still eventually need to be converted to Go).
LGTM=bradfitz, minux, iant
R=golang-codereviews, bradfitz, iant, minux
CC=golang-codereviews, khr, r
https://golang.org/cl/138740043
2014-08-27 19:59:49 -06:00
|
|
|
if cas(addr, v, v-1) {
|
2014-08-25 10:12:26 -06:00
|
|
|
return true
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func (root *semaRoot) queue(addr *uint32, s *sudog) {
|
|
|
|
s.g = getg()
|
|
|
|
s.elem = unsafe.Pointer(addr)
|
|
|
|
s.next = nil
|
|
|
|
s.prev = root.tail
|
|
|
|
if root.tail != nil {
|
|
|
|
root.tail.next = s
|
|
|
|
} else {
|
|
|
|
root.head = s
|
|
|
|
}
|
|
|
|
root.tail = s
|
|
|
|
}
|
|
|
|
|
|
|
|
func (root *semaRoot) dequeue(s *sudog) {
|
|
|
|
if s.next != nil {
|
|
|
|
s.next.prev = s.prev
|
|
|
|
} else {
|
|
|
|
root.tail = s.prev
|
|
|
|
}
|
|
|
|
if s.prev != nil {
|
|
|
|
s.prev.next = s.next
|
|
|
|
} else {
|
|
|
|
root.head = s.next
|
|
|
|
}
|
2014-10-03 11:36:48 -06:00
|
|
|
s.elem = nil
|
2014-08-25 10:12:26 -06:00
|
|
|
s.next = nil
|
|
|
|
s.prev = nil
|
|
|
|
}
|
|
|
|
|
2014-08-24 02:41:23 -06:00
|
|
|
// Synchronous semaphore for sync.Cond.
|
|
|
|
type syncSema struct {
|
2014-08-27 21:32:49 -06:00
|
|
|
lock mutex
|
2014-08-24 02:41:23 -06:00
|
|
|
head *sudog
|
|
|
|
tail *sudog
|
|
|
|
}
|
|
|
|
|
2014-12-22 11:27:53 -07:00
|
|
|
// syncsemacquire waits for a pairing syncsemrelease on the same semaphore s.
|
|
|
|
//go:linkname syncsemacquire sync.runtime_Syncsemacquire
|
2014-08-24 02:41:23 -06:00
|
|
|
func syncsemacquire(s *syncSema) {
|
2014-08-27 21:32:49 -06:00
|
|
|
lock(&s.lock)
|
2014-08-24 02:41:23 -06:00
|
|
|
if s.head != nil && s.head.nrelease > 0 {
|
|
|
|
// Have pending release, consume it.
|
|
|
|
var wake *sudog
|
|
|
|
s.head.nrelease--
|
|
|
|
if s.head.nrelease == 0 {
|
|
|
|
wake = s.head
|
2014-08-25 10:12:26 -06:00
|
|
|
s.head = wake.next
|
2014-08-24 02:41:23 -06:00
|
|
|
if s.head == nil {
|
|
|
|
s.tail = nil
|
|
|
|
}
|
|
|
|
}
|
2014-08-27 21:32:49 -06:00
|
|
|
unlock(&s.lock)
|
2014-08-24 02:41:23 -06:00
|
|
|
if wake != nil {
|
runtime: fix sudog leak
The SudoG used to sit on the stack, so it was cheap to allocated
and didn't need to be cleaned up when finished.
For the conversion to Go, we had to move sudog off the stack
for a few reasons, so we added a cache of recently used sudogs
to keep allocation cheap. But we didn't add any of the necessary
cleanup before adding a SudoG to the new cache, and so the cached
SudoGs had stale pointers inside them that have caused all sorts
of awful, hard to debug problems.
CL 155760043 made sure SudoG.elem is cleaned up.
CL 150520043 made sure SudoG.selectdone is cleaned up.
This CL makes sure SudoG.next, SudoG.prev, and SudoG.waitlink
are cleaned up. I should have done this when I did the other two
fields; instead I wasted a week tracking down a leak they caused.
A dangling SudoG.waitlink can point into a sudogcache list that
has been "forgotten" in order to let the GC collect it, but that
dangling .waitlink keeps the list from being collected.
And then the list holding the SudoG with the dangling waitlink
can find itself in the same situation, and so on. We end up
with lists of lists of unusable SudoGs that are still linked into
the object graph and never collected (given the right mix of
non-trivial selects and non-channel synchronization).
More details in golang.org/issue/9110.
Fixes #9110.
LGTM=r
R=r
CC=dvyukov, golang-codereviews, iant, khr
https://golang.org/cl/177870043
2014-11-16 14:44:45 -07:00
|
|
|
wake.next = nil
|
2015-02-21 11:01:40 -07:00
|
|
|
goready(wake.g, 4)
|
2014-08-24 02:41:23 -06:00
|
|
|
}
|
|
|
|
} else {
|
|
|
|
// Enqueue itself.
|
|
|
|
w := acquireSudog()
|
|
|
|
w.g = getg()
|
|
|
|
w.nrelease = -1
|
2014-08-25 10:12:26 -06:00
|
|
|
w.next = nil
|
2014-08-24 02:41:23 -06:00
|
|
|
w.releasetime = 0
|
|
|
|
t0 := int64(0)
|
|
|
|
if blockprofilerate > 0 {
|
cmd/cc, runtime: preserve C runtime type names in generated Go
uintptr or uint64 in the runtime C were turning into uint in the Go,
bool was turning into uint8, and so on. Fix that.
Also delete Go wrappers for C functions.
The C functions can be called directly now
(but still eventually need to be converted to Go).
LGTM=bradfitz, minux, iant
R=golang-codereviews, bradfitz, iant, minux
CC=golang-codereviews, khr, r
https://golang.org/cl/138740043
2014-08-27 19:59:49 -06:00
|
|
|
t0 = cputicks()
|
2014-08-24 02:41:23 -06:00
|
|
|
w.releasetime = -1
|
|
|
|
}
|
|
|
|
if s.tail == nil {
|
|
|
|
s.head = w
|
|
|
|
} else {
|
2014-08-25 10:12:26 -06:00
|
|
|
s.tail.next = w
|
2014-08-24 02:41:23 -06:00
|
|
|
}
|
|
|
|
s.tail = w
|
2015-02-21 11:01:40 -07:00
|
|
|
goparkunlock(&s.lock, "semacquire", traceEvGoBlockCond, 3)
|
2014-08-24 02:41:23 -06:00
|
|
|
if t0 != 0 {
|
cmd/cc, runtime: preserve C runtime type names in generated Go
uintptr or uint64 in the runtime C were turning into uint in the Go,
bool was turning into uint8, and so on. Fix that.
Also delete Go wrappers for C functions.
The C functions can be called directly now
(but still eventually need to be converted to Go).
LGTM=bradfitz, minux, iant
R=golang-codereviews, bradfitz, iant, minux
CC=golang-codereviews, khr, r
https://golang.org/cl/138740043
2014-08-27 19:59:49 -06:00
|
|
|
blockevent(int64(w.releasetime)-t0, 2)
|
2014-08-24 02:41:23 -06:00
|
|
|
}
|
|
|
|
releaseSudog(w)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-12-22 11:27:53 -07:00
|
|
|
// syncsemrelease waits for n pairing syncsemacquire on the same semaphore s.
|
|
|
|
//go:linkname syncsemrelease sync.runtime_Syncsemrelease
|
2014-08-24 02:41:23 -06:00
|
|
|
func syncsemrelease(s *syncSema, n uint32) {
|
2014-08-27 21:32:49 -06:00
|
|
|
lock(&s.lock)
|
2014-08-24 02:41:23 -06:00
|
|
|
for n > 0 && s.head != nil && s.head.nrelease < 0 {
|
|
|
|
// Have pending acquire, satisfy it.
|
|
|
|
wake := s.head
|
2014-08-25 10:12:26 -06:00
|
|
|
s.head = wake.next
|
2014-08-24 02:41:23 -06:00
|
|
|
if s.head == nil {
|
|
|
|
s.tail = nil
|
|
|
|
}
|
|
|
|
if wake.releasetime != 0 {
|
cmd/cc, runtime: preserve C runtime type names in generated Go
uintptr or uint64 in the runtime C were turning into uint in the Go,
bool was turning into uint8, and so on. Fix that.
Also delete Go wrappers for C functions.
The C functions can be called directly now
(but still eventually need to be converted to Go).
LGTM=bradfitz, minux, iant
R=golang-codereviews, bradfitz, iant, minux
CC=golang-codereviews, khr, r
https://golang.org/cl/138740043
2014-08-27 19:59:49 -06:00
|
|
|
wake.releasetime = cputicks()
|
2014-08-24 02:41:23 -06:00
|
|
|
}
|
runtime: fix sudog leak
The SudoG used to sit on the stack, so it was cheap to allocated
and didn't need to be cleaned up when finished.
For the conversion to Go, we had to move sudog off the stack
for a few reasons, so we added a cache of recently used sudogs
to keep allocation cheap. But we didn't add any of the necessary
cleanup before adding a SudoG to the new cache, and so the cached
SudoGs had stale pointers inside them that have caused all sorts
of awful, hard to debug problems.
CL 155760043 made sure SudoG.elem is cleaned up.
CL 150520043 made sure SudoG.selectdone is cleaned up.
This CL makes sure SudoG.next, SudoG.prev, and SudoG.waitlink
are cleaned up. I should have done this when I did the other two
fields; instead I wasted a week tracking down a leak they caused.
A dangling SudoG.waitlink can point into a sudogcache list that
has been "forgotten" in order to let the GC collect it, but that
dangling .waitlink keeps the list from being collected.
And then the list holding the SudoG with the dangling waitlink
can find itself in the same situation, and so on. We end up
with lists of lists of unusable SudoGs that are still linked into
the object graph and never collected (given the right mix of
non-trivial selects and non-channel synchronization).
More details in golang.org/issue/9110.
Fixes #9110.
LGTM=r
R=r
CC=dvyukov, golang-codereviews, iant, khr
https://golang.org/cl/177870043
2014-11-16 14:44:45 -07:00
|
|
|
wake.next = nil
|
2015-02-21 11:01:40 -07:00
|
|
|
goready(wake.g, 4)
|
2014-08-24 02:41:23 -06:00
|
|
|
n--
|
|
|
|
}
|
|
|
|
if n > 0 {
|
|
|
|
// enqueue itself
|
|
|
|
w := acquireSudog()
|
|
|
|
w.g = getg()
|
|
|
|
w.nrelease = int32(n)
|
2014-08-25 10:12:26 -06:00
|
|
|
w.next = nil
|
2014-08-24 02:41:23 -06:00
|
|
|
w.releasetime = 0
|
|
|
|
if s.tail == nil {
|
|
|
|
s.head = w
|
|
|
|
} else {
|
2014-08-25 10:12:26 -06:00
|
|
|
s.tail.next = w
|
2014-08-24 02:41:23 -06:00
|
|
|
}
|
|
|
|
s.tail = w
|
2015-02-21 11:01:40 -07:00
|
|
|
goparkunlock(&s.lock, "semarelease", traceEvGoBlockCond, 3)
|
2014-11-09 18:21:03 -07:00
|
|
|
releaseSudog(w)
|
2014-08-24 02:41:23 -06:00
|
|
|
} else {
|
2014-08-27 21:32:49 -06:00
|
|
|
unlock(&s.lock)
|
2014-08-24 02:41:23 -06:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-12-22 11:27:53 -07:00
|
|
|
//go:linkname syncsemcheck sync.runtime_Syncsemcheck
|
2014-08-24 02:41:23 -06:00
|
|
|
func syncsemcheck(sz uintptr) {
|
|
|
|
if sz != unsafe.Sizeof(syncSema{}) {
|
|
|
|
print("runtime: bad syncSema size - sync=", sz, " runtime=", unsafe.Sizeof(syncSema{}), "\n")
|
2014-12-27 21:58:00 -07:00
|
|
|
throw("bad syncSema size")
|
2014-08-24 02:41:23 -06:00
|
|
|
}
|
|
|
|
}
|