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