/*----------------------------------------------------------------------------*/ | |
/* Copyright (c) FIRST 2008. All Rights Reserved. */ | |
/* Open Source Software - may be modified and shared by FRC teams. The code */ | |
/* must be accompanied by the FIRST BSD license file in $(WIND_BASE)/WPILib. */ | |
/*----------------------------------------------------------------------------*/ | |
#ifndef SYNCHRONIZED_H | |
#define SYNCHRONIZED_H | |
#include <semLib.h> | |
#include "Base.h" | |
#define CRITICAL_REGION(s) { Synchronized _sync(s); | |
#define END_REGION } | |
class Synchronized; | |
/** | |
* Wrap a vxWorks semaphore (SEM_ID) for easier use in C++. For a static | |
* instance, the constructor runs at program load time before main() can spawn | |
* any tasks. Use that to fix race conditions in setup code. | |
* | |
* This uses a semM semaphore which is "reentrant" in the sense that the owning | |
* task can "take" the semaphore more than once. It will need to "give" the | |
* semaphore the same number of times to unlock it. | |
* | |
* This class is safe to use in static variables because it does not depend on | |
* any other C++ static constructors or destructors. | |
*/ | |
class ReentrantSemaphore | |
{ | |
public: | |
explicit ReentrantSemaphore() { | |
m_semaphore = semMCreate(SEM_Q_PRIORITY | SEM_DELETE_SAFE); | |
} | |
~ReentrantSemaphore() { | |
semDelete(m_semaphore); | |
} | |
/** | |
* Lock the semaphore, blocking until it's available. | |
* @return 0 for success, -1 for error. If -1, the error will be in errno. | |
*/ | |
int take() { | |
return semTake(m_semaphore, WAIT_FOREVER); | |
} | |
/** | |
* Unlock the semaphore. | |
* @return 0 for success, -1 for error. If -1, the error will be in errno. | |
*/ | |
int give() { | |
return semGive(m_semaphore); | |
} | |
private: | |
SEM_ID m_semaphore; | |
friend class Synchronized; | |
DISALLOW_COPY_AND_ASSIGN(ReentrantSemaphore); | |
}; | |
/** | |
* Provide easy support for critical regions. | |
* | |
* A critical region is an area of code that is always executed under mutual exclusion. Only | |
* one task can be executing this code at any time. The idea is that code that manipulates data | |
* that is shared between two or more tasks has to be prevented from executing at the same time | |
* otherwise a race condition is possible when both tasks try to update the data. Typically | |
* semaphores are used to ensure only single task access to the data. | |
* | |
* Synchronized objects are a simple wrapper around semaphores to help ensure | |
* that semaphores are always unlocked (semGive) after locking (semTake). | |
* | |
* You allocate a Synchronized as a local variable, *not* on the heap. That | |
* makes it a "stack object" whose destructor runs automatically when it goes | |
* out of scope. E.g. | |
* | |
* { Synchronized _sync(aReentrantSemaphore); ... critical region ... } | |
*/ | |
class Synchronized | |
{ | |
public: | |
explicit Synchronized(SEM_ID); | |
explicit Synchronized(ReentrantSemaphore&); | |
virtual ~Synchronized(); | |
private: | |
SEM_ID m_semaphore; | |
DISALLOW_COPY_AND_ASSIGN(Synchronized); | |
}; | |
#endif |