Fawkes API Fawkes Development Version
syncpoint_manager.cpp
1/***************************************************************************
2 * syncpoint_manager.cpp - Fawkes SyncPointManager
3 *
4 * Created: Thu Jan 09 15:22:19 2014
5 * Copyright 2014-2018 Till Hofmann
6 *
7 ****************************************************************************/
8
9/* This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation; either version 2 of the License, or
12 * (at your option) any later version.
13 *
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU Library General Public License for more details.
18 *
19 * Read the full text in the LICENSE.GPL file in the doc directory.
20 */
21
22#include "syncpoint_call_stats.h"
23
24#include <core/threading/mutex_locker.h>
25#include <syncpoint/exceptions.h>
26#include <syncpoint/syncpoint_manager.h>
27
28#include <string>
29
30namespace fawkes {
31
32/** @class SyncPointManager <syncpoint/syncpoint_manager.h>
33 * This class gives access to SyncPoints. SyncPoints should never be created
34 * directly but always by using this class.
35 *
36 * All threads with the SyncPointManager Aspect share the same SyncPointManager.
37 * SyncPointManager provides basic methods to get and release shared SyncPoints
38 *
39 * @author Till Hofmann
40 * @see SyncPoint
41 */
42
43/** Constructor.
44 * @param logger the logger to use for logging messages
45 */
46SyncPointManager::SyncPointManager(MultiLogger *logger) : mutex_(new Mutex()), logger_(logger)
47{
48}
49
50SyncPointManager::~SyncPointManager()
51{
52 delete mutex_;
53}
54
55/**
56 * Get a SyncPoint. This allows accessing the SyncPoint's wait() and emit() methods.
57 * This function creates a SyncPoint with the given identifier if it does not
58 * exist yet and constructs its predecessor.
59 * @param component The name of the component calling the method
60 * @param identifier The identifier of the requested SyncPoint
61 * @return A RefPtr to a SyncPoint which is shared by all threads with this
62 * SyncPoint.
63 * @throw SyncPointInvalidComponentException thrown if component name is invalid
64 * @throw SyncPointAlreadyOpenedException thrown if SyncPoint is already opened
65 * by the component
66 */
67RefPtr<SyncPoint>
68SyncPointManager::get_syncpoint(const std::string &component, const std::string &identifier)
69{
71 return get_syncpoint_no_lock(component, identifier);
72}
73
74/**
75 * Release a SyncPoint. After releasing the SyncPoint, its wait() and emit()
76 * methods cannot be called anymore by the releasing component.
77 * This also releases the SyncPoint's predecessor if existent.
78 * @param component The releasing component
79 * @param sync_point A RefPtr to the released SyncPoint
80 * @throw SyncPointReleasedDoesNotExistException thrown if the SyncPoint doesn't
81 * exist, i.e. is not in the list of the manager's SyncPoints.
82 * @throw SyncPointReleasedByNonWatcherException The releasing component is not
83 * a watcher of the SyncPoint
84 */
85void
86SyncPointManager::release_syncpoint(const std::string &component, RefPtr<SyncPoint> sync_point)
87{
89 release_syncpoint_no_lock(component, sync_point);
90}
91
92/** @class SyncPointSetLessThan "syncpoint_manager.h"
93 * Compare sets of syncpoints
94 */
95
96/**
97 * LessThan Operator to use for the manager's SyncPoint set
98 * Since we store RefPtrs to SyncPoints we have to override this operator
99 * otherwise, each SyncPoint would be unique
100 * @param sp1 A RefPtr to a SyncPoint
101 * @param sp2 A RefPtr to a SyncPoint
102 * @return true if strcmp returns a value < 0 for the SyncPoints' identifiers
103 */
104bool
106{
107 return **sp1 < **sp2;
108}
109
110/**
111 * Get the current list of all SyncPoints managed by this SyncPointManager
112 * @return a set of SyncPoints
113 */
114std::set<RefPtr<SyncPoint>, SyncPointSetLessThan>
116{
118 return syncpoints_;
119}
120
121/** Find the prefix of the SyncPoint's identifier which is the identifier of
122 * the direct predecessor SyncPoint.
123 * The predecessor of a SyncPoint "/some/path" is "/some"
124 * @param identifier The identifier of the SyncPoint
125 * @return The identifier of the predecessor SyncPoint
126 */
127std::string
128SyncPointManager::find_prefix(const std::string &identifier) const
129{
130 size_t last_pos = identifier.rfind("/");
131 if (last_pos != 0) {
132 return identifier.substr(0, last_pos);
133 } else {
134 return "/";
135 }
136}
137
138RefPtr<SyncPoint>
139SyncPointManager::get_syncpoint_no_lock(const std::string &component, const std::string &identifier)
140{
141 if (component == "") {
142 throw SyncPointInvalidComponentException(component.c_str(), identifier.c_str());
143 }
144 // insert a new SyncPoint if no SyncPoint with the same identifier exists,
145 // otherwise, use that SyncPoint
146 std::pair<std::set<RefPtr<SyncPoint>>::iterator, bool> insert_ret;
147 insert_ret = syncpoints_.insert(RefPtr<SyncPoint>(new SyncPoint(identifier, logger_)));
148 std::set<RefPtr<SyncPoint>>::iterator sp_it = insert_ret.first;
149
150 // add component to the set of watchers
151 (*sp_it)->add_watcher(component);
152
153 if (identifier != "/") {
154 // create prefix SyncPoints.
155 // If this is the root SyncPoint ("/"), there will be no prefix
156 std::string prefix = find_prefix(identifier);
157 RefPtr<SyncPoint> predecessor = get_syncpoint_no_lock(component, prefix);
158 predecessor->successors_.insert(*sp_it);
159 (*sp_it)->predecessor_ = predecessor;
160 }
161
162 return *sp_it;
163}
164
165void
166SyncPointManager::release_syncpoint_no_lock(const std::string &component,
167 RefPtr<SyncPoint> sync_point)
168{
169 std::set<RefPtr<SyncPoint>>::iterator sp_it = syncpoints_.find(sync_point);
170 if (sp_it == syncpoints_.end()) {
171 throw SyncPointReleasedDoesNotExistException(component.c_str(),
172 sync_point->get_identifier().c_str());
173 }
174 if (component_watches_any_successor(sync_point, component)) {
175 // successor is watched, do not release the syncpoint yet
176 return;
177 }
178 (*sp_it)->unwait(component);
179 if (!(*sp_it)->watchers_.erase(component)) {
180 throw SyncPointReleasedByNonWatcherException(component.c_str(),
181 sync_point->get_identifier().c_str());
182 }
183 if ((*sp_it)->is_emitter(component) && !(*sp_it)->is_watcher(component)) {
184 throw SyncPointCannotReleaseEmitter(component.c_str(), (*sp_it)->get_identifier().c_str());
185 }
186
187 if (sync_point->predecessor_) {
188 release_syncpoint_no_lock(component, sync_point->predecessor_);
189 }
190}
191
192bool
193SyncPointManager::component_watches_any_successor(const RefPtr<SyncPoint> syncpoint,
194 const std::string component) const
195{
196 for (std::set<RefPtr<SyncPoint>>::const_iterator it = syncpoint->successors_.begin();
197 it != syncpoint->successors_.end();
198 it++) {
199 if ((*it)->get_watchers().count(component)) {
200 return true;
201 }
202 }
203 return false;
204}
205
206} // namespace fawkes
Log through multiple loggers.
Definition: multi.h:35
Mutex locking helper.
Definition: mutex_locker.h:34
Mutex mutual exclusion lock.
Definition: mutex.h:33
void release_syncpoint(const std::string &component, RefPtr< SyncPoint > syncpoint)
Release a SyncPoint.
std::set< RefPtr< SyncPoint >, SyncPointSetLessThan > get_syncpoints()
Get the current list of all SyncPoints managed by this SyncPointManager.
SyncPointManager(MultiLogger *logger)
Constructor.
Mutex * mutex_
Mutex used for all SyncPointManager calls.
std::set< RefPtr< SyncPoint >, SyncPointSetLessThan > syncpoints_
Set of all existing SyncPoints.
RefPtr< SyncPoint > get_syncpoint(const std::string &component, const std::string &identifier)
Get a SyncPoint.
Compare sets of syncpoints.
Definition: syncpoint.h:44
bool operator()(const RefPtr< SyncPoint > sp1, const RefPtr< SyncPoint > sp2) const
LessThan Operator to use for the manager's SyncPoint set Since we store RefPtrs to SyncPoints we have...
Fawkes library namespace.