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 static int32 debug
= 0;
15 typedef struct WaitQ WaitQ
;
16 typedef struct SudoG SudoG
;
17 typedef struct Select Select
;
18 typedef struct Scase Scase
;
20 typedef struct __go_type_descriptor Type
;
21 typedef struct __go_channel_type ChanType
;
25 G
* g
; // g and selgen constitute
26 uint32 selgen
; // a weak pointer to g
29 byte
* elem
; // data element
40 uintgo qcount
; // total data in the q
41 uintgo dataqsiz
; // size of the circular q
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 // Buffer follows Hchan immediately in memory.
53 // chanbuf(c, i) is pointer to the i'th slot in the buffer.
54 #define chanbuf(c, i) ((byte*)((c)+1)+(uintptr)(c)->elemsize*(i))
66 SudoG sg
; // must be first member (cast to Scase)
69 uint16 index
; // index to return
70 bool* receivedp
; // pointer to received bool (recv2)
75 uint16 tcase
; // total count of scase[]
76 uint16 ncase
; // currently filled scase[]
77 uint16
* pollorder
; // case poll order
78 Hchan
** lockorder
; // channel lock order
79 Scase scase
[1]; // one per case (in order of appearance)
82 static void dequeueg(WaitQ
*);
83 static SudoG
* dequeue(WaitQ
*);
84 static void enqueue(WaitQ
*, SudoG
*);
85 static void racesync(Hchan
*, SudoG
*);
88 runtime_makechan_c(ChanType
*t
, int64 hint
)
94 elem
= t
->__element_type
;
96 // compiler checks this but be safe.
97 if(elem
->__size
>= (1<<16))
98 runtime_throw("makechan: invalid channel element type");
100 if(hint
< 0 || (intgo
)hint
!= hint
|| (elem
->__size
> 0 && (uintptr
)hint
> MaxMem
/ elem
->__size
))
101 runtime_panicstring("makechan: size out of range");
105 // allocate memory in one call
106 c
= (Hchan
*)runtime_mal(n
+ hint
*elem
->__size
);
107 c
->elemsize
= elem
->__size
;
108 c
->elemalign
= elem
->__align
;
112 runtime_printf("makechan: chan=%p; elemsize=%D; elemalign=%d; dataqsiz=%D\n",
113 c
, (int64
)elem
->__size
, elem
->__align
, (int64
)c
->dataqsiz
);
119 // func makechan(typ *ChanType, size uint64) (chan)
120 uintptr
reflect_makechan(ChanType
*, uint64
)
121 asm ("reflect.makechan");
124 reflect_makechan(ChanType
*t
, uint64 size
)
129 c
= runtime_makechan_c(t
, size
);
130 ret
= runtime_mal(sizeof(void*));
131 __builtin_memcpy(ret
, &c
, sizeof(void*));
135 // makechan(t *ChanType, hint int64) (hchan *chan any);
137 __go_new_channel(ChanType
*t
, uintptr hint
)
139 return runtime_makechan_c(t
, hint
);
143 __go_new_channel_big(ChanType
*t
, uint64 hint
)
145 return runtime_makechan_c(t
, hint
);
149 * generic single channel send/recv
150 * if the bool pointer is nil,
151 * then the full exchange will
152 * occur. if pres is not nil,
153 * then the protocol will not
154 * sleep but return if it could
157 * sleep can wake up with g->param == nil
158 * when a channel involved in the sleep has
159 * been closed. it is easiest to loop and re-run
160 * the operation; we'll see that it's now closed.
163 runtime_chansend(ChanType
*t
, Hchan
*c
, byte
*ep
, bool *pres
, void *pc
)
179 runtime_park(nil
, nil
, "chan send (nil chan)");
180 return; // not reached
183 if(runtime_gcwaiting
)
187 runtime_printf("chansend: chan=%p\n", c
);
191 mysg
.releasetime
= 0;
192 if(runtime_blockprofilerate
> 0) {
193 t0
= runtime_cputicks();
194 mysg
.releasetime
= -1;
198 // TODO(dvyukov): add similar instrumentation to select.
200 runtime_racereadpc(c
, pc
, runtime_chansend
);
207 sg
= dequeue(&c
->recvq
);
216 runtime_memmove(sg
->elem
, ep
, c
->elemsize
);
218 sg
->releasetime
= runtime_cputicks();
234 mysg
.selgen
= NOSELGEN
;
236 enqueue(&c
->sendq
, &mysg
);
237 runtime_park(runtime_unlock
, c
, "chan send");
239 if(g
->param
== nil
) {
242 runtime_throw("chansend: spurious wakeup");
246 if(mysg
.releasetime
> 0)
247 runtime_blockevent(mysg
.releasetime
- t0
, 2);
255 if(c
->qcount
>= c
->dataqsiz
) {
263 mysg
.selgen
= NOSELGEN
;
264 enqueue(&c
->sendq
, &mysg
);
265 runtime_park(runtime_unlock
, c
, "chan send");
272 runtime_racerelease(chanbuf(c
, c
->sendx
));
274 runtime_memmove(chanbuf(c
, c
->sendx
), ep
, c
->elemsize
);
275 if(++c
->sendx
== c
->dataqsiz
)
279 sg
= dequeue(&c
->recvq
);
284 sg
->releasetime
= runtime_cputicks();
290 if(mysg
.releasetime
> 0)
291 runtime_blockevent(mysg
.releasetime
- t0
, 2);
296 runtime_panicstring("send on closed channel");
301 runtime_chanrecv(ChanType
*t
, Hchan
* c
, byte
*ep
, bool *selected
, bool *received
)
309 if(runtime_gcwaiting
)
313 runtime_printf("chanrecv: chan=%p\n", c
);
319 if(selected
!= nil
) {
323 runtime_park(nil
, nil
, "chan receive (nil chan)");
324 return; // not reached
328 mysg
.releasetime
= 0;
329 if(runtime_blockprofilerate
> 0) {
330 t0
= runtime_cputicks();
331 mysg
.releasetime
= -1;
341 sg
= dequeue(&c
->sendq
);
348 runtime_memmove(ep
, sg
->elem
, c
->elemsize
);
352 sg
->releasetime
= runtime_cputicks();
362 if(selected
!= nil
) {
370 mysg
.selgen
= NOSELGEN
;
372 enqueue(&c
->recvq
, &mysg
);
373 runtime_park(runtime_unlock
, c
, "chan receive");
375 if(g
->param
== nil
) {
378 runtime_throw("chanrecv: spurious wakeup");
384 if(mysg
.releasetime
> 0)
385 runtime_blockevent(mysg
.releasetime
- t0
, 2);
393 if(selected
!= nil
) {
402 mysg
.selgen
= NOSELGEN
;
403 enqueue(&c
->recvq
, &mysg
);
404 runtime_park(runtime_unlock
, c
, "chan receive");
411 runtime_raceacquire(chanbuf(c
, c
->recvx
));
414 runtime_memmove(ep
, chanbuf(c
, c
->recvx
), c
->elemsize
);
415 runtime_memclr(chanbuf(c
, c
->recvx
), c
->elemsize
);
416 if(++c
->recvx
== c
->dataqsiz
)
420 sg
= dequeue(&c
->sendq
);
425 sg
->releasetime
= runtime_cputicks();
434 if(mysg
.releasetime
> 0)
435 runtime_blockevent(mysg
.releasetime
- t0
, 2);
440 runtime_memclr(ep
, c
->elemsize
);
446 runtime_raceacquire(c
);
448 if(mysg
.releasetime
> 0)
449 runtime_blockevent(mysg
.releasetime
- t0
, 2);
452 // The compiler generates a call to __go_send_small to send a value 8
455 __go_send_small(ChanType
*t
, Hchan
* c
, uint64 val
)
459 byte b
[sizeof(uint64
)];
465 #ifndef WORDS_BIGENDIAN
468 p
= u
.b
+ sizeof(uint64
) - t
->__element_type
->__size
;
470 runtime_chansend(t
, c
, p
, nil
, runtime_getcallerpc(&t
));
473 // The compiler generates a call to __go_send_big to send a value
474 // larger than 8 bytes or smaller.
476 __go_send_big(ChanType
*t
, Hchan
* c
, byte
* p
)
478 runtime_chansend(t
, c
, p
, nil
, runtime_getcallerpc(&t
));
481 // The compiler generates a call to __go_receive_small to receive a
482 // value 8 bytes or smaller.
484 __go_receive_small(ChanType
*t
, Hchan
* c
)
487 byte b
[sizeof(uint64
)];
493 #ifndef WORDS_BIGENDIAN
496 p
= u
.b
+ sizeof(uint64
) - t
->__element_type
->__size
;
498 runtime_chanrecv(t
, c
, p
, nil
, nil
);
502 // The compiler generates a call to __go_receive_big to receive a
503 // value larger than 8 bytes.
505 __go_receive_big(ChanType
*t
, Hchan
* c
, byte
* p
)
507 runtime_chanrecv(t
, c
, p
, nil
, nil
);
510 _Bool
runtime_chanrecv2(ChanType
*t
, Hchan
* c
, byte
* p
)
511 __asm__("runtime.chanrecv2");
514 runtime_chanrecv2(ChanType
*t
, Hchan
* c
, byte
* p
)
518 runtime_chanrecv(t
, c
, p
, nil
, &received
);
522 // func selectnbsend(c chan any, elem any) bool
524 // compiler implements
535 // if selectnbsend(c, v) {
542 runtime_selectnbsend(ChanType
*t
, Hchan
*c
, byte
*p
)
546 runtime_chansend(t
, c
, p
, &res
, runtime_getcallerpc(&t
));
550 // func selectnbrecv(elem *any, c chan any) bool
552 // compiler implements
563 // if selectnbrecv(&v, c) {
570 runtime_selectnbrecv(ChanType
*t
, byte
*v
, Hchan
*c
)
574 runtime_chanrecv(t
, c
, v
, &selected
, nil
);
578 // func selectnbrecv2(elem *any, ok *bool, c chan any) bool
580 // compiler implements
591 // if c != nil && selectnbrecv2(&v, &ok, c) {
598 runtime_selectnbrecv2(ChanType
*t
, byte
*v
, _Bool
*received
, Hchan
*c
)
604 runtime_chanrecv(t
, c
, v
, &selected
, received
== nil
? nil
: &r
);
611 // func chansend(c chan, val iword, nb bool) (selected bool)
612 // where an iword is the same word an interface value would use:
613 // the actual data if it fits, or else a pointer to the data.
615 _Bool
reflect_chansend(ChanType
*, Hchan
*, uintptr
, _Bool
)
616 __asm__("reflect.chansend");
619 reflect_chansend(ChanType
*t
, Hchan
*c
, uintptr val
, _Bool nb
)
627 sp
= (bool*)&selected
;
632 if(__go_is_pointer_type(t
->__element_type
))
636 runtime_chansend(t
, c
, vp
, sp
, runtime_getcallerpc(&t
));
641 // func chanrecv(c chan, nb bool) (val iword, selected, received bool)
642 // where an iword is the same word an interface value would use:
643 // the actual data if it fits, or else a pointer to the data.
652 struct chanrecv_ret
reflect_chanrecv(ChanType
*, Hchan
*, _Bool
)
653 __asm__("reflect.chanrecv");
656 reflect_chanrecv(ChanType
*t
, Hchan
*c
, _Bool nb
)
658 struct chanrecv_ret ret
;
672 if(__go_is_pointer_type(t
->__element_type
)) {
673 vp
= (byte
*)&ret
.val
;
675 vp
= runtime_mal(t
->__element_type
->__size
);
676 ret
.val
= (uintptr
)vp
;
678 runtime_chanrecv(t
, c
, vp
, sp
, &received
);
680 ret
.selected
= selected
;
681 ret
.received
= received
;
685 static void newselect(int32
, Select
**);
687 // newselect(size uint32) (sel *byte);
689 void* runtime_newselect(int32
) __asm__("runtime.newselect");
692 runtime_newselect(int32 size
)
696 newselect(size
, &sel
);
701 newselect(int32 size
, Select
**selp
)
710 // allocate all the memory we need in a single allocation
711 // start with Select with size cases
712 // then lockorder with size entries
713 // then pollorder with size entries
714 sel
= runtime_mal(sizeof(*sel
) +
715 n
*sizeof(sel
->scase
[0]) +
716 size
*sizeof(sel
->lockorder
[0]) +
717 size
*sizeof(sel
->pollorder
[0]));
721 sel
->lockorder
= (void*)(sel
->scase
+ size
);
722 sel
->pollorder
= (void*)(sel
->lockorder
+ size
);
726 runtime_printf("newselect s=%p size=%d\n", sel
, size
);
729 // cut in half to give stack a chance to split
730 static void selectsend(Select
*sel
, Hchan
*c
, int index
, void *elem
);
732 // selectsend(sel *byte, hchan *chan any, elem *any) (selected bool);
734 void runtime_selectsend(Select
*, Hchan
*, void *, int32
)
735 __asm__("runtime.selectsend");
738 runtime_selectsend(Select
*sel
, Hchan
*c
, void *elem
, int32 index
)
740 // nil cases do not compete
744 selectsend(sel
, c
, index
, elem
);
748 selectsend(Select
*sel
, Hchan
*c
, int index
, void *elem
)
755 runtime_throw("selectsend: too many cases");
757 cas
= &sel
->scase
[i
];
761 cas
->kind
= CaseSend
;
765 runtime_printf("selectsend s=%p index=%d chan=%p\n",
766 sel
, cas
->index
, cas
->chan
);
769 // cut in half to give stack a chance to split
770 static void selectrecv(Select
*sel
, Hchan
*c
, int index
, void *elem
, bool*);
772 // selectrecv(sel *byte, hchan *chan any, elem *any) (selected bool);
774 void runtime_selectrecv(Select
*, Hchan
*, void *, int32
)
775 __asm__("runtime.selectrecv");
778 runtime_selectrecv(Select
*sel
, Hchan
*c
, void *elem
, int32 index
)
780 // nil cases do not compete
784 selectrecv(sel
, c
, index
, elem
, nil
);
787 // selectrecv2(sel *byte, hchan *chan any, elem *any, received *bool) (selected bool);
789 void runtime_selectrecv2(Select
*, Hchan
*, void *, bool *, int32
)
790 __asm__("runtime.selectrecv2");
793 runtime_selectrecv2(Select
*sel
, Hchan
*c
, void *elem
, bool *received
, int32 index
)
795 // nil cases do not compete
799 selectrecv(sel
, c
, index
, elem
, received
);
803 selectrecv(Select
*sel
, Hchan
*c
, int index
, void *elem
, bool *received
)
810 runtime_throw("selectrecv: too many cases");
812 cas
= &sel
->scase
[i
];
816 cas
->kind
= CaseRecv
;
818 cas
->receivedp
= received
;
821 runtime_printf("selectrecv s=%p index=%d chan=%p\n",
822 sel
, cas
->index
, cas
->chan
);
825 // cut in half to give stack a chance to split
826 static void selectdefault(Select
*, int);
828 // selectdefault(sel *byte) (selected bool);
830 void runtime_selectdefault(Select
*, int32
) __asm__("runtime.selectdefault");
833 runtime_selectdefault(Select
*sel
, int32 index
)
835 selectdefault(sel
, index
);
839 selectdefault(Select
*sel
, int32 index
)
846 runtime_throw("selectdefault: too many cases");
848 cas
= &sel
->scase
[i
];
852 cas
->kind
= CaseDefault
;
855 runtime_printf("selectdefault s=%p index=%d\n",
866 for(i
=0; i
<sel
->ncase
; i
++) {
867 c0
= sel
->lockorder
[i
];
869 c
= sel
->lockorder
[i
];
876 selunlock(Select
*sel
)
882 for(i
=sel
->ncase
; i
-->0;) {
883 c0
= sel
->lockorder
[i
];
894 runtime_park(nil
, nil
, "select (no cases)"); // forever
897 static int selectgo(Select
**);
899 // selectgo(sel *byte);
901 int runtime_selectgo(Select
*) __asm__("runtime.selectgo");
904 runtime_selectgo(Select
*sel
)
906 return selectgo(&sel
);
910 selectgo(Select
**selp
)
922 if(runtime_gcwaiting
)
926 runtime_printf("select: sel=%p\n", sel
);
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 for(i
=0; i
<sel
->ncase
; i
++) {
950 c
= sel
->scase
[i
].chan
;
951 for(j
=i
; j
>0 && sel
->lockorder
[j
-1] >= c
; j
--)
952 sel
->lockorder
[j
] = sel
->lockorder
[j
-1];
953 sel
->lockorder
[j
] = c
;
958 // pass 1 - look for something already waiting
960 for(i
=0; i
<sel
->ncase
; i
++) {
961 o
= sel
->pollorder
[i
];
962 cas
= &sel
->scase
[o
];
967 if(c
->dataqsiz
> 0) {
971 sg
= dequeue(&c
->sendq
);
982 if(c
->dataqsiz
> 0) {
983 if(c
->qcount
< c
->dataqsiz
)
986 sg
= dequeue(&c
->recvq
);
1005 // pass 2 - enqueue on all chans
1006 for(i
=0; i
<sel
->ncase
; i
++) {
1007 o
= sel
->pollorder
[i
];
1008 cas
= &sel
->scase
[o
];
1012 sg
->selgen
= g
->selgen
;
1016 enqueue(&c
->recvq
, sg
);
1020 enqueue(&c
->sendq
, sg
);
1026 runtime_park((void(*)(Lock
*))selunlock
, (Lock
*)sel
, "select");
1031 // pass 3 - dequeue from unsuccessful chans
1032 // otherwise they stack up on quiet channels
1033 for(i
=0; i
<sel
->ncase
; i
++) {
1034 cas
= &sel
->scase
[i
];
1035 if(cas
!= (Scase
*)sg
) {
1037 if(cas
->kind
== CaseSend
)
1038 dequeueg(&c
->sendq
);
1040 dequeueg(&c
->recvq
);
1051 runtime_throw("selectgo: shouldnt happen");
1054 runtime_printf("wait-return: sel=%p c=%p cas=%p kind=%d\n",
1055 sel
, c
, cas
, cas
->kind
);
1057 if(cas
->kind
== CaseRecv
) {
1058 if(cas
->receivedp
!= nil
)
1059 *cas
->receivedp
= true;
1066 // can receive from buffer
1068 runtime_raceacquire(chanbuf(c
, c
->recvx
));
1069 if(cas
->receivedp
!= nil
)
1070 *cas
->receivedp
= true;
1071 if(cas
->sg
.elem
!= nil
)
1072 runtime_memmove(cas
->sg
.elem
, chanbuf(c
, c
->recvx
), c
->elemsize
);
1073 runtime_memclr(chanbuf(c
, c
->recvx
), c
->elemsize
);
1074 if(++c
->recvx
== c
->dataqsiz
)
1077 sg
= dequeue(&c
->sendq
);
1088 // can send to buffer
1090 runtime_racerelease(chanbuf(c
, c
->sendx
));
1091 runtime_memmove(chanbuf(c
, c
->sendx
), cas
->sg
.elem
, c
->elemsize
);
1092 if(++c
->sendx
== c
->dataqsiz
)
1095 sg
= dequeue(&c
->recvq
);
1106 // can receive from sleeping sender (sg)
1111 runtime_printf("syncrecv: sel=%p c=%p o=%d\n", sel
, c
, o
);
1112 if(cas
->receivedp
!= nil
)
1113 *cas
->receivedp
= true;
1114 if(cas
->sg
.elem
!= nil
)
1115 runtime_memmove(cas
->sg
.elem
, sg
->elem
, c
->elemsize
);
1122 // read at end of closed channel
1124 if(cas
->receivedp
!= nil
)
1125 *cas
->receivedp
= false;
1126 if(cas
->sg
.elem
!= nil
)
1127 runtime_memclr(cas
->sg
.elem
, c
->elemsize
);
1129 runtime_raceacquire(c
);
1133 // can send to sleeping receiver (sg)
1138 runtime_printf("syncsend: sel=%p c=%p o=%d\n", sel
, c
, o
);
1140 runtime_memmove(sg
->elem
, cas
->sg
.elem
, c
->elemsize
);
1146 // return index corresponding to chosen case
1152 // send on closed channel
1154 runtime_panicstring("send on closed channel");
1155 return 0; // not reached
1158 // This struct must match ../reflect/value.go:/runtimeSelect.
1159 typedef struct runtimeSelect runtimeSelect
;
1160 struct runtimeSelect
1168 // This enum must match ../reflect/value.go:/SelectDir.
1175 struct rselect_ret
{
1181 // func rselect(cases []runtimeSelect) (chosen int, word uintptr, recvOK bool)
1183 struct rselect_ret
reflect_rselect(Slice
)
1184 asm("reflect.rselect");
1187 reflect_rselect(Slice cases
)
1189 struct rselect_ret ret
;
1192 runtimeSelect
* rcase
, *rc
;
1204 rcase
= (runtimeSelect
*)cases
.__values
;
1205 for(i
=0; i
<cases
.__count
; i
++) {
1207 if(rc
->dir
== SelectRecv
&& rc
->ch
!= nil
) {
1208 if(maxsize
< rc
->typ
->__element_type
->__size
)
1209 maxsize
= rc
->typ
->__element_type
->__size
;
1210 if(!__go_is_pointer_type(rc
->typ
->__element_type
))
1217 recvptr
= runtime_mal(maxsize
);
1219 newselect(cases
.__count
, &sel
);
1220 for(i
=0; i
<cases
.__count
; i
++) {
1224 selectdefault(sel
, i
);
1229 if(!__go_is_pointer_type(rc
->typ
->__element_type
))
1230 elem
= (void*)rc
->val
;
1232 elem
= (void*)&rc
->val
;
1233 selectsend(sel
, rc
->ch
, i
, elem
);
1238 if(!__go_is_pointer_type(rc
->typ
->__element_type
))
1242 selectrecv(sel
, rc
->ch
, i
, elem
, &ret
.recvOK
);
1247 ret
.chosen
= (intgo
)(uintptr
)selectgo(&sel
);
1248 if(rcase
[ret
.chosen
].dir
== SelectRecv
&& !__go_is_pointer_type(rcase
[ret
.chosen
].typ
->__element_type
))
1249 ret
.word
= (uintptr
)recvptr
;
1254 // closechan(sel *byte);
1256 runtime_closechan(Hchan
*c
)
1262 runtime_panicstring("close of nil channel");
1264 if(runtime_gcwaiting
)
1270 runtime_panicstring("close of closed channel");
1274 runtime_racewritepc(c
, runtime_getcallerpc(&c
), runtime_closechan
);
1275 runtime_racerelease(c
);
1280 // release all readers
1282 sg
= dequeue(&c
->recvq
);
1290 // release all writers
1292 sg
= dequeue(&c
->sendq
);
1304 __go_builtin_close(Hchan
*c
)
1306 runtime_closechan(c
);
1310 // func chanclose(c chan)
1312 void reflect_chanclose(uintptr
) __asm__("reflect.chanclose");
1315 reflect_chanclose(uintptr c
)
1317 runtime_closechan((Hchan
*)c
);
1321 // func chanlen(c chan) (len int)
1323 intgo
reflect_chanlen(uintptr
) __asm__("reflect.chanlen");
1326 reflect_chanlen(uintptr ca
)
1340 __go_chan_len(Hchan
*c
)
1342 return reflect_chanlen((uintptr
)c
);
1346 // func chancap(c chan) (cap intgo)
1348 intgo
reflect_chancap(uintptr
) __asm__("reflect.chancap");
1351 reflect_chancap(uintptr ca
)
1365 __go_chan_cap(Hchan
*c
)
1367 return reflect_chancap((uintptr
)c
);
1379 q
->first
= sgp
->link
;
1381 // if sgp is stale, ignore it
1382 if(sgp
->selgen
!= NOSELGEN
&&
1383 (sgp
->selgen
!= sgp
->g
->selgen
||
1384 !runtime_cas(&sgp
->g
->selgen
, sgp
->selgen
, sgp
->selgen
+ 2))) {
1385 //prints("INVALID PSEUDOG POINTER\n");
1395 SudoG
**l
, *sgp
, *prevsgp
;
1400 for(l
=&q
->first
; (sgp
=*l
) != nil
; l
=&sgp
->link
, prevsgp
=sgp
) {
1411 enqueue(WaitQ
*q
, SudoG
*sgp
)
1414 if(q
->first
== nil
) {
1419 q
->last
->link
= sgp
;
1424 racesync(Hchan
*c
, SudoG
*sg
)
1426 runtime_racerelease(chanbuf(c
, 0));
1427 runtime_raceacquireg(sg
->g
, chanbuf(c
, 0));
1428 runtime_racereleaseg(sg
->g
, chanbuf(c
, 0));
1429 runtime_raceacquire(chanbuf(c
, 0));