summaryrefslogtreecommitdiff
path: root/src/pkg/runtime/sema.goc
diff options
context:
space:
mode:
Diffstat (limited to 'src/pkg/runtime/sema.goc')
-rw-r--r--src/pkg/runtime/sema.goc137
1 files changed, 117 insertions, 20 deletions
diff --git a/src/pkg/runtime/sema.goc b/src/pkg/runtime/sema.goc
index 4df01fc4e..57f32a0dd 100644
--- a/src/pkg/runtime/sema.goc
+++ b/src/pkg/runtime/sema.goc
@@ -20,23 +20,25 @@
package sync
#include "runtime.h"
#include "arch_GOARCH.h"
+#include "../../cmd/ld/textflag.h"
-typedef struct Sema Sema;
-struct Sema
+typedef struct SemaWaiter SemaWaiter;
+struct SemaWaiter
{
uint32 volatile* addr;
G* g;
int64 releasetime;
- Sema* prev;
- Sema* next;
+ int32 nrelease; // -1 for acquire
+ SemaWaiter* prev;
+ SemaWaiter* next;
};
typedef struct SemaRoot SemaRoot;
struct SemaRoot
{
Lock;
- Sema* head;
- Sema* tail;
+ SemaWaiter* head;
+ SemaWaiter* tail;
// Number of waiters. Read w/o the lock.
uint32 volatile nwait;
};
@@ -49,7 +51,7 @@ struct semtable
SemaRoot;
uint8 pad[CacheLineSize-sizeof(SemaRoot)];
};
-#pragma dataflag 16 /* mark semtable as 'no pointers', hiding from garbage collector */
+#pragma dataflag NOPTR /* mark semtable as 'no pointers', hiding from garbage collector */
static struct semtable semtable[SEMTABLESZ];
static SemaRoot*
@@ -59,7 +61,7 @@ semroot(uint32 *addr)
}
static void
-semqueue(SemaRoot *root, uint32 volatile *addr, Sema *s)
+semqueue(SemaRoot *root, uint32 volatile *addr, SemaWaiter *s)
{
s->g = g;
s->addr = addr;
@@ -73,7 +75,7 @@ semqueue(SemaRoot *root, uint32 volatile *addr, Sema *s)
}
static void
-semdequeue(SemaRoot *root, Sema *s)
+semdequeue(SemaRoot *root, SemaWaiter *s)
{
if(s->next)
s->next->prev = s->prev;
@@ -98,10 +100,10 @@ cansemacquire(uint32 *addr)
return 0;
}
-static void
-semacquireimpl(uint32 volatile *addr, int32 profile)
+void
+runtime·semacquire(uint32 volatile *addr, bool profile)
{
- Sema s; // Needs to be allocated on stack, otherwise garbage collector could deallocate it
+ SemaWaiter s; // Needs to be allocated on stack, otherwise garbage collector could deallocate it
SemaRoot *root;
int64 t0;
@@ -145,15 +147,9 @@ semacquireimpl(uint32 volatile *addr, int32 profile)
}
void
-runtime·semacquire(uint32 volatile *addr)
-{
- semacquireimpl(addr, 0);
-}
-
-void
runtime·semrelease(uint32 volatile *addr)
{
- Sema *s;
+ SemaWaiter *s;
SemaRoot *root;
root = semroot(addr);
@@ -188,10 +184,111 @@ runtime·semrelease(uint32 volatile *addr)
}
}
+// 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) {
- semacquireimpl(addr, 1);
+ 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·park(runtime·unlock, 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·park(runtime·unlock, s, "semarelease");
+ } else
+ runtime·unlock(s);
+}