HOME       UP       PREV       NEXT (Overall Farming Compilation Flow)  

LLC Dispatcher module, transmit-side multiplexor with exclusion Mutex.

class Dispatcher
{ static Mutex tx_mutex;

 // Transmit interface - this is a simple exclusion zone:
 // only one application can send at a time
 public static void ClientWriteInt(uint data,   KiwiFarmingInterface.Framing kf, uint port)
 {
   if (kf == KiwiFarmingInterface.Framing.Start)
   { 
     // If start of write - need to write LLC header
     Monitor.Wait(tx_mutex); // Wait here until we gain the lock.
     KiwiNetworkDevice.WriteInt(llc_header_const<<16 | port,
                                KiwiFarmingInterface.Framing.Start);
     KiwiNetworkDevice.WriteInt(data,  KiwiFarmingInterface.Framing.Mid);
   }
   else if (kf==KiwiFarmingInterface.Framing.End)
   { 
     // If end of write - need to release lock
     KiwiNetworkDevice.WriteInt(data, kf);
     Monitor.PulseAll(tx_mutex);
   }
   else KiwiNetworkDevice.WriteInt(data, kf);
 }

Each application server sends a thread into the dispatcher via its presentation layer.

The LAN receiver thread copies in a frame and unblocks the appropriate client thread.

Each application writes to the LAN using its own thread, passed through its instance of the presentation layer and contending for exclusive access to the MAC-layer PacketSend method.

 ...
   static int PortsInUse = 0;

   public class Farmable
   {
     public volatile bool rx_ready;
     public void IndicateRX()  { rx_ready = true; }
     ...
   }
   static Farmable [] PortBindings = new Farmable [Ports];

   public static int Register(string id)
   {  // NB: entirely executed at compile time under KiwiC.
     PortBindings[PortsInUse] = new Farmable(id);
     return PortsInUse++;
   }

   static void ReceiverThread()
   {
       // LLC-like header scan
       rxpktLen = KiwiNetworkDevice.ReadInt();
       WriteLine("Dispatcher - pkt len word {0}", rxpktLen);
       uint llc_header;
       do llc_header = KiwiNetworkDevice.ReadInt();
       // scan for LLC protocol id and flags.
       while (llc_header>>16 != llc_header_const)
       uint port = (uint)(llc_header & 0xFF);
       if (port >= PortsInUse)
       { WriteLine("Discarded frame ({1} words) rx'd on port {0}", port, rxpktLen, PortsInUse);
         KiwiNetworkDevice.DiscardRxFrame();
       }
       else
       { WriteLine("Forwarding frame {1} rx'd on port {0}.", port, rxpktLen);
         lock (rx_mutex)
         { PortBindings[port].rx_ready = true;
           // Set a ready flag and wait for client application
           while (PortBindings[port].rx_ready)
              { Kiwi.NoUnroll(); Monitor.Wait(rx_mutex); }
           Monitor.PulseAll(rx_mutex);
         }
       }
    }

28: (C) 2011, DJ Greaves, S Singh, University of Cambridge, Computer Laboratory.