| 499 | } |
| 500 | |
| 501 | void vvl::Semaphore::RetireSignal(uint64_t payload) { |
| 502 | auto guard = WriteLock(); |
| 503 | if (payload <= completed_.payload) { |
| 504 | return; |
| 505 | } |
| 506 | TimePoint& timepoint = vvl::FindExisting(timeline_, payload); |
| 507 | assert(timepoint.signal_submit.has_value()); |
| 508 | |
| 509 | OpType completed_op = kSignal; |
| 510 | const Queue* completed_op_queue = timepoint.signal_submit->queue; |
| 511 | |
| 512 | // If there is a wait operation then mark it as the last completed instead. |
| 513 | // The reason to do this here instead on the waiter side (after it is unblocked) |
| 514 | // is because signal can have larger (timeline) value than corresponding wait value. |
| 515 | // In this case it's the signal that defines the last completed value. |
| 516 | if (!timepoint.wait_submits.empty()) { |
| 517 | completed_op = kWait; |
| 518 | // NOTE: for timeline semaphores there can be several waiters. Also for timeline |
| 519 | // semaphores the queue of the completed operation is only used by Semaphore::InUse |
| 520 | // for reporting purposes. We can choose any valid wait queue if there are multiple. |
| 521 | completed_op_queue = timepoint.wait_submits[0].queue; |
| 522 | } |
| 523 | |
| 524 | RetireTimePoint(payload, completed_op, completed_op_queue); |
| 525 | } |
| 526 | |
| 527 | void vvl::Semaphore::RetireTimePoint(uint64_t payload, OpType completed_op, const Queue* completed_op_queue) { |
| 528 | auto it = timeline_.begin(); |