class PortDispatcher
Defined at line 232 of file ../../zircon/kernel/object/include/object/port_dispatcher.h
PortObserver lifetime and locking notes.
PortDispatcher is responsible for destroying PortObservers (MaybeReap
or on_zero_handles), however, their destruction may be initiated by
either Dispatcher or PortDispatcher.
PortObservers can exist on up to two doubly linked lists:
- PortObserver::List on PortDispatcher
- DoublyLinkedList
<SignalObserver
*> on Dispatcher
The diagrams below show the *relevant* pointers on different
states of the system. The pure header view is really the
union of all these pointer which can be confusing.
rc = ref counted
p = raw pointer
o = owning pointer
1) Situation after object_wait_async(port, handle) is issued:
list +--------+
+------p------+ +----p-----+ Port |
| v v | |
+-------+--+ +-----------+ +-+------+
| object | | Port | ^
| |
<
--p---+ Observer | |
+----------+ | +---rc----+
| |
+-----------+
| Port |
| Packet |
+-----------+
State changes of the object are propagated from the object
to the port via |p| --> observer --> |rc| calls.
2) Situation after the packet is queued on signal match or the wait
is canceled through the Dispatcher.
+--------+
| Port |
| |
+----------+ +-----------+ +-+---+--+
| object | | Port | ^ |
| | | Observer | | |
+----------+ | +---rc----+ |
+---> | | |
| +-----------+ | list
| | Port | |
+-rc--| Packet |
<
-----o-----+
+-----------+
Note that the object no longer has a |p| to the observer
but the observer still owns the port via |rc|.
The |o| pointer is used to destroy the port observer only
when cancellation happens and the port still owns the packet.
The PortObserver's raw pointer to the Dispatcher is a weak reference
guarded by the port's lock. It is cleared either in MaybeReap or
in PortDispatcher::on_zero_handles.
Cancelation ordering
Observers can be canceled by way of the object or the port. Observers are
canceled by the object when the object's handle count reaches zero and when
waits are canceled by port_cancel. In this path the Dispatcher's lock is
acquired first and the observer is removed from the Dispatcher's observer
list, then the PortDispatcher lock is acquired and the observer is removed
from the PortDispatcher's observer list and may be cleaned up.
When an observer is canceled through the port by way of port_cancel_key there
is a lock ordering issue. The PortDispatcher lock must be held to iterate
over pending observers but the locks for Dispatchers associated with these
observers cannot be acquired while holding the PortDispatcher lock. In this
case, the PortDispatcher first cancels each pending observer with the
PortDispatcher lock held by assigning the observer's packet's type to a
sentinel value and removing them from the PortDispatcher's list to a
temporary list. Then the PortDispatcher lock is released and the observers
are deregistered from their Dispatchers (acquiring the Dispatcher lock) one
at a time. If an observer fires in this state and attempts to queue a
packet PortDispatcher will check the type field and not queue the packet.
Locking
The PortDispatcher's lock guards PortDispatcher's list of observers, the
PortObserver's reference to its Dispatcher, and the packet type field on the
PortObserver's stored zx_port_packet_t in pending observers. The
PortDispatcher lock can be acquired while holding the Dispatcher's lock.
The Dispatcher's lock guards the Dispatcher's list of observers and the
other fields on PortObserver, most notably the packet itself. The
dispatcher lock cannot be acquired while holding the PortDispatcher lock.
Both the PortDispatcher and Dispatcher locks are held when delivering a
packet and when deciding whether to destroy it in MaybeReap.
Public Methods
PortAllocator * DefaultPortAllocator ()
//////////////////////////////////////////////////////////////////////////////////////
Defined at line 165 of file ../../zircon/kernel/object/port_dispatcher.cc
zx_status_t Create (uint32_t options, KernelHandle<PortDispatcher> * handle, zx_rights_t * rights)
Defined at line 167 of file ../../zircon/kernel/object/port_dispatcher.cc
void ~PortDispatcher ()
Defined at line 187 of file ../../zircon/kernel/object/port_dispatcher.cc
void on_zero_handles ()
Defined at line 193 of file ../../zircon/kernel/object/port_dispatcher.cc
zx_obj_type_t get_type ()
Defined at line 239 of file ../../zircon/kernel/object/include/object/port_dispatcher.h
bool can_bind_to_interrupt ()
Defined at line 241 of file ../../zircon/kernel/object/include/object/port_dispatcher.h
zx_status_t Queue (PortPacket * port_packet)
Queues a packet on the port.
Defined at line 286 of file ../../zircon/kernel/object/port_dispatcher.cc
zx_status_t QueueAndRemoveObserver (PortPacket * port_packet, zx_signals_t observed, PortObserver * observer, OwnedWaitQueue * queue_to_own)
Queues a packet based on a signal observation and deregisters the observer from the port.
If |observer| is non-null, also removes it from the observer list.
Defined at line 290 of file ../../zircon/kernel/object/port_dispatcher.cc
zx_status_t QueueUser (const zx_port_packet_t & packet)
Queues a user packet.
Defined at line 243 of file ../../zircon/kernel/object/port_dispatcher.cc
bool QueueInterruptPacket (PortInterruptPacket * port_packet, zx_instant_boot_t timestamp)
Queues an interrupt packet.
Defined at line 268 of file ../../zircon/kernel/object/port_dispatcher.cc
zx_status_t Dequeue (const Deadline & deadline, zx_port_packet_t * packet)
Defined at line 358 of file ../../zircon/kernel/object/port_dispatcher.cc
bool RemoveInterruptPacket (PortInterruptPacket * port_packet)
Defined at line 259 of file ../../zircon/kernel/object/port_dispatcher.cc
void MaybeReap (PortObserver * observer, PortPacket * port_packet)
This method determines the observer's fate. Upon return, one of the following will have
occurred:
1. The observer is destroyed.
2. The observer is linked to an alreadyed queued packet and will be destroyed when the packet
is destroyed (Queued or CancelQueued).
3. The observer is left for on_zero_handles to destroyed.
Defined at line 421 of file ../../zircon/kernel/object/port_dispatcher.cc
zx_status_t MakeObserver (uint32_t options, Handle * handle, uint64_t key, zx_signals_t signals)
Called under the handle table lock.
Defined at line 459 of file ../../zircon/kernel/object/port_dispatcher.cc
bool CancelQueued (const void * handle, uint64_t key)
Returns true if at least one packet was removed from the queue.
Called under the handle table lock when |handle| is not null.
When |handle| is null, ephemeral PortPackets are removed from the queue but not freed.
Defined at line 537 of file ../../zircon/kernel/object/port_dispatcher.cc
bool CancelQueued (PortPacket * port_packet)
Removes |port_packet| from this port's queue. Returns false if the packet was
not in this queue. It is undefined to call this with a packet queued in another port.
Defined at line 545 of file ../../zircon/kernel/object/port_dispatcher.cc
zx_status_t CancelKey (uint64_t key)
Cancel all pending waits and packets registered with |key|.
Returns ZX_OK if any waits or packets were canceled and ZX_ERR_NOT_FOUND if
no matching waits or packets were found.
Defined at line 561 of file ../../zircon/kernel/object/port_dispatcher.cc
void InitializeCacheAllocators (uint32_t level)
Init hook that sets up the cache allocators used by this dispatcher.
Defined at line 592 of file ../../zircon/kernel/object/port_dispatcher.cc