]> Cypherpunks repositories - gostls13.git/commitdiff
runtime: convert synchronous semaphores to Go
authorDmitriy Vyukov <dvyukov@google.com>
Sun, 24 Aug 2014 08:41:23 +0000 (12:41 +0400)
committerDmitriy Vyukov <dvyukov@google.com>
Sun, 24 Aug 2014 08:41:23 +0000 (12:41 +0400)
LGTM=rsc
R=golang-codereviews, khr, rsc
CC=golang-codereviews, rlh
https://golang.org/cl/130340043

src/pkg/runtime/sema.go [new file with mode: 0644]
src/pkg/runtime/sema.goc
src/pkg/runtime/thunk.s [new file with mode: 0644]
src/pkg/sync/runtime.go

diff --git a/src/pkg/runtime/sema.go b/src/pkg/runtime/sema.go
new file mode 100644 (file)
index 0000000..ac855f9
--- /dev/null
@@ -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")
+       }
+}
index 7b1f8f2ed3e79a434402d1223f25f029793dfcbf..7724566a1ee2eeb8e32c8fd9683f97a3c7ca939a 100644 (file)
@@ -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 (file)
index 0000000..2a48f5f
--- /dev/null
@@ -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)
index 3bf47ea52aad3e3e98a25b2ab200d876618b35df..3b866303a96109fabf6140444094a0a9db0466ce 100644 (file)
@@ -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)