2 * Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
8 * http://www.apache.org/licenses/LICENSE-2.0
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
18 * @author Przemyslaw Dobrowolski (p.dobrowolsk@samsung.com)
19 * @author Radoslaw Wicik (r.wicik@samsung.com)
21 * @brief Header file for abstaract task definition
26 #include <dpl/scoped_array.h>
27 #include <dpl/noncopyable.h>
28 #include <dpl/union_cast.h>
29 #include <dpl/semaphore.h>
30 #include <dpl/foreach.h>
31 #include <dpl/mutex.h>
32 #include <dpl/assert.h>
33 #include <dpl/log/log.h>
51 virtual bool NextStep() = 0;
52 virtual bool Abort() = 0;
53 virtual size_t GetStepCount() const = 0;
56 template<typename Impl>
61 typedef void (Impl::*Step)();
64 typedef std::list<Step> StepList;
67 StepList m_abortSteps;
68 typename StepList::iterator m_currentStep;
69 typename StepList::iterator m_nextStep;
76 void AddStep(Step step)
78 Assert(!m_running && "AddStep is not allowed after calling NextStep!");
79 Assert(m_steps.end() == std::find(m_steps.begin(), m_steps.end(), step) && "The same step started twice is not supported");
80 m_steps.push_back(step);
81 m_nextStep = m_steps.begin();
84 void AddAbortStep(Step step)
86 Assert(!m_running && "AddAbortStep is not allowed after calling NextStep!");
87 Assert(m_abortSteps.end() == std::find(m_abortSteps.begin(), m_abortSteps.end(), step) && "The same step started twice is not supported");
88 m_abortSteps.push_front(step);
91 void SwitchToStep(Step step)
93 /// @TODO There can be problem here if user sets the same method two times in task list.
94 typename StepList::iterator i = std::find(m_steps.begin(), m_steps.end(), step);
95 Assert(i != m_steps.end());
100 Step GetCurrentStep() const
102 if(m_currentStep == m_steps.end())
105 return *m_currentStep;
114 Assert(this == m_impl);
115 m_currentStep = m_steps.end();
116 m_nextStep = m_steps.end();
123 Assert(m_nextStep != m_steps.end() && "Step list is empty or all steps done");
127 Step call = *m_nextStep;
130 m_currentStep = m_nextStep;
135 return ++m_nextStep != m_steps.end();
144 if (m_abortSteps.empty())
147 FOREACH (it, m_abortSteps)
148 m_steps.push_back(*it);
150 m_nextStep = m_steps.begin();
152 m_abortSteps.clear();
157 size_t GetStepCount() const
159 return static_cast<size_t>(m_steps.size());
163 template<typename ImplementationType>
168 typedef void (ImplementationType::*Step)();
169 typedef std::list<Step> StepList;
170 typedef std::stack<Step> StepStack;
173 static std::string StepToString(Step step)
175 std::ostringstream pseudoAddressStream;
176 pseudoAddressStream << std::hex << union_cast<size_t>(step);
178 std::string pseudoAddress = pseudoAddressStream.str();
180 std::transform(pseudoAddress.begin(), pseudoAddress.end(),
181 pseudoAddress.begin(), ::toupper);
183 return std::string("0x") + pseudoAddress;
186 struct ConditionalStep
191 StepList unsatisfiedDependencies;
192 StepList satisfiedDependencies;
199 ConditionalStep(Step stepArg,
200 StepList dependenciesArg)
202 unsatisfiedDependencies(dependenciesArg)
207 typedef std::list<ConditionalStep> ConditionalStepList;
210 Semaphore m_activeStepsSemaphore;
211 mutable Mutex m_dependencyListMutex;
213 // Those steps that have their dependency lists satified and are ready
215 // Current step is defined to be the front of satisfied list
216 ConditionalStepList m_satisfiedSteps;
218 // Those steps that are going to be executed but their dependency
219 // lists have not been satified
220 ConditionalStepList m_unsatisfiedSteps;
222 // Those steps that have their dependency lists satified and are currently
224 ConditionalStepList m_executingSteps;
226 // Those steps that have been executed with their dependency lists
228 ConditionalStepList m_historicSteps;
230 ///< Growing list of submitted abort steps
231 StepStack m_abortSteps;
233 // Deriving implementation
234 ImplementationType *m_implementation;
236 // Max parallel steps
237 size_t m_maxParallelCount;
239 ///< Valid in dependency list mutex only
240 void SatisfyDependencies(const ConditionalStep &conditionalStep)
242 LogPedantic("Satisfying steps with dependecy to step: "
243 << StepToString(conditionalStep.step));
245 // Can satisfy conditional steps if and only if there are no more
246 // satisfied, unsatisfied or running same steps
247 // There is at least one historic step - this one
248 if (IsContainingStep(conditionalStep.step, m_unsatisfiedSteps) ||
249 IsContainingStep(conditionalStep.step, m_satisfiedSteps) ||
250 IsContainingStep(conditionalStep.step, m_executingSteps))
252 LogPedantic("Step " << StepToString(conditionalStep.step)
253 << " cannot satify other steps yet");
258 LogPedantic("Step " << StepToString(conditionalStep.step)
259 << " can satify other steps");
262 typename ConditionalStepList::iterator unsatisfiedStepIterator =
263 m_unsatisfiedSteps.begin();;
265 while (unsatisfiedStepIterator != m_unsatisfiedSteps.end())
267 typename StepList::iterator iterator =
269 unsatisfiedStepIterator->unsatisfiedDependencies.begin(),
270 unsatisfiedStepIterator->unsatisfiedDependencies.end(),
271 conditionalStep.step);
273 // Does this conditional step need to be satisfied ?
275 unsatisfiedStepIterator->unsatisfiedDependencies.end())
280 LogPedantic("Satisfying step "
281 << StepToString(unsatisfiedStepIterator->step)
282 << " dependency to step "
283 << StepToString(conditionalStep.step));
285 // Satisfy dependency
286 unsatisfiedStepIterator->unsatisfiedDependencies.erase(
289 unsatisfiedStepIterator->satisfiedDependencies.push_back(
290 conditionalStep.step);
292 // If step is fully satisfied, transfer it to the satisfied
294 if (unsatisfiedStepIterator->unsatisfiedDependencies.empty())
297 << StepToString(unsatisfiedStepIterator->step)
298 << " is fully satisfied");
301 m_satisfiedSteps.push_back(*unsatisfiedStepIterator);
303 unsatisfiedStepIterator =
304 m_unsatisfiedSteps.erase(unsatisfiedStepIterator);
309 // Check next unsatisfied step
310 ++unsatisfiedStepIterator;
314 ///< Valid in dependency list mutex only
315 bool IsContainingStep(Step step, const ConditionalStepList &dependencies) const
317 FOREACH (iterator, dependencies)
318 if (iterator->step == step)
324 ///< Valid in dependency list mutex only
325 bool IsStepDependecyListSatisfied(
326 const StepList &dependencies) const
328 // All dependant step must be historic
329 FOREACH (iterator, dependencies)
330 if (!IsContainingStep(*iterator, m_historicSteps))
333 // Also, none dependant step can exist in
334 // unsatisfied/satisfied/inProgress lists
335 FOREACH (iterator, dependencies)
337 if (IsContainingStep(*iterator, m_unsatisfiedSteps) ||
338 IsContainingStep(*iterator, m_satisfiedSteps) ||
339 IsContainingStep(*iterator, m_executingSteps))
350 // Clear all steps and construct
351 // a single-dependency list of abort steps
352 m_unsatisfiedSteps.clear();
353 m_satisfiedSteps.clear();
354 m_executingSteps.clear();
355 m_historicSteps.clear();
357 if (m_abortSteps.empty())
360 // Register last abort step as satisfied
361 m_satisfiedSteps.push_back(
366 Step lastStep = m_abortSteps.top();
369 // Create abort step list
370 while (!m_abortSteps.empty())
372 // Add next unsatisfied step
373 StepList dependencies;
374 dependencies.push_back(lastStep);
376 m_unsatisfiedSteps.push_back(
381 // Remove top abort step
382 lastStep = m_abortSteps.top();
390 void AddStep(Step step,
391 const StepList &dependencies)
393 Mutex::ScopedLock lock(&m_dependencyListMutex);
395 LogPedantic("Adding step: " << StepToString(step));
397 FOREACH (iterator, dependencies)
398 LogPedantic(" Dependency: " << StepToString(*iterator));
400 // Add step to proper list
401 if (IsStepDependecyListSatisfied(dependencies))
403 m_satisfiedSteps.push_back(ConditionalStep(step, dependencies));
405 LogPedantic("Step " << StepToString(step) << " is satisfied");
409 m_unsatisfiedSteps.push_back(ConditionalStep(step, dependencies));
411 LogPedantic("Step " << StepToString(step) << " is unsatisfied");
414 LogPedantic("Satisfied step count: " << m_satisfiedSteps.size());
415 LogPedantic("Unsatisfied step count: " << m_unsatisfiedSteps.size());
418 void AddAbortStep(Step step)
420 Mutex::ScopedLock lock(&m_dependencyListMutex);
422 m_abortSteps.push_front(step);
424 LogPedantic("Abort step count: " << m_abortSteps.size());
428 MultiTaskDecl(ImplementationType *implementation,
429 size_t maxParallelCount)
430 : m_activeStepsSemaphore(maxParallelCount),
431 m_implementation(implementation),
432 m_maxParallelCount(maxParallelCount)
438 ConditionalStep stepToExecute;
439 typename ConditionalStepList::iterator executingStepIterator;
441 // Take the main semaphore lock
442 Semaphore::ScopedLock semaphoreLock(&m_activeStepsSemaphore);
444 // Take the dependency list lock
446 Mutex::ScopedLock listLock(&m_dependencyListMutex);
448 // Get next step to execute
449 if (m_satisfiedSteps.empty())
451 LogPedantic("No more satisfied steps to execute");
455 // Get next satisfied step to execute
456 stepToExecute = m_satisfiedSteps.front();
457 m_satisfiedSteps.pop_front();
459 // Register it in executing step list
460 m_executingSteps.push_back(stepToExecute);
461 executingStepIterator = --m_executingSteps.end();
463 // Leave the dependency list lock
467 (*m_implementation.*stepToExecute.step)();
471 Mutex::ScopedLock listLock(&m_dependencyListMutex);
473 // Unregister executing step
474 m_executingSteps.erase(executingStepIterator);
477 m_historicSteps.push_back(stepToExecute);
479 // Satisfy dependencies
480 SatisfyDependencies(stepToExecute);
491 // Wait until all active steps are done
492 // This is achieved by taking all semaphore slots
493 ScopedArray<Semaphore::ScopedLock *> semaphoreLocks(
494 new Semaphore::ScopedLock *[m_maxParallelCount]);
496 for (size_t i = 0; i < m_maxParallelCount; ++i)
497 semaphoreLocks[i] = new Semaphore::ScopedLock(
498 &m_activeStepsSemaphore);
503 // Take step lists lock
505 Mutex::ScopedLock mutexLock(&m_dependencyListMutex);
508 result = AbortInternal();
510 // Leave steps list lock
513 // Leave semaphore locks
514 for (size_t i = 0; i < m_maxParallelCount; ++i)
515 delete semaphoreLocks[i];
521 size_t GetStepCount() const
523 // Return sum of sizes of all lists
524 Mutex::ScopedLock lock(&m_dependencyListMutex);
526 return static_cast<size_t>(
527 m_unsatisfiedSteps.size() +
528 m_satisfiedSteps.size() +
529 m_executingSteps.size() +
530 m_historicSteps.size());