@@ -25,6 +25,7 @@ package runtime
2525
2626import (
2727 "internal/task"
28+ "runtime/interrupt"
2829 "unsafe"
2930)
3031
@@ -308,13 +309,17 @@ func (ch *channel) trySend(value unsafe.Pointer) bool {
308309 return false
309310 }
310311
312+ i := interrupt .Disable ()
313+
311314 switch ch .state {
312315 case chanStateEmpty , chanStateBuf :
313316 // try to dump the value directly into the buffer
314317 if ch .push (value ) {
315318 ch .state = chanStateBuf
319+ interrupt .Restore (i )
316320 return true
317321 }
322+ interrupt .Restore (i )
318323 return false
319324 case chanStateRecv :
320325 // unblock reciever
@@ -328,16 +333,21 @@ func (ch *channel) trySend(value unsafe.Pointer) bool {
328333 ch .state = chanStateEmpty
329334 }
330335
336+ interrupt .Restore (i )
331337 return true
332338 case chanStateSend :
333339 // something else is already waiting to send
340+ interrupt .Restore (i )
334341 return false
335342 case chanStateClosed :
343+ interrupt .Restore (i )
336344 runtimePanic ("send on closed channel" )
337345 default :
346+ interrupt .Restore (i )
338347 runtimePanic ("invalid channel state" )
339348 }
340349
350+ interrupt .Restore (i )
341351 return false
342352}
343353
@@ -351,6 +361,8 @@ func (ch *channel) tryRecv(value unsafe.Pointer) (bool, bool) {
351361 return false , false
352362 }
353363
364+ i := interrupt .Disable ()
365+
354366 switch ch .state {
355367 case chanStateBuf , chanStateSend :
356368 // try to pop the value directly from the buffer
@@ -373,6 +385,7 @@ func (ch *channel) tryRecv(value unsafe.Pointer) (bool, bool) {
373385 ch .state = chanStateEmpty
374386 }
375387
388+ interrupt .Restore (i )
376389 return true , true
377390 } else if ch .blocked != nil {
378391 // unblock next sender if applicable
@@ -386,19 +399,24 @@ func (ch *channel) tryRecv(value unsafe.Pointer) (bool, bool) {
386399 ch .state = chanStateEmpty
387400 }
388401
402+ interrupt .Restore (i )
389403 return true , true
390404 }
405+ interrupt .Restore (i )
391406 return false , false
392407 case chanStateRecv , chanStateEmpty :
393408 // something else is already waiting to recieve
409+ interrupt .Restore (i )
394410 return false , false
395411 case chanStateClosed :
396412 if ch .pop (value ) {
413+ interrupt .Restore (i )
397414 return true , true
398415 }
399416
400417 // channel closed - nothing to recieve
401418 memzero (value , ch .elementSize )
419+ interrupt .Restore (i )
402420 return true , false
403421 default :
404422 runtimePanic ("invalid channel state" )
@@ -447,14 +465,18 @@ type chanSelectState struct {
447465// This operation will block unless a value is immediately available.
448466// May panic if the channel is closed.
449467func chanSend (ch * channel , value unsafe.Pointer , blockedlist * channelBlockedList ) {
468+ i := interrupt .Disable ()
469+
450470 if ch .trySend (value ) {
451471 // value immediately sent
452472 chanDebug (ch )
473+ interrupt .Restore (i )
453474 return
454475 }
455476
456477 if ch == nil {
457478 // A nil channel blocks forever. Do not schedule this goroutine again.
479+ interrupt .Restore (i )
458480 deadlock ()
459481 }
460482
@@ -468,6 +490,7 @@ func chanSend(ch *channel, value unsafe.Pointer, blockedlist *channelBlockedList
468490 }
469491 ch .blocked = blockedlist
470492 chanDebug (ch )
493+ interrupt .Restore (i )
471494 task .Pause ()
472495 sender .Ptr = nil
473496}
@@ -477,14 +500,18 @@ func chanSend(ch *channel, value unsafe.Pointer, blockedlist *channelBlockedList
477500// The recieved value is copied into the value pointer.
478501// Returns the comma-ok value.
479502func chanRecv (ch * channel , value unsafe.Pointer , blockedlist * channelBlockedList ) bool {
503+ i := interrupt .Disable ()
504+
480505 if rx , ok := ch .tryRecv (value ); rx {
481506 // value immediately available
482507 chanDebug (ch )
508+ interrupt .Restore (i )
483509 return ok
484510 }
485511
486512 if ch == nil {
487513 // A nil channel blocks forever. Do not schedule this goroutine again.
514+ interrupt .Restore (i )
488515 deadlock ()
489516 }
490517
@@ -498,6 +525,7 @@ func chanRecv(ch *channel, value unsafe.Pointer, blockedlist *channelBlockedList
498525 }
499526 ch .blocked = blockedlist
500527 chanDebug (ch )
528+ interrupt .Restore (i )
501529 task .Pause ()
502530 ok := receiver .Data == 1
503531 receiver .Ptr , receiver .Data = nil , 0
@@ -511,15 +539,18 @@ func chanClose(ch *channel) {
511539 // Not allowed by the language spec.
512540 runtimePanic ("close of nil channel" )
513541 }
542+ i := interrupt .Disable ()
514543 switch ch .state {
515544 case chanStateClosed :
516545 // Not allowed by the language spec.
546+ interrupt .Restore (i )
517547 runtimePanic ("close of closed channel" )
518548 case chanStateSend :
519549 // This panic should ideally on the sending side, not in this goroutine.
520550 // But when a goroutine tries to send while the channel is being closed,
521551 // that is clearly invalid: the send should have been completed already
522552 // before the close.
553+ interrupt .Restore (i )
523554 runtimePanic ("close channel during send" )
524555 case chanStateRecv :
525556 // unblock all receivers with the zero value
@@ -531,6 +562,7 @@ func chanClose(ch *channel) {
531562 // Easy case. No available sender or receiver.
532563 }
533564 ch .state = chanStateClosed
565+ interrupt .Restore (i )
534566 chanDebug (ch )
535567}
536568
@@ -541,8 +573,11 @@ func chanClose(ch *channel) {
541573// TODO: do this in a round-robin fashion (as specified in the Go spec) instead
542574// of picking the first one that can proceed.
543575func chanSelect (recvbuf unsafe.Pointer , states []chanSelectState , ops []channelBlockedList ) (uintptr , bool ) {
576+ istate := interrupt .Disable ()
577+
544578 if selected , ok := tryChanSelect (recvbuf , states ); selected != ^ uintptr (0 ) {
545579 // one channel was immediately ready
580+ interrupt .Restore (istate )
546581 return selected , ok
547582 }
548583
@@ -570,6 +605,7 @@ func chanSelect(recvbuf unsafe.Pointer, states []chanSelectState, ops []channelB
570605 case chanStateRecv :
571606 // already in correct state
572607 default :
608+ interrupt .Restore (istate )
573609 runtimePanic ("invalid channel state" )
574610 }
575611 } else {
@@ -582,6 +618,7 @@ func chanSelect(recvbuf unsafe.Pointer, states []chanSelectState, ops []channelB
582618 case chanStateBuf :
583619 // already in correct state
584620 default :
621+ interrupt .Restore (istate )
585622 runtimePanic ("invalid channel state" )
586623 }
587624 }
@@ -594,6 +631,7 @@ func chanSelect(recvbuf unsafe.Pointer, states []chanSelectState, ops []channelB
594631 t .Data = 1
595632
596633 // wait for one case to fire
634+ interrupt .Restore (istate )
597635 task .Pause ()
598636
599637 // figure out which one fired and return the ok value
@@ -602,22 +640,27 @@ func chanSelect(recvbuf unsafe.Pointer, states []chanSelectState, ops []channelB
602640
603641// tryChanSelect is like chanSelect, but it does a non-blocking select operation.
604642func tryChanSelect (recvbuf unsafe.Pointer , states []chanSelectState ) (uintptr , bool ) {
643+ istate := interrupt .Disable ()
644+
605645 // See whether we can receive from one of the channels.
606646 for i , state := range states {
607647 if state .value == nil {
608648 // A receive operation.
609649 if rx , ok := state .ch .tryRecv (recvbuf ); rx {
610650 chanDebug (state .ch )
651+ interrupt .Restore (istate )
611652 return uintptr (i ), ok
612653 }
613654 } else {
614655 // A send operation: state.value is not nil.
615656 if state .ch .trySend (state .value ) {
616657 chanDebug (state .ch )
658+ interrupt .Restore (istate )
617659 return uintptr (i ), true
618660 }
619661 }
620662 }
621663
664+ interrupt .Restore (istate )
622665 return ^ uintptr (0 ), false
623666}
0 commit comments