|
1 | 1 | #include <cassert>
|
2 | 2 | #include <cstring>
|
3 | 3 | #include <iostream>
|
4 |
| -#include <chrono> |
| 4 | +#include <cstdlib> |
5 | 5 | #include <csignal>
|
| 6 | +#include <cerrno> |
6 | 7 |
|
7 | 8 | #include "msgq/impl_msgq.h"
|
8 | 9 |
|
9 |
| -using namespace std::chrono; |
| 10 | + |
| 11 | +volatile sig_atomic_t msgq_do_exit = 0; |
| 12 | + |
| 13 | +void sig_handler(int signal) { |
| 14 | + assert(signal == SIGINT || signal == SIGTERM); |
| 15 | + msgq_do_exit = 1; |
| 16 | +} |
| 17 | + |
10 | 18 |
|
11 | 19 | MSGQContext::MSGQContext() {
|
12 | 20 | }
|
@@ -62,55 +70,61 @@ int MSGQSubSocket::connect(Context *context, std::string endpoint, std::string a
|
62 | 70 | return 0;
|
63 | 71 | }
|
64 | 72 |
|
65 |
| -Message *MSGQSubSocket::receive(bool non_blocking) { |
66 |
| - msgq_msg_t msg{}; |
| 73 | + |
| 74 | +Message * MSGQSubSocket::receive(bool non_blocking){ |
| 75 | + msgq_do_exit = 0; |
| 76 | + |
| 77 | + void (*prev_handler_sigint)(int); |
| 78 | + void (*prev_handler_sigterm)(int); |
| 79 | + if (!non_blocking){ |
| 80 | + prev_handler_sigint = std::signal(SIGINT, sig_handler); |
| 81 | + prev_handler_sigterm = std::signal(SIGTERM, sig_handler); |
| 82 | + } |
| 83 | + |
| 84 | + msgq_msg_t msg; |
| 85 | + |
| 86 | + MSGQMessage *r = NULL; |
| 87 | + |
67 | 88 | int rc = msgq_msg_recv(&msg, q);
|
68 | 89 |
|
69 |
| - if (rc == 0 && !non_blocking) { |
70 |
| - sigset_t mask; |
71 |
| - sigset_t old_mask; |
72 |
| - sigemptyset(&mask); |
73 |
| - sigaddset(&mask, SIGINT); |
74 |
| - sigaddset(&mask, SIGTERM); |
75 |
| - sigaddset(&mask, SIGUSR2); // notification from publisher |
76 |
| - |
77 |
| - pthread_sigmask(SIG_BLOCK, &mask, &old_mask); |
78 |
| - |
79 |
| - int64_t timeout_ns = ((timeout != -1) ? timeout : 100) * 1000000; |
80 |
| - auto start = steady_clock::now(); |
81 |
| - |
82 |
| - // Continue receiving messages until timeout or interruption by SIGINT or SIGTERM |
83 |
| - while (rc == 0 && timeout_ns > 0) { |
84 |
| - struct timespec ts { |
85 |
| - timeout_ns / 1000000000, |
86 |
| - timeout_ns % 1000000000, |
87 |
| - }; |
88 |
| - |
89 |
| - int ret = sigtimedwait(&mask, nullptr, &ts); |
90 |
| - if (ret == SIGINT || ret == SIGTERM) { |
91 |
| - // Ensure signal handling is not missed |
92 |
| - raise(ret); |
93 |
| - break; |
94 |
| - } else if (ret == -1 && errno == EAGAIN && timeout != -1) { |
95 |
| - break; // Timed out |
96 |
| - } |
97 |
| - |
98 |
| - rc = msgq_msg_recv(&msg, q); |
99 |
| - |
100 |
| - if (timeout != -1) { |
101 |
| - timeout_ns -= duration_cast<nanoseconds>(steady_clock::now() - start).count(); |
102 |
| - start = steady_clock::now(); // Update start time |
103 |
| - } |
| 90 | + // Hack to implement blocking read with a poller. Don't use this |
| 91 | + while (!non_blocking && rc == 0 && msgq_do_exit == 0){ |
| 92 | + msgq_pollitem_t items[1]; |
| 93 | + items[0].q = q; |
| 94 | + |
| 95 | + int t = (timeout != -1) ? timeout : 100; |
| 96 | + |
| 97 | + int n = msgq_poll(items, 1, t); |
| 98 | + rc = msgq_msg_recv(&msg, q); |
| 99 | + |
| 100 | + // The poll indicated a message was ready, but the receive failed. Try again |
| 101 | + if (n == 1 && rc == 0){ |
| 102 | + continue; |
| 103 | + } |
| 104 | + |
| 105 | + if (timeout != -1){ |
| 106 | + break; |
104 | 107 | }
|
105 |
| - pthread_sigmask(SIG_SETMASK, &old_mask, nullptr); |
106 | 108 | }
|
107 | 109 |
|
108 |
| - if (rc > 0) { |
109 |
| - MSGQMessage *r = new MSGQMessage; |
110 |
| - r->takeOwnership(msg.data, msg.size); |
111 |
| - return r; |
| 110 | + |
| 111 | + if (!non_blocking){ |
| 112 | + std::signal(SIGINT, prev_handler_sigint); |
| 113 | + std::signal(SIGTERM, prev_handler_sigterm); |
112 | 114 | }
|
113 |
| - return nullptr; |
| 115 | + |
| 116 | + errno = msgq_do_exit ? EINTR : 0; |
| 117 | + |
| 118 | + if (rc > 0){ |
| 119 | + if (msgq_do_exit){ |
| 120 | + msgq_msg_close(&msg); // Free unused message on exit |
| 121 | + } else { |
| 122 | + r = new MSGQMessage; |
| 123 | + r->takeOwnership(msg.data, msg.size); |
| 124 | + } |
| 125 | + } |
| 126 | + |
| 127 | + return (Message*)r; |
114 | 128 | }
|
115 | 129 |
|
116 | 130 | void MSGQSubSocket::setTimeout(int t){
|
|
0 commit comments