// func selectnbsend(c chan any, elem *any) bool // // compiler implements // // select { // case c <- v: // ... foo // default: // ... bar // } // // as // // if selectnbsend(c, v) { // ... foo // } else { // ... bar // } // _Bool runtime_selectnbsend(ChanType *t, Hchan *c, byte *val) { bool res; res = chansend(t, c, val, false, runtime_getcallerpc(&t)); return (_Bool)res; }
_Bool reflect_chansend(ChanType *t, Hchan *c, byte *val, _Bool nb) { bool selected; selected = chansend(t, c, val, !nb, runtime_getcallerpc(&t)); return (_Bool)selected; }
// func selectnbsend(c chan any, elem any) bool // // compiler implements // // select { // case c <- v: // ... foo // default: // ... bar // } // // as // // if selectnbsend(c, v) { // ... foo // } else { // ... bar // } // _Bool runtime_selectnbsend(ChanType *t, Hchan *c, byte *p) { bool res; runtime_chansend(t, c, p, &res, runtime_getcallerpc(&t)); return res; }
// The compiler generates a call to __go_send_small to send a value 8 // bytes or smaller. void __go_send_small(ChanType *t, Hchan* c, uint64 val) { union { byte b[sizeof(uint64)]; uint64 v; } u; byte *v; u.v = val; #ifndef WORDS_BIGENDIAN v = u.b; #else v = u.b + sizeof(uint64) - t->__element_type->__size; #endif chansend(t, c, v, true, runtime_getcallerpc(&t)); }
_Bool reflect_chansend(ChanType *t, Hchan *c, uintptr val, _Bool nb) { bool selected; bool *sp; byte *vp; if(nb) { selected = false; sp = (bool*)&selected; } else { selected = true; sp = nil; } if(__go_is_pointer_type(t->__element_type)) vp = (byte*)&val; else vp = (byte*)val; runtime_chansend(t, c, vp, sp, runtime_getcallerpc(&t)); return selected; }
// The compiler generates a call to __go_send_big to send a value // larger than 8 bytes or smaller. void __go_send_big(ChanType *t, Hchan* c, byte* v) { chansend(t, c, v, true, runtime_getcallerpc(&t)); }
/* * generic single channel send/recv * if the bool pointer is nil, * then the full exchange will * occur. if pres is not nil, * then the protocol will not * sleep but return if it could * not complete. * * sleep can wake up with g->param == nil * when a channel involved in the sleep has * been closed. it is easiest to loop and re-run * the operation; we'll see that it's now closed. */ static bool chansend(ChanType *t, Hchan *c, byte *ep, bool block, void *pc) { SudoG *sg; SudoG mysg; G* gp; int64 t0; G* g; g = runtime_g(); if(raceenabled) runtime_racereadobjectpc(ep, t->__element_type, runtime_getcallerpc(&t), chansend); if(c == nil) { USED(t); if(!block) return false; runtime_park(nil, nil, "chan send (nil chan)"); return false; // not reached } if(runtime_gcwaiting()) runtime_gosched(); if(debug) { runtime_printf("chansend: chan=%p\n", c); } t0 = 0; mysg.releasetime = 0; if(runtime_blockprofilerate > 0) { t0 = runtime_cputicks(); mysg.releasetime = -1; } runtime_lock(c); if(raceenabled) runtime_racereadpc(c, pc, chansend); if(c->closed) goto closed; if(c->dataqsiz > 0) goto asynch; sg = dequeue(&c->recvq); if(sg != nil) { if(raceenabled) racesync(c, sg); runtime_unlock(c); gp = sg->g; gp->param = sg; if(sg->elem != nil) runtime_memmove(sg->elem, ep, c->elemsize); if(sg->releasetime) sg->releasetime = runtime_cputicks(); runtime_ready(gp); return true; } if(!block) { runtime_unlock(c); return false; } mysg.elem = ep; mysg.g = g; mysg.selectdone = nil; g->param = nil; enqueue(&c->sendq, &mysg); runtime_parkunlock(c, "chan send"); if(g->param == nil) { runtime_lock(c); if(!c->closed) runtime_throw("chansend: spurious wakeup"); goto closed; } if(mysg.releasetime > 0) runtime_blockevent(mysg.releasetime - t0, 2); return true; asynch: if(c->closed) goto closed; if(c->qcount >= c->dataqsiz) { if(!block) { runtime_unlock(c); return false; } mysg.g = g; mysg.elem = nil; mysg.selectdone = nil; enqueue(&c->sendq, &mysg); runtime_parkunlock(c, "chan send"); runtime_lock(c); goto asynch; } if(raceenabled) runtime_racerelease(chanbuf(c, c->sendx)); runtime_memmove(chanbuf(c, c->sendx), ep, c->elemsize); if(++c->sendx == c->dataqsiz) c->sendx = 0; c->qcount++; sg = dequeue(&c->recvq); if(sg != nil) { gp = sg->g; runtime_unlock(c); if(sg->releasetime) sg->releasetime = runtime_cputicks(); runtime_ready(gp); } else runtime_unlock(c); if(mysg.releasetime > 0) runtime_blockevent(mysg.releasetime - t0, 2); return true; closed: runtime_unlock(c); runtime_panicstring("send on closed channel"); return false; // not reached }
runtime_printhex(va_arg(va, uint64)); break; } lp = p+1; } if(p > lp) gwrite(lp, p-lp); //runtime_unlock(&debuglock); } void runtime_printpc(void *p __attribute__ ((unused))) { runtime_prints("PC="); runtime_printhex((uint64)(uintptr)runtime_getcallerpc(p)); } void runtime_printbool(_Bool v) { if(v) { gwrite("true", 4); return; } gwrite("false", 5); } void runtime_printbyte(int8 c) {
// The compiler generates a call to __go_send_big to send a value // larger than 8 bytes or smaller. void __go_send_big(ChanType *t, Hchan* c, byte* p) { runtime_chansend(t, c, p, nil, runtime_getcallerpc(&t)); }