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 package runtime 6 7 // This file contains the implementation of Go select statements. 8 9 import "unsafe" 10 11 const ( 12 debugSelect = false 13 14 // scase.kind 15 caseRecv = iota 16 caseSend 17 caseDefault 18 ) 19 20 // Select statement header. 21 // Known to compiler. 22 // Changes here must also be made in src/cmd/internal/gc/select.go's selecttype. 23 type hselect struct { 24 tcase uint16 // total count of scase[] 25 ncase uint16 // currently filled scase[] 26 pollorder *uint16 // case poll order 27 lockorder **hchan // channel lock order 28 scase [1]scase // one per case (in order of appearance) 29 } 30 31 // Select case descriptor. 32 // Known to compiler. 33 // Changes here must also be made in src/cmd/internal/gc/select.go's selecttype. 34 type scase struct { 35 elem unsafe.Pointer // data element 36 c *hchan // chan 37 pc uintptr // return pc 38 kind uint16 39 so uint16 // vararg of selected bool 40 receivedp *bool // pointer to received bool (recv2) 41 releasetime int64 42 } 43 44 var ( 45 chansendpc = funcPC(chansend) 46 chanrecvpc = funcPC(chanrecv) 47 ) 48 49 func selectsize(size uintptr) uintptr { 50 selsize := unsafe.Sizeof(hselect{}) + 51 (size-1)*unsafe.Sizeof(hselect{}.scase[0]) + 52 size*unsafe.Sizeof(*hselect{}.lockorder) + 53 size*unsafe.Sizeof(*hselect{}.pollorder) 54 return round(selsize, _Int64Align) 55 } 56 57 func newselect(sel *hselect, selsize int64, size int32) { 58 if selsize != int64(selectsize(uintptr(size))) { 59 print("runtime: bad select size ", selsize, ", want ", selectsize(uintptr(size)), "\n") 60 throw("bad select size") 61 } 62 sel.tcase = uint16(size) 63 sel.ncase = 0 64 sel.lockorder = (**hchan)(add(unsafe.Pointer(&sel.scase), uintptr(size)*unsafe.Sizeof(hselect{}.scase[0]))) 65 sel.pollorder = (*uint16)(add(unsafe.Pointer(sel.lockorder), uintptr(size)*unsafe.Sizeof(*hselect{}.lockorder))) 66 67 if debugSelect { 68 print("newselect s=", sel, " size=", size, "\n") 69 } 70 } 71 72 //go:nosplit 73 func selectsend(sel *hselect, c *hchan, elem unsafe.Pointer) (selected bool) { 74 // nil cases do not compete 75 if c != nil { 76 selectsendImpl(sel, c, getcallerpc(unsafe.Pointer(&sel)), elem, uintptr(unsafe.Pointer(&selected))-uintptr(unsafe.Pointer(&sel))) 77 } 78 return 79 } 80 81 // cut in half to give stack a chance to split 82 func selectsendImpl(sel *hselect, c *hchan, pc uintptr, elem unsafe.Pointer, so uintptr) { 83 i := sel.ncase 84 if i >= sel.tcase { 85 throw("selectsend: too many cases") 86 } 87 sel.ncase = i + 1 88 cas := (*scase)(add(unsafe.Pointer(&sel.scase), uintptr(i)*unsafe.Sizeof(sel.scase[0]))) 89 90 cas.pc = pc 91 cas.c = c 92 cas.so = uint16(so) 93 cas.kind = caseSend 94 cas.elem = elem 95 96 if debugSelect { 97 print("selectsend s=", sel, " pc=", hex(cas.pc), " chan=", cas.c, " so=", cas.so, "\n") 98 } 99 } 100 101 //go:nosplit 102 func selectrecv(sel *hselect, c *hchan, elem unsafe.Pointer) (selected bool) { 103 // nil cases do not compete 104 if c != nil { 105 selectrecvImpl(sel, c, getcallerpc(unsafe.Pointer(&sel)), elem, nil, uintptr(unsafe.Pointer(&selected))-uintptr(unsafe.Pointer(&sel))) 106 } 107 return 108 } 109 110 //go:nosplit 111 func selectrecv2(sel *hselect, c *hchan, elem unsafe.Pointer, received *bool) (selected bool) { 112 // nil cases do not compete 113 if c != nil { 114 selectrecvImpl(sel, c, getcallerpc(unsafe.Pointer(&sel)), elem, received, uintptr(unsafe.Pointer(&selected))-uintptr(unsafe.Pointer(&sel))) 115 } 116 return 117 } 118 119 func selectrecvImpl(sel *hselect, c *hchan, pc uintptr, elem unsafe.Pointer, received *bool, so uintptr) { 120 i := sel.ncase 121 if i >= sel.tcase { 122 throw("selectrecv: too many cases") 123 } 124 sel.ncase = i + 1 125 cas := (*scase)(add(unsafe.Pointer(&sel.scase), uintptr(i)*unsafe.Sizeof(sel.scase[0]))) 126 cas.pc = pc 127 cas.c = c 128 cas.so = uint16(so) 129 cas.kind = caseRecv 130 cas.elem = elem 131 cas.receivedp = received 132 133 if debugSelect { 134 print("selectrecv s=", sel, " pc=", hex(cas.pc), " chan=", cas.c, " so=", cas.so, "\n") 135 } 136 } 137 138 //go:nosplit 139 func selectdefault(sel *hselect) (selected bool) { 140 selectdefaultImpl(sel, getcallerpc(unsafe.Pointer(&sel)), uintptr(unsafe.Pointer(&selected))-uintptr(unsafe.Pointer(&sel))) 141 return 142 } 143 144 func selectdefaultImpl(sel *hselect, callerpc uintptr, so uintptr) { 145 i := sel.ncase 146 if i >= sel.tcase { 147 throw("selectdefault: too many cases") 148 } 149 sel.ncase = i + 1 150 cas := (*scase)(add(unsafe.Pointer(&sel.scase), uintptr(i)*unsafe.Sizeof(sel.scase[0]))) 151 cas.pc = callerpc 152 cas.c = nil 153 cas.so = uint16(so) 154 cas.kind = caseDefault 155 156 if debugSelect { 157 print("selectdefault s=", sel, " pc=", hex(cas.pc), " so=", cas.so, "\n") 158 } 159 } 160 161 func sellock(sel *hselect) { 162 lockslice := slice{unsafe.Pointer(sel.lockorder), int(sel.ncase), int(sel.ncase)} 163 lockorder := *(*[]*hchan)(unsafe.Pointer(&lockslice)) 164 var c *hchan 165 for _, c0 := range lockorder { 166 if c0 != nil && c0 != c { 167 c = c0 168 lock(&c.lock) 169 } 170 } 171 } 172 173 func selunlock(sel *hselect) { 174 // We must be very careful here to not touch sel after we have unlocked 175 // the last lock, because sel can be freed right after the last unlock. 176 // Consider the following situation. 177 // First M calls runtimepark() in runtimeselectgo() passing the sel. 178 // Once runtimepark() has unlocked the last lock, another M makes 179 // the G that calls select runnable again and schedules it for execution. 180 // When the G runs on another M, it locks all the locks and frees sel. 181 // Now if the first M touches sel, it will access freed memory. 182 n := int(sel.ncase) 183 r := 0 184 lockslice := slice{unsafe.Pointer(sel.lockorder), n, n} 185 lockorder := *(*[]*hchan)(unsafe.Pointer(&lockslice)) 186 // skip the default case 187 if n > 0 && lockorder[0] == nil { 188 r = 1 189 } 190 for i := n - 1; i >= r; i-- { 191 c := lockorder[i] 192 if i > 0 && c == lockorder[i-1] { 193 continue // will unlock it on the next iteration 194 } 195 unlock(&c.lock) 196 } 197 } 198 199 func selparkcommit(gp *g, sel unsafe.Pointer) bool { 200 selunlock((*hselect)(sel)) 201 return true 202 } 203 204 func block() { 205 gopark(nil, nil, "select (no cases)", traceEvGoStop, 1) // forever 206 } 207 208 // overwrites return pc on stack to signal which case of the select 209 // to run, so cannot appear at the top of a split stack. 210 //go:nosplit 211 func selectgo(sel *hselect) { 212 pc, offset := selectgoImpl(sel) 213 *(*bool)(add(unsafe.Pointer(&sel), uintptr(offset))) = true 214 setcallerpc(unsafe.Pointer(&sel), pc) 215 } 216 217 // selectgoImpl returns scase.pc and scase.so for the select 218 // case which fired. 219 func selectgoImpl(sel *hselect) (uintptr, uint16) { 220 if debugSelect { 221 print("select: sel=", sel, "\n") 222 } 223 224 scaseslice := slice{unsafe.Pointer(&sel.scase), int(sel.ncase), int(sel.ncase)} 225 scases := *(*[]scase)(unsafe.Pointer(&scaseslice)) 226 227 var t0 int64 228 if blockprofilerate > 0 { 229 t0 = cputicks() 230 for i := 0; i < int(sel.ncase); i++ { 231 scases[i].releasetime = -1 232 } 233 } 234 235 // The compiler rewrites selects that statically have 236 // only 0 or 1 cases plus default into simpler constructs. 237 // The only way we can end up with such small sel.ncase 238 // values here is for a larger select in which most channels 239 // have been nilled out. The general code handles those 240 // cases correctly, and they are rare enough not to bother 241 // optimizing (and needing to test). 242 243 // generate permuted order 244 pollslice := slice{unsafe.Pointer(sel.pollorder), int(sel.ncase), int(sel.ncase)} 245 pollorder := *(*[]uint16)(unsafe.Pointer(&pollslice)) 246 for i := 1; i < int(sel.ncase); i++ { 247 j := int(fastrand1()) % (i + 1) 248 pollorder[i] = pollorder[j] 249 pollorder[j] = uint16(i) 250 } 251 252 // sort the cases by Hchan address to get the locking order. 253 // simple heap sort, to guarantee n log n time and constant stack footprint. 254 lockslice := slice{unsafe.Pointer(sel.lockorder), int(sel.ncase), int(sel.ncase)} 255 lockorder := *(*[]*hchan)(unsafe.Pointer(&lockslice)) 256 for i := 0; i < int(sel.ncase); i++ { 257 j := i 258 c := scases[j].c 259 for j > 0 && lockorder[(j-1)/2].sortkey() < c.sortkey() { 260 k := (j - 1) / 2 261 lockorder[j] = lockorder[k] 262 j = k 263 } 264 lockorder[j] = c 265 } 266 for i := int(sel.ncase) - 1; i >= 0; i-- { 267 c := lockorder[i] 268 lockorder[i] = lockorder[0] 269 j := 0 270 for { 271 k := j*2 + 1 272 if k >= i { 273 break 274 } 275 if k+1 < i && lockorder[k].sortkey() < lockorder[k+1].sortkey() { 276 k++ 277 } 278 if c.sortkey() < lockorder[k].sortkey() { 279 lockorder[j] = lockorder[k] 280 j = k 281 continue 282 } 283 break 284 } 285 lockorder[j] = c 286 } 287 /* 288 for i := 0; i+1 < int(sel.ncase); i++ { 289 if lockorder[i].sortkey() > lockorder[i+1].sortkey() { 290 print("i=", i, " x=", lockorder[i], " y=", lockorder[i+1], "\n") 291 throw("select: broken sort") 292 } 293 } 294 */ 295 296 // lock all the channels involved in the select 297 sellock(sel) 298 299 var ( 300 gp *g 301 done uint32 302 sg *sudog 303 c *hchan 304 k *scase 305 sglist *sudog 306 sgnext *sudog 307 futile byte 308 ) 309 310 loop: 311 // pass 1 - look for something already waiting 312 var dfl *scase 313 var cas *scase 314 for i := 0; i < int(sel.ncase); i++ { 315 cas = &scases[pollorder[i]] 316 c = cas.c 317 318 switch cas.kind { 319 case caseRecv: 320 if c.dataqsiz > 0 { 321 if c.qcount > 0 { 322 goto asyncrecv 323 } 324 } else { 325 sg = c.sendq.dequeue() 326 if sg != nil { 327 goto syncrecv 328 } 329 } 330 if c.closed != 0 { 331 goto rclose 332 } 333 334 case caseSend: 335 if raceenabled { 336 racereadpc(unsafe.Pointer(c), cas.pc, chansendpc) 337 } 338 if c.closed != 0 { 339 goto sclose 340 } 341 if c.dataqsiz > 0 { 342 if c.qcount < c.dataqsiz { 343 goto asyncsend 344 } 345 } else { 346 sg = c.recvq.dequeue() 347 if sg != nil { 348 goto syncsend 349 } 350 } 351 352 case caseDefault: 353 dfl = cas 354 } 355 } 356 357 if dfl != nil { 358 selunlock(sel) 359 cas = dfl 360 goto retc 361 } 362 363 // pass 2 - enqueue on all chans 364 gp = getg() 365 done = 0 366 for i := 0; i < int(sel.ncase); i++ { 367 cas = &scases[pollorder[i]] 368 c = cas.c 369 sg := acquireSudog() 370 sg.g = gp 371 // Note: selectdone is adjusted for stack copies in stack1.go:adjustsudogs 372 sg.selectdone = (*uint32)(noescape(unsafe.Pointer(&done))) 373 sg.elem = cas.elem 374 sg.releasetime = 0 375 if t0 != 0 { 376 sg.releasetime = -1 377 } 378 sg.waitlink = gp.waiting 379 gp.waiting = sg 380 381 switch cas.kind { 382 case caseRecv: 383 c.recvq.enqueue(sg) 384 385 case caseSend: 386 c.sendq.enqueue(sg) 387 } 388 } 389 390 // wait for someone to wake us up 391 gp.param = nil 392 gopark(selparkcommit, unsafe.Pointer(sel), "select", traceEvGoBlockSelect|futile, 2) 393 394 // someone woke us up 395 sellock(sel) 396 sg = (*sudog)(gp.param) 397 gp.param = nil 398 399 // pass 3 - dequeue from unsuccessful chans 400 // otherwise they stack up on quiet channels 401 // record the successful case, if any. 402 // We singly-linked up the SudoGs in case order, so when 403 // iterating through the linked list they are in reverse order. 404 cas = nil 405 sglist = gp.waiting 406 // Clear all elem before unlinking from gp.waiting. 407 for sg1 := gp.waiting; sg1 != nil; sg1 = sg1.waitlink { 408 sg1.selectdone = nil 409 sg1.elem = nil 410 } 411 gp.waiting = nil 412 for i := int(sel.ncase) - 1; i >= 0; i-- { 413 k = &scases[pollorder[i]] 414 if sglist.releasetime > 0 { 415 k.releasetime = sglist.releasetime 416 } 417 if sg == sglist { 418 // sg has already been dequeued by the G that woke us up. 419 cas = k 420 } else { 421 c = k.c 422 if k.kind == caseSend { 423 c.sendq.dequeueSudoG(sglist) 424 } else { 425 c.recvq.dequeueSudoG(sglist) 426 } 427 } 428 sgnext = sglist.waitlink 429 sglist.waitlink = nil 430 releaseSudog(sglist) 431 sglist = sgnext 432 } 433 434 if cas == nil { 435 futile = traceFutileWakeup 436 goto loop 437 } 438 439 c = cas.c 440 441 if c.dataqsiz > 0 { 442 throw("selectgo: shouldn't happen") 443 } 444 445 if debugSelect { 446 print("wait-return: sel=", sel, " c=", c, " cas=", cas, " kind=", cas.kind, "\n") 447 } 448 449 if cas.kind == caseRecv { 450 if cas.receivedp != nil { 451 *cas.receivedp = true 452 } 453 } 454 455 if raceenabled { 456 if cas.kind == caseRecv && cas.elem != nil { 457 raceWriteObjectPC(c.elemtype, cas.elem, cas.pc, chanrecvpc) 458 } else if cas.kind == caseSend { 459 raceReadObjectPC(c.elemtype, cas.elem, cas.pc, chansendpc) 460 } 461 } 462 463 selunlock(sel) 464 goto retc 465 466 asyncrecv: 467 // can receive from buffer 468 if raceenabled { 469 if cas.elem != nil { 470 raceWriteObjectPC(c.elemtype, cas.elem, cas.pc, chanrecvpc) 471 } 472 raceacquire(chanbuf(c, c.recvx)) 473 racerelease(chanbuf(c, c.recvx)) 474 } 475 if cas.receivedp != nil { 476 *cas.receivedp = true 477 } 478 if cas.elem != nil { 479 typedmemmove(c.elemtype, cas.elem, chanbuf(c, c.recvx)) 480 } 481 memclr(chanbuf(c, c.recvx), uintptr(c.elemsize)) 482 c.recvx++ 483 if c.recvx == c.dataqsiz { 484 c.recvx = 0 485 } 486 c.qcount-- 487 sg = c.sendq.dequeue() 488 if sg != nil { 489 gp = sg.g 490 selunlock(sel) 491 if sg.releasetime != 0 { 492 sg.releasetime = cputicks() 493 } 494 goready(gp, 3) 495 } else { 496 selunlock(sel) 497 } 498 goto retc 499 500 asyncsend: 501 // can send to buffer 502 if raceenabled { 503 raceacquire(chanbuf(c, c.sendx)) 504 racerelease(chanbuf(c, c.sendx)) 505 raceReadObjectPC(c.elemtype, cas.elem, cas.pc, chansendpc) 506 } 507 typedmemmove(c.elemtype, chanbuf(c, c.sendx), cas.elem) 508 c.sendx++ 509 if c.sendx == c.dataqsiz { 510 c.sendx = 0 511 } 512 c.qcount++ 513 sg = c.recvq.dequeue() 514 if sg != nil { 515 gp = sg.g 516 selunlock(sel) 517 if sg.releasetime != 0 { 518 sg.releasetime = cputicks() 519 } 520 goready(gp, 3) 521 } else { 522 selunlock(sel) 523 } 524 goto retc 525 526 syncrecv: 527 // can receive from sleeping sender (sg) 528 if raceenabled { 529 if cas.elem != nil { 530 raceWriteObjectPC(c.elemtype, cas.elem, cas.pc, chanrecvpc) 531 } 532 racesync(c, sg) 533 } 534 selunlock(sel) 535 if debugSelect { 536 print("syncrecv: sel=", sel, " c=", c, "\n") 537 } 538 if cas.receivedp != nil { 539 *cas.receivedp = true 540 } 541 if cas.elem != nil { 542 typedmemmove(c.elemtype, cas.elem, sg.elem) 543 } 544 sg.elem = nil 545 gp = sg.g 546 gp.param = unsafe.Pointer(sg) 547 if sg.releasetime != 0 { 548 sg.releasetime = cputicks() 549 } 550 goready(gp, 3) 551 goto retc 552 553 rclose: 554 // read at end of closed channel 555 selunlock(sel) 556 if cas.receivedp != nil { 557 *cas.receivedp = false 558 } 559 if cas.elem != nil { 560 memclr(cas.elem, uintptr(c.elemsize)) 561 } 562 if raceenabled { 563 raceacquire(unsafe.Pointer(c)) 564 } 565 goto retc 566 567 syncsend: 568 // can send to sleeping receiver (sg) 569 if raceenabled { 570 raceReadObjectPC(c.elemtype, cas.elem, cas.pc, chansendpc) 571 racesync(c, sg) 572 } 573 selunlock(sel) 574 if debugSelect { 575 print("syncsend: sel=", sel, " c=", c, "\n") 576 } 577 if sg.elem != nil { 578 syncsend(c, sg, cas.elem) 579 } 580 sg.elem = nil 581 gp = sg.g 582 gp.param = unsafe.Pointer(sg) 583 if sg.releasetime != 0 { 584 sg.releasetime = cputicks() 585 } 586 goready(gp, 3) 587 588 retc: 589 if cas.releasetime > 0 { 590 blockevent(cas.releasetime-t0, 2) 591 } 592 return cas.pc, cas.so 593 594 sclose: 595 // send on closed channel 596 selunlock(sel) 597 panic("send on closed channel") 598 } 599 600 func (c *hchan) sortkey() uintptr { 601 // TODO(khr): if we have a moving garbage collector, we'll need to 602 // change this function. 603 return uintptr(unsafe.Pointer(c)) 604 } 605 606 // A runtimeSelect is a single case passed to rselect. 607 // This must match ../reflect/value.go:/runtimeSelect 608 type runtimeSelect struct { 609 dir selectDir 610 typ unsafe.Pointer // channel type (not used here) 611 ch *hchan // channel 612 val unsafe.Pointer // ptr to data (SendDir) or ptr to receive buffer (RecvDir) 613 } 614 615 // These values must match ../reflect/value.go:/SelectDir. 616 type selectDir int 617 618 const ( 619 _ selectDir = iota 620 selectSend // case Chan <- Send 621 selectRecv // case <-Chan: 622 selectDefault // default 623 ) 624 625 //go:linkname reflect_rselect reflect.rselect 626 func reflect_rselect(cases []runtimeSelect) (chosen int, recvOK bool) { 627 // flagNoScan is safe here, because all objects are also referenced from cases. 628 size := selectsize(uintptr(len(cases))) 629 sel := (*hselect)(mallocgc(size, nil, flagNoScan)) 630 newselect(sel, int64(size), int32(len(cases))) 631 r := new(bool) 632 for i := range cases { 633 rc := &cases[i] 634 switch rc.dir { 635 case selectDefault: 636 selectdefaultImpl(sel, uintptr(i), 0) 637 case selectSend: 638 if rc.ch == nil { 639 break 640 } 641 selectsendImpl(sel, rc.ch, uintptr(i), rc.val, 0) 642 case selectRecv: 643 if rc.ch == nil { 644 break 645 } 646 selectrecvImpl(sel, rc.ch, uintptr(i), rc.val, r, 0) 647 } 648 } 649 650 pc, _ := selectgoImpl(sel) 651 chosen = int(pc) 652 recvOK = *r 653 return 654 } 655 656 func (q *waitq) dequeueSudoG(sgp *sudog) { 657 x := sgp.prev 658 y := sgp.next 659 if x != nil { 660 if y != nil { 661 // middle of queue 662 x.next = y 663 y.prev = x 664 sgp.next = nil 665 sgp.prev = nil 666 return 667 } 668 // end of queue 669 x.next = nil 670 q.last = x 671 sgp.prev = nil 672 return 673 } 674 if y != nil { 675 // start of queue 676 y.prev = nil 677 q.first = y 678 sgp.next = nil 679 return 680 } 681 682 // x==y==nil. Either sgp is the only element in the queue, 683 // or it has already been removed. Use q.first to disambiguate. 684 if q.first == sgp { 685 q.first = nil 686 q.last = nil 687 } 688 } 689