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 21 matching lines...) Expand all Loading... |
150 SudoG mysg; | 156 SudoG mysg; |
151 G* gp; | 157 G* gp; |
152 int64 t0; | 158 int64 t0; |
153 | 159 |
154 if(c == nil) { | 160 if(c == nil) { |
155 USED(t); | 161 USED(t); |
156 if(pres != nil) { | 162 if(pres != nil) { |
157 *pres = false; | 163 *pres = false; |
158 return; | 164 return; |
159 } | 165 } |
160 » » g->status = Gwaiting; | 166 » » runtime·park(nil, nil, "chan send (nil chan)"); |
161 » » g->waitreason = "chan send (nil chan)"; | |
162 » » runtime·gosched(); | |
163 return; // not reached | 167 return; // not reached |
164 } | 168 } |
165 | 169 |
166 if(runtime·gcwaiting) | 170 if(runtime·gcwaiting) |
167 runtime·gosched(); | 171 runtime·gosched(); |
168 | 172 |
169 if(debug) { | 173 if(debug) { |
170 runtime·printf("chansend: chan=%p; elem=", c); | 174 runtime·printf("chansend: chan=%p; elem=", c); |
171 c->elemalg->print(c->elemsize, ep); | 175 c->elemalg->print(c->elemsize, ep); |
172 runtime·prints("\n"); | 176 runtime·prints("\n"); |
173 } | 177 } |
174 | 178 |
175 t0 = 0; | 179 t0 = 0; |
176 mysg.releasetime = 0; | 180 mysg.releasetime = 0; |
177 » if(runtime·ContentionProfileRate > 0) { | 181 » if(runtime·blockprofilerate > 0) { |
178 t0 = runtime·cputicks(); | 182 t0 = runtime·cputicks(); |
179 mysg.releasetime = -1; | 183 mysg.releasetime = -1; |
180 } | 184 } |
181 | 185 |
182 runtime·lock(c); | 186 runtime·lock(c); |
183 if(c->closed) | 187 if(c->closed) |
184 goto closed; | 188 goto closed; |
185 | 189 |
186 if(c->dataqsiz > 0) | 190 if(c->dataqsiz > 0) |
187 goto asynch; | 191 goto asynch; |
(...skipping 18 matching lines...) Expand all Loading... |
206 if(pres != nil) { | 210 if(pres != nil) { |
207 runtime·unlock(c); | 211 runtime·unlock(c); |
208 *pres = false; | 212 *pres = false; |
209 return; | 213 return; |
210 } | 214 } |
211 | 215 |
212 mysg.elem = ep; | 216 mysg.elem = ep; |
213 mysg.g = g; | 217 mysg.g = g; |
214 mysg.selgen = NOSELGEN; | 218 mysg.selgen = NOSELGEN; |
215 g->param = nil; | 219 g->param = nil; |
216 g->status = Gwaiting; | |
217 g->waitreason = "chan send"; | |
218 enqueue(&c->sendq, &mysg); | 220 enqueue(&c->sendq, &mysg); |
219 » runtime·unlock(c); | 221 » runtime·park(runtime·unlock, c, "chan send"); |
220 » runtime·gosched(); | |
221 | 222 |
222 if(g->param == nil) { | 223 if(g->param == nil) { |
223 runtime·lock(c); | 224 runtime·lock(c); |
224 if(!c->closed) | 225 if(!c->closed) |
225 runtime·throw("chansend: spurious wakeup"); | 226 runtime·throw("chansend: spurious wakeup"); |
226 goto closed; | 227 goto closed; |
227 } | 228 } |
228 | 229 |
229 if(mysg.releasetime > 0) | 230 if(mysg.releasetime > 0) |
230 » » runtime·contentionevent(mysg.releasetime - t0, 2); | 231 » » runtime·blockevent(mysg.releasetime - t0, 2); |
231 | 232 |
232 return; | 233 return; |
233 | 234 |
234 asynch: | 235 asynch: |
235 if(c->closed) | 236 if(c->closed) |
236 goto closed; | 237 goto closed; |
237 | 238 |
238 if(c->qcount >= c->dataqsiz) { | 239 if(c->qcount >= c->dataqsiz) { |
239 if(pres != nil) { | 240 if(pres != nil) { |
240 runtime·unlock(c); | 241 runtime·unlock(c); |
241 *pres = false; | 242 *pres = false; |
242 return; | 243 return; |
243 } | 244 } |
244 mysg.g = g; | 245 mysg.g = g; |
245 mysg.elem = nil; | 246 mysg.elem = nil; |
246 mysg.selgen = NOSELGEN; | 247 mysg.selgen = NOSELGEN; |
247 g->status = Gwaiting; | |
248 g->waitreason = "chan send"; | |
249 enqueue(&c->sendq, &mysg); | 248 enqueue(&c->sendq, &mysg); |
250 » » runtime·unlock(c); | 249 » » runtime·park(runtime·unlock, c, "chan send"); |
251 » » runtime·gosched(); | |
252 | 250 |
253 runtime·lock(c); | 251 runtime·lock(c); |
254 goto asynch; | 252 goto asynch; |
255 } | 253 } |
256 c->elemalg->copy(c->elemsize, chanbuf(c, c->sendx), ep); | 254 c->elemalg->copy(c->elemsize, chanbuf(c, c->sendx), ep); |
257 if(++c->sendx == c->dataqsiz) | 255 if(++c->sendx == c->dataqsiz) |
258 c->sendx = 0; | 256 c->sendx = 0; |
259 c->qcount++; | 257 c->qcount++; |
260 | 258 |
261 sg = dequeue(&c->recvq); | 259 sg = dequeue(&c->recvq); |
262 if(sg != nil) { | 260 if(sg != nil) { |
263 gp = sg->g; | 261 gp = sg->g; |
264 runtime·unlock(c); | 262 runtime·unlock(c); |
265 if(sg->releasetime) | 263 if(sg->releasetime) |
266 sg->releasetime = runtime·cputicks(); | 264 sg->releasetime = runtime·cputicks(); |
267 runtime·ready(gp); | 265 runtime·ready(gp); |
268 } else | 266 } else |
269 runtime·unlock(c); | 267 runtime·unlock(c); |
270 if(pres != nil) | 268 if(pres != nil) |
271 *pres = true; | 269 *pres = true; |
272 if(mysg.releasetime > 0) | 270 if(mysg.releasetime > 0) |
273 » » runtime·contentionevent(mysg.releasetime - t0, 2); | 271 » » runtime·blockevent(mysg.releasetime - t0, 2); |
274 return; | 272 return; |
275 | 273 |
276 closed: | 274 closed: |
277 runtime·unlock(c); | 275 runtime·unlock(c); |
278 runtime·panicstring("send on closed channel"); | 276 runtime·panicstring("send on closed channel"); |
279 } | 277 } |
280 | 278 |
281 | 279 |
282 void | 280 void |
283 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
) |
284 { | 282 { |
285 SudoG *sg; | 283 SudoG *sg; |
286 SudoG mysg; | 284 SudoG mysg; |
287 G *gp; | 285 G *gp; |
288 int64 t0; | 286 int64 t0; |
289 | 287 |
290 if(runtime·gcwaiting) | 288 if(runtime·gcwaiting) |
291 runtime·gosched(); | 289 runtime·gosched(); |
292 | 290 |
293 if(debug) | 291 if(debug) |
294 runtime·printf("chanrecv: chan=%p\n", c); | 292 runtime·printf("chanrecv: chan=%p\n", c); |
295 | 293 |
296 if(c == nil) { | 294 if(c == nil) { |
297 USED(t); | 295 USED(t); |
298 if(selected != nil) { | 296 if(selected != nil) { |
299 *selected = false; | 297 *selected = false; |
300 return; | 298 return; |
301 } | 299 } |
302 » » g->status = Gwaiting; | 300 » » runtime·park(nil, nil, "chan receive (nil chan)"); |
303 » » g->waitreason = "chan receive (nil chan)"; | |
304 » » runtime·gosched(); | |
305 return; // not reached | 301 return; // not reached |
306 } | 302 } |
307 | 303 |
308 t0 = 0; | 304 t0 = 0; |
309 mysg.releasetime = 0; | 305 mysg.releasetime = 0; |
310 » if(runtime·ContentionProfileRate > 0) { | 306 » if(runtime·blockprofilerate > 0) { |
311 t0 = runtime·cputicks(); | 307 t0 = runtime·cputicks(); |
312 mysg.releasetime = -1; | 308 mysg.releasetime = -1; |
313 } | 309 } |
314 | 310 |
315 runtime·lock(c); | 311 runtime·lock(c); |
316 if(c->dataqsiz > 0) | 312 if(c->dataqsiz > 0) |
317 goto asynch; | 313 goto asynch; |
318 | 314 |
319 if(c->closed) | 315 if(c->closed) |
320 goto closed; | 316 goto closed; |
(...skipping 20 matching lines...) Expand all Loading... |
341 if(selected != nil) { | 337 if(selected != nil) { |
342 runtime·unlock(c); | 338 runtime·unlock(c); |
343 *selected = false; | 339 *selected = false; |
344 return; | 340 return; |
345 } | 341 } |
346 | 342 |
347 mysg.elem = ep; | 343 mysg.elem = ep; |
348 mysg.g = g; | 344 mysg.g = g; |
349 mysg.selgen = NOSELGEN; | 345 mysg.selgen = NOSELGEN; |
350 g->param = nil; | 346 g->param = nil; |
351 g->status = Gwaiting; | |
352 g->waitreason = "chan receive"; | |
353 enqueue(&c->recvq, &mysg); | 347 enqueue(&c->recvq, &mysg); |
354 » runtime·unlock(c); | 348 » runtime·park(runtime·unlock, c, "chan receive"); |
355 » runtime·gosched(); | |
356 | 349 |
357 if(g->param == nil) { | 350 if(g->param == nil) { |
358 runtime·lock(c); | 351 runtime·lock(c); |
359 if(!c->closed) | 352 if(!c->closed) |
360 runtime·throw("chanrecv: spurious wakeup"); | 353 runtime·throw("chanrecv: spurious wakeup"); |
361 goto closed; | 354 goto closed; |
362 } | 355 } |
363 | 356 |
364 if(received != nil) | 357 if(received != nil) |
365 *received = true; | 358 *received = true; |
366 if(mysg.releasetime > 0) | 359 if(mysg.releasetime > 0) |
367 » » runtime·contentionevent(mysg.releasetime - t0, 2); | 360 » » runtime·blockevent(mysg.releasetime - t0, 2); |
368 return; | 361 return; |
369 | 362 |
370 asynch: | 363 asynch: |
371 if(c->qcount <= 0) { | 364 if(c->qcount <= 0) { |
372 if(c->closed) | 365 if(c->closed) |
373 goto closed; | 366 goto closed; |
374 | 367 |
375 if(selected != nil) { | 368 if(selected != nil) { |
376 runtime·unlock(c); | 369 runtime·unlock(c); |
377 *selected = false; | 370 *selected = false; |
378 if(received != nil) | 371 if(received != nil) |
379 *received = false; | 372 *received = false; |
380 return; | 373 return; |
381 } | 374 } |
382 mysg.g = g; | 375 mysg.g = g; |
383 mysg.elem = nil; | 376 mysg.elem = nil; |
384 mysg.selgen = NOSELGEN; | 377 mysg.selgen = NOSELGEN; |
385 g->status = Gwaiting; | |
386 g->waitreason = "chan receive"; | |
387 enqueue(&c->recvq, &mysg); | 378 enqueue(&c->recvq, &mysg); |
388 » » runtime·unlock(c); | 379 » » runtime·park(runtime·unlock, c, "chan receive"); |
389 » » runtime·gosched(); | |
390 | 380 |
391 runtime·lock(c); | 381 runtime·lock(c); |
392 goto asynch; | 382 goto asynch; |
393 } | 383 } |
394 if(ep != nil) | 384 if(ep != nil) |
395 c->elemalg->copy(c->elemsize, ep, chanbuf(c, c->recvx)); | 385 c->elemalg->copy(c->elemsize, ep, chanbuf(c, c->recvx)); |
396 c->elemalg->copy(c->elemsize, chanbuf(c, c->recvx), nil); | 386 c->elemalg->copy(c->elemsize, chanbuf(c, c->recvx), nil); |
397 if(++c->recvx == c->dataqsiz) | 387 if(++c->recvx == c->dataqsiz) |
398 c->recvx = 0; | 388 c->recvx = 0; |
399 c->qcount--; | 389 c->qcount--; |
400 | 390 |
401 sg = dequeue(&c->sendq); | 391 sg = dequeue(&c->sendq); |
402 if(sg != nil) { | 392 if(sg != nil) { |
403 gp = sg->g; | 393 gp = sg->g; |
404 runtime·unlock(c); | 394 runtime·unlock(c); |
405 if(sg->releasetime) | 395 if(sg->releasetime) |
406 sg->releasetime = runtime·cputicks(); | 396 sg->releasetime = runtime·cputicks(); |
407 runtime·ready(gp); | 397 runtime·ready(gp); |
408 } else | 398 } else |
409 runtime·unlock(c); | 399 runtime·unlock(c); |
410 | 400 |
411 if(selected != nil) | 401 if(selected != nil) |
412 *selected = true; | 402 *selected = true; |
413 if(received != nil) | 403 if(received != nil) |
414 *received = true; | 404 *received = true; |
415 if(mysg.releasetime > 0) | 405 if(mysg.releasetime > 0) |
416 » » runtime·contentionevent(mysg.releasetime - t0, 2); | 406 » » runtime·blockevent(mysg.releasetime - t0, 2); |
417 return; | 407 return; |
418 | 408 |
419 closed: | 409 closed: |
420 if(ep != nil) | 410 if(ep != nil) |
421 c->elemalg->copy(c->elemsize, ep, nil); | 411 c->elemalg->copy(c->elemsize, ep, nil); |
422 if(selected != nil) | 412 if(selected != nil) |
423 *selected = true; | 413 *selected = true; |
424 if(received != nil) | 414 if(received != nil) |
425 *received = false; | 415 *received = false; |
426 runtime·unlock(c); | 416 runtime·unlock(c); |
427 if(mysg.releasetime > 0) | 417 if(mysg.releasetime > 0) |
428 » » runtime·contentionevent(mysg.releasetime - t0, 2); | 418 » » runtime·blockevent(mysg.releasetime - t0, 2); |
429 } | 419 } |
430 | 420 |
431 // chansend1(hchan *chan any, elem any); | 421 // chansend1(hchan *chan any, elem any); |
432 #pragma textflag 7 | 422 #pragma textflag 7 |
433 void | 423 void |
434 runtime·chansend1(ChanType *t, Hchan* c, ...) | 424 runtime·chansend1(ChanType *t, Hchan* c, ...) |
435 { | 425 { |
436 runtime·chansend(t, c, (byte*)(&c+1), nil); | 426 runtime·chansend(t, c, (byte*)(&c+1), nil); |
437 } | 427 } |
438 | 428 |
(...skipping 364 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
803 if(c0 && c0 != c) { | 793 if(c0 && c0 != c) { |
804 c = c0; | 794 c = c0; |
805 runtime·unlock(c); | 795 runtime·unlock(c); |
806 } | 796 } |
807 } | 797 } |
808 } | 798 } |
809 | 799 |
810 void | 800 void |
811 runtime·block(void) | 801 runtime·block(void) |
812 { | 802 { |
813 » g->status = Gwaiting;» // forever | 803 » runtime·park(nil, nil, "select (no cases)");» // forever |
814 » g->waitreason = "select (no cases)"; | |
815 » runtime·gosched(); | |
816 } | 804 } |
817 | 805 |
818 static void* selectgo(Select**); | 806 static void* selectgo(Select**); |
819 | 807 |
820 // selectgo(sel *byte); | 808 // selectgo(sel *byte); |
821 // | 809 // |
822 // overwrites return pc on stack to signal which case of the select | 810 // overwrites return pc on stack to signal which case of the select |
823 // to run, so cannot appear at the top of a split stack. | 811 // to run, so cannot appear at the top of a split stack. |
824 #pragma textflag 7 | 812 #pragma textflag 7 |
825 void | 813 void |
(...skipping 110 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
936 enqueue(&c->recvq, sg); | 924 enqueue(&c->recvq, sg); |
937 break; | 925 break; |
938 | 926 |
939 case CaseSend: | 927 case CaseSend: |
940 enqueue(&c->sendq, sg); | 928 enqueue(&c->sendq, sg); |
941 break; | 929 break; |
942 } | 930 } |
943 } | 931 } |
944 | 932 |
945 g->param = nil; | 933 g->param = nil; |
946 » g->status = Gwaiting; | 934 » runtime·park((void(*)(Lock*))selunlock, (Lock*)sel, "select"); |
947 » g->waitreason = "select"; | |
948 » selunlock(sel); | |
949 » runtime·gosched(); | |
950 | 935 |
951 sellock(sel); | 936 sellock(sel); |
952 sg = g->param; | 937 sg = g->param; |
953 | 938 |
954 // pass 3 - dequeue from unsuccessful chans | 939 // pass 3 - dequeue from unsuccessful chans |
955 // otherwise they stack up on quiet channels | 940 // otherwise they stack up on quiet channels |
956 for(i=0; i<sel->ncase; i++) { | 941 for(i=0; i<sel->ncase; i++) { |
957 cas = &sel->scase[i]; | 942 cas = &sel->scase[i]; |
958 if(cas != (Scase*)sg) { | 943 if(cas != (Scase*)sg) { |
959 c = cas->chan; | 944 c = cas->chan; |
(...skipping 89 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1049 selunlock(sel); | 1034 selunlock(sel); |
1050 if(debug) | 1035 if(debug) |
1051 runtime·printf("syncsend: sel=%p c=%p o=%d\n", sel, c, o); | 1036 runtime·printf("syncsend: sel=%p c=%p o=%d\n", sel, c, o); |
1052 if(sg->elem != nil) | 1037 if(sg->elem != nil) |
1053 c->elemalg->copy(c->elemsize, sg->elem, cas->sg.elem); | 1038 c->elemalg->copy(c->elemsize, sg->elem, cas->sg.elem); |
1054 gp = sg->g; | 1039 gp = sg->g; |
1055 gp->param = sg; | 1040 gp->param = sg; |
1056 runtime·ready(gp); | 1041 runtime·ready(gp); |
1057 | 1042 |
1058 retc: | 1043 retc: |
1059 » // return to pc corresponding to chosen case | 1044 » // return pc corresponding to chosen case. |
| 1045 » // Set boolean passed during select creation |
| 1046 » // (at offset selp + cas->so) to true. |
| 1047 » // If cas->so == 0, this is a reflect-driven select and we |
| 1048 » // don't need to update the boolean. |
1060 pc = cas->pc; | 1049 pc = cas->pc; |
1061 » as = (byte*)selp + cas->so; | 1050 » if(cas->so > 0) { |
| 1051 » » as = (byte*)selp + cas->so; |
| 1052 » » *as = true; |
| 1053 » } |
1062 runtime·free(sel); | 1054 runtime·free(sel); |
1063 *as = true; | |
1064 return pc; | 1055 return pc; |
1065 | 1056 |
1066 sclose: | 1057 sclose: |
1067 // send on closed channel | 1058 // send on closed channel |
1068 selunlock(sel); | 1059 selunlock(sel); |
1069 runtime·panicstring("send on closed channel"); | 1060 runtime·panicstring("send on closed channel"); |
1070 return nil; // not reached | 1061 return nil; // not reached |
| 1062 } |
| 1063 |
| 1064 // This struct must match ../reflect/value.go:/runtimeSelect. |
| 1065 typedef struct runtimeSelect runtimeSelect; |
| 1066 struct runtimeSelect |
| 1067 { |
| 1068 uintptr dir; |
| 1069 ChanType *typ; |
| 1070 Hchan *ch; |
| 1071 uintptr val; |
| 1072 }; |
| 1073 |
| 1074 // This enum must match ../reflect/value.go:/SelectDir. |
| 1075 enum SelectDir { |
| 1076 SelectSend = 1, |
| 1077 SelectRecv, |
| 1078 SelectDefault, |
| 1079 }; |
| 1080 |
| 1081 // func rselect(cases []runtimeSelect) (chosen int, word uintptr, recvOK bool) |
| 1082 void |
| 1083 reflect·rselect(Slice cases, intgo chosen, uintptr word, bool recvOK) |
| 1084 { |
| 1085 int32 i; |
| 1086 Select *sel; |
| 1087 runtimeSelect* rcase, *rc; |
| 1088 void *elem; |
| 1089 void *recvptr; |
| 1090 uintptr maxsize; |
| 1091 |
| 1092 chosen = -1; |
| 1093 word = 0; |
| 1094 recvOK = false; |
| 1095 |
| 1096 maxsize = 0; |
| 1097 rcase = (runtimeSelect*)cases.array; |
| 1098 for(i=0; i<cases.len; i++) { |
| 1099 rc = &rcase[i]; |
| 1100 if(rc->dir == SelectRecv && rc->ch != nil && maxsize < rc->typ->
elem->size) |
| 1101 maxsize = rc->typ->elem->size; |
| 1102 } |
| 1103 |
| 1104 recvptr = nil; |
| 1105 if(maxsize > sizeof(void*)) |
| 1106 recvptr = runtime·mal(maxsize); |
| 1107 |
| 1108 newselect(cases.len, &sel); |
| 1109 for(i=0; i<cases.len; i++) { |
| 1110 rc = &rcase[i]; |
| 1111 switch(rc->dir) { |
| 1112 case SelectDefault: |
| 1113 selectdefault(sel, (void*)i, 0); |
| 1114 break; |
| 1115 case SelectSend: |
| 1116 if(rc->ch == nil) |
| 1117 break; |
| 1118 if(rc->typ->elem->size > sizeof(void*)) |
| 1119 elem = (void*)rc->val; |
| 1120 else |
| 1121 elem = (void*)&rc->val; |
| 1122 selectsend(sel, rc->ch, (void*)i, elem, 0); |
| 1123 break; |
| 1124 case SelectRecv: |
| 1125 if(rc->ch == nil) |
| 1126 break; |
| 1127 if(rc->typ->elem->size > sizeof(void*)) |
| 1128 elem = recvptr; |
| 1129 else |
| 1130 elem = &word; |
| 1131 selectrecv(sel, rc->ch, (void*)i, elem, &recvOK, 0); |
| 1132 break; |
| 1133 } |
| 1134 } |
| 1135 |
| 1136 chosen = (intgo)(uintptr)selectgo(&sel); |
| 1137 if(rcase[chosen].dir == SelectRecv && rcase[chosen].typ->elem->size > si
zeof(void*)) |
| 1138 word = (uintptr)recvptr; |
| 1139 |
| 1140 FLUSH(&chosen); |
| 1141 FLUSH(&word); |
| 1142 FLUSH(&recvOK); |
1071 } | 1143 } |
1072 | 1144 |
1073 // closechan(sel *byte); | 1145 // closechan(sel *byte); |
1074 void | 1146 void |
1075 runtime·closechan(Hchan *c) | 1147 runtime·closechan(Hchan *c) |
1076 { | 1148 { |
1077 SudoG *sg; | 1149 SudoG *sg; |
1078 G* gp; | 1150 G* gp; |
1079 | 1151 |
1080 if(c == nil) | 1152 if(c == nil) |
(...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1116 | 1188 |
1117 // For reflect | 1189 // For reflect |
1118 // func chanclose(c chan) | 1190 // func chanclose(c chan) |
1119 void | 1191 void |
1120 reflect·chanclose(Hchan *c) | 1192 reflect·chanclose(Hchan *c) |
1121 { | 1193 { |
1122 runtime·closechan(c); | 1194 runtime·closechan(c); |
1123 } | 1195 } |
1124 | 1196 |
1125 // For reflect | 1197 // For reflect |
1126 //» func chanlen(c chan) (len int32) | 1198 //» func chanlen(c chan) (len int) |
1127 void | 1199 void |
1128 reflect·chanlen(Hchan *c, int32 len) | 1200 reflect·chanlen(Hchan *c, intgo len) |
1129 { | 1201 { |
1130 if(c == nil) | 1202 if(c == nil) |
1131 len = 0; | 1203 len = 0; |
1132 else | 1204 else |
1133 len = c->qcount; | 1205 len = c->qcount; |
1134 FLUSH(&len); | 1206 FLUSH(&len); |
1135 } | 1207 } |
1136 | 1208 |
1137 // For reflect | 1209 // For reflect |
1138 //» func chancap(c chan) (cap int32) | 1210 //» func chancap(c chan) int |
1139 void | 1211 void |
1140 reflect·chancap(Hchan *c, int32 cap) | 1212 reflect·chancap(Hchan *c, intgo cap) |
1141 { | 1213 { |
1142 if(c == nil) | 1214 if(c == nil) |
1143 cap = 0; | 1215 cap = 0; |
1144 else | 1216 else |
1145 cap = c->dataqsiz; | 1217 cap = c->dataqsiz; |
1146 FLUSH(&cap); | 1218 FLUSH(&cap); |
1147 } | 1219 } |
1148 | 1220 |
1149 static SudoG* | 1221 static SudoG* |
1150 dequeue(WaitQ *q) | 1222 dequeue(WaitQ *q) |
(...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1189 { | 1261 { |
1190 sgp->link = nil; | 1262 sgp->link = nil; |
1191 if(q->first == nil) { | 1263 if(q->first == nil) { |
1192 q->first = sgp; | 1264 q->first = sgp; |
1193 q->last = sgp; | 1265 q->last = sgp; |
1194 return; | 1266 return; |
1195 } | 1267 } |
1196 q->last->link = sgp; | 1268 q->last->link = sgp; |
1197 q->last = sgp; | 1269 q->last = sgp; |
1198 } | 1270 } |
LEFT | RIGHT |