home *** CD-ROM | disk | FTP | other *** search
/ ftp.sustworks.com 2018 / ftp.sustworks.com.zip / ftp.sustworks.com / USBAx8817x_101.dmg / src / Source / AxOutputQueue.cpp next >
C/C++ Source or Header  |  2005-10-08  |  12KB  |  524 lines

  1. /*
  2.  *
  3.  */
  4.  
  5. #include <IOKit/network/IOOutputQueue.h>
  6. #include <IOKit/network/IONetworkStats.h>
  7. #include <IOKit/network/IONetworkController.h>
  8. #include <IOKit/IOLocks.h>
  9.  
  10. #include "AxOutputQueue.h"
  11.  
  12. #define CMD_START (1 << 0)
  13. #define CMD_STOP (1 << 1)
  14. #define CMD_SERVICE (1 << 2)
  15. #define CMD_EXITTHREAD (1 << 3)
  16. #define CMD_SETCAPACITY (1 << 4)
  17. #define CMD_FLUSH (1 << 5)
  18.  
  19. #define Q_RUNNING (1 << 0)
  20. #define Q_STALLED (1 << 1)
  21. #define Q_ACTIVE (1 << 2)
  22. #define Q_THREADALIVE (1 << 3)
  23.  
  24. #define super IOOutputQueue
  25.  
  26. OSDefineMetaClassAndStructors( AxOutputQueue, IOOutputQueue )
  27.  
  28. #define kIOOutputQueueSignature      ((void *) 0xadd1add2)
  29.  
  30. bool AxOutputQueue::init(OSObject *     target,
  31.                          IOOutputAction action,
  32.                          UInt32         capacity) {
  33.    if(!super::init()) {
  34.     return false;
  35.   }
  36.  
  37.   cmdLock = NULL;
  38.   qLock = NULL;
  39.   qThread = NULL;
  40.   qCmd = 0;
  41.   qState = 0;
  42.   blockingCount = 0;
  43.   stallCount = 0;
  44.   outputCount = 0;
  45.   dropCount = 0;
  46.   retryCount = 0;
  47.  
  48.   cmdActive = false;
  49.   _action = action;
  50.   _target = target;
  51.   inQueue = IONew(IOMbufQueue, 1);
  52.   IOMbufQueueInit(inQueue, capacity);
  53.  
  54.   if(inQueue == NULL) {
  55.     IOLog("AxOutputQueue: Failed to create input queue.\n");
  56.     return false;
  57.   }
  58.  
  59.   cmdLock = IOLockAlloc();
  60.   if(cmdLock == NULL) {
  61.     IOLog("AxOutputQueue: Failed to allocate command lock.\n");
  62.     return false;
  63.   }
  64.  
  65.   qLock = IOLockAlloc();
  66.   if(qLock == NULL) {
  67.     IOLog("AxOutputQueue: Failed to allocate queue lock.\n");
  68.     IOLockFree(cmdLock);
  69.     cmdLock = NULL;
  70.     return false;    
  71.   }
  72.   wakeConsumer = (void *)qLock;
  73.  
  74.   qState |= Q_THREADALIVE;
  75.   qThread = IOCreateThread(qThreadEntry, this);
  76.   if(qThread == NULL) {
  77.     IOLog("AxOutputQueue: Failed to start thread.\n");
  78.     IOLockFree(cmdLock);
  79.     cmdLock = NULL;
  80.     IOLockFree(qLock);
  81.     qLock = NULL;
  82.     return false;
  83.   }
  84.  
  85.   return true;;
  86. }
  87.  
  88. //---------------------------------------------------------------------------
  89. // Factory methods that will construct and initialize an AxOutputQueue 
  90. // object.
  91. AxOutputQueue *
  92. AxOutputQueue::withTarget(IONetworkController * target,
  93.                           UInt32                capacity) {
  94.   AxOutputQueue * queue = new AxOutputQueue;
  95.  
  96.   if (queue && !queue->init(target, target->getOutputHandler(), capacity)) {
  97.     queue->release();
  98.     queue = NULL;
  99.   }
  100.   return queue;
  101. }
  102.  
  103. AxOutputQueue *
  104. AxOutputQueue::withTarget(OSObject *     target,
  105.                           IOOutputAction action,
  106.                           UInt32         capacity) {
  107.   AxOutputQueue * queue = new AxOutputQueue;
  108.     
  109.   if (queue && !queue->init(target, action, capacity)) {
  110.     queue->release();
  111.     queue = 0;
  112.   }
  113.   return queue;
  114. }
  115.  
  116. //---------------------------------------------------------------------------
  117. // Release all resources previously allocated before calling super::free().
  118. void AxOutputQueue::free() {
  119.   if(qLock &&  cmdLock) {
  120.     IOLockLock(cmdLock);
  121.     if(cmdActive) {
  122.       IOLog("AxOutputQueue: free: cmdActive == true!\n");
  123.     }
  124.     cmdActive = true;
  125.     IOLockUnlock(cmdLock);
  126.  
  127.     IOLockLock(qLock);
  128.     if(qState & Q_THREADALIVE) {
  129.       qCmd |= CMD_EXITTHREAD;
  130.       while(qCmd & CMD_EXITTHREAD) {
  131.         IOLockWakeup(qLock, wakeConsumer, true);
  132.         IOLockSleep(qLock, NO_EVENT, THREAD_ABORTSAFE);
  133.       }
  134.  
  135.       IOLockWakeup(qLock, wakeConsumer, true);
  136.       IOLockUnlock(qLock);
  137.  
  138.       IOLockLock(cmdLock);
  139.       while(cmdActive) {
  140.         IOLockWakeup(cmdLock, NO_EVENT, true);
  141.         IOLockSleep(cmdLock, NO_EVENT, THREAD_ABORTSAFE);
  142.       }
  143.       IOLockWakeup(cmdLock, NO_EVENT, true);
  144.       IOLockUnlock(cmdLock);
  145.     }
  146.  
  147.     IOLockFree(cmdLock);
  148.     IOLockFree(qLock);
  149.     qLock = NULL;
  150.     cmdLock = NULL;
  151.   }
  152.  
  153.   if(inQueue) {
  154.     IOMbufFree( IOMbufQueueDequeueAll(inQueue) );
  155.     IODelete(inQueue, IOMbufQueue, 1);
  156.     inQueue = NULL;
  157.   }
  158.  
  159.   super::free();
  160. }
  161.  
  162. //---------------------------------------------------------------------------
  163. // Add a single packet, or a chain of packets, to the queue object.
  164. // This method can support multiple clients threads.
  165. UInt32 AxOutputQueue::enqueue(mbuf_t m, void * param) {
  166.   int loopCount;
  167.  
  168.   IOLockLock(qLock);
  169.   loopCount = 0;
  170.   while(qState & Q_RUNNING) {
  171.     if(IOMbufQueueEnqueue(inQueue, m)) {
  172.       IOLockWakeup(qLock, wakeConsumer, true);
  173.       IOLockUnlock(qLock);
  174.       return 0;
  175.     }
  176.  
  177.     if( (blockingCount > 0) || (loopCount > 3)) {
  178.       ++dropCount;
  179.       IOLockWakeup(qLock, wakeConsumer, true);
  180.       IOLockUnlock(qLock);
  181.       IOMbufFree(m);
  182.       return ENOBUFS;
  183.     }
  184.  
  185.     ++blockingCount;
  186.     IOLockSleep(qLock, NO_EVENT, THREAD_ABORTSAFE);
  187.     --blockingCount;
  188.  
  189.     ++loopCount;
  190.   }
  191.  
  192.   if(blockingCount == 0) {
  193.     IOLockWakeup(qLock, wakeConsumer, true);
  194.   } else {
  195.     IOLockWakeup(qLock, NO_EVENT, true);
  196.   }
  197.   ++dropCount;
  198.   IOLockUnlock(qLock);
  199.  
  200.   IOMbufFree(m);
  201.  
  202.   return ENOBUFS;
  203. }
  204.  
  205. //---------------------------------------------------------------------------
  206. // Start or enable the queue.
  207. bool AxOutputQueue::start() {
  208.   if(!sendCmdSync(CMD_START)) {
  209.     IOLog("AxOutputQueue: start: failed.\n");
  210.     return false;
  211.   }
  212.  
  213.   return true;
  214. }
  215.  
  216. //---------------------------------------------------------------------------
  217. // Stop or disable the queue.
  218. bool AxOutputQueue::stop() {
  219.   if(!sendCmdSync(CMD_STOP)) {
  220.     IOLog("AxOutputQueue: stop: failed.\n");
  221.     return false;
  222.   }
  223.  
  224.   return true;
  225. }
  226.  
  227. bool AxOutputQueue::sendCmdSync(UInt32 cmd) {
  228.   IOLockLock(cmdLock);
  229.   if(cmdActive) {
  230.     IOLog("AxOutputQueue: cmdActive: cmdActive == true!\n");
  231.     IOLockUnlock(cmdLock);
  232.     return false;
  233.   }
  234.  
  235.   cmdActive = true;
  236.   IOLockUnlock(cmdLock);
  237.  
  238.   IOLockLock(qLock);
  239.   if(qState & Q_THREADALIVE) {
  240.     qCmd |= cmd;
  241.     IOLockWakeup(qLock, wakeConsumer, true);
  242.     IOLockUnlock(qLock);
  243.  
  244.     IOLockLock(cmdLock);
  245.     while(cmdActive) {
  246.       IOLockWakeup(cmdLock, NO_EVENT, true);
  247.       IOLockSleep(cmdLock, NO_EVENT, THREAD_ABORTSAFE);
  248.     }
  249.     IOLockWakeup(cmdLock, NO_EVENT, true);
  250.     IOLockUnlock(cmdLock);
  251.   } else {
  252.     IOLockUnlock(qLock);
  253.     IOLog("AxOutputQueue: sendCmdSync: thread not alive.\n");
  254.     return false;
  255.   }
  256.  
  257.   return true;
  258. }
  259.  
  260. //---------------------------------------------------------------------------
  261. // If the queue becomes stalled, then service() must be called by the target
  262. // to restart the queue when the target is ready to accept more packets.
  263. bool AxOutputQueue::service(UInt32 options) {
  264.   IOLockLock(qLock);
  265.   qCmd |= CMD_SERVICE;
  266.   IOLockWakeup(qLock, wakeConsumer, true);
  267.   IOLockUnlock(qLock);
  268.  
  269.   return true;
  270. }
  271.  
  272. //---------------------------------------------------------------------------
  273. // Release all packets held by the queue.
  274. UInt32 AxOutputQueue::flush() {
  275.   if(!sendCmdSync(CMD_FLUSH)) {
  276.     IOLog("AxOutputQueue: flush: failed.\n");
  277.     return false;
  278.   }
  279.  
  280.   return true;
  281. }
  282.  
  283. //---------------------------------------------------------------------------
  284. // Change the capacity of the queue.
  285. bool AxOutputQueue::setCapacity(UInt32 capacity) {
  286.   IOLockLock(cmdLock);
  287.   if(cmdActive) {
  288.     IOLog("AxOutputQueue: setCapacity: cmdActive == true!\n");
  289.     IOLockUnlock(cmdLock);
  290.     return false;
  291.   }
  292.  
  293.   cmdActive = true;
  294.   IOLockUnlock(cmdLock);
  295.  
  296.   IOLockLock(qLock);
  297.   if(qState & Q_THREADALIVE) {
  298.     requestedCapacity = capacity;
  299.     qCmd |= CMD_SETCAPACITY;
  300.     IOLockWakeup(qLock, wakeConsumer, true);
  301.     IOLockUnlock(qLock);
  302.  
  303.     IOLockLock(cmdLock);
  304.     while(cmdActive) {
  305.       IOLockWakeup(cmdLock, NO_EVENT, true);
  306.       IOLockSleep(cmdLock, NO_EVENT, THREAD_ABORTSAFE);
  307.     }
  308.     IOLockWakeup(cmdLock, NO_EVENT, true);
  309.     IOLockUnlock(cmdLock);
  310.   } else {
  311.     IOLockWakeup(qLock, wakeConsumer, true);
  312.     IOLockUnlock(qLock);
  313.     IOLog("AxOutputQueue: setCapacity: thread not alive.\n");
  314.     return false;
  315.   }
  316.  
  317.   return true;
  318. }
  319.  
  320. //---------------------------------------------------------------------------
  321. // Returns the current queue capacity.
  322. UInt32 AxOutputQueue::getCapacity() const {
  323.   UInt32 capacity;
  324.  
  325.   IOLockLock(qLock);
  326.   capacity = IOMbufQueueGetCapacity(inQueue);
  327.   IOLockUnlock(qLock);
  328.  
  329.   return capacity;
  330. }
  331.  
  332. UInt32 AxOutputQueue::getSize() const {
  333.   UInt32 size;
  334.  
  335.   IOLockLock(qLock);
  336.   size = IOMbufQueueGetSize(inQueue);
  337.   IOLockUnlock(qLock);
  338.  
  339.   return size;
  340. }
  341.  
  342. UInt32 AxOutputQueue::getDropCount() {
  343.   return dropCount;
  344. }
  345.  
  346. UInt32 AxOutputQueue::getOutputCount() {
  347.   return outputCount;
  348. }
  349.  
  350. UInt32 AxOutputQueue::getRetryCount() {
  351.   return retryCount;
  352. }
  353.  
  354. UInt32 AxOutputQueue::getStallCount() {
  355.   return stallCount;
  356. }
  357.  
  358. UInt32 AxOutputQueue::getState() const {
  359.   UInt32 state;
  360.  
  361.   state = qState;
  362.  
  363.   return state & 0x07;
  364. }
  365.  
  366. void AxOutputQueue::qThreadEntry(void *ob) {
  367.   AxOutputQueue *me;
  368.   
  369.   if(ob) {
  370.     if(me = OSDynamicCast(AxOutputQueue, (OSObject *)ob)) {
  371.       me->threadGo();
  372.     }
  373.   } else {
  374.     IOLog("AxOutputQueue: ob == NULL!\n");
  375.   }
  376.  
  377.   
  378.   IOExitThread();
  379. }
  380.  
  381. void AxOutputQueue::threadGo() {
  382.   bool didSomething;
  383.   mbuf_t pkt;
  384.   UInt32 status;
  385.  
  386.   didSomething = false;
  387.  
  388.   IOLockLock(qLock);
  389.   while(true) {
  390.  
  391.     while(qCmd) {
  392.       didSomething = true;
  393.       if(qCmd & CMD_EXITTHREAD) {
  394.         qCmd &= ~CMD_EXITTHREAD;
  395.         qState &= ~Q_THREADALIVE;
  396.  
  397.         while(blockingCount > 0) {
  398.           IOLockWakeup(qLock, NO_EVENT, true);
  399.           IOLockSleep(qLock, wakeConsumer, THREAD_ABORTSAFE);
  400.         }
  401.  
  402.         IOLockWakeup(qLock, NO_EVENT, true);
  403.         IOLockUnlock(qLock);
  404.  
  405.         IOLockLock(cmdLock);
  406.         cmdActive = false;
  407.         IOLockWakeup(cmdLock, NO_EVENT, true);
  408.         IOLockUnlock(cmdLock);
  409.         return;
  410.       }
  411.  
  412.       if(qCmd & CMD_START) {
  413.         qCmd &= ~CMD_START;
  414.         if(!(qState & Q_RUNNING)) {
  415.           qState |= Q_RUNNING;
  416.           qState &= ~Q_STALLED;
  417.         }
  418.         ackCmdSync();
  419.       }
  420.  
  421.       if(qCmd & CMD_SERVICE) {
  422.         qCmd &= ~CMD_SERVICE;
  423.         qState &= ~Q_STALLED;
  424.       }
  425.  
  426.       if(qCmd & CMD_FLUSH) {
  427.         qCmd &= ~CMD_FLUSH;
  428.         dropCount += IOMbufQueueGetSize(inQueue);
  429.         pkt = IOMbufQueueDequeueAll(inQueue);
  430.         IOLockWakeup(qLock, NO_EVENT, true);    
  431.         IOLockUnlock(qLock);
  432.  
  433.         IOMbufFree(pkt);
  434.  
  435.         IOLockLock(cmdLock);
  436.         cmdActive = false;
  437.         IOLockWakeup(cmdLock, NO_EVENT, true);
  438.         IOLockUnlock(cmdLock);
  439.  
  440.         IOLockLock(qLock);
  441.       }
  442.  
  443.       if(qCmd & CMD_STOP) {
  444.         qCmd &= ~CMD_STOP;
  445.         qState &= ~Q_RUNNING;
  446.         while(blockingCount > 0) {
  447.           IOLockWakeup(qLock, NO_EVENT, true);
  448.           IOLockSleep(qLock, wakeConsumer, THREAD_ABORTSAFE);
  449.         }
  450.         ackCmdSync();
  451.       }
  452.  
  453.       if(qCmd & CMD_SETCAPACITY) {
  454.         qCmd &= ~CMD_SETCAPACITY;
  455.         IOMbufQueueSetCapacity(inQueue, requestedCapacity);
  456.         ackCmdSync();
  457.       }
  458.     }
  459.  
  460.     while(!qCmd && !(qState & Q_STALLED) && (qState & Q_RUNNING) &&
  461.           (pkt = IOMbufQueueDequeue(inQueue)) ) {
  462.       qState |= Q_ACTIVE;
  463.       qCmd &= ~CMD_SERVICE;
  464.       didSomething = true;
  465.       IOLockUnlock(qLock);
  466.  
  467.       status = (_target->*_action)( pkt, 0 );
  468.  
  469.       IOLockLock(qLock);
  470.  
  471.       if(status == kIOReturnOutputSuccess) {
  472.         // Fast-path the typical code path.
  473.         ++outputCount;
  474.       } else {
  475.         // Look at the return status and update statistics counters.
  476.         switch (status & kIOOutputStatusMask) {
  477.         default:
  478.         case kIOOutputStatusAccepted:
  479.           ++outputCount;
  480.           break;
  481.         case kIOOutputStatusRetry:
  482.           IOMbufQueuePrepend(inQueue, pkt);
  483.           ++retryCount;
  484.           break;
  485.         }
  486.  
  487.         // Handle the requested action.
  488.         switch (status & kIOOutputCommandMask) {
  489.         case kIOOutputCommandStall:
  490.           qState |= Q_STALLED;
  491.           ++stallCount;
  492.           break;
  493.         default:
  494.           break;
  495.         }
  496.       }
  497.       qState &= ~Q_ACTIVE;
  498.  
  499.       if(qCmd & CMD_SERVICE) {
  500.         qCmd &= ~CMD_SERVICE;
  501.         qState &= ~Q_STALLED;
  502.       }
  503.     }
  504.  
  505.     IOLockWakeup(qLock, NO_EVENT, true);
  506.     if(didSomething == false) {
  507.       IOLockSleep(qLock, wakeConsumer, THREAD_ABORTSAFE);
  508.     }
  509.     didSomething = false;
  510.   }
  511. }
  512.  
  513. void AxOutputQueue::ackCmdSync() {
  514.   IOLockWakeup(qLock, NO_EVENT, true);
  515.   IOLockUnlock(qLock);
  516.  
  517.   IOLockLock(cmdLock);
  518.   cmdActive = false;
  519.   IOLockWakeup(cmdLock, NO_EVENT, true);
  520.   IOLockUnlock(cmdLock);
  521.  
  522.   IOLockLock(qLock);
  523. }
  524.