1 |
/*************************************************************************** |
/*************************************************************************** |
2 |
* * |
* * |
3 |
* Copyright (C) 2006-2012 Andreas Persson * |
* Copyright (C) 2006-2014 Andreas Persson * |
4 |
* * |
* * |
5 |
* This program is free software; you can redistribute it and/or modify * |
* This program is free software; you can redistribute it and/or modify * |
6 |
* it under the terms of the GNU General Public License as published by * |
* it under the terms of the GNU General Public License as published by * |
123 |
T& GetConfigForUpdate(); |
T& GetConfigForUpdate(); |
124 |
|
|
125 |
/** |
/** |
126 |
|
* Get the data on update side <b>unprotected</b>, that is |
127 |
|
* <b>without</b> locking or any means of synchronizations. |
128 |
|
* |
129 |
|
* Due to its nature this must only be called for read access and |
130 |
|
* you have to make sure by yourself, that the data/member you |
131 |
|
* access is really safe for concurrent read access (i.e. SGI's |
132 |
|
* implementation of std::vector::size() would be safe). |
133 |
|
* |
134 |
|
* Only use this when you are absolutely sure what you are doing! |
135 |
|
*/ |
136 |
|
const T& GetUnsafeUpdateConfig() const { |
137 |
|
return config[updateIndex]; |
138 |
|
} |
139 |
|
|
140 |
|
/** |
141 |
* Atomically switch the newly updated configuration |
* Atomically switch the newly updated configuration |
142 |
* object with the one used by the real time thread, then |
* object with the one used by the real time thread, then |
143 |
* wait for the real time thread to finish working with |
* wait for the real time thread to finish working with |
241 |
* |
* |
242 |
* @return the shared protected data |
* @return the shared protected data |
243 |
*/ |
*/ |
244 |
virtual T& beginSync() = 0; //TODO: or call it lock() instead ? |
virtual void beginSync() = 0; //TODO: or call it lock() instead ? |
245 |
|
|
246 |
|
/** |
247 |
|
* Retrieve reference to critical, shared data. This method shall be |
248 |
|
* called between a beginSync() and endSync() call pair, to be sure |
249 |
|
* that shared data can be accessed safely. |
250 |
|
*/ |
251 |
|
virtual T& syncedData() = 0; |
252 |
|
|
253 |
/** |
/** |
254 |
* Signal that the synchronized code block has been left. Depending |
* Signal that the synchronized code block has been left. Depending |
255 |
* on the actual implementation, this call may block the calling |
* on the actual implementation, this call may block the calling |
273 |
public: |
public: |
274 |
Sync(Synchronizer<T>* syncer) { |
Sync(Synchronizer<T>* syncer) { |
275 |
this->syncer = syncer; |
this->syncer = syncer; |
276 |
this->data = &syncer->beginSync(); |
syncer->beginSync(); |
277 |
} |
} |
278 |
|
|
279 |
virtual ~Sync() { |
virtual ~Sync() { |
280 |
syncer->endSync(); |
syncer->endSync(); |
281 |
} |
} |
282 |
|
|
283 |
Sync& operator =(const Sync& arg) { |
/*Sync& operator =(const Sync& arg) { |
284 |
*this->data = *arg.data; |
*this->data = *arg.data; |
285 |
return *this; |
return *this; |
286 |
} |
}*/ |
287 |
|
|
288 |
Sync& operator =(const T& arg) { |
/*Sync& operator =(const T& arg) { |
289 |
*this->data = arg; |
*this->data = arg; |
290 |
return *this; |
return *this; |
291 |
} |
}*/ |
292 |
|
|
293 |
const T& operator *() const { return *data; } |
const T& operator *() const { return syncer->syncedData(); } |
294 |
T& operator *() { return *data; } |
T& operator *() { return syncer->syncedData(); } |
295 |
|
|
296 |
const T* operator ->() const { return data; } |
const T* operator ->() const { return &syncer->syncedData(); } |
297 |
T* operator ->() { return data; } |
T* operator ->() { return &syncer->syncedData(); } |
298 |
|
|
299 |
private: |
private: |
300 |
Synchronizer<T>* syncer; ///< Points to the object that shall be responsible to protect the shared data. |
Synchronizer<T>* syncer; ///< Points to the object that shall be responsible to protect the shared data. |
|
T* data; ///< Points to the shared data that should be protected. |
|
301 |
}; |
}; |
302 |
|
|
303 |
/** |
/** |
310 |
template<class T> |
template<class T> |
311 |
class BackBuffer : public SynchronizedConfig<T>, public Synchronizer<T> { |
class BackBuffer : public SynchronizedConfig<T>, public Synchronizer<T> { |
312 |
public: |
public: |
313 |
virtual T& beginSync() OVERRIDE { |
virtual void beginSync() OVERRIDE { |
314 |
mutex.Lock(); |
mutex.Lock(); |
315 |
data = &SynchronizedConfig<T>::GetConfigForUpdate(); |
} |
316 |
return *data; |
|
317 |
|
virtual T& syncedData() OVERRIDE { |
318 |
|
return SynchronizedConfig<T>::GetConfigForUpdate(); |
319 |
} |
} |
320 |
|
|
321 |
virtual void endSync() OVERRIDE { |
virtual void endSync() OVERRIDE { |
322 |
const T clone = *data; |
const T clone = SynchronizedConfig<T>::GetConfigForUpdate(); |
323 |
SynchronizedConfig<T>::SwitchConfig() = clone; |
SynchronizedConfig<T>::SwitchConfig() = clone; |
324 |
mutex.Unlock(); |
mutex.Unlock(); |
325 |
} |
} |
326 |
|
|
327 |
|
const T& unsafeData() const { |
328 |
|
return SynchronizedConfig<T>::GetUnsafeUpdateConfig(); |
329 |
|
} |
330 |
|
|
331 |
private: |
private: |
|
T* data; |
|
332 |
Mutex mutex; |
Mutex mutex; |
333 |
}; |
}; |
334 |
|
|
347 |
class FrontBuffer : public SynchronizedConfig<T>::Reader, public Synchronizer<T> { |
class FrontBuffer : public SynchronizedConfig<T>::Reader, public Synchronizer<T> { |
348 |
public: |
public: |
349 |
FrontBuffer(BackBuffer<T>& backBuffer) : SynchronizedConfig<T>::Reader::Reader(&backBuffer) {} |
FrontBuffer(BackBuffer<T>& backBuffer) : SynchronizedConfig<T>::Reader::Reader(&backBuffer) {} |
350 |
virtual T& beginSync() OVERRIDE { return SynchronizedConfig<T>::Reader::Lock(); } |
virtual void beginSync() OVERRIDE { data = &SynchronizedConfig<T>::Reader::Lock(); } |
351 |
|
virtual T& syncedData() OVERRIDE { return *data; } |
352 |
virtual void endSync() OVERRIDE { SynchronizedConfig<T>::Reader::Unlock(); } |
virtual void endSync() OVERRIDE { SynchronizedConfig<T>::Reader::Unlock(); } |
353 |
|
private: |
354 |
|
T* data; |
355 |
}; |
}; |
356 |
|
|
357 |
/** |
/** |
393 |
inline |
inline |
394 |
Sync<T> back() { return Sync<T>(&m_back); } |
Sync<T> back() { return Sync<T>(&m_back); } |
395 |
|
|
396 |
|
/** |
397 |
|
* Get the backbuffer data <b>unprotected</b>, that is <b>without</b> |
398 |
|
* locking or any means of synchronizations. |
399 |
|
* |
400 |
|
* Due to its nature this must only be called for read access and |
401 |
|
* you have to make sure by yourself, that the data/member you |
402 |
|
* access is really safe for concurrent read access (i.e. SGI's |
403 |
|
* implementation of std::vector::size() would be safe). |
404 |
|
* |
405 |
|
* Only use this when you are absolutely sure what you are doing! |
406 |
|
*/ |
407 |
|
const T& unsafeBack() const { return m_back.unsafeData(); } |
408 |
|
|
409 |
private: |
private: |
410 |
BackBuffer<T> m_back; ///< Back buffer (non real-time thread(s) side). |
BackBuffer<T> m_back; ///< Back buffer (non real-time thread(s) side). |
411 |
FrontBuffer<T> m_front; ///< Front buffer (real-time thread side). |
FrontBuffer<T> m_front; ///< Front buffer (real-time thread side). |