github.com/iDigitalFlame/xmt@v0.5.4/c2/state.go (about)

     1  // Copyright (C) 2020 - 2023 iDigitalFlame
     2  //
     3  // This program is free software: you can redistribute it and/or modify
     4  // it under the terms of the GNU General Public License as published by
     5  // the Free Software Foundation, either version 3 of the License, or
     6  // any later version.
     7  //
     8  // This program is distributed in the hope that it will be useful,
     9  // but WITHOUT ANY WARRANTY; without even the implied warranty of
    10  // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    11  // GNU General Public License for more details.
    12  //
    13  // You should have received a copy of the GNU General Public License
    14  // along with this program.  If not, see <https://www.gnu.org/licenses/>.
    15  //
    16  
    17  package c2
    18  
    19  import (
    20  	"sync/atomic"
    21  
    22  	"github.com/iDigitalFlame/xmt/util/bugtrack"
    23  )
    24  
    25  const (
    26  	stateCanRecv uint32 = 1 << iota
    27  	stateReady
    28  	stateClosed
    29  	stateClosing
    30  	stateShutdown
    31  	stateSendClose
    32  	stateRecvClose
    33  	stateWakeClose
    34  	stateChannel
    35  	stateChannelValue
    36  	stateChannelUpdated
    37  	stateChannelProxy
    38  	stateSeen
    39  	stateMoving
    40  	stateReplacing
    41  	stateShutdownWait
    42  )
    43  
    44  type state uint32
    45  
    46  func (s *state) Tag() bool {
    47  	if !s.Seen() {
    48  		return false
    49  	}
    50  	s.Unset(stateSeen)
    51  	return true
    52  }
    53  func (s *state) Seen() bool {
    54  	return atomic.LoadUint32((*uint32)(s))&stateSeen != 0
    55  }
    56  func (s *state) Ready() bool {
    57  	if s.Closed() {
    58  		return false
    59  	}
    60  	return atomic.LoadUint32((*uint32)(s))&stateReady != 0
    61  }
    62  func (s *state) Last() uint16 {
    63  	return uint16(atomic.LoadUint32((*uint32)(s)) >> 16)
    64  }
    65  func (s *state) Moving() bool {
    66  	return atomic.LoadUint32((*uint32)(s))&stateMoving != 0
    67  }
    68  func (s *state) Closed() bool {
    69  	return atomic.LoadUint32((*uint32)(s))&stateClosed != 0
    70  }
    71  func (s *state) Set(v uint32) {
    72  	atomic.StoreUint32((*uint32)(s), atomic.LoadUint32((*uint32)(s))|v)
    73  }
    74  func (s *state) CanRecv() bool {
    75  	if s.Closed() || s.RecvClosed() {
    76  		return false
    77  	}
    78  	return atomic.LoadUint32((*uint32)(s))&stateCanRecv != 0
    79  }
    80  func (s *state) Closing() bool {
    81  	if s.Closed() {
    82  		return true
    83  	}
    84  	return atomic.LoadUint32((*uint32)(s))&stateClosing != 0
    85  }
    86  func (s *state) Channel() bool {
    87  	return atomic.LoadUint32((*uint32)(s))&stateChannel != 0
    88  }
    89  func (s *state) Shutdown() bool {
    90  	if s.Closed() {
    91  		return true
    92  	}
    93  	return atomic.LoadUint32((*uint32)(s))&stateShutdown != 0
    94  }
    95  func (s *state) Unset(v uint32) {
    96  	d := atomic.LoadUint32((*uint32)(s)) &^ v
    97  	atomic.StoreUint32((*uint32)(s), d)
    98  }
    99  func (s *state) Replacing() bool {
   100  	return atomic.LoadUint32((*uint32)(s))&stateReplacing != 0
   101  }
   102  func (s *state) RecvClosed() bool {
   103  	if s.Closed() {
   104  		return true
   105  	}
   106  	return atomic.LoadUint32((*uint32)(s))&stateRecvClose != 0
   107  }
   108  func (s *state) SendClosed() bool {
   109  	if s.Closed() {
   110  		return true
   111  	}
   112  	return atomic.LoadUint32((*uint32)(s))&stateSendClose != 0
   113  }
   114  func (s *state) WakeClosed() bool {
   115  	if s.Closed() {
   116  		return true
   117  	}
   118  	return atomic.LoadUint32((*uint32)(s))&stateWakeClose != 0
   119  }
   120  func (s *state) SetLast(v uint16) {
   121  	atomic.StoreUint32((*uint32)(s), (uint32(v)<<16)|uint32(uint16(atomic.LoadUint32((*uint32)(s)))))
   122  }
   123  func (s *state) ShutdownWait() bool {
   124  	return atomic.LoadUint32((*uint32)(s))&stateShutdownWait != 0
   125  }
   126  func (s *state) ChannelValue() bool {
   127  	return atomic.LoadUint32((*uint32)(s))&stateChannelValue != 0
   128  }
   129  func (s *state) ChannelProxy() bool {
   130  	return atomic.LoadUint32((*uint32)(s))&stateChannelProxy != 0
   131  }
   132  func (s *state) ChannelUpdated() bool {
   133  	return atomic.LoadUint32((*uint32)(s))&stateChannelUpdated != 0
   134  }
   135  func (s *state) ChannelCanStop() bool {
   136  	if s.Closing() || !s.Channel() {
   137  		return true
   138  	}
   139  	if s.ChannelUpdated() {
   140  		s.Unset(stateChannelUpdated)
   141  		return !s.ChannelValue()
   142  	}
   143  	return !s.Channel()
   144  }
   145  func (s *state) ChannelCanStart() bool {
   146  	if s.Closed() {
   147  		return false
   148  	}
   149  	if s.Channel() {
   150  		return true
   151  	}
   152  	return s.ChannelValue()
   153  }
   154  func (s *state) SetChannel(e bool) bool {
   155  	if e {
   156  		if s.ChannelValue() {
   157  			if bugtrack.Enabled {
   158  				bugtrack.Track("c2.(*state).SetChannel(): e=%t, s.ChannelValue()=true, setting channel is NOP since we are in a channel.", e)
   159  			}
   160  			return false
   161  		}
   162  		s.Set(stateChannelValue)
   163  	} else {
   164  		if (!s.Channel() || !s.ChannelProxy()) && !s.ChannelValue() {
   165  			if bugtrack.Enabled {
   166  				bugtrack.Track(
   167  					"c2.(*state).SetChannel(): e=%t, s.Channel()=%t, s.ChannelProxy()=%t, s.ChannelValue()=%t, canceling channel is NOP since we are not in a channel.",
   168  					e, s.Channel(), s.ChannelProxy(), s.ChannelValue(),
   169  				)
   170  			}
   171  			return false
   172  		}
   173  		s.Unset(stateChannelValue)
   174  	}
   175  	s.Set(stateChannelUpdated)
   176  	return true
   177  }