mirror of
https://salsa.debian.org/ha-team/libqb
synced 2025-12-31 02:32:41 +00:00
IPC: fix resource cleanup if the server dies
Signed-off-by: Angus Salkeld <asalkeld@redhat.com>
This commit is contained in:
parent
b32a027d5b
commit
477fac4e01
@ -112,6 +112,7 @@ struct qb_ipcc_connection {
|
||||
struct qb_ipcc_funcs funcs;
|
||||
struct qb_ipc_request_header *receive_buf;
|
||||
uint32_t fc_enable_max;
|
||||
int32_t is_connected;
|
||||
};
|
||||
|
||||
int32_t qb_ipcc_us_setup_connect(struct qb_ipcc_connection *c,
|
||||
|
||||
@ -22,6 +22,7 @@
|
||||
|
||||
#include "ipc_int.h"
|
||||
#include "util_int.h"
|
||||
#include "ringbuffer_int.h"
|
||||
#include <qb/qbdefs.h>
|
||||
#include <qb/qbatomic.h>
|
||||
#include <qb/qbloop.h>
|
||||
@ -38,9 +39,15 @@
|
||||
static void
|
||||
qb_ipcc_shm_disconnect(struct qb_ipcc_connection *c)
|
||||
{
|
||||
qb_rb_close(c->request.u.shm.rb);
|
||||
qb_rb_close(c->response.u.shm.rb);
|
||||
qb_rb_close(c->event.u.shm.rb);
|
||||
if (c->is_connected) {
|
||||
qb_rb_close(c->request.u.shm.rb);
|
||||
qb_rb_close(c->response.u.shm.rb);
|
||||
qb_rb_close(c->event.u.shm.rb);
|
||||
} else {
|
||||
qb_rb_force_close(c->request.u.shm.rb);
|
||||
qb_rb_force_close(c->response.u.shm.rb);
|
||||
qb_rb_force_close(c->event.u.shm.rb);
|
||||
}
|
||||
}
|
||||
|
||||
static ssize_t
|
||||
|
||||
12
lib/ipcc.c
12
lib/ipcc.c
@ -85,6 +85,7 @@ qb_ipcc_connect(const char *name, size_t max_msg_size)
|
||||
if (res != 0) {
|
||||
goto disconnect_and_cleanup;
|
||||
}
|
||||
c->is_connected = QB_TRUE;
|
||||
return c;
|
||||
|
||||
disconnect_and_cleanup:
|
||||
@ -123,6 +124,7 @@ qb_ipcc_send(struct qb_ipcc_connection * c, const void *msg_ptr, size_t msg_len)
|
||||
res2 = qb_ipc_us_send(&c->setup, msg_ptr, 1);
|
||||
} while (res2 == -EAGAIN);
|
||||
if (res2 == -EPIPE) {
|
||||
c->is_connected = QB_FALSE;
|
||||
return -ENOTCONN;
|
||||
}
|
||||
if (res2 != 1) {
|
||||
@ -177,6 +179,7 @@ qb_ipcc_sendv(struct qb_ipcc_connection * c, const struct iovec * iov,
|
||||
res2 = qb_ipc_us_send(&c->setup, &res, 1);
|
||||
} while (res2 == -EAGAIN);
|
||||
if (res2 == -EPIPE) {
|
||||
c->is_connected = QB_FALSE;
|
||||
return -ENOTCONN;
|
||||
}
|
||||
if (res2 != 1) {
|
||||
@ -200,6 +203,9 @@ qb_ipcc_recv(struct qb_ipcc_connection * c, void *msg_ptr,
|
||||
if ((res == -EAGAIN || res == -ETIMEDOUT) && c->needs_sock_for_poll) {
|
||||
res2 = qb_ipc_us_recv_ready(&c->setup, 0);
|
||||
if (res2 < 0) {
|
||||
if (res2 == -ENOTCONN) {
|
||||
c->is_connected = QB_FALSE;
|
||||
}
|
||||
return res2;
|
||||
} else {
|
||||
return res;
|
||||
@ -275,6 +281,9 @@ qb_ipcc_event_recv(struct qb_ipcc_connection * c, void *msg_pt,
|
||||
if (ow) {
|
||||
res = qb_ipc_us_recv_ready(ow, ms_timeout);
|
||||
if (res < 0) {
|
||||
if (res == -ENOTCONN) {
|
||||
c->is_connected = QB_FALSE;
|
||||
}
|
||||
return res;
|
||||
}
|
||||
}
|
||||
@ -285,6 +294,9 @@ qb_ipcc_event_recv(struct qb_ipcc_connection * c, void *msg_pt,
|
||||
if (c->needs_sock_for_poll) {
|
||||
res = qb_ipc_us_recv(&c->setup, &one_byte, 1, -1);
|
||||
if (res < 0) {
|
||||
if (res == -ENOTCONN) {
|
||||
c->is_connected = QB_FALSE;
|
||||
}
|
||||
return res;
|
||||
}
|
||||
}
|
||||
|
||||
@ -247,6 +247,24 @@ qb_rb_close(qb_ringbuffer_t * rb)
|
||||
free(rb);
|
||||
}
|
||||
|
||||
void
|
||||
qb_rb_force_close(qb_ringbuffer_t * rb)
|
||||
{
|
||||
if (rb == NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
(void)rb->sem_destroy_fn(rb);
|
||||
unlink(rb->shared_hdr->data_path);
|
||||
unlink(rb->shared_hdr->hdr_path);
|
||||
qb_util_log(LOG_DEBUG,
|
||||
"Force free'ing ringbuffer: %s",
|
||||
rb->shared_hdr->hdr_path);
|
||||
munmap(rb->shared_data, (rb->shared_hdr->size * sizeof(uint32_t)) << 1);
|
||||
munmap(rb->shared_hdr, sizeof(struct qb_ringbuffer_shared_s));
|
||||
free(rb);
|
||||
}
|
||||
|
||||
char *
|
||||
qb_rb_name_get(qb_ringbuffer_t * rb)
|
||||
{
|
||||
|
||||
@ -71,6 +71,9 @@ struct qb_ringbuffer_s {
|
||||
qb_rb_sem_destroy_fn_t sem_destroy_fn;
|
||||
};
|
||||
|
||||
|
||||
void qb_rb_force_close(qb_ringbuffer_t * rb);
|
||||
|
||||
#if defined(_SEM_SEMUN_UNDEFINED)
|
||||
union semun {
|
||||
int32_t val;
|
||||
|
||||
@ -262,10 +262,12 @@ repeat_send:
|
||||
qb_perror(LOG_DEBUG, "qb_ipcc_recv");
|
||||
return res;
|
||||
}
|
||||
ck_assert_int_eq(res, sizeof(struct qb_ipc_response_header));
|
||||
ck_assert_int_eq(res_header.id, IPC_MSG_RES_TX_RX);
|
||||
ck_assert_int_eq(res_header.size, sizeof(struct qb_ipc_response_header));
|
||||
return 0;
|
||||
if (expect_perfection) {
|
||||
ck_assert_int_eq(res, sizeof(struct qb_ipc_response_header));
|
||||
ck_assert_int_eq(res_header.id, IPC_MSG_RES_TX_RX);
|
||||
ck_assert_int_eq(res_header.size, sizeof(struct qb_ipc_response_header));
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
static int32_t recv_timeout = -1;
|
||||
@ -297,7 +299,7 @@ test_ipc_txrx(void)
|
||||
size *= 2;
|
||||
if (size >= MAX_MSG_SIZE)
|
||||
break;
|
||||
if (send_and_check(size, recv_timeout) < 0) {
|
||||
if (send_and_check(size, recv_timeout, QB_TRUE) < 0) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
@ -308,6 +310,54 @@ test_ipc_txrx(void)
|
||||
stop_process(pid);
|
||||
}
|
||||
|
||||
static void
|
||||
test_ipc_exit(void)
|
||||
{
|
||||
int32_t c = 0;
|
||||
int32_t j = 0;
|
||||
int32_t rc = 0;
|
||||
pid_t pid;
|
||||
|
||||
pid = run_function_in_new_process(run_ipc_server);
|
||||
fail_if(pid == -1);
|
||||
sleep(1);
|
||||
|
||||
do {
|
||||
conn = qb_ipcc_connect(ipc_name, MAX_MSG_SIZE);
|
||||
if (conn == NULL) {
|
||||
j = waitpid(pid, NULL, WNOHANG);
|
||||
ck_assert_int_eq(j, 0);
|
||||
sleep(1);
|
||||
c++;
|
||||
}
|
||||
} while (conn == NULL && c < 5);
|
||||
fail_if(conn == NULL);
|
||||
|
||||
/* confirm we can send one message */
|
||||
rc = send_and_check(100, recv_timeout, QB_TRUE);
|
||||
_ck_assert_int(rc, >=, 0);
|
||||
|
||||
/* kill the server */
|
||||
stop_process(pid);
|
||||
|
||||
/* assertion: we can call send/recv without locking up */
|
||||
rc = send_and_check(100, recv_timeout, QB_FALSE);
|
||||
ck_assert_int_eq(rc, -ENOTCONN);
|
||||
|
||||
/* this needs to free up the shared mem */
|
||||
qb_ipcc_disconnect(conn);
|
||||
}
|
||||
|
||||
|
||||
START_TEST(test_ipc_exit_shm)
|
||||
{
|
||||
ipc_type = QB_IPC_SHM;
|
||||
ipc_name = __func__;
|
||||
recv_timeout = 1000;
|
||||
test_ipc_exit();
|
||||
}
|
||||
END_TEST
|
||||
|
||||
START_TEST(test_ipc_txrx_shm_tmo)
|
||||
{
|
||||
turn_on_fc = QB_FALSE;
|
||||
@ -469,8 +519,6 @@ END_TEST
|
||||
|
||||
static void
|
||||
test_ipc_server_fail(void)
|
||||
#ifdef IPC_HANDLES_FAILED_SERVER
|
||||
|
||||
{
|
||||
struct qb_ipc_request_header req_header;
|
||||
struct qb_ipc_response_header res_header;
|
||||
@ -544,7 +592,6 @@ START_TEST(test_ipc_server_fail_shm)
|
||||
test_ipc_server_fail();
|
||||
}
|
||||
END_TEST
|
||||
#endif /* IPC_HANDLES_FAILED_SERVER */
|
||||
|
||||
static Suite *
|
||||
ipc_suite(void)
|
||||
@ -553,7 +600,6 @@ ipc_suite(void)
|
||||
uid_t uid;
|
||||
Suite *s = suite_create("ipc");
|
||||
|
||||
#ifdef IPC_HANDLES_FAILED_SERVER
|
||||
tc = tcase_create("ipc_server_fail_shm");
|
||||
tcase_add_test(tc, test_ipc_server_fail_shm);
|
||||
tcase_set_timeout(tc, 6);
|
||||
@ -563,7 +609,6 @@ ipc_suite(void)
|
||||
tcase_add_test(tc, test_ipc_server_fail_soc);
|
||||
tcase_set_timeout(tc, 6);
|
||||
suite_add_tcase(s, tc);
|
||||
#endif /* IPC_HANDLES_FAILED_SERVER */
|
||||
|
||||
tc = tcase_create("ipc_txrx_shm_block");
|
||||
tcase_add_test(tc, test_ipc_txrx_shm_block);
|
||||
@ -617,6 +662,11 @@ ipc_suite(void)
|
||||
tcase_set_timeout(tc, 16);
|
||||
suite_add_tcase(s, tc);
|
||||
|
||||
tc = tcase_create("ipc_exit_shm");
|
||||
tcase_add_test(tc, test_ipc_exit_shm);
|
||||
tcase_set_timeout(tc, 3);
|
||||
suite_add_tcase(s, tc);
|
||||
|
||||
return s;
|
||||
}
|
||||
|
||||
|
||||
Loading…
Reference in New Issue
Block a user