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 
30 namespace 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  */
46 SyncPointManager::SyncPointManager(MultiLogger *logger) : mutex_(new Mutex()), logger_(logger)
47 {
48 }
49 
50 SyncPointManager::~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  */
67 RefPtr<SyncPoint>
68 SyncPointManager::get_syncpoint(const std::string &component, const std::string &identifier)
69 {
70  MutexLocker ml(mutex_);
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  */
85 void
86 SyncPointManager::release_syncpoint(const std::string &component, RefPtr<SyncPoint> sync_point)
87 {
88  MutexLocker ml(mutex_);
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  */
104 bool
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  */
114 std::set<RefPtr<SyncPoint>, SyncPointSetLessThan>
116 {
117  MutexLocker ml(mutex_);
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  */
127 std::string
128 SyncPointManager::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 
138 RefPtr<SyncPoint>
139 SyncPointManager::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 
165 void
166 SyncPointManager::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 
192 bool
193 SyncPointManager::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
fawkes::SyncPointSetLessThan::operator()
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...
Definition: syncpoint_manager.cpp:105
fawkes::SyncPointManager::mutex_
Mutex * mutex_
Mutex used for all SyncPointManager calls.
Definition: syncpoint_manager.h:52
fawkes::Mutex
Mutex mutual exclusion lock.
Definition: mutex.h:33
fawkes::MultiLogger
Log through multiple loggers.
Definition: multi.h:35
fawkes::RefPtr< SyncPoint >
fawkes::MutexLocker
Mutex locking helper.
Definition: mutex_locker.h:34
fawkes::SyncPointManager::syncpoints_
std::set< RefPtr< SyncPoint >, SyncPointSetLessThan > syncpoints_
Set of all existing SyncPoints.
Definition: syncpoint_manager.h:50
fawkes::SyncPointManager::get_syncpoint
RefPtr< SyncPoint > get_syncpoint(const std::string &component, const std::string &identifier)
Get a SyncPoint.
Definition: syncpoint_manager.cpp:68
fawkes
Fawkes library namespace.
fawkes::SyncPointSetLessThan
Compare sets of syncpoints.
Definition: syncpoint.h:44
fawkes::SyncPointManager::SyncPointManager
SyncPointManager(MultiLogger *logger)
Constructor.
Definition: syncpoint_manager.cpp:46
fawkes::SyncPointManager::get_syncpoints
std::set< RefPtr< SyncPoint >, SyncPointSetLessThan > get_syncpoints()
Get the current list of all SyncPoints managed by this SyncPointManager.
Definition: syncpoint_manager.cpp:115
fawkes::SyncPointManager::release_syncpoint
void release_syncpoint(const std::string &component, RefPtr< SyncPoint > syncpoint)
Release a SyncPoint.
Definition: syncpoint_manager.cpp:86