github.com/xushiwei/go@v0.0.0-20130601165731-2b9d83f45bc9/src/pkg/runtime/chan.c (about) 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 #include "runtime.h" 6 #include "arch_GOARCH.h" 7 #include "type.h" 8 #include "race.h" 9 #include "malloc.h" 10 11 #define MAXALIGN 7 12 #define NOSELGEN 1 13 14 static int32 debug = 0; 15 16 typedef struct WaitQ WaitQ; 17 typedef struct SudoG SudoG; 18 typedef struct Select Select; 19 typedef struct Scase Scase; 20 21 struct SudoG 22 { 23 G* g; // g and selgen constitute 24 uint32 selgen; // a weak pointer to g 25 SudoG* link; 26 int64 releasetime; 27 byte* elem; // data element 28 }; 29 30 struct WaitQ 31 { 32 SudoG* first; 33 SudoG* last; 34 }; 35 36 // The garbage collector is assuming that Hchan can only contain pointers into the stack 37 // and cannot contain pointers into the heap. 38 struct Hchan 39 { 40 uintgo qcount; // total data in the q 41 uintgo dataqsiz; // size of the circular q 42 uint16 elemsize; 43 bool closed; 44 uint8 elemalign; 45 Alg* elemalg; // interface for element type 46 uintgo sendx; // send index 47 uintgo recvx; // receive index 48 WaitQ recvq; // list of recv waiters 49 WaitQ sendq; // list of send waiters 50 Lock; 51 }; 52 53 uint32 runtime·Hchansize = sizeof(Hchan); 54 55 // Buffer follows Hchan immediately in memory. 56 // chanbuf(c, i) is pointer to the i'th slot in the buffer. 57 #define chanbuf(c, i) ((byte*)((c)+1)+(uintptr)(c)->elemsize*(i)) 58 59 enum 60 { 61 // Scase.kind 62 CaseRecv, 63 CaseSend, 64 CaseDefault, 65 }; 66 67 struct Scase 68 { 69 SudoG sg; // must be first member (cast to Scase) 70 Hchan* chan; // chan 71 byte* pc; // return pc 72 uint16 kind; 73 uint16 so; // vararg of selected bool 74 bool* receivedp; // pointer to received bool (recv2) 75 }; 76 77 struct Select 78 { 79 uint16 tcase; // total count of scase[] 80 uint16 ncase; // currently filled scase[] 81 uint16* pollorder; // case poll order 82 Hchan** lockorder; // channel lock order 83 Scase scase[1]; // one per case (in order of appearance) 84 }; 85 86 static void dequeueg(WaitQ*); 87 static SudoG* dequeue(WaitQ*); 88 static void enqueue(WaitQ*, SudoG*); 89 static void destroychan(Hchan*); 90 static void racesync(Hchan*, SudoG*); 91 92 Hchan* 93 runtime·makechan_c(ChanType *t, int64 hint) 94 { 95 Hchan *c; 96 uintptr n; 97 Type *elem; 98 99 elem = t->elem; 100 101 // compiler checks this but be safe. 102 if(elem->size >= (1<<16)) 103 runtime·throw("makechan: invalid channel element type"); 104 105 if(hint < 0 || (intgo)hint != hint || (elem->size > 0 && hint > MaxMem / elem->size)) 106 runtime·panicstring("makechan: size out of range"); 107 108 // calculate rounded size of Hchan 109 n = sizeof(*c); 110 while(n & MAXALIGN) 111 n++; 112 113 // allocate memory in one call 114 c = (Hchan*)runtime·mal(n + hint*elem->size); 115 c->elemsize = elem->size; 116 c->elemalg = elem->alg; 117 c->elemalign = elem->align; 118 c->dataqsiz = hint; 119 runtime·settype(c, (uintptr)t | TypeInfo_Chan); 120 121 if(debug) 122 runtime·printf("makechan: chan=%p; elemsize=%D; elemalg=%p; elemalign=%d; dataqsiz=%D\n", 123 c, (int64)elem->size, elem->alg, elem->align, (int64)c->dataqsiz); 124 125 return c; 126 } 127 128 // For reflect 129 // func makechan(typ *ChanType, size uint64) (chan) 130 void 131 reflect·makechan(ChanType *t, uint64 size, Hchan *c) 132 { 133 c = runtime·makechan_c(t, size); 134 FLUSH(&c); 135 } 136 137 // makechan(t *ChanType, hint int64) (hchan *chan any); 138 void 139 runtime·makechan(ChanType *t, int64 hint, Hchan *ret) 140 { 141 ret = runtime·makechan_c(t, hint); 142 FLUSH(&ret); 143 } 144 145 /* 146 * generic single channel send/recv 147 * if the bool pointer is nil, 148 * then the full exchange will 149 * occur. if pres is not nil, 150 * then the protocol will not 151 * sleep but return if it could 152 * not complete. 153 * 154 * sleep can wake up with g->param == nil 155 * when a channel involved in the sleep has 156 * been closed. it is easiest to loop and re-run 157 * the operation; we'll see that it's now closed. 158 */ 159 void 160 runtime·chansend(ChanType *t, Hchan *c, byte *ep, bool *pres, void *pc) 161 { 162 SudoG *sg; 163 SudoG mysg; 164 G* gp; 165 int64 t0; 166 167 if(c == nil) { 168 USED(t); 169 if(pres != nil) { 170 *pres = false; 171 return; 172 } 173 runtime·park(nil, nil, "chan send (nil chan)"); 174 return; // not reached 175 } 176 177 if(runtime·gcwaiting) 178 runtime·gosched(); 179 180 if(debug) { 181 runtime·printf("chansend: chan=%p; elem=", c); 182 c->elemalg->print(c->elemsize, ep); 183 runtime·prints("\n"); 184 } 185 186 t0 = 0; 187 mysg.releasetime = 0; 188 if(runtime·blockprofilerate > 0) { 189 t0 = runtime·cputicks(); 190 mysg.releasetime = -1; 191 } 192 193 runtime·lock(c); 194 // TODO(dvyukov): add similar instrumentation to select. 195 if(raceenabled) 196 runtime·racereadpc(c, pc, runtime·chansend); 197 if(c->closed) 198 goto closed; 199 200 if(c->dataqsiz > 0) 201 goto asynch; 202 203 sg = dequeue(&c->recvq); 204 if(sg != nil) { 205 if(raceenabled) 206 racesync(c, sg); 207 runtime·unlock(c); 208 209 gp = sg->g; 210 gp->param = sg; 211 if(sg->elem != nil) 212 c->elemalg->copy(c->elemsize, sg->elem, ep); 213 if(sg->releasetime) 214 sg->releasetime = runtime·cputicks(); 215 runtime·ready(gp); 216 217 if(pres != nil) 218 *pres = true; 219 return; 220 } 221 222 if(pres != nil) { 223 runtime·unlock(c); 224 *pres = false; 225 return; 226 } 227 228 mysg.elem = ep; 229 mysg.g = g; 230 mysg.selgen = NOSELGEN; 231 g->param = nil; 232 enqueue(&c->sendq, &mysg); 233 runtime·park(runtime·unlock, c, "chan send"); 234 235 if(g->param == nil) { 236 runtime·lock(c); 237 if(!c->closed) 238 runtime·throw("chansend: spurious wakeup"); 239 goto closed; 240 } 241 242 if(mysg.releasetime > 0) 243 runtime·blockevent(mysg.releasetime - t0, 2); 244 245 return; 246 247 asynch: 248 if(c->closed) 249 goto closed; 250 251 if(c->qcount >= c->dataqsiz) { 252 if(pres != nil) { 253 runtime·unlock(c); 254 *pres = false; 255 return; 256 } 257 mysg.g = g; 258 mysg.elem = nil; 259 mysg.selgen = NOSELGEN; 260 enqueue(&c->sendq, &mysg); 261 runtime·park(runtime·unlock, c, "chan send"); 262 263 runtime·lock(c); 264 goto asynch; 265 } 266 267 if(raceenabled) 268 runtime·racerelease(chanbuf(c, c->sendx)); 269 270 c->elemalg->copy(c->elemsize, chanbuf(c, c->sendx), ep); 271 if(++c->sendx == c->dataqsiz) 272 c->sendx = 0; 273 c->qcount++; 274 275 sg = dequeue(&c->recvq); 276 if(sg != nil) { 277 gp = sg->g; 278 runtime·unlock(c); 279 if(sg->releasetime) 280 sg->releasetime = runtime·cputicks(); 281 runtime·ready(gp); 282 } else 283 runtime·unlock(c); 284 if(pres != nil) 285 *pres = true; 286 if(mysg.releasetime > 0) 287 runtime·blockevent(mysg.releasetime - t0, 2); 288 return; 289 290 closed: 291 runtime·unlock(c); 292 runtime·panicstring("send on closed channel"); 293 } 294 295 296 void 297 runtime·chanrecv(ChanType *t, Hchan* c, byte *ep, bool *selected, bool *received) 298 { 299 SudoG *sg; 300 SudoG mysg; 301 G *gp; 302 int64 t0; 303 304 if(runtime·gcwaiting) 305 runtime·gosched(); 306 307 if(debug) 308 runtime·printf("chanrecv: chan=%p\n", c); 309 310 if(c == nil) { 311 USED(t); 312 if(selected != nil) { 313 *selected = false; 314 return; 315 } 316 runtime·park(nil, nil, "chan receive (nil chan)"); 317 return; // not reached 318 } 319 320 t0 = 0; 321 mysg.releasetime = 0; 322 if(runtime·blockprofilerate > 0) { 323 t0 = runtime·cputicks(); 324 mysg.releasetime = -1; 325 } 326 327 runtime·lock(c); 328 if(c->dataqsiz > 0) 329 goto asynch; 330 331 if(c->closed) 332 goto closed; 333 334 sg = dequeue(&c->sendq); 335 if(sg != nil) { 336 if(raceenabled) 337 racesync(c, sg); 338 runtime·unlock(c); 339 340 if(ep != nil) 341 c->elemalg->copy(c->elemsize, ep, sg->elem); 342 gp = sg->g; 343 gp->param = sg; 344 if(sg->releasetime) 345 sg->releasetime = runtime·cputicks(); 346 runtime·ready(gp); 347 348 if(selected != nil) 349 *selected = true; 350 if(received != nil) 351 *received = true; 352 return; 353 } 354 355 if(selected != nil) { 356 runtime·unlock(c); 357 *selected = false; 358 return; 359 } 360 361 mysg.elem = ep; 362 mysg.g = g; 363 mysg.selgen = NOSELGEN; 364 g->param = nil; 365 enqueue(&c->recvq, &mysg); 366 runtime·park(runtime·unlock, c, "chan receive"); 367 368 if(g->param == nil) { 369 runtime·lock(c); 370 if(!c->closed) 371 runtime·throw("chanrecv: spurious wakeup"); 372 goto closed; 373 } 374 375 if(received != nil) 376 *received = true; 377 if(mysg.releasetime > 0) 378 runtime·blockevent(mysg.releasetime - t0, 2); 379 return; 380 381 asynch: 382 if(c->qcount <= 0) { 383 if(c->closed) 384 goto closed; 385 386 if(selected != nil) { 387 runtime·unlock(c); 388 *selected = false; 389 if(received != nil) 390 *received = false; 391 return; 392 } 393 mysg.g = g; 394 mysg.elem = nil; 395 mysg.selgen = NOSELGEN; 396 enqueue(&c->recvq, &mysg); 397 runtime·park(runtime·unlock, c, "chan receive"); 398 399 runtime·lock(c); 400 goto asynch; 401 } 402 403 if(raceenabled) 404 runtime·raceacquire(chanbuf(c, c->recvx)); 405 406 if(ep != nil) 407 c->elemalg->copy(c->elemsize, ep, chanbuf(c, c->recvx)); 408 c->elemalg->copy(c->elemsize, chanbuf(c, c->recvx), nil); 409 if(++c->recvx == c->dataqsiz) 410 c->recvx = 0; 411 c->qcount--; 412 413 sg = dequeue(&c->sendq); 414 if(sg != nil) { 415 gp = sg->g; 416 runtime·unlock(c); 417 if(sg->releasetime) 418 sg->releasetime = runtime·cputicks(); 419 runtime·ready(gp); 420 } else 421 runtime·unlock(c); 422 423 if(selected != nil) 424 *selected = true; 425 if(received != nil) 426 *received = true; 427 if(mysg.releasetime > 0) 428 runtime·blockevent(mysg.releasetime - t0, 2); 429 return; 430 431 closed: 432 if(ep != nil) 433 c->elemalg->copy(c->elemsize, ep, nil); 434 if(selected != nil) 435 *selected = true; 436 if(received != nil) 437 *received = false; 438 if(raceenabled) 439 runtime·raceacquire(c); 440 runtime·unlock(c); 441 if(mysg.releasetime > 0) 442 runtime·blockevent(mysg.releasetime - t0, 2); 443 } 444 445 // chansend1(hchan *chan any, elem any); 446 #pragma textflag 7 447 void 448 runtime·chansend1(ChanType *t, Hchan* c, ...) 449 { 450 runtime·chansend(t, c, (byte*)(&c+1), nil, runtime·getcallerpc(&t)); 451 } 452 453 // chanrecv1(hchan *chan any) (elem any); 454 #pragma textflag 7 455 void 456 runtime·chanrecv1(ChanType *t, Hchan* c, ...) 457 { 458 runtime·chanrecv(t, c, (byte*)(&c+1), nil, nil); 459 } 460 461 // chanrecv2(hchan *chan any) (elem any, received bool); 462 #pragma textflag 7 463 void 464 runtime·chanrecv2(ChanType *t, Hchan* c, ...) 465 { 466 byte *ae, *ap; 467 468 ae = (byte*)(&c+1); 469 ap = ae + t->elem->size; 470 runtime·chanrecv(t, c, ae, nil, ap); 471 } 472 473 // func selectnbsend(c chan any, elem any) bool 474 // 475 // compiler implements 476 // 477 // select { 478 // case c <- v: 479 // ... foo 480 // default: 481 // ... bar 482 // } 483 // 484 // as 485 // 486 // if selectnbsend(c, v) { 487 // ... foo 488 // } else { 489 // ... bar 490 // } 491 // 492 #pragma textflag 7 493 void 494 runtime·selectnbsend(ChanType *t, Hchan *c, ...) 495 { 496 byte *ae, *ap; 497 498 ae = (byte*)(&c + 1); 499 ap = ae + ROUND(t->elem->size, Structrnd); 500 runtime·chansend(t, c, ae, ap, runtime·getcallerpc(&t)); 501 } 502 503 // func selectnbrecv(elem *any, c chan any) bool 504 // 505 // compiler implements 506 // 507 // select { 508 // case v = <-c: 509 // ... foo 510 // default: 511 // ... bar 512 // } 513 // 514 // as 515 // 516 // if selectnbrecv(&v, c) { 517 // ... foo 518 // } else { 519 // ... bar 520 // } 521 // 522 #pragma textflag 7 523 void 524 runtime·selectnbrecv(ChanType *t, byte *v, Hchan *c, bool selected) 525 { 526 runtime·chanrecv(t, c, v, &selected, nil); 527 } 528 529 // func selectnbrecv2(elem *any, ok *bool, c chan any) bool 530 // 531 // compiler implements 532 // 533 // select { 534 // case v, ok = <-c: 535 // ... foo 536 // default: 537 // ... bar 538 // } 539 // 540 // as 541 // 542 // if c != nil && selectnbrecv2(&v, &ok, c) { 543 // ... foo 544 // } else { 545 // ... bar 546 // } 547 // 548 #pragma textflag 7 549 void 550 runtime·selectnbrecv2(ChanType *t, byte *v, bool *received, Hchan *c, bool selected) 551 { 552 runtime·chanrecv(t, c, v, &selected, received); 553 } 554 555 // For reflect: 556 // func chansend(c chan, val iword, nb bool) (selected bool) 557 // where an iword is the same word an interface value would use: 558 // the actual data if it fits, or else a pointer to the data. 559 // 560 // The "uintptr selected" is really "bool selected" but saying 561 // uintptr gets us the right alignment for the output parameter block. 562 #pragma textflag 7 563 void 564 reflect·chansend(ChanType *t, Hchan *c, uintptr val, bool nb, uintptr selected) 565 { 566 bool *sp; 567 byte *vp; 568 569 if(nb) { 570 selected = false; 571 sp = (bool*)&selected; 572 } else { 573 *(bool*)&selected = true; 574 FLUSH(&selected); 575 sp = nil; 576 } 577 if(t->elem->size <= sizeof(val)) 578 vp = (byte*)&val; 579 else 580 vp = (byte*)val; 581 runtime·chansend(t, c, vp, sp, runtime·getcallerpc(&t)); 582 } 583 584 // For reflect: 585 // func chanrecv(c chan, nb bool) (val iword, selected, received bool) 586 // where an iword is the same word an interface value would use: 587 // the actual data if it fits, or else a pointer to the data. 588 void 589 reflect·chanrecv(ChanType *t, Hchan *c, bool nb, uintptr val, bool selected, bool received) 590 { 591 byte *vp; 592 bool *sp; 593 594 if(nb) { 595 selected = false; 596 sp = &selected; 597 } else { 598 selected = true; 599 FLUSH(&selected); 600 sp = nil; 601 } 602 received = false; 603 FLUSH(&received); 604 if(t->elem->size <= sizeof(val)) { 605 val = 0; 606 vp = (byte*)&val; 607 } else { 608 vp = runtime·mal(t->elem->size); 609 val = (uintptr)vp; 610 FLUSH(&val); 611 } 612 runtime·chanrecv(t, c, vp, sp, &received); 613 } 614 615 static void newselect(int32, Select**); 616 617 // newselect(size uint32) (sel *byte); 618 #pragma textflag 7 619 void 620 runtime·newselect(int32 size, ...) 621 { 622 int32 o; 623 Select **selp; 624 625 o = ROUND(sizeof(size), Structrnd); 626 selp = (Select**)((byte*)&size + o); 627 newselect(size, selp); 628 } 629 630 static void 631 newselect(int32 size, Select **selp) 632 { 633 int32 n; 634 Select *sel; 635 636 n = 0; 637 if(size > 1) 638 n = size-1; 639 640 // allocate all the memory we need in a single allocation 641 // start with Select with size cases 642 // then lockorder with size entries 643 // then pollorder with size entries 644 sel = runtime·mal(sizeof(*sel) + 645 n*sizeof(sel->scase[0]) + 646 size*sizeof(sel->lockorder[0]) + 647 size*sizeof(sel->pollorder[0])); 648 649 sel->tcase = size; 650 sel->ncase = 0; 651 sel->lockorder = (void*)(sel->scase + size); 652 sel->pollorder = (void*)(sel->lockorder + size); 653 *selp = sel; 654 655 if(debug) 656 runtime·printf("newselect s=%p size=%d\n", sel, size); 657 } 658 659 // cut in half to give stack a chance to split 660 static void selectsend(Select *sel, Hchan *c, void *pc, void *elem, int32 so); 661 662 // selectsend(sel *byte, hchan *chan any, elem *any) (selected bool); 663 #pragma textflag 7 664 void 665 runtime·selectsend(Select *sel, Hchan *c, void *elem, bool selected) 666 { 667 selected = false; 668 FLUSH(&selected); 669 670 // nil cases do not compete 671 if(c == nil) 672 return; 673 674 selectsend(sel, c, runtime·getcallerpc(&sel), elem, (byte*)&selected - (byte*)&sel); 675 } 676 677 static void 678 selectsend(Select *sel, Hchan *c, void *pc, void *elem, int32 so) 679 { 680 int32 i; 681 Scase *cas; 682 683 i = sel->ncase; 684 if(i >= sel->tcase) 685 runtime·throw("selectsend: too many cases"); 686 sel->ncase = i+1; 687 cas = &sel->scase[i]; 688 689 cas->pc = pc; 690 cas->chan = c; 691 cas->so = so; 692 cas->kind = CaseSend; 693 cas->sg.elem = elem; 694 695 if(debug) 696 runtime·printf("selectsend s=%p pc=%p chan=%p so=%d\n", 697 sel, cas->pc, cas->chan, cas->so); 698 } 699 700 // cut in half to give stack a chance to split 701 static void selectrecv(Select *sel, Hchan *c, void *pc, void *elem, bool*, int32 so); 702 703 // selectrecv(sel *byte, hchan *chan any, elem *any) (selected bool); 704 #pragma textflag 7 705 void 706 runtime·selectrecv(Select *sel, Hchan *c, void *elem, bool selected) 707 { 708 selected = false; 709 FLUSH(&selected); 710 711 // nil cases do not compete 712 if(c == nil) 713 return; 714 715 selectrecv(sel, c, runtime·getcallerpc(&sel), elem, nil, (byte*)&selected - (byte*)&sel); 716 } 717 718 // selectrecv2(sel *byte, hchan *chan any, elem *any, received *bool) (selected bool); 719 #pragma textflag 7 720 void 721 runtime·selectrecv2(Select *sel, Hchan *c, void *elem, bool *received, bool selected) 722 { 723 selected = false; 724 FLUSH(&selected); 725 726 // nil cases do not compete 727 if(c == nil) 728 return; 729 730 selectrecv(sel, c, runtime·getcallerpc(&sel), elem, received, (byte*)&selected - (byte*)&sel); 731 } 732 733 static void 734 selectrecv(Select *sel, Hchan *c, void *pc, void *elem, bool *received, int32 so) 735 { 736 int32 i; 737 Scase *cas; 738 739 i = sel->ncase; 740 if(i >= sel->tcase) 741 runtime·throw("selectrecv: too many cases"); 742 sel->ncase = i+1; 743 cas = &sel->scase[i]; 744 cas->pc = pc; 745 cas->chan = c; 746 747 cas->so = so; 748 cas->kind = CaseRecv; 749 cas->sg.elem = elem; 750 cas->receivedp = received; 751 752 if(debug) 753 runtime·printf("selectrecv s=%p pc=%p chan=%p so=%d\n", 754 sel, cas->pc, cas->chan, cas->so); 755 } 756 757 // cut in half to give stack a chance to split 758 static void selectdefault(Select*, void*, int32); 759 760 // selectdefault(sel *byte) (selected bool); 761 #pragma textflag 7 762 void 763 runtime·selectdefault(Select *sel, bool selected) 764 { 765 selected = false; 766 FLUSH(&selected); 767 768 selectdefault(sel, runtime·getcallerpc(&sel), (byte*)&selected - (byte*)&sel); 769 } 770 771 static void 772 selectdefault(Select *sel, void *callerpc, int32 so) 773 { 774 int32 i; 775 Scase *cas; 776 777 i = sel->ncase; 778 if(i >= sel->tcase) 779 runtime·throw("selectdefault: too many cases"); 780 sel->ncase = i+1; 781 cas = &sel->scase[i]; 782 cas->pc = callerpc; 783 cas->chan = nil; 784 785 cas->so = so; 786 cas->kind = CaseDefault; 787 788 if(debug) 789 runtime·printf("selectdefault s=%p pc=%p so=%d\n", 790 sel, cas->pc, cas->so); 791 } 792 793 static void 794 sellock(Select *sel) 795 { 796 uint32 i; 797 Hchan *c, *c0; 798 799 c = nil; 800 for(i=0; i<sel->ncase; i++) { 801 c0 = sel->lockorder[i]; 802 if(c0 && c0 != c) { 803 c = sel->lockorder[i]; 804 runtime·lock(c); 805 } 806 } 807 } 808 809 static void 810 selunlock(Select *sel) 811 { 812 int32 i, n, r; 813 Hchan *c; 814 815 // We must be very careful here to not touch sel after we have unlocked 816 // the last lock, because sel can be freed right after the last unlock. 817 // Consider the following situation. 818 // First M calls runtime·park() in runtime·selectgo() passing the sel. 819 // Once runtime·park() has unlocked the last lock, another M makes 820 // the G that calls select runnable again and schedules it for execution. 821 // When the G runs on another M, it locks all the locks and frees sel. 822 // Now if the first M touches sel, it will access freed memory. 823 n = (int32)sel->ncase; 824 r = 0; 825 // skip the default case 826 if(n>0 && sel->lockorder[0] == nil) 827 r = 1; 828 for(i = n-1; i >= r; i--) { 829 c = sel->lockorder[i]; 830 if(i>0 && sel->lockorder[i-1] == c) 831 continue; // will unlock it on the next iteration 832 runtime·unlock(c); 833 } 834 } 835 836 void 837 runtime·block(void) 838 { 839 runtime·park(nil, nil, "select (no cases)"); // forever 840 } 841 842 static void* selectgo(Select**); 843 844 // selectgo(sel *byte); 845 // 846 // overwrites return pc on stack to signal which case of the select 847 // to run, so cannot appear at the top of a split stack. 848 #pragma textflag 7 849 void 850 runtime·selectgo(Select *sel) 851 { 852 runtime·setcallerpc(&sel, selectgo(&sel)); 853 } 854 855 static void* 856 selectgo(Select **selp) 857 { 858 Select *sel; 859 uint32 o, i, j, k; 860 Scase *cas, *dfl; 861 Hchan *c; 862 SudoG *sg; 863 G *gp; 864 byte *as; 865 void *pc; 866 867 sel = *selp; 868 if(runtime·gcwaiting) 869 runtime·gosched(); 870 871 if(debug) 872 runtime·printf("select: sel=%p\n", sel); 873 874 // The compiler rewrites selects that statically have 875 // only 0 or 1 cases plus default into simpler constructs. 876 // The only way we can end up with such small sel->ncase 877 // values here is for a larger select in which most channels 878 // have been nilled out. The general code handles those 879 // cases correctly, and they are rare enough not to bother 880 // optimizing (and needing to test). 881 882 // generate permuted order 883 for(i=0; i<sel->ncase; i++) 884 sel->pollorder[i] = i; 885 for(i=1; i<sel->ncase; i++) { 886 o = sel->pollorder[i]; 887 j = runtime·fastrand1()%(i+1); 888 sel->pollorder[i] = sel->pollorder[j]; 889 sel->pollorder[j] = o; 890 } 891 892 // sort the cases by Hchan address to get the locking order. 893 // simple heap sort, to guarantee n log n time and constant stack footprint. 894 for(i=0; i<sel->ncase; i++) { 895 j = i; 896 c = sel->scase[j].chan; 897 while(j > 0 && sel->lockorder[k=(j-1)/2] < c) { 898 sel->lockorder[j] = sel->lockorder[k]; 899 j = k; 900 } 901 sel->lockorder[j] = c; 902 } 903 for(i=sel->ncase; i-->0; ) { 904 c = sel->lockorder[i]; 905 sel->lockorder[i] = sel->lockorder[0]; 906 j = 0; 907 for(;;) { 908 k = j*2+1; 909 if(k >= i) 910 break; 911 if(k+1 < i && sel->lockorder[k] < sel->lockorder[k+1]) 912 k++; 913 if(c < sel->lockorder[k]) { 914 sel->lockorder[j] = sel->lockorder[k]; 915 j = k; 916 continue; 917 } 918 break; 919 } 920 sel->lockorder[j] = c; 921 } 922 /* 923 for(i=0; i+1<sel->ncase; i++) 924 if(sel->lockorder[i] > sel->lockorder[i+1]) { 925 runtime·printf("i=%d %p %p\n", i, sel->lockorder[i], sel->lockorder[i+1]); 926 runtime·throw("select: broken sort"); 927 } 928 */ 929 sellock(sel); 930 931 loop: 932 // pass 1 - look for something already waiting 933 dfl = nil; 934 for(i=0; i<sel->ncase; i++) { 935 o = sel->pollorder[i]; 936 cas = &sel->scase[o]; 937 c = cas->chan; 938 939 switch(cas->kind) { 940 case CaseRecv: 941 if(c->dataqsiz > 0) { 942 if(c->qcount > 0) 943 goto asyncrecv; 944 } else { 945 sg = dequeue(&c->sendq); 946 if(sg != nil) 947 goto syncrecv; 948 } 949 if(c->closed) 950 goto rclose; 951 break; 952 953 case CaseSend: 954 if(c->closed) 955 goto sclose; 956 if(c->dataqsiz > 0) { 957 if(c->qcount < c->dataqsiz) 958 goto asyncsend; 959 } else { 960 sg = dequeue(&c->recvq); 961 if(sg != nil) 962 goto syncsend; 963 } 964 break; 965 966 case CaseDefault: 967 dfl = cas; 968 break; 969 } 970 } 971 972 if(dfl != nil) { 973 selunlock(sel); 974 cas = dfl; 975 goto retc; 976 } 977 978 979 // pass 2 - enqueue on all chans 980 for(i=0; i<sel->ncase; i++) { 981 o = sel->pollorder[i]; 982 cas = &sel->scase[o]; 983 c = cas->chan; 984 sg = &cas->sg; 985 sg->g = g; 986 sg->selgen = g->selgen; 987 988 switch(cas->kind) { 989 case CaseRecv: 990 enqueue(&c->recvq, sg); 991 break; 992 993 case CaseSend: 994 enqueue(&c->sendq, sg); 995 break; 996 } 997 } 998 999 g->param = nil; 1000 runtime·park((void(*)(Lock*))selunlock, (Lock*)sel, "select"); 1001 1002 sellock(sel); 1003 sg = g->param; 1004 1005 // pass 3 - dequeue from unsuccessful chans 1006 // otherwise they stack up on quiet channels 1007 for(i=0; i<sel->ncase; i++) { 1008 cas = &sel->scase[i]; 1009 if(cas != (Scase*)sg) { 1010 c = cas->chan; 1011 if(cas->kind == CaseSend) 1012 dequeueg(&c->sendq); 1013 else 1014 dequeueg(&c->recvq); 1015 } 1016 } 1017 1018 if(sg == nil) 1019 goto loop; 1020 1021 cas = (Scase*)sg; 1022 c = cas->chan; 1023 1024 if(c->dataqsiz > 0) 1025 runtime·throw("selectgo: shouldn't happen"); 1026 1027 if(debug) 1028 runtime·printf("wait-return: sel=%p c=%p cas=%p kind=%d\n", 1029 sel, c, cas, cas->kind); 1030 1031 if(cas->kind == CaseRecv) { 1032 if(cas->receivedp != nil) 1033 *cas->receivedp = true; 1034 } 1035 1036 selunlock(sel); 1037 goto retc; 1038 1039 asyncrecv: 1040 // can receive from buffer 1041 if(raceenabled) 1042 runtime·raceacquire(chanbuf(c, c->recvx)); 1043 if(cas->receivedp != nil) 1044 *cas->receivedp = true; 1045 if(cas->sg.elem != nil) 1046 c->elemalg->copy(c->elemsize, cas->sg.elem, chanbuf(c, c->recvx)); 1047 c->elemalg->copy(c->elemsize, chanbuf(c, c->recvx), nil); 1048 if(++c->recvx == c->dataqsiz) 1049 c->recvx = 0; 1050 c->qcount--; 1051 sg = dequeue(&c->sendq); 1052 if(sg != nil) { 1053 gp = sg->g; 1054 selunlock(sel); 1055 runtime·ready(gp); 1056 } else { 1057 selunlock(sel); 1058 } 1059 goto retc; 1060 1061 asyncsend: 1062 // can send to buffer 1063 if(raceenabled) 1064 runtime·racerelease(chanbuf(c, c->sendx)); 1065 c->elemalg->copy(c->elemsize, chanbuf(c, c->sendx), cas->sg.elem); 1066 if(++c->sendx == c->dataqsiz) 1067 c->sendx = 0; 1068 c->qcount++; 1069 sg = dequeue(&c->recvq); 1070 if(sg != nil) { 1071 gp = sg->g; 1072 selunlock(sel); 1073 runtime·ready(gp); 1074 } else { 1075 selunlock(sel); 1076 } 1077 goto retc; 1078 1079 syncrecv: 1080 // can receive from sleeping sender (sg) 1081 if(raceenabled) 1082 racesync(c, sg); 1083 selunlock(sel); 1084 if(debug) 1085 runtime·printf("syncrecv: sel=%p c=%p o=%d\n", sel, c, o); 1086 if(cas->receivedp != nil) 1087 *cas->receivedp = true; 1088 if(cas->sg.elem != nil) 1089 c->elemalg->copy(c->elemsize, cas->sg.elem, sg->elem); 1090 gp = sg->g; 1091 gp->param = sg; 1092 runtime·ready(gp); 1093 goto retc; 1094 1095 rclose: 1096 // read at end of closed channel 1097 selunlock(sel); 1098 if(cas->receivedp != nil) 1099 *cas->receivedp = false; 1100 if(cas->sg.elem != nil) 1101 c->elemalg->copy(c->elemsize, cas->sg.elem, nil); 1102 if(raceenabled) 1103 runtime·raceacquire(c); 1104 goto retc; 1105 1106 syncsend: 1107 // can send to sleeping receiver (sg) 1108 if(raceenabled) 1109 racesync(c, sg); 1110 selunlock(sel); 1111 if(debug) 1112 runtime·printf("syncsend: sel=%p c=%p o=%d\n", sel, c, o); 1113 if(sg->elem != nil) 1114 c->elemalg->copy(c->elemsize, sg->elem, cas->sg.elem); 1115 gp = sg->g; 1116 gp->param = sg; 1117 runtime·ready(gp); 1118 1119 retc: 1120 // return pc corresponding to chosen case. 1121 // Set boolean passed during select creation 1122 // (at offset selp + cas->so) to true. 1123 // If cas->so == 0, this is a reflect-driven select and we 1124 // don't need to update the boolean. 1125 pc = cas->pc; 1126 if(cas->so > 0) { 1127 as = (byte*)selp + cas->so; 1128 *as = true; 1129 } 1130 runtime·free(sel); 1131 return pc; 1132 1133 sclose: 1134 // send on closed channel 1135 selunlock(sel); 1136 runtime·panicstring("send on closed channel"); 1137 return nil; // not reached 1138 } 1139 1140 // This struct must match ../reflect/value.go:/runtimeSelect. 1141 typedef struct runtimeSelect runtimeSelect; 1142 struct runtimeSelect 1143 { 1144 uintptr dir; 1145 ChanType *typ; 1146 Hchan *ch; 1147 uintptr val; 1148 }; 1149 1150 // This enum must match ../reflect/value.go:/SelectDir. 1151 enum SelectDir { 1152 SelectSend = 1, 1153 SelectRecv, 1154 SelectDefault, 1155 }; 1156 1157 // func rselect(cases []runtimeSelect) (chosen int, word uintptr, recvOK bool) 1158 void 1159 reflect·rselect(Slice cases, intgo chosen, uintptr word, bool recvOK) 1160 { 1161 int32 i; 1162 Select *sel; 1163 runtimeSelect* rcase, *rc; 1164 void *elem; 1165 void *recvptr; 1166 uintptr maxsize; 1167 1168 chosen = -1; 1169 word = 0; 1170 recvOK = false; 1171 1172 maxsize = 0; 1173 rcase = (runtimeSelect*)cases.array; 1174 for(i=0; i<cases.len; i++) { 1175 rc = &rcase[i]; 1176 if(rc->dir == SelectRecv && rc->ch != nil && maxsize < rc->typ->elem->size) 1177 maxsize = rc->typ->elem->size; 1178 } 1179 1180 recvptr = nil; 1181 if(maxsize > sizeof(void*)) 1182 recvptr = runtime·mal(maxsize); 1183 1184 newselect(cases.len, &sel); 1185 for(i=0; i<cases.len; i++) { 1186 rc = &rcase[i]; 1187 switch(rc->dir) { 1188 case SelectDefault: 1189 selectdefault(sel, (void*)i, 0); 1190 break; 1191 case SelectSend: 1192 if(rc->ch == nil) 1193 break; 1194 if(rc->typ->elem->size > sizeof(void*)) 1195 elem = (void*)rc->val; 1196 else 1197 elem = (void*)&rc->val; 1198 selectsend(sel, rc->ch, (void*)i, elem, 0); 1199 break; 1200 case SelectRecv: 1201 if(rc->ch == nil) 1202 break; 1203 if(rc->typ->elem->size > sizeof(void*)) 1204 elem = recvptr; 1205 else 1206 elem = &word; 1207 selectrecv(sel, rc->ch, (void*)i, elem, &recvOK, 0); 1208 break; 1209 } 1210 } 1211 1212 chosen = (intgo)(uintptr)selectgo(&sel); 1213 if(rcase[chosen].dir == SelectRecv && rcase[chosen].typ->elem->size > sizeof(void*)) 1214 word = (uintptr)recvptr; 1215 1216 FLUSH(&chosen); 1217 FLUSH(&word); 1218 FLUSH(&recvOK); 1219 } 1220 1221 // closechan(sel *byte); 1222 #pragma textflag 7 1223 void 1224 runtime·closechan(Hchan *c) 1225 { 1226 SudoG *sg; 1227 G* gp; 1228 1229 if(c == nil) 1230 runtime·panicstring("close of nil channel"); 1231 1232 if(runtime·gcwaiting) 1233 runtime·gosched(); 1234 1235 runtime·lock(c); 1236 if(c->closed) { 1237 runtime·unlock(c); 1238 runtime·panicstring("close of closed channel"); 1239 } 1240 1241 if(raceenabled) { 1242 runtime·racewritepc(c, runtime·getcallerpc(&c), runtime·closechan); 1243 runtime·racerelease(c); 1244 } 1245 1246 c->closed = true; 1247 1248 // release all readers 1249 for(;;) { 1250 sg = dequeue(&c->recvq); 1251 if(sg == nil) 1252 break; 1253 gp = sg->g; 1254 gp->param = nil; 1255 runtime·ready(gp); 1256 } 1257 1258 // release all writers 1259 for(;;) { 1260 sg = dequeue(&c->sendq); 1261 if(sg == nil) 1262 break; 1263 gp = sg->g; 1264 gp->param = nil; 1265 runtime·ready(gp); 1266 } 1267 1268 runtime·unlock(c); 1269 } 1270 1271 // For reflect 1272 // func chanclose(c chan) 1273 void 1274 reflect·chanclose(Hchan *c) 1275 { 1276 runtime·closechan(c); 1277 } 1278 1279 // For reflect 1280 // func chanlen(c chan) (len int) 1281 void 1282 reflect·chanlen(Hchan *c, intgo len) 1283 { 1284 if(c == nil) 1285 len = 0; 1286 else 1287 len = c->qcount; 1288 FLUSH(&len); 1289 } 1290 1291 // For reflect 1292 // func chancap(c chan) int 1293 void 1294 reflect·chancap(Hchan *c, intgo cap) 1295 { 1296 if(c == nil) 1297 cap = 0; 1298 else 1299 cap = c->dataqsiz; 1300 FLUSH(&cap); 1301 } 1302 1303 static SudoG* 1304 dequeue(WaitQ *q) 1305 { 1306 SudoG *sgp; 1307 1308 loop: 1309 sgp = q->first; 1310 if(sgp == nil) 1311 return nil; 1312 q->first = sgp->link; 1313 1314 // if sgp is stale, ignore it 1315 if(sgp->selgen != NOSELGEN && 1316 (sgp->selgen != sgp->g->selgen || 1317 !runtime·cas(&sgp->g->selgen, sgp->selgen, sgp->selgen + 2))) { 1318 //prints("INVALID PSEUDOG POINTER\n"); 1319 goto loop; 1320 } 1321 1322 return sgp; 1323 } 1324 1325 static void 1326 dequeueg(WaitQ *q) 1327 { 1328 SudoG **l, *sgp, *prevsgp; 1329 1330 prevsgp = nil; 1331 for(l=&q->first; (sgp=*l) != nil; l=&sgp->link, prevsgp=sgp) { 1332 if(sgp->g == g) { 1333 *l = sgp->link; 1334 if(q->last == sgp) 1335 q->last = prevsgp; 1336 break; 1337 } 1338 } 1339 } 1340 1341 static void 1342 enqueue(WaitQ *q, SudoG *sgp) 1343 { 1344 sgp->link = nil; 1345 if(q->first == nil) { 1346 q->first = sgp; 1347 q->last = sgp; 1348 return; 1349 } 1350 q->last->link = sgp; 1351 q->last = sgp; 1352 } 1353 1354 static void 1355 racesync(Hchan *c, SudoG *sg) 1356 { 1357 runtime·racerelease(chanbuf(c, 0)); 1358 runtime·raceacquireg(sg->g, chanbuf(c, 0)); 1359 runtime·racereleaseg(sg->g, chanbuf(c, 0)); 1360 runtime·raceacquire(chanbuf(c, 0)); 1361 }