#include "munga.h" #pragma hdrstop #include "event.h" #include "registry.h" #include "app.h" #include "entity.h" #include "evtstat.h" #if defined(TRACE_PROCESS_EVENT) static BitTrace Process_Event("Process Event"); # define SET_PROCESS_EVENT() Process_Event.Set() # define CLEAR_PROCESS_EVENT() Process_Event.Clear() #else # define SET_PROCESS_EVENT() # define CLEAR_PROCESS_EVENT() #endif //############################################################################# //########################### AbstractEvent ############################# //############################################################################# //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // AbstractEvent::AbstractEvent( Receiver::Message *message, Time time, ClassID class_id ): Node(class_id) { Verify(message); alarmTime = time; // //-------------------------------------------------------- // Allocate some memory to store the message parameters in //-------------------------------------------------------- // size_t long_size = (message->messageLength+3)>>2; messageToSend = (Receiver::Message*)new long[long_size]; Check_Pointer(messageToSend); Register_Pointer(messageToSend); Mem_Copy( messageToSend, message, message->messageLength, long_size*sizeof(long) ); } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // AbstractEvent::~AbstractEvent() { if (messageToSend) { Unregister_Pointer(messageToSend); delete messageToSend; } } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // void AbstractEvent::Process() { Fail("AbstractEvent::Process should not be called!\n"); } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // void AbstractEvent::DumpData() { Fail("AbstractEvent::DumpData should not be called!\n"); } //############################################################################# //############################### Event ################################# //############################################################################# MemoryBlock *Event::GetAllocatedMemory() { static MemoryBlock allocatedMemory(sizeof(Event), 20, 10, "Events"); return &allocatedMemory; } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // Event::Event( Receiver *target, Receiver::Message *message, Time time ): AbstractEvent(message, time, EventClassID), targetReceiver(this) { targetReceiver.Add(target); } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // Event::~Event() { #if defined(TRACE_EVENT_COUNT) // //------------------------------------------- // Delete the link to the current event queue //------------------------------------------- // PlugIteratorOf old_queue_link(this); Node *node; while ((node = old_queue_link.GetCurrent()) != NULL) { Check(node); if ( node->GetClassID() == EventQueueClassID || node->GetClassID() == GeneralEventQueueClassID ) { GeneralEventQueue *q = Cast_Object(GeneralEventQueue*, node); while (q->priorityLevels < 0) { --q; Check(q); } --q->eventCount; if (q->eventCountTrace) { Check(q->eventCountTrace); q->eventCountTrace->TakeSnapshot(q->eventCount); } break; } } #endif } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // void Event::Repost( EventQueue* queue, int priority, Time new_time ) { Check(this); Check(queue); // //------------------------------------------- // Delete the link to the current event queue //------------------------------------------- // PlugIteratorOf old_queue_link(this); Node *node; while ((node = old_queue_link.GetCurrent()) != NULL) { Check(node); if ( node->GetClassID() == EventQueueClassID || node->GetClassID() == GeneralEventQueueClassID || node->GetClassID() == DeferredEventQueueClassID ) { #if defined(TRACE_EVENT_COUNT) if (node->GetClassID() != DeferredEventQueueClassID) { GeneralEventQueue *q = Cast_Object(GeneralEventQueue*, node); while (q->priorityLevels < 0) { --q; Check(q); } --q->eventCount; if (q->eventCountTrace) { Check(q->eventCountTrace); q->eventCountTrace->TakeSnapshot(q->eventCount); } } #endif old_queue_link.Remove(); break; } else { old_queue_link.Next(); } } // //----------------------------------------------------------------------- // Now, if necessary, reset the time and stuff the event in the new event // queue //----------------------------------------------------------------------- // if (new_time.ticks) { alarmTime = new_time; } queue->Enqueue(priority,this); } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // void Event::Defer() { // //----------------------------------------------- // See if the target has a deferred queue already //----------------------------------------------- // Receiver *target = targetReceiver.GetCurrent(); Check(target); PlugIteratorOf blind_links(target); DeferredEventQueue *deferred_queue; while ((deferred_queue = blind_links.ReadAndNext()) != NULL) { if (deferred_queue->GetClassID() == DeferredEventQueueClassID) { break; } } // //---------------------------------------------------------------------- // If we couldn't find a deferred queue, then a new one must be created // and attached to the object //---------------------------------------------------------------------- // if (!deferred_queue) { deferred_queue = new DeferredEventQueue(target); Register_Object(deferred_queue); } // //------------------------------------------------- // Now, simply repost the event to this event queue //------------------------------------------------- // Repost(deferred_queue->deferredEvents,0); } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // void Event::Process() { Check(this); // MP DIAGNOSTIC (task #47): a network-delivered TakeDamage (msgID 21) is // carried by an event -- confirm it actually gets Processed (vs deferred). if (messageToSend && messageToSend->messageID == 21 && getenv("BT_MP_NET")) DEBUG_STREAM << "[mp-evt] Event::Process TakeDamage target=" << (void*)targetReceiver.GetCurrent() << "\n" << std::flush; targetReceiver.GetCurrent()->Receive(this); } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // void Event::DumpData() { Check(this); Receiver *target = targetReceiver.GetCurrent(); Check(target); Check(application); Registry *registry = application->GetRegistry(); if (registry) { Check(registry); Receiver::SharedData *shared_data = registry->GetStaticData(target->GetClassID()); if (shared_data) { Check(shared_data); Derivation *derivation = shared_data->derivedClasses; Check(derivation); Receiver::MessageHandlerSet *handlers = shared_data->activeMessageHandlers; Check(handlers); DEBUG_STREAM << handlers->GetName(messageToSend->messageID) << " message for class " << derivation->className << std::endl << std::flush; } else { goto Vanilla_Message; } } else { Vanilla_Message: DEBUG_STREAM << "Message " << messageToSend->messageID << " for object of classID " << target->GetClassID() << std::endl << std::flush; } } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // void Event::ReleaseLinkHandler( Socket*, Plug* ) { Unregister_Object(this); delete this; } //############################################################################# //########################### NetworkEvent ############################## //############################################################################# //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // NetworkEvent::NetworkEvent( HostID host_ID, NetworkManager::ClientID client_ID, EventStyle event_style, Receiver::Message *message, Time time ): AbstractEvent(message, time, NetworkEventClassID) { hostID = host_ID; clientID = client_ID; eventStyle = event_style; } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // NetworkEvent::~NetworkEvent() { } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // void NetworkEvent::Process() { Check(this); switch (eventStyle) { case SendStyle: Check(application); application->GetNetworkManager()->Send( messageToSend, clientID, hostID ); break; case BroadcastStyle: Check(application); application->GetNetworkManager()->Broadcast( messageToSend, clientID ); break; case ExclusiveBroadcastStyle: Check(application); application->GetNetworkManager()->ExclusiveBroadcast( messageToSend, clientID ); break; } Unregister_Object(this); delete this; } //############################################################################# //####################### GeneralEventQueue ############################ //############################################################################# //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // GeneralEventQueue::GeneralEventQueue(ClassID class_ID): Node(class_ID), pendingEvents(this), timedEvents(this) { priorityLevels = -1; eventCount = 0; #if defined(TRACE_EVENT_COUNT) eventCountTrace = NULL; #endif } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // GeneralEventQueue::GeneralEventQueue(): Node(GeneralEventQueueClassID), pendingEvents(this), timedEvents(this) { priorityLevels = -1; eventCount = 0; #if defined(TRACE_EVENT_COUNT) eventCountTrace = NULL; #endif } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // GeneralEventQueue::~GeneralEventQueue() { #if defined(TRACE_EVENT_COUNT) if (eventCountTrace) { Unregister_Object(eventCountTrace); delete eventCountTrace; } #endif } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // GeneralEventQueue* GeneralEventQueue::Make( int priorities, #if defined(TRACE_EVENT_COUNT) const char* trace_name #else const char* #endif ) { GeneralEventQueue *queue = new GeneralEventQueue[priorities]; Register_Object(queue); queue->priorityLevels = priorities; #if defined(TRACE_EVENT_COUNT) if (trace_name) { Check_Pointer(trace_name); queue->eventCountTrace = new TraceOf( trace_name, 0, Trace::IntegerType, TraceSample::IntegerSnapshot ); Register_Object(queue->eventCountTrace); } #endif return queue; } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // void GeneralEventQueue::Post( int priority, Receiver *target, Receiver::Message *message, Time time ) { Check(this); Check(target); Check(message); // //------------------------------------------------------------------------ // Create a new event, then insert it at the end of the event queue. This // means that timed events get put in sort of haphazardly!!!! //------------------------------------------------------------------------ // Event *event = new Event(target, message, time); Register_Object(event); Enqueue(priority, event); } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // void GeneralEventQueue::SendEvent( int priority, HostID host_ID, NetworkManager::ClientID client_id, Receiver::Message *message, Time when ) { Check(this); Check(message); NetworkEvent *event = new NetworkEvent( host_ID, client_id, NetworkEvent::SendStyle, message, when ); Register_Object(event); Enqueue(priority, event); } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // void GeneralEventQueue::BroadcastEvent( int priority, NetworkManager::ClientID client_ID, Receiver::Message *message, Time when ) { Check(this); Check(message); // // HACK - What is a null network address? // NetworkEvent *event = new NetworkEvent( (NetworkAddress)0, client_ID, NetworkEvent::BroadcastStyle, message, when ); Register_Object(event); Enqueue(priority, event); } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // void GeneralEventQueue::ExclusiveBroadcastEvent( int priority, NetworkManager::ClientID client_ID, Receiver::Message *message, Time when ) { Check(this); Check(message); // // HACK - What is a null network address? // NetworkEvent *event = new NetworkEvent( (NetworkAddress)0, client_ID, NetworkEvent::ExclusiveBroadcastStyle, message, when ); Register_Object(event); Enqueue(priority, event); } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // void GeneralEventQueue::Enqueue( int priority, AbstractEvent *event ) { Check(event); Verify((unsigned)priority < priorityLevels); // //------------------------------------------------------------ // If this is not a timed event, stuff it in the pending queue //------------------------------------------------------------ // if (!event->alarmTime.ticks) { this[priority].pendingEvents.Add(event); } // //---------------------------------------- // Otherwise, sort it into the timed queue //---------------------------------------- // else { ChainIteratorOf timed_events(this[priority].timedEvents); timed_events.Last(); AbstractEvent* next_event = timed_events.GetCurrent(); // //--------------------------------------------------------------------- // If the timed queue is empty, or if we are later than the last entry, // just add the event to the end //--------------------------------------------------------------------- // if (!next_event || next_event->alarmTime.ticks <= event->alarmTime.ticks) { this[priority].timedEvents.Add(event); } // //-------------------------------------------------------------------- // Find the event to insert before. If we run off the beginning, stop // checking and set the iterator to the first event in the queue //-------------------------------------------------------------------- // else { do { timed_events.Previous(); next_event = timed_events.GetCurrent(); if (!next_event) { timed_events.First(); break; } } while (next_event->alarmTime.ticks > event->alarmTime.ticks); // //-------------------------------------------------------------------- // If we didn't run off the queue, we need to insert after the current // event, so bump the iterator forward one event //-------------------------------------------------------------------- // if (next_event) { timed_events.Next(); } // //------------------------------------------------------------------ // Insert the new event ahead of where the iterator currently points //------------------------------------------------------------------ // timed_events.Insert(event); } } #if defined(TRACE_EVENT_COUNT) ++eventCount; if (eventCountTrace) { Check(eventCountTrace); eventCountTrace->TakeSnapshot(eventCount); } #endif #if defined(USE_EVENT_STATISTICS) event_statistics_manager.Maintain(Cast_Object(Event*, event)); #endif } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // AbstractEvent* GeneralEventQueue::PeekAtNextEvent(int min_priority) { Check(this); // //-------------------------------------------------------------------------- // Start at the top of the priority queue, searching backwards until we find // an available event or run off the minimum queue priority //-------------------------------------------------------------------------- // Verify(min_priority >= 0); int priority = priorityLevels; while (--priority >= min_priority) { // //------------------------------------------------------------------- // See if the first event in the timed queue is ready to go. If not, // none of the other timed events will be ready to go either //------------------------------------------------------------------- // ChainIteratorOf timed_events(this[priority].timedEvents); AbstractEvent *event = timed_events.GetCurrent(); if (event) { Check(event); if (event->alarmTime.ticks <= Now().ticks) { return event; } } // //------------------------------ // Now look in the untimed queue //------------------------------ // ChainIteratorOf events(this[priority].pendingEvents); event = events.GetCurrent(); if (event) { Check(event); return event; } } return NULL; } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // Logical GeneralEventQueue::IsPriorityEmpty(int priority) { Check(this); Verify(priority >= 0 && priority < priorityLevels); ChainIteratorOf i(this[priority].pendingEvents); ChainIteratorOf j(this[priority].timedEvents); return !i.GetCurrent() && !j.GetCurrent(); } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // Logical GeneralEventQueue::ProcessOneEvent(int min_priority) { Check(this); Verify(min_priority >= 0); AbstractEvent *event=PeekAtNextEvent(min_priority); if (event) { SET_PROCESS_EVENT(); event->Process(); CLEAR_PROCESS_EVENT(); return True; } return False; } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // void GeneralEventQueue::ProcessAllEvents(int min_priority) { Check(this); Verify(min_priority >= 0); while (ProcessOneEvent(min_priority)); } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // void GeneralEventQueue::FlushAllEvents(int max_priority) { Check(this); Verify(max_priority < priorityLevels); // //----------------------------------------- // Make sure that max_priority is set right //----------------------------------------- // if (max_priority < 0) { max_priority = priorityLevels - 1; } // //--------------------------------------------------------------------- // Step through each of the priority queues and delete any events found // within //--------------------------------------------------------------------- // for (int priority=max_priority; priority>=0; --priority) { // //--------------------------------------- // Delete the events from the timed queue //--------------------------------------- // ChainIteratorOf i(this[priority].timedEvents); AbstractEvent *event; while ((event = i.ReadAndNext()) != NULL) { Unregister_Object(event); delete event; } // //----------------------------------------- // Delete the events from the regular queue //----------------------------------------- // ChainIteratorOf j(this[priority].pendingEvents); while ((event = j.ReadAndNext()) != NULL) { Unregister_Object(event); delete event; } } } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // void GeneralEventQueue::FlushMatchingEvents( Receiver::MessageID target_message, int max_priority ) { Check(this); Verify(max_priority < priorityLevels); // //----------------------------------------- // Make sure that max_priority is set right //----------------------------------------- // if (max_priority < 0) { max_priority = priorityLevels - 1; } // //--------------------------------------------------------------------- // Step through each of the priority queues and delete any events found // within //--------------------------------------------------------------------- // for (int p=max_priority; p>=0; --p) { // //------------------------------------------- // Delete events from the regular queue first //------------------------------------------- // ChainIteratorOf i(this[p].pendingEvents); AbstractEvent *event; while ((event = i.ReadAndNext()) != NULL) { // //------------------------------ // Make sure the message matches //------------------------------ // if ( target_message == Receiver::AnyMessageID || target_message == event->messageToSend->messageID ) { Unregister_Object(event); delete event; } } // //----------------------------------- // Delete events from the timed queue //----------------------------------- // ChainIteratorOf j(this[p].timedEvents); while ((event = j.ReadAndNext()) != NULL) { // //------------------------------ // Make sure the message matches //------------------------------ // if ( target_message == Receiver::AnyMessageID || target_message == event->messageToSend->messageID ) { Unregister_Object(event); delete event; } } } } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // void GeneralEventQueue::DumpEventQueue() { Check(this); // //---------------------------------------------------------------------- // Step through each of the priority queues and display any events found // within //---------------------------------------------------------------------- // CollectionSize total_count = 0; for (int priority=priorityLevels - 1; priority>=0; --priority) { DEBUG_STREAM << "EventQueue priority " << priority << "\n--------------------------------------------------------------\n"; ChainIteratorOf i(this[priority].pendingEvents); AbstractEvent *event; size_t count=0; while ((event = i.ReadAndNext()) != NULL) { ++count; event->DumpData(); } DEBUG_STREAM << count << " priority " << priority << " events\n\n" << std::flush; count = 0; ChainIteratorOf j(this[priority].timedEvents); while ((event = j.ReadAndNext()) != NULL) { ++count; event->DumpData(); } DEBUG_STREAM << count << " priority " << priority << " timed events\n\n" << std::flush; total_count += count; } DEBUG_STREAM << total_count << " total events in queues\n\n" << std::flush; } //############################################################################# //############################ EventQueue ############################### //############################################################################# //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // EventQueue::EventQueue(): GeneralEventQueue(EventQueueClassID) { } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // EventQueue::~EventQueue() { } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // EventQueue* EventQueue::Make( int priorities, #if defined(TRACE_EVENT_COUNT) const char* trace_name #else const char* #endif ) { EventQueue *queue = new EventQueue[priorities]; Register_Object(queue); queue->priorityLevels = priorities; #if defined(TRACE_EVENT_COUNT) if (trace_name) { Check_Pointer(trace_name); queue->eventCountTrace = new TraceOf( trace_name, 0, Trace::IntegerType, TraceSample::IntegerSnapshot ); Register_Object(queue->eventCountTrace); } #endif return queue; } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // void EventQueue::ProcessMatchingEvents( Receiver *receiver, Receiver::MessageID message_ID ) { Check(this); Check(receiver); // //---------------------------------------------------------------- // Step through each of the priority queues and process any events // found within //---------------------------------------------------------------- // for (int p=priorityLevels-1; p>=0; --p) { Event *event; AbstractEvent *abstract_event; ChainIteratorOf i(this[p].pendingEvents); while ((abstract_event = i.ReadAndNext()) != NULL) { Check(abstract_event); event = Cast_Object(Event*, abstract_event); // //------------------------------ // Make sure the message matches //------------------------------ // if ( (event->targetReceiver.GetCurrent() == receiver) && (message_ID == Receiver::AnyMessageID || message_ID == event->messageToSend->messageID) ) { event->Process(); } } ChainIteratorOf j(this[p].timedEvents); while ((abstract_event = j.ReadAndNext()) != NULL) { Check(abstract_event); event = Cast_Object(Event*, abstract_event); // //------------------------------ // Make sure the message matches //------------------------------ // if ( (event->targetReceiver.GetCurrent() == receiver) && (message_ID == Receiver::AnyMessageID || message_ID == event->messageToSend->messageID) ) { event->Process(); } } } } //############################################################################# //######################## DeferredEventQueue ########################### //############################################################################# //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // DeferredEventQueue::DeferredEventQueue(Receiver* target): Node(DeferredEventQueueClassID), waitingReceiver(this) { deferredEvents = new EventQueue; Register_Object(deferredEvents); waitingReceiver.Add(target); } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // DeferredEventQueue::~DeferredEventQueue() { Unregister_Object(deferredEvents); delete deferredEvents; } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // void DeferredEventQueue::ReleaseLinkHandler( Socket*, Plug* ) { Unregister_Object(this); delete this; } #if defined(TEST_CLASS) #include "event.tcp" #endif