LEFT | RIGHT |
1 // Copyright 2009 The Go Authors. All rights reserved. | 1 // Copyright 2009 The Go Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style | 2 // Use of this source code is governed by a BSD-style |
3 // license that can be found in the LICENSE file. | 3 // license that can be found in the LICENSE file. |
4 | 4 |
5 #include "runtime.h" | 5 #include "runtime.h" |
| 6 #include "arch_GOARCH.h" |
6 #include "type.h" | 7 #include "type.h" |
| 8 #include "malloc.h" |
7 | 9 |
8 #define MAXALIGN 7 | 10 #define MAXALIGN 7 |
9 #define NOSELGEN 1 | 11 #define NOSELGEN 1 |
10 | 12 |
11 static int32 debug = 0; | 13 static int32 debug = 0; |
12 | 14 |
13 typedef struct WaitQ WaitQ; | 15 typedef struct WaitQ WaitQ; |
14 typedef struct SudoG SudoG; | 16 typedef struct SudoG SudoG; |
15 typedef struct Select Select; | 17 typedef struct Select Select; |
16 typedef struct Scase Scase; | 18 typedef struct Scase Scase; |
17 | 19 |
18 struct SudoG | 20 struct SudoG |
19 { | 21 { |
20 G* g; // g and selgen constitute | 22 G* g; // g and selgen constitute |
21 uint32 selgen; // a weak pointer to g | 23 uint32 selgen; // a weak pointer to g |
22 SudoG* link; | 24 SudoG* link; |
23 int64 releasetime; | 25 int64 releasetime; |
24 byte* elem; // data element | 26 byte* elem; // data element |
25 }; | 27 }; |
26 | 28 |
27 struct WaitQ | 29 struct WaitQ |
28 { | 30 { |
29 SudoG* first; | 31 SudoG* first; |
30 SudoG* last; | 32 SudoG* last; |
31 }; | 33 }; |
32 | 34 |
33 struct Hchan | 35 struct Hchan |
34 { | 36 { |
35 » uint32» qcount;»» » // total data in the q | 37 » uintgo» qcount;»» » // total data in the q |
36 » uint32» dataqsiz;» » // size of the circular q | 38 » uintgo» dataqsiz;» » // size of the circular q |
37 uint16 elemsize; | 39 uint16 elemsize; |
38 bool closed; | 40 bool closed; |
39 uint8 elemalign; | 41 uint8 elemalign; |
40 Alg* elemalg; // interface for element type | 42 Alg* elemalg; // interface for element type |
41 » uint32» sendx;» » » // send index | 43 » uintgo» sendx;» » » // send index |
42 » uint32» recvx;» » » // receive index | 44 » uintgo» recvx;» » » // receive index |
43 WaitQ recvq; // list of recv waiters | 45 WaitQ recvq; // list of recv waiters |
44 WaitQ sendq; // list of send waiters | 46 WaitQ sendq; // list of send waiters |
45 Lock; | 47 Lock; |
46 }; | 48 }; |
47 | 49 |
48 // Buffer follows Hchan immediately in memory. | 50 // Buffer follows Hchan immediately in memory. |
49 // chanbuf(c, i) is pointer to the i'th slot in the buffer. | 51 // chanbuf(c, i) is pointer to the i'th slot in the buffer. |
50 #define chanbuf(c, i) ((byte*)((c)+1)+(uintptr)(c)->elemsize*(i)) | 52 #define chanbuf(c, i) ((byte*)((c)+1)+(uintptr)(c)->elemsize*(i)) |
51 | 53 |
52 enum | 54 enum |
(...skipping 25 matching lines...) Expand all Loading... |
78 | 80 |
79 static void dequeueg(WaitQ*); | 81 static void dequeueg(WaitQ*); |
80 static SudoG* dequeue(WaitQ*); | 82 static SudoG* dequeue(WaitQ*); |
81 static void enqueue(WaitQ*, SudoG*); | 83 static void enqueue(WaitQ*, SudoG*); |
82 static void destroychan(Hchan*); | 84 static void destroychan(Hchan*); |
83 | 85 |
84 Hchan* | 86 Hchan* |
85 runtime·makechan_c(ChanType *t, int64 hint) | 87 runtime·makechan_c(ChanType *t, int64 hint) |
86 { | 88 { |
87 Hchan *c; | 89 Hchan *c; |
88 » int32 n; | 90 » uintptr n; |
89 Type *elem; | 91 Type *elem; |
90 | 92 |
91 elem = t->elem; | 93 elem = t->elem; |
92 | 94 |
93 » if(hint < 0 || (int32)hint != hint || (elem->size > 0 && hint > ((uintpt
r)-1) / elem->size)) | 95 » // compiler checks this but be safe. |
| 96 » if(elem->size >= (1<<16)) |
| 97 » » runtime·throw("makechan: invalid channel element type"); |
| 98 |
| 99 » if(hint < 0 || (intgo)hint != hint || (elem->size > 0 && hint > MaxMem /
elem->size)) |
94 runtime·panicstring("makechan: size out of range"); | 100 runtime·panicstring("makechan: size out of range"); |
95 | 101 |
96 // calculate rounded size of Hchan | 102 // calculate rounded size of Hchan |
97 n = sizeof(*c); | 103 n = sizeof(*c); |
98 while(n & MAXALIGN) | 104 while(n & MAXALIGN) |
99 n++; | 105 n++; |
100 | 106 |
101 // allocate memory in one call | 107 // allocate memory in one call |
102 c = (Hchan*)runtime·mal(n + hint*elem->size); | 108 c = (Hchan*)runtime·mal(n + hint*elem->size); |
103 c->elemsize = elem->size; | 109 c->elemsize = elem->size; |
104 c->elemalg = elem->alg; | 110 c->elemalg = elem->alg; |
105 c->elemalign = elem->align; | 111 c->elemalign = elem->align; |
106 c->dataqsiz = hint; | 112 c->dataqsiz = hint; |
107 | 113 |
108 if(debug) | 114 if(debug) |
109 » » runtime·printf("makechan: chan=%p; elemsize=%D; elemalg=%p; elem
align=%d; dataqsiz=%d\n", | 115 » » runtime·printf("makechan: chan=%p; elemsize=%D; elemalg=%p; elem
align=%d; dataqsiz=%D\n", |
110 » » » c, (int64)elem->size, elem->alg, elem->align, c->dataqsi
z); | 116 » » » c, (int64)elem->size, elem->alg, elem->align, (int64)c->
dataqsiz); |
111 | 117 |
112 return c; | 118 return c; |
113 } | 119 } |
114 | 120 |
115 // For reflect | 121 // For reflect |
116 //» func makechan(typ *ChanType, size uint32) (chan) | 122 //» func makechan(typ *ChanType, size uint64) (chan) |
117 void | 123 void |
118 reflect·makechan(ChanType *t, uint32 size, Hchan *c) | 124 reflect·makechan(ChanType *t, uint64 size, Hchan *c) |
119 { | 125 { |
120 c = runtime·makechan_c(t, size); | 126 c = runtime·makechan_c(t, size); |
121 FLUSH(&c); | 127 FLUSH(&c); |
122 } | 128 } |
123 | 129 |
124 // makechan(t *ChanType, hint int64) (hchan *chan any); | 130 // makechan(t *ChanType, hint int64) (hchan *chan any); |
125 void | 131 void |
126 runtime·makechan(ChanType *t, int64 hint, Hchan *ret) | 132 runtime·makechan(ChanType *t, int64 hint, Hchan *ret) |
127 { | 133 { |
128 ret = runtime·makechan_c(t, hint); | 134 ret = runtime·makechan_c(t, hint); |
(...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
165 runtime·gosched(); | 171 runtime·gosched(); |
166 | 172 |
167 if(debug) { | 173 if(debug) { |
168 runtime·printf("chansend: chan=%p; elem=", c); | 174 runtime·printf("chansend: chan=%p; elem=", c); |
169 c->elemalg->print(c->elemsize, ep); | 175 c->elemalg->print(c->elemsize, ep); |
170 runtime·prints("\n"); | 176 runtime·prints("\n"); |
171 } | 177 } |
172 | 178 |
173 t0 = 0; | 179 t0 = 0; |
174 mysg.releasetime = 0; | 180 mysg.releasetime = 0; |
175 » if(runtime·ContentionProfileRate > 0) { | 181 » if(runtime·blockprofilerate > 0) { |
176 t0 = runtime·cputicks(); | 182 t0 = runtime·cputicks(); |
177 mysg.releasetime = -1; | 183 mysg.releasetime = -1; |
178 } | 184 } |
179 | 185 |
180 runtime·lock(c); | 186 runtime·lock(c); |
181 if(c->closed) | 187 if(c->closed) |
182 goto closed; | 188 goto closed; |
183 | 189 |
184 if(c->dataqsiz > 0) | 190 if(c->dataqsiz > 0) |
185 goto asynch; | 191 goto asynch; |
(...skipping 29 matching lines...) Expand all Loading... |
215 runtime·park(runtime·unlock, c, "chan send"); | 221 runtime·park(runtime·unlock, c, "chan send"); |
216 | 222 |
217 if(g->param == nil) { | 223 if(g->param == nil) { |
218 runtime·lock(c); | 224 runtime·lock(c); |
219 if(!c->closed) | 225 if(!c->closed) |
220 runtime·throw("chansend: spurious wakeup"); | 226 runtime·throw("chansend: spurious wakeup"); |
221 goto closed; | 227 goto closed; |
222 } | 228 } |
223 | 229 |
224 if(mysg.releasetime > 0) | 230 if(mysg.releasetime > 0) |
225 » » runtime·contentionevent(mysg.releasetime - t0, 2); | 231 » » runtime·blockevent(mysg.releasetime - t0, 2); |
226 | 232 |
227 return; | 233 return; |
228 | 234 |
229 asynch: | 235 asynch: |
230 if(c->closed) | 236 if(c->closed) |
231 goto closed; | 237 goto closed; |
232 | 238 |
233 if(c->qcount >= c->dataqsiz) { | 239 if(c->qcount >= c->dataqsiz) { |
234 if(pres != nil) { | 240 if(pres != nil) { |
235 runtime·unlock(c); | 241 runtime·unlock(c); |
(...skipping 19 matching lines...) Expand all Loading... |
255 gp = sg->g; | 261 gp = sg->g; |
256 runtime·unlock(c); | 262 runtime·unlock(c); |
257 if(sg->releasetime) | 263 if(sg->releasetime) |
258 sg->releasetime = runtime·cputicks(); | 264 sg->releasetime = runtime·cputicks(); |
259 runtime·ready(gp); | 265 runtime·ready(gp); |
260 } else | 266 } else |
261 runtime·unlock(c); | 267 runtime·unlock(c); |
262 if(pres != nil) | 268 if(pres != nil) |
263 *pres = true; | 269 *pres = true; |
264 if(mysg.releasetime > 0) | 270 if(mysg.releasetime > 0) |
265 » » runtime·contentionevent(mysg.releasetime - t0, 2); | 271 » » runtime·blockevent(mysg.releasetime - t0, 2); |
266 return; | 272 return; |
267 | 273 |
268 closed: | 274 closed: |
269 runtime·unlock(c); | 275 runtime·unlock(c); |
270 runtime·panicstring("send on closed channel"); | 276 runtime·panicstring("send on closed channel"); |
271 } | 277 } |
272 | 278 |
273 | 279 |
274 void | 280 void |
275 runtime·chanrecv(ChanType *t, Hchan* c, byte *ep, bool *selected, bool *received
) | 281 runtime·chanrecv(ChanType *t, Hchan* c, byte *ep, bool *selected, bool *received
) |
(...skipping 14 matching lines...) Expand all Loading... |
290 if(selected != nil) { | 296 if(selected != nil) { |
291 *selected = false; | 297 *selected = false; |
292 return; | 298 return; |
293 } | 299 } |
294 runtime·park(nil, nil, "chan receive (nil chan)"); | 300 runtime·park(nil, nil, "chan receive (nil chan)"); |
295 return; // not reached | 301 return; // not reached |
296 } | 302 } |
297 | 303 |
298 t0 = 0; | 304 t0 = 0; |
299 mysg.releasetime = 0; | 305 mysg.releasetime = 0; |
300 » if(runtime·ContentionProfileRate > 0) { | 306 » if(runtime·blockprofilerate > 0) { |
301 t0 = runtime·cputicks(); | 307 t0 = runtime·cputicks(); |
302 mysg.releasetime = -1; | 308 mysg.releasetime = -1; |
303 } | 309 } |
304 | 310 |
305 runtime·lock(c); | 311 runtime·lock(c); |
306 if(c->dataqsiz > 0) | 312 if(c->dataqsiz > 0) |
307 goto asynch; | 313 goto asynch; |
308 | 314 |
309 if(c->closed) | 315 if(c->closed) |
310 goto closed; | 316 goto closed; |
(...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
344 if(g->param == nil) { | 350 if(g->param == nil) { |
345 runtime·lock(c); | 351 runtime·lock(c); |
346 if(!c->closed) | 352 if(!c->closed) |
347 runtime·throw("chanrecv: spurious wakeup"); | 353 runtime·throw("chanrecv: spurious wakeup"); |
348 goto closed; | 354 goto closed; |
349 } | 355 } |
350 | 356 |
351 if(received != nil) | 357 if(received != nil) |
352 *received = true; | 358 *received = true; |
353 if(mysg.releasetime > 0) | 359 if(mysg.releasetime > 0) |
354 » » runtime·contentionevent(mysg.releasetime - t0, 2); | 360 » » runtime·blockevent(mysg.releasetime - t0, 2); |
355 return; | 361 return; |
356 | 362 |
357 asynch: | 363 asynch: |
358 if(c->qcount <= 0) { | 364 if(c->qcount <= 0) { |
359 if(c->closed) | 365 if(c->closed) |
360 goto closed; | 366 goto closed; |
361 | 367 |
362 if(selected != nil) { | 368 if(selected != nil) { |
363 runtime·unlock(c); | 369 runtime·unlock(c); |
364 *selected = false; | 370 *selected = false; |
(...skipping 25 matching lines...) Expand all Loading... |
390 sg->releasetime = runtime·cputicks(); | 396 sg->releasetime = runtime·cputicks(); |
391 runtime·ready(gp); | 397 runtime·ready(gp); |
392 } else | 398 } else |
393 runtime·unlock(c); | 399 runtime·unlock(c); |
394 | 400 |
395 if(selected != nil) | 401 if(selected != nil) |
396 *selected = true; | 402 *selected = true; |
397 if(received != nil) | 403 if(received != nil) |
398 *received = true; | 404 *received = true; |
399 if(mysg.releasetime > 0) | 405 if(mysg.releasetime > 0) |
400 » » runtime·contentionevent(mysg.releasetime - t0, 2); | 406 » » runtime·blockevent(mysg.releasetime - t0, 2); |
401 return; | 407 return; |
402 | 408 |
403 closed: | 409 closed: |
404 if(ep != nil) | 410 if(ep != nil) |
405 c->elemalg->copy(c->elemsize, ep, nil); | 411 c->elemalg->copy(c->elemsize, ep, nil); |
406 if(selected != nil) | 412 if(selected != nil) |
407 *selected = true; | 413 *selected = true; |
408 if(received != nil) | 414 if(received != nil) |
409 *received = false; | 415 *received = false; |
410 runtime·unlock(c); | 416 runtime·unlock(c); |
411 if(mysg.releasetime > 0) | 417 if(mysg.releasetime > 0) |
412 » » runtime·contentionevent(mysg.releasetime - t0, 2); | 418 » » runtime·blockevent(mysg.releasetime - t0, 2); |
413 } | 419 } |
414 | 420 |
415 // chansend1(hchan *chan any, elem any); | 421 // chansend1(hchan *chan any, elem any); |
416 #pragma textflag 7 | 422 #pragma textflag 7 |
417 void | 423 void |
418 runtime·chansend1(ChanType *t, Hchan* c, ...) | 424 runtime·chansend1(ChanType *t, Hchan* c, ...) |
419 { | 425 { |
420 runtime·chansend(t, c, (byte*)(&c+1), nil); | 426 runtime·chansend(t, c, (byte*)(&c+1), nil); |
421 } | 427 } |
422 | 428 |
(...skipping 644 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1067 | 1073 |
1068 // This enum must match ../reflect/value.go:/SelectDir. | 1074 // This enum must match ../reflect/value.go:/SelectDir. |
1069 enum SelectDir { | 1075 enum SelectDir { |
1070 SelectSend = 1, | 1076 SelectSend = 1, |
1071 SelectRecv, | 1077 SelectRecv, |
1072 SelectDefault, | 1078 SelectDefault, |
1073 }; | 1079 }; |
1074 | 1080 |
1075 // func rselect(cases []runtimeSelect) (chosen int, word uintptr, recvOK bool) | 1081 // func rselect(cases []runtimeSelect) (chosen int, word uintptr, recvOK bool) |
1076 void | 1082 void |
1077 reflect·rselect(Slice cases, int32 chosen, uintptr word, bool recvOK) | 1083 reflect·rselect(Slice cases, intgo chosen, uintptr word, bool recvOK) |
1078 { | 1084 { |
1079 int32 i; | 1085 int32 i; |
1080 Select *sel; | 1086 Select *sel; |
1081 runtimeSelect* rcase, *rc; | 1087 runtimeSelect* rcase, *rc; |
1082 void *elem; | 1088 void *elem; |
1083 void *recvptr; | 1089 void *recvptr; |
1084 uintptr maxsize; | 1090 uintptr maxsize; |
1085 | 1091 |
1086 chosen = -1; | 1092 chosen = -1; |
1087 word = 0; | 1093 word = 0; |
(...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1120 break; | 1126 break; |
1121 if(rc->typ->elem->size > sizeof(void*)) | 1127 if(rc->typ->elem->size > sizeof(void*)) |
1122 elem = recvptr; | 1128 elem = recvptr; |
1123 else | 1129 else |
1124 elem = &word; | 1130 elem = &word; |
1125 selectrecv(sel, rc->ch, (void*)i, elem, &recvOK, 0); | 1131 selectrecv(sel, rc->ch, (void*)i, elem, &recvOK, 0); |
1126 break; | 1132 break; |
1127 } | 1133 } |
1128 } | 1134 } |
1129 | 1135 |
1130 » chosen = (int32)(uintptr)selectgo(&sel); | 1136 » chosen = (intgo)(uintptr)selectgo(&sel); |
1131 if(rcase[chosen].dir == SelectRecv && rcase[chosen].typ->elem->size > si
zeof(void*)) | 1137 if(rcase[chosen].dir == SelectRecv && rcase[chosen].typ->elem->size > si
zeof(void*)) |
1132 word = (uintptr)recvptr; | 1138 word = (uintptr)recvptr; |
1133 | 1139 |
1134 FLUSH(&chosen); | 1140 FLUSH(&chosen); |
1135 FLUSH(&word); | 1141 FLUSH(&word); |
1136 FLUSH(&recvOK); | 1142 FLUSH(&recvOK); |
1137 } | 1143 } |
1138 | 1144 |
1139 // closechan(sel *byte); | 1145 // closechan(sel *byte); |
1140 void | 1146 void |
(...skipping 41 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1182 | 1188 |
1183 // For reflect | 1189 // For reflect |
1184 // func chanclose(c chan) | 1190 // func chanclose(c chan) |
1185 void | 1191 void |
1186 reflect·chanclose(Hchan *c) | 1192 reflect·chanclose(Hchan *c) |
1187 { | 1193 { |
1188 runtime·closechan(c); | 1194 runtime·closechan(c); |
1189 } | 1195 } |
1190 | 1196 |
1191 // For reflect | 1197 // For reflect |
1192 //» func chanlen(c chan) (len int32) | 1198 //» func chanlen(c chan) (len int) |
1193 void | 1199 void |
1194 reflect·chanlen(Hchan *c, int32 len) | 1200 reflect·chanlen(Hchan *c, intgo len) |
1195 { | 1201 { |
1196 if(c == nil) | 1202 if(c == nil) |
1197 len = 0; | 1203 len = 0; |
1198 else | 1204 else |
1199 len = c->qcount; | 1205 len = c->qcount; |
1200 FLUSH(&len); | 1206 FLUSH(&len); |
1201 } | 1207 } |
1202 | 1208 |
1203 // For reflect | 1209 // For reflect |
1204 //» func chancap(c chan) (cap int32) | 1210 //» func chancap(c chan) int |
1205 void | 1211 void |
1206 reflect·chancap(Hchan *c, int32 cap) | 1212 reflect·chancap(Hchan *c, intgo cap) |
1207 { | 1213 { |
1208 if(c == nil) | 1214 if(c == nil) |
1209 cap = 0; | 1215 cap = 0; |
1210 else | 1216 else |
1211 cap = c->dataqsiz; | 1217 cap = c->dataqsiz; |
1212 FLUSH(&cap); | 1218 FLUSH(&cap); |
1213 } | 1219 } |
1214 | 1220 |
1215 static SudoG* | 1221 static SudoG* |
1216 dequeue(WaitQ *q) | 1222 dequeue(WaitQ *q) |
(...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1255 { | 1261 { |
1256 sgp->link = nil; | 1262 sgp->link = nil; |
1257 if(q->first == nil) { | 1263 if(q->first == nil) { |
1258 q->first = sgp; | 1264 q->first = sgp; |
1259 q->last = sgp; | 1265 q->last = sgp; |
1260 return; | 1266 return; |
1261 } | 1267 } |
1262 q->last->link = sgp; | 1268 q->last->link = sgp; |
1263 q->last = sgp; | 1269 q->last = sgp; |
1264 } | 1270 } |
LEFT | RIGHT |