diff --git a/include/maxscale/dcb.h b/include/maxscale/dcb.h index 84eb7e0eb..4b9486acc 100644 --- a/include/maxscale/dcb.h +++ b/include/maxscale/dcb.h @@ -222,6 +222,16 @@ int dcb_read(DCB *, GWBUF **, int); int dcb_drain_writeq(DCB *); void dcb_close(DCB *); +/** + * @brief Close DCB in the thread that owns it. + * + * @param dcb The dcb to be closed. + * + * @note Even if the calling thread owns the dcb, the closing will + * still be made via the event loop. + */ +void dcb_close_in_owning_thread(DCB *dcb); + /** * Add a DCB to the owner's list * diff --git a/server/core/dcb.cc b/server/core/dcb.cc index 58010ad5b..7f2f3c78e 100644 --- a/server/core/dcb.cc +++ b/server/core/dcb.cc @@ -1106,6 +1106,34 @@ void dcb_close(DCB *dcb) } } +static void cb_dcb_close_in_owning_thread(int worker_id, void* data) +{ + DCB* dcb = static_cast(data); + ss_dassert(dcb); + + dcb_close(dcb); +} + +void dcb_close_in_owning_thread(DCB* dcb) +{ + // TODO: If someone now calls dcb_close(dcb) from the owning thread while + // TODO: the dcb is being delivered to the owning thread, there will be a + // TODO: crash when dcb_close(dcb) is called anew. Also dcbs should be + // TODO: reference counted, so that we could addref before posting, thus + // TODO: preventing too early a deletion. + + MXS_WORKER* worker = mxs_worker_get(dcb->poll.thread.id); // The owning worker + ss_dassert(worker); + + intptr_t arg1 = (intptr_t)cb_dcb_close_in_owning_thread; + intptr_t arg2 = (intptr_t)dcb; + + if (!mxs_worker_post_message(worker, MXS_WORKER_MSG_CALL, arg1, arg2)) + { + MXS_ERROR("Could not post dcb for closing to the owning thread.."); + } +} + static void dcb_final_close(DCB* dcb) { #if defined(SS_DEBUG)