github.com/panjjo/go@v0.0.0-20161104043856-d62b31386338/src/runtime/chan.go (about) 1 // Copyright 2014 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 channels. 8 9 // Invariants: 10 // At least one of c.sendq and c.recvq is empty, 11 // except for the case of an unbuffered channel with a single goroutine 12 // blocked on it for both sending and receiving using a select statement, 13 // in which case the length of c.sendq and c.recvq is limited only by the 14 // size of the select statement. 15 // 16 // For buffered channels, also: 17 // c.qcount > 0 implies that c.recvq is empty. 18 // c.qcount < c.dataqsiz implies that c.sendq is empty. 19 20 import ( 21 "runtime/internal/atomic" 22 "unsafe" 23 ) 24 25 const ( 26 maxAlign = 8 27 hchanSize = unsafe.Sizeof(hchan{}) + uintptr(-int(unsafe.Sizeof(hchan{}))&(maxAlign-1)) 28 debugChan = false 29 ) 30 31 type hchan struct { 32 qcount uint // total data in the queue 33 dataqsiz uint // size of the circular queue 34 buf unsafe.Pointer // points to an array of dataqsiz elements 35 elemsize uint16 36 closed uint32 37 elemtype *_type // element type 38 sendx uint // send index 39 recvx uint // receive index 40 recvq waitq // list of recv waiters 41 sendq waitq // list of send waiters 42 43 // lock protects all fields in hchan, as well as several 44 // fields in sudogs blocked on this channel. 45 // 46 // Do not change another G's status while holding this lock 47 // (in particular, do not ready a G), as this can deadlock 48 // with stack shrinking. 49 lock mutex 50 } 51 52 type waitq struct { 53 first *sudog 54 last *sudog 55 } 56 57 //go:linkname reflect_makechan reflect.makechan 58 func reflect_makechan(t *chantype, size int64) *hchan { 59 return makechan(t, size) 60 } 61 62 func makechan(t *chantype, size int64) *hchan { 63 elem := t.elem 64 65 // compiler checks this but be safe. 66 if elem.size >= 1<<16 { 67 throw("makechan: invalid channel element type") 68 } 69 if hchanSize%maxAlign != 0 || elem.align > maxAlign { 70 throw("makechan: bad alignment") 71 } 72 if size < 0 || int64(uintptr(size)) != size || (elem.size > 0 && uintptr(size) > (_MaxMem-hchanSize)/elem.size) { 73 panic(plainError("makechan: size out of range")) 74 } 75 76 var c *hchan 77 if elem.kind&kindNoPointers != 0 || size == 0 { 78 // Allocate memory in one call. 79 // Hchan does not contain pointers interesting for GC in this case: 80 // buf points into the same allocation, elemtype is persistent. 81 // SudoG's are referenced from their owning thread so they can't be collected. 82 // TODO(dvyukov,rlh): Rethink when collector can move allocated objects. 83 c = (*hchan)(mallocgc(hchanSize+uintptr(size)*elem.size, nil, true)) 84 if size > 0 && elem.size != 0 { 85 c.buf = add(unsafe.Pointer(c), hchanSize) 86 } else { 87 // race detector uses this location for synchronization 88 // Also prevents us from pointing beyond the allocation (see issue 9401). 89 c.buf = unsafe.Pointer(c) 90 } 91 } else { 92 c = new(hchan) 93 c.buf = newarray(elem, int(size)) 94 } 95 c.elemsize = uint16(elem.size) 96 c.elemtype = elem 97 c.dataqsiz = uint(size) 98 99 if debugChan { 100 print("makechan: chan=", c, "; elemsize=", elem.size, "; elemalg=", elem.alg, "; dataqsiz=", size, "\n") 101 } 102 return c 103 } 104 105 // chanbuf(c, i) is pointer to the i'th slot in the buffer. 106 func chanbuf(c *hchan, i uint) unsafe.Pointer { 107 return add(c.buf, uintptr(i)*uintptr(c.elemsize)) 108 } 109 110 // entry point for c <- x from compiled code 111 //go:nosplit 112 func chansend1(t *chantype, c *hchan, elem unsafe.Pointer) { 113 chansend(t, c, elem, true, getcallerpc(unsafe.Pointer(&t))) 114 } 115 116 /* 117 * generic single channel send/recv 118 * If block is not nil, 119 * then the protocol will not 120 * sleep but return if it could 121 * not complete. 122 * 123 * sleep can wake up with g.param == nil 124 * when a channel involved in the sleep has 125 * been closed. it is easiest to loop and re-run 126 * the operation; we'll see that it's now closed. 127 */ 128 func chansend(t *chantype, c *hchan, ep unsafe.Pointer, block bool, callerpc uintptr) bool { 129 if raceenabled { 130 raceReadObjectPC(t.elem, ep, callerpc, funcPC(chansend)) 131 } 132 if msanenabled { 133 msanread(ep, t.elem.size) 134 } 135 136 if c == nil { 137 if !block { 138 return false 139 } 140 gopark(nil, nil, "chan send (nil chan)", traceEvGoStop, 2) 141 throw("unreachable") 142 } 143 144 if debugChan { 145 print("chansend: chan=", c, "\n") 146 } 147 148 if raceenabled { 149 racereadpc(unsafe.Pointer(c), callerpc, funcPC(chansend)) 150 } 151 152 // Fast path: check for failed non-blocking operation without acquiring the lock. 153 // 154 // After observing that the channel is not closed, we observe that the channel is 155 // not ready for sending. Each of these observations is a single word-sized read 156 // (first c.closed and second c.recvq.first or c.qcount depending on kind of channel). 157 // Because a closed channel cannot transition from 'ready for sending' to 158 // 'not ready for sending', even if the channel is closed between the two observations, 159 // they imply a moment between the two when the channel was both not yet closed 160 // and not ready for sending. We behave as if we observed the channel at that moment, 161 // and report that the send cannot proceed. 162 // 163 // It is okay if the reads are reordered here: if we observe that the channel is not 164 // ready for sending and then observe that it is not closed, that implies that the 165 // channel wasn't closed during the first observation. 166 if !block && c.closed == 0 && ((c.dataqsiz == 0 && c.recvq.first == nil) || 167 (c.dataqsiz > 0 && c.qcount == c.dataqsiz)) { 168 return false 169 } 170 171 var t0 int64 172 if blockprofilerate > 0 { 173 t0 = cputicks() 174 } 175 176 lock(&c.lock) 177 178 if c.closed != 0 { 179 unlock(&c.lock) 180 panic(plainError("send on closed channel")) 181 } 182 183 if sg := c.recvq.dequeue(); sg != nil { 184 // Found a waiting receiver. We pass the value we want to send 185 // directly to the receiver, bypassing the channel buffer (if any). 186 send(c, sg, ep, func() { unlock(&c.lock) }) 187 return true 188 } 189 190 if c.qcount < c.dataqsiz { 191 // Space is available in the channel buffer. Enqueue the element to send. 192 qp := chanbuf(c, c.sendx) 193 if raceenabled { 194 raceacquire(qp) 195 racerelease(qp) 196 } 197 typedmemmove(c.elemtype, qp, ep) 198 c.sendx++ 199 if c.sendx == c.dataqsiz { 200 c.sendx = 0 201 } 202 c.qcount++ 203 unlock(&c.lock) 204 return true 205 } 206 207 if !block { 208 unlock(&c.lock) 209 return false 210 } 211 212 // Block on the channel. Some receiver will complete our operation for us. 213 gp := getg() 214 mysg := acquireSudog() 215 mysg.releasetime = 0 216 if t0 != 0 { 217 mysg.releasetime = -1 218 } 219 // No stack splits between assigning elem and enqueuing mysg 220 // on gp.waiting where copystack can find it. 221 mysg.elem = ep 222 mysg.waitlink = nil 223 mysg.g = gp 224 mysg.selectdone = nil 225 mysg.c = c 226 gp.waiting = mysg 227 gp.param = nil 228 c.sendq.enqueue(mysg) 229 goparkunlock(&c.lock, "chan send", traceEvGoBlockSend, 3) 230 231 // someone woke us up. 232 if mysg != gp.waiting { 233 throw("G waiting list is corrupted") 234 } 235 gp.waiting = nil 236 if gp.param == nil { 237 if c.closed == 0 { 238 throw("chansend: spurious wakeup") 239 } 240 panic(plainError("send on closed channel")) 241 } 242 gp.param = nil 243 if mysg.releasetime > 0 { 244 blockevent(mysg.releasetime-t0, 2) 245 } 246 mysg.c = nil 247 releaseSudog(mysg) 248 return true 249 } 250 251 // send processes a send operation on an empty channel c. 252 // The value ep sent by the sender is copied to the receiver sg. 253 // The receiver is then woken up to go on its merry way. 254 // Channel c must be empty and locked. send unlocks c with unlockf. 255 // sg must already be dequeued from c. 256 // ep must be non-nil and point to the heap or the caller's stack. 257 func send(c *hchan, sg *sudog, ep unsafe.Pointer, unlockf func()) { 258 if raceenabled { 259 if c.dataqsiz == 0 { 260 racesync(c, sg) 261 } else { 262 // Pretend we go through the buffer, even though 263 // we copy directly. Note that we need to increment 264 // the head/tail locations only when raceenabled. 265 qp := chanbuf(c, c.recvx) 266 raceacquire(qp) 267 racerelease(qp) 268 raceacquireg(sg.g, qp) 269 racereleaseg(sg.g, qp) 270 c.recvx++ 271 if c.recvx == c.dataqsiz { 272 c.recvx = 0 273 } 274 c.sendx = c.recvx // c.sendx = (c.sendx+1) % c.dataqsiz 275 } 276 } 277 if sg.elem != nil { 278 sendDirect(c.elemtype, sg, ep) 279 sg.elem = nil 280 } 281 gp := sg.g 282 unlockf() 283 gp.param = unsafe.Pointer(sg) 284 if sg.releasetime != 0 { 285 sg.releasetime = cputicks() 286 } 287 goready(gp, 4) 288 } 289 290 // Sends and receives on unbuffered or empty-buffered channels are the 291 // only operations where one running goroutine writes to the stack of 292 // another running goroutine. The GC assumes that stack writes only 293 // happen when the goroutine is running and are only done by that 294 // goroutine. Using a write barrier is sufficient to make up for 295 // violating that assumption, but the write barrier has to work. 296 // typedmemmove will call bulkBarrierPreWrite, but the target bytes 297 // are not in the heap, so that will not help. We arrange to call 298 // memmove and typeBitsBulkBarrier instead. 299 300 func sendDirect(t *_type, sg *sudog, src unsafe.Pointer) { 301 // src is on our stack, dst is a slot on another stack. 302 303 // Once we read sg.elem out of sg, it will no longer 304 // be updated if the destination's stack gets copied (shrunk). 305 // So make sure that no preemption points can happen between read & use. 306 dst := sg.elem 307 typeBitsBulkBarrier(t, uintptr(dst), uintptr(src), t.size) 308 memmove(dst, src, t.size) 309 } 310 311 func recvDirect(t *_type, sg *sudog, dst unsafe.Pointer) { 312 // dst is on our stack or the heap, src is on another stack. 313 // The channel is locked, so src will not move during this 314 // operation. 315 src := sg.elem 316 typeBitsBulkBarrier(t, uintptr(dst), uintptr(src), t.size) 317 memmove(dst, src, t.size) 318 } 319 320 func closechan(c *hchan) { 321 if c == nil { 322 panic(plainError("close of nil channel")) 323 } 324 325 lock(&c.lock) 326 if c.closed != 0 { 327 unlock(&c.lock) 328 panic(plainError("close of closed channel")) 329 } 330 331 if raceenabled { 332 callerpc := getcallerpc(unsafe.Pointer(&c)) 333 racewritepc(unsafe.Pointer(c), callerpc, funcPC(closechan)) 334 racerelease(unsafe.Pointer(c)) 335 } 336 337 c.closed = 1 338 339 var glist *g 340 341 // release all readers 342 for { 343 sg := c.recvq.dequeue() 344 if sg == nil { 345 break 346 } 347 if sg.elem != nil { 348 typedmemclr(c.elemtype, sg.elem) 349 sg.elem = nil 350 } 351 if sg.releasetime != 0 { 352 sg.releasetime = cputicks() 353 } 354 gp := sg.g 355 gp.param = nil 356 if raceenabled { 357 raceacquireg(gp, unsafe.Pointer(c)) 358 } 359 gp.schedlink.set(glist) 360 glist = gp 361 } 362 363 // release all writers (they will panic) 364 for { 365 sg := c.sendq.dequeue() 366 if sg == nil { 367 break 368 } 369 sg.elem = nil 370 if sg.releasetime != 0 { 371 sg.releasetime = cputicks() 372 } 373 gp := sg.g 374 gp.param = nil 375 if raceenabled { 376 raceacquireg(gp, unsafe.Pointer(c)) 377 } 378 gp.schedlink.set(glist) 379 glist = gp 380 } 381 unlock(&c.lock) 382 383 // Ready all Gs now that we've dropped the channel lock. 384 for glist != nil { 385 gp := glist 386 glist = glist.schedlink.ptr() 387 gp.schedlink = 0 388 goready(gp, 3) 389 } 390 } 391 392 // entry points for <- c from compiled code 393 //go:nosplit 394 func chanrecv1(t *chantype, c *hchan, elem unsafe.Pointer) { 395 chanrecv(t, c, elem, true) 396 } 397 398 //go:nosplit 399 func chanrecv2(t *chantype, c *hchan, elem unsafe.Pointer) (received bool) { 400 _, received = chanrecv(t, c, elem, true) 401 return 402 } 403 404 // chanrecv receives on channel c and writes the received data to ep. 405 // ep may be nil, in which case received data is ignored. 406 // If block == false and no elements are available, returns (false, false). 407 // Otherwise, if c is closed, zeros *ep and returns (true, false). 408 // Otherwise, fills in *ep with an element and returns (true, true). 409 // A non-nil ep must point to the heap or the caller's stack. 410 func chanrecv(t *chantype, c *hchan, ep unsafe.Pointer, block bool) (selected, received bool) { 411 // raceenabled: don't need to check ep, as it is always on the stack 412 // or is new memory allocated by reflect. 413 414 if debugChan { 415 print("chanrecv: chan=", c, "\n") 416 } 417 418 if c == nil { 419 if !block { 420 return 421 } 422 gopark(nil, nil, "chan receive (nil chan)", traceEvGoStop, 2) 423 throw("unreachable") 424 } 425 426 // Fast path: check for failed non-blocking operation without acquiring the lock. 427 // 428 // After observing that the channel is not ready for receiving, we observe that the 429 // channel is not closed. Each of these observations is a single word-sized read 430 // (first c.sendq.first or c.qcount, and second c.closed). 431 // Because a channel cannot be reopened, the later observation of the channel 432 // being not closed implies that it was also not closed at the moment of the 433 // first observation. We behave as if we observed the channel at that moment 434 // and report that the receive cannot proceed. 435 // 436 // The order of operations is important here: reversing the operations can lead to 437 // incorrect behavior when racing with a close. 438 if !block && (c.dataqsiz == 0 && c.sendq.first == nil || 439 c.dataqsiz > 0 && atomic.Loaduint(&c.qcount) == 0) && 440 atomic.Load(&c.closed) == 0 { 441 return 442 } 443 444 var t0 int64 445 if blockprofilerate > 0 { 446 t0 = cputicks() 447 } 448 449 lock(&c.lock) 450 451 if c.closed != 0 && c.qcount == 0 { 452 if raceenabled { 453 raceacquire(unsafe.Pointer(c)) 454 } 455 unlock(&c.lock) 456 if ep != nil { 457 typedmemclr(c.elemtype, ep) 458 } 459 return true, false 460 } 461 462 if sg := c.sendq.dequeue(); sg != nil { 463 // Found a waiting sender. If buffer is size 0, receive value 464 // directly from sender. Otherwise, receive from head of queue 465 // and add sender's value to the tail of the queue (both map to 466 // the same buffer slot because the queue is full). 467 recv(c, sg, ep, func() { unlock(&c.lock) }) 468 return true, true 469 } 470 471 if c.qcount > 0 { 472 // Receive directly from queue 473 qp := chanbuf(c, c.recvx) 474 if raceenabled { 475 raceacquire(qp) 476 racerelease(qp) 477 } 478 if ep != nil { 479 typedmemmove(c.elemtype, ep, qp) 480 } 481 typedmemclr(c.elemtype, qp) 482 c.recvx++ 483 if c.recvx == c.dataqsiz { 484 c.recvx = 0 485 } 486 c.qcount-- 487 unlock(&c.lock) 488 return true, true 489 } 490 491 if !block { 492 unlock(&c.lock) 493 return false, false 494 } 495 496 // no sender available: block on this channel. 497 gp := getg() 498 mysg := acquireSudog() 499 mysg.releasetime = 0 500 if t0 != 0 { 501 mysg.releasetime = -1 502 } 503 // No stack splits between assigning elem and enqueuing mysg 504 // on gp.waiting where copystack can find it. 505 mysg.elem = ep 506 mysg.waitlink = nil 507 gp.waiting = mysg 508 mysg.g = gp 509 mysg.selectdone = nil 510 mysg.c = c 511 gp.param = nil 512 c.recvq.enqueue(mysg) 513 goparkunlock(&c.lock, "chan receive", traceEvGoBlockRecv, 3) 514 515 // someone woke us up 516 if mysg != gp.waiting { 517 throw("G waiting list is corrupted") 518 } 519 gp.waiting = nil 520 if mysg.releasetime > 0 { 521 blockevent(mysg.releasetime-t0, 2) 522 } 523 closed := gp.param == nil 524 gp.param = nil 525 mysg.c = nil 526 releaseSudog(mysg) 527 return true, !closed 528 } 529 530 // recv processes a receive operation on a full channel c. 531 // There are 2 parts: 532 // 1) The value sent by the sender sg is put into the channel 533 // and the sender is woken up to go on its merry way. 534 // 2) The value received by the receiver (the current G) is 535 // written to ep. 536 // For synchronous channels, both values are the same. 537 // For asynchronous channels, the receiver gets its data from 538 // the channel buffer and the sender's data is put in the 539 // channel buffer. 540 // Channel c must be full and locked. recv unlocks c with unlockf. 541 // sg must already be dequeued from c. 542 // A non-nil ep must point to the heap or the caller's stack. 543 func recv(c *hchan, sg *sudog, ep unsafe.Pointer, unlockf func()) { 544 if c.dataqsiz == 0 { 545 if raceenabled { 546 racesync(c, sg) 547 } 548 if ep != nil { 549 // copy data from sender 550 recvDirect(c.elemtype, sg, ep) 551 } 552 } else { 553 // Queue is full. Take the item at the 554 // head of the queue. Make the sender enqueue 555 // its item at the tail of the queue. Since the 556 // queue is full, those are both the same slot. 557 qp := chanbuf(c, c.recvx) 558 if raceenabled { 559 raceacquire(qp) 560 racerelease(qp) 561 raceacquireg(sg.g, qp) 562 racereleaseg(sg.g, qp) 563 } 564 // copy data from queue to receiver 565 if ep != nil { 566 typedmemmove(c.elemtype, ep, qp) 567 } 568 // copy data from sender to queue 569 typedmemmove(c.elemtype, qp, sg.elem) 570 c.recvx++ 571 if c.recvx == c.dataqsiz { 572 c.recvx = 0 573 } 574 c.sendx = c.recvx // c.sendx = (c.sendx+1) % c.dataqsiz 575 } 576 sg.elem = nil 577 gp := sg.g 578 unlockf() 579 gp.param = unsafe.Pointer(sg) 580 if sg.releasetime != 0 { 581 sg.releasetime = cputicks() 582 } 583 goready(gp, 4) 584 } 585 586 // compiler implements 587 // 588 // select { 589 // case c <- v: 590 // ... foo 591 // default: 592 // ... bar 593 // } 594 // 595 // as 596 // 597 // if selectnbsend(c, v) { 598 // ... foo 599 // } else { 600 // ... bar 601 // } 602 // 603 func selectnbsend(t *chantype, c *hchan, elem unsafe.Pointer) (selected bool) { 604 return chansend(t, c, elem, false, getcallerpc(unsafe.Pointer(&t))) 605 } 606 607 // compiler implements 608 // 609 // select { 610 // case v = <-c: 611 // ... foo 612 // default: 613 // ... bar 614 // } 615 // 616 // as 617 // 618 // if selectnbrecv(&v, c) { 619 // ... foo 620 // } else { 621 // ... bar 622 // } 623 // 624 func selectnbrecv(t *chantype, elem unsafe.Pointer, c *hchan) (selected bool) { 625 selected, _ = chanrecv(t, c, elem, false) 626 return 627 } 628 629 // compiler implements 630 // 631 // select { 632 // case v, ok = <-c: 633 // ... foo 634 // default: 635 // ... bar 636 // } 637 // 638 // as 639 // 640 // if c != nil && selectnbrecv2(&v, &ok, c) { 641 // ... foo 642 // } else { 643 // ... bar 644 // } 645 // 646 func selectnbrecv2(t *chantype, elem unsafe.Pointer, received *bool, c *hchan) (selected bool) { 647 // TODO(khr): just return 2 values from this function, now that it is in Go. 648 selected, *received = chanrecv(t, c, elem, false) 649 return 650 } 651 652 //go:linkname reflect_chansend reflect.chansend 653 func reflect_chansend(t *chantype, c *hchan, elem unsafe.Pointer, nb bool) (selected bool) { 654 return chansend(t, c, elem, !nb, getcallerpc(unsafe.Pointer(&t))) 655 } 656 657 //go:linkname reflect_chanrecv reflect.chanrecv 658 func reflect_chanrecv(t *chantype, c *hchan, nb bool, elem unsafe.Pointer) (selected bool, received bool) { 659 return chanrecv(t, c, elem, !nb) 660 } 661 662 //go:linkname reflect_chanlen reflect.chanlen 663 func reflect_chanlen(c *hchan) int { 664 if c == nil { 665 return 0 666 } 667 return int(c.qcount) 668 } 669 670 //go:linkname reflect_chancap reflect.chancap 671 func reflect_chancap(c *hchan) int { 672 if c == nil { 673 return 0 674 } 675 return int(c.dataqsiz) 676 } 677 678 //go:linkname reflect_chanclose reflect.chanclose 679 func reflect_chanclose(c *hchan) { 680 closechan(c) 681 } 682 683 func (q *waitq) enqueue(sgp *sudog) { 684 sgp.next = nil 685 x := q.last 686 if x == nil { 687 sgp.prev = nil 688 q.first = sgp 689 q.last = sgp 690 return 691 } 692 sgp.prev = x 693 x.next = sgp 694 q.last = sgp 695 } 696 697 func (q *waitq) dequeue() *sudog { 698 for { 699 sgp := q.first 700 if sgp == nil { 701 return nil 702 } 703 y := sgp.next 704 if y == nil { 705 q.first = nil 706 q.last = nil 707 } else { 708 y.prev = nil 709 q.first = y 710 sgp.next = nil // mark as removed (see dequeueSudog) 711 } 712 713 // if sgp participates in a select and is already signaled, ignore it 714 if sgp.selectdone != nil { 715 // claim the right to signal 716 if *sgp.selectdone != 0 || !atomic.Cas(sgp.selectdone, 0, 1) { 717 continue 718 } 719 } 720 721 return sgp 722 } 723 } 724 725 func racesync(c *hchan, sg *sudog) { 726 racerelease(chanbuf(c, 0)) 727 raceacquireg(sg.g, chanbuf(c, 0)) 728 racereleaseg(sg.g, chanbuf(c, 0)) 729 raceacquire(chanbuf(c, 0)) 730 }