github.com/c0deoo1/golang1.5@v0.0.0-20220525150107-c87c805d4593/src/runtime/select.go (about)

     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.
     4  
     5  package runtime
     6  
     7  // This file contains the implementation of Go select statements.
     8  
     9  import "unsafe"
    10  
    11  const (
    12  	debugSelect = false
    13  
    14  	// scase.kind
    15  	caseRecv = iota
    16  	caseSend
    17  	caseDefault
    18  )
    19  
    20  // Select statement header.
    21  // Known to compiler.
    22  // Changes here must also be made in src/cmd/internal/gc/select.go's selecttype.
    23  type hselect struct {
    24  	tcase     uint16   // total count of scase[]
    25  	ncase     uint16   // currently filled scase[]
    26  	pollorder *uint16  // case poll order
    27  	lockorder **hchan  // channel lock order
    28  	scase     [1]scase // one per case (in order of appearance)
    29  }
    30  
    31  // Select case descriptor.
    32  // Known to compiler.
    33  // Changes here must also be made in src/cmd/internal/gc/select.go's selecttype.
    34  type scase struct {
    35  	elem        unsafe.Pointer // data element
    36  	c           *hchan         // chan
    37  	pc          uintptr        // return pc
    38  	kind        uint16
    39  	so          uint16 // vararg of selected bool
    40  	receivedp   *bool  // pointer to received bool (recv2)
    41  	releasetime int64
    42  }
    43  
    44  var (
    45  	chansendpc = funcPC(chansend)
    46  	chanrecvpc = funcPC(chanrecv)
    47  )
    48  
    49  func selectsize(size uintptr) uintptr {
    50  	selsize := unsafe.Sizeof(hselect{}) +
    51  		(size-1)*unsafe.Sizeof(hselect{}.scase[0]) +
    52  		size*unsafe.Sizeof(*hselect{}.lockorder) +
    53  		size*unsafe.Sizeof(*hselect{}.pollorder)
    54  	return round(selsize, _Int64Align)
    55  }
    56  
    57  func newselect(sel *hselect, selsize int64, size int32) {
    58  	if selsize != int64(selectsize(uintptr(size))) {
    59  		print("runtime: bad select size ", selsize, ", want ", selectsize(uintptr(size)), "\n")
    60  		throw("bad select size")
    61  	}
    62  	sel.tcase = uint16(size)
    63  	sel.ncase = 0
    64  	sel.lockorder = (**hchan)(add(unsafe.Pointer(&sel.scase), uintptr(size)*unsafe.Sizeof(hselect{}.scase[0])))
    65  	sel.pollorder = (*uint16)(add(unsafe.Pointer(sel.lockorder), uintptr(size)*unsafe.Sizeof(*hselect{}.lockorder)))
    66  
    67  	if debugSelect {
    68  		print("newselect s=", sel, " size=", size, "\n")
    69  	}
    70  }
    71  
    72  //go:nosplit
    73  func selectsend(sel *hselect, c *hchan, elem unsafe.Pointer) (selected bool) {
    74  	// nil cases do not compete
    75  	if c != nil {
    76  		selectsendImpl(sel, c, getcallerpc(unsafe.Pointer(&sel)), elem, uintptr(unsafe.Pointer(&selected))-uintptr(unsafe.Pointer(&sel)))
    77  	}
    78  	return
    79  }
    80  
    81  // cut in half to give stack a chance to split
    82  func selectsendImpl(sel *hselect, c *hchan, pc uintptr, elem unsafe.Pointer, so uintptr) {
    83  	i := sel.ncase
    84  	if i >= sel.tcase {
    85  		throw("selectsend: too many cases")
    86  	}
    87  	sel.ncase = i + 1
    88  	cas := (*scase)(add(unsafe.Pointer(&sel.scase), uintptr(i)*unsafe.Sizeof(sel.scase[0])))
    89  
    90  	cas.pc = pc
    91  	cas.c = c
    92  	cas.so = uint16(so)
    93  	cas.kind = caseSend
    94  	cas.elem = elem
    95  
    96  	if debugSelect {
    97  		print("selectsend s=", sel, " pc=", hex(cas.pc), " chan=", cas.c, " so=", cas.so, "\n")
    98  	}
    99  }
   100  
   101  //go:nosplit
   102  func selectrecv(sel *hselect, c *hchan, elem unsafe.Pointer) (selected bool) {
   103  	// nil cases do not compete
   104  	if c != nil {
   105  		selectrecvImpl(sel, c, getcallerpc(unsafe.Pointer(&sel)), elem, nil, uintptr(unsafe.Pointer(&selected))-uintptr(unsafe.Pointer(&sel)))
   106  	}
   107  	return
   108  }
   109  
   110  //go:nosplit
   111  func selectrecv2(sel *hselect, c *hchan, elem unsafe.Pointer, received *bool) (selected bool) {
   112  	// nil cases do not compete
   113  	if c != nil {
   114  		selectrecvImpl(sel, c, getcallerpc(unsafe.Pointer(&sel)), elem, received, uintptr(unsafe.Pointer(&selected))-uintptr(unsafe.Pointer(&sel)))
   115  	}
   116  	return
   117  }
   118  
   119  func selectrecvImpl(sel *hselect, c *hchan, pc uintptr, elem unsafe.Pointer, received *bool, so uintptr) {
   120  	i := sel.ncase
   121  	if i >= sel.tcase {
   122  		throw("selectrecv: too many cases")
   123  	}
   124  	sel.ncase = i + 1
   125  	cas := (*scase)(add(unsafe.Pointer(&sel.scase), uintptr(i)*unsafe.Sizeof(sel.scase[0])))
   126  	cas.pc = pc
   127  	cas.c = c
   128  	cas.so = uint16(so)
   129  	cas.kind = caseRecv
   130  	cas.elem = elem
   131  	cas.receivedp = received
   132  
   133  	if debugSelect {
   134  		print("selectrecv s=", sel, " pc=", hex(cas.pc), " chan=", cas.c, " so=", cas.so, "\n")
   135  	}
   136  }
   137  
   138  //go:nosplit
   139  func selectdefault(sel *hselect) (selected bool) {
   140  	selectdefaultImpl(sel, getcallerpc(unsafe.Pointer(&sel)), uintptr(unsafe.Pointer(&selected))-uintptr(unsafe.Pointer(&sel)))
   141  	return
   142  }
   143  
   144  func selectdefaultImpl(sel *hselect, callerpc uintptr, so uintptr) {
   145  	i := sel.ncase
   146  	if i >= sel.tcase {
   147  		throw("selectdefault: too many cases")
   148  	}
   149  	sel.ncase = i + 1
   150  	cas := (*scase)(add(unsafe.Pointer(&sel.scase), uintptr(i)*unsafe.Sizeof(sel.scase[0])))
   151  	cas.pc = callerpc
   152  	cas.c = nil
   153  	cas.so = uint16(so)
   154  	cas.kind = caseDefault
   155  
   156  	if debugSelect {
   157  		print("selectdefault s=", sel, " pc=", hex(cas.pc), " so=", cas.so, "\n")
   158  	}
   159  }
   160  
   161  func sellock(sel *hselect) {
   162  	lockslice := slice{unsafe.Pointer(sel.lockorder), int(sel.ncase), int(sel.ncase)}
   163  	lockorder := *(*[]*hchan)(unsafe.Pointer(&lockslice))
   164  	var c *hchan
   165  	for _, c0 := range lockorder {
   166  		if c0 != nil && c0 != c {
   167  			c = c0
   168  			lock(&c.lock)
   169  		}
   170  	}
   171  }
   172  
   173  func selunlock(sel *hselect) {
   174  	// We must be very careful here to not touch sel after we have unlocked
   175  	// the last lock, because sel can be freed right after the last unlock.
   176  	// Consider the following situation.
   177  	// First M calls runtime·park() in runtime·selectgo() passing the sel.
   178  	// Once runtime·park() has unlocked the last lock, another M makes
   179  	// the G that calls select runnable again and schedules it for execution.
   180  	// When the G runs on another M, it locks all the locks and frees sel.
   181  	// Now if the first M touches sel, it will access freed memory.
   182  	n := int(sel.ncase)
   183  	r := 0
   184  	lockslice := slice{unsafe.Pointer(sel.lockorder), n, n}
   185  	lockorder := *(*[]*hchan)(unsafe.Pointer(&lockslice))
   186  	// skip the default case
   187  	if n > 0 && lockorder[0] == nil {
   188  		r = 1
   189  	}
   190  	for i := n - 1; i >= r; i-- {
   191  		c := lockorder[i]
   192  		if i > 0 && c == lockorder[i-1] {
   193  			continue // will unlock it on the next iteration
   194  		}
   195  		unlock(&c.lock)
   196  	}
   197  }
   198  
   199  func selparkcommit(gp *g, sel unsafe.Pointer) bool {
   200  	selunlock((*hselect)(sel))
   201  	return true
   202  }
   203  
   204  func block() {
   205  	gopark(nil, nil, "select (no cases)", traceEvGoStop, 1) // forever
   206  }
   207  
   208  // overwrites return pc on stack to signal which case of the select
   209  // to run, so cannot appear at the top of a split stack.
   210  //go:nosplit
   211  func selectgo(sel *hselect) {
   212  	pc, offset := selectgoImpl(sel)
   213  	*(*bool)(add(unsafe.Pointer(&sel), uintptr(offset))) = true
   214  	setcallerpc(unsafe.Pointer(&sel), pc)
   215  }
   216  
   217  // selectgoImpl returns scase.pc and scase.so for the select
   218  // case which fired.
   219  func selectgoImpl(sel *hselect) (uintptr, uint16) {
   220  	if debugSelect {
   221  		print("select: sel=", sel, "\n")
   222  	}
   223  
   224  	scaseslice := slice{unsafe.Pointer(&sel.scase), int(sel.ncase), int(sel.ncase)}
   225  	scases := *(*[]scase)(unsafe.Pointer(&scaseslice))
   226  
   227  	var t0 int64
   228  	if blockprofilerate > 0 {
   229  		t0 = cputicks()
   230  		for i := 0; i < int(sel.ncase); i++ {
   231  			scases[i].releasetime = -1
   232  		}
   233  	}
   234  
   235  	// The compiler rewrites selects that statically have
   236  	// only 0 or 1 cases plus default into simpler constructs.
   237  	// The only way we can end up with such small sel.ncase
   238  	// values here is for a larger select in which most channels
   239  	// have been nilled out.  The general code handles those
   240  	// cases correctly, and they are rare enough not to bother
   241  	// optimizing (and needing to test).
   242  
   243  	// generate permuted order
   244  	pollslice := slice{unsafe.Pointer(sel.pollorder), int(sel.ncase), int(sel.ncase)}
   245  	pollorder := *(*[]uint16)(unsafe.Pointer(&pollslice))
   246  	for i := 1; i < int(sel.ncase); i++ {
   247  		j := int(fastrand1()) % (i + 1)
   248  		pollorder[i] = pollorder[j]
   249  		pollorder[j] = uint16(i)
   250  	}
   251  
   252  	// sort the cases by Hchan address to get the locking order.
   253  	// simple heap sort, to guarantee n log n time and constant stack footprint.
   254  	lockslice := slice{unsafe.Pointer(sel.lockorder), int(sel.ncase), int(sel.ncase)}
   255  	lockorder := *(*[]*hchan)(unsafe.Pointer(&lockslice))
   256  	for i := 0; i < int(sel.ncase); i++ {
   257  		j := i
   258  		c := scases[j].c
   259  		for j > 0 && lockorder[(j-1)/2].sortkey() < c.sortkey() {
   260  			k := (j - 1) / 2
   261  			lockorder[j] = lockorder[k]
   262  			j = k
   263  		}
   264  		lockorder[j] = c
   265  	}
   266  	for i := int(sel.ncase) - 1; i >= 0; i-- {
   267  		c := lockorder[i]
   268  		lockorder[i] = lockorder[0]
   269  		j := 0
   270  		for {
   271  			k := j*2 + 1
   272  			if k >= i {
   273  				break
   274  			}
   275  			if k+1 < i && lockorder[k].sortkey() < lockorder[k+1].sortkey() {
   276  				k++
   277  			}
   278  			if c.sortkey() < lockorder[k].sortkey() {
   279  				lockorder[j] = lockorder[k]
   280  				j = k
   281  				continue
   282  			}
   283  			break
   284  		}
   285  		lockorder[j] = c
   286  	}
   287  	/*
   288  		for i := 0; i+1 < int(sel.ncase); i++ {
   289  			if lockorder[i].sortkey() > lockorder[i+1].sortkey() {
   290  				print("i=", i, " x=", lockorder[i], " y=", lockorder[i+1], "\n")
   291  				throw("select: broken sort")
   292  			}
   293  		}
   294  	*/
   295  
   296  	// lock all the channels involved in the select
   297  	sellock(sel)
   298  
   299  	var (
   300  		gp     *g
   301  		done   uint32
   302  		sg     *sudog
   303  		c      *hchan
   304  		k      *scase
   305  		sglist *sudog
   306  		sgnext *sudog
   307  		futile byte
   308  	)
   309  
   310  loop:
   311  	// pass 1 - look for something already waiting
   312  	var dfl *scase
   313  	var cas *scase
   314  	for i := 0; i < int(sel.ncase); i++ {
   315  		cas = &scases[pollorder[i]]
   316  		c = cas.c
   317  
   318  		switch cas.kind {
   319  		case caseRecv:
   320  			if c.dataqsiz > 0 {
   321  				if c.qcount > 0 {
   322  					goto asyncrecv
   323  				}
   324  			} else {
   325  				sg = c.sendq.dequeue()
   326  				if sg != nil {
   327  					goto syncrecv
   328  				}
   329  			}
   330  			if c.closed != 0 {
   331  				goto rclose
   332  			}
   333  
   334  		case caseSend:
   335  			if raceenabled {
   336  				racereadpc(unsafe.Pointer(c), cas.pc, chansendpc)
   337  			}
   338  			if c.closed != 0 {
   339  				goto sclose
   340  			}
   341  			if c.dataqsiz > 0 {
   342  				if c.qcount < c.dataqsiz {
   343  					goto asyncsend
   344  				}
   345  			} else {
   346  				sg = c.recvq.dequeue()
   347  				if sg != nil {
   348  					goto syncsend
   349  				}
   350  			}
   351  
   352  		case caseDefault:
   353  			dfl = cas
   354  		}
   355  	}
   356  
   357  	if dfl != nil {
   358  		selunlock(sel)
   359  		cas = dfl
   360  		goto retc
   361  	}
   362  
   363  	// pass 2 - enqueue on all chans
   364  	gp = getg()
   365  	done = 0
   366  	for i := 0; i < int(sel.ncase); i++ {
   367  		cas = &scases[pollorder[i]]
   368  		c = cas.c
   369  		sg := acquireSudog()
   370  		sg.g = gp
   371  		// Note: selectdone is adjusted for stack copies in stack1.go:adjustsudogs
   372  		sg.selectdone = (*uint32)(noescape(unsafe.Pointer(&done)))
   373  		sg.elem = cas.elem
   374  		sg.releasetime = 0
   375  		if t0 != 0 {
   376  			sg.releasetime = -1
   377  		}
   378  		sg.waitlink = gp.waiting
   379  		gp.waiting = sg
   380  
   381  		switch cas.kind {
   382  		case caseRecv:
   383  			c.recvq.enqueue(sg)
   384  
   385  		case caseSend:
   386  			c.sendq.enqueue(sg)
   387  		}
   388  	}
   389  
   390  	// wait for someone to wake us up
   391  	gp.param = nil
   392  	gopark(selparkcommit, unsafe.Pointer(sel), "select", traceEvGoBlockSelect|futile, 2)
   393  
   394  	// someone woke us up
   395  	sellock(sel)
   396  	sg = (*sudog)(gp.param)
   397  	gp.param = nil
   398  
   399  	// pass 3 - dequeue from unsuccessful chans
   400  	// otherwise they stack up on quiet channels
   401  	// record the successful case, if any.
   402  	// We singly-linked up the SudoGs in case order, so when
   403  	// iterating through the linked list they are in reverse order.
   404  	cas = nil
   405  	sglist = gp.waiting
   406  	// Clear all elem before unlinking from gp.waiting.
   407  	for sg1 := gp.waiting; sg1 != nil; sg1 = sg1.waitlink {
   408  		sg1.selectdone = nil
   409  		sg1.elem = nil
   410  	}
   411  	gp.waiting = nil
   412  	for i := int(sel.ncase) - 1; i >= 0; i-- {
   413  		k = &scases[pollorder[i]]
   414  		if sglist.releasetime > 0 {
   415  			k.releasetime = sglist.releasetime
   416  		}
   417  		if sg == sglist {
   418  			// sg has already been dequeued by the G that woke us up.
   419  			cas = k
   420  		} else {
   421  			c = k.c
   422  			if k.kind == caseSend {
   423  				c.sendq.dequeueSudoG(sglist)
   424  			} else {
   425  				c.recvq.dequeueSudoG(sglist)
   426  			}
   427  		}
   428  		sgnext = sglist.waitlink
   429  		sglist.waitlink = nil
   430  		releaseSudog(sglist)
   431  		sglist = sgnext
   432  	}
   433  
   434  	if cas == nil {
   435  		futile = traceFutileWakeup
   436  		goto loop
   437  	}
   438  
   439  	c = cas.c
   440  
   441  	if c.dataqsiz > 0 {
   442  		throw("selectgo: shouldn't happen")
   443  	}
   444  
   445  	if debugSelect {
   446  		print("wait-return: sel=", sel, " c=", c, " cas=", cas, " kind=", cas.kind, "\n")
   447  	}
   448  
   449  	if cas.kind == caseRecv {
   450  		if cas.receivedp != nil {
   451  			*cas.receivedp = true
   452  		}
   453  	}
   454  
   455  	if raceenabled {
   456  		if cas.kind == caseRecv && cas.elem != nil {
   457  			raceWriteObjectPC(c.elemtype, cas.elem, cas.pc, chanrecvpc)
   458  		} else if cas.kind == caseSend {
   459  			raceReadObjectPC(c.elemtype, cas.elem, cas.pc, chansendpc)
   460  		}
   461  	}
   462  
   463  	selunlock(sel)
   464  	goto retc
   465  
   466  asyncrecv:
   467  	// can receive from buffer
   468  	if raceenabled {
   469  		if cas.elem != nil {
   470  			raceWriteObjectPC(c.elemtype, cas.elem, cas.pc, chanrecvpc)
   471  		}
   472  		raceacquire(chanbuf(c, c.recvx))
   473  		racerelease(chanbuf(c, c.recvx))
   474  	}
   475  	if cas.receivedp != nil {
   476  		*cas.receivedp = true
   477  	}
   478  	if cas.elem != nil {
   479  		typedmemmove(c.elemtype, cas.elem, chanbuf(c, c.recvx))
   480  	}
   481  	memclr(chanbuf(c, c.recvx), uintptr(c.elemsize))
   482  	c.recvx++
   483  	if c.recvx == c.dataqsiz {
   484  		c.recvx = 0
   485  	}
   486  	c.qcount--
   487  	sg = c.sendq.dequeue()
   488  	if sg != nil {
   489  		gp = sg.g
   490  		selunlock(sel)
   491  		if sg.releasetime != 0 {
   492  			sg.releasetime = cputicks()
   493  		}
   494  		goready(gp, 3)
   495  	} else {
   496  		selunlock(sel)
   497  	}
   498  	goto retc
   499  
   500  asyncsend:
   501  	// can send to buffer
   502  	if raceenabled {
   503  		raceacquire(chanbuf(c, c.sendx))
   504  		racerelease(chanbuf(c, c.sendx))
   505  		raceReadObjectPC(c.elemtype, cas.elem, cas.pc, chansendpc)
   506  	}
   507  	typedmemmove(c.elemtype, chanbuf(c, c.sendx), cas.elem)
   508  	c.sendx++
   509  	if c.sendx == c.dataqsiz {
   510  		c.sendx = 0
   511  	}
   512  	c.qcount++
   513  	sg = c.recvq.dequeue()
   514  	if sg != nil {
   515  		gp = sg.g
   516  		selunlock(sel)
   517  		if sg.releasetime != 0 {
   518  			sg.releasetime = cputicks()
   519  		}
   520  		goready(gp, 3)
   521  	} else {
   522  		selunlock(sel)
   523  	}
   524  	goto retc
   525  
   526  syncrecv:
   527  	// can receive from sleeping sender (sg)
   528  	if raceenabled {
   529  		if cas.elem != nil {
   530  			raceWriteObjectPC(c.elemtype, cas.elem, cas.pc, chanrecvpc)
   531  		}
   532  		racesync(c, sg)
   533  	}
   534  	selunlock(sel)
   535  	if debugSelect {
   536  		print("syncrecv: sel=", sel, " c=", c, "\n")
   537  	}
   538  	if cas.receivedp != nil {
   539  		*cas.receivedp = true
   540  	}
   541  	if cas.elem != nil {
   542  		typedmemmove(c.elemtype, cas.elem, sg.elem)
   543  	}
   544  	sg.elem = nil
   545  	gp = sg.g
   546  	gp.param = unsafe.Pointer(sg)
   547  	if sg.releasetime != 0 {
   548  		sg.releasetime = cputicks()
   549  	}
   550  	goready(gp, 3)
   551  	goto retc
   552  
   553  rclose:
   554  	// read at end of closed channel
   555  	selunlock(sel)
   556  	if cas.receivedp != nil {
   557  		*cas.receivedp = false
   558  	}
   559  	if cas.elem != nil {
   560  		memclr(cas.elem, uintptr(c.elemsize))
   561  	}
   562  	if raceenabled {
   563  		raceacquire(unsafe.Pointer(c))
   564  	}
   565  	goto retc
   566  
   567  syncsend:
   568  	// can send to sleeping receiver (sg)
   569  	if raceenabled {
   570  		raceReadObjectPC(c.elemtype, cas.elem, cas.pc, chansendpc)
   571  		racesync(c, sg)
   572  	}
   573  	selunlock(sel)
   574  	if debugSelect {
   575  		print("syncsend: sel=", sel, " c=", c, "\n")
   576  	}
   577  	if sg.elem != nil {
   578  		syncsend(c, sg, cas.elem)
   579  	}
   580  	sg.elem = nil
   581  	gp = sg.g
   582  	gp.param = unsafe.Pointer(sg)
   583  	if sg.releasetime != 0 {
   584  		sg.releasetime = cputicks()
   585  	}
   586  	goready(gp, 3)
   587  
   588  retc:
   589  	if cas.releasetime > 0 {
   590  		blockevent(cas.releasetime-t0, 2)
   591  	}
   592  	return cas.pc, cas.so
   593  
   594  sclose:
   595  	// send on closed channel
   596  	selunlock(sel)
   597  	panic("send on closed channel")
   598  }
   599  
   600  func (c *hchan) sortkey() uintptr {
   601  	// TODO(khr): if we have a moving garbage collector, we'll need to
   602  	// change this function.
   603  	return uintptr(unsafe.Pointer(c))
   604  }
   605  
   606  // A runtimeSelect is a single case passed to rselect.
   607  // This must match ../reflect/value.go:/runtimeSelect
   608  type runtimeSelect struct {
   609  	dir selectDir
   610  	typ unsafe.Pointer // channel type (not used here)
   611  	ch  *hchan         // channel
   612  	val unsafe.Pointer // ptr to data (SendDir) or ptr to receive buffer (RecvDir)
   613  }
   614  
   615  // These values must match ../reflect/value.go:/SelectDir.
   616  type selectDir int
   617  
   618  const (
   619  	_             selectDir = iota
   620  	selectSend              // case Chan <- Send
   621  	selectRecv              // case <-Chan:
   622  	selectDefault           // default
   623  )
   624  
   625  //go:linkname reflect_rselect reflect.rselect
   626  func reflect_rselect(cases []runtimeSelect) (chosen int, recvOK bool) {
   627  	// flagNoScan is safe here, because all objects are also referenced from cases.
   628  	size := selectsize(uintptr(len(cases)))
   629  	sel := (*hselect)(mallocgc(size, nil, flagNoScan))
   630  	newselect(sel, int64(size), int32(len(cases)))
   631  	r := new(bool)
   632  	for i := range cases {
   633  		rc := &cases[i]
   634  		switch rc.dir {
   635  		case selectDefault:
   636  			selectdefaultImpl(sel, uintptr(i), 0)
   637  		case selectSend:
   638  			if rc.ch == nil {
   639  				break
   640  			}
   641  			selectsendImpl(sel, rc.ch, uintptr(i), rc.val, 0)
   642  		case selectRecv:
   643  			if rc.ch == nil {
   644  				break
   645  			}
   646  			selectrecvImpl(sel, rc.ch, uintptr(i), rc.val, r, 0)
   647  		}
   648  	}
   649  
   650  	pc, _ := selectgoImpl(sel)
   651  	chosen = int(pc)
   652  	recvOK = *r
   653  	return
   654  }
   655  
   656  func (q *waitq) dequeueSudoG(sgp *sudog) {
   657  	x := sgp.prev
   658  	y := sgp.next
   659  	if x != nil {
   660  		if y != nil {
   661  			// middle of queue
   662  			x.next = y
   663  			y.prev = x
   664  			sgp.next = nil
   665  			sgp.prev = nil
   666  			return
   667  		}
   668  		// end of queue
   669  		x.next = nil
   670  		q.last = x
   671  		sgp.prev = nil
   672  		return
   673  	}
   674  	if y != nil {
   675  		// start of queue
   676  		y.prev = nil
   677  		q.first = y
   678  		sgp.next = nil
   679  		return
   680  	}
   681  
   682  	// x==y==nil.  Either sgp is the only element in the queue,
   683  	// or it has already been removed.  Use q.first to disambiguate.
   684  	if q.first == sgp {
   685  		q.first = nil
   686  		q.last = nil
   687  	}
   688  }