StatechartManager.cpp
Go to the documentation of this file.
1/*
2* This file is part of ArmarX.
3*
4* Copyright (C) 2011-2016, High Performance Humanoid Technologies (H2T), Karlsruhe Institute of Technology (KIT), all rights reserved.
5*
6* ArmarX is free software; you can redistribute it and/or modify
7* it under the terms of the GNU General Public License version 2 as
8* published by the Free Software Foundation.
9*
10* ArmarX is distributed in the hope that it will be useful, but
11* WITHOUT ANY WARRANTY; without even the implied warranty of
12* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13* GNU General Public License for more details.
14*
15* You should have received a copy of the GNU General Public License
16* along with this program. If not, see <http://www.gnu.org/licenses/>.
17*
18* @package ArmarX::Core::Statechart
19* @author Mirko Waechter ( mirko.waechter at kit dot edu)
20* @date 2012
21* @copyright http://www.gnu.org/licenses/gpl-2.0.txt
22* GNU General Public License
23*/
24
25#include "StatechartManager.h"
26
28
29#include "State.h"
30#include "StateController.h"
31
32using namespace armarx;
33
35 managerState(eConstructed),
36 // runningTaskMutex(10000, "runningTaskMutex")
37 managerStateMutex(10000, "managerStateMutex")
38{
39 setTag("StatechartManager");
40}
41
46
47bool
49 StringVariantContainerBaseMap startParameters)
50{
51 if (isRunning())
52 {
53 return false;
54 }
55
56 toplevelState = newToplevelState;
57 this->startParameters = startParameters;
58 return true;
59}
60
63{
64 return toplevelState;
65}
66
67void
68StatechartManager::start(bool enterToplevelState)
69{
70 ARMARX_DEBUG << "starting StatechartManager";
71 HiddenTimedMutex::ScopedLock lock(managerStateMutex);
72 // HiddenTimedMutex::scoped_lock lock(runningTaskMutex);
73
74
75 if (!runningTask && managerState != eShutDown)
76 {
77 if (toplevelState)
78 {
79 ARMARX_DEBUG << "starting StatechartManagerTask";
80
81 runningTask = new RunningTask<StatechartManager>(
82 this, &StatechartManager::processEvents, "StatechartManager");
83 runningTask->start();
84 managerState = eRunning;
85 lock.unlock();
86
87 if (enterToplevelState)
88 {
89 toplevelState->enter(startParameters);
90 }
91
92 // toplevelState = NULL;
93 }
94 else
95 {
96 throw LocalException("No toplevel state was set in StatechartManager!");
97 }
98 }
99}
100
101void
103{
104 if (isShutdown())
105 {
106 return;
107 }
108
109 {
110 // HiddenTimedMutex::scoped_lock lock(runningTaskMutex);
111 HiddenTimedMutex::ScopedLock lock2(managerStateMutex);
112 managerState = eShutDown;
113 }
114
115 // ARMARX_INFO << "RefCount: " << toplevelState->IceUtil::Shared::__getRef();
116 if (toplevelState)
117 {
118 toplevelState->disableRunFunction();
119 }
120
121 toplevelState = nullptr; // delete so that there are not ring pointers
122
123
124 // first issue stop, then wake up, then wait
125 {
126 std::unique_lock lock(eventQueueMutex); // necessary?
127
128 if (runningTask)
129 {
130 runningTask->stop(false);
131 }
132
133 idleCondition.notify_one();
134 }
135
136 if (runningTask)
137 {
138 runningTask->waitForFinished();
139 }
140
141
142 ARMARX_VERBOSE << "StatechartManager is shutdown!";
143}
144
145bool
147{
148 HiddenTimedMutex::ScopedLock lock(managerStateMutex);
149
150 if (managerState == eRunning)
151 {
152 return true;
153 }
154
155 return false;
156}
157
158bool
160{
161 HiddenTimedMutex::ScopedLock lock(managerStateMutex);
162
163 if (managerState == eShutDown)
164 {
165 return true;
166 }
167
168 return false;
169}
170
173{
174 HiddenTimedMutex::ScopedLock lock(managerStateMutex);
175 return managerState;
176}
177
178void
180{
181 idleCondition.notify_all();
182}
183
184bool
185StatechartManager::addEvent(const EventPtr& newEvent, const StateControllerPtr& receivingState)
186{
187 // HiddenTimedMutex::scoped_lock lock2(runningTaskMutex);
188 {
189 HiddenTimedMutex::ScopedLock lock2(managerStateMutex);
190
191 if (!runningTask || !runningTask->isRunning())
192 {
193 return false;
194 }
195
196 if (!newEvent || !receivingState)
197 {
198 return false;
199 }
200 }
201 EventProcessingData data;
202 data.event = newEvent;
203 data.receivingState = receivingState;
204 /* if(!checkEvent(data))
205 {
206 ARMARX_INFO << "event skipped: " << newEvent->eventName;
207 // return true;
208 }*/
209
210 std::unique_lock lock(eventQueueMutex);
211 eventQueue.push_back(data);
212 // ARMARX_INFO << "New event: " << newEvent->eventName << " for " << receivingState->getStateName();
213 idleCondition.notify_one();
214 return true;
215}
216
217void
219{
220
221 while (!runningTask->isStopped())
222 {
223 EventProcessingData nextEvent;
224 {
225 // just retrieve the event and release the lock
226 std::unique_lock lock(eventQueueMutex);
227
228 if (eventQueue.size() > 0)
229 {
230 nextEvent = eventQueue.front();
231 eventQueue.pop_front();
232 }
233 }
234
235 try
236 {
237 if (nextEvent.receivingState)
238 {
240 {
241 TimeUtil::WaitForNextTick(); // delay transition if time is not running
242 }
243 nextEvent.receivingState->__processEvent(nextEvent.event);
244 }
245 }
246 catch (...)
247 {
249 }
250
251 std::unique_lock lock(eventQueueMutex); // lock so that no events can be added
252
253 // between size checking and going to sleep AND that shutdown cannot be issued after isStopped() was checked
254 if (runningTask->isStopped())
255 {
256 break;
257 }
258
259 while (eventQueue.size() == 0 && !runningTask->isStopped())
260 {
261 // wait in idle mode until new events are available
262 // ARMARX_VERBOSE << "Waiting...";
263 idleCondition.wait(lock);
264 }
265 }
266}
267
268bool
269StatechartManager::checkEvent(const StatechartManager::EventProcessingData& eventData) const
270{
271 std::unique_lock lock(eventQueueMutex);
272 std::list<EventProcessingData>::const_iterator it = eventQueue.begin();
273
274 for (; it != eventQueue.end(); it++)
275 {
276 if (eventData.receivingState == it->receivingState)
277 {
278 return false;
279 }
280 }
281
282 return true;
283}
void setTag(const LogTag &tag)
Definition Logging.cpp:54
void wakeUp()
wakeUp signals the event processing thread to wake up and check for new events or shutdown conditions
void start(bool enterToplevelState=true)
bool setToplevelState(const armarx::StatePtr &newToplevelState, StringVariantContainerBaseMap startParameters=StringVariantContainerBaseMap())
setToplevelState sets the toplevel state of this manager.
bool addEvent(const EventPtr &newEvent, const StateControllerPtr &receivingState)
StatechartManagerState getManagerState() const
static void WaitForNextTick()
block until the next tick of the timeserver.
Definition TimeUtil.cpp:112
static bool HasTimeServer()
check if we have been initialized with a Timeserver
Definition TimeUtil.cpp:124
#define ARMARX_DEBUG
The logging level for output that is only interesting while debugging.
Definition Logging.h:184
#define ARMARX_VERBOSE
The logging level for verbose information.
Definition Logging.h:187
boost::unique_lock< HiddenTimedMutex > ScopedLock
This file offers overloads of toIce() and fromIce() functions for STL container types.
void handleExceptions()
IceInternal::Handle< State > StatePtr
Definition State.h:44
IceInternal::Handle< Event > EventPtr
Typedef of EventPtr as IceInternal::Handle<Event> for convenience.
Definition Event.h:40
IceInternal::Handle< StateController > StateControllerPtr