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.
13 typedef struct WaitQ WaitQ
;
14 typedef struct SudoG SudoG
;
15 typedef struct Select Select
;
16 typedef struct Scase Scase
;
18 typedef struct __go_type_descriptor Type
;
19 typedef struct __go_channel_type ChanType
;
23 G
* g
; // g and selgen constitute
24 uint32 selgen
; // a weak pointer to g
27 byte
* elem
; // data element
36 // The garbage collector is assuming that Hchan can only contain pointers into the stack
37 // and cannot contain pointers into the heap.
40 uintgo qcount
; // total data in the q
41 uintgo dataqsiz
; // size of the circular q
44 uint8 pad
; // ensures proper alignment of the buffer that follows Hchan in memory
46 uintgo sendx
; // send index
47 uintgo recvx
; // receive index
48 WaitQ recvq
; // list of recv waiters
49 WaitQ sendq
; // list of send waiters
53 uint32 runtime_Hchansize
= sizeof(Hchan
);
55 // Buffer follows Hchan immediately in memory.
56 // chanbuf(c, i) is pointer to the i'th slot in the buffer.
57 #define chanbuf(c, i) ((byte*)((c)+1)+(uintptr)(c)->elemsize*(i))
71 SudoG sg
; // must be first member (cast to Scase)
74 uint16 index
; // index to return
75 bool* receivedp
; // pointer to received bool (recv2)
80 uint16 tcase
; // total count of scase[]
81 uint16 ncase
; // currently filled scase[]
82 uint16
* pollorder
; // case poll order
83 Hchan
** lockorder
; // channel lock order
84 Scase scase
[1]; // one per case (in order of appearance)
87 static void dequeueg(WaitQ
*);
88 static SudoG
* dequeue(WaitQ
*);
89 static void enqueue(WaitQ
*, SudoG
*);
90 static void racesync(Hchan
*, SudoG
*);
93 runtime_makechan_c(ChanType
*t
, int64 hint
)
99 elem
= t
->__element_type
;
101 // compiler checks this but be safe.
102 if(elem
->__size
>= (1<<16))
103 runtime_throw("makechan: invalid channel element type");
105 if(hint
< 0 || (intgo
)hint
!= hint
|| (elem
->__size
> 0 && (uintptr
)hint
> MaxMem
/ elem
->__size
))
106 runtime_panicstring("makechan: size out of range");
109 n
= ROUND(n
, elem
->__align
);
111 // allocate memory in one call
112 c
= (Hchan
*)runtime_mallocgc(n
+ hint
*elem
->__size
, (uintptr
)t
| TypeInfo_Chan
, 0);
113 c
->elemsize
= elem
->__size
;
114 c
->elemalign
= elem
->__align
;
118 runtime_printf("makechan: chan=%p; elemsize=%D; dataqsiz=%D\n",
119 c
, (int64
)elem
->__size
, (int64
)c
->dataqsiz
);
125 // func makechan(typ *ChanType, size uint64) (chan)
126 Hchan
*reflect_makechan(ChanType
*, uint64
)
127 __asm__ (GOSYM_PREFIX
"reflect.makechan");
130 reflect_makechan(ChanType
*t
, uint64 size
)
134 c
= runtime_makechan_c(t
, size
);
138 // makechan(t *ChanType, hint int64) (hchan *chan any);
140 __go_new_channel(ChanType
*t
, uintptr hint
)
142 return runtime_makechan_c(t
, hint
);
146 __go_new_channel_big(ChanType
*t
, uint64 hint
)
148 return runtime_makechan_c(t
, hint
);
152 * generic single channel send/recv
153 * if the bool pointer is nil,
154 * then the full exchange will
155 * occur. if pres is not nil,
156 * then the protocol will not
157 * sleep but return if it could
160 * sleep can wake up with g->param == nil
161 * when a channel involved in the sleep has
162 * been closed. it is easiest to loop and re-run
163 * the operation; we'll see that it's now closed.
166 runtime_chansend(ChanType
*t
, Hchan
*c
, byte
*ep
, bool *pres
, void *pc
)
182 runtime_park(nil
, nil
, "chan send (nil chan)");
183 return; // 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
, runtime_chansend
);
209 sg
= dequeue(&c
->recvq
);
218 runtime_memmove(sg
->elem
, ep
, c
->elemsize
);
220 sg
->releasetime
= runtime_cputicks();
236 mysg
.selgen
= NOSELGEN
;
238 enqueue(&c
->sendq
, &mysg
);
239 runtime_park(runtime_unlock
, c
, "chan send");
241 if(g
->param
== nil
) {
244 runtime_throw("chansend: spurious wakeup");
248 if(mysg
.releasetime
> 0)
249 runtime_blockevent(mysg
.releasetime
- t0
, 2);
257 if(c
->qcount
>= c
->dataqsiz
) {
265 mysg
.selgen
= NOSELGEN
;
266 enqueue(&c
->sendq
, &mysg
);
267 runtime_park(runtime_unlock
, c
, "chan send");
274 runtime_racerelease(chanbuf(c
, c
->sendx
));
276 runtime_memmove(chanbuf(c
, c
->sendx
), ep
, c
->elemsize
);
277 if(++c
->sendx
== c
->dataqsiz
)
281 sg
= dequeue(&c
->recvq
);
286 sg
->releasetime
= runtime_cputicks();
292 if(mysg
.releasetime
> 0)
293 runtime_blockevent(mysg
.releasetime
- t0
, 2);
298 runtime_panicstring("send on closed channel");
303 runtime_chanrecv(ChanType
*t
, Hchan
* c
, byte
*ep
, bool *selected
, bool *received
)
311 if(runtime_gcwaiting())
315 runtime_printf("chanrecv: chan=%p\n", c
);
321 if(selected
!= nil
) {
325 runtime_park(nil
, nil
, "chan receive (nil chan)");
326 return; // not reached
330 mysg
.releasetime
= 0;
331 if(runtime_blockprofilerate
> 0) {
332 t0
= runtime_cputicks();
333 mysg
.releasetime
= -1;
343 sg
= dequeue(&c
->sendq
);
350 runtime_memmove(ep
, sg
->elem
, c
->elemsize
);
354 sg
->releasetime
= runtime_cputicks();
364 if(selected
!= nil
) {
372 mysg
.selgen
= NOSELGEN
;
374 enqueue(&c
->recvq
, &mysg
);
375 runtime_park(runtime_unlock
, c
, "chan receive");
377 if(g
->param
== nil
) {
380 runtime_throw("chanrecv: spurious wakeup");
386 if(mysg
.releasetime
> 0)
387 runtime_blockevent(mysg
.releasetime
- t0
, 2);
395 if(selected
!= nil
) {
404 mysg
.selgen
= NOSELGEN
;
405 enqueue(&c
->recvq
, &mysg
);
406 runtime_park(runtime_unlock
, c
, "chan receive");
413 runtime_raceacquire(chanbuf(c
, c
->recvx
));
416 runtime_memmove(ep
, chanbuf(c
, c
->recvx
), c
->elemsize
);
417 runtime_memclr(chanbuf(c
, c
->recvx
), c
->elemsize
);
418 if(++c
->recvx
== c
->dataqsiz
)
422 sg
= dequeue(&c
->sendq
);
427 sg
->releasetime
= runtime_cputicks();
436 if(mysg
.releasetime
> 0)
437 runtime_blockevent(mysg
.releasetime
- t0
, 2);
442 runtime_memclr(ep
, c
->elemsize
);
448 runtime_raceacquire(c
);
450 if(mysg
.releasetime
> 0)
451 runtime_blockevent(mysg
.releasetime
- t0
, 2);
454 // The compiler generates a call to __go_send_small to send a value 8
457 __go_send_small(ChanType
*t
, Hchan
* c
, uint64 val
)
461 byte b
[sizeof(uint64
)];
467 #ifndef WORDS_BIGENDIAN
470 p
= u
.b
+ sizeof(uint64
) - t
->__element_type
->__size
;
472 runtime_chansend(t
, c
, p
, nil
, runtime_getcallerpc(&t
));
475 // The compiler generates a call to __go_send_big to send a value
476 // larger than 8 bytes or smaller.
478 __go_send_big(ChanType
*t
, Hchan
* c
, byte
* p
)
480 runtime_chansend(t
, c
, p
, nil
, runtime_getcallerpc(&t
));
483 // The compiler generates a call to __go_receive to receive a
484 // value from a channel.
486 __go_receive(ChanType
*t
, Hchan
* c
, byte
* p
)
488 runtime_chanrecv(t
, c
, p
, nil
, nil
);
491 _Bool
runtime_chanrecv2(ChanType
*t
, Hchan
* c
, byte
* p
)
492 __asm__ (GOSYM_PREFIX
"runtime.chanrecv2");
495 runtime_chanrecv2(ChanType
*t
, Hchan
* c
, byte
* p
)
499 runtime_chanrecv(t
, c
, p
, nil
, &received
);
503 // func selectnbsend(c chan any, elem any) bool
505 // compiler implements
516 // if selectnbsend(c, v) {
523 runtime_selectnbsend(ChanType
*t
, Hchan
*c
, byte
*p
)
527 runtime_chansend(t
, c
, p
, &res
, runtime_getcallerpc(&t
));
531 // func selectnbrecv(elem *any, c chan any) bool
533 // compiler implements
544 // if selectnbrecv(&v, c) {
551 runtime_selectnbrecv(ChanType
*t
, byte
*v
, Hchan
*c
)
555 runtime_chanrecv(t
, c
, v
, &selected
, nil
);
559 // func selectnbrecv2(elem *any, ok *bool, c chan any) bool
561 // compiler implements
572 // if c != nil && selectnbrecv2(&v, &ok, c) {
579 runtime_selectnbrecv2(ChanType
*t
, byte
*v
, _Bool
*received
, Hchan
*c
)
585 runtime_chanrecv(t
, c
, v
, &selected
, received
== nil
? nil
: &r
);
592 // func chansend(c chan, val iword, nb bool) (selected bool)
593 // where an iword is the same word an interface value would use:
594 // the actual data if it fits, or else a pointer to the data.
596 _Bool
reflect_chansend(ChanType
*, Hchan
*, uintptr
, _Bool
)
597 __asm__ (GOSYM_PREFIX
"reflect.chansend");
600 reflect_chansend(ChanType
*t
, Hchan
*c
, uintptr val
, _Bool nb
)
608 sp
= (bool*)&selected
;
613 if(__go_is_pointer_type(t
->__element_type
))
617 runtime_chansend(t
, c
, vp
, sp
, runtime_getcallerpc(&t
));
622 // func chanrecv(c chan, nb bool) (val iword, selected, received bool)
623 // where an iword is the same word an interface value would use:
624 // the actual data if it fits, or else a pointer to the data.
633 struct chanrecv_ret
reflect_chanrecv(ChanType
*, Hchan
*, _Bool
)
634 __asm__ (GOSYM_PREFIX
"reflect.chanrecv");
637 reflect_chanrecv(ChanType
*t
, Hchan
*c
, _Bool nb
)
639 struct chanrecv_ret ret
;
653 if(__go_is_pointer_type(t
->__element_type
)) {
654 vp
= (byte
*)&ret
.val
;
656 vp
= runtime_mal(t
->__element_type
->__size
);
657 ret
.val
= (uintptr
)vp
;
659 runtime_chanrecv(t
, c
, vp
, sp
, &received
);
661 ret
.selected
= selected
;
662 ret
.received
= received
;
666 static void newselect(int32
, Select
**);
668 // newselect(size uint32) (sel *byte);
670 void* runtime_newselect(int32
) __asm__ (GOSYM_PREFIX
"runtime.newselect");
673 runtime_newselect(int32 size
)
677 newselect(size
, &sel
);
682 newselect(int32 size
, Select
**selp
)
691 // allocate all the memory we need in a single allocation
692 // start with Select with size cases
693 // then lockorder with size entries
694 // then pollorder with size entries
695 sel
= runtime_mal(sizeof(*sel
) +
696 n
*sizeof(sel
->scase
[0]) +
697 size
*sizeof(sel
->lockorder
[0]) +
698 size
*sizeof(sel
->pollorder
[0]));
702 sel
->lockorder
= (void*)(sel
->scase
+ size
);
703 sel
->pollorder
= (void*)(sel
->lockorder
+ size
);
707 runtime_printf("newselect s=%p size=%d\n", sel
, size
);
710 // cut in half to give stack a chance to split
711 static void selectsend(Select
*sel
, Hchan
*c
, int index
, void *elem
);
713 // selectsend(sel *byte, hchan *chan any, elem *any) (selected bool);
715 void runtime_selectsend(Select
*, Hchan
*, void *, int32
)
716 __asm__ (GOSYM_PREFIX
"runtime.selectsend");
719 runtime_selectsend(Select
*sel
, Hchan
*c
, void *elem
, int32 index
)
721 // nil cases do not compete
725 selectsend(sel
, c
, index
, elem
);
729 selectsend(Select
*sel
, Hchan
*c
, int index
, void *elem
)
736 runtime_throw("selectsend: too many cases");
738 cas
= &sel
->scase
[i
];
742 cas
->kind
= CaseSend
;
746 runtime_printf("selectsend s=%p index=%d chan=%p\n",
747 sel
, cas
->index
, cas
->chan
);
750 // cut in half to give stack a chance to split
751 static void selectrecv(Select
*sel
, Hchan
*c
, int index
, void *elem
, bool*);
753 // selectrecv(sel *byte, hchan *chan any, elem *any) (selected bool);
755 void runtime_selectrecv(Select
*, Hchan
*, void *, int32
)
756 __asm__ (GOSYM_PREFIX
"runtime.selectrecv");
759 runtime_selectrecv(Select
*sel
, Hchan
*c
, void *elem
, int32 index
)
761 // nil cases do not compete
765 selectrecv(sel
, c
, index
, elem
, nil
);
768 // selectrecv2(sel *byte, hchan *chan any, elem *any, received *bool) (selected bool);
770 void runtime_selectrecv2(Select
*, Hchan
*, void *, bool *, int32
)
771 __asm__ (GOSYM_PREFIX
"runtime.selectrecv2");
774 runtime_selectrecv2(Select
*sel
, Hchan
*c
, void *elem
, bool *received
, int32 index
)
776 // nil cases do not compete
780 selectrecv(sel
, c
, index
, elem
, received
);
784 selectrecv(Select
*sel
, Hchan
*c
, int index
, void *elem
, bool *received
)
791 runtime_throw("selectrecv: too many cases");
793 cas
= &sel
->scase
[i
];
797 cas
->kind
= CaseRecv
;
799 cas
->receivedp
= received
;
802 runtime_printf("selectrecv s=%p index=%d chan=%p\n",
803 sel
, cas
->index
, cas
->chan
);
806 // cut in half to give stack a chance to split
807 static void selectdefault(Select
*, int);
809 // selectdefault(sel *byte) (selected bool);
811 void runtime_selectdefault(Select
*, int32
) __asm__ (GOSYM_PREFIX
"runtime.selectdefault");
814 runtime_selectdefault(Select
*sel
, int32 index
)
816 selectdefault(sel
, index
);
820 selectdefault(Select
*sel
, int32 index
)
827 runtime_throw("selectdefault: too many cases");
829 cas
= &sel
->scase
[i
];
833 cas
->kind
= CaseDefault
;
836 runtime_printf("selectdefault s=%p index=%d\n",
847 for(i
=0; i
<sel
->ncase
; i
++) {
848 c0
= sel
->lockorder
[i
];
850 c
= sel
->lockorder
[i
];
857 selunlock(Select
*sel
)
862 // We must be very careful here to not touch sel after we have unlocked
863 // the last lock, because sel can be freed right after the last unlock.
864 // Consider the following situation.
865 // First M calls runtime_park() in runtime_selectgo() passing the sel.
866 // Once runtime_park() has unlocked the last lock, another M makes
867 // the G that calls select runnable again and schedules it for execution.
868 // When the G runs on another M, it locks all the locks and frees sel.
869 // Now if the first M touches sel, it will access freed memory.
870 n
= (int32
)sel
->ncase
;
872 // skip the default case
873 if(n
>0 && sel
->lockorder
[0] == nil
)
875 for(i
= n
-1; i
>= r
; i
--) {
876 c
= sel
->lockorder
[i
];
877 if(i
>0 && sel
->lockorder
[i
-1] == c
)
878 continue; // will unlock it on the next iteration
886 runtime_park(nil
, nil
, "select (no cases)"); // forever
889 static int selectgo(Select
**);
891 // selectgo(sel *byte);
893 int runtime_selectgo(Select
*) __asm__ (GOSYM_PREFIX
"runtime.selectgo");
896 runtime_selectgo(Select
*sel
)
898 return selectgo(&sel
);
902 selectgo(Select
**selp
)
915 if(runtime_gcwaiting())
919 runtime_printf("select: sel=%p\n", sel
);
924 if(runtime_blockprofilerate
> 0) {
925 t0
= runtime_cputicks();
926 for(i
=0; i
<sel
->ncase
; i
++)
927 sel
->scase
[i
].sg
.releasetime
= -1;
930 // The compiler rewrites selects that statically have
931 // only 0 or 1 cases plus default into simpler constructs.
932 // The only way we can end up with such small sel->ncase
933 // values here is for a larger select in which most channels
934 // have been nilled out. The general code handles those
935 // cases correctly, and they are rare enough not to bother
936 // optimizing (and needing to test).
938 // generate permuted order
939 for(i
=0; i
<sel
->ncase
; i
++)
940 sel
->pollorder
[i
] = i
;
941 for(i
=1; i
<sel
->ncase
; i
++) {
942 o
= sel
->pollorder
[i
];
943 j
= runtime_fastrand1()%(i
+1);
944 sel
->pollorder
[i
] = sel
->pollorder
[j
];
945 sel
->pollorder
[j
] = o
;
948 // sort the cases by Hchan address to get the locking order.
949 // simple heap sort, to guarantee n log n time and constant stack footprint.
950 for(i
=0; i
<sel
->ncase
; i
++) {
952 c
= sel
->scase
[j
].chan
;
953 while(j
> 0 && sel
->lockorder
[k
=(j
-1)/2] < c
) {
954 sel
->lockorder
[j
] = sel
->lockorder
[k
];
957 sel
->lockorder
[j
] = c
;
959 for(i
=sel
->ncase
; i
-->0; ) {
960 c
= sel
->lockorder
[i
];
961 sel
->lockorder
[i
] = sel
->lockorder
[0];
967 if(k
+1 < i
&& sel
->lockorder
[k
] < sel
->lockorder
[k
+1])
969 if(c
< sel
->lockorder
[k
]) {
970 sel
->lockorder
[j
] = sel
->lockorder
[k
];
976 sel
->lockorder
[j
] = c
;
979 for(i=0; i+1<sel->ncase; i++)
980 if(sel->lockorder[i] > sel->lockorder[i+1]) {
981 runtime_printf("i=%d %p %p\n", i, sel->lockorder[i], sel->lockorder[i+1]);
982 runtime_throw("select: broken sort");
988 // pass 1 - look for something already waiting
990 for(i
=0; i
<sel
->ncase
; i
++) {
991 o
= sel
->pollorder
[i
];
992 cas
= &sel
->scase
[o
];
997 if(c
->dataqsiz
> 0) {
1001 sg
= dequeue(&c
->sendq
);
1011 runtime_racereadpc(c
, runtime_selectgo
, runtime_chansend
);
1014 if(c
->dataqsiz
> 0) {
1015 if(c
->qcount
< c
->dataqsiz
)
1018 sg
= dequeue(&c
->recvq
);
1037 // pass 2 - enqueue on all chans
1038 for(i
=0; i
<sel
->ncase
; i
++) {
1039 o
= sel
->pollorder
[i
];
1040 cas
= &sel
->scase
[o
];
1044 sg
->selgen
= g
->selgen
;
1048 enqueue(&c
->recvq
, sg
);
1052 enqueue(&c
->sendq
, sg
);
1058 runtime_park((void(*)(Lock
*))selunlock
, (Lock
*)sel
, "select");
1063 // pass 3 - dequeue from unsuccessful chans
1064 // otherwise they stack up on quiet channels
1065 for(i
=0; i
<sel
->ncase
; i
++) {
1066 cas
= &sel
->scase
[i
];
1067 if(cas
!= (Scase
*)sg
) {
1069 if(cas
->kind
== CaseSend
)
1070 dequeueg(&c
->sendq
);
1072 dequeueg(&c
->recvq
);
1083 runtime_throw("selectgo: shouldn't happen");
1086 runtime_printf("wait-return: sel=%p c=%p cas=%p kind=%d\n",
1087 sel
, c
, cas
, cas
->kind
);
1089 if(cas
->kind
== CaseRecv
) {
1090 if(cas
->receivedp
!= nil
)
1091 *cas
->receivedp
= true;
1098 // can receive from buffer
1100 runtime_raceacquire(chanbuf(c
, c
->recvx
));
1101 if(cas
->receivedp
!= nil
)
1102 *cas
->receivedp
= true;
1103 if(cas
->sg
.elem
!= nil
)
1104 runtime_memmove(cas
->sg
.elem
, chanbuf(c
, c
->recvx
), c
->elemsize
);
1105 runtime_memclr(chanbuf(c
, c
->recvx
), c
->elemsize
);
1106 if(++c
->recvx
== c
->dataqsiz
)
1109 sg
= dequeue(&c
->sendq
);
1114 sg
->releasetime
= runtime_cputicks();
1122 // can send to buffer
1124 runtime_racerelease(chanbuf(c
, c
->sendx
));
1125 runtime_memmove(chanbuf(c
, c
->sendx
), cas
->sg
.elem
, c
->elemsize
);
1126 if(++c
->sendx
== c
->dataqsiz
)
1129 sg
= dequeue(&c
->recvq
);
1134 sg
->releasetime
= runtime_cputicks();
1142 // can receive from sleeping sender (sg)
1147 runtime_printf("syncrecv: sel=%p c=%p o=%d\n", sel
, c
, o
);
1148 if(cas
->receivedp
!= nil
)
1149 *cas
->receivedp
= true;
1150 if(cas
->sg
.elem
!= nil
)
1151 runtime_memmove(cas
->sg
.elem
, sg
->elem
, c
->elemsize
);
1155 sg
->releasetime
= runtime_cputicks();
1160 // read at end of closed channel
1162 if(cas
->receivedp
!= nil
)
1163 *cas
->receivedp
= false;
1164 if(cas
->sg
.elem
!= nil
)
1165 runtime_memclr(cas
->sg
.elem
, c
->elemsize
);
1167 runtime_raceacquire(c
);
1171 // can send to sleeping receiver (sg)
1176 runtime_printf("syncsend: sel=%p c=%p o=%d\n", sel
, c
, o
);
1178 runtime_memmove(sg
->elem
, cas
->sg
.elem
, c
->elemsize
);
1182 sg
->releasetime
= runtime_cputicks();
1186 // return index corresponding to chosen case
1188 if(cas
->sg
.releasetime
> 0)
1189 runtime_blockevent(cas
->sg
.releasetime
- t0
, 2);
1194 // send on closed channel
1196 runtime_panicstring("send on closed channel");
1197 return 0; // not reached
1200 // This struct must match ../reflect/value.go:/runtimeSelect.
1201 typedef struct runtimeSelect runtimeSelect
;
1202 struct runtimeSelect
1210 // This enum must match ../reflect/value.go:/SelectDir.
1217 struct rselect_ret
{
1223 // func rselect(cases []runtimeSelect) (chosen int, word uintptr, recvOK bool)
1225 struct rselect_ret
reflect_rselect(Slice
)
1226 __asm__ (GOSYM_PREFIX
"reflect.rselect");
1229 reflect_rselect(Slice cases
)
1231 struct rselect_ret ret
;
1234 runtimeSelect
* rcase
, *rc
;
1246 rcase
= (runtimeSelect
*)cases
.__values
;
1247 for(i
=0; i
<cases
.__count
; i
++) {
1249 if(rc
->dir
== SelectRecv
&& rc
->ch
!= nil
) {
1250 if(maxsize
< rc
->typ
->__element_type
->__size
)
1251 maxsize
= rc
->typ
->__element_type
->__size
;
1252 if(!__go_is_pointer_type(rc
->typ
->__element_type
))
1259 recvptr
= runtime_mal(maxsize
);
1261 newselect(cases
.__count
, &sel
);
1262 for(i
=0; i
<cases
.__count
; i
++) {
1266 selectdefault(sel
, i
);
1271 if(!__go_is_pointer_type(rc
->typ
->__element_type
))
1272 elem
= (void*)rc
->val
;
1274 elem
= (void*)&rc
->val
;
1275 selectsend(sel
, rc
->ch
, i
, elem
);
1280 if(!__go_is_pointer_type(rc
->typ
->__element_type
))
1284 selectrecv(sel
, rc
->ch
, i
, elem
, &ret
.recvOK
);
1289 ret
.chosen
= (intgo
)(uintptr
)selectgo(&sel
);
1290 if(rcase
[ret
.chosen
].dir
== SelectRecv
&& !__go_is_pointer_type(rcase
[ret
.chosen
].typ
->__element_type
))
1291 ret
.word
= (uintptr
)recvptr
;
1296 static void closechan(Hchan
*c
, void *pc
);
1298 // closechan(sel *byte);
1300 runtime_closechan(Hchan
*c
)
1302 closechan(c
, runtime_getcallerpc(&c
));
1306 // func chanclose(c chan)
1308 void reflect_chanclose(Hchan
*) __asm__ (GOSYM_PREFIX
"reflect.chanclose");
1311 reflect_chanclose(Hchan
*c
)
1313 closechan(c
, runtime_getcallerpc(&c
));
1317 closechan(Hchan
*c
, void *pc
)
1323 runtime_panicstring("close of nil channel");
1325 if(runtime_gcwaiting())
1331 runtime_panicstring("close of closed channel");
1335 runtime_racewritepc(c
, pc
, runtime_closechan
);
1336 runtime_racerelease(c
);
1341 // release all readers
1343 sg
= dequeue(&c
->recvq
);
1349 sg
->releasetime
= runtime_cputicks();
1353 // release all writers
1355 sg
= dequeue(&c
->sendq
);
1361 sg
->releasetime
= runtime_cputicks();
1369 __go_builtin_close(Hchan
*c
)
1371 runtime_closechan(c
);
1375 // func chanlen(c chan) (len int)
1377 intgo
reflect_chanlen(Hchan
*) __asm__ (GOSYM_PREFIX
"reflect.chanlen");
1380 reflect_chanlen(Hchan
*c
)
1392 __go_chan_len(Hchan
*c
)
1394 return reflect_chanlen(c
);
1398 // func chancap(c chan) int
1400 intgo
reflect_chancap(Hchan
*) __asm__ (GOSYM_PREFIX
"reflect.chancap");
1403 reflect_chancap(Hchan
*c
)
1415 __go_chan_cap(Hchan
*c
)
1417 return reflect_chancap(c
);
1429 q
->first
= sgp
->link
;
1431 // if sgp is stale, ignore it
1432 if(sgp
->selgen
!= NOSELGEN
&&
1433 (sgp
->selgen
!= sgp
->g
->selgen
||
1434 !runtime_cas(&sgp
->g
->selgen
, sgp
->selgen
, sgp
->selgen
+ 2))) {
1435 //prints("INVALID PSEUDOG POINTER\n");
1445 SudoG
**l
, *sgp
, *prevsgp
;
1450 for(l
=&q
->first
; (sgp
=*l
) != nil
; l
=&sgp
->link
, prevsgp
=sgp
) {
1461 enqueue(WaitQ
*q
, SudoG
*sgp
)
1464 if(q
->first
== nil
) {
1469 q
->last
->link
= sgp
;
1474 racesync(Hchan
*c
, SudoG
*sg
)
1476 runtime_racerelease(chanbuf(c
, 0));
1477 runtime_raceacquireg(sg
->g
, chanbuf(c
, 0));
1478 runtime_racereleaseg(sg
->g
, chanbuf(c
, 0));
1479 runtime_raceacquire(chanbuf(c
, 0));