summaryrefslogtreecommitdiff
path: root/src/pkg/runtime/sema.go
diff options
context:
space:
mode:
Diffstat (limited to 'src/pkg/runtime/sema.go')
-rw-r--r--src/pkg/runtime/sema.go266
1 files changed, 0 insertions, 266 deletions
diff --git a/src/pkg/runtime/sema.go b/src/pkg/runtime/sema.go
deleted file mode 100644
index 87ba5463b..000000000
--- a/src/pkg/runtime/sema.go
+++ /dev/null
@@ -1,266 +0,0 @@
-// 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"
-
-// Asynchronous semaphore for sync.Mutex.
-
-type semaRoot struct {
- lock mutex
- 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
- pad [cacheLineSize - unsafe.Sizeof(semaRoot{})]byte
-}
-
-// Called from sync/net packages.
-func asyncsemacquire(addr *uint32) {
- semacquire(addr, true)
-}
-
-func asyncsemrelease(addr *uint32) {
- semrelease(addr)
-}
-
-// Called from runtime.
-func semacquire(addr *uint32, profile bool) {
- // 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 {
- t0 = cputicks()
- s.releasetime = -1
- }
- for {
- lock(&root.lock)
- // Add ourselves to nwait to disable "easy case" in semrelease.
- xadd(&root.nwait, 1)
- // Check cansemacquire to avoid missed wakeup.
- if cansemacquire(addr) {
- xadd(&root.nwait, -1)
- unlock(&root.lock)
- break
- }
- // Any semrelease after the cansemacquire knows we're waiting
- // (we set nwait above), so go to sleep.
- root.queue(addr, s)
- goparkunlock(&root.lock, "semacquire")
- if cansemacquire(addr) {
- break
- }
- }
- if s.releasetime > 0 {
- blockevent(int64(s.releasetime)-t0, 3)
- }
- releaseSudog(s)
-}
-
-func semrelease(addr *uint32) {
- root := semroot(addr)
- xadd(addr, 1)
-
- // Easy case: no waiters?
- // This check must happen after the xadd, to avoid a missed wakeup
- // (see loop in semacquire).
- if atomicload(&root.nwait) == 0 {
- return
- }
-
- // Harder case: search for a waiter and wake it.
- lock(&root.lock)
- if atomicload(&root.nwait) == 0 {
- // The count is already consumed by another goroutine,
- // so no need to wake up another goroutine.
- unlock(&root.lock)
- return
- }
- s := root.head
- for ; s != nil; s = s.next {
- if s.elem == unsafe.Pointer(addr) {
- xadd(&root.nwait, -1)
- root.dequeue(s)
- break
- }
- }
- unlock(&root.lock)
- if s != nil {
- if s.releasetime != 0 {
- s.releasetime = cputicks()
- }
- goready(s.g)
- }
-}
-
-func semroot(addr *uint32) *semaRoot {
- return &semtable[(uintptr(unsafe.Pointer(addr))>>3)%semTabSize].root
-}
-
-func cansemacquire(addr *uint32) bool {
- for {
- v := atomicload(addr)
- if v == 0 {
- return false
- }
- if cas(addr, v, v-1) {
- 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
- }
- s.next = nil
- s.prev = nil
-}
-
-// Synchronous semaphore for sync.Cond.
-type syncSema struct {
- lock mutex
- head *sudog
- tail *sudog
-}
-
-// Syncsemacquire waits for a pairing syncsemrelease on the same semaphore s.
-func syncsemacquire(s *syncSema) {
- lock(&s.lock)
- 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
- s.head = wake.next
- if s.head == nil {
- s.tail = nil
- }
- }
- unlock(&s.lock)
- if wake != nil {
- goready(wake.g)
- }
- } else {
- // Enqueue itself.
- w := acquireSudog()
- w.g = getg()
- w.nrelease = -1
- w.next = nil
- w.releasetime = 0
- t0 := int64(0)
- if blockprofilerate > 0 {
- t0 = cputicks()
- w.releasetime = -1
- }
- if s.tail == nil {
- s.head = w
- } else {
- s.tail.next = w
- }
- s.tail = w
- goparkunlock(&s.lock, "semacquire")
- if t0 != 0 {
- blockevent(int64(w.releasetime)-t0, 2)
- }
- releaseSudog(w)
- }
-}
-
-// Syncsemrelease waits for n pairing syncsemacquire on the same semaphore s.
-func syncsemrelease(s *syncSema, n uint32) {
- lock(&s.lock)
- for n > 0 && s.head != nil && s.head.nrelease < 0 {
- // Have pending acquire, satisfy it.
- wake := s.head
- s.head = wake.next
- if s.head == nil {
- s.tail = nil
- }
- if wake.releasetime != 0 {
- wake.releasetime = cputicks()
- }
- goready(wake.g)
- n--
- }
- if n > 0 {
- // enqueue itself
- w := acquireSudog()
- w.g = getg()
- w.nrelease = int32(n)
- w.next = nil
- w.releasetime = 0
- if s.tail == nil {
- s.head = w
- } else {
- s.tail.next = w
- }
- s.tail = w
- goparkunlock(&s.lock, "semarelease")
- } else {
- unlock(&s.lock)
- }
-}
-
-func syncsemcheck(sz uintptr) {
- if sz != unsafe.Sizeof(syncSema{}) {
- print("runtime: bad syncSema size - sync=", sz, " runtime=", unsafe.Sizeof(syncSema{}), "\n")
- gothrow("bad syncSema size")
- }
-}