WPILibC++ 2024.3.2
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 */
70
71/**
72 * Sets an event to signaled state.
73 *
74 * @param handle event handle
75 */
77
78/**
79 * Sets an event to non-signaled state.
80 *
81 * @param handle event handle
82 */
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 */
97 int maximumCount = INT_MAX);
98
99/**
100 * Destroys a semaphore. Destruction wakes up any waiters.
101 *
102 * @param handle semaphore handle
103 */
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 */
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 Event 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 */
216void CreateSignalObject(WPI_Handle handle, bool manualReset = false,
217 bool initialState = false);
218
219/**
220 * Sets a handle to signaled state.
221 *
222 * @param handle handle
223 */
225
226/**
227 * Sets a handle to non-signaled state.
228 *
229 * @param handle handle
230 */
232
233/**
234 * Cleans up signaling for a handle. Destruction wakes up any waiters.
235 *
236 * @param handle handle
237 */
239
240/**
241 * An atomic signaling event for synchronization.
242 *
243 * Events have binary state (signaled or not signaled) and may be either
244 * automatically reset or manually reset. Automatic-reset events go to
245 * non-signaled state when a WaitForObject is woken up by the event;
246 * manual-reset events require Reset() to be called to set the event to
247 * non-signaled state; if Reset() is not called, any waiter on that event
248 * will immediately wake when called.
249 */
250class Event final {
251 public:
252 /**
253 * Constructor.
254 *
255 * @param manualReset true for manual reset, false for automatic reset
256 * @param initialState true to make the event initially in signaled state
257 */
258 explicit Event(bool manualReset = false, bool initialState = false)
259 : m_handle{CreateEvent(manualReset, initialState)} {}
261 if (m_handle != 0) {
262 DestroyEvent(m_handle);
263 }
264 }
265
266 Event(const Event&) = delete;
267 Event& operator=(const Event&) = delete;
268
269 Event(Event&& rhs) : m_handle{rhs.m_handle} { rhs.m_handle = 0; }
271 if (m_handle != 0) {
272 DestroyEvent(m_handle);
273 }
274 m_handle = rhs.m_handle;
275 rhs.m_handle = 0;
276 return *this;
277 }
278
279 /**
280 * Gets the event handle (e.g. for WaitForObject).
281 *
282 * @return handle
283 */
284 explicit operator WPI_Handle() const { return m_handle; }
285
286 /**
287 * Gets the event handle (e.g. for WaitForObject).
288 *
289 * @return handle
290 */
291 WPI_EventHandle GetHandle() const { return m_handle; }
292
293 /**
294 * Sets the event to signaled state.
295 */
296 void Set() { SetEvent(m_handle); }
297
298 /**
299 * Sets the event to non-signaled state.
300 */
301 void Reset() { ResetEvent(m_handle); }
302
303 private:
304 WPI_EventHandle m_handle;
305};
306
307/**
308 * A semaphore for synchronization.
309 *
310 * Semaphores keep an internal counter. Releasing the semaphore increases
311 * the count. A semaphore with a non-zero count is considered signaled.
312 * When a waiter wakes up it atomically decrements the count by 1. This
313 * is generally useful in a single-supplier, multiple-consumer scenario.
314 */
315class Semaphore final {
316 public:
317 /**
318 * Constructor.
319 *
320 * @param initialCount initial value for the semaphore's internal counter
321 * @param maximumCount maximum value for the samephore's internal counter
322 */
323 explicit Semaphore(int initialCount = 0, int maximumCount = INT_MAX)
324 : m_handle{CreateSemaphore(initialCount, maximumCount)} {}
326 if (m_handle != 0) {
327 DestroySemaphore(m_handle);
328 }
329 }
330
331 Semaphore(const Semaphore&) = delete;
332 Semaphore& operator=(const Semaphore&) = delete;
333
334 Semaphore(Semaphore&& rhs) : m_handle{rhs.m_handle} { rhs.m_handle = 0; }
336 if (m_handle != 0) {
337 DestroySemaphore(m_handle);
338 }
339 m_handle = rhs.m_handle;
340 rhs.m_handle = 0;
341 return *this;
342 }
343
344 /**
345 * Gets the semaphore handle (e.g. for WaitForObject).
346 *
347 * @return handle
348 */
349 explicit operator WPI_Handle() const { return m_handle; }
350
351 /**
352 * Gets the semaphore handle (e.g. for WaitForObject).
353 *
354 * @return handle
355 */
356 WPI_SemaphoreHandle GetHandle() const { return m_handle; }
357
358 /**
359 * Releases N counts of the semaphore.
360 *
361 * @param releaseCount amount to add to semaphore's internal counter;
362 * must be positive
363 * @param prevCount if non-null, previous count (output parameter)
364 * @return True on successful release, false on failure (e.g. release count
365 * would exceed maximum value, or handle invalid)
366 */
367 bool Release(int releaseCount = 1, int* prevCount = nullptr) {
368 return ReleaseSemaphore(m_handle, releaseCount, prevCount);
369 }
370
371 private:
372 WPI_SemaphoreHandle m_handle;
373};
374
375/**
376 * RAII wrapper for signaling handles.
377 *
378 * Sets up signaling for an arbitrary handle. This enables any handle
379 * to operate like an event handle.
380 */
381template <typename T>
382class SignalObject final {
383 public:
384 /**
385 * Constructor.
386 *
387 * @param handle handle
388 * @param manualReset true for manual reset, false for automatic reset
389 * @param initialState true to make the handle initially in signaled state
390 */
391 explicit SignalObject(T handle = 0, bool manualReset = false,
392 bool initialState = false)
393 : m_handle{handle} {
394 CreateSignalObject(handle, manualReset, initialState);
395 }
397 if (m_handle != 0) {
398 DestroySignalObject(m_handle);
399 }
400 }
401
402 SignalObject(const SignalObject&) = delete;
404
405 SignalObject(SignalObject&& rhs) : m_handle{rhs.m_handle} {
406 rhs.m_handle = 0;
407 }
409 if (m_handle != 0) {
410 DestroySemaphore(m_handle);
411 }
412 m_handle = rhs.m_handle;
413 rhs.m_handle = 0;
414 return *this;
415 }
416
417 /**
418 * Gets the handle.
419 *
420 * @return handle
421 */
422 /*implicit*/ operator T() const { return m_handle; } // NOLINT
423
424 /**
425 * Gets the handle (e.g. for WaitForObject).
426 *
427 * @return handle
428 */
429 T GetHandle() const { return m_handle; }
430
431 /**
432 * Sets the handle to signaled state.
433 */
434 void Set() { SetSignalObject(m_handle); }
435
436 /**
437 * Sets the handle to non-signaled state.
438 */
439 void Reset() { ResetSignalObject(m_handle); }
440
441 private:
442 T m_handle;
443};
444
445} // namespace wpi
446
447extern "C" {
448
449#endif // __cplusplus
450
451/**
452 * Creates an event. Events have binary state (signaled or not signaled) and
453 * may be either automatically reset or manually reset. Automatic-reset events
454 * go to non-signaled state when a WaitForObject is woken up by the event;
455 * manual-reset events require ResetEvent() to be called to set the event to
456 * non-signaled state; if ResetEvent() is not called, any waiter on that event
457 * will immediately wake when called.
458 *
459 * @param manual_reset true for manual reset, false for automatic reset
460 * @param initial_state true to make the event initially in signaled state
461 * @return Event handle
462 */
463WPI_EventHandle WPI_CreateEvent(int manual_reset, int initial_state);
464
465/**
466 * Destroys an event. Destruction wakes up any waiters.
467 *
468 * @param handle event handle
469 */
471
472/**
473 * Sets an event to signaled state.
474 *
475 * @param handle event handle
476 */
478
479/**
480 * Sets an event to non-signaled state.
481 *
482 * @param handle event handle
483 */
485
486/**
487 * Creates a semaphore. Semaphores keep an internal counter. Releasing the
488 * semaphore increases the count. A semaphore with a non-zero count is
489 * considered signaled. When a waiter wakes up it atomically decrements the
490 * count by 1. This is generally useful in a single-supplier,
491 * multiple-consumer scenario.
492 *
493 * @param initial_count initial value for the semaphore's internal counter
494 * @param maximum_count maximum value for the samephore's internal counter
495 * @return Semaphore handle
496 */
497WPI_SemaphoreHandle WPI_CreateSemaphore(int initial_count, int maximum_count);
498
499/**
500 * Destroys a semaphore. Destruction wakes up any waiters.
501 *
502 * @param handle semaphore handle
503 */
505
506/**
507 * Releases N counts of a semaphore.
508 *
509 * @param handle semaphore handle
510 * @param release_count amount to add to semaphore's internal counter;
511 * must be positive
512 * @param prev_count if non-null, previous count (output parameter)
513 * @return Non-zero on successful release, zero on failure (e.g. release count
514 * would exceed maximum value, or handle invalid)
515 */
516int WPI_ReleaseSemaphore(WPI_SemaphoreHandle handle, int release_count,
517 int* prev_count);
518
519/**
520 * Waits for an handle to be signaled.
521 *
522 * @param handle handle to wait on
523 * @return Non-zero if handle was signaled, zero otherwise (e.g. object was
524 * destroyed)
525 */
527
528/**
529 * Waits for an handle to be signaled, with timeout.
530 *
531 * @param handle handle to wait on
532 * @param timeout timeout in seconds
533 * @param timed_out if non-null, set to non-zero if timeout reached without
534 * handle being signaled; set to zero otherwise (output)
535 * @return Non-zero if handle was signaled, zero otherwise (e.g. object was
536 * destroyed or timed out)
537 */
538int WPI_WaitForObjectTimeout(WPI_Handle handle, double timeout, int* timed_out);
539
540/**
541 * Waits for one or more handles to be signaled.
542 *
543 * Invalid handles are treated as signaled; the returned array will have the
544 * handle error bit set for any invalid handles.
545 *
546 * @param handles array of handles to wait on
547 * @param handles_count length of the handles array
548 * @param signaled output array for storage of signaled handles; must be at
549 * least the size of the handles input array
550 * @return number of signaled handles
551 */
552int WPI_WaitForObjects(const WPI_Handle* handles, int handles_count,
553 WPI_Handle* signaled);
554
555/**
556 * Waits for one or more handles to be signaled, with timeout.
557 *
558 * Invalid handles are treated as signaled; the returned array will have the
559 * handle error bit set for any invalid handles.
560 *
561 * @param handles array of handles to wait on
562 * @param handles_count length of the handles array
563 * @param signaled output array for storage of signaled handles; must be at
564 * least the size of the handles input array
565 * @param timeout timeout in seconds
566 * @param timed_out if non-null, set to non-zero if timeout reached without any
567 * handle being signaled; set to zero otherwise (output)
568 * @return number of signaled handles
569 */
570int WPI_WaitForObjectsTimeout(const WPI_Handle* handles, int handles_count,
571 WPI_Handle* signaled, double timeout,
572 int* timed_out);
573
574/**
575 * Sets up signaling for an arbitrary handle. With this function, any handle
576 * can operate like an event handle.
577 *
578 * @param handle handle
579 * @param manual_reset true for manual reset, false for automatic reset
580 * @param initial_state true to make the handle initially in signaled state
581 */
582void WPI_CreateSignalObject(WPI_Handle handle, int manual_reset,
583 int initial_state);
584
585/**
586 * Sets a handle to signaled state.
587 *
588 * @param handle handle
589 */
591
592/**
593 * Sets a handle to non-signaled state.
594 *
595 * @param handle handle
596 */
598
599/**
600 * Cleans up signaling for a handle. Destruction wakes up any waiters.
601 *
602 * @param handle handle
603 */
605
606#ifdef __cplusplus
607} // extern "C"
608#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.
An atomic signaling event for synchronization.
Definition: Synchronization.h:250
void Set()
Sets the event to signaled state.
Definition: Synchronization.h:296
Event(bool manualReset=false, bool initialState=false)
Constructor.
Definition: Synchronization.h:258
Event & operator=(const Event &)=delete
Event & operator=(Event &&rhs)
Definition: Synchronization.h:270
Event(Event &&rhs)
Definition: Synchronization.h:269
~Event()
Definition: Synchronization.h:260
void Reset()
Sets the event to non-signaled state.
Definition: Synchronization.h:301
WPI_EventHandle GetHandle() const
Gets the event handle (e.g.
Definition: Synchronization.h:291
Event(const Event &)=delete
A semaphore for synchronization.
Definition: Synchronization.h:315
~Semaphore()
Definition: Synchronization.h:325
Semaphore & operator=(const Semaphore &)=delete
bool Release(int releaseCount=1, int *prevCount=nullptr)
Releases N counts of the semaphore.
Definition: Synchronization.h:367
Semaphore(int initialCount=0, int maximumCount=INT_MAX)
Constructor.
Definition: Synchronization.h:323
Semaphore & operator=(Semaphore &&rhs)
Definition: Synchronization.h:335
Semaphore(Semaphore &&rhs)
Definition: Synchronization.h:334
WPI_SemaphoreHandle GetHandle() const
Gets the semaphore handle (e.g.
Definition: Synchronization.h:356
Semaphore(const Semaphore &)=delete
RAII wrapper for signaling handles.
Definition: Synchronization.h:382
void Reset()
Sets the handle to non-signaled state.
Definition: Synchronization.h:439
SignalObject(T handle=0, bool manualReset=false, bool initialState=false)
Constructor.
Definition: Synchronization.h:391
SignalObject & operator=(SignalObject &&rhs)
Definition: Synchronization.h:408
SignalObject(const SignalObject &)=delete
T GetHandle() const
Gets the handle (e.g.
Definition: Synchronization.h:429
void Set()
Sets the handle to signaled state.
Definition: Synchronization.h:434
SignalObject(SignalObject &&rhs)
Definition: Synchronization.h:405
~SignalObject()
Definition: Synchronization.h:396
SignalObject & operator=(const SignalObject &)=delete
Definition: ntcore_cpp.h:26
void DestroySemaphore(WPI_SemaphoreHandle handle)
Destroys a semaphore.
void CreateSignalObject(WPI_Handle handle, bool manualReset=false, bool initialState=false)
Sets up signaling for an arbitrary handle.
void SetEvent(WPI_EventHandle handle)
Sets an event to signaled state.
void ResetSignalObject(WPI_Handle handle)
Sets a handle to non-signaled state.
WPI_EventHandle CreateEvent(bool manualReset=false, bool initialState=false)
Creates an event.
void ResetEvent(WPI_EventHandle handle)
Sets an event to non-signaled state.
bool WaitForObject(WPI_Handle handle)
Waits for an handle to be signaled.
void DestroySignalObject(WPI_Handle handle)
Cleans up signaling for a handle.
void SetSignalObject(WPI_Handle handle)
Sets a handle to signaled state.
bool ReleaseSemaphore(WPI_SemaphoreHandle handle, int releaseCount=1, int *prevCount=nullptr)
Releases N counts of a semaphore.
void DestroyEvent(WPI_EventHandle handle)
Destroys an event.
WPI_SemaphoreHandle CreateSemaphore(int initialCount=0, int maximumCount=INT_MAX)
Creates a semaphore.
std::span< WPI_Handle > WaitForObjects(std::span< const WPI_Handle > handles, std::span< WPI_Handle > signaled)
Waits for one or more handles to be signaled.
constexpr int kHandleTypeSemaphore
Definition: Synchronization.h:42
constexpr int kHandleTypeCSBase
Definition: Synchronization.h:43
constexpr int kHandleTypeNTBase
Definition: Synchronization.h:44
constexpr int kHandleTypeEvent
Standard types for handles.
Definition: Synchronization.h:41
constexpr int kHandleTypeUserBase
Definition: Synchronization.h:46
constexpr int kHandleTypeHALBase
Definition: Synchronization.h:45
constexpr unsigned int kInvalidHandle
Constant representing an invalid handle.
Definition: Synchronization.h:35