WPILibC++ 2023.4.3
Synchronization.h
Go to the documentation of this file.
1// Copyright (c) FIRST and other WPILib contributors.
2// Open Source Software; you can modify and/or share it under the terms of
3// the WPILib BSD license file in the root directory of this project.
4
5#pragma once
6
7#ifdef __cplusplus
8#include <climits> // NOLINT
9
10#include <initializer_list>
11#include <span>
12#endif
13
14/**
15 * Generic handle for all WPI handle-based interfaces.
16 *
17 * Handle data layout:
18 * - Bits 0-23: Type-specific
19 * - Bits 24-30: Type
20 * - Bit 31: Error
21 */
22typedef unsigned int WPI_Handle; // NOLINT
23
24/** An event handle. */
25typedef WPI_Handle WPI_EventHandle; // NOLINT
26
27/** A semaphore handle. */
29
30#ifdef __cplusplus
31
32namespace wpi {
33
34/** Constant representing an invalid handle. */
35constexpr unsigned int kInvalidHandle = 0;
36
37/**
38 * Standard types for handles.
39 * @{
40 */
41constexpr int kHandleTypeEvent = 1;
42constexpr int kHandleTypeSemaphore = 2;
43constexpr int kHandleTypeCSBase = 3;
44constexpr int kHandleTypeNTBase = 16;
45constexpr int kHandleTypeHALBase = 48;
46constexpr int kHandleTypeUserBase = 80;
47/** @} */
48
49/**
50 * Creates an event. Events have binary state (signaled or not signaled) and
51 * may be either automatically reset or manually reset. Automatic-reset events
52 * go to non-signaled state when a WaitForObject is woken up by the event;
53 * manual-reset events require ResetEvent() to be called to set the event to
54 * non-signaled state; if ResetEvent() is not called, any waiter on that event
55 * will immediately wake when called.
56 *
57 * @param manualReset true for manual reset, false for automatic reset
58 * @param initialState true to make the event initially in signaled state
59 * @return Event handle
60 */
61WPI_EventHandle CreateEvent(bool manualReset = false,
62 bool initialState = false);
63
64/**
65 * Destroys an event. Destruction wakes up any waiters.
66 *
67 * @param handle event handle
68 */
69void DestroyEvent(WPI_EventHandle handle);
70
71/**
72 * Sets an event to signaled state.
73 *
74 * @param handle event handle
75 */
76void SetEvent(WPI_EventHandle handle);
77
78/**
79 * Sets an event to non-signaled state.
80 *
81 * @param handle event handle
82 */
83void ResetEvent(WPI_EventHandle handle);
84
85/**
86 * Creates a semaphore. Semaphores keep an internal counter. Releasing the
87 * semaphore increases the count. A semaphore with a non-zero count is
88 * considered signaled. When a waiter wakes up it atomically decrements the
89 * count by 1. This is generally useful in a single-supplier,
90 * multiple-consumer scenario.
91 *
92 * @param initialCount initial value for the semaphore's internal counter
93 * @param maximumCount maximum value for the samephore's internal counter
94 * @return Semaphore handle
95 */
96WPI_SemaphoreHandle CreateSemaphore(int initialCount = 0,
97 int maximumCount = INT_MAX);
98
99/**
100 * Destroys a semaphore. Destruction wakes up any waiters.
101 *
102 * @param handle semaphore handle
103 */
104void DestroySemaphore(WPI_SemaphoreHandle handle);
105
106/**
107 * Releases N counts of a semaphore.
108 *
109 * @param handle semaphore handle
110 * @param releaseCount amount to add to semaphore's internal counter;
111 * must be positive
112 * @param prevCount if non-null, previous count (output parameter)
113 * @return True on successful release, false on failure (e.g. release count
114 * would exceed maximum value, or handle invalid)
115 */
116bool ReleaseSemaphore(WPI_SemaphoreHandle handle, int releaseCount = 1,
117 int* prevCount = nullptr);
118
119/**
120 * Waits for an handle to be signaled.
121 *
122 * @param handle handle to wait on
123 * @return True if handle was signaled, false otherwise (e.g. object was
124 * destroyed)
125 */
126bool WaitForObject(WPI_Handle handle);
127
128/**
129 * Waits for an handle to be signaled, with timeout.
130 *
131 * @param handle handle to wait on
132 * @param timeout timeout in seconds
133 * @param timedOut if non-null, set to true if timeout reached without handle
134 * being signaled; set to false otherwise (output)
135 * @return True if handle was signaled, false otherwise (e.g. object was
136 * destroyed or timed out)
137 */
138bool WaitForObject(WPI_Handle handle, double timeout, bool* timedOut);
139
140/**
141 * Waits for one or more handles to be signaled.
142 *
143 * Invalid handles are treated as signaled; the returned array will have the
144 * handle error bit set for any invalid handles.
145 *
146 * @param handles array of handles to wait on
147 * @param signaled output array for storage of signaled handles; must be at
148 * least the size of the handles input array
149 * @return array of signaled handles (points into signaled array)
150 */
151std::span<WPI_Handle> WaitForObjects(std::span<const WPI_Handle> handles,
152 std::span<WPI_Handle> signaled);
153
154/**
155 * Waits for one or more handles to be signaled.
156 *
157 * Invalid handles are treated as signaled; the returned array will have the
158 * handle error bit set for any invalid handles.
159 *
160 * @param handles array of handles to wait on
161 * @param signaled output array for storage of signaled handles; must be at
162 * least the size of the handles input array
163 * @return array of signaled handles (points into signaled array)
164 */
165inline std::span<WPI_Handle> WaitForObjects(
166 std::initializer_list<WPI_Handle> handles, std::span<WPI_Handle> signaled) {
167 return WaitForObjects(std::span{handles.begin(), handles.size()}, signaled);
168}
169
170/**
171 * Waits for one or more handles to be signaled, with timeout.
172 *
173 * Invalid handles are treated as signaled; the returned array will have the
174 * handle error bit set for any invalid handles.
175 *
176 * @param handles array of handles to wait on
177 * @param signaled output array for storage of signaled handles; must be at
178 * least the size of the handles input array
179 * @param timeout timeout in seconds
180 * @param timedOut if non-null, set to true if timeout reached without any
181 * handle being signaled; set to false otherwise (output)
182 * @return array of signaled handles (points into signaled array)
183 */
184std::span<WPI_Handle> WaitForObjects(std::span<const WPI_Handle> handles,
185 std::span<WPI_Handle> signaled,
186 double timeout, bool* timedOut);
187/**
188 * Waits for one or more handles to be signaled, with timeout.
189 *
190 * Invalid handles are treated as signaled; the returned array will have the
191 * handle error bit set for any invalid handles.
192 *
193 * @param handles array of handles to wait on
194 * @param signaled output array for storage of signaled handles; must be at
195 * least the size of the handles input array
196 * @param timeout timeout in seconds
197 * @param timedOut if non-null, set to true if timeout reached without any
198 * handle being signaled; set to false otherwise (output)
199 * @return array of signaled handles (points into signaled array)
200 */
201inline std::span<WPI_Handle> WaitForObjects(
202 std::initializer_list<WPI_Handle> handles, std::span<WPI_Handle> signaled,
203 double timeout, bool* timedOut) {
204 return WaitForObjects(std::span{handles.begin(), handles.size()}, signaled,
205 timeout, timedOut);
206}
207
208/**
209 * Sets up signaling for an arbitrary handle. With this function, any handle
210 * can operate like an event handle.
211 *
212 * @param handle handle
213 * @param manualReset true for manual reset, false for automatic reset
214 * @param initialState true to make the handle initially in signaled state
215 * @return Event handle
216 */
217void CreateSignalObject(WPI_Handle handle, bool manualReset = false,
218 bool initialState = false);
219
220/**
221 * Sets a handle to signaled state.
222 *
223 * @param handle handle
224 */
225void SetSignalObject(WPI_Handle handle);
226
227/**
228 * Sets a handle to non-signaled state.
229 *
230 * @param handle handle
231 */
232void ResetSignalObject(WPI_Handle handle);
233
234/**
235 * Cleans up signaling for a handle. Destruction wakes up any waiters.
236 *
237 * @param handle handle
238 */
239void DestroySignalObject(WPI_Handle handle);
240
241/**
242 * An atomic signaling event for synchronization.
243 *
244 * Events have binary state (signaled or not signaled) and may be either
245 * automatically reset or manually reset. Automatic-reset events go to
246 * non-signaled state when a WaitForObject is woken up by the event;
247 * manual-reset events require Reset() to be called to set the event to
248 * non-signaled state; if Reset() is not called, any waiter on that event
249 * will immediately wake when called.
250 */
251class Event final {
252 public:
253 /**
254 * Constructor.
255 *
256 * @param manualReset true for manual reset, false for automatic reset
257 * @param initialState true to make the event initially in signaled state
258 */
259 explicit Event(bool manualReset = false, bool initialState = false)
260 : m_handle{CreateEvent(manualReset, initialState)} {}
261 ~Event() {
262 if (m_handle != 0) {
263 DestroyEvent(m_handle);
264 }
265 }
266
267 Event(const Event&) = delete;
268 Event& operator=(const Event&) = delete;
269
270 Event(Event&& rhs) : m_handle{rhs.m_handle} { rhs.m_handle = 0; }
271 Event& operator=(Event&& rhs) {
272 if (m_handle != 0) {
273 DestroyEvent(m_handle);
274 }
275 m_handle = rhs.m_handle;
276 rhs.m_handle = 0;
277 return *this;
278 }
279
280 /**
281 * Gets the event handle (e.g. for WaitForObject).
282 *
283 * @return handle
284 */
285 explicit operator WPI_Handle() const { return m_handle; }
286
287 /**
288 * Gets the event handle (e.g. for WaitForObject).
289 *
290 * @return handle
291 */
292 WPI_EventHandle GetHandle() const { return m_handle; }
293
294 /**
295 * Sets the event to signaled state.
296 */
297 void Set() { SetEvent(m_handle); }
298
299 /**
300 * Sets the event to non-signaled state.
301 */
302 void Reset() { ResetEvent(m_handle); }
303
304 private:
305 WPI_EventHandle m_handle;
306};
307
308/**
309 * A semaphore for synchronization.
310 *
311 * Semaphores keep an internal counter. Releasing the semaphore increases
312 * the count. A semaphore with a non-zero count is considered signaled.
313 * When a waiter wakes up it atomically decrements the count by 1. This
314 * is generally useful in a single-supplier, multiple-consumer scenario.
315 */
316class Semaphore final {
317 public:
318 /**
319 * Constructor.
320 *
321 * @param initialCount initial value for the semaphore's internal counter
322 * @param maximumCount maximum value for the samephore's internal counter
323 */
324 explicit Semaphore(int initialCount = 0, int maximumCount = INT_MAX)
325 : m_handle{CreateSemaphore(initialCount, maximumCount)} {}
326 ~Semaphore() {
327 if (m_handle != 0) {
328 DestroySemaphore(m_handle);
329 }
330 }
331
332 Semaphore(const Semaphore&) = delete;
333 Semaphore& operator=(const Semaphore&) = delete;
334
335 Semaphore(Semaphore&& rhs) : m_handle{rhs.m_handle} { rhs.m_handle = 0; }
336 Semaphore& operator=(Semaphore&& rhs) {
337 if (m_handle != 0) {
338 DestroySemaphore(m_handle);
339 }
340 m_handle = rhs.m_handle;
341 rhs.m_handle = 0;
342 return *this;
343 }
344
345 /**
346 * Gets the semaphore handle (e.g. for WaitForObject).
347 *
348 * @return handle
349 */
350 explicit operator WPI_Handle() const { return m_handle; }
351
352 /**
353 * Gets the semaphore handle (e.g. for WaitForObject).
354 *
355 * @return handle
356 */
357 WPI_SemaphoreHandle GetHandle() const { return m_handle; }
358
359 /**
360 * Releases N counts of the semaphore.
361 *
362 * @param releaseCount amount to add to semaphore's internal counter;
363 * must be positive
364 * @param prevCount if non-null, previous count (output parameter)
365 * @return True on successful release, false on failure (e.g. release count
366 * would exceed maximum value, or handle invalid)
367 */
368 bool Release(int releaseCount = 1, int* prevCount = nullptr) {
369 return ReleaseSemaphore(m_handle, releaseCount, prevCount);
370 }
371
372 private:
373 WPI_SemaphoreHandle m_handle;
374};
375
376/**
377 * RAII wrapper for signaling handles.
378 *
379 * Sets up signaling for an arbitrary handle. This enables any handle
380 * to operate like an event handle.
381 */
382template <typename T>
383class SignalObject final {
384 public:
385 /**
386 * Constructor.
387 *
388 * @param handle handle
389 * @param manualReset true for manual reset, false for automatic reset
390 * @param initialState true to make the handle initially in signaled state
391 */
392 explicit SignalObject(T handle = 0, bool manualReset = false,
393 bool initialState = false)
394 : m_handle{handle} {
395 CreateSignalObject(handle, manualReset, initialState);
396 }
397 ~SignalObject() {
398 if (m_handle != 0) {
399 DestroySignalObject(m_handle);
400 }
401 }
402
403 SignalObject(const SignalObject&) = delete;
404 SignalObject& operator=(const SignalObject&) = delete;
405
406 SignalObject(SignalObject&& rhs) : m_handle{rhs.m_handle} {
407 rhs.m_handle = 0;
408 }
409 SignalObject& operator=(SignalObject&& rhs) {
410 if (m_handle != 0) {
411 DestroySemaphore(m_handle);
412 }
413 m_handle = rhs.m_handle;
414 rhs.m_handle = 0;
415 return *this;
416 }
417
418 /**
419 * Gets the handle.
420 *
421 * @return handle
422 */
423 /*implicit*/ operator T() const { return m_handle; } // NOLINT
424
425 /**
426 * Gets the handle (e.g. for WaitForObject).
427 *
428 * @return handle
429 */
430 T GetHandle() const { return m_handle; }
431
432 /**
433 * Sets the handle to signaled state.
434 */
435 void Set() { SetSignalObject(m_handle); }
436
437 /**
438 * Sets the handle to non-signaled state.
439 */
440 void Reset() { ResetSignalObject(m_handle); }
441
442 private:
443 T m_handle;
444};
445
446} // namespace wpi
447
448extern "C" {
449
450#endif // __cplusplus
451
452/**
453 * Creates an event. Events have binary state (signaled or not signaled) and
454 * may be either automatically reset or manually reset. Automatic-reset events
455 * go to non-signaled state when a WaitForObject is woken up by the event;
456 * manual-reset events require ResetEvent() to be called to set the event to
457 * non-signaled state; if ResetEvent() is not called, any waiter on that event
458 * will immediately wake when called.
459 *
460 * @param manual_reset true for manual reset, false for automatic reset
461 * @param initial_state true to make the event initially in signaled state
462 * @return Event handle
463 */
464WPI_EventHandle WPI_CreateEvent(int manual_reset, int initial_state);
465
466/**
467 * Destroys an event. Destruction wakes up any waiters.
468 *
469 * @param handle event handle
470 */
472
473/**
474 * Sets an event to signaled state.
475 *
476 * @param handle event handle
477 */
479
480/**
481 * Sets an event to non-signaled state.
482 *
483 * @param handle event handle
484 */
486
487/**
488 * Creates a semaphore. Semaphores keep an internal counter. Releasing the
489 * semaphore increases the count. A semaphore with a non-zero count is
490 * considered signaled. When a waiter wakes up it atomically decrements the
491 * count by 1. This is generally useful in a single-supplier,
492 * multiple-consumer scenario.
493 *
494 * @param initial_count initial value for the semaphore's internal counter
495 * @param maximum_count maximum value for the samephore's internal counter
496 * @return Semaphore handle
497 */
498WPI_SemaphoreHandle WPI_CreateSemaphore(int initial_count, int maximum_count);
499
500/**
501 * Destroys a semaphore. Destruction wakes up any waiters.
502 *
503 * @param handle semaphore handle
504 */
506
507/**
508 * Releases N counts of a semaphore.
509 *
510 * @param handle semaphore handle
511 * @param release_count amount to add to semaphore's internal counter;
512 * must be positive
513 * @param prev_count if non-null, previous count (output parameter)
514 * @return Non-zero on successful release, zero on failure (e.g. release count
515 * would exceed maximum value, or handle invalid)
516 */
517int WPI_ReleaseSemaphore(WPI_SemaphoreHandle handle, int release_count,
518 int* prev_count);
519
520/**
521 * Waits for an handle to be signaled.
522 *
523 * @param handle handle to wait on
524 * @return Non-zero if handle was signaled, zero otherwise (e.g. object was
525 * destroyed)
526 */
528
529/**
530 * Waits for an handle to be signaled, with timeout.
531 *
532 * @param handle handle to wait on
533 * @param timeout timeout in seconds
534 * @param timed_out if non-null, set to non-zero if timeout reached without
535 * handle being signaled; set to zero otherwise (output)
536 * @return Non-zero if handle was signaled, zero otherwise (e.g. object was
537 * destroyed or timed out)
538 */
539int WPI_WaitForObjectTimeout(WPI_Handle handle, double timeout, int* timed_out);
540
541/**
542 * Waits for one or more handles to be signaled.
543 *
544 * Invalid handles are treated as signaled; the returned array will have the
545 * handle error bit set for any invalid handles.
546 *
547 * @param handles array of handles to wait on
548 * @param handles_count length of the handles array
549 * @param signaled output array for storage of signaled handles; must be at
550 * least the size of the handles input array
551 * @return number of signaled handles
552 */
553int WPI_WaitForObjects(const WPI_Handle* handles, int handles_count,
554 WPI_Handle* signaled);
555
556/**
557 * Waits for one or more handles to be signaled, with timeout.
558 *
559 * Invalid handles are treated as signaled; the returned array will have the
560 * handle error bit set for any invalid handles.
561 *
562 * @param handles array of handles to wait on
563 * @param handles_count length of the handles array
564 * @param signaled output array for storage of signaled handles; must be at
565 * least the size of the handles input array
566 * @param timeout timeout in seconds
567 * @param timed_out if non-null, set to non-zero if timeout reached without any
568 * handle being signaled; set to zero otherwise (output)
569 * @return number of signaled handles
570 */
571int WPI_WaitForObjectsTimeout(const WPI_Handle* handles, int handles_count,
572 WPI_Handle* signaled, double timeout,
573 int* timed_out);
574
575/**
576 * Sets up signaling for an arbitrary handle. With this function, any handle
577 * can operate like an event handle.
578 *
579 * @param handle handle
580 * @param manual_reset true for manual reset, false for automatic reset
581 * @param initial_state true to make the handle initially in signaled state
582 */
583void WPI_CreateSignalObject(WPI_Handle handle, int manual_reset,
584 int initial_state);
585
586/**
587 * Sets a handle to signaled state.
588 *
589 * @param handle handle
590 */
592
593/**
594 * Sets a handle to non-signaled state.
595 *
596 * @param handle handle
597 */
599
600/**
601 * Cleans up signaling for a handle. Destruction wakes up any waiters.
602 *
603 * @param handle handle
604 */
606
607#ifdef __cplusplus
608} // extern "C"
609#endif
void WPI_DestroySemaphore(WPI_SemaphoreHandle handle)
Destroys a semaphore.
int WPI_WaitForObjectsTimeout(const WPI_Handle *handles, int handles_count, WPI_Handle *signaled, double timeout, int *timed_out)
Waits for one or more handles to be signaled, with timeout.
WPI_SemaphoreHandle WPI_CreateSemaphore(int initial_count, int maximum_count)
Creates a semaphore.
void WPI_SetSignalObject(WPI_Handle handle)
Sets a handle to signaled state.
int WPI_ReleaseSemaphore(WPI_SemaphoreHandle handle, int release_count, int *prev_count)
Releases N counts of a semaphore.
void WPI_ResetSignalObject(WPI_Handle handle)
Sets a handle to non-signaled state.
WPI_Handle WPI_SemaphoreHandle
A semaphore handle.
Definition: Synchronization.h:28
unsigned int WPI_Handle
Generic handle for all WPI handle-based interfaces.
Definition: Synchronization.h:22
int WPI_WaitForObjectTimeout(WPI_Handle handle, double timeout, int *timed_out)
Waits for an handle to be signaled, with timeout.
WPI_Handle WPI_EventHandle
An event handle.
Definition: Synchronization.h:25
void WPI_CreateSignalObject(WPI_Handle handle, int manual_reset, int initial_state)
Sets up signaling for an arbitrary handle.
void WPI_DestroyEvent(WPI_EventHandle handle)
Destroys an event.
WPI_EventHandle WPI_CreateEvent(int manual_reset, int initial_state)
Creates an event.
void WPI_DestroySignalObject(WPI_Handle handle)
Cleans up signaling for a handle.
void WPI_ResetEvent(WPI_EventHandle handle)
Sets an event to non-signaled state.
int WPI_WaitForObject(WPI_Handle handle)
Waits for an handle to be signaled.
void WPI_SetEvent(WPI_EventHandle handle)
Sets an event to signaled state.
int WPI_WaitForObjects(const WPI_Handle *handles, int handles_count, WPI_Handle *signaled)
Waits for one or more handles to be signaled.
void Release(NT_Handle pubsubentry)
Stops entry/subscriber/publisher.
/file This file defines the SmallVector class.
Definition: AprilTagFieldLayout.h:18