| // Copyright 2022 The Chromium Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #ifndef IPCZ_SRC_IPCZ_TRAP_SET_H_ |
| #define IPCZ_SRC_IPCZ_TRAP_SET_H_ |
| |
| #include <cstdint> |
| |
| #include "ipcz/ipcz.h" |
| #include "third_party/abseil-cpp/absl/container/inlined_vector.h" |
| |
| namespace ipcz { |
| |
| class TrapEventDispatcher; |
| |
| // A set of traps installed on a portal. |
| class TrapSet { |
| public: |
| // The reason for each status update when something happens that might |
| // interest a trap. This is particularly useful for observing edge-triggered |
| // conditions. |
| enum class UpdateReason { |
| // A new trap is being installed and this is an initial state query. |
| kInstallTrap, |
| |
| // A new inbound parcel has arrived for retrieval. |
| kNewLocalParcel, |
| |
| // We just discovered that the remote portal is gone. |
| kPeerClosed, |
| |
| // A previously queued inbound parcel has been fully or partially retrieved |
| // by the application. |
| kLocalParcelConsumed, |
| |
| // A remote peer has changed state in a way that may be interesting to a |
| // trap in the set; for example, parcels may have been consumed from the |
| // remote queue. |
| kRemoteActivity, |
| }; |
| |
| TrapSet(); |
| TrapSet(const TrapSet&) = delete; |
| TrapSet& operator=(const TrapSet&) = delete; |
| |
| // NOTE: A TrapSet must be empty before it can be destroyed. |
| ~TrapSet(); |
| |
| bool empty() const { return traps_.empty(); } |
| |
| // Indicates whether any installed traps in this set require monitoring of |
| // remote queue state. |
| bool need_remote_state() const { |
| return num_traps_monitoring_remote_state_ > 0; |
| } |
| |
| // Attempts to install a new trap in the set. This effectively implements |
| // the ipcz Trap() API. If `conditions` are already met, returns |
| // IPCZ_RESULT_FAILED_PRECONDITION and populates `satisfied_condition_flags` |
| // and/or `status` if non-null. |
| IpczResult Add(const IpczTrapConditions& conditions, |
| IpczTrapEventHandler handler, |
| uintptr_t context, |
| const IpczPortalStatus& current_status, |
| IpczTrapConditionFlags* satisfied_condition_flags, |
| IpczPortalStatus* status); |
| |
| // Notifies this TrapSet of a state change on the portal it's interested in. |
| // If the state change is interesting to any trap in the set, an appropriate |
| // event may be appended to `dispatcher` for imminent dispatch and the trap is |
| // removed from the set before returning. |
| void UpdatePortalStatus(const IpczPortalStatus& status, |
| UpdateReason reason, |
| TrapEventDispatcher& dispatcher); |
| |
| // Immediately removes all traps from the set. Every trap present appends an |
| // IPCZ_TRAP_REMOVED event to `dispatcher` before removal. |
| void RemoveAll(TrapEventDispatcher& dispatcher); |
| |
| private: |
| struct Trap { |
| Trap(IpczTrapConditions conditions, |
| IpczTrapEventHandler handler, |
| uintptr_t context); |
| ~Trap(); |
| |
| IpczTrapConditions conditions; |
| IpczTrapEventHandler handler; |
| uintptr_t context; |
| }; |
| |
| using TrapList = absl::InlinedVector<Trap, 4>; |
| TrapList traps_; |
| size_t num_traps_monitoring_remote_state_ = 0; |
| IpczPortalStatus last_known_status_ = {.size = sizeof(last_known_status_)}; |
| }; |
| |
| } // namespace ipcz |
| |
| #endif // IPCZ_SRC_IPCZ_TRAP_SET_H_ |