0 Replies Latest reply on Aug 6, 2012 8:01 AM by dan_schiro

    How does the Event Handler in Nucleus NET work?


      The Events Dispatcher


      Events are used throughout Nucleus NET for various  tasks: window probes, retransmissions, DHCP, ARP requests, and keeping  connections alive to name a few. Many events are required at the same  time. These events must be executed in an orderly fashion so that no  event is lost.


      The Events Dispatcher schedules and handles events  within Nucleus NET. The Events Dispatcher is a task that removes events  from the Event List and the Event Queue, deciphers the event, and  processes it accordingly. Events are placed on the Event List by the  Timer task. Events are placed on the Event Queue by different networking  processes.







      connection has opened, CONCLASS


      the other side has closed its side of the connection


      connection open attempt has failed


      This used to be CONRX, but this has been removed


      Just a null event... Used to wake up the  dispatcher from a indefinite sleep should a timer queue entry be  posted...could be used for other purposes also.


      UDP data has arrived on listening port, USERCLASS


      TCP segment retransmission event


      Window Probe event


      TCP ACK transmission event


      buffer needs to be sent


      TCP Select timeout event


      ARP event


      A RARP request event


      Send an IGMP Group Report


      Timeout the reassembly of an IPv4 datagram


      Timeout the reassembly of an IPv6 datagram


      Timeout waiting for a ping reply


      IP data has arrived


      Timeout the closing of a connection



      NAT specific event


      NAT specific event


      NAT specific event


      NAT specific event


      NAT specific event


      Resume a task suspended on memory allocation






      Setting Timers


      Timer events are set by the network processes on events  that should not be executed immediately, but rather after some interval  of time. The network processes do this by calling TQ_Timerset() which  sets a timer for an event. This event is then placed on the Event List  (EQ_Event_List).


      The Event List is kept in due time order. This certifies  the next event to expire will be at the front of the list. Since it is  possible for multiple events to be due at the same time, it is necessary  to organize the list to prevent it from becoming too long. Each event  on the Event List has a duplist. The duplist is a list of duplicate  events (events who have duplicate due times). This shorter list reduces  the time to insert new events onto the Event List.


      It is possible that before the timer interval finishes, a  network process determines that the event is unnecessary. A process can  cancel a timer event using the routine TQ_Timerunset(). This function  will then remove the event from the Event List.



      FILE: TQ.C


      FUNCTION: TQ_Timerset


      *   FUNCTION                                                             
      *       TQ_Timerset
      *   DESCRIPTION                                                          
      *       Set an async timer, and when time elapses sticks an event in the
      *       network event queue.                                            
      *       Class, event, dat is what gets posted when howlong times out.   
      *   INPUTS                                                               
      *       event                   The event to attach to the timer                                                           
      *       dat                     Data or pointer attached to the event                                                      
      *       howlong                 How long for the timer                                                      
      *       extra                   An extra parameter for data.                                                     
      *   OUTPUTS                                                              
      *       OS_SUCCESS                                                      
      *       -1                                                              
      STATUS TQ_Timerset(TQ_EVENT event, UNSIGNED dat, UNSIGNED howlong,
                          UNSIGNED extra)
           tqe_t       *tqe;
           STATUS      status;
           tqe_t       *return_ptr = OS_NULL;


          /* Get an entry from the freelist.  */
           tqe = (tqe_t *) DLL_Dequeue (&EQ_Event_Freelist);


          /* Check to see if an entry was found.  If one was not found, need
              to allocate a new one. */
           if (!tqe)
               /* Get some memory for the new entry. */


      #if (INCLUDE_STATIC_BUILD == OS_FALSE)        
               status = OS_Allocate_Memory(MEM_Cached, (void **) &return_ptr,
               /* Assign memory to the TQ entry */
               if(No_of_Entry != NET_MAX_TQ_ENTRIES )
                   return_ptr = &NET_TQ_Entry_Memory[No_of_Entry++];
                   status = OS_SUCCESS;
                   status = OS_NO_MEMORY;


              /* check status of memory allocation */
               if (status == OS_SUCCESS)
                   return_ptr = (tqe_t *)TLS_Normalize_Ptr(return_ptr);
                   tqe = return_ptr;
                   NLOG_Error_Log ("Unable to alloc memory for timer entry", NERR_RECOVERABLE,
                                       __FILE__, __LINE__);
                   return (-1);


          /* Set up the new entry. */
           tqe->tqe_event = event;
           tqe->tqe_data = dat;
           tqe->tqe_ext_data = extra;
           tqe->duetime = OS_Retrieve_Clock() + (UNSIGNED) howlong;
           tqe->tqe_id = EQ_ID_VALUE;


          /* Clear out the new entry's duplist. */
           tqe->duplist.flink = (tqe_t *)OS_NULL;
           tqe->duplist.blink = (tqe_t *)OS_NULL;


          /* Place the new entry on the timerlist. */
           TQ_Post ((tqe_t *) &EQ_Event_List, tqe);


          /* Check to see if the current task is the  events dispatcher.  If it
              is we do not want to place an item onto the event queue.  If the queue
              is full the events dispatcher will suspend on the queue, and since
              the events dispatcher is the only task that removes items from the
              queue, deadlock will occur. */
           if (OS_MATCH_CURRENT_TASK(OS_Current_Task_Pointer(),
               return (OS_SUCCESS);


          /* Wake up the event dispatcher from an indefinite wait
              if this is the first entry on the timer list. */
           if (EQ_Event_List.flink == tqe)
               EQ_Put_Event(CONNULL, dat, 0);


          return (OS_SUCCESS);


      } /* TQ_Timerset */






      Setting Events


      The setting of an event adds that event to the Event  Queue (eQueue), which causes the event to be handled by the Events  Dispatcher after all expired timer events have been processed.


      STATUS EQ_Put_Event(TQ_EVENT event, UNSIGNED dat, UNSIGNED extra)




      The event to attach to the timer


      Data or pointer attached to the event


      An extra parameter for data








      Registering Events


      As networking processes are executed, it may be  necessary to dynamically add to the list of possible events. This can be  done by registering a new event. To register a new event, the event  handler is passed to the registration function, and the macro value  associated with that event is passed back. Whenever an event is set with  the system, the macro value returned must be used to refer to the  registered event.




      STATUS EQ_Register_Event(EQ_Handler handler, TQ_EVENT *newevt)





      The event handler function that will be responsible for handling the newly registered event when it expires.


      The new macro value will be returned through this parameter.








      Handling Events


      The handling of events is a continuous loop the Event  Dispatcher must follow. It begins with checking the Event List. Recall  that the Event List is populated by TQ_Timerset(). If events exist  within the Event List, the Events Dispatcher must check the due times of  these events. If an event is due, the variable waittime is set to  NU_NO_SUSPEND. If an event is not due, waittime is set to the earliest  due time. If an event does not exist, waittime is set to NU_SUSPEND.


      At this point it is required that the Events Dispatcher  relinquish control to the system to prevent system starvation. If an  event is due, the dispatcher will call NU_Relinquish(). If waittime is  anything either than NU_NO_SUSPEND, an event is not ready to be  processed, and the dispatcher will suspend on the Event Queue for the  amount of time specified by waittime , or until an event is received.


      If an event exists, the dispatcher will begin processing  it. Many timer events can expire at the same time, however, the  dispatcher can only address them one at a time. To handle each of these  events, the dispatcher will check the duplist. If events are present on  the duplist, each one will be placed on the Event Queue, to be handled  after the current event has been processed.


      Now, the Events Dispatcher will determine what type of  event has been set, and call the appropriate event handler. With the  event handler completed, the Events Dispatcher is ready to process the  next event, if one exists.