mirror of
https://github.com/golang/go
synced 2024-11-19 02:04:42 -07:00
runtime: convert synchronous semaphores to Go
LGTM=rsc R=golang-codereviews, khr, rsc CC=golang-codereviews, rlh https://golang.org/cl/130340043
This commit is contained in:
parent
9a1e142bbc
commit
a6950fe0f9
117
src/pkg/runtime/sema.go
Normal file
117
src/pkg/runtime/sema.go
Normal file
@ -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")
|
||||
}
|
||||
}
|
@ -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);
|
||||
}
|
||||
|
21
src/pkg/runtime/thunk.s
Normal file
21
src/pkg/runtime/thunk.s
Normal file
@ -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)
|
@ -19,8 +19,12 @@ func runtime_Semacquire(s *uint32)
|
||||
// library and should not be used directly.
|
||||
func runtime_Semrelease(s *uint32)
|
||||
|
||||
// Opaque representation of SyncSema in runtime/sema.goc.
|
||||
type syncSema [3]uintptr
|
||||
// Approximation of syncSema in runtime/sema.go.
|
||||
type syncSema struct {
|
||||
lock uintptr
|
||||
head unsafe.Pointer
|
||||
tail unsafe.Pointer
|
||||
}
|
||||
|
||||
// Syncsemacquire waits for a pairing Syncsemrelease on the same semaphore s.
|
||||
func runtime_Syncsemacquire(s *syncSema)
|
||||
|
Loading…
Reference in New Issue
Block a user