--- /dev/null
+<?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>
--- /dev/null
+<?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>
--- /dev/null
+<?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>
--- /dev/null
+<?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>
<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>
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}/
* 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"
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;
}
<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>
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)
{
}
return stopOnErr;
}
+void Action::setType(ActionType val)
+{
+ type = val;
+}
+
+Action::ActionType Action::getType()
+{
+ return type;
+}
+
Action::ActionRestrict Action::getRestrict()
{
return restriction;
typedef enum {
REQ_NONE,
REQ_LOCK
- }ActionRestrict;
+ } ActionRestrict;
+
+ typedef enum {
+ SYNC,
+ ASYNC
+ } ActionType;
Action();
Action(const std::string &ruleName);
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;
private:
std::string id;
bool stopOnErr;
+ ActionType type;
ActionRestrict restriction;
};
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)
MODE_NORMAL,
MODE_ONESHOT,
MODE_EXCLUSIVE
- }ModeType;
+ } ModeType;
Mode();
~Mode();
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)
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";
MODES_NAMESPACE_BEGIN
struct ModesXMLTag {
-//common
+ //common
static const xmlChar* const XML_VERSION;
static const xmlChar* const XML_ENCODING;
static const xmlChar* const TIZENMODES;
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;
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;
};
#include <map>
#include <string>
#include <sstream>
+#include <thread>
#include "mdss.h"
#include "Action.h"
#include "ValueChecker.h"
class TAction : public Action {
public:
TAction(const std::string &name)
- :Action(name)
+ : Action(name)
{
}
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
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
_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]);