| 4 | #include <atomic> |
| 5 | |
| 6 | orbis::ErrorCode orbis::EventFlag::wait(Thread *thread, std::uint8_t waitMode, |
| 7 | std::uint64_t bitPattern, |
| 8 | std::uint32_t *timeout) { |
| 9 | using namespace std::chrono; |
| 10 | |
| 11 | steady_clock::time_point start{}; |
| 12 | uint64_t elapsed = 0; |
| 13 | uint64_t fullTimeout = -1; |
| 14 | if (timeout) { |
| 15 | start = steady_clock::now(); |
| 16 | fullTimeout = *timeout; |
| 17 | } |
| 18 | |
| 19 | auto update_timeout = [&] { |
| 20 | if (!timeout) |
| 21 | return; |
| 22 | auto now = steady_clock::now(); |
| 23 | elapsed = duration_cast<microseconds>(now - start).count(); |
| 24 | if (fullTimeout > elapsed) { |
| 25 | *timeout = fullTimeout - elapsed; |
| 26 | return; |
| 27 | } |
| 28 | *timeout = 0; |
| 29 | }; |
| 30 | |
| 31 | thread->evfResultPattern = 0; |
| 32 | thread->evfIsCancelled = -1; |
| 33 | |
| 34 | std::unique_lock lock(queueMtx); |
| 35 | orbis::ErrorCode result = {}; |
| 36 | while (true) { |
| 37 | if (isDeleted) { |
| 38 | if (thread->evfIsCancelled == UINT64_MAX) |
| 39 | thread->evfResultPattern = value.load(); |
| 40 | return ErrorCode::ACCES; |
| 41 | } |
| 42 | if (thread->evfIsCancelled == 1) { |
| 43 | return ErrorCode::CANCELED; |
| 44 | } |
| 45 | if (thread->evfIsCancelled == 0) { |
| 46 | break; |
| 47 | } |
| 48 | |
| 49 | thread->evfResultPattern = 0; |
| 50 | thread->evfIsCancelled = -1; |
| 51 | |
| 52 | auto waitingThread = WaitingThread{ |
| 53 | .thread = thread, .bitPattern = bitPattern, .waitMode = waitMode}; |
| 54 | |
| 55 | if (auto patValue = value.load(std::memory_order::relaxed); |
| 56 | waitingThread.test(patValue)) { |
| 57 | auto resultValue = waitingThread.applyClear(patValue); |
| 58 | value.store(resultValue, std::memory_order::relaxed); |
| 59 | thread->evfResultPattern = patValue; |
| 60 | // Success |
| 61 | break; |
| 62 | } else if (timeout && *timeout == 0) { |
| 63 | thread->evfResultPattern = patValue; |
no test coverage detected