Bug 1116458 - Introduce a queue for command chain to avoid running simultaneously. r=dlee
authorHenry Chang <hchang@mozilla.com>
Mon, 05 Jan 2015 16:21:58 +0800
changeset 247924 67ea86c1f2e9d6bb2a80199300e3aa518bc1f0c5
parent 247923 8768e1f8108ed4b898a83713ea83efe08c1754ff
child 247925 587c2fdd0c3bd2572acd682f397d415b99497972
push id4489
push userraliiev@mozilla.com
push dateMon, 23 Feb 2015 15:17:55 +0000
treeherdermozilla-beta@fd7c3dc24146 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersdlee
bugs1116458
milestone37.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1116458 - Introduce a queue for command chain to avoid running simultaneously. r=dlee
dom/system/gonk/NetworkUtils.cpp
dom/system/gonk/NetworkUtils.h
--- a/dom/system/gonk/NetworkUtils.cpp
+++ b/dom/system/gonk/NetworkUtils.cpp
@@ -117,16 +117,17 @@ typedef Tuple3<NetdCommand*, CommandChai
 
 static NetworkUtils* gNetworkUtils;
 static nsTArray<QueueData> gCommandQueue;
 static CurrentCommand gCurrentCommand;
 static bool gPending = false;
 static nsTArray<nsCString> gReason;
 static NetworkParams *gWifiTetheringParms = 0;
 
+static nsTArray<CommandChain*> gCommandChainQueue;
 
 const CommandFunc NetworkUtils::sWifiEnableChain[] = {
   NetworkUtils::clearWifiTetherParms,
   NetworkUtils::wifiFirmwareReload,
   NetworkUtils::startAccessPointDriver,
   NetworkUtils::setAccessPoint,
   NetworkUtils::startSoftAP,
   NetworkUtils::setInterfaceUp,
@@ -380,30 +381,46 @@ static void postMessage(NetworkParams& a
   MOZ_ASSERT(gNetworkUtils->getMessageCallback());
 
   aResult.mId = aOptions.mId;
 
   if (*(gNetworkUtils->getMessageCallback()))
     (*(gNetworkUtils->getMessageCallback()))(aResult);
 }
 
+void NetworkUtils::runNextQueuedCommandChain()
+{
+  if (gCommandChainQueue.IsEmpty()) {
+    NU_DBG("No command chain left in the queue. Done!");
+    return;
+  }
+  NU_DBG("Process the queued command chain.");
+  CommandChain* nextChain = gCommandChainQueue[0];
+  NetworkResultOptions newResult;
+  next(nextChain, false, newResult);
+}
+
 void NetworkUtils::next(CommandChain* aChain, bool aError, NetworkResultOptions& aResult)
 {
   if (aError) {
     ErrorCallback onError = aChain->getErrorCallback();
     if(onError) {
       aResult.mError = true;
       (*onError)(aChain->getParams(), aResult);
     }
     delete aChain;
+    gCommandChainQueue.RemoveElementAt(0);
+    runNextQueuedCommandChain();
     return;
   }
   CommandFunc f = aChain->getNextCommand();
   if (!f) {
     delete aChain;
+    gCommandChainQueue.RemoveElementAt(0);
+    runNextQueuedCommandChain();
     return;
   }
 
   (*f)(aChain, next, aResult);
 }
 
 CommandResult::CommandResult(int32_t aResultCode)
   : mIsPending(false)
@@ -932,57 +949,76 @@ void NetworkUtils::setInterfaceDns(Comma
 #undef GET_FIELD
 
 /*
  * Netd command success/fail function
  */
 #define ASSIGN_FIELD(prop)  aResult.prop = aChain->getParams().prop;
 #define ASSIGN_FIELD_VALUE(prop, value)  aResult.prop = value;
 
-#define RUN_CHAIN(param, cmds, err)                                \
-  uint32_t size = sizeof(cmds) / sizeof(CommandFunc);              \
-  CommandChain* chain = new CommandChain(param, cmds, size, err);  \
-  NetworkResultOptions result;                                     \
-  next(chain, false, result);
+template<size_t N>
+void NetworkUtils::runChain(const NetworkParams& aParams,
+                            const CommandFunc (&aCmds)[N],
+                            ErrorCallback aError)
+{
+  CommandChain* chain = new CommandChain(aParams, aCmds, N, aError);
+  gCommandChainQueue.AppendElement(chain);
+
+  if (gCommandChainQueue.Length() > 1) {
+    NU_DBG("%d command chains are queued. Wait!", gCommandChainQueue.Length());
+    return;
+  }
+
+  NetworkResultOptions result;
+  NetworkUtils::next(gCommandChainQueue[0], false, result);
+}
+
+// Called to clean up the command chain and process the queued command chain if any.
+void NetworkUtils::finalizeSuccess(CommandChain* aChain,
+                                   NetworkResultOptions& aResult)
+{
+  next(aChain, false, aResult);
+}
 
 void NetworkUtils::wifiTetheringFail(NetworkParams& aOptions, NetworkResultOptions& aResult)
 {
   // Notify the main thread.
   postMessage(aOptions, aResult);
 
   // If one of the stages fails, we try roll back to ensure
   // we don't leave the network systems in limbo.
   ASSIGN_FIELD_VALUE(mEnable, false)
-  RUN_CHAIN(aOptions, sWifiFailChain, nullptr)
+  runChain(aOptions, sWifiFailChain, nullptr);
 }
 
 void NetworkUtils::wifiTetheringSuccess(CommandChain* aChain,
                                         CommandCallback aCallback,
                                         NetworkResultOptions& aResult)
 {
   ASSIGN_FIELD(mEnable)
 
   if (aChain->getParams().mEnable) {
     MOZ_ASSERT(!gWifiTetheringParms);
     gWifiTetheringParms = new NetworkParams(aChain->getParams());
   }
   postMessage(aChain->getParams(), aResult);
+  finalizeSuccess(aChain, aResult);
 }
 
 void NetworkUtils::usbTetheringFail(NetworkParams& aOptions,
                                     NetworkResultOptions& aResult)
 {
   // Notify the main thread.
   postMessage(aOptions, aResult);
   // Try to roll back to ensure
   // we don't leave the network systems in limbo.
   // This parameter is used to disable ipforwarding.
   {
     aOptions.mEnable = false;
-    RUN_CHAIN(aOptions, sUSBFailChain, nullptr)
+    runChain(aOptions, sUSBFailChain, nullptr);
   }
 
   // Disable usb rndis function.
   {
     NetworkParams options;
     options.mEnable = false;
     options.mReport = false;
     gNetworkUtils->enableUsbRndis(options);
@@ -990,68 +1026,73 @@ void NetworkUtils::usbTetheringFail(Netw
 }
 
 void NetworkUtils::usbTetheringSuccess(CommandChain* aChain,
                                        CommandCallback aCallback,
                                        NetworkResultOptions& aResult)
 {
   ASSIGN_FIELD(mEnable)
   postMessage(aChain->getParams(), aResult);
+  finalizeSuccess(aChain, aResult);
 }
 
 void NetworkUtils::networkInterfaceAlarmFail(NetworkParams& aOptions, NetworkResultOptions& aResult)
 {
   postMessage(aOptions, aResult);
 }
 
 void NetworkUtils::networkInterfaceAlarmSuccess(CommandChain* aChain,
                                                 CommandCallback aCallback,
                                                 NetworkResultOptions& aResult)
 {
   // TODO : error is not used , and it is conflict with boolean type error.
   // params.error = parseFloat(params.resultReason);
   postMessage(aChain->getParams(), aResult);
+  finalizeSuccess(aChain, aResult);
 }
 
 void NetworkUtils::updateUpStreamFail(NetworkParams& aOptions, NetworkResultOptions& aResult)
 {
   postMessage(aOptions, aResult);
 }
 
 void NetworkUtils::updateUpStreamSuccess(CommandChain* aChain,
                                          CommandCallback aCallback,
                                          NetworkResultOptions& aResult)
 {
   ASSIGN_FIELD(mCurExternalIfname)
   ASSIGN_FIELD(mCurInternalIfname)
   postMessage(aChain->getParams(), aResult);
+  finalizeSuccess(aChain, aResult);
 }
 
 void NetworkUtils::setDhcpServerFail(NetworkParams& aOptions, NetworkResultOptions& aResult)
 {
   aResult.mSuccess = false;
   postMessage(aOptions, aResult);
 }
 
 void NetworkUtils::setDhcpServerSuccess(CommandChain* aChain, CommandCallback aCallback, NetworkResultOptions& aResult)
 {
   aResult.mSuccess = true;
   postMessage(aChain->getParams(), aResult);
+  finalizeSuccess(aChain, aResult);
 }
 
 void NetworkUtils::wifiOperationModeFail(NetworkParams& aOptions, NetworkResultOptions& aResult)
 {
   postMessage(aOptions, aResult);
 }
 
 void NetworkUtils::wifiOperationModeSuccess(CommandChain* aChain,
                                             CommandCallback aCallback,
                                             NetworkResultOptions& aResult)
 {
   postMessage(aChain->getParams(), aResult);
+  finalizeSuccess(aChain, aResult);
 }
 
 void NetworkUtils::setDnsFail(NetworkParams& aOptions, NetworkResultOptions& aResult)
 {
   postMessage(aOptions, aResult);
 }
 
 #undef ASSIGN_FIELD
@@ -1183,17 +1224,17 @@ void NetworkUtils::onNetdMessage(NetdCom
       if (gWifiTetheringParms) {
         char linkdownReason[MAX_COMMAND_SIZE];
         snprintf(linkdownReason, MAX_COMMAND_SIZE - 1,
                  "Iface linkstate %s down",
                  NS_ConvertUTF16toUTF8(gWifiTetheringParms->mIfname).get());
 
         if (!strcmp(reason, linkdownReason)) {
           NU_DBG("Wifi link down, restarting tethering.");
-          RUN_CHAIN(*gWifiTetheringParms, sWifiRetryChain, wifiTetheringFail)
+          runChain(*gWifiTetheringParms, sWifiRetryChain, wifiTetheringFail);
         }
       }
     }
 
     nextNetdCommand();
     return;
   }
 
@@ -1237,19 +1278,19 @@ CommandResult NetworkUtils::setDhcpServe
 {
   if (aOptions.mEnabled) {
     aOptions.mWifiStartIp = aOptions.mStartIp;
     aOptions.mWifiEndIp = aOptions.mEndIp;
     aOptions.mIp = aOptions.mServerIp;
     aOptions.mPrefix = aOptions.mMaskLength;
     aOptions.mLink = NS_ConvertUTF8toUTF16("up");
 
-    RUN_CHAIN(aOptions, sStartDhcpServerChain, setDhcpServerFail)
+    runChain(aOptions, sStartDhcpServerChain, setDhcpServerFail);
   } else {
-    RUN_CHAIN(aOptions, sStopDhcpServerChain, setDhcpServerFail)
+    runChain(aOptions, sStopDhcpServerChain, setDhcpServerFail);
   }
   return CommandResult::Pending();
 }
 
 /**
  * Set DNS servers for given network interface.
  */
 CommandResult NetworkUtils::setDNS(NetworkParams& aOptions)
@@ -1278,17 +1319,17 @@ CommandResult NetworkUtils::setDNS(Netwo
   property_get("net.dnschange", dnschange, "0");
 
   char num[PROPERTY_VALUE_MAX];
   snprintf(num, PROPERTY_VALUE_MAX - 1, "%d", atoi(dnschange) + 1);
   property_set("net.dnschange", num);
 
   // DNS needs to be set through netd since JellyBean (4.3).
   if (SDK_VERSION >= 18) {
-    RUN_CHAIN(aOptions, sSetDnsChain, setDnsFail)
+    runChain(aOptions, sSetDnsChain, setDnsFail);
     return CommandResult::Pending();
   }
 
   return SUCCESS;
 }
 
 CommandResult NetworkUtils::configureInterface(NetworkParams& aOptions)
 {
@@ -1595,41 +1636,41 @@ CommandResult NetworkUtils::removeSecond
 
   doCommand(command, nullptr, nullptr);
   return SUCCESS;
 }
 
 CommandResult NetworkUtils::setNetworkInterfaceAlarm(NetworkParams& aOptions)
 {
   NU_DBG("setNetworkInterfaceAlarms: %s", GET_CHAR(mIfname));
-  RUN_CHAIN(aOptions, sNetworkInterfaceSetAlarmChain, networkInterfaceAlarmFail);
+  runChain(aOptions, sNetworkInterfaceSetAlarmChain, networkInterfaceAlarmFail);
   return CommandResult::Pending();
 }
 
 CommandResult NetworkUtils::enableNetworkInterfaceAlarm(NetworkParams& aOptions)
 {
   NU_DBG("enableNetworkInterfaceAlarm: %s", GET_CHAR(mIfname));
-  RUN_CHAIN(aOptions, sNetworkInterfaceEnableAlarmChain, networkInterfaceAlarmFail);
+  runChain(aOptions, sNetworkInterfaceEnableAlarmChain, networkInterfaceAlarmFail);
   return CommandResult::Pending();
 }
 
 CommandResult NetworkUtils::disableNetworkInterfaceAlarm(NetworkParams& aOptions)
 {
   NU_DBG("disableNetworkInterfaceAlarms: %s", GET_CHAR(mIfname));
-  RUN_CHAIN(aOptions, sNetworkInterfaceDisableAlarmChain, networkInterfaceAlarmFail);
+  runChain(aOptions, sNetworkInterfaceDisableAlarmChain, networkInterfaceAlarmFail);
   return CommandResult::Pending();
 }
 
 /**
  * handling main thread's reload Wifi firmware request
  */
 CommandResult NetworkUtils::setWifiOperationMode(NetworkParams& aOptions)
 {
   NU_DBG("setWifiOperationMode: %s %s", GET_CHAR(mIfname), GET_CHAR(mMode));
-  RUN_CHAIN(aOptions, sWifiOperationModeChain, wifiOperationModeFail);
+  runChain(aOptions, sWifiOperationModeChain, wifiOperationModeFail);
   return CommandResult::Pending();
 }
 
 /**
  * handling main thread's enable/disable WiFi Tethering request
  */
 CommandResult NetworkUtils::setWifiTethering(NetworkParams& aOptions)
 {
@@ -1649,21 +1690,21 @@ CommandResult NetworkUtils::setWifiTethe
       aOptions.mDns2 = NS_ConvertUTF8toUTF16(interfaceProperties.dns2);
     }
   }
   dumpParams(aOptions, "WIFI");
 
   if (enable) {
     NU_DBG("Starting Wifi Tethering on %s <-> %s",
            GET_CHAR(mInternalIfname), GET_CHAR(mExternalIfname));
-    RUN_CHAIN(aOptions, sWifiEnableChain, wifiTetheringFail)
+    runChain(aOptions, sWifiEnableChain, wifiTetheringFail);
   } else {
     NU_DBG("Stopping Wifi Tethering on %s <-> %s",
            GET_CHAR(mInternalIfname), GET_CHAR(mExternalIfname));
-    RUN_CHAIN(aOptions, sWifiDisableChain, wifiTetheringFail)
+    runChain(aOptions, sWifiDisableChain, wifiTetheringFail);
   }
   return CommandResult::Pending();
 }
 
 CommandResult NetworkUtils::setUSBTethering(NetworkParams& aOptions)
 {
   bool enable = aOptions.mEnable;
   IFProperties interfaceProperties;
@@ -1681,21 +1722,21 @@ CommandResult NetworkUtils::setUSBTether
       aOptions.mDns2 = NS_ConvertUTF8toUTF16(interfaceProperties.dns2);
     }
   }
   dumpParams(aOptions, "USB");
 
   if (enable) {
     NU_DBG("Starting USB Tethering on %s <-> %s",
            GET_CHAR(mInternalIfname), GET_CHAR(mExternalIfname));
-    RUN_CHAIN(aOptions, sUSBEnableChain, usbTetheringFail)
+    runChain(aOptions, sUSBEnableChain, usbTetheringFail);
   } else {
     NU_DBG("Stopping USB Tethering on %s <-> %s",
            GET_CHAR(mInternalIfname), GET_CHAR(mExternalIfname));
-    RUN_CHAIN(aOptions, sUSBDisableChain, usbTetheringFail)
+    runChain(aOptions, sUSBDisableChain, usbTetheringFail);
   }
   return CommandResult::Pending();
 }
 
 void NetworkUtils::escapeQuote(nsCString& aString)
 {
   aString.ReplaceSubstring("\\", "\\\\");
   aString.ReplaceSubstring("\"", "\\\"");
@@ -1795,17 +1836,17 @@ CommandResult NetworkUtils::enableUsbRnd
   return SUCCESS;
 }
 
 /**
  * handling upstream interface change event.
  */
 CommandResult NetworkUtils::updateUpStream(NetworkParams& aOptions)
 {
-  RUN_CHAIN(aOptions, sUpdateUpStreamChain, updateUpStreamFail)
+  runChain(aOptions, sUpdateUpStreamChain, updateUpStreamFail);
   return CommandResult::Pending();
 }
 
 void NetworkUtils::sendBroadcastMessage(uint32_t code, char* reason)
 {
   NetworkResultOptions result;
   switch(code) {
     case NETD_COMMAND_INTERFACE_CHANGE:
--- a/dom/system/gonk/NetworkUtils.h
+++ b/dom/system/gonk/NetworkUtils.h
@@ -355,16 +355,25 @@ private:
 
   static void escapeQuote(nsCString& aString);
   inline uint32_t netdResponseType(uint32_t code);
   inline bool isBroadcastMessage(uint32_t code);
   inline bool isError(uint32_t code);
   inline bool isComplete(uint32_t code);
   inline bool isProceeding(uint32_t code);
   void Shutdown();
+  static void runNextQueuedCommandChain();
+  static void finalizeSuccess(CommandChain* aChain,
+                              mozilla::dom::NetworkResultOptions& aResult);
+
+  template<size_t N>
+  static void runChain(const NetworkParams& aParams,
+                       const CommandFunc (&aCmds)[N],
+                       ErrorCallback aError);
+
   /**
    * Callback function to send netd result to main thread.
    */
   MessageCallback mMessageCallback;
 
   /*
    * Utility class to access libnetutils.
    */