blob: 4200cc50f7ef6e902b49687e3099f7b511dba294 [file] [log] [blame]
jerrymf1579332013-02-07 01:56:28 +00001/*----------------------------------------------------------------------------*/
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
17class 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 */
31class ReentrantSemaphore
32{
33public:
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
57private:
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 */
82class Synchronized
83{
84public:
85 explicit Synchronized(SEM_ID);
86 explicit Synchronized(ReentrantSemaphore&);
87 virtual ~Synchronized();
88private:
89 SEM_ID m_semaphore;
90
91 DISALLOW_COPY_AND_ASSIGN(Synchronized);
92};
93
94#endif