blob: 4200cc50f7ef6e902b49687e3099f7b511dba294 [file] [log] [blame]
/*----------------------------------------------------------------------------*/
/* 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