jerrym | f157933 | 2013-02-07 01:56:28 +0000 | [diff] [blame] | 1 | /*----------------------------------------------------------------------------*/
|
| 2 | /* Copyright (c) FIRST 2008. All Rights Reserved. */
|
| 3 | /* Open Source Software - may be modified and shared by FRC teams. The code */
|
| 4 | /* must be accompanied by the FIRST BSD license file in $(WIND_BASE)/WPILib. */
|
| 5 | /*----------------------------------------------------------------------------*/
|
| 6 |
|
| 7 | #ifndef SYNCHRONIZED_H
|
| 8 | #define SYNCHRONIZED_H
|
| 9 |
|
| 10 | #include <semLib.h>
|
| 11 |
|
| 12 | #include "Base.h"
|
| 13 |
|
| 14 | #define CRITICAL_REGION(s) { Synchronized _sync(s);
|
| 15 | #define END_REGION }
|
| 16 |
|
| 17 | class Synchronized;
|
| 18 |
|
| 19 | /**
|
| 20 | * Wrap a vxWorks semaphore (SEM_ID) for easier use in C++. For a static
|
| 21 | * instance, the constructor runs at program load time before main() can spawn
|
| 22 | * any tasks. Use that to fix race conditions in setup code.
|
| 23 | *
|
| 24 | * This uses a semM semaphore which is "reentrant" in the sense that the owning
|
| 25 | * task can "take" the semaphore more than once. It will need to "give" the
|
| 26 | * semaphore the same number of times to unlock it.
|
| 27 | *
|
| 28 | * This class is safe to use in static variables because it does not depend on
|
| 29 | * any other C++ static constructors or destructors.
|
| 30 | */
|
| 31 | class ReentrantSemaphore
|
| 32 | {
|
| 33 | public:
|
| 34 | explicit ReentrantSemaphore() {
|
| 35 | m_semaphore = semMCreate(SEM_Q_PRIORITY | SEM_DELETE_SAFE);
|
| 36 | }
|
| 37 | ~ReentrantSemaphore() {
|
| 38 | semDelete(m_semaphore);
|
| 39 | }
|
| 40 |
|
| 41 | /**
|
| 42 | * Lock the semaphore, blocking until it's available.
|
| 43 | * @return 0 for success, -1 for error. If -1, the error will be in errno.
|
| 44 | */
|
| 45 | int take() {
|
| 46 | return semTake(m_semaphore, WAIT_FOREVER);
|
| 47 | }
|
| 48 |
|
| 49 | /**
|
| 50 | * Unlock the semaphore.
|
| 51 | * @return 0 for success, -1 for error. If -1, the error will be in errno.
|
| 52 | */
|
| 53 | int give() {
|
| 54 | return semGive(m_semaphore);
|
| 55 | }
|
| 56 |
|
| 57 | private:
|
| 58 | SEM_ID m_semaphore;
|
| 59 |
|
| 60 | friend class Synchronized;
|
| 61 | DISALLOW_COPY_AND_ASSIGN(ReentrantSemaphore);
|
| 62 | };
|
| 63 |
|
| 64 | /**
|
| 65 | * Provide easy support for critical regions.
|
| 66 | *
|
| 67 | * A critical region is an area of code that is always executed under mutual exclusion. Only
|
| 68 | * one task can be executing this code at any time. The idea is that code that manipulates data
|
| 69 | * that is shared between two or more tasks has to be prevented from executing at the same time
|
| 70 | * otherwise a race condition is possible when both tasks try to update the data. Typically
|
| 71 | * semaphores are used to ensure only single task access to the data.
|
| 72 | *
|
| 73 | * Synchronized objects are a simple wrapper around semaphores to help ensure
|
| 74 | * that semaphores are always unlocked (semGive) after locking (semTake).
|
| 75 | *
|
| 76 | * You allocate a Synchronized as a local variable, *not* on the heap. That
|
| 77 | * makes it a "stack object" whose destructor runs automatically when it goes
|
| 78 | * out of scope. E.g.
|
| 79 | *
|
| 80 | * { Synchronized _sync(aReentrantSemaphore); ... critical region ... }
|
| 81 | */
|
| 82 | class Synchronized
|
| 83 | {
|
| 84 | public:
|
| 85 | explicit Synchronized(SEM_ID);
|
| 86 | explicit Synchronized(ReentrantSemaphore&);
|
| 87 | virtual ~Synchronized();
|
| 88 | private:
|
| 89 | SEM_ID m_semaphore;
|
| 90 |
|
| 91 | DISALLOW_COPY_AND_ASSIGN(Synchronized);
|
| 92 | };
|
| 93 |
|
| 94 | #endif
|