1 // Copyright 2018 The Fuchsia Authors 2 // 3 // Use of this source code is governed by a MIT-style 4 // license that can be found in the LICENSE file or at 5 // https://opensource.org/licenses/MIT 6 7 #pragma once 8 9 #include <assert.h> 10 11 // The state of a thread has two axes. One is its arc from birth to 12 // death, expressed via its Lifecycle value. The other its current 13 // exception handler state, expressed via its Exception value. 14 15 // This class exists to encapsulate all legal state transitions, so 16 // generally other assertions about the state of a thread prior to 17 // transitioning are not necessary. 18 19 // Only RUNNING, SUSPENDED, or DYING threads may participate in 20 // exception handling. 21 22 class ThreadState { 23 public: 24 // The only legal transition that isn't from top-to-bottom occurs 25 // when a thread is resumed after being suspended. 26 enum class Lifecycle { 27 // The ThreadDispatcher has been allocated, but not yet 28 // associated to a thread_t or an aspace. 29 INITIAL, 30 31 // The ThreadDispatcher is now associated to its underlying 32 // thread_t and the containing process's address space, and is 33 // waiting to be run. 34 INITIALIZED, 35 36 // The thread is running. 37 RUNNING, 38 39 // The thread is currently suspended. 40 // Note that suspension is orthogonal to being "in an exception". 41 // A thread may be both suspended and in an exception, and the thread 42 // does not "resume" execution until it is resumed from both the 43 // suspension and the exception. 44 SUSPENDED, 45 46 // The thread is going to die. It may still be interacting 47 // with exception handling state. 48 DYING, 49 50 // The thread is being dissociated from all of its state, and 51 // no more interaction with userspace (including exception 52 // handlers) is possible. 53 DEAD, 54 }; 55 56 // IDLE threads become UNPROCESSED. UNPROCESSED threads are told 57 // to either RESUME or TRY_NEXT in a loop until they are killed 58 // (no more exception handlers) or resumed, in which case they 59 // become IDLE again. 60 enum class Exception { 61 // There's no pending exception. 62 IDLE, 63 64 // The thread is waiting for the pending exception to be 65 // processed. 66 UNPROCESSED, 67 68 // The exception has been processed, and the next exception 69 // handler should be queried. 70 TRY_NEXT, 71 72 // The exception has been processed, and the thread should 73 // resume. 74 RESUME, 75 }; 76 lifecycle()77 Lifecycle lifecycle() const { 78 switch (value_) { 79 case Value::INITIAL_IDLE: 80 return Lifecycle::INITIAL; 81 case Value::INITIALIZED_IDLE: 82 return Lifecycle::INITIALIZED; 83 case Value::RUNNING_IDLE: 84 case Value::RUNNING_UNPROCESSED: 85 case Value::RUNNING_TRY_NEXT: 86 case Value::RUNNING_RESUME: 87 return Lifecycle::RUNNING; 88 case Value::SUSPENDED_IDLE: 89 case Value::SUSPENDED_UNPROCESSED: 90 case Value::SUSPENDED_TRY_NEXT: 91 case Value::SUSPENDED_RESUME: 92 return Lifecycle::SUSPENDED; 93 case Value::DYING_IDLE: 94 case Value::DYING_UNPROCESSED: 95 case Value::DYING_TRY_NEXT: 96 case Value::DYING_RESUME: 97 return Lifecycle::DYING; 98 case Value::DEAD_IDLE: 99 return Lifecycle::DEAD; 100 default: 101 ASSERT(false); 102 } 103 } 104 105 // Only RUNNING, SUSPENDED, and DYING threads have meaningful 106 // exception state. exception()107 Exception exception() const { 108 switch (value_) { 109 case Value::RUNNING_IDLE: 110 case Value::SUSPENDED_IDLE: 111 case Value::DYING_IDLE: 112 return Exception::IDLE; 113 case Value::RUNNING_UNPROCESSED: 114 case Value::SUSPENDED_UNPROCESSED: 115 case Value::DYING_UNPROCESSED: 116 return Exception::UNPROCESSED; 117 case Value::RUNNING_TRY_NEXT: 118 case Value::SUSPENDED_TRY_NEXT: 119 case Value::DYING_TRY_NEXT: 120 return Exception::TRY_NEXT; 121 case Value::RUNNING_RESUME: 122 case Value::SUSPENDED_RESUME: 123 case Value::DYING_RESUME: 124 return Exception::RESUME; 125 case Value::INITIALIZED_IDLE: 126 case Value::DEAD_IDLE: 127 // Someone could have, for example, requested zx_info_thread_t. 128 return Exception::IDLE; 129 default: 130 ASSERT(false); 131 } 132 } 133 set(Lifecycle lifecycle)134 void set(Lifecycle lifecycle) { 135 switch (lifecycle) { 136 case Lifecycle::INITIAL: 137 DEBUG_ASSERT(false); 138 return; 139 case Lifecycle::INITIALIZED: 140 switch (value_) { 141 case Value::INITIAL_IDLE: 142 value_ = Value::INITIALIZED_IDLE; 143 return; 144 default: 145 DEBUG_ASSERT(false); 146 return; 147 } 148 case Lifecycle::RUNNING: 149 switch (value_) { 150 case Value::INITIALIZED_IDLE: 151 case Value::SUSPENDED_IDLE: 152 value_ = Value::RUNNING_IDLE; 153 return; 154 case Value::SUSPENDED_UNPROCESSED: 155 value_ = Value::RUNNING_UNPROCESSED; 156 return; 157 case Value::SUSPENDED_TRY_NEXT: 158 value_ = Value::RUNNING_TRY_NEXT; 159 return; 160 case Value::SUSPENDED_RESUME: 161 value_ = Value::RUNNING_RESUME; 162 return; 163 default: 164 DEBUG_ASSERT(false); 165 return; 166 } 167 case Lifecycle::SUSPENDED: 168 switch (value_) { 169 case Value::RUNNING_IDLE: 170 value_ = Value::SUSPENDED_IDLE; 171 return; 172 case Value::RUNNING_UNPROCESSED: 173 value_ = Value::SUSPENDED_UNPROCESSED; 174 return; 175 case Value::RUNNING_TRY_NEXT: 176 value_ = Value::SUSPENDED_TRY_NEXT; 177 return; 178 case Value::RUNNING_RESUME: 179 value_ = Value::SUSPENDED_RESUME; 180 return; 181 default: 182 DEBUG_ASSERT(false); 183 return; 184 } 185 case Lifecycle::DYING: 186 switch (value_) { 187 case Value::RUNNING_IDLE: 188 case Value::SUSPENDED_IDLE: 189 case Value::DYING_IDLE: 190 value_ = Value::DYING_IDLE; 191 return; 192 case Value::RUNNING_UNPROCESSED: 193 case Value::SUSPENDED_UNPROCESSED: 194 case Value::DYING_UNPROCESSED: 195 value_ = Value::DYING_UNPROCESSED; 196 return; 197 case Value::RUNNING_TRY_NEXT: 198 case Value::SUSPENDED_TRY_NEXT: 199 case Value::DYING_TRY_NEXT: 200 value_ = Value::DYING_TRY_NEXT; 201 return; 202 case Value::RUNNING_RESUME: 203 case Value::SUSPENDED_RESUME: 204 case Value::DYING_RESUME: 205 value_ = Value::DYING_RESUME; 206 return; 207 default: 208 DEBUG_ASSERT(false); 209 return; 210 } 211 case Lifecycle::DEAD: 212 switch (value_) { 213 case Value::DYING_IDLE: 214 case Value::DYING_UNPROCESSED: 215 case Value::DYING_TRY_NEXT: 216 case Value::DYING_RESUME: 217 value_ = Value::DEAD_IDLE; 218 return; 219 default: 220 DEBUG_ASSERT(false); 221 return; 222 } 223 } 224 } 225 set(Exception exception)226 void set(Exception exception) { 227 switch (exception) { 228 case Exception::IDLE: 229 switch (value_) { 230 case Value::RUNNING_UNPROCESSED: 231 case Value::RUNNING_TRY_NEXT: 232 case Value::RUNNING_RESUME: 233 value_ = Value::RUNNING_IDLE; 234 return; 235 case Value::SUSPENDED_UNPROCESSED: 236 case Value::SUSPENDED_TRY_NEXT: 237 case Value::SUSPENDED_RESUME: 238 value_ = Value::SUSPENDED_IDLE; 239 return; 240 case Value::DYING_UNPROCESSED: 241 case Value::DYING_TRY_NEXT: 242 case Value::DYING_RESUME: 243 value_ = Value::DYING_IDLE; 244 return; 245 default: 246 DEBUG_ASSERT(false); 247 return; 248 } 249 case Exception::UNPROCESSED: 250 switch (value_) { 251 case Value::RUNNING_IDLE: 252 value_ = Value::RUNNING_UNPROCESSED; 253 return; 254 case Value::SUSPENDED_IDLE: 255 value_ = Value::SUSPENDED_UNPROCESSED; 256 return; 257 case Value::DYING_IDLE: 258 value_ = Value::DYING_UNPROCESSED; 259 return; 260 default: 261 DEBUG_ASSERT(false); 262 return; 263 } 264 case Exception::TRY_NEXT: 265 switch (value_) { 266 case Value::RUNNING_UNPROCESSED: 267 value_ = Value::RUNNING_TRY_NEXT; 268 return; 269 case Value::SUSPENDED_UNPROCESSED: 270 value_ = Value::SUSPENDED_TRY_NEXT; 271 return; 272 case Value::DYING_UNPROCESSED: 273 value_ = Value::DYING_TRY_NEXT; 274 return; 275 default: 276 DEBUG_ASSERT(false); 277 return; 278 } 279 case Exception::RESUME: 280 switch (value_) { 281 case Value::RUNNING_UNPROCESSED: 282 value_ = Value::RUNNING_RESUME; 283 return; 284 case Value::SUSPENDED_UNPROCESSED: 285 value_ = Value::SUSPENDED_RESUME; 286 return; 287 case Value::DYING_UNPROCESSED: 288 value_ = Value::DYING_RESUME; 289 return; 290 default: 291 DEBUG_ASSERT(false); 292 return; 293 } 294 } 295 } 296 297 private: 298 enum class Value { 299 INITIAL_IDLE, 300 301 INITIALIZED_IDLE, 302 303 RUNNING_IDLE, 304 RUNNING_UNPROCESSED, 305 RUNNING_TRY_NEXT, 306 RUNNING_RESUME, 307 308 SUSPENDED_IDLE, 309 SUSPENDED_UNPROCESSED, 310 SUSPENDED_TRY_NEXT, 311 SUSPENDED_RESUME, 312 313 DYING_IDLE, 314 DYING_UNPROCESSED, 315 DYING_TRY_NEXT, 316 DYING_RESUME, 317 318 DEAD_IDLE, 319 }; 320 321 Value value_ = Value::INITIAL_IDLE; 322 }; 323 324 const char* ThreadLifecycleToString(ThreadState::Lifecycle lifecycle); 325