diff options
Diffstat (limited to 'src/pkg/runtime/sema.goc')
-rw-r--r-- | src/pkg/runtime/sema.goc | 294 |
1 files changed, 0 insertions, 294 deletions
diff --git a/src/pkg/runtime/sema.goc b/src/pkg/runtime/sema.goc deleted file mode 100644 index c1e8e4e18..000000000 --- a/src/pkg/runtime/sema.goc +++ /dev/null @@ -1,294 +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 sync -#include "runtime.h" -#include "arch_GOARCH.h" -#include "../../cmd/ld/textflag.h" - -typedef struct SemaWaiter SemaWaiter; -struct SemaWaiter -{ - uint32 volatile* addr; - G* g; - int64 releasetime; - int32 nrelease; // -1 for acquire - SemaWaiter* prev; - SemaWaiter* next; -}; - -typedef struct SemaRoot SemaRoot; -struct SemaRoot -{ - Lock; - SemaWaiter* head; - SemaWaiter* tail; - // Number of waiters. Read w/o the lock. - uint32 volatile nwait; -}; - -// Prime to not correlate with any user patterns. -#define SEMTABLESZ 251 - -struct semtable -{ - SemaRoot; - uint8 pad[CacheLineSize-sizeof(SemaRoot)]; -}; -#pragma dataflag NOPTR /* mark semtable as 'no pointers', hiding from garbage collector */ -static struct semtable semtable[SEMTABLESZ]; - -static SemaRoot* -semroot(uint32 *addr) -{ - return &semtable[((uintptr)addr >> 3) % SEMTABLESZ]; -} - -static void -semqueue(SemaRoot *root, uint32 volatile *addr, SemaWaiter *s) -{ - s->g = g; - s->addr = addr; - s->next = nil; - s->prev = root->tail; - if(root->tail) - root->tail->next = s; - else - root->head = s; - root->tail = s; -} - -static void -semdequeue(SemaRoot *root, SemaWaiter *s) -{ - if(s->next) - s->next->prev = s->prev; - else - root->tail = s->prev; - if(s->prev) - s->prev->next = s->next; - else - root->head = s->next; - s->prev = nil; - s->next = nil; -} - -static int32 -cansemacquire(uint32 *addr) -{ - uint32 v; - - while((v = runtime·atomicload(addr)) > 0) - if(runtime·cas(addr, v, v-1)) - return 1; - return 0; -} - -void -runtime·semacquire(uint32 volatile *addr, bool profile) -{ - SemaWaiter s; // Needs to be allocated on stack, otherwise garbage collector could deallocate it - SemaRoot *root; - int64 t0; - - // 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) - root = semroot(addr); - t0 = 0; - s.releasetime = 0; - if(profile && runtime·blockprofilerate > 0) { - t0 = runtime·cputicks(); - s.releasetime = -1; - } - for(;;) { - runtime·lock(root); - // Add ourselves to nwait to disable "easy case" in semrelease. - runtime·xadd(&root->nwait, 1); - // Check cansemacquire to avoid missed wakeup. - if(cansemacquire(addr)) { - runtime·xadd(&root->nwait, -1); - runtime·unlock(root); - return; - } - // Any semrelease after the cansemacquire knows we're waiting - // (we set nwait above), so go to sleep. - semqueue(root, addr, &s); - runtime·parkunlock(root, "semacquire"); - if(cansemacquire(addr)) { - if(t0) - runtime·blockevent(s.releasetime - t0, 3); - return; - } - } -} - -void -runtime·semrelease(uint32 volatile *addr) -{ - SemaWaiter *s; - SemaRoot *root; - - root = semroot(addr); - runtime·xadd(addr, 1); - - // Easy case: no waiters? - // This check must happen after the xadd, to avoid a missed wakeup - // (see loop in semacquire). - if(runtime·atomicload(&root->nwait) == 0) - return; - - // Harder case: search for a waiter and wake it. - runtime·lock(root); - if(runtime·atomicload(&root->nwait) == 0) { - // The count is already consumed by another goroutine, - // so no need to wake up another goroutine. - runtime·unlock(root); - return; - } - for(s = root->head; s; s = s->next) { - if(s->addr == addr) { - runtime·xadd(&root->nwait, -1); - semdequeue(root, s); - break; - } - } - runtime·unlock(root); - if(s) { - if(s->releasetime) - s->releasetime = runtime·cputicks(); - runtime·ready(s->g); - } -} - -// TODO(dvyukov): move to netpoll.goc once it's used by all OSes. -void net·runtime_Semacquire(uint32 *addr) -{ - runtime·semacquire(addr, true); -} - -void net·runtime_Semrelease(uint32 *addr) -{ - runtime·semrelease(addr); -} - -func runtime_Semacquire(addr *uint32) { - runtime·semacquire(addr, true); -} - -func runtime_Semrelease(addr *uint32) { - runtime·semrelease(addr); -} - -typedef struct SyncSema SyncSema; -struct SyncSema -{ - 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); - 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); - 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, "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); - 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, "semarelease"); - } else - runtime·unlock(s); -} |