Source file
src/runtime/chan.go
1
2
3
4
5 package runtime
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20 import (
21 "internal/abi"
22 "internal/runtime/atomic"
23 "internal/runtime/math"
24 "internal/runtime/sys"
25 "unsafe"
26 )
27
28 const (
29 maxAlign = 8
30 hchanSize = unsafe.Sizeof(hchan{}) + uintptr(-int(unsafe.Sizeof(hchan{}))&(maxAlign-1))
31 debugChan = false
32 )
33
34 type hchan struct {
35 qcount uint
36 dataqsiz uint
37 buf unsafe.Pointer
38 elemsize uint16
39 closed uint32
40 timer *timer
41 elemtype *_type
42 sendx uint
43 recvx uint
44 recvq waitq
45 sendq waitq
46 bubble *synctestBubble
47
48
49
50
51
52
53
54 lock mutex
55 }
56
57 type waitq struct {
58 first *sudog
59 last *sudog
60 }
61
62
63 func reflect_makechan(t *chantype, size int) *hchan {
64 return makechan(t, size)
65 }
66
67 func makechan64(t *chantype, size int64) *hchan {
68 if int64(int(size)) != size {
69 panic(plainError("makechan: size out of range"))
70 }
71
72 return makechan(t, int(size))
73 }
74
75 func makechan(t *chantype, size int) *hchan {
76 elem := t.Elem
77
78
79 if elem.Size_ >= 1<<16 {
80 throw("makechan: invalid channel element type")
81 }
82 if hchanSize%maxAlign != 0 || elem.Align_ > maxAlign {
83 throw("makechan: bad alignment")
84 }
85
86 mem, overflow := math.MulUintptr(elem.Size_, uintptr(size))
87 if overflow || mem > maxAlloc-hchanSize || size < 0 {
88 panic(plainError("makechan: size out of range"))
89 }
90
91
92
93
94
95 var c *hchan
96 switch {
97 case mem == 0:
98
99 c = (*hchan)(mallocgc(hchanSize, nil, true))
100
101 c.buf = c.raceaddr()
102 case !elem.Pointers():
103
104
105 c = (*hchan)(mallocgc(hchanSize+mem, nil, true))
106 c.buf = add(unsafe.Pointer(c), hchanSize)
107 default:
108
109 c = new(hchan)
110 c.buf = mallocgc(mem, elem, true)
111 }
112
113 c.elemsize = uint16(elem.Size_)
114 c.elemtype = elem
115 c.dataqsiz = uint(size)
116 if b := getg().bubble; b != nil {
117 c.bubble = b
118 }
119 lockInit(&c.lock, lockRankHchan)
120
121 if debugChan {
122 print("makechan: chan=", c, "; elemsize=", elem.Size_, "; dataqsiz=", size, "\n")
123 }
124 return c
125 }
126
127
128
129
130
131
132
133
134
135
136
137
138 func chanbuf(c *hchan, i uint) unsafe.Pointer {
139 return add(c.buf, uintptr(i)*uintptr(c.elemsize))
140 }
141
142
143
144
145
146 func full(c *hchan) bool {
147
148
149 if c.dataqsiz == 0 {
150
151 return c.recvq.first == nil
152 }
153
154 return c.qcount == c.dataqsiz
155 }
156
157
158
159
160 func chansend1(c *hchan, elem unsafe.Pointer) {
161 chansend(c, elem, true, sys.GetCallerPC())
162 }
163
164
165
166
167
168 func chansend(c *hchan, ep unsafe.Pointer, block bool, callerpc uintptr) bool {
169 if c == nil {
170 if !block {
171 return false
172 }
173 gopark(nil, nil, waitReasonChanSendNilChan, traceBlockForever, 2)
174 throw("unreachable")
175 }
176
177 if debugChan {
178 print("chansend: chan=", c, "\n")
179 }
180
181 if raceenabled {
182 racereadpc(c.raceaddr(), callerpc, abi.FuncPCABIInternal(chansend))
183 }
184
185 if c.bubble != nil && getg().bubble != c.bubble {
186 fatal("send on synctest channel from outside bubble")
187 }
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205 if !block && c.closed == 0 && full(c) {
206 return false
207 }
208
209 var t0 int64
210 if blockprofilerate > 0 {
211 t0 = cputicks()
212 }
213
214 lock(&c.lock)
215
216 if c.closed != 0 {
217 unlock(&c.lock)
218 panic(plainError("send on closed channel"))
219 }
220
221 if sg := c.recvq.dequeue(); sg != nil {
222
223
224 send(c, sg, ep, func() { unlock(&c.lock) }, 3)
225 return true
226 }
227
228 if c.qcount < c.dataqsiz {
229
230 qp := chanbuf(c, c.sendx)
231 if raceenabled {
232 racenotify(c, c.sendx, nil)
233 }
234 typedmemmove(c.elemtype, qp, ep)
235 c.sendx++
236 if c.sendx == c.dataqsiz {
237 c.sendx = 0
238 }
239 c.qcount++
240 unlock(&c.lock)
241 return true
242 }
243
244 if !block {
245 unlock(&c.lock)
246 return false
247 }
248
249
250 gp := getg()
251 mysg := acquireSudog()
252 mysg.releasetime = 0
253 if t0 != 0 {
254 mysg.releasetime = -1
255 }
256
257
258 mysg.elem.set(ep)
259 mysg.waitlink = nil
260 mysg.g = gp
261 mysg.isSelect = false
262 mysg.c.set(c)
263 gp.waiting = mysg
264 gp.param = nil
265 c.sendq.enqueue(mysg)
266
267
268
269
270 gp.parkingOnChan.Store(true)
271 reason := waitReasonChanSend
272 if c.bubble != nil {
273 reason = waitReasonSynctestChanSend
274 }
275 gopark(chanparkcommit, unsafe.Pointer(&c.lock), reason, traceBlockChanSend, 2)
276
277
278
279
280 KeepAlive(ep)
281
282
283 if mysg != gp.waiting {
284 throw("G waiting list is corrupted")
285 }
286 gp.waiting = nil
287 gp.activeStackChans = false
288 closed := !mysg.success
289 gp.param = nil
290 if mysg.releasetime > 0 {
291 blockevent(mysg.releasetime-t0, 2)
292 }
293 mysg.c.set(nil)
294 releaseSudog(mysg)
295 if closed {
296 if c.closed == 0 {
297 throw("chansend: spurious wakeup")
298 }
299 panic(plainError("send on closed channel"))
300 }
301 return true
302 }
303
304
305
306
307
308
309
310 func send(c *hchan, sg *sudog, ep unsafe.Pointer, unlockf func(), skip int) {
311 if c.bubble != nil && getg().bubble != c.bubble {
312 unlockf()
313 fatal("send on synctest channel from outside bubble")
314 }
315 if raceenabled {
316 if c.dataqsiz == 0 {
317 racesync(c, sg)
318 } else {
319
320
321
322 racenotify(c, c.recvx, nil)
323 racenotify(c, c.recvx, sg)
324 c.recvx++
325 if c.recvx == c.dataqsiz {
326 c.recvx = 0
327 }
328 c.sendx = c.recvx
329 }
330 }
331 if sg.elem.get() != nil {
332 sendDirect(c.elemtype, sg, ep)
333 sg.elem.set(nil)
334 }
335 gp := sg.g
336 unlockf()
337 gp.param = unsafe.Pointer(sg)
338 sg.success = true
339 if sg.releasetime != 0 {
340 sg.releasetime = cputicks()
341 }
342 goready(gp, skip+1)
343 }
344
345
346
347
348
349
350 func timerchandrain(c *hchan) bool {
351
352
353
354
355
356 if atomic.Loaduint(&c.qcount) == 0 {
357 return false
358 }
359 lock(&c.lock)
360 any := false
361 for c.qcount > 0 {
362 any = true
363 typedmemclr(c.elemtype, chanbuf(c, c.recvx))
364 c.recvx++
365 if c.recvx == c.dataqsiz {
366 c.recvx = 0
367 }
368 c.qcount--
369 }
370 unlock(&c.lock)
371 return any
372 }
373
374
375
376
377
378
379
380
381
382
383
384 func sendDirect(t *_type, sg *sudog, src unsafe.Pointer) {
385
386
387
388
389
390 dst := sg.elem.get()
391 typeBitsBulkBarrier(t, uintptr(dst), uintptr(src), t.Size_)
392
393
394 memmove(dst, src, t.Size_)
395 }
396
397 func recvDirect(t *_type, sg *sudog, dst unsafe.Pointer) {
398
399
400
401 src := sg.elem.get()
402 typeBitsBulkBarrier(t, uintptr(dst), uintptr(src), t.Size_)
403 memmove(dst, src, t.Size_)
404 }
405
406 func closechan(c *hchan) {
407 if c == nil {
408 panic(plainError("close of nil channel"))
409 }
410 if c.bubble != nil && getg().bubble != c.bubble {
411 fatal("close of synctest channel from outside bubble")
412 }
413
414 lock(&c.lock)
415 if c.closed != 0 {
416 unlock(&c.lock)
417 panic(plainError("close of closed channel"))
418 }
419
420 if raceenabled {
421 callerpc := sys.GetCallerPC()
422 racewritepc(c.raceaddr(), callerpc, abi.FuncPCABIInternal(closechan))
423 racerelease(c.raceaddr())
424 }
425
426 c.closed = 1
427
428 var glist gList
429
430
431 for {
432 sg := c.recvq.dequeue()
433 if sg == nil {
434 break
435 }
436 if sg.elem.get() != nil {
437 typedmemclr(c.elemtype, sg.elem.get())
438 sg.elem.set(nil)
439 }
440 if sg.releasetime != 0 {
441 sg.releasetime = cputicks()
442 }
443 gp := sg.g
444 gp.param = unsafe.Pointer(sg)
445 sg.success = false
446 if raceenabled {
447 raceacquireg(gp, c.raceaddr())
448 }
449 glist.push(gp)
450 }
451
452
453 for {
454 sg := c.sendq.dequeue()
455 if sg == nil {
456 break
457 }
458 sg.elem.set(nil)
459 if sg.releasetime != 0 {
460 sg.releasetime = cputicks()
461 }
462 gp := sg.g
463 gp.param = unsafe.Pointer(sg)
464 sg.success = false
465 if raceenabled {
466 raceacquireg(gp, c.raceaddr())
467 }
468 glist.push(gp)
469 }
470 unlock(&c.lock)
471
472
473 for !glist.empty() {
474 gp := glist.pop()
475 gp.schedlink = 0
476 goready(gp, 3)
477 }
478 }
479
480
481
482
483
484 func empty(c *hchan) bool {
485
486 if c.dataqsiz == 0 {
487 return atomic.Loadp(unsafe.Pointer(&c.sendq.first)) == nil
488 }
489
490
491 if c.timer != nil {
492 c.timer.maybeRunChan(c)
493 }
494 return atomic.Loaduint(&c.qcount) == 0
495 }
496
497
498
499
500 func chanrecv1(c *hchan, elem unsafe.Pointer) {
501 chanrecv(c, elem, true)
502 }
503
504
505 func chanrecv2(c *hchan, elem unsafe.Pointer) (received bool) {
506 _, received = chanrecv(c, elem, true)
507 return
508 }
509
510
511
512
513
514
515
516 func chanrecv(c *hchan, ep unsafe.Pointer, block bool) (selected, received bool) {
517
518
519
520 if debugChan {
521 print("chanrecv: chan=", c, "\n")
522 }
523
524 if c == nil {
525 if !block {
526 return
527 }
528 gopark(nil, nil, waitReasonChanReceiveNilChan, traceBlockForever, 2)
529 throw("unreachable")
530 }
531
532 if c.bubble != nil && getg().bubble != c.bubble {
533 fatal("receive on synctest channel from outside bubble")
534 }
535
536 if c.timer != nil {
537 c.timer.maybeRunChan(c)
538 }
539
540
541 if !block && empty(c) {
542
543
544
545
546
547
548
549
550
551 if atomic.Load(&c.closed) == 0 {
552
553
554
555
556 return
557 }
558
559
560
561 if empty(c) {
562
563 if raceenabled {
564 raceacquire(c.raceaddr())
565 }
566 if ep != nil {
567 typedmemclr(c.elemtype, ep)
568 }
569 return true, false
570 }
571 }
572
573 var t0 int64
574 if blockprofilerate > 0 {
575 t0 = cputicks()
576 }
577
578 lock(&c.lock)
579
580 if c.closed != 0 {
581 if c.qcount == 0 {
582 if raceenabled {
583 raceacquire(c.raceaddr())
584 }
585 unlock(&c.lock)
586 if ep != nil {
587 typedmemclr(c.elemtype, ep)
588 }
589 return true, false
590 }
591
592 } else {
593
594 if sg := c.sendq.dequeue(); sg != nil {
595
596
597
598
599 recv(c, sg, ep, func() { unlock(&c.lock) }, 3)
600 return true, true
601 }
602 }
603
604 if c.qcount > 0 {
605
606 qp := chanbuf(c, c.recvx)
607 if raceenabled {
608 racenotify(c, c.recvx, nil)
609 }
610 if ep != nil {
611 typedmemmove(c.elemtype, ep, qp)
612 }
613 typedmemclr(c.elemtype, qp)
614 c.recvx++
615 if c.recvx == c.dataqsiz {
616 c.recvx = 0
617 }
618 c.qcount--
619 unlock(&c.lock)
620 return true, true
621 }
622
623 if !block {
624 unlock(&c.lock)
625 return false, false
626 }
627
628
629 gp := getg()
630 mysg := acquireSudog()
631 mysg.releasetime = 0
632 if t0 != 0 {
633 mysg.releasetime = -1
634 }
635
636
637 mysg.elem.set(ep)
638 mysg.waitlink = nil
639 gp.waiting = mysg
640
641 mysg.g = gp
642 mysg.isSelect = false
643 mysg.c.set(c)
644 gp.param = nil
645 c.recvq.enqueue(mysg)
646 if c.timer != nil {
647 blockTimerChan(c)
648 }
649
650
651
652
653
654 gp.parkingOnChan.Store(true)
655 reason := waitReasonChanReceive
656 if c.bubble != nil {
657 reason = waitReasonSynctestChanReceive
658 }
659 gopark(chanparkcommit, unsafe.Pointer(&c.lock), reason, traceBlockChanRecv, 2)
660
661
662 if mysg != gp.waiting {
663 throw("G waiting list is corrupted")
664 }
665 if c.timer != nil {
666 unblockTimerChan(c)
667 }
668 gp.waiting = nil
669 gp.activeStackChans = false
670 if mysg.releasetime > 0 {
671 blockevent(mysg.releasetime-t0, 2)
672 }
673 success := mysg.success
674 gp.param = nil
675 mysg.c.set(nil)
676 releaseSudog(mysg)
677 return true, success
678 }
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694 func recv(c *hchan, sg *sudog, ep unsafe.Pointer, unlockf func(), skip int) {
695 if c.bubble != nil && getg().bubble != c.bubble {
696 unlockf()
697 fatal("receive on synctest channel from outside bubble")
698 }
699 if c.dataqsiz == 0 {
700 if raceenabled {
701 racesync(c, sg)
702 }
703 if ep != nil {
704
705 recvDirect(c.elemtype, sg, ep)
706 }
707 } else {
708
709
710
711
712 qp := chanbuf(c, c.recvx)
713 if raceenabled {
714 racenotify(c, c.recvx, nil)
715 racenotify(c, c.recvx, sg)
716 }
717
718 if ep != nil {
719 typedmemmove(c.elemtype, ep, qp)
720 }
721
722 typedmemmove(c.elemtype, qp, sg.elem.get())
723 c.recvx++
724 if c.recvx == c.dataqsiz {
725 c.recvx = 0
726 }
727 c.sendx = c.recvx
728 }
729 sg.elem.set(nil)
730 gp := sg.g
731 unlockf()
732 gp.param = unsafe.Pointer(sg)
733 sg.success = true
734 if sg.releasetime != 0 {
735 sg.releasetime = cputicks()
736 }
737 goready(gp, skip+1)
738 }
739
740 func chanparkcommit(gp *g, chanLock unsafe.Pointer) bool {
741
742
743
744
745
746 gp.activeStackChans = true
747
748
749
750 gp.parkingOnChan.Store(false)
751
752
753
754
755
756 unlock((*mutex)(chanLock))
757 return true
758 }
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776 func selectnbsend(c *hchan, elem unsafe.Pointer) (selected bool) {
777 return chansend(c, elem, false, sys.GetCallerPC())
778 }
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796 func selectnbrecv(elem unsafe.Pointer, c *hchan) (selected, received bool) {
797 return chanrecv(c, elem, false)
798 }
799
800
801 func reflect_chansend(c *hchan, elem unsafe.Pointer, nb bool) (selected bool) {
802 return chansend(c, elem, !nb, sys.GetCallerPC())
803 }
804
805
806 func reflect_chanrecv(c *hchan, nb bool, elem unsafe.Pointer) (selected bool, received bool) {
807 return chanrecv(c, elem, !nb)
808 }
809
810 func chanlen(c *hchan) int {
811 if c == nil || c.timer != nil {
812
813
814
815 return 0
816 }
817 return int(c.qcount)
818 }
819
820 func chancap(c *hchan) int {
821 if c == nil || c.timer != nil {
822
823
824
825 return 0
826 }
827 return int(c.dataqsiz)
828 }
829
830
831 func reflect_chanlen(c *hchan) int {
832 return chanlen(c)
833 }
834
835
836 func reflectlite_chanlen(c *hchan) int {
837 return chanlen(c)
838 }
839
840
841 func reflect_chancap(c *hchan) int {
842 return chancap(c)
843 }
844
845
846 func reflect_chanclose(c *hchan) {
847 closechan(c)
848 }
849
850 func (q *waitq) enqueue(sgp *sudog) {
851 sgp.next = nil
852 x := q.last
853 if x == nil {
854 sgp.prev = nil
855 q.first = sgp
856 q.last = sgp
857 return
858 }
859 sgp.prev = x
860 x.next = sgp
861 q.last = sgp
862 }
863
864 func (q *waitq) dequeue() *sudog {
865 for {
866 sgp := q.first
867 if sgp == nil {
868 return nil
869 }
870 y := sgp.next
871 if y == nil {
872 q.first = nil
873 q.last = nil
874 } else {
875 y.prev = nil
876 q.first = y
877 sgp.next = nil
878 }
879
880
881
882
883
884
885
886
887
888 if sgp.isSelect {
889 if !sgp.g.selectDone.CompareAndSwap(0, 1) {
890
891 continue
892 }
893 }
894
895 return sgp
896 }
897 }
898
899 func (c *hchan) raceaddr() unsafe.Pointer {
900
901
902
903
904
905 return unsafe.Pointer(&c.buf)
906 }
907
908 func racesync(c *hchan, sg *sudog) {
909 racerelease(chanbuf(c, 0))
910 raceacquireg(sg.g, chanbuf(c, 0))
911 racereleaseg(sg.g, chanbuf(c, 0))
912 raceacquire(chanbuf(c, 0))
913 }
914
915
916
917
918 func racenotify(c *hchan, idx uint, sg *sudog) {
919
920
921
922
923
924
925
926 qp := chanbuf(c, idx)
927
928
929
930
931
932
933 if c.elemsize == 0 {
934 if sg == nil {
935 raceacquire(qp)
936 racerelease(qp)
937 } else {
938 raceacquireg(sg.g, qp)
939 racereleaseg(sg.g, qp)
940 }
941 } else {
942 if sg == nil {
943 racereleaseacquire(qp)
944 } else {
945 racereleaseacquireg(sg.g, qp)
946 }
947 }
948 }
949
View as plain text