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 }