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

    How does the Event Handler in Nucleus NET work?

    dan_schiro

      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.

       

       

       

      Event

      Description

      CONOPEN

      connection has opened, CONCLASS

      CONCLOSE

      the other side has closed its side of the connection

      CONFAIL

      connection open attempt has failed

      UNUSED_EVENT_SPOT

      This used to be CONRX, but this has been removed

      CONNULL

      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.

      UDPDATA

      UDP data has arrived on listening port, USERCLASS

      TCPRETRANS

      TCP segment retransmission event

      WINPROBE

      Window Probe event

      TCPACK

      TCP ACK transmission event

      CONTX

      buffer needs to be sent

      SELECT

      TCP Select timeout event

      ARPRESOLVE

      ARP event

      RARP_REQUEST

      A RARP request event

      EV_IGMP_REPORT

      Send an IGMP Group Report

      EV_IP_REASSEMBLY

      Timeout the reassembly of an IPv4 datagram

      EV_IP6_REASSEMBLY

      Timeout the reassembly of an IPv6 datagram

      ICMP_ECHO_TIMEOUT

      Timeout waiting for a ping reply

      IPDATA

      IP data has arrived

      TCPCLOSETIMEOUTSFW2

      Timeout the closing of a connection

      TCPTIMEWAIT

      NAT_CLEANUP_TCP

      NAT specific event

      NAT_CLEANUP_UDP

      NAT specific event

      NAT_TIMEOUT

      NAT specific event

      NAT_CLOSE

      NAT specific event

      NAT_CLEANUP_ICMP

      NAT specific event

      MEM_RESUME

      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,
                                       (UNSIGNED)sizeof(tqe_t),
                                       (UNSIGNED)OS_NO_SUSPEND);
      #else      
               /* 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;
               }
               else
                   status = OS_NO_MEMORY;
      #endif    

       

              /* check status of memory allocation */
               if (status == OS_SUCCESS)
               {
                   return_ptr = (tqe_t *)TLS_Normalize_Ptr(return_ptr);
                   tqe = return_ptr;
               }
               else
               {
                   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(),
                                     NU_EventsDispatcher_ptr))
           {
               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)

       

       

      event

      The event to attach to the timer

      dat

      Data or pointer attached to the event

      extra

      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)

       

       

       

      handler

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

      newevt

      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.