runtime: runtime.Caller should succeed even without debug info.
[gcc.git] / libgo / runtime / sema.goc
1 // Copyright 2009 The Go Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style
3 // license that can be found in the LICENSE file.
4
5 // Semaphore implementation exposed to Go.
6 // Intended use is provide a sleep and wakeup
7 // primitive that can be used in the contended case
8 // of other synchronization primitives.
9 // Thus it targets the same goal as Linux's futex,
10 // but it has much simpler semantics.
11 //
12 // That is, don't think of these as semaphores.
13 // Think of them as a way to implement sleep and wakeup
14 // such that every sleep is paired with a single wakeup,
15 // even if, due to races, the wakeup happens before the sleep.
16 //
17 // See Mullender and Cox, ``Semaphores in Plan 9,''
18 // http://swtch.com/semaphore.pdf
19
20 package sync
21 #include "runtime.h"
22 #include "arch.h"
23
24 typedef struct Sema Sema;
25 struct Sema
26 {
27 uint32 volatile *addr;
28 G *g;
29 Sema *prev;
30 Sema *next;
31 };
32
33 typedef struct SemaRoot SemaRoot;
34 struct SemaRoot
35 {
36 Lock;
37 Sema *head;
38 Sema *tail;
39 // Number of waiters. Read w/o the lock.
40 uint32 volatile nwait;
41 };
42
43 // Prime to not correlate with any user patterns.
44 #define SEMTABLESZ 251
45
46 static union
47 {
48 SemaRoot;
49 uint8 pad[CacheLineSize];
50 } semtable[SEMTABLESZ];
51
52 static SemaRoot*
53 semroot(uint32 volatile *addr)
54 {
55 return &semtable[((uintptr)addr >> 3) % SEMTABLESZ];
56 }
57
58 static void
59 semqueue(SemaRoot *root, uint32 volatile *addr, Sema *s)
60 {
61 s->g = runtime_g();
62 s->addr = addr;
63 s->next = nil;
64 s->prev = root->tail;
65 if(root->tail)
66 root->tail->next = s;
67 else
68 root->head = s;
69 root->tail = s;
70 }
71
72 static void
73 semdequeue(SemaRoot *root, Sema *s)
74 {
75 if(s->next)
76 s->next->prev = s->prev;
77 else
78 root->tail = s->prev;
79 if(s->prev)
80 s->prev->next = s->next;
81 else
82 root->head = s->next;
83 s->prev = nil;
84 s->next = nil;
85 }
86
87 static int32
88 cansemacquire(uint32 volatile *addr)
89 {
90 uint32 v;
91
92 while((v = runtime_atomicload(addr)) > 0)
93 if(runtime_cas(addr, v, v-1))
94 return 1;
95 return 0;
96 }
97
98 void
99 runtime_semacquire(uint32 volatile *addr)
100 {
101 G *g;
102 Sema s;
103 SemaRoot *root;
104
105 // Easy case.
106 if(cansemacquire(addr))
107 return;
108
109 // Harder case:
110 // increment waiter count
111 // try cansemacquire one more time, return if succeeded
112 // enqueue itself as a waiter
113 // sleep
114 // (waiter descriptor is dequeued by signaler)
115 g = runtime_g();
116 root = semroot(addr);
117 for(;;) {
118
119 runtime_lock(root);
120 // Add ourselves to nwait to disable "easy case" in semrelease.
121 runtime_xadd(&root->nwait, 1);
122 // Check cansemacquire to avoid missed wakeup.
123 if(cansemacquire(addr)) {
124 runtime_xadd(&root->nwait, -1);
125 runtime_unlock(root);
126 return;
127 }
128 // Any semrelease after the cansemacquire knows we're waiting
129 // (we set nwait above), so go to sleep.
130 semqueue(root, addr, &s);
131 g->status = Gwaiting;
132 g->waitreason = "semacquire";
133 runtime_unlock(root);
134 runtime_gosched();
135 if(cansemacquire(addr))
136 return;
137 }
138 }
139
140 void
141 runtime_semrelease(uint32 volatile *addr)
142 {
143 Sema *s;
144 SemaRoot *root;
145
146 root = semroot(addr);
147 runtime_xadd(addr, 1);
148
149 // Easy case: no waiters?
150 // This check must happen after the xadd, to avoid a missed wakeup
151 // (see loop in semacquire).
152 if(runtime_atomicload(&root->nwait) == 0)
153 return;
154
155 // Harder case: search for a waiter and wake it.
156 runtime_lock(root);
157 if(runtime_atomicload(&root->nwait) == 0) {
158 // The count is already consumed by another goroutine,
159 // so no need to wake up another goroutine.
160 runtime_unlock(root);
161 return;
162 }
163 for(s = root->head; s; s = s->next) {
164 if(s->addr == addr) {
165 runtime_xadd(&root->nwait, -1);
166 semdequeue(root, s);
167 break;
168 }
169 }
170 runtime_unlock(root);
171 if(s)
172 runtime_ready(s->g);
173 }
174
175 func runtime_Semacquire(addr *uint32) {
176 runtime_semacquire(addr);
177 }
178
179 func runtime_Semrelease(addr *uint32) {
180 runtime_semrelease(addr);
181 }