|
1 | 1 | #include <cassert>
|
2 | 2 | #include <cstring>
|
3 | 3 | #include <iostream>
|
4 |
| -#include <cstdlib> |
| 4 | +#include <chrono> |
5 | 5 | #include <csignal>
|
6 |
| -#include <cerrno> |
7 | 6 |
|
8 | 7 | #include "msgq/impl_msgq.h"
|
9 | 8 |
|
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 |
| - |
| 9 | +using namespace std::chrono; |
18 | 10 |
|
19 | 11 | MSGQContext::MSGQContext() {
|
20 | 12 | }
|
@@ -70,61 +62,55 @@ int MSGQSubSocket::connect(Context *context, std::string endpoint, std::string a
|
70 | 62 | return 0;
|
71 | 63 | }
|
72 | 64 |
|
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 |
| - |
| 65 | +Message *MSGQSubSocket::receive(bool non_blocking) { |
| 66 | + msgq_msg_t msg{}; |
88 | 67 | int rc = msgq_msg_recv(&msg, q);
|
89 | 68 |
|
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; |
| 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 | + } |
107 | 104 | }
|
| 105 | + pthread_sigmask(SIG_SETMASK, &old_mask, nullptr); |
108 | 106 | }
|
109 | 107 |
|
110 |
| - |
111 |
| - if (!non_blocking){ |
112 |
| - std::signal(SIGINT, prev_handler_sigint); |
113 |
| - std::signal(SIGTERM, prev_handler_sigterm); |
114 |
| - } |
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 |
| - } |
| 108 | + if (rc > 0) { |
| 109 | + MSGQMessage *r = new MSGQMessage; |
| 110 | + r->takeOwnership(msg.data, msg.size); |
| 111 | + return r; |
125 | 112 | }
|
126 |
| - |
127 |
| - return (Message*)r; |
| 113 | + return nullptr; |
128 | 114 | }
|
129 | 115 |
|
130 | 116 | void MSGQSubSocket::setTimeout(int t){
|
|
0 commit comments