001 /*----------------------------------------------------------------------------*/
002 /* Copyright (c) FIRST 2008-2012. All Rights Reserved. */
003 /* Open Source Software - may be modified and shared by FRC teams. The code */
004 /* must be accompanied by the FIRST BSD license file in the root directory of */
005 /* the project. */
006 /*----------------------------------------------------------------------------*/
007
008 package edu.wpi.first.wpilibj.communication;
009
010 import com.sun.cldc.jna.Function;
011 import com.sun.cldc.jna.NativeLibrary;
012 import com.sun.cldc.jna.Pointer;
013 import com.sun.squawk.platform.posix.LibCUtil;
014
015 /**
016 * Class exposing VxWorks semaphores.
017 * @author dtjones
018 */
019 public class Semaphore {
020 Pointer m_semaphore;
021
022 /** Integer ms value indicating wait forever. */
023 public static final int WAIT_FOREVER = -1;
024
025 static final int SEM_Q_FIFO = 0x00; /* first in first out queue */
026 static final int SEM_Q_PRIORITY = 0x01; /* priority sorted queue */
027 static final int SEM_DELETE_SAFE = 0x04; /* owner delete safe (mutex opt.) */
028 static final int SEM_INVERSION_SAFE = 0x08; /* no priority inversion (mutex opt.) */
029 static final int SEM_EVENTSEND_ERR_NOTIFY = 0x10; /* notify when eventRsrcSend fails */
030 static final int SEM_INTERRUPTIBLE = 0x20; /* interruptible on RTP signal */
031
032 /**
033 * Options to create a semaphore with.
034 */
035 public static class Options {
036 int value = 0;
037 /**
038 * Set true to use a priority sorted queue, false to use first-in first-out
039 * @param priority
040 */
041 public void setPrioritySorted(boolean priority) {
042 if (priority) value |= SEM_Q_PRIORITY;
043 else value &= ~SEM_Q_PRIORITY;
044 }
045 /**
046 * Set whether or not the semaphore is delete safe.
047 * @param delSafe True to make the semaphore delete safe.
048 */
049 public void setDeleteSafe(boolean delSafe) {
050 if (delSafe) value |= SEM_DELETE_SAFE;
051 else value &= ~SEM_DELETE_SAFE;
052 }
053 /**
054 * Set whether the semaphore is inversion safe.
055 * @param invSafe True to set the semaphore to inversion safe.
056 */
057 public void setInversionSafe(boolean invSafe) {
058 if (invSafe) value |= SEM_INVERSION_SAFE;
059 else value &= ~SEM_INVERSION_SAFE;
060 }
061 /**
062 * Set whether the semaphore should notify on an error.
063 * @param errNot True to set error notify.
064 */
065 public void setErrorNotify(boolean errNot) {
066 if (errNot) value |= SEM_EVENTSEND_ERR_NOTIFY;
067 else value &= ~SEM_EVENTSEND_ERR_NOTIFY;
068 }
069 /**
070 * Set whether the semaphore is interruptable.
071 * @param intable True allows this semaphore to be interrupted.
072 */
073 public void setInterruptable(boolean intable) {
074 if (intable) value |= SEM_INTERRUPTIBLE;
075 else value &= ~SEM_INTERRUPTIBLE;
076 }
077 }
078
079 private static Function semMCreateFn = NativeLibrary.getDefaultInstance().getFunction("semMCreate"); //SEM_ID semMCreate (int options);
080 private static Function semBCreateFn = NativeLibrary.getDefaultInstance().getFunction("semBCreate"); //SEM_ID semBCreate (int options, SEM_B_STATE initialState);
081 private static Function semCCreateFn = NativeLibrary.getDefaultInstance().getFunction("semCCreate"); //SEM_ID semCCreate (int options, int initialCount);
082 private static Function semDeleteFn = NativeLibrary.getDefaultInstance().getFunction("semDelete"); //STATUS semDelete (SEM_ID semId);
083 private static Function semFlushFn = NativeLibrary.getDefaultInstance().getFunction("semFlush"); //STATUS semFlush (SEM_ID semId);
084 private static Function semGiveFn = NativeLibrary.getDefaultInstance().getFunction("semGive"); //STATUS semGive (SEM_ID semId);
085 private static Function semTakeFn = NativeLibrary.getDefaultInstance().getFunction("semTake"); //STATUS semTake (SEM_ID semId, int timeout);
086 private static Function semTakeBlockingFn = NativeLibrary.getDefaultInstance().getBlockingFunction("semTake"); //STATUS semTake (SEM_ID semId, int timeout);
087 // private static Function semOpenFn = NativeLibrary.getDefaultInstance().getFunction("semOpen"); //SEM_ID semOpen (const char * name, SEM_TYPE type, int initState, int options, int mode, void * context);
088 // private static Function semInfoGetFn = NativeLibrary.getDefaultInstance().getFunction("semInfoGet"); //STATUS semInfoGet (SEM_ID semId, SEM_INFO *pInfo);
089 private static Function semCloseFn = NativeLibrary.getDefaultInstance().getFunction("semClose"); //STATUS semClose (SEM_ID semId);
090 // private static Function semUnlinkFn = NativeLibrary.getDefaultInstance().getFunction("semUnlink"); //STATUS semUnlink (const char * name);
091
092 private void checkStatus (int status) throws SemaphoreException{
093 if (status != 0) {
094 throw new SemaphoreException(LibCUtil.errno());
095 }
096 }
097
098 /**
099 * Create a new semaphore.
100 * @param options The options to create the semaphore with.
101 */
102 public Semaphore (Options options) {
103 m_semaphore = new Pointer(semMCreateFn.call1(options.value), 0);
104 }
105
106 /**
107 * Create a semaphore with the given initial state.
108 * @param options The options to create the semaphore with.
109 * @param initialState The initial state for the semaphore to have.
110 */
111 public Semaphore (Options options, boolean initialState) {
112 m_semaphore = new Pointer(semBCreateFn.call2(options.value,initialState?1:0), 0);
113 }
114
115 /**
116 * Create a counting semaphore with the given value.
117 * @param options The options to create the semaphore with.
118 * @param count The initial count for the semaphore to hold.
119 */
120 public Semaphore (Options options, int count) {
121 m_semaphore = new Pointer(semCCreateFn.call2(options.value, count), 0);
122 }
123
124 /**
125 * Get the pointer to the native semaphore.
126 * @return Pointer to the native semaphore.
127 */
128 public Pointer getPointer() {
129 return m_semaphore;
130 }
131
132 /**
133 * Unblock every task that is blocked by the semaphore.
134 */
135 public void flush() throws SemaphoreException{
136 checkStatus(semFlushFn.call1(m_semaphore));
137 }
138
139 /**
140 * Release the semaphore.
141 */
142 public void give() throws SemaphoreException{
143 checkStatus(semGiveFn.call1(m_semaphore));
144 }
145
146 /**
147 * Take the semaphore. Block for timeout milliseconds.
148 * @param timeout The maximum time in milliseconds to block for the semaphore.
149 * @throws SemaphoreException if the lock can't be take in timeout seconds, or some other semaphore error condition occurs.
150 */
151 public void takeMillis(int timeout) throws SemaphoreException{
152 checkStatus(semTakeBlockingFn.call2(m_semaphore, timeout));
153 }
154
155 /**
156 * Take the semaphore. Block forever until semaphore is available.
157 * @throws SemaphoreException if some semaphore error condition occurs.
158 */
159 public void takeForever() throws SemaphoreException{
160 takeMillis(WAIT_FOREVER);
161 }
162
163 /*
164 * Non-blocking version of take(). Try to take the Semaphore.
165 *
166 * @return If succeeded return true, otherwise return false.
167 * @throws SemaphoreException if some semaphore error condition occurs.
168 */
169 public boolean tryTake() throws SemaphoreException{
170 int result = semTakeFn.call2(m_semaphore, 0);
171 if (result == 0) {
172 return true;
173 } else {
174 int errno = LibCUtil.errno();
175 if (errno == SemaphoreException.S_objLib_OBJ_UNAVAILABLE) {
176 return false;
177 } else {
178 throw new SemaphoreException(errno);
179 }
180 }
181 }
182
183 /**
184 * Close the semaphore.
185 */
186 public void close () throws SemaphoreException{
187 checkStatus(semCloseFn.call1(m_semaphore));
188 }
189
190 /**
191 * Release all resources associated with the semaphore.
192 */
193 public void free () throws SemaphoreException{
194 checkStatus(semDeleteFn.call1(m_semaphore));
195 }
196 }