Add async apply logic at action
authorDonghoon Kwak <dh0128.kwak@samsung.com>
Fri, 15 Nov 2019 06:00:15 +0000 (15:00 +0900)
committerYoungjae Shin <yj99.shin@samsung.com>
Wed, 18 Mar 2020 08:53:50 +0000 (17:53 +0900)
17 files changed:
example/mode/tizen_applyNormalAsync1_mode.xml [new file with mode: 0644]
example/mode/tizen_applyNormalSync1_mode.xml [new file with mode: 0644]
example/mode/tizen_applyOneshotAsync1_mode.xml [new file with mode: 0644]
example/mode/tizen_applyOneshotSync1_mode.xml [new file with mode: 0644]
example/rule/tizen_ex_rule.xml
packaging/modes.spec
plugin/TestPlugin.cpp
schema/tizen_mode.xsd
supervisor/Action.cpp
supervisor/Action.h
supervisor/CMakeLists.txt
supervisor/Mode.h
supervisor/ModeXMLParser.cpp
supervisor/ModesXMLTag.cpp
supervisor/ModesXMLTag.h
supervisor/TAction.h
unittest/modes_mode_test.c

diff --git a/example/mode/tizen_applyNormalAsync1_mode.xml b/example/mode/tizen_applyNormalAsync1_mode.xml
new file mode 100644 (file)
index 0000000..669b73b
--- /dev/null
@@ -0,0 +1,10 @@
+<?xml version="1.0" encoding="utf-8"?>
+<tizenModes xmlns="http://www.tizen.org" version="6.0">
+  <mode name="applyNormalAsync1" type="normal" >
+    <action ID="test_001" rule="test.sleep" type="async" >5</action>
+    <action ID="test_002" rule="test.sleep" type="async" >5</action>
+    <action ID="test_003" rule="test.sleepErrorReturn" type="async" >5</action>
+    <action ID="test_004" rule="test.sleep" type="async" >5</action>
+    <action ID="test_005" rule="test.sleep" type="async" >5</action>
+  </mode>
+</tizenModes>
diff --git a/example/mode/tizen_applyNormalSync1_mode.xml b/example/mode/tizen_applyNormalSync1_mode.xml
new file mode 100644 (file)
index 0000000..2fbf7fe
--- /dev/null
@@ -0,0 +1,10 @@
+<?xml version="1.0" encoding="utf-8"?>
+<tizenModes xmlns="http://www.tizen.org" version="6.0">
+  <mode name="applyNormalSync1" type="normal">
+    <action ID="test_001" rule="test.sleep" >5</action>
+    <action ID="test_002" rule="test.sleep" >5</action>
+    <action ID="test_003" rule="test.sleepErrorReturn" >5</action>
+    <action ID="test_004" rule="test.sleep" type="sync" >5</action>
+    <action ID="test_005" rule="test.sleep" type="sync" >5</action>
+  </mode>
+</tizenModes>
diff --git a/example/mode/tizen_applyOneshotAsync1_mode.xml b/example/mode/tizen_applyOneshotAsync1_mode.xml
new file mode 100644 (file)
index 0000000..747104f
--- /dev/null
@@ -0,0 +1,10 @@
+<?xml version="1.0" encoding="utf-8"?>
+<tizenModes xmlns="http://www.tizen.org" version="6.0">
+  <mode name="applyOneshotAsync1" type="oneshot" >
+    <action ID="test_001" rule="test.sleep" type="async" >5</action>
+    <action ID="test_002" rule="test.sleep" type="async" >5</action>
+    <action ID="test_003" rule="test.sleepErrorReturn" type="async" >5</action>
+    <action ID="test_004" rule="test.sleep" type="async" >5</action>
+    <action ID="test_005" rule="test.sleep" type="async" >5</action>
+  </mode>
+</tizenModes>
diff --git a/example/mode/tizen_applyOneshotSync1_mode.xml b/example/mode/tizen_applyOneshotSync1_mode.xml
new file mode 100644 (file)
index 0000000..41e902d
--- /dev/null
@@ -0,0 +1,10 @@
+<?xml version="1.0" encoding="utf-8"?>
+<tizenModes xmlns="http://www.tizen.org" version="6.0">
+  <mode name="applyOneshotSync1" type="oneshot">
+    <action ID="test_001" rule="test.sleep" >5</action>
+    <action ID="test_002" rule="test.sleep" type="sync" >5</action>
+    <action ID="test_003" rule="test.sleepErrorReturn" >5</action>
+    <action ID="test_004" rule="test.sleep" >5</action>
+    <action ID="test_005" rule="test.sleep" type="sync" >5</action>
+  </mode>
+</tizenModes>
index c99b94021b8f16649f995d3c6f36ed04bbfe149c..9f69422acbf5d21ee9f227c6d60ef224a4e0a2ac 100644 (file)
       <desc>It prints boolean value</desc>
       <domain>System</domain>
     </rule>
+    <rule name="test.sleep" type="int" since="6.0" plugin="test">
+      <desc>Sleep</desc>
+      <domain>System</domain>
+    </rule>
+    <rule name="test.sleepErrorReturn" type="int" since="6.0" plugin="test">
+      <desc>Sleep and return valuse is error</desc>
+      <domain>System</domain>
+    </rule>
   </actionRule>
 </tizenModes>
index 469ffe22f9cef054babf1bc36853cab5fbccfc6a..7652f894b42161dca9fff130131d0218533e9ec9 100644 (file)
@@ -100,6 +100,7 @@ install -d -m 755 %{buildroot}%{modes_data_dir}/rule
 install -d -m 755 %{buildroot}%{modes_data_dir}/custom-mode
 install -d -m 755 %{buildroot}%{modes_info_dir}/undo-info
 install -m 0644 example/mode/*ex*_mode.xml %{buildroot}%{modes_data_dir}/mode/
+install -m 0644 example/mode/*apply*_mode.xml %{buildroot}%{modes_data_dir}/mode/
 install -m 0644 example/rule/*ex*_rule.xml %{buildroot}%{modes_data_dir}/rule/
 install -m 0644 example/mode/*conflict*_mode.xml %{buildroot}%{modes_test_dir}/
 install -m 0644 example/mode/*invalid*_mode.xml %{buildroot}%{modes_test_dir}/
index 9abb10130041011c0825bdbcd8f03b81b397726d..b6d1fa4c6c4d5eb8aeecdb1ae04d26a14e8e5637 100644 (file)
@@ -13,6 +13,8 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
+#include <thread>
+#include <chrono>
 #include "modes_errors.h"
 #include "Plugin.h"
 #include "PluginAction.h"
@@ -71,6 +73,17 @@ int TestPlugin::set(const std::string &key, int val, PluginAction **piAction)
                TestPluginAction *testAction = new TestPluginAction();
                *piAction = testAction;
        }
+
+       if (key.compare("sleep") == 0) {
+               DBG("Sleep %d seconds", val);
+               std::this_thread::sleep_for(std::chrono::seconds(val));
+               DBG("TestPlugin::set int ( %s, %d ) Wakeup", key.c_str(), val);
+       } else if (key.compare("sleepErrorReturn") == 0) {
+               DBG("Sleep %d seconds", val);
+               std::this_thread::sleep_for(std::chrono::seconds(val));
+               DBG("TestPlugin::set int ( %s, %d ) Wakeup", key.c_str(), val);
+               return MODES_ERROR_SYSTEM;
+       }
        return MODES_ERROR_NONE;
 }
 
index 2482af8d1f390e0d392e9db2a7f495e520a926cf..1762ee7edff204c3d493a2ee0057e385cc6671dd 100644 (file)
         <xs:attribute name="priority" type="xs:byte" use="optional" />
         <xs:attribute name="before" type="xs:string" use="optional" />
         <xs:attribute name="after" type="xs:string" use="optional" />
+        <xs:attribute name="type" use="optional">
+          <xs:simpleType>
+            <xs:restriction base="xs:string">
+              <xs:enumeration value="sync"/>
+              <xs:enumeration value="async"/>
+            </xs:restriction>
+          </xs:simpleType>
+        </xs:attribute>
       </xs:extension>
     </xs:simpleContent>
   </xs:complexType>
index fbfaa7c713434f79a6a89d96609e2361ec745b96..2aa3dc8c469dec4fac8e9769aa1f57f275e56941 100644 (file)
 MODES_NAMESPACE_USE;
 
 Action::Action()
-       :isChanged(false), plugin(nullptr), piAction(nullptr), stopOnErr(false), restriction(REQ_NONE)
+       : isChanged(false), plugin(nullptr), piAction(nullptr), stopOnErr(false), type(SYNC), restriction(REQ_NONE)
+
 {
 }
 
 Action::Action(const std::string &name)
-       :ruleName(name), isChanged(false), plugin(nullptr), piAction(nullptr), stopOnErr(false), restriction(REQ_NONE)
+       : ruleName(name), isChanged(false), plugin(nullptr), piAction(nullptr), stopOnErr(false), type(SYNC), restriction(REQ_NONE)
 {
 }
 
@@ -76,6 +77,16 @@ bool Action::getStopOnErr()
        return stopOnErr;
 }
 
+void Action::setType(ActionType val)
+{
+       type = val;
+}
+
+Action::ActionType Action::getType()
+{
+       return type;
+}
+
 Action::ActionRestrict Action::getRestrict()
 {
        return restriction;
index 15cb0905f0ca74ddcf8586e5f705c8456723cbbf..ffda280f6c7735e8e8db372fa85d45396af7dcde 100644 (file)
@@ -27,7 +27,12 @@ public:
        typedef enum {
                REQ_NONE,
                REQ_LOCK
-       }ActionRestrict;
+       } ActionRestrict;
+
+       typedef enum {
+               SYNC,
+               ASYNC
+       } ActionType;
 
        Action();
        Action(const std::string &ruleName);
@@ -42,6 +47,8 @@ public:
        ActionRestrict getRestrict();
        void setStopOnErr(bool val);
        bool getStopOnErr();
+       void setType(ActionType val);
+       ActionType getType();
        void setPlugin(Plugin *pi);
        virtual int setValue(const std::string &val) = 0;
        virtual std::string getStringOfValue() = 0;
@@ -59,6 +66,7 @@ protected:
 private:
        std::string id;
        bool stopOnErr;
+       ActionType type;
        ActionRestrict restriction;
 };
 
index 0935bf49a59bf549bf51ca6f82b1c82e2519aa4f..3afd7fbc419ec3795c84531c384ec5378adef208 100644 (file)
@@ -21,7 +21,7 @@ ADD_DEFINITIONS("-DMDS_SUPERVISOR")
 
 ADD_EXECUTABLE(${DAEMON} ${DAEMON_SRCS})
 ADD_DEPENDENCIES(${DAEMON} GENERATED_DBUS_CODE)
-TARGET_LINK_LIBRARIES(${DAEMON} ${daemon_pkgs_LIBRARIES} dl)
+TARGET_LINK_LIBRARIES(${DAEMON} ${daemon_pkgs_LIBRARIES} dl pthread )
 
 CONFIGURE_FILE(${DBUS_INTERFACE}.service.in ${DBUS_INTERFACE}.service @ONLY)
 CONFIGURE_FILE(${DBUS_INTERFACE}.conf.in ${DBUS_INTERFACE}.conf @ONLY)
index 909f941cafe8ca3cc47851c0ab2a9f8bd2032fd7..2f3fc515f83ed5fa4fa5477cd02659deb88e72d9 100644 (file)
@@ -29,7 +29,7 @@ public:
                MODE_NORMAL,
                MODE_ONESHOT,
                MODE_EXCLUSIVE
-       }ModeType;
+       } ModeType;
 
        Mode();
        ~Mode();
index 9ad693e168626ee839936aae076b76b85d118b26..3eb7ffc5ea176dc770975832d8cac9599daf74d0 100644 (file)
@@ -129,6 +129,13 @@ void ModeXMLParser::parseActionAttr(xmlNodePtr node, Action *action)
        else
                action->setStopOnErr(false);
        xmlFree(stopOnErrProp);
+
+       char *actionTypeProp = (char*)xmlGetProp(node, ModesXMLTag::TYPE);
+       if (actionTypeProp && MDS_EQUAL == strcmp(actionTypeProp, "async"))
+               action->setType(Action::ActionType::ASYNC);
+       else
+               action->setType(Action::ActionType::SYNC);
+       xmlFree(actionTypeProp);
 }
 
 void ModeXMLParser::parseAction(xmlNodePtr node)
index e1a25f18f3d8285216c756b535695d1a3aecaffd..20968003cec3efb5294313b7791c906758e93c00 100644 (file)
@@ -26,10 +26,10 @@ const xmlChar* const ModesXMLTag::XMLNS = (xmlChar*)"xmlns";
 const xmlChar* const ModesXMLTag::XMLNS_STR = (xmlChar*)"http://www.tizen.org";
 const xmlChar* const ModesXMLTag::VERSION = (xmlChar*)"version";
 const xmlChar* const ModesXMLTag::CUR_VERSION = (xmlChar*)"6.0";
+const xmlChar* const ModesXMLTag::TYPE = (xmlChar*)"type";
 //Mode
 const xmlChar* const ModesXMLTag::MODE = (xmlChar*)"mode";
 const xmlChar* const ModesXMLTag::NAME = (xmlChar*)"name";
-const xmlChar* const ModesXMLTag::TYPE = (xmlChar*)"type";
 //Action
 const xmlChar* const ModesXMLTag::ACTION = (xmlChar*)"action";
 const xmlChar* const ModesXMLTag::UNDO = (xmlChar*)"undo";
index d880faa38884942f3b0d478a2682972cf3572e68..27bb7079501ee75c5dafb014b768d592fd65e559 100644 (file)
@@ -21,7 +21,7 @@
 MODES_NAMESPACE_BEGIN
 
 struct ModesXMLTag {
-//common
+       //common
        static const xmlChar* const XML_VERSION;
        static const xmlChar* const XML_ENCODING;
        static const xmlChar* const TIZENMODES;
@@ -29,11 +29,11 @@ struct ModesXMLTag {
        static const xmlChar* const XMLNS_STR;
        static const xmlChar* const VERSION;
        static const xmlChar* const CUR_VERSION;
-//Mode
+       static const xmlChar* const TYPE;
+       //Mode
        static const xmlChar* const MODE;
        static const xmlChar* const NAME;
-       static const xmlChar* const TYPE;
-//Action
+       //Action
        static const xmlChar* const ACTION;
        static const xmlChar* const UNDO;
        static const xmlChar* const RULE;
@@ -41,7 +41,7 @@ struct ModesXMLTag {
        static const xmlChar* const RESTICT;
        static const char* const RESTICT_LOCK;
        static const xmlChar* const ID;
-//UndoInfo
+       //UndoInfo
        static const xmlChar* const UNDO_INFO;
        static const xmlChar* const INFO;
 };
index 1287d7dcaf36f1666446d052125b22d4a67cb235..030474b9fc0056f03e845349a3472a31cc65a4f3 100644 (file)
@@ -18,6 +18,7 @@
 #include <map>
 #include <string>
 #include <sstream>
+#include <thread>
 #include "mdss.h"
 #include "Action.h"
 #include "ValueChecker.h"
@@ -28,7 +29,7 @@ template <typename T>
 class TAction : public Action {
 public:
        TAction(const std::string &name)
-               :Action(name)
+               : Action(name)
        {
        }
 
@@ -100,36 +101,12 @@ public:
 
        int apply() override
        {
-               RETVM_IF(NULL == plugin, MODES_ERROR_NO_DATA, "Action(%s) : No plugin", ruleName.c_str());
-
-               int pos = ruleName.find_first_of(".");
-               PluginAction *tmpAction = nullptr;
-               int ret = plugin->set(ruleName.substr(pos + 1), value, &tmpAction);
-               if (MODES_ERROR_NONE != ret) {
-                       ERR("plugin(%s) set() Fail(%d)", plugin->getName().c_str(), ret);
-                       return ret;
-               }
-               if (tmpAction)
-                       tmpAction->setChangedCallback(valueChangedCallback, this);
-
-               piAction = tmpAction;
-               return MODES_ERROR_NONE;
+               return applyImpl(false, getType() == Action::ActionType::ASYNC);
        }
 
        int applyOneShot() override
        {
-               RETVM_IF(NULL == plugin, MODES_ERROR_NO_DATA, "Action(%s) : No plugin", ruleName.c_str());
-
-               int pos = ruleName.find_first_of(".");
-               PluginAction *tmpAction = nullptr;
-               int ret = plugin->set(ruleName.substr(pos + 1), value, &tmpAction);
-               if (MODES_ERROR_NONE != ret) {
-                       ERR("plugin(%s) set() Fail(%d)", plugin->getName().c_str(), ret);
-                       return ret;
-               }
-
-               piAction = tmpAction;
-               return MODES_ERROR_NONE;
+               return applyImpl(true, getType() == Action::ActionType::ASYNC);
        }
 
        void undo() override
@@ -150,20 +127,61 @@ public:
 private:
        struct CaseIndependentLess {
                struct Compare {
-                       bool operator() (const unsigned char &c1, const unsigned char &c2) const
+                       bool operator()(const unsigned char &c1, const unsigned char &c2) const
                        {
                                return tolower(c1) < tolower(c2);
                        }
                };
-               bool operator() (const std::string &s1, const std::string &s2) const
+               bool operator()(const std::string &s1, const std::string &s2) const
                {
                        return std::lexicographical_compare(s1.begin(), s1.end(),
-                                       s2.begin(), s2.end(), Compare());
+                                                           s2.begin(), s2.end(), Compare());
                }
        };
 
+       int applyImpl(bool isOneShot, bool asyncFlag)
+       {
+               RETVM_IF(NULL == plugin, MODES_ERROR_NO_DATA, "Action(%s) : No plugin", ruleName.c_str());
+
+               int pos = ruleName.find_first_of(".");
+               if (asyncFlag) {
+                       std::thread th1([](TAction * action, Plugin * plugin, std::string key, T value, bool isOneShot) {
+                               PluginAction *tmpAction = nullptr;
+                               int ret = plugin->set(key, value, &tmpAction);
+                               if (MODES_ERROR_NONE != ret) {
+                                       ERR("plugin(%s) set() Fail(%d)", plugin->getName().c_str(), ret);
+                                       return;
+                               }
+
+                               // mode class and action class are destroyed at applyOneShot.
+                               // so need to skip register callback function.
+                               if (!isOneShot) {
+                                       if (tmpAction != nullptr)
+                                               tmpAction->setChangedCallback(action->valueChangedCallback, action);
+
+                                       action->piAction = tmpAction;
+                               }
+                               return;
+                       }, this, plugin, ruleName.substr(pos + 1), value, isOneShot);
+                       th1.detach();
+               } else {
+                       PluginAction *tmpAction = nullptr;
+
+                       int ret = plugin->set(ruleName.substr(pos + 1), value, &tmpAction);
+                       if (MODES_ERROR_NONE != ret) {
+                               ERR("plugin(%s) set() Fail(%d)", plugin->getName().c_str(), ret);
+                               return ret;
+                       }
+
+                       if (!isOneShot && tmpAction != nullptr)
+                               tmpAction->setChangedCallback(valueChangedCallback, this);
+
+                       piAction = tmpAction;
+               }
+               return MODES_ERROR_NONE;
+       }
+
        std::map<std::string, T, CaseIndependentLess> valueAliases;
        T value{};
 };
-
 MODES_NAMESPACE_END
index 5c24119f3e4203102eec4406a048fe6d1fe5296e..4468f2fe97bff05f5df294eecb0e24ef28510c65 100644 (file)
@@ -61,9 +61,9 @@ int main(int argc, char **argv)
 
        _modes_loop = g_main_loop_new(NULL, FALSE);
        if (0 == strcasecmp(argv[1], "apply")) {
-               g_idle_add(apply_idler, argv[1]);
+               g_idle_add(apply_idler, argv[2]);
        } else if (0 == strcasecmp(argv[1], "undo")) {
-               g_idle_add(undo_idler, argv[1]);
+               g_idle_add(undo_idler, argv[2]);
        } else {
                PRINT("Invalid option(%s)", argv[1]);
                print_usage(argv[0]);