#include <ServerUtil.h>
#include <JobAction.h>
+#include "SchedTimer.h"
#include "JobRunner.h"
#include "JobManager.h"
__release();
}
+uid_t JobManager::getUid() const
+{
+ return __uid;
+}
+
bool JobManager::isSupported(JobContext::Type type, const std::string& uri)
{
//TODO: availability check
jobInfo->setId(__generateJobId());
- unsigned int cnt = __addRunner(new JobRunner(owner->getName(), jobInfo));
+ unsigned int cnt = __addRunner(new PeriodicJobRunner(this, owner->getName(), jobInfo));
_D("%u jobs have been registered", cnt);
return jobInfo->getId();
jobInfo->setId(__generateJobId());
- unsigned int cnt = __addRunner(new JobRunner(owner->getName(), jobInfo));
+ unsigned int cnt = __addRunner(new OnDemandJobRunner(this, owner->getName(), jobInfo));
_D("%u jobs have been registered", cnt);
return jobInfo->getId();
JobRunner* runner = __getRunner(owner->getName(), jobId);
IF_FAIL_RETURN_TAG(runner, E_PARAM, _W, "Not found");
- if (runner->isStarted())
- runner->stop();
-
if (runner->isPersistent())
__jobInfoDatabase.remove(jobId);
return E_NONE;
}
+void JobManager::removeRunner(JobRunner* runner)
+{
+ if (runner->isPersistent())
+ __jobInfoDatabase.remove(runner->getJobId());
+
+ __removeRunner(runner);
+}
+
JobInfo* JobManager::getJobInfo(int jobId, IClient* owner)
{
JobRunner* jobRunner = __getRunner(owner->getName(), jobId);
return __jobRunners.size();
}
-bool JobManager::__removeRunner(JobRunner* runner)
+void JobManager::__removeRunner(JobRunner* runner)
{
__jobRunners.remove(runner);
delete runner;
- return true;
}
JobRunner* JobManager::__getRunner(const std::string& ownerId, int jobId)
_I("Restoring %u jobs", storedJobs.size());
+ SchedTimer::pause();
+
for (auto& storedJob : storedJobs) {
const std::string& owner = storedJob.first;
JobInfo* jobInfo = storedJob.second;
maxJobId = MAX(maxJobId, jobInfo->getId());
- JobRunner* runner = new JobRunner(owner, jobInfo);
+ JobRunner* runner = NULL;
+ if (jobInfo->getType() == JobInfo::Type::PERIODIC)
+ runner = new PeriodicJobRunner(this, owner, jobInfo);
+ else
+ runner = new OnDemandJobRunner(this, owner, jobInfo);
+
if (jobInfo->isStarted())
runner->start();
__addRunner(runner);
}
+ SchedTimer::resume();
+
__lastJobId = maxJobId;
}
void JobManager::__release()
{
+ SchedTimer::pause();
+
for (auto& runner : __jobRunners) {
- runner->stop();
delete runner;
}
- __jobRunners.clear();
+ SchedTimer::resume();
}
JobManager(uid_t uid);
~JobManager();
+ uid_t getUid() const;
+
bool isSupported(JobContext::Type type, const std::string& uri);
int addJob(JobInfo* jobInfo, IClient* owner);
int startJob(int jobId, IClient* owner);
int stopJob(int jobId, IClient* owner);
int removeJob(int jobId, IClient* owner);
+ void removeRunner(JobRunner* runner);
JobInfo* getJobInfo(int jobId, IClient* owner);
std::vector<JobInfo*> getAllJobInfo(IClient* owner);
int __generateJobId();
unsigned int __addRunner(JobRunner* runner);
- bool __removeRunner(JobRunner* runner);
+ void __removeRunner(JobRunner* runner);
JobRunner* __getRunner(const std::string& ownerId, int jobId);
std::vector<JobRunner*> __getRunners(const std::string& ownerId);
* limitations under the License.
*/
+#include <stdexcept>
+#include "SchedTimer.h"
+#include "JobManager.h"
+#include "JobState.h"
#include "JobRunner.h"
using namespace ctx;
-JobRunner::JobRunner(const std::string& owner, JobInfo* jobInfo) :
+unsigned int PeriodicJobRunner::__periodicJobRunnerCnt = 0;
+
+JobRunner::JobRunner(JobManager* mgr, const std::string& owner, JobInfo* info) :
+ __jobManager(mgr),
+ __jobInfo(info),
+ __client(NULL),
__owner(owner),
- __jobInfo(jobInfo)
+ __state(NULL)
+{
+}
+
+JobRunner::~JobRunner()
+{
+ delete __state;
+ delete __jobInfo;
+}
+
+uid_t JobRunner::getUid() const
{
+ return __jobManager->getUid();
}
-const std::string& JobRunner::getOwner()
+const std::string& JobRunner::getOwner() const
{
return __owner;
}
-int JobRunner::getJobId()
+int JobRunner::getJobId() const
{
return __jobInfo->getId();
}
-bool JobRunner::isStarted()
+bool JobRunner::isStarted() const
{
return __jobInfo->isStarted();
}
-bool JobRunner::isPersistent()
+bool JobRunner::isPersistent() const
{
return __jobInfo->isPersistent();
}
return __jobInfo;
}
-void JobRunner::start()
+void JobRunner::setState(JobState* state)
+{
+ delete __state;
+ __state = state;
+
+ IF_FAIL_VOID(__state);
+
+ try {
+ if (__state->execute())
+ __state->setClient(__client);
+ } catch (const std::runtime_error& e) {
+ _E("State transtion failed: %s", e.what());
+ _I("Terminating Job-%d of '%s'", getJobId(), getOwner().c_str());
+ terminate();
+ }
+}
+
+void JobRunner::setClient(IClient* client)
+{
+ __client = client;
+
+ if (__state)
+ __state->setClient(client);
+}
+
+void JobRunner::jobFinished()
+{
+ if (__state)
+ __state->jobFinished();
+}
+
+
+PeriodicJobRunner::PeriodicJobRunner(JobManager* mgr, const std::string& owner, JobInfo* info) :
+ JobRunner(mgr, owner, info)
+{
+ ++__periodicJobRunnerCnt;
+}
+
+PeriodicJobRunner::~PeriodicJobRunner()
+{
+ --__periodicJobRunnerCnt;
+}
+
+void PeriodicJobRunner::start()
+{
+ __jobInfo->setStarted(true);
+ setState(new TimerStandbyState(this));
+
+ if (__periodicJobRunnerCnt == TimerStandbyState::getCount())
+ SchedTimer::reset();
+}
+
+void PeriodicJobRunner::stop()
+{
+ __jobInfo->setStarted(false);
+ setState(NULL);
+
+ if (__periodicJobRunnerCnt == TimerStandbyState::getCount())
+ SchedTimer::reset();
+}
+
+void PeriodicJobRunner::restart()
+{
+ setState(new TimerStandbyState(this));
+
+ if (__periodicJobRunnerCnt == TimerStandbyState::getCount())
+ SchedTimer::reset();
+}
+
+void PeriodicJobRunner::terminate()
+{
+ setState(NULL);
+ __jobManager->removeRunner(this);
+
+ if (__periodicJobRunnerCnt == TimerStandbyState::getCount())
+ SchedTimer::reset();
+}
+
+
+OnDemandJobRunner::OnDemandJobRunner(JobManager* mgr, const std::string& owner, JobInfo* info) :
+ JobRunner(mgr, owner, info)
+{
+}
+
+void OnDemandJobRunner::start()
{
__jobInfo->setStarted(true);
+ setState(new TriggerStandbyState(this));
}
-void JobRunner::stop()
+void OnDemandJobRunner::stop()
{
__jobInfo->setStarted(false);
+ setState(NULL);
+}
+
+void OnDemandJobRunner::restart()
+{
+ setState(new TriggerStandbyState(this));
+}
+
+void OnDemandJobRunner::terminate()
+{
+ setState(NULL);
+ __jobManager->removeRunner(this);
}
#ifndef __CONTEXT_JOB_SCHEDULER_JOB_RUNNER_H__
#define __CONTEXT_JOB_SCHEDULER_JOB_RUNNER_H__
+#include <IClient.h>
#include <JobInfo.h>
namespace ctx {
+ class JobManager;
+ class JobState;
+
class JobRunner {
public:
- JobRunner(const std::string& owner, JobInfo* jobInfo);
+ virtual ~JobRunner();
- const std::string& getOwner();
- int getJobId();
- bool isStarted();
- bool isPersistent();
+ uid_t getUid() const;
+ const std::string& getOwner() const;
+ int getJobId() const;
+ bool isStarted() const;
+ bool isPersistent() const;
JobInfo* getJobInfo();
+ void setState(JobState* state);
+ void setClient(IClient* client);
+ void jobFinished();
+
+ virtual void start() = 0;
+ virtual void stop() = 0;
+ virtual void restart() = 0;
+ virtual void terminate() = 0;
+
+ protected:
+ JobRunner(JobManager* mgr, const std::string& owner, JobInfo* info);
+
+ JobManager* __jobManager;
+ JobInfo* __jobInfo;
+ IClient* __client;
+
+ private:
+ std::string __owner;
+ JobState* __state;
+ };
+
+
+ class PeriodicJobRunner : public JobRunner {
+ public:
+ PeriodicJobRunner(JobManager* mgr, const std::string& owner, JobInfo* info);
+ ~PeriodicJobRunner();
+
void start();
void stop();
+ void restart();
+ void terminate();
private:
- std::string __owner;
- JobInfo* __jobInfo;
+ static unsigned int __periodicJobRunnerCnt;
+ };
+
+
+ class OnDemandJobRunner : public JobRunner {
+ public:
+ OnDemandJobRunner(JobManager* mgr, const std::string& owner, JobInfo* info);
+
+ void start();
+ void stop();
+ void restart();
+ void terminate();
};
}
--- /dev/null
+/*
+ * Copyright (c) 2017 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "JobRunner.h"
+#include "JobState.h"
+
+#define ENTER _I("ENTER: Job-%d of '%s'", getJobId(), getOwner().c_str())
+#define EXIT _I("EXIT : Job-%d of '%s'", getJobId(), getOwner().c_str())
+
+using namespace ctx;
+
+unsigned int TimerStandbyState::__timerStandbyStateCnt = 0;
+
+JobState::JobState(JobRunner* runner) :
+ __jobRunner(runner)
+{
+}
+
+JobState::JobState(JobState* prevState) :
+ __jobRunner(prevState->__jobRunner)
+{
+}
+
+JobState::~JobState()
+{
+}
+
+void JobState::setClient(IClient* client)
+{
+}
+
+void JobState::jobFinished()
+{
+}
+
+uid_t JobState::getUid() const
+{
+ return __jobRunner->getUid();
+}
+
+const std::string& JobState::getOwner() const
+{
+ return __jobRunner->getOwner();
+}
+
+int JobState::getJobId() const
+{
+ return __jobRunner->getJobId();
+}
+
+JobInfo* JobState::getJobInfo()
+{
+ return __jobRunner->getJobInfo();
+}
+
+JobRunner* JobState::getJobRunner()
+{
+ return __jobRunner;
+}
+
+void JobState::transit(JobState* nextState)
+{
+ __jobRunner->setState(nextState);
+}
+
+
+TimerStandbyState::TimerStandbyState(JobRunner* runner) :
+ JobState(runner)
+{
+ ENTER;
+ ++__timerStandbyStateCnt;
+}
+
+TimerStandbyState::~TimerStandbyState()
+{
+ EXIT;
+ --__timerStandbyStateCnt;
+}
+
+bool TimerStandbyState::execute()
+{
+ //TODO: Set a timer.
+ return true;
+}
+
+void TimerStandbyState::onSchedTimerExpired()
+{
+ //TODO: Transit to ReqVerificationState.
+}
+
+unsigned int TimerStandbyState::getCount()
+{
+ return __timerStandbyStateCnt;
+}
+
+
+TriggerStandbyState::TriggerStandbyState(JobRunner* runner) :
+ JobState(runner)
+{
+ ENTER;
+}
+
+TriggerStandbyState::~TriggerStandbyState()
+{
+ EXIT;
+}
+
+bool TriggerStandbyState::execute()
+{
+ //TODO: Subscribe the trigger contexts.
+ // If a context expires, verify its attributes, and transit to ReqVerificationState.
+ return true;
+}
+
+
+ReqVerificationState::ReqVerificationState(JobState* prevState) :
+ JobState(prevState)
+{
+ ENTER;
+}
+
+ReqVerificationState::~ReqVerificationState()
+{
+ EXIT;
+}
+
+bool ReqVerificationState::execute()
+{
+ //TODO: Read the requirement contexts.
+ // If all satisfied, goto ActionState.
+ // If the RequirementTimeout == 0, goto restart the machine.
+ // Set the timeout.
+ // If the timeout expires, read the requirements again.
+ // If all mandatory satisfied, goto ActionState, restart otherwise.
+ return true;
+}
+
+
+ActionState::ActionState(JobState* prevState) :
+ JobState(prevState)
+{
+ ENTER;
+ //TODO: Check whether the timeout expired.
+}
+
+ActionState::~ActionState()
+{
+ EXIT;
+}
+
+bool ActionState::execute()
+{
+ //TODO: Set a timeout for waiting the client finishes the job.
+ // If the timeout expires, let the client know that the device is about to suspend.
+ // And goto ClosingState.
+ return true;
+}
+
+void ActionState::setClient(IClient* client)
+{
+ //TODO: Notify the client which job has been expired (once).
+ // Notify the client if the timeout already expired (once).
+}
+
+void ActionState::jobFinished()
+{
+ //TODO: cancel the timeout and goto ClosingState.
+}
+
+
+ClosingState::ClosingState(JobRunner* runner) :
+ JobState(runner)
+{
+ ENTER;
+}
+
+ClosingState::ClosingState(JobState* prevState) :
+ JobState(prevState)
+{
+ ENTER;
+}
+
+ClosingState::~ClosingState()
+{
+ EXIT;
+}
+
+bool ClosingState::execute()
+{
+ //TODO: restart or terminate the job.
+ return false;
+}
--- /dev/null
+/*
+ * Copyright (c) 2017 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __CONTEXT_JOB_SCHEDULER_JOB_STATE_H__
+#define __CONTEXT_JOB_SCHEDULER_JOB_STATE_H__
+
+#include <string>
+#include <IClient.h>
+#include <JobInfo.h>
+#include "SchedTimer.h"
+
+namespace ctx {
+
+ class JobRunner;
+
+
+ class JobState {
+ public:
+ virtual ~JobState();
+
+ virtual bool execute() = 0;
+
+ virtual void setClient(IClient* client);
+ virtual void jobFinished();
+
+ protected:
+ JobState(JobRunner* runner);
+ JobState(JobState* prevState);
+
+ uid_t getUid() const;
+ const std::string& getOwner() const;
+ int getJobId() const;
+ JobInfo* getJobInfo();
+ JobRunner* getJobRunner();
+
+ void transit(JobState* nextState);
+
+ private:
+ JobRunner* __jobRunner;
+ };
+
+
+ class TimerStandbyState : public JobState, public ISchedTimerListener {
+ public:
+ TimerStandbyState(JobRunner* runner);
+ ~TimerStandbyState();
+
+ bool execute();
+
+ void onSchedTimerExpired();
+
+ static unsigned int getCount();
+
+ private:
+ static unsigned int __timerStandbyStateCnt;
+ };
+
+
+ class TriggerStandbyState : public JobState {
+ public:
+ TriggerStandbyState(JobRunner* runner);
+ ~TriggerStandbyState();
+
+ bool execute();
+ };
+
+
+ class ReqVerificationState : public JobState {
+ public:
+ ReqVerificationState(JobState* prevState);
+ ~ReqVerificationState();
+
+ bool execute();
+ };
+
+
+ class ActionState : public JobState {
+ public:
+ ActionState(JobState* prevState);
+ ~ActionState();
+
+ bool execute();
+
+ void setClient(IClient* client);
+ void jobFinished();
+ };
+
+
+ class ClosingState : public JobState {
+ public:
+ ClosingState(JobRunner* runner);
+ ClosingState(JobState* prevState);
+ ~ClosingState();
+
+ bool execute();
+ };
+
+}
+
+#endif /* __CONTEXT_JOB_SCHEDULER_JOB_STATE_H__ */
SchedTimer* SchedTimer::__instance = NULL;
SchedTimer::SchedTimer() :
- __scheduledTime(0)
+ __scheduledTime(0),
+ __paused(false)
{
}
__instance->__reset();
}
+void SchedTimer::pause()
+{
+ IF_FAIL_VOID(__instance);
+ __instance->__pause();
+}
+
+void SchedTimer::resume()
+{
+ IF_FAIL_VOID(__instance);
+ __instance->__resume();
+}
+
bool SchedTimer::onTimerExpired(unsigned int timerId, unsigned int intervalMs, void* userData)
{
time_t limit = time(NULL);
void SchedTimer::__reset()
{
+ IF_FAIL_VOID(!__paused);
+
time_t next = __timeLine.getNextScheduledTime();
IF_FAIL_VOID(DIFF(next, __scheduledTime) >= DIFF_THRESHOLD);
//TODO: g_timeout to catch the device wakeups caused by other reasons.
}
+void SchedTimer::__pause()
+{
+ __scheduledTime = 0;
+ __timer.cancelAll();
+ __paused = true;
+}
+
+void SchedTimer::__resume()
+{
+ __paused = false;
+ __reset();
+}
+
SchedTimer::TimeLineEntry::TimeLineEntry(ISchedTimerListener* l, time_t t, unsigned int m) :
listener(l),
scheduledTime(t),
// Reset the timer when the all periodic jobs enter to the interval waiting state,
// or a job has been removed and all others are in the waiting state.
static void reset();
+ static void pause();
+ static void resume();
bool onTimerExpired(unsigned int timerId, unsigned int intervalMs, void* userData);
bool __set(ISchedTimerListener* listener, time_t scheduledTime, unsigned int margin);
void __remove(ISchedTimerListener* listener);
void __reset();
+ void __pause();
+ void __resume();
struct TimeLineEntry {
ISchedTimerListener* listener;
TimeLine __timeLine;
Timer __timer;
time_t __scheduledTime;
+ bool __paused;
static SchedTimer* __instance;
};