3
3
#include < cerrno>
4
4
#include < cmath>
5
5
#include < cstring>
6
- #include < cstdint>
7
6
#include < chrono>
8
7
#include < algorithm>
9
8
#include < cstdlib>
10
- #include < csignal>
11
9
#include < random>
12
10
#include < string>
13
11
#include < limits>
14
-
15
- #include < poll.h>
16
- #include < sys/ioctl.h>
17
12
#include < sys/mman.h>
18
- #include < sys/stat.h>
19
- #include < sys/types.h>
20
- #include < sys/syscall.h>
21
13
#include < fcntl.h>
22
14
#include < unistd.h>
23
15
24
- #include < stdio.h>
25
-
16
+ #include " msgq/futex.h"
26
17
#include " msgq/msgq.h"
27
18
28
- void sigusr2_handler (int signal) {
29
- assert (signal == SIGUSR2);
30
- }
19
+ Futex g_futex (" /dev/shm/msgq_futex" );
31
20
32
- uint64_t msgq_get_uid (void ){
21
+ static uint64_t msgq_get_uid (void ) {
33
22
std::random_device rd (" /dev/urandom" );
34
- std::uniform_int_distribution<uint64_t > distribution (0 , std::numeric_limits<uint32_t >::max ());
35
-
36
- #ifdef __APPLE__
37
- // TODO: this doesn't work
38
- uint64_t uid = distribution (rd) << 32 | getpid ();
39
- #else
40
- uint64_t uid = distribution (rd) << 32 | syscall (SYS_gettid);
41
- #endif
42
-
43
- return uid;
23
+ std::uniform_int_distribution<uint64_t > distribution (1 , std::numeric_limits<uint64_t >::max ());
24
+ return distribution (rd);
44
25
}
45
26
46
27
int msgq_msg_init_size (msgq_msg_t * msg, size_t size){
@@ -85,7 +66,6 @@ void msgq_wait_for_subscriber(msgq_queue_t *q){
85
66
86
67
int msgq_new_queue (msgq_queue_t * q, const char * path, size_t size){
87
68
assert (size < 0xFFFFFFFF ); // Buffer must be smaller than 2^32 bytes
88
- std::signal (SIGUSR2, sigusr2_handler);
89
69
90
70
std::string full_path = " /dev/shm/" ;
91
71
const char * prefix = std::getenv (" OPENPILOT_PREFIX" );
@@ -142,7 +122,6 @@ void msgq_close_queue(msgq_queue_t *q){
142
122
}
143
123
}
144
124
145
-
146
125
void msgq_init_publisher (msgq_queue_t * q) {
147
126
// std::cout << "Starting publisher" << std::endl;
148
127
uint64_t uid = msgq_get_uid ();
@@ -158,15 +137,6 @@ void msgq_init_publisher(msgq_queue_t * q) {
158
137
q->write_uid_local = uid;
159
138
}
160
139
161
- static void thread_signal (uint32_t tid) {
162
- #ifndef SYS_tkill
163
- // TODO: this won't work for multithreaded programs
164
- kill (tid, SIGUSR2);
165
- #else
166
- syscall (SYS_tkill, tid, SIGUSR2);
167
- #endif
168
- }
169
-
170
140
void msgq_init_subscriber (msgq_queue_t * q) {
171
141
assert (q != NULL );
172
142
assert (q->num_readers != NULL );
@@ -185,14 +155,11 @@ void msgq_init_subscriber(msgq_queue_t * q) {
185
155
186
156
for (size_t i = 0 ; i < NUM_READERS; i++){
187
157
*q->read_valids [i] = false ;
188
-
189
- uint64_t old_uid = *q->read_uids [i];
190
158
*q->read_uids [i] = 0 ;
191
-
192
- // Wake up reader in case they are in a poll
193
- thread_signal (old_uid & 0xFFFFFFFF );
194
159
}
195
160
161
+ // Notify readers
162
+ g_futex.broadcast ();
196
163
continue ;
197
164
}
198
165
@@ -293,10 +260,7 @@ int msgq_msg_send(msgq_msg_t * msg, msgq_queue_t *q){
293
260
PACK64 (*q->write_pointer , write_cycles, new_ptr);
294
261
295
262
// Notify readers
296
- for (uint64_t i = 0 ; i < num_readers; i++){
297
- uint64_t reader_uid = *q->read_uids [i];
298
- thread_signal (reader_uid & 0xFFFFFFFF );
299
- }
263
+ g_futex.broadcast ();
300
264
301
265
return msg->size ;
302
266
}
@@ -414,42 +378,31 @@ int msgq_msg_recv(msgq_msg_t * msg, msgq_queue_t * q){
414
378
goto start;
415
379
}
416
380
417
-
418
381
return msg->size ;
419
382
}
420
383
421
-
422
-
423
- int msgq_poll (msgq_pollitem_t * items, size_t nitems, int timeout){
384
+ int msgq_poll (msgq_pollitem_t * items, size_t nitems, int timeout) {
424
385
int num = 0 ;
386
+ int timeout_ms = (timeout == -1 ) ? 100 : timeout;
387
+ uint32_t current_futex_value = 0 ;
425
388
426
- // Check if messages ready
427
- for (size_t i = 0 ; i < nitems; i++) {
428
- items[i].revents = msgq_msg_ready (items[i].q );
429
- if (items[i].revents ) num++;
430
- }
431
-
432
- int ms = (timeout == -1 ) ? 100 : timeout;
433
- struct timespec ts;
434
- ts.tv_sec = ms / 1000 ;
435
- ts.tv_nsec = (ms % 1000 ) * 1000 * 1000 ;
436
-
437
-
389
+ auto start_time = std::chrono::high_resolution_clock::now ();
438
390
while (num == 0 ) {
439
- int ret;
440
-
441
- ret = nanosleep (&ts, &ts);
391
+ if (g_futex.wait (current_futex_value, timeout_ms)) {
392
+ current_futex_value = g_futex.value ();
442
393
443
- // Check if messages ready
444
- for (size_t i = 0 ; i < nitems; i++) {
445
- if (items[i].revents == 0 && msgq_msg_ready (items[i].q )){
446
- num += 1 ;
447
- items[i].revents = 1 ;
394
+ // Check if messages ready
395
+ for (size_t i = 0 ; i < nitems; i++) {
396
+ items[i].revents = msgq_msg_ready (items[i].q );
397
+ if (items[i].revents ) ++num;
448
398
}
449
399
}
450
400
451
- // exit if we had a timeout and the sleep finished
452
- if (timeout != -1 && ret == 0 ){
401
+ // Update the remaining timeout
402
+ auto current_time = std::chrono::high_resolution_clock::now ();
403
+ timeout_ms -= std::chrono::duration_cast<std::chrono::milliseconds>(current_time - start_time).count ();
404
+ start_time = current_time;
405
+ if (timeout_ms <= 0 ) {
453
406
break ;
454
407
}
455
408
}
0 commit comments