objdb_notify_dispatch traverse thru confdb_ipc_message_holder_list list until it's empty. If IPC connection is still feeding confdb/objdb with changes then iteration will never end. To prevent this and let corosync properly preempt, terminal condition is enhanced with maximum number of processed items from list. Change makes confdb preemptable so corosync can accept new connections, receive/send token, ... Signed-off-by: Jan Friesse <jfriesse@xxxxxxxxxx> --- services/confdb.c | 68 ++++++++++++++++++++++++++++++++++++++-------------- 1 files changed, 49 insertions(+), 19 deletions(-) diff --git a/services/confdb.c b/services/confdb.c index acedb96..25f9706 100644 --- a/services/confdb.c +++ b/services/confdb.c @@ -1003,12 +1003,44 @@ static void message_handler_req_lib_confdb_reload (void *conn, api->ipc_response_send(conn, &res_lib_confdb_reload, sizeof(res_lib_confdb_reload)); } +/* + * Write byte to notify_pipe, what makes objdb_notify_dispatch trigger. + * Return -1 on failure otherwise 0. + */ +static int write_to_notify_pipe(void) +{ + char pipe_cmd; + ssize_t written; + + pipe_cmd = 'M'; /* Message */ +retry_write: + written = write(notify_pipe[1], &pipe_cmd, sizeof(pipe_cmd)); + + if (written == -1) { + if (errno == EINTR) { + goto retry_write; + } + + if (errno != EAGAIN && errno != EWOULDBLOCK) { + /* + * Different error then EINTR or BLOCK -> exit with error + */ + return (-1); + } + } else if (written != sizeof (pipe_cmd)) { + return (-1); + } + + return (0); +} + static int objdb_notify_dispatch(hdb_handle_t handle, int fd, int revents, void *data) { struct confdb_ipc_message_holder *holder; ssize_t rc; char pipe_cmd; + int counter; if (revents & POLLHUP) { return -1; @@ -1034,7 +1066,14 @@ retry_read: goto unlock_exit; /* rc != -1 && rc != 1 -> end of file */ } - while (!list_empty (&confdb_ipc_message_holder_list_head)) { + /* + * To ensure we will not spent too much time in this function, counter is added + * and terminate condition for while cycle is not only empty_list but also number + * of processed items. + */ + counter = 0; + + while (!list_empty (&confdb_ipc_message_holder_list_head) && counter++ < 256) { holder = list_entry (confdb_ipc_message_holder_list_head.next, struct confdb_ipc_message_holder, list); @@ -1058,6 +1097,13 @@ retry_read: pthread_mutex_lock (&confdb_ipc_message_holder_list_mutex); } + if (!list_empty (&confdb_ipc_message_holder_list_head)) { + /* + * Ensure to call this function again. We have no way how + * to handle error so it's ignored. + */ + (void)write_to_notify_pipe(); + } unlock_exit: pthread_mutex_unlock (&confdb_ipc_message_holder_list_mutex); @@ -1067,9 +1113,7 @@ unlock_exit: static int32_t ipc_dispatch_send_from_poll_thread(void *conn, const void *msg, size_t mlen) { struct confdb_ipc_message_holder *holder; - ssize_t written; size_t holder_size; - char pipe_cmd; api->ipc_refcnt_inc(conn); @@ -1090,24 +1134,10 @@ static int32_t ipc_dispatch_send_from_poll_thread(void *conn, const void *msg, s list_add_tail (&holder->list, &confdb_ipc_message_holder_list_head); - pipe_cmd = 'M'; /* Message */ -retry_write: - written = write(notify_pipe[1], &pipe_cmd, sizeof(pipe_cmd)); - - if (written == -1) { - if (errno == EINTR) { - goto retry_write; - } - - if (errno != EAGAIN && errno != EWOULDBLOCK) { - /* - * Different error then EINTR or BLOCK -> exit with error - */ - goto refcnt_del_unlock_exit; - } - } else if (written != sizeof (pipe_cmd)) { + if (write_to_notify_pipe() == -1) { goto refcnt_del_unlock_exit; } + pthread_mutex_unlock (&confdb_ipc_message_holder_list_mutex); return 0; -- 1.7.1 _______________________________________________ discuss mailing list discuss@xxxxxxxxxxxx http://lists.corosync.org/mailman/listinfo/discuss