diff options
| author | Dmitriy Vyukov <dvyukov@google.com> | 2014-08-24 12:41:23 +0400 |
|---|---|---|
| committer | Dmitriy Vyukov <dvyukov@google.com> | 2014-08-24 12:41:23 +0400 |
| commit | a6950fe0f9c23fe681109db746038092b5a04728 (patch) | |
| tree | a6a374f5c65a61e8f113b1b3caeabd3c24dedbd3 /src/pkg/runtime | |
| parent | 9a1e142bbc3209f8899a729ec857a1c8838bf9f4 (diff) | |
| download | go-a6950fe0f9c23fe681109db746038092b5a04728.tar.xz | |
runtime: convert synchronous semaphores to Go
LGTM=rsc
R=golang-codereviews, khr, rsc
CC=golang-codereviews, rlh
https://golang.org/cl/130340043
Diffstat (limited to 'src/pkg/runtime')
| -rw-r--r-- | src/pkg/runtime/sema.go | 117 | ||||
| -rw-r--r-- | src/pkg/runtime/sema.goc | 90 | ||||
| -rw-r--r-- | src/pkg/runtime/thunk.s | 21 |
3 files changed, 138 insertions, 90 deletions
diff --git a/src/pkg/runtime/sema.go b/src/pkg/runtime/sema.go new file mode 100644 index 0000000000..ac855f9d8c --- /dev/null +++ b/src/pkg/runtime/sema.go @@ -0,0 +1,117 @@ +// 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" + +// Synchronous semaphore for sync.Cond. +type syncSema struct { + lock lock + head *sudog + tail *sudog +} + +// Syncsemacquire waits for a pairing syncsemrelease on the same semaphore s. +func syncsemacquire(s *syncSema) { + golock(&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.link + if s.head == nil { + s.tail = nil + } + } + gounlock(&s.lock) + if wake != nil { + goready(wake.g) + } + } else { + // Enqueue itself. + w := acquireSudog() + w.g = getg() + w.nrelease = -1 + w.link = nil + w.releasetime = 0 + t0 := int64(0) + if blockprofilerate > 0 { + t0 = gocputicks() + w.releasetime = -1 + } + if s.tail == nil { + s.head = w + } else { + s.tail.link = w + } + s.tail = w + goparkunlock(&s.lock, "semacquire") + if t0 != 0 { + goblockevent(int64(w.releasetime)-t0, 2) + } + releaseSudog(w) + } +} + +// Syncsemrelease waits for n pairing syncsemacquire on the same semaphore s. +func syncsemrelease(s *syncSema, n uint32) { + golock(&s.lock) + for n > 0 && s.head != nil && s.head.nrelease < 0 { + // Have pending acquire, satisfy it. + wake := s.head + s.head = wake.link + if s.head == nil { + s.tail = nil + } + if wake.releasetime != 0 { + // TODO: Remove use of unsafe here. + releasetimep := (*int64)(unsafe.Pointer(&wake.releasetime)) + *releasetimep = gocputicks() + } + goready(wake.g) + n-- + } + if n > 0 { + // enqueue itself + w := acquireSudog() + w.g = getg() + w.nrelease = int32(n) + w.link = nil + w.releasetime = 0 + if s.tail == nil { + s.head = w + } else { + s.tail.link = w + } + s.tail = w + goparkunlock(&s.lock, "semarelease") + } else { + gounlock(&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") + } +} diff --git a/src/pkg/runtime/sema.goc b/src/pkg/runtime/sema.goc index 7b1f8f2ed3..7724566a1e 100644 --- a/src/pkg/runtime/sema.goc +++ b/src/pkg/runtime/sema.goc @@ -202,93 +202,3 @@ func runtime_Semacquire(addr *uint32) { func runtime_Semrelease(addr *uint32) { runtime·semrelease(addr); } - -typedef struct SyncSema SyncSema; -struct SyncSema -{ - Lock lock; - SemaWaiter* head; - SemaWaiter* tail; -}; - -func runtime_Syncsemcheck(size uintptr) { - if(size != sizeof(SyncSema)) { - runtime·printf("bad SyncSema size: sync:%D runtime:%D\n", (int64)size, (int64)sizeof(SyncSema)); - runtime·throw("bad SyncSema size"); - } -} - -// Syncsemacquire waits for a pairing Syncsemrelease on the same semaphore s. -func runtime_Syncsemacquire(s *SyncSema) { - SemaWaiter w, *wake; - int64 t0; - - w.g = g; - w.nrelease = -1; - w.next = nil; - w.releasetime = 0; - t0 = 0; - if(runtime·blockprofilerate > 0) { - t0 = runtime·cputicks(); - w.releasetime = -1; - } - - runtime·lock(&s->lock); - if(s->head && s->head->nrelease > 0) { - // have pending release, consume it - wake = nil; - s->head->nrelease--; - if(s->head->nrelease == 0) { - wake = s->head; - s->head = wake->next; - if(s->head == nil) - s->tail = nil; - } - runtime·unlock(&s->lock); - if(wake) - runtime·ready(wake->g); - } else { - // enqueue itself - if(s->tail == nil) - s->head = &w; - else - s->tail->next = &w; - s->tail = &w; - runtime·parkunlock(&s->lock, runtime·gostringnocopy((byte*)"semacquire")); - if(t0) - runtime·blockevent(w.releasetime - t0, 2); - } -} - -// Syncsemrelease waits for n pairing Syncsemacquire on the same semaphore s. -func runtime_Syncsemrelease(s *SyncSema, n uint32) { - SemaWaiter w, *wake; - - w.g = g; - w.nrelease = (int32)n; - w.next = nil; - w.releasetime = 0; - - runtime·lock(&s->lock); - while(w.nrelease > 0 && s->head && 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) - wake->releasetime = runtime·cputicks(); - runtime·ready(wake->g); - w.nrelease--; - } - if(w.nrelease > 0) { - // enqueue itself - if(s->tail == nil) - s->head = &w; - else - s->tail->next = &w; - s->tail = &w; - runtime·parkunlock(&s->lock, runtime·gostringnocopy((byte*)"semarelease")); - } else - runtime·unlock(&s->lock); -} diff --git a/src/pkg/runtime/thunk.s b/src/pkg/runtime/thunk.s new file mode 100644 index 0000000000..2a48f5ff23 --- /dev/null +++ b/src/pkg/runtime/thunk.s @@ -0,0 +1,21 @@ +// Copyright 2014 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. + +// This file exposes various internal runtime functions to other packages in std lib. + +#include "zasm_GOOS_GOARCH.h" +#include "../../cmd/ld/textflag.h" + +#ifdef GOARCH_arm +#define JMP B +#endif + +TEXT sync·runtime_Syncsemacquire(SB),NOSPLIT,$0-0 + JMP runtime·syncsemacquire(SB) + +TEXT sync·runtime_Syncsemrelease(SB),NOSPLIT,$0-0 + JMP runtime·syncsemrelease(SB) + +TEXT sync·runtime_Syncsemcheck(SB),NOSPLIT,$0-0 + JMP runtime·syncsemcheck(SB) |
