RobotCore 1.0
WPILib port to raspberry Pi
Loading...
Searching...
No Matches
PiSignals.java
1package org.wpilib.hardware.hal.PiNotifier;
2
3import java.util.ArrayList;
4import java.util.HashMap;
5import java.util.List;
6import java.util.Map;
7import java.util.concurrent.atomic.AtomicInteger;
8import java.util.concurrent.locks.Condition;
9import java.util.concurrent.locks.ReentrantLock;
10
20public final class PiSignals {
22 public static final int TYPE_EVENT = 0x01;
23
25 public static final int TYPE_SEMAPHORE = 0x02;
26
28 public static final int TYPE_NOTIFIER = 0x13;
29
30 private static final int ERROR_BIT = 0x80000000;
31
32 private static final class State {
33 int signaled;
34 boolean autoReset;
35 int maxCount; // semaphores only
36 final List<Condition> waiters = new ArrayList<>(2);
37 }
38
39 private static final ReentrantLock s_lock = new ReentrantLock();
40 private static final Map<Integer, State> s_states = new HashMap<>();
41 private static final Map<Integer, AtomicInteger> s_nextIndex = new HashMap<>();
42
43 private PiSignals() {}
44
45 // ---------------------------------------------------------------- handles
46
53 public static int allocateHandle(int type) {
54 AtomicInteger counter;
55 s_lock.lock();
56 try {
57 counter = s_nextIndex.computeIfAbsent(type, t -> new AtomicInteger());
58 } finally {
59 s_lock.unlock();
60 }
61 int index = counter.incrementAndGet() & 0xFFFFFF;
62 if (index == 0) {
63 index = counter.incrementAndGet() & 0xFFFFFF; // skip 0 on wraparound
64 }
65 return ((type & 0x7F) << 24) | index;
66 }
67
68 // ---------------------------------------------------------- signal objects
69
77 public static void createSignalObject(int handle, boolean manualReset, boolean initialState) {
78 s_lock.lock();
79 try {
80 State s = s_states.computeIfAbsent(handle, h -> new State());
81 s.signaled = initialState ? 1 : 0;
82 s.autoReset = !manualReset;
83 } finally {
84 s_lock.unlock();
85 }
86 }
87
93 public static void setSignalObject(int handle) {
94 s_lock.lock();
95 try {
96 State s = s_states.get(handle);
97 if (s == null) {
98 return;
99 }
100 s.signaled = 1;
101 // Wake everyone; with auto-reset only the first to re-check consumes it, the rest re-wait.
102 for (Condition c : s.waiters) {
103 c.signalAll();
104 }
105 } finally {
106 s_lock.unlock();
107 }
108 }
109
115 public static void resetSignalObject(int handle) {
116 s_lock.lock();
117 try {
118 State s = s_states.get(handle);
119 if (s != null) {
120 s.signaled = 0;
121 }
122 } finally {
123 s_lock.unlock();
124 }
125 }
126
133 public static void destroySignalObject(int handle) {
134 s_lock.lock();
135 try {
136 State s = s_states.remove(handle);
137 if (s != null) {
138 for (Condition c : s.waiters) {
139 c.signalAll();
140 }
141 }
142 } finally {
143 s_lock.unlock();
144 }
145 }
146
147 // ------------------------------------------------------------------ events
148
156 public static int makeEvent(boolean manualReset, boolean initialState) {
157 int handle = allocateHandle(TYPE_EVENT);
158 createSignalObject(handle, manualReset, initialState);
159 return handle;
160 }
161
167 public static void destroyEvent(int handle) {
168 if ((handle >>> 24) == TYPE_EVENT) {
169 destroySignalObject(handle);
170 }
171 }
172
178 public static void setEvent(int handle) {
179 if ((handle >>> 24) == TYPE_EVENT) {
180 setSignalObject(handle);
181 }
182 }
183
189 public static void resetEvent(int handle) {
190 if ((handle >>> 24) == TYPE_EVENT) {
191 resetSignalObject(handle);
192 }
193 }
194
195 // -------------------------------------------------------------- semaphores
196
204 public static int makeSemaphore(int initialCount, int maximumCount) {
205 int handle = allocateHandle(TYPE_SEMAPHORE);
206 s_lock.lock();
207 try {
208 State s = new State();
209 s.signaled = initialCount;
210 s.autoReset = true;
211 s.maxCount = maximumCount;
212 s_states.put(handle, s);
213 } finally {
214 s_lock.unlock();
215 }
216 return handle;
217 }
218
224 public static void destroySemaphore(int handle) {
225 if ((handle >>> 24) == TYPE_SEMAPHORE) {
226 destroySignalObject(handle);
227 }
228 }
229
237 public static boolean releaseSemaphore(int handle, int releaseCount) {
238 if ((handle >>> 24) != TYPE_SEMAPHORE || releaseCount <= 0) {
239 return false;
240 }
241 s_lock.lock();
242 try {
243 State s = s_states.get(handle);
244 if (s == null || (s.maxCount - s.signaled) < releaseCount) {
245 return false;
246 }
247 s.signaled += releaseCount;
248 for (Condition c : s.waiters) {
249 c.signalAll();
250 }
251 return true;
252 } finally {
253 s_lock.unlock();
254 }
255 }
256
257 // ------------------------------------------------------------------ waits
258 // These four match the WPIUtilJNI Java signatures and exception behavior.
259
266 public static void waitForObject(int handle) throws InterruptedException {
267 int[] r = waitCore(new int[] {handle}, -1, null);
268 if (r.length == 0 || (r[0] & ERROR_BIT) != 0) {
269 throw new InterruptedException("WaitForObject interrupted");
270 }
271 }
272
281 public static boolean waitForObjectTimeout(int handle, double timeout)
282 throws InterruptedException {
283 boolean[] timedOut = new boolean[1];
284 int[] r = waitCore(new int[] {handle}, timeout, timedOut);
285 if (timedOut[0]) {
286 return true;
287 }
288 if (r.length == 0 || (r[0] & ERROR_BIT) != 0) {
289 throw new InterruptedException("WaitForObject interrupted");
290 }
291 return false;
292 }
293
301 public static int[] waitForObjects(int[] handles) throws InterruptedException {
302 int[] r = waitCore(handles, -1, null);
303 if (r.length == 0) {
304 throw new InterruptedException("WaitForObjects interrupted");
305 }
306 return r;
307 }
308
317 public static int[] waitForObjectsTimeout(int[] handles, double timeout)
318 throws InterruptedException {
319 boolean[] timedOut = new boolean[1];
320 int[] r = waitCore(handles, timeout, timedOut);
321 if (r.length == 0 && !timedOut[0]) {
322 throw new InterruptedException("WaitForObjects interrupted");
323 }
324 return r;
325 }
326
327 private static int[] waitCore(int[] handles, double timeout, boolean[] timedOutOut)
328 throws InterruptedException {
329 s_lock.lock();
330 Condition cond = null;
331 try {
332 long deadline = timeout >= 0 ? System.nanoTime() + (long) (timeout * 1e9) : 0;
333 boolean timedOut = false;
334 int[] out = new int[handles.length];
335 int count;
336 for (;;) {
337 count = 0;
338 for (int h : handles) {
339 State s = s_states.get(h);
340 if (s == null) {
341 out[count++] = h | ERROR_BIT; // non-existent/destroyed handle counts as signaled+error
342 } else if (s.signaled > 0) {
343 out[count++] = h;
344 if (s.autoReset) {
345 s.signaled--;
346 }
347 }
348 }
349 if (count != 0 || timedOut) {
350 break;
351 }
352 if (timeout == 0) {
353 timedOut = true;
354 break;
355 }
356 if (cond == null) {
357 cond = s_lock.newCondition();
358 for (int h : handles) {
359 State s = s_states.get(h);
360 if (s != null) {
361 s.waiters.add(cond);
362 }
363 }
364 }
365 if (timeout < 0) {
366 cond.await();
367 } else {
368 long remaining = deadline - System.nanoTime();
369 if (remaining <= 0 || cond.awaitNanos(remaining) <= 0) {
370 timedOut = true; // loop once more: a signal may have raced the timeout
371 }
372 }
373 }
374 if (timedOutOut != null) {
375 timedOutOut[0] = timedOut && count == 0;
376 }
377 int[] result = new int[count];
378 System.arraycopy(out, 0, result, 0, count);
379 return result;
380 } finally {
381 if (cond != null) {
382 for (int h : handles) {
383 State s = s_states.get(h);
384 if (s != null) {
385 s.waiters.remove(cond);
386 }
387 }
388 }
389 s_lock.unlock();
390 }
391 }
392}
static void createSignalObject(int handle, boolean manualReset, boolean initialState)
static int makeEvent(boolean manualReset, boolean initialState)
static int makeSemaphore(int initialCount, int maximumCount)
static int[] waitForObjects(int[] handles)
static boolean waitForObjectTimeout(int handle, double timeout)
static boolean releaseSemaphore(int handle, int releaseCount)
static int[] waitForObjectsTimeout(int[] handles, double timeout)