flush_ports: flush POSIX message queues properly
On Linux, read() on a message queue descriptor returns the message queue statistics, not the actual message queue data. We need to use mq_receive() to drain the queues instead. Fixes a problem where a POSIX message queue socket unit with messages in the queue at shutdown time could result in a hang on reboot/shutdown.
This commit is contained in:
committed by
Yu Watanabe
parent
676fb42aae
commit
ffb6adb763
@@ -5,6 +5,7 @@
|
||||
#include <limits.h>
|
||||
#include <linux/if.h>
|
||||
#include <linux/if_arp.h>
|
||||
#include <mqueue.h>
|
||||
#include <net/if.h>
|
||||
#include <netdb.h>
|
||||
#include <netinet/ip.h>
|
||||
@@ -1319,6 +1320,54 @@ int flush_accept(int fd) {
|
||||
}
|
||||
}
|
||||
|
||||
ssize_t flush_mqueue(int fd) {
|
||||
_cleanup_free_ char *buf = NULL;
|
||||
struct mq_attr attr;
|
||||
ssize_t count = 0;
|
||||
int r;
|
||||
|
||||
assert(fd >= 0);
|
||||
|
||||
/* Similar to flush_fd() but flushes all messages from a POSIX message queue. */
|
||||
|
||||
for (;;) {
|
||||
ssize_t l;
|
||||
|
||||
r = fd_wait_for_event(fd, POLLIN, /* timeout= */ 0);
|
||||
if (r < 0) {
|
||||
if (r == -EINTR)
|
||||
continue;
|
||||
|
||||
return r;
|
||||
}
|
||||
if (r == 0)
|
||||
return count;
|
||||
|
||||
if (!buf) {
|
||||
/* Buffer must be at least as large as mq_msgsize. */
|
||||
if (mq_getattr(fd, &attr) < 0)
|
||||
return -errno;
|
||||
|
||||
buf = malloc(attr.mq_msgsize);
|
||||
if (!buf)
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
l = mq_receive(fd, buf, attr.mq_msgsize, /* msg_prio = */ NULL);
|
||||
if (l < 0) {
|
||||
if (errno == EINTR)
|
||||
continue;
|
||||
|
||||
if (errno == EAGAIN)
|
||||
return count;
|
||||
|
||||
return -errno;
|
||||
}
|
||||
|
||||
count += l;
|
||||
}
|
||||
}
|
||||
|
||||
struct cmsghdr* cmsg_find(struct msghdr *mh, int level, int type, socklen_t length) {
|
||||
struct cmsghdr *cmsg;
|
||||
|
||||
|
||||
@@ -199,6 +199,7 @@ int receive_many_fds(int transport_fd, int **ret_fds_array, size_t *ret_n_fds_ar
|
||||
ssize_t next_datagram_size_fd(int fd);
|
||||
|
||||
int flush_accept(int fd);
|
||||
ssize_t flush_mqueue(int fd);
|
||||
|
||||
#define CMSG_FOREACH(cmsg, mh) \
|
||||
for ((cmsg) = CMSG_FIRSTHDR(mh); (cmsg); (cmsg) = CMSG_NXTHDR((mh), (cmsg)))
|
||||
|
||||
Reference in New Issue
Block a user