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.
11 typedef struct WaitQ WaitQ
;
12 typedef struct SudoG SudoG
;
13 typedef struct Select Select
;
14 typedef struct Scase Scase
;
16 typedef struct __go_type_descriptor Type
;
17 typedef struct __go_channel_type ChanType
;
25 byte
* elem
; // data element
34 // The garbage collector is assuming that Hchan can only contain pointers into the stack
35 // and cannot contain pointers into the heap.
38 uintgo qcount
; // total data in the q
39 uintgo dataqsiz
; // size of the circular q
42 uint8 pad
; // ensures proper alignment of the buffer that follows Hchan in memory
44 const Type
* elemtype
; // element type
45 uintgo sendx
; // send index
46 uintgo recvx
; // receive index
47 WaitQ recvq
; // list of recv waiters
48 WaitQ sendq
; // list of send waiters
52 uint32 runtime_Hchansize
= sizeof(Hchan
);
54 // Buffer follows Hchan immediately in memory.
55 // chanbuf(c, i) is pointer to the i'th slot in the buffer.
56 #define chanbuf(c, i) ((byte*)((c)+1)+(uintptr)(c)->elemsize*(i))
70 SudoG sg
; // must be first member (cast to Scase)
73 uint16 index
; // index to return
74 bool* receivedp
; // pointer to received bool (recv2)
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)
86 static void dequeueg(WaitQ
*);
87 static SudoG
* dequeue(WaitQ
*);
88 static void enqueue(WaitQ
*, SudoG
*);
89 static void racesync(Hchan
*, SudoG
*);
92 makechan(ChanType
*t
, int64 hint
)
98 elem
= t
->__element_type
;
100 // compiler checks this but be safe.
101 if(elem
->__size
>= (1<<16))
102 runtime_throw("makechan: invalid channel element type");
104 if(hint
< 0 || (intgo
)hint
!= hint
|| (elem
->__size
> 0 && (uintptr
)hint
> (MaxMem
- sizeof(*c
)) / elem
->__size
))
105 runtime_panicstring("makechan: size out of range");
108 n
= ROUND(n
, elem
->__align
);
110 // allocate memory in one call
111 c
= (Hchan
*)runtime_mallocgc(sizeof(*c
) + hint
*elem
->__size
, (uintptr
)t
| TypeInfo_Chan
, 0);
112 c
->elemsize
= elem
->__size
;
117 runtime_printf("makechan: chan=%p; elemsize=%D; dataqsiz=%D\n",
118 c
, (int64
)elem
->__size
, (int64
)c
->dataqsiz
);
124 // func makechan(typ *ChanType, size uint64) (chan)
125 Hchan
*reflect_makechan(ChanType
*, uint64
)
126 __asm__ (GOSYM_PREFIX
"reflect.makechan");
129 reflect_makechan(ChanType
*t
, uint64 size
)
133 c
= makechan(t
, size
);
137 // makechan(t *ChanType, hint int64) (hchan *chan any);
139 __go_new_channel(ChanType
*t
, uintptr hint
)
141 return makechan(t
, hint
);
145 __go_new_channel_big(ChanType
*t
, uint64 hint
)
147 return makechan(t
, hint
);
151 * generic single channel send/recv
152 * if the bool pointer is nil,
153 * then the full exchange will
154 * occur. if pres is not nil,
155 * then the protocol will not
156 * sleep but return if it could
159 * sleep can wake up with g->param == nil
160 * when a channel involved in the sleep has
161 * been closed. it is easiest to loop and re-run
162 * the operation; we'll see that it's now closed.
165 chansend(ChanType
*t
, Hchan
*c
, byte
*ep
, bool block
, void *pc
)
176 runtime_racereadobjectpc(ep
, t
->__element_type
, runtime_getcallerpc(&t
), chansend
);
182 runtime_park(nil
, nil
, "chan send (nil chan)");
183 return false; // not reached
186 if(runtime_gcwaiting())
190 runtime_printf("chansend: chan=%p\n", c
);
194 mysg
.releasetime
= 0;
195 if(runtime_blockprofilerate
> 0) {
196 t0
= runtime_cputicks();
197 mysg
.releasetime
= -1;
202 runtime_racereadpc(c
, pc
, chansend
);
209 sg
= dequeue(&c
->recvq
);
218 runtime_memmove(sg
->elem
, ep
, c
->elemsize
);
220 sg
->releasetime
= runtime_cputicks();
232 mysg
.selectdone
= nil
;
234 enqueue(&c
->sendq
, &mysg
);
235 runtime_parkunlock(c
, "chan send");
237 if(g
->param
== nil
) {
240 runtime_throw("chansend: spurious wakeup");
244 if(mysg
.releasetime
> 0)
245 runtime_blockevent(mysg
.releasetime
- t0
, 2);
253 if(c
->qcount
>= c
->dataqsiz
) {
260 mysg
.selectdone
= nil
;
261 enqueue(&c
->sendq
, &mysg
);
262 runtime_parkunlock(c
, "chan send");
269 runtime_racerelease(chanbuf(c
, c
->sendx
));
271 runtime_memmove(chanbuf(c
, c
->sendx
), ep
, c
->elemsize
);
272 if(++c
->sendx
== c
->dataqsiz
)
276 sg
= dequeue(&c
->recvq
);
281 sg
->releasetime
= runtime_cputicks();
285 if(mysg
.releasetime
> 0)
286 runtime_blockevent(mysg
.releasetime
- t0
, 2);
291 runtime_panicstring("send on closed channel");
292 return false; // not reached
297 chanrecv(ChanType
*t
, Hchan
* c
, byte
*ep
, bool block
, bool *received
)
305 if(runtime_gcwaiting())
308 // raceenabled: don't need to check ep, as it is always on the stack.
311 runtime_printf("chanrecv: chan=%p\n", c
);
319 runtime_park(nil
, nil
, "chan receive (nil chan)");
320 return false; // not reached
324 mysg
.releasetime
= 0;
325 if(runtime_blockprofilerate
> 0) {
326 t0
= runtime_cputicks();
327 mysg
.releasetime
= -1;
337 sg
= dequeue(&c
->sendq
);
344 runtime_memmove(ep
, sg
->elem
, c
->elemsize
);
348 sg
->releasetime
= runtime_cputicks();
363 mysg
.selectdone
= nil
;
365 enqueue(&c
->recvq
, &mysg
);
366 runtime_parkunlock(c
, "chan receive");
368 if(g
->param
== nil
) {
371 runtime_throw("chanrecv: spurious wakeup");
377 if(mysg
.releasetime
> 0)
378 runtime_blockevent(mysg
.releasetime
- t0
, 2);
394 mysg
.selectdone
= nil
;
395 enqueue(&c
->recvq
, &mysg
);
396 runtime_parkunlock(c
, "chan receive");
403 runtime_raceacquire(chanbuf(c
, c
->recvx
));
406 runtime_memmove(ep
, chanbuf(c
, c
->recvx
), c
->elemsize
);
407 runtime_memclr(chanbuf(c
, c
->recvx
), c
->elemsize
);
408 if(++c
->recvx
== c
->dataqsiz
)
412 sg
= dequeue(&c
->sendq
);
417 sg
->releasetime
= runtime_cputicks();
424 if(mysg
.releasetime
> 0)
425 runtime_blockevent(mysg
.releasetime
- t0
, 2);
430 runtime_memclr(ep
, c
->elemsize
);
434 runtime_raceacquire(c
);
436 if(mysg
.releasetime
> 0)
437 runtime_blockevent(mysg
.releasetime
- t0
, 2);
441 // The compiler generates a call to __go_send_small to send a value 8
444 __go_send_small(ChanType
*t
, Hchan
* c
, uint64 val
)
448 byte b
[sizeof(uint64
)];
454 #ifndef WORDS_BIGENDIAN
457 v
= u
.b
+ sizeof(uint64
) - t
->__element_type
->__size
;
459 chansend(t
, c
, v
, true, runtime_getcallerpc(&t
));
462 // The compiler generates a call to __go_send_big to send a value
463 // larger than 8 bytes or smaller.
465 __go_send_big(ChanType
*t
, Hchan
* c
, byte
* v
)
467 chansend(t
, c
, v
, true, runtime_getcallerpc(&t
));
470 // The compiler generates a call to __go_receive to receive a
471 // value from a channel.
473 __go_receive(ChanType
*t
, Hchan
* c
, byte
* v
)
475 chanrecv(t
, c
, v
, true, nil
);
478 _Bool
runtime_chanrecv2(ChanType
*t
, Hchan
* c
, byte
* v
)
479 __asm__ (GOSYM_PREFIX
"runtime.chanrecv2");
482 runtime_chanrecv2(ChanType
*t
, Hchan
* c
, byte
* v
)
484 bool received
= false;
486 chanrecv(t
, c
, v
, true, &received
);
490 // func selectnbsend(c chan any, elem *any) bool
492 // compiler implements
503 // if selectnbsend(c, v) {
510 runtime_selectnbsend(ChanType
*t
, Hchan
*c
, byte
*val
)
514 res
= chansend(t
, c
, val
, false, runtime_getcallerpc(&t
));
518 // func selectnbrecv(elem *any, c chan any) bool
520 // compiler implements
531 // if selectnbrecv(&v, c) {
538 runtime_selectnbrecv(ChanType
*t
, byte
*v
, Hchan
*c
)
542 selected
= chanrecv(t
, c
, v
, false, nil
);
543 return (_Bool
)selected
;
546 // func selectnbrecv2(elem *any, ok *bool, c chan any) bool
548 // compiler implements
559 // if c != nil && selectnbrecv2(&v, &ok, c) {
566 runtime_selectnbrecv2(ChanType
*t
, byte
*v
, _Bool
*received
, Hchan
*c
)
572 selected
= chanrecv(t
, c
, v
, false, received
== nil
? nil
: &r
);
579 // func chansend(c chan, val *any, nb bool) (selected bool)
580 // where val points to the data to be sent.
582 // The "uintptr selected" is really "bool selected" but saying
583 // uintptr gets us the right alignment for the output parameter block.
585 _Bool
reflect_chansend(ChanType
*, Hchan
*, byte
*, _Bool
)
586 __asm__ (GOSYM_PREFIX
"reflect.chansend");
589 reflect_chansend(ChanType
*t
, Hchan
*c
, byte
*val
, _Bool nb
)
593 selected
= chansend(t
, c
, val
, !nb
, runtime_getcallerpc(&t
));
594 return (_Bool
)selected
;
598 // func chanrecv(c chan, nb bool, val *any) (selected, received bool)
599 // where val points to a data area that will be filled in with the
600 // received value. val must have the size and type of the channel element type.
608 struct chanrecv_ret
reflect_chanrecv(ChanType
*, Hchan
*, _Bool
, byte
*val
)
609 __asm__ (GOSYM_PREFIX
"reflect.chanrecv");
612 reflect_chanrecv(ChanType
*t
, Hchan
*c
, _Bool nb
, byte
*val
)
614 struct chanrecv_ret ret
;
619 selected
= chanrecv(t
, c
, val
, !nb
, &received
);
620 ret
.selected
= (_Bool
)selected
;
621 ret
.received
= (_Bool
)received
;
625 static Select
* newselect(int32
);
627 // newselect(size uint32) (sel *byte);
629 void* runtime_newselect(int32
) __asm__ (GOSYM_PREFIX
"runtime.newselect");
632 runtime_newselect(int32 size
)
634 return (void*)newselect(size
);
638 newselect(int32 size
)
647 // allocate all the memory we need in a single allocation
648 // start with Select with size cases
649 // then lockorder with size entries
650 // then pollorder with size entries
651 sel
= runtime_mal(sizeof(*sel
) +
652 n
*sizeof(sel
->scase
[0]) +
653 size
*sizeof(sel
->lockorder
[0]) +
654 size
*sizeof(sel
->pollorder
[0]));
658 sel
->lockorder
= (void*)(sel
->scase
+ size
);
659 sel
->pollorder
= (void*)(sel
->lockorder
+ size
);
662 runtime_printf("newselect s=%p size=%d\n", sel
, size
);
666 // cut in half to give stack a chance to split
667 static void selectsend(Select
*sel
, Hchan
*c
, int index
, void *elem
);
669 // selectsend(sel *byte, hchan *chan any, elem *any) (selected bool);
671 void runtime_selectsend(Select
*, Hchan
*, void *, int32
)
672 __asm__ (GOSYM_PREFIX
"runtime.selectsend");
675 runtime_selectsend(Select
*sel
, Hchan
*c
, void *elem
, int32 index
)
677 // nil cases do not compete
681 selectsend(sel
, c
, index
, elem
);
685 selectsend(Select
*sel
, Hchan
*c
, int index
, void *elem
)
692 runtime_throw("selectsend: too many cases");
694 cas
= &sel
->scase
[i
];
698 cas
->kind
= CaseSend
;
702 runtime_printf("selectsend s=%p index=%d chan=%p\n",
703 sel
, cas
->index
, cas
->chan
);
706 // cut in half to give stack a chance to split
707 static void selectrecv(Select
*sel
, Hchan
*c
, int index
, void *elem
, bool*);
709 // selectrecv(sel *byte, hchan *chan any, elem *any) (selected bool);
711 void runtime_selectrecv(Select
*, Hchan
*, void *, int32
)
712 __asm__ (GOSYM_PREFIX
"runtime.selectrecv");
715 runtime_selectrecv(Select
*sel
, Hchan
*c
, void *elem
, int32 index
)
717 // nil cases do not compete
721 selectrecv(sel
, c
, index
, elem
, nil
);
724 // selectrecv2(sel *byte, hchan *chan any, elem *any, received *bool) (selected bool);
726 void runtime_selectrecv2(Select
*, Hchan
*, void *, bool *, int32
)
727 __asm__ (GOSYM_PREFIX
"runtime.selectrecv2");
730 runtime_selectrecv2(Select
*sel
, Hchan
*c
, void *elem
, bool *received
, int32 index
)
732 // nil cases do not compete
736 selectrecv(sel
, c
, index
, elem
, received
);
740 selectrecv(Select
*sel
, Hchan
*c
, int index
, void *elem
, bool *received
)
747 runtime_throw("selectrecv: too many cases");
749 cas
= &sel
->scase
[i
];
753 cas
->kind
= CaseRecv
;
755 cas
->receivedp
= received
;
758 runtime_printf("selectrecv s=%p index=%d chan=%p\n",
759 sel
, cas
->index
, cas
->chan
);
762 // cut in half to give stack a chance to split
763 static void selectdefault(Select
*, int);
765 // selectdefault(sel *byte) (selected bool);
767 void runtime_selectdefault(Select
*, int32
) __asm__ (GOSYM_PREFIX
"runtime.selectdefault");
770 runtime_selectdefault(Select
*sel
, int32 index
)
772 selectdefault(sel
, index
);
776 selectdefault(Select
*sel
, int32 index
)
783 runtime_throw("selectdefault: too many cases");
785 cas
= &sel
->scase
[i
];
789 cas
->kind
= CaseDefault
;
792 runtime_printf("selectdefault s=%p index=%d\n",
803 for(i
=0; i
<sel
->ncase
; i
++) {
804 c0
= sel
->lockorder
[i
];
806 c
= sel
->lockorder
[i
];
813 selunlock(Select
*sel
)
818 // We must be very careful here to not touch sel after we have unlocked
819 // the last lock, because sel can be freed right after the last unlock.
820 // Consider the following situation.
821 // First M calls runtime_park() in runtime_selectgo() passing the sel.
822 // Once runtime_park() has unlocked the last lock, another M makes
823 // the G that calls select runnable again and schedules it for execution.
824 // When the G runs on another M, it locks all the locks and frees sel.
825 // Now if the first M touches sel, it will access freed memory.
826 n
= (int32
)sel
->ncase
;
828 // skip the default case
829 if(n
>0 && sel
->lockorder
[0] == nil
)
831 for(i
= n
-1; i
>= r
; i
--) {
832 c
= sel
->lockorder
[i
];
833 if(i
>0 && sel
->lockorder
[i
-1] == c
)
834 continue; // will unlock it on the next iteration
840 selparkcommit(G
*gp
, void *sel
)
850 runtime_park(nil
, nil
, "select (no cases)"); // forever
853 static int selectgo(Select
**);
855 // selectgo(sel *byte);
857 int runtime_selectgo(Select
*) __asm__ (GOSYM_PREFIX
"runtime.selectgo");
860 runtime_selectgo(Select
*sel
)
862 return selectgo(&sel
);
866 selectgo(Select
**selp
)
869 uint32 o
, i
, j
, k
, done
;
879 if(runtime_gcwaiting())
883 runtime_printf("select: sel=%p\n", sel
);
888 if(runtime_blockprofilerate
> 0) {
889 t0
= runtime_cputicks();
890 for(i
=0; i
<sel
->ncase
; i
++)
891 sel
->scase
[i
].sg
.releasetime
= -1;
894 // The compiler rewrites selects that statically have
895 // only 0 or 1 cases plus default into simpler constructs.
896 // The only way we can end up with such small sel->ncase
897 // values here is for a larger select in which most channels
898 // have been nilled out. The general code handles those
899 // cases correctly, and they are rare enough not to bother
900 // optimizing (and needing to test).
902 // generate permuted order
903 for(i
=0; i
<sel
->ncase
; i
++)
904 sel
->pollorder
[i
] = i
;
905 for(i
=1; i
<sel
->ncase
; i
++) {
906 o
= sel
->pollorder
[i
];
907 j
= runtime_fastrand1()%(i
+1);
908 sel
->pollorder
[i
] = sel
->pollorder
[j
];
909 sel
->pollorder
[j
] = o
;
912 // sort the cases by Hchan address to get the locking order.
913 // simple heap sort, to guarantee n log n time and constant stack footprint.
914 for(i
=0; i
<sel
->ncase
; i
++) {
916 c
= sel
->scase
[j
].chan
;
917 while(j
> 0 && sel
->lockorder
[k
=(j
-1)/2] < c
) {
918 sel
->lockorder
[j
] = sel
->lockorder
[k
];
921 sel
->lockorder
[j
] = c
;
923 for(i
=sel
->ncase
; i
-->0; ) {
924 c
= sel
->lockorder
[i
];
925 sel
->lockorder
[i
] = sel
->lockorder
[0];
931 if(k
+1 < i
&& sel
->lockorder
[k
] < sel
->lockorder
[k
+1])
933 if(c
< sel
->lockorder
[k
]) {
934 sel
->lockorder
[j
] = sel
->lockorder
[k
];
940 sel
->lockorder
[j
] = c
;
943 for(i=0; i+1<sel->ncase; i++)
944 if(sel->lockorder[i] > sel->lockorder[i+1]) {
945 runtime_printf("i=%d %p %p\n", i, sel->lockorder[i], sel->lockorder[i+1]);
946 runtime_throw("select: broken sort");
952 // pass 1 - look for something already waiting
954 for(i
=0; i
<sel
->ncase
; i
++) {
955 o
= sel
->pollorder
[i
];
956 cas
= &sel
->scase
[o
];
961 if(c
->dataqsiz
> 0) {
965 sg
= dequeue(&c
->sendq
);
975 runtime_racereadpc(c
, runtime_selectgo
, chansend
);
978 if(c
->dataqsiz
> 0) {
979 if(c
->qcount
< c
->dataqsiz
)
982 sg
= dequeue(&c
->recvq
);
1001 // pass 2 - enqueue on all chans
1003 for(i
=0; i
<sel
->ncase
; i
++) {
1004 o
= sel
->pollorder
[i
];
1005 cas
= &sel
->scase
[o
];
1009 sg
->selectdone
= &done
;
1013 enqueue(&c
->recvq
, sg
);
1017 enqueue(&c
->sendq
, sg
);
1023 runtime_park(selparkcommit
, sel
, "select");
1028 // pass 3 - dequeue from unsuccessful chans
1029 // otherwise they stack up on quiet channels
1030 for(i
=0; i
<sel
->ncase
; i
++) {
1031 cas
= &sel
->scase
[i
];
1032 if(cas
!= (Scase
*)sg
) {
1034 if(cas
->kind
== CaseSend
)
1035 dequeueg(&c
->sendq
);
1037 dequeueg(&c
->recvq
);
1048 runtime_throw("selectgo: shouldn't happen");
1051 runtime_printf("wait-return: sel=%p c=%p cas=%p kind=%d\n",
1052 sel
, c
, cas
, cas
->kind
);
1054 if(cas
->kind
== CaseRecv
) {
1055 if(cas
->receivedp
!= nil
)
1056 *cas
->receivedp
= true;
1060 if(cas
->kind
== CaseRecv
&& cas
->sg
.elem
!= nil
)
1061 runtime_racewriteobjectpc(cas
->sg
.elem
, c
->elemtype
, selectgo
, chanrecv
);
1062 else if(cas
->kind
== CaseSend
)
1063 runtime_racereadobjectpc(cas
->sg
.elem
, c
->elemtype
, selectgo
, chansend
);
1070 // can receive from buffer
1072 if(cas
->sg
.elem
!= nil
)
1073 runtime_racewriteobjectpc(cas
->sg
.elem
, c
->elemtype
, selectgo
, chanrecv
);
1074 runtime_raceacquire(chanbuf(c
, c
->recvx
));
1076 if(cas
->receivedp
!= nil
)
1077 *cas
->receivedp
= true;
1078 if(cas
->sg
.elem
!= nil
)
1079 runtime_memmove(cas
->sg
.elem
, chanbuf(c
, c
->recvx
), c
->elemsize
);
1080 runtime_memclr(chanbuf(c
, c
->recvx
), c
->elemsize
);
1081 if(++c
->recvx
== c
->dataqsiz
)
1084 sg
= dequeue(&c
->sendq
);
1089 sg
->releasetime
= runtime_cputicks();
1097 // can send to buffer
1099 runtime_racerelease(chanbuf(c
, c
->sendx
));
1100 runtime_racereadobjectpc(cas
->sg
.elem
, c
->elemtype
, selectgo
, chansend
);
1102 runtime_memmove(chanbuf(c
, c
->sendx
), cas
->sg
.elem
, c
->elemsize
);
1103 if(++c
->sendx
== c
->dataqsiz
)
1106 sg
= dequeue(&c
->recvq
);
1111 sg
->releasetime
= runtime_cputicks();
1119 // can receive from sleeping sender (sg)
1121 if(cas
->sg
.elem
!= nil
)
1122 runtime_racewriteobjectpc(cas
->sg
.elem
, c
->elemtype
, selectgo
, chanrecv
);
1127 runtime_printf("syncrecv: sel=%p c=%p o=%d\n", sel
, c
, o
);
1128 if(cas
->receivedp
!= nil
)
1129 *cas
->receivedp
= true;
1130 if(cas
->sg
.elem
!= nil
)
1131 runtime_memmove(cas
->sg
.elem
, sg
->elem
, c
->elemsize
);
1135 sg
->releasetime
= runtime_cputicks();
1140 // read at end of closed channel
1142 if(cas
->receivedp
!= nil
)
1143 *cas
->receivedp
= false;
1144 if(cas
->sg
.elem
!= nil
)
1145 runtime_memclr(cas
->sg
.elem
, c
->elemsize
);
1147 runtime_raceacquire(c
);
1151 // can send to sleeping receiver (sg)
1153 runtime_racereadobjectpc(cas
->sg
.elem
, c
->elemtype
, selectgo
, chansend
);
1158 runtime_printf("syncsend: sel=%p c=%p o=%d\n", sel
, c
, o
);
1160 runtime_memmove(sg
->elem
, cas
->sg
.elem
, c
->elemsize
);
1164 sg
->releasetime
= runtime_cputicks();
1168 // return index corresponding to chosen case
1170 if(cas
->sg
.releasetime
> 0)
1171 runtime_blockevent(cas
->sg
.releasetime
- t0
, 2);
1176 // send on closed channel
1178 runtime_panicstring("send on closed channel");
1179 return 0; // not reached
1182 // This struct must match ../reflect/value.go:/runtimeSelect.
1183 typedef struct runtimeSelect runtimeSelect
;
1184 struct runtimeSelect
1192 // This enum must match ../reflect/value.go:/SelectDir.
1199 // func rselect(cases []runtimeSelect) (chosen int, recvOK bool)
1201 struct rselect_ret
{
1206 struct rselect_ret
reflect_rselect(Slice
)
1207 __asm__ (GOSYM_PREFIX
"reflect.rselect");
1210 reflect_rselect(Slice cases
)
1212 struct rselect_ret ret
;
1217 runtimeSelect
* rcase
, *rc
;
1222 rcase
= (runtimeSelect
*)cases
.__values
;
1224 sel
= newselect(cases
.__count
);
1225 for(i
=0; i
<cases
.__count
; i
++) {
1229 selectdefault(sel
, i
);
1234 selectsend(sel
, rc
->ch
, i
, rc
->val
);
1239 selectrecv(sel
, rc
->ch
, i
, rc
->val
, &recvOK
);
1244 chosen
= (intgo
)(uintptr
)selectgo(&sel
);
1246 ret
.chosen
= chosen
;
1247 ret
.recvOK
= (_Bool
)recvOK
;
1251 static void closechan(Hchan
*c
, void *pc
);
1253 // closechan(sel *byte);
1255 runtime_closechan(Hchan
*c
)
1257 closechan(c
, runtime_getcallerpc(&c
));
1261 // func chanclose(c chan)
1263 void reflect_chanclose(Hchan
*) __asm__ (GOSYM_PREFIX
"reflect.chanclose");
1266 reflect_chanclose(Hchan
*c
)
1268 closechan(c
, runtime_getcallerpc(&c
));
1272 closechan(Hchan
*c
, void *pc
)
1278 runtime_panicstring("close of nil channel");
1280 if(runtime_gcwaiting())
1286 runtime_panicstring("close of closed channel");
1290 runtime_racewritepc(c
, pc
, runtime_closechan
);
1291 runtime_racerelease(c
);
1296 // release all readers
1298 sg
= dequeue(&c
->recvq
);
1304 sg
->releasetime
= runtime_cputicks();
1308 // release all writers
1310 sg
= dequeue(&c
->sendq
);
1316 sg
->releasetime
= runtime_cputicks();
1324 __go_builtin_close(Hchan
*c
)
1326 runtime_closechan(c
);
1330 // func chanlen(c chan) (len int)
1332 intgo
reflect_chanlen(Hchan
*) __asm__ (GOSYM_PREFIX
"reflect.chanlen");
1335 reflect_chanlen(Hchan
*c
)
1347 __go_chan_len(Hchan
*c
)
1349 return reflect_chanlen(c
);
1353 // func chancap(c chan) int
1355 intgo
reflect_chancap(Hchan
*) __asm__ (GOSYM_PREFIX
"reflect.chancap");
1358 reflect_chancap(Hchan
*c
)
1370 __go_chan_cap(Hchan
*c
)
1372 return reflect_chancap(c
);
1384 q
->first
= sgp
->link
;
1386 // if sgp participates in a select and is already signaled, ignore it
1387 if(sgp
->selectdone
!= nil
) {
1388 // claim the right to signal
1389 if(*sgp
->selectdone
!= 0 || !runtime_cas(sgp
->selectdone
, 0, 1))
1399 SudoG
**l
, *sgp
, *prevsgp
;
1404 for(l
=&q
->first
; (sgp
=*l
) != nil
; l
=&sgp
->link
, prevsgp
=sgp
) {
1415 enqueue(WaitQ
*q
, SudoG
*sgp
)
1418 if(q
->first
== nil
) {
1423 q
->last
->link
= sgp
;
1428 racesync(Hchan
*c
, SudoG
*sg
)
1430 runtime_racerelease(chanbuf(c
, 0));
1431 runtime_raceacquireg(sg
->g
, chanbuf(c
, 0));
1432 runtime_racereleaseg(sg
->g
, chanbuf(c
, 0));
1433 runtime_raceacquire(chanbuf(c
, 0));