github.com/riscv/riscv-go@v0.0.0-20200123204226-124ebd6fcc8e/src/runtime/chan.go (about)

     1  // Copyright 2014 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 channels.
     8  
     9  // Invariants:
    10  //  At least one of c.sendq and c.recvq is empty,
    11  //  except for the case of an unbuffered channel with a single goroutine
    12  //  blocked on it for both sending and receiving using a select statement,
    13  //  in which case the length of c.sendq and c.recvq is limited only by the
    14  //  size of the select statement.
    15  //
    16  // For buffered channels, also:
    17  //  c.qcount > 0 implies that c.recvq is empty.
    18  //  c.qcount < c.dataqsiz implies that c.sendq is empty.
    19  
    20  import (
    21  	"runtime/internal/atomic"
    22  	"unsafe"
    23  )
    24  
    25  const (
    26  	maxAlign  = 8
    27  	hchanSize = unsafe.Sizeof(hchan{}) + uintptr(-int(unsafe.Sizeof(hchan{}))&(maxAlign-1))
    28  	debugChan = false
    29  )
    30  
    31  type hchan struct {
    32  	qcount   uint           // total data in the queue
    33  	dataqsiz uint           // size of the circular queue
    34  	buf      unsafe.Pointer // points to an array of dataqsiz elements
    35  	elemsize uint16
    36  	closed   uint32
    37  	elemtype *_type // element type
    38  	sendx    uint   // send index
    39  	recvx    uint   // receive index
    40  	recvq    waitq  // list of recv waiters
    41  	sendq    waitq  // list of send waiters
    42  
    43  	// lock protects all fields in hchan, as well as several
    44  	// fields in sudogs blocked on this channel.
    45  	//
    46  	// Do not change another G's status while holding this lock
    47  	// (in particular, do not ready a G), as this can deadlock
    48  	// with stack shrinking.
    49  	lock mutex
    50  }
    51  
    52  type waitq struct {
    53  	first *sudog
    54  	last  *sudog
    55  }
    56  
    57  //go:linkname reflect_makechan reflect.makechan
    58  func reflect_makechan(t *chantype, size int64) *hchan {
    59  	return makechan(t, size)
    60  }
    61  
    62  func makechan(t *chantype, size int64) *hchan {
    63  	elem := t.elem
    64  
    65  	// compiler checks this but be safe.
    66  	if elem.size >= 1<<16 {
    67  		throw("makechan: invalid channel element type")
    68  	}
    69  	if hchanSize%maxAlign != 0 || elem.align > maxAlign {
    70  		throw("makechan: bad alignment")
    71  	}
    72  	if size < 0 || int64(uintptr(size)) != size || (elem.size > 0 && uintptr(size) > (_MaxMem-hchanSize)/elem.size) {
    73  		panic(plainError("makechan: size out of range"))
    74  	}
    75  
    76  	var c *hchan
    77  	if elem.kind&kindNoPointers != 0 || size == 0 {
    78  		// Allocate memory in one call.
    79  		// Hchan does not contain pointers interesting for GC in this case:
    80  		// buf points into the same allocation, elemtype is persistent.
    81  		// SudoG's are referenced from their owning thread so they can't be collected.
    82  		// TODO(dvyukov,rlh): Rethink when collector can move allocated objects.
    83  		c = (*hchan)(mallocgc(hchanSize+uintptr(size)*elem.size, nil, true))
    84  		if size > 0 && elem.size != 0 {
    85  			c.buf = add(unsafe.Pointer(c), hchanSize)
    86  		} else {
    87  			// race detector uses this location for synchronization
    88  			// Also prevents us from pointing beyond the allocation (see issue 9401).
    89  			c.buf = unsafe.Pointer(c)
    90  		}
    91  	} else {
    92  		c = new(hchan)
    93  		c.buf = newarray(elem, int(size))
    94  	}
    95  	c.elemsize = uint16(elem.size)
    96  	c.elemtype = elem
    97  	c.dataqsiz = uint(size)
    98  
    99  	if debugChan {
   100  		print("makechan: chan=", c, "; elemsize=", elem.size, "; elemalg=", elem.alg, "; dataqsiz=", size, "\n")
   101  	}
   102  	return c
   103  }
   104  
   105  // chanbuf(c, i) is pointer to the i'th slot in the buffer.
   106  func chanbuf(c *hchan, i uint) unsafe.Pointer {
   107  	return add(c.buf, uintptr(i)*uintptr(c.elemsize))
   108  }
   109  
   110  // entry point for c <- x from compiled code
   111  //go:nosplit
   112  func chansend1(t *chantype, c *hchan, elem unsafe.Pointer) {
   113  	chansend(t, c, elem, true, getcallerpc(unsafe.Pointer(&t)))
   114  }
   115  
   116  /*
   117   * generic single channel send/recv
   118   * If block is not nil,
   119   * then the protocol will not
   120   * sleep but return if it could
   121   * not complete.
   122   *
   123   * sleep can wake up with g.param == nil
   124   * when a channel involved in the sleep has
   125   * been closed.  it is easiest to loop and re-run
   126   * the operation; we'll see that it's now closed.
   127   */
   128  func chansend(t *chantype, c *hchan, ep unsafe.Pointer, block bool, callerpc uintptr) bool {
   129  	if raceenabled {
   130  		raceReadObjectPC(t.elem, ep, callerpc, funcPC(chansend))
   131  	}
   132  	if msanenabled {
   133  		msanread(ep, t.elem.size)
   134  	}
   135  
   136  	if c == nil {
   137  		if !block {
   138  			return false
   139  		}
   140  		gopark(nil, nil, "chan send (nil chan)", traceEvGoStop, 2)
   141  		throw("unreachable")
   142  	}
   143  
   144  	if debugChan {
   145  		print("chansend: chan=", c, "\n")
   146  	}
   147  
   148  	if raceenabled {
   149  		racereadpc(unsafe.Pointer(c), callerpc, funcPC(chansend))
   150  	}
   151  
   152  	// Fast path: check for failed non-blocking operation without acquiring the lock.
   153  	//
   154  	// After observing that the channel is not closed, we observe that the channel is
   155  	// not ready for sending. Each of these observations is a single word-sized read
   156  	// (first c.closed and second c.recvq.first or c.qcount depending on kind of channel).
   157  	// Because a closed channel cannot transition from 'ready for sending' to
   158  	// 'not ready for sending', even if the channel is closed between the two observations,
   159  	// they imply a moment between the two when the channel was both not yet closed
   160  	// and not ready for sending. We behave as if we observed the channel at that moment,
   161  	// and report that the send cannot proceed.
   162  	//
   163  	// It is okay if the reads are reordered here: if we observe that the channel is not
   164  	// ready for sending and then observe that it is not closed, that implies that the
   165  	// channel wasn't closed during the first observation.
   166  	if !block && c.closed == 0 && ((c.dataqsiz == 0 && c.recvq.first == nil) ||
   167  		(c.dataqsiz > 0 && c.qcount == c.dataqsiz)) {
   168  		return false
   169  	}
   170  
   171  	var t0 int64
   172  	if blockprofilerate > 0 {
   173  		t0 = cputicks()
   174  	}
   175  
   176  	lock(&c.lock)
   177  
   178  	if c.closed != 0 {
   179  		unlock(&c.lock)
   180  		panic(plainError("send on closed channel"))
   181  	}
   182  
   183  	if sg := c.recvq.dequeue(); sg != nil {
   184  		// Found a waiting receiver. We pass the value we want to send
   185  		// directly to the receiver, bypassing the channel buffer (if any).
   186  		send(c, sg, ep, func() { unlock(&c.lock) })
   187  		return true
   188  	}
   189  
   190  	if c.qcount < c.dataqsiz {
   191  		// Space is available in the channel buffer. Enqueue the element to send.
   192  		qp := chanbuf(c, c.sendx)
   193  		if raceenabled {
   194  			raceacquire(qp)
   195  			racerelease(qp)
   196  		}
   197  		typedmemmove(c.elemtype, qp, ep)
   198  		c.sendx++
   199  		if c.sendx == c.dataqsiz {
   200  			c.sendx = 0
   201  		}
   202  		c.qcount++
   203  		unlock(&c.lock)
   204  		return true
   205  	}
   206  
   207  	if !block {
   208  		unlock(&c.lock)
   209  		return false
   210  	}
   211  
   212  	// Block on the channel. Some receiver will complete our operation for us.
   213  	gp := getg()
   214  	mysg := acquireSudog()
   215  	mysg.releasetime = 0
   216  	if t0 != 0 {
   217  		mysg.releasetime = -1
   218  	}
   219  	// No stack splits between assigning elem and enqueuing mysg
   220  	// on gp.waiting where copystack can find it.
   221  	mysg.elem = ep
   222  	mysg.waitlink = nil
   223  	mysg.g = gp
   224  	mysg.selectdone = nil
   225  	mysg.c = c
   226  	gp.waiting = mysg
   227  	gp.param = nil
   228  	c.sendq.enqueue(mysg)
   229  	goparkunlock(&c.lock, "chan send", traceEvGoBlockSend, 3)
   230  
   231  	// someone woke us up.
   232  	if mysg != gp.waiting {
   233  		throw("G waiting list is corrupted")
   234  	}
   235  	gp.waiting = nil
   236  	if gp.param == nil {
   237  		if c.closed == 0 {
   238  			throw("chansend: spurious wakeup")
   239  		}
   240  		panic(plainError("send on closed channel"))
   241  	}
   242  	gp.param = nil
   243  	if mysg.releasetime > 0 {
   244  		blockevent(mysg.releasetime-t0, 2)
   245  	}
   246  	mysg.c = nil
   247  	releaseSudog(mysg)
   248  	return true
   249  }
   250  
   251  // send processes a send operation on an empty channel c.
   252  // The value ep sent by the sender is copied to the receiver sg.
   253  // The receiver is then woken up to go on its merry way.
   254  // Channel c must be empty and locked.  send unlocks c with unlockf.
   255  // sg must already be dequeued from c.
   256  // ep must be non-nil and point to the heap or the caller's stack.
   257  func send(c *hchan, sg *sudog, ep unsafe.Pointer, unlockf func()) {
   258  	if raceenabled {
   259  		if c.dataqsiz == 0 {
   260  			racesync(c, sg)
   261  		} else {
   262  			// Pretend we go through the buffer, even though
   263  			// we copy directly. Note that we need to increment
   264  			// the head/tail locations only when raceenabled.
   265  			qp := chanbuf(c, c.recvx)
   266  			raceacquire(qp)
   267  			racerelease(qp)
   268  			raceacquireg(sg.g, qp)
   269  			racereleaseg(sg.g, qp)
   270  			c.recvx++
   271  			if c.recvx == c.dataqsiz {
   272  				c.recvx = 0
   273  			}
   274  			c.sendx = c.recvx // c.sendx = (c.sendx+1) % c.dataqsiz
   275  		}
   276  	}
   277  	if sg.elem != nil {
   278  		sendDirect(c.elemtype, sg, ep)
   279  		sg.elem = nil
   280  	}
   281  	gp := sg.g
   282  	unlockf()
   283  	gp.param = unsafe.Pointer(sg)
   284  	if sg.releasetime != 0 {
   285  		sg.releasetime = cputicks()
   286  	}
   287  	goready(gp, 4)
   288  }
   289  
   290  // Sends and receives on unbuffered or empty-buffered channels are the
   291  // only operations where one running goroutine writes to the stack of
   292  // another running goroutine. The GC assumes that stack writes only
   293  // happen when the goroutine is running and are only done by that
   294  // goroutine. Using a write barrier is sufficient to make up for
   295  // violating that assumption, but the write barrier has to work.
   296  // typedmemmove will call bulkBarrierPreWrite, but the target bytes
   297  // are not in the heap, so that will not help. We arrange to call
   298  // memmove and typeBitsBulkBarrier instead.
   299  
   300  func sendDirect(t *_type, sg *sudog, src unsafe.Pointer) {
   301  	// src is on our stack, dst is a slot on another stack.
   302  
   303  	// Once we read sg.elem out of sg, it will no longer
   304  	// be updated if the destination's stack gets copied (shrunk).
   305  	// So make sure that no preemption points can happen between read & use.
   306  	dst := sg.elem
   307  	typeBitsBulkBarrier(t, uintptr(dst), uintptr(src), t.size)
   308  	memmove(dst, src, t.size)
   309  }
   310  
   311  func recvDirect(t *_type, sg *sudog, dst unsafe.Pointer) {
   312  	// dst is on our stack or the heap, src is on another stack.
   313  	// The channel is locked, so src will not move during this
   314  	// operation.
   315  	src := sg.elem
   316  	typeBitsBulkBarrier(t, uintptr(dst), uintptr(src), t.size)
   317  	memmove(dst, src, t.size)
   318  }
   319  
   320  func closechan(c *hchan) {
   321  	if c == nil {
   322  		panic(plainError("close of nil channel"))
   323  	}
   324  
   325  	lock(&c.lock)
   326  	if c.closed != 0 {
   327  		unlock(&c.lock)
   328  		panic(plainError("close of closed channel"))
   329  	}
   330  
   331  	if raceenabled {
   332  		callerpc := getcallerpc(unsafe.Pointer(&c))
   333  		racewritepc(unsafe.Pointer(c), callerpc, funcPC(closechan))
   334  		racerelease(unsafe.Pointer(c))
   335  	}
   336  
   337  	c.closed = 1
   338  
   339  	var glist *g
   340  
   341  	// release all readers
   342  	for {
   343  		sg := c.recvq.dequeue()
   344  		if sg == nil {
   345  			break
   346  		}
   347  		if sg.elem != nil {
   348  			typedmemclr(c.elemtype, sg.elem)
   349  			sg.elem = nil
   350  		}
   351  		if sg.releasetime != 0 {
   352  			sg.releasetime = cputicks()
   353  		}
   354  		gp := sg.g
   355  		gp.param = nil
   356  		if raceenabled {
   357  			raceacquireg(gp, unsafe.Pointer(c))
   358  		}
   359  		gp.schedlink.set(glist)
   360  		glist = gp
   361  	}
   362  
   363  	// release all writers (they will panic)
   364  	for {
   365  		sg := c.sendq.dequeue()
   366  		if sg == nil {
   367  			break
   368  		}
   369  		sg.elem = nil
   370  		if sg.releasetime != 0 {
   371  			sg.releasetime = cputicks()
   372  		}
   373  		gp := sg.g
   374  		gp.param = nil
   375  		if raceenabled {
   376  			raceacquireg(gp, unsafe.Pointer(c))
   377  		}
   378  		gp.schedlink.set(glist)
   379  		glist = gp
   380  	}
   381  	unlock(&c.lock)
   382  
   383  	// Ready all Gs now that we've dropped the channel lock.
   384  	for glist != nil {
   385  		gp := glist
   386  		glist = glist.schedlink.ptr()
   387  		gp.schedlink = 0
   388  		goready(gp, 3)
   389  	}
   390  }
   391  
   392  // entry points for <- c from compiled code
   393  //go:nosplit
   394  func chanrecv1(t *chantype, c *hchan, elem unsafe.Pointer) {
   395  	chanrecv(t, c, elem, true)
   396  }
   397  
   398  //go:nosplit
   399  func chanrecv2(t *chantype, c *hchan, elem unsafe.Pointer) (received bool) {
   400  	_, received = chanrecv(t, c, elem, true)
   401  	return
   402  }
   403  
   404  // chanrecv receives on channel c and writes the received data to ep.
   405  // ep may be nil, in which case received data is ignored.
   406  // If block == false and no elements are available, returns (false, false).
   407  // Otherwise, if c is closed, zeros *ep and returns (true, false).
   408  // Otherwise, fills in *ep with an element and returns (true, true).
   409  // A non-nil ep must point to the heap or the caller's stack.
   410  func chanrecv(t *chantype, c *hchan, ep unsafe.Pointer, block bool) (selected, received bool) {
   411  	// raceenabled: don't need to check ep, as it is always on the stack
   412  	// or is new memory allocated by reflect.
   413  
   414  	if debugChan {
   415  		print("chanrecv: chan=", c, "\n")
   416  	}
   417  
   418  	if c == nil {
   419  		if !block {
   420  			return
   421  		}
   422  		gopark(nil, nil, "chan receive (nil chan)", traceEvGoStop, 2)
   423  		throw("unreachable")
   424  	}
   425  
   426  	// Fast path: check for failed non-blocking operation without acquiring the lock.
   427  	//
   428  	// After observing that the channel is not ready for receiving, we observe that the
   429  	// channel is not closed. Each of these observations is a single word-sized read
   430  	// (first c.sendq.first or c.qcount, and second c.closed).
   431  	// Because a channel cannot be reopened, the later observation of the channel
   432  	// being not closed implies that it was also not closed at the moment of the
   433  	// first observation. We behave as if we observed the channel at that moment
   434  	// and report that the receive cannot proceed.
   435  	//
   436  	// The order of operations is important here: reversing the operations can lead to
   437  	// incorrect behavior when racing with a close.
   438  	if !block && (c.dataqsiz == 0 && c.sendq.first == nil ||
   439  		c.dataqsiz > 0 && atomic.Loaduint(&c.qcount) == 0) &&
   440  		atomic.Load(&c.closed) == 0 {
   441  		return
   442  	}
   443  
   444  	var t0 int64
   445  	if blockprofilerate > 0 {
   446  		t0 = cputicks()
   447  	}
   448  
   449  	lock(&c.lock)
   450  
   451  	if c.closed != 0 && c.qcount == 0 {
   452  		if raceenabled {
   453  			raceacquire(unsafe.Pointer(c))
   454  		}
   455  		unlock(&c.lock)
   456  		if ep != nil {
   457  			typedmemclr(c.elemtype, ep)
   458  		}
   459  		return true, false
   460  	}
   461  
   462  	if sg := c.sendq.dequeue(); sg != nil {
   463  		// Found a waiting sender. If buffer is size 0, receive value
   464  		// directly from sender. Otherwise, receive from head of queue
   465  		// and add sender's value to the tail of the queue (both map to
   466  		// the same buffer slot because the queue is full).
   467  		recv(c, sg, ep, func() { unlock(&c.lock) })
   468  		return true, true
   469  	}
   470  
   471  	if c.qcount > 0 {
   472  		// Receive directly from queue
   473  		qp := chanbuf(c, c.recvx)
   474  		if raceenabled {
   475  			raceacquire(qp)
   476  			racerelease(qp)
   477  		}
   478  		if ep != nil {
   479  			typedmemmove(c.elemtype, ep, qp)
   480  		}
   481  		typedmemclr(c.elemtype, qp)
   482  		c.recvx++
   483  		if c.recvx == c.dataqsiz {
   484  			c.recvx = 0
   485  		}
   486  		c.qcount--
   487  		unlock(&c.lock)
   488  		return true, true
   489  	}
   490  
   491  	if !block {
   492  		unlock(&c.lock)
   493  		return false, false
   494  	}
   495  
   496  	// no sender available: block on this channel.
   497  	gp := getg()
   498  	mysg := acquireSudog()
   499  	mysg.releasetime = 0
   500  	if t0 != 0 {
   501  		mysg.releasetime = -1
   502  	}
   503  	// No stack splits between assigning elem and enqueuing mysg
   504  	// on gp.waiting where copystack can find it.
   505  	mysg.elem = ep
   506  	mysg.waitlink = nil
   507  	gp.waiting = mysg
   508  	mysg.g = gp
   509  	mysg.selectdone = nil
   510  	mysg.c = c
   511  	gp.param = nil
   512  	c.recvq.enqueue(mysg)
   513  	goparkunlock(&c.lock, "chan receive", traceEvGoBlockRecv, 3)
   514  
   515  	// someone woke us up
   516  	if mysg != gp.waiting {
   517  		throw("G waiting list is corrupted")
   518  	}
   519  	gp.waiting = nil
   520  	if mysg.releasetime > 0 {
   521  		blockevent(mysg.releasetime-t0, 2)
   522  	}
   523  	closed := gp.param == nil
   524  	gp.param = nil
   525  	mysg.c = nil
   526  	releaseSudog(mysg)
   527  	return true, !closed
   528  }
   529  
   530  // recv processes a receive operation on a full channel c.
   531  // There are 2 parts:
   532  // 1) The value sent by the sender sg is put into the channel
   533  //    and the sender is woken up to go on its merry way.
   534  // 2) The value received by the receiver (the current G) is
   535  //    written to ep.
   536  // For synchronous channels, both values are the same.
   537  // For asynchronous channels, the receiver gets its data from
   538  // the channel buffer and the sender's data is put in the
   539  // channel buffer.
   540  // Channel c must be full and locked. recv unlocks c with unlockf.
   541  // sg must already be dequeued from c.
   542  // A non-nil ep must point to the heap or the caller's stack.
   543  func recv(c *hchan, sg *sudog, ep unsafe.Pointer, unlockf func()) {
   544  	if c.dataqsiz == 0 {
   545  		if raceenabled {
   546  			racesync(c, sg)
   547  		}
   548  		if ep != nil {
   549  			// copy data from sender
   550  			recvDirect(c.elemtype, sg, ep)
   551  		}
   552  	} else {
   553  		// Queue is full. Take the item at the
   554  		// head of the queue. Make the sender enqueue
   555  		// its item at the tail of the queue. Since the
   556  		// queue is full, those are both the same slot.
   557  		qp := chanbuf(c, c.recvx)
   558  		if raceenabled {
   559  			raceacquire(qp)
   560  			racerelease(qp)
   561  			raceacquireg(sg.g, qp)
   562  			racereleaseg(sg.g, qp)
   563  		}
   564  		// copy data from queue to receiver
   565  		if ep != nil {
   566  			typedmemmove(c.elemtype, ep, qp)
   567  		}
   568  		// copy data from sender to queue
   569  		typedmemmove(c.elemtype, qp, sg.elem)
   570  		c.recvx++
   571  		if c.recvx == c.dataqsiz {
   572  			c.recvx = 0
   573  		}
   574  		c.sendx = c.recvx // c.sendx = (c.sendx+1) % c.dataqsiz
   575  	}
   576  	sg.elem = nil
   577  	gp := sg.g
   578  	unlockf()
   579  	gp.param = unsafe.Pointer(sg)
   580  	if sg.releasetime != 0 {
   581  		sg.releasetime = cputicks()
   582  	}
   583  	goready(gp, 4)
   584  }
   585  
   586  // compiler implements
   587  //
   588  //	select {
   589  //	case c <- v:
   590  //		... foo
   591  //	default:
   592  //		... bar
   593  //	}
   594  //
   595  // as
   596  //
   597  //	if selectnbsend(c, v) {
   598  //		... foo
   599  //	} else {
   600  //		... bar
   601  //	}
   602  //
   603  func selectnbsend(t *chantype, c *hchan, elem unsafe.Pointer) (selected bool) {
   604  	return chansend(t, c, elem, false, getcallerpc(unsafe.Pointer(&t)))
   605  }
   606  
   607  // compiler implements
   608  //
   609  //	select {
   610  //	case v = <-c:
   611  //		... foo
   612  //	default:
   613  //		... bar
   614  //	}
   615  //
   616  // as
   617  //
   618  //	if selectnbrecv(&v, c) {
   619  //		... foo
   620  //	} else {
   621  //		... bar
   622  //	}
   623  //
   624  func selectnbrecv(t *chantype, elem unsafe.Pointer, c *hchan) (selected bool) {
   625  	selected, _ = chanrecv(t, c, elem, false)
   626  	return
   627  }
   628  
   629  // compiler implements
   630  //
   631  //	select {
   632  //	case v, ok = <-c:
   633  //		... foo
   634  //	default:
   635  //		... bar
   636  //	}
   637  //
   638  // as
   639  //
   640  //	if c != nil && selectnbrecv2(&v, &ok, c) {
   641  //		... foo
   642  //	} else {
   643  //		... bar
   644  //	}
   645  //
   646  func selectnbrecv2(t *chantype, elem unsafe.Pointer, received *bool, c *hchan) (selected bool) {
   647  	// TODO(khr): just return 2 values from this function, now that it is in Go.
   648  	selected, *received = chanrecv(t, c, elem, false)
   649  	return
   650  }
   651  
   652  //go:linkname reflect_chansend reflect.chansend
   653  func reflect_chansend(t *chantype, c *hchan, elem unsafe.Pointer, nb bool) (selected bool) {
   654  	return chansend(t, c, elem, !nb, getcallerpc(unsafe.Pointer(&t)))
   655  }
   656  
   657  //go:linkname reflect_chanrecv reflect.chanrecv
   658  func reflect_chanrecv(t *chantype, c *hchan, nb bool, elem unsafe.Pointer) (selected bool, received bool) {
   659  	return chanrecv(t, c, elem, !nb)
   660  }
   661  
   662  //go:linkname reflect_chanlen reflect.chanlen
   663  func reflect_chanlen(c *hchan) int {
   664  	if c == nil {
   665  		return 0
   666  	}
   667  	return int(c.qcount)
   668  }
   669  
   670  //go:linkname reflect_chancap reflect.chancap
   671  func reflect_chancap(c *hchan) int {
   672  	if c == nil {
   673  		return 0
   674  	}
   675  	return int(c.dataqsiz)
   676  }
   677  
   678  //go:linkname reflect_chanclose reflect.chanclose
   679  func reflect_chanclose(c *hchan) {
   680  	closechan(c)
   681  }
   682  
   683  func (q *waitq) enqueue(sgp *sudog) {
   684  	sgp.next = nil
   685  	x := q.last
   686  	if x == nil {
   687  		sgp.prev = nil
   688  		q.first = sgp
   689  		q.last = sgp
   690  		return
   691  	}
   692  	sgp.prev = x
   693  	x.next = sgp
   694  	q.last = sgp
   695  }
   696  
   697  func (q *waitq) dequeue() *sudog {
   698  	for {
   699  		sgp := q.first
   700  		if sgp == nil {
   701  			return nil
   702  		}
   703  		y := sgp.next
   704  		if y == nil {
   705  			q.first = nil
   706  			q.last = nil
   707  		} else {
   708  			y.prev = nil
   709  			q.first = y
   710  			sgp.next = nil // mark as removed (see dequeueSudog)
   711  		}
   712  
   713  		// if sgp participates in a select and is already signaled, ignore it
   714  		if sgp.selectdone != nil {
   715  			// claim the right to signal
   716  			if *sgp.selectdone != 0 || !atomic.Cas(sgp.selectdone, 0, 1) {
   717  				continue
   718  			}
   719  		}
   720  
   721  		return sgp
   722  	}
   723  }
   724  
   725  func racesync(c *hchan, sg *sudog) {
   726  	racerelease(chanbuf(c, 0))
   727  	raceacquireg(sg.g, chanbuf(c, 0))
   728  	racereleaseg(sg.g, chanbuf(c, 0))
   729  	raceacquire(chanbuf(c, 0))
   730  }