| 3216 | |
| 3217 | |
| 3218 | bool ProcessManager::wait(const UPID& pid) |
| 3219 | { |
| 3220 | std::shared_ptr<Gate> gate; |
| 3221 | |
| 3222 | ProcessBase* process = nullptr; // Set to non-null if we donate thread. |
| 3223 | |
| 3224 | if (ProcessReference reference = use(pid)) { |
| 3225 | // Save the process assuming we can donate to it. |
| 3226 | process = reference; |
| 3227 | |
| 3228 | gate = process->gate; |
| 3229 | |
| 3230 | // Check if it is runnable in order to donate this thread. |
| 3231 | switch (process->state.load()) { |
| 3232 | case ProcessBase::State::BOTTOM: |
| 3233 | case ProcessBase::State::READY: |
| 3234 | // Assume that we'll be able to successfully extract the |
| 3235 | // process from the run queue and optimistically increment |
| 3236 | // `running` so that `Clock::settle` properly waits. In the |
| 3237 | // event that we aren't able to extract the process from the |
| 3238 | // run queue then we'll decrement `running`. Note that we |
| 3239 | // can't assume that `running` is already non-zero because any |
| 3240 | // thread may call `wait`, and thus we can't assume that we're |
| 3241 | // calling it from a process that is already running. |
| 3242 | running.fetch_add(1); |
| 3243 | |
| 3244 | // Try and extract the process from the run queue. This may |
| 3245 | // fail because another thread might resume the process first |
| 3246 | // or the run queue might not support arbitrary extraction. |
| 3247 | if (!runq.extract(process)) { |
| 3248 | running.fetch_sub(1); |
| 3249 | process = nullptr; |
| 3250 | } |
| 3251 | break; |
| 3252 | case ProcessBase::State::BLOCKED: |
| 3253 | case ProcessBase::State::TERMINATING: |
| 3254 | process = nullptr; |
| 3255 | break; |
| 3256 | } |
| 3257 | } |
| 3258 | |
| 3259 | if (process != nullptr) { |
| 3260 | VLOG(3) << "Donating thread to " << process->pid << " while waiting"; |
| 3261 | ProcessBase* donator = __process__; |
| 3262 | resume(process); |
| 3263 | running.fetch_sub(1); |
| 3264 | __process__ = donator; |
| 3265 | } |
| 3266 | |
| 3267 | // NOTE: `process` is possibly deleted at this point and we must not |
| 3268 | // use it! |
| 3269 | |
| 3270 | // TODO(benh): Donating only once may not be sufficient, so we might |
| 3271 | // still deadlock here ... perhaps warn if that's the case? |
| 3272 | // |
| 3273 | // In fact, we might want to support the ability to donate a thread |
| 3274 | // to any process for a limited number of messages while we wait |
| 3275 | // (i.e., donate for a message, check and see if our gate is open, |