--- /dev/null
+// 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")
+ }
+}
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);
-}
--- /dev/null
+// 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)
// 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)