...
Run Format

Source file src/runtime/chan.go

Documentation: runtime

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

View as plain text