summaryrefslogtreecommitdiff
path: root/lib/frr_zmq.c
diff options
context:
space:
mode:
Diffstat (limited to 'lib/frr_zmq.c')
-rw-r--r--lib/frr_zmq.c39
1 files changed, 33 insertions, 6 deletions
diff --git a/lib/frr_zmq.c b/lib/frr_zmq.c
index ce52848a25..e572558de1 100644
--- a/lib/frr_zmq.c
+++ b/lib/frr_zmq.c
@@ -17,6 +17,14 @@
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
+/*
+ * IF YOU MODIFY THIS FILE PLEASE RUN `make check` and ensure that
+ * the test_zmq.c unit test is still working. There are dependencies
+ * between the two that are extremely fragile. My understanding
+ * is that there is specialized ownership of the cb pointer based
+ * upon what is happening. Those assumptions are supposed to be
+ * tested in the test_zmq.c
+ */
#include <zebra.h>
#include <zmq.h>
@@ -76,7 +84,10 @@ static int frrzmq_read_msg(struct thread *t)
break;
if (cb->read.cb_msg) {
+ cb->in_cb = true;
cb->read.cb_msg(cb->read.arg, cb->zmqsock);
+ cb->in_cb = false;
+
read = 1;
if (cb->read.cancelled) {
@@ -84,7 +95,8 @@ static int frrzmq_read_msg(struct thread *t)
ZMQ_POLLOUT);
cb->read.thread = NULL;
if (cb->write.cancelled && !cb->write.thread)
- XFREE(MTYPE_ZEROMQ_CB, cb);
+ XFREE(MTYPE_ZEROMQ_CB, *cbp);
+
return 0;
}
continue;
@@ -104,15 +116,19 @@ static int frrzmq_read_msg(struct thread *t)
}
read = 1;
+ cb->in_cb = true;
cb->read.cb_part(cb->read.arg, cb->zmqsock, &msg,
partno);
+ cb->in_cb = false;
+
if (cb->read.cancelled) {
zmq_msg_close(&msg);
frrzmq_check_events(cbp, &cb->write,
ZMQ_POLLOUT);
cb->read.thread = NULL;
if (cb->write.cancelled && !cb->write.thread)
- XFREE(MTYPE_ZEROMQ_CB, cb);
+ XFREE(MTYPE_ZEROMQ_CB, *cbp);
+
return 0;
}
@@ -175,7 +191,6 @@ int _frrzmq_thread_add_read(const struct xref_threadsched *xref,
cb = *cbp;
else {
cb = XCALLOC(MTYPE_ZEROMQ_CB, sizeof(struct frrzmq_cb));
-
cb->write.cancelled = true;
*cbp = cb;
}
@@ -187,6 +202,7 @@ int _frrzmq_thread_add_read(const struct xref_threadsched *xref,
cb->read.cb_part = partfunc;
cb->read.cb_error = errfunc;
cb->read.cancelled = false;
+ cb->in_cb = false;
if (events & ZMQ_POLLIN) {
thread_cancel(&cb->read.thread);
@@ -224,14 +240,18 @@ static int frrzmq_write_msg(struct thread *t)
break;
if (cb->write.cb_msg) {
+ cb->in_cb = true;
cb->write.cb_msg(cb->write.arg, cb->zmqsock);
+ cb->in_cb = false;
+
written = 1;
if (cb->write.cancelled) {
frrzmq_check_events(cbp, &cb->read, ZMQ_POLLIN);
cb->write.thread = NULL;
if (cb->read.cancelled && !cb->read.thread)
- XFREE(MTYPE_ZEROMQ_CB, cb);
+ XFREE(MTYPE_ZEROMQ_CB, *cbp);
+
return 0;
}
continue;
@@ -278,7 +298,6 @@ int _frrzmq_thread_add_write(const struct xref_threadsched *xref,
cb = *cbp;
else {
cb = XCALLOC(MTYPE_ZEROMQ_CB, sizeof(struct frrzmq_cb));
-
cb->read.cancelled = true;
*cbp = cb;
}
@@ -290,6 +309,7 @@ int _frrzmq_thread_add_write(const struct xref_threadsched *xref,
cb->write.cb_part = NULL;
cb->write.cb_error = errfunc;
cb->write.cancelled = false;
+ cb->in_cb = false;
if (events & ZMQ_POLLOUT) {
thread_cancel(&cb->write.thread);
@@ -309,8 +329,15 @@ void frrzmq_thread_cancel(struct frrzmq_cb **cb, struct cb_core *core)
core->cancelled = true;
thread_cancel(&core->thread);
+ /* If cancelled from within a callback, don't try to free memory
+ * in this path.
+ */
+ if ((*cb)->in_cb)
+ return;
+
+ /* Ok to free the callback context if no more ... context. */
if ((*cb)->read.cancelled && !(*cb)->read.thread
- && (*cb)->write.cancelled && !(*cb)->write.thread)
+ && (*cb)->write.cancelled && ((*cb)->write.thread == NULL))
XFREE(MTYPE_ZEROMQ_CB, *cb);
}