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