MINOR: connection: track mux calls to report their allocation context

Most calls to mux ops were instrumented with a CALL_MUX_WITH_RET() or
CALL_MUX_NO_RET() macro in order to make the current thread's context
point to the called mux and be able to track its allocations. Only
a bunch of harmless mux_ctl() and ->subscribe/unsubscribe calls were
left untouched since useless. But destroy/detach/shut/init/snd_buf
and rcv_buf are now tracked.

It will not show allocations performed in IO callback via tasklet
wakeups however.

In order to ease reading of the output, cmp_memprof_ctx() knows about
muxes and sorts based on the .subscribe function address instead of
the mux_ops address so as to keep various callers grouped.
This commit is contained in:
Willy Tarreau 2026-03-11 10:28:25 +01:00
parent e8e4449985
commit ec7b07b650
21 changed files with 76 additions and 52 deletions

View File

@ -49,6 +49,13 @@ extern struct mux_stopping_data mux_stopping_data[MAX_THREADS];
#define IS_HTX_CONN(conn) ((conn)->mux && ((conn)->mux->flags & MX_FL_HTX))
/* macros to switch the calling context to the mux during a call. There's one
* with a return value for most calls, and one without for the few like shut(),
* detach() or destroy() with no return.
*/
#define CALL_MUX_WITH_RET(mux, func) EXEC_CTX_WITH_RET(EXEC_CTX_MAKE(TH_EX_CTX_MUX, (mux)), (mux)->func)
#define CALL_MUX_NO_RET(mux, func) EXEC_CTX_NO_RET(EXEC_CTX_MAKE(TH_EX_CTX_MUX, (mux)), (mux)->func)
/* receive a PROXY protocol header over a connection */
int conn_recv_proxy(struct connection *conn, int flag);
int conn_send_proxy(struct connection *conn, unsigned int flag);
@ -480,7 +487,7 @@ static inline int conn_install_mux(struct connection *conn, const struct mux_ops
conn->mux = mux;
conn->ctx = ctx;
ret = mux->init ? mux->init(conn, prx, sess, &BUF_NULL) : 0;
ret = mux->init ? CALL_MUX_WITH_RET(mux, init(conn, prx, sess, &BUF_NULL)) : 0;
if (ret < 0) {
conn->mux = NULL;
conn->ctx = NULL;

View File

@ -452,7 +452,7 @@ static inline size_t se_nego_ff(struct sedesc *se, struct buffer *input, size_t
goto end;
}
ret = mux->nego_fastfwd(se->sc, input, count, flags);
ret = CALL_MUX_WITH_RET(mux, nego_fastfwd(se->sc, input, count, flags));
if (se->iobuf.flags & IOBUF_FL_FF_BLOCKED) {
sc_ep_report_blocked_send(se->sc, 0);
@ -485,7 +485,7 @@ static inline size_t se_done_ff(struct sedesc *se)
size_t to_send = se_ff_data(se);
BUG_ON(!mux->done_fastfwd);
ret = mux->done_fastfwd(se->sc);
ret = CALL_MUX_WITH_RET(mux, done_fastfwd(se->sc));
if (ret) {
/* Something was forwarded, unblock the zero-copy forwarding.
* If all data was sent, report and send activity.

View File

@ -86,6 +86,7 @@ enum thread_exec_ctx_type {
TH_EX_CTX_FUNC, /* hopefully recognizable function/callback, using .pointer */
TH_EX_CTX_ACTION, /* directly registered action function, using .action_kwl */
TH_EX_CTX_FLT, /* filter whose config is in .flt_conf */
TH_EX_CTX_MUX, /* mux whose mux_ops is in .mux_ops */
};
struct thread_exec_ctx {
@ -99,6 +100,7 @@ struct thread_exec_ctx {
const struct sample_conv_kw_list *conv_kwl; /* used with TH_EX_CTX_CONV */
const struct action_kw_list *action_kwl; /* used with TH_EX_CTX_ACTION */
const struct flt_conf *flt_conf; /* used with TH_EX_CTX_FLTCONF */
const struct mux_ops *mux_ops; /* used with TH_EX_CTX_MUX */
};
};

View File

@ -964,10 +964,22 @@ static int cmp_memprof_ctx(const void *a, const void *b)
{
const struct memprof_stats *l = (const struct memprof_stats *)a;
const struct memprof_stats *r = (const struct memprof_stats *)b;
const void *ptrl = l->exec_ctx.pointer;
const void *ptrr = r->exec_ctx.pointer;
if (l->exec_ctx.pointer > r->exec_ctx.pointer)
/* in case of a mux, we'll use the always-present ->subscribe()
* function as a sorting key so that mux-ops and other mux functions
* appear grouped together.
*/
if (l->exec_ctx.type == TH_EX_CTX_MUX)
ptrl = l->exec_ctx.mux_ops->subscribe;
if (r->exec_ctx.type == TH_EX_CTX_MUX)
ptrr = r->exec_ctx.mux_ops->subscribe;
if (ptrl > ptrr)
return -1;
else if (l->exec_ctx.pointer < r->exec_ctx.pointer)
else if (ptrl < ptrr)
return 1;
else if (l->exec_ctx.type > r->exec_ctx.type)
return -1;

View File

@ -1396,7 +1396,7 @@ check_tgid:
tree = search_tree ? &srv->per_thr[i].safe_conns : &srv->per_thr[i].idle_conns;
conn = srv_lookup_conn(tree, hash);
while (conn) {
if (conn->mux->takeover && conn->mux->takeover(conn, i, 0) == 0) {
if (conn->mux->takeover && CALL_MUX_WITH_RET(conn->mux, takeover(conn, i, 0)) == 0) {
conn_delete_from_tree(conn, i);
_HA_ATOMIC_INC(&activity[tid].fd_takeover);
found = 1;
@ -1498,7 +1498,7 @@ takeover_random_idle_conn(struct ceb_root **root, int curtid)
conn = ceb64_item_first(root, hash_node.node, hash_node.key, struct connection);
while (conn) {
if (conn->mux->takeover && conn->mux->takeover(conn, curtid, 1) == 0) {
if (conn->mux->takeover && CALL_MUX_WITH_RET(conn->mux, takeover(conn, curtid, 1)) == 0) {
conn_delete_from_tree(conn, curtid);
return conn;
}
@ -1555,7 +1555,7 @@ kill_random_idle_conn(struct server *srv)
*/
_HA_ATOMIC_INC(&srv->curr_used_conns);
}
conn->mux->destroy(conn->ctx);
CALL_MUX_NO_RET(conn->mux, destroy(conn->ctx));
return 1;
}
return 0;
@ -1765,7 +1765,7 @@ int be_reuse_connection(int64_t hash, struct session *sess,
}
if (avail >= 1) {
if (srv_conn->mux->attach(srv_conn, sc->sedesc, sess) == -1) {
if (CALL_MUX_WITH_RET(srv_conn->mux, attach(srv_conn, sc->sedesc, sess)) == -1) {
if (sc_reset_endp(sc) < 0)
goto err;
sc_ep_clr(sc, ~SE_FL_DETACHED);
@ -1879,7 +1879,7 @@ int connect_server(struct stream *s)
* It will in turn call srv_release_conn through
* conn_free which also uses it.
*/
tokill_conn->mux->destroy(tokill_conn->ctx);
CALL_MUX_NO_RET(tokill_conn->mux, destroy(tokill_conn->ctx));
}
else {
HA_SPIN_UNLOCK(IDLE_CONNS_LOCK, &idle_conns[tid].idle_conns_lock);

View File

@ -232,14 +232,14 @@ int conn_notify_mux(struct connection *conn, int old_flags, int forced_wake)
HA_SPIN_UNLOCK(IDLE_CONNS_LOCK, &idle_conns[tid].idle_conns_lock);
}
ret = conn->mux->wake(conn);
ret = CALL_MUX_WITH_RET(conn->mux, wake(conn));
if (ret < 0)
goto done;
if (conn_in_list) {
if (srv && (srv->cur_admin & SRV_ADMF_MAINT)) {
/* Do not store an idle conn if server in maintenance. */
conn->mux->destroy(conn->ctx);
CALL_MUX_NO_RET(conn->mux, destroy(conn->ctx));
ret = -1;
goto done;
}
@ -247,7 +247,7 @@ int conn_notify_mux(struct connection *conn, int old_flags, int forced_wake)
if (conn->flags & CO_FL_SESS_IDLE) {
if (!session_reinsert_idle_conn(conn->owner, conn)) {
/* session add conn failure */
conn->mux->destroy(conn->ctx);
CALL_MUX_NO_RET(conn->mux, destroy(conn->ctx));
ret = -1;
}
}
@ -291,7 +291,7 @@ int conn_upgrade_mux_fe(struct connection *conn, void *ctx, struct buffer *buf,
old_mux_ctx = conn->ctx;
conn->mux = new_mux;
conn->ctx = ctx;
if (new_mux->init(conn, bind_conf->frontend, conn->owner, buf) == -1) {
if (CALL_MUX_WITH_RET(new_mux, init(conn, bind_conf->frontend, conn->owner, buf)) == -1) {
/* The mux upgrade failed, so restore the old mux */
conn->ctx = old_mux_ctx;
conn->mux = old_mux;
@ -300,7 +300,7 @@ int conn_upgrade_mux_fe(struct connection *conn, void *ctx, struct buffer *buf,
/* The mux was upgraded, destroy the old one */
*buf = BUF_NULL;
old_mux->destroy(old_mux_ctx);
CALL_MUX_NO_RET(old_mux, destroy(old_mux_ctx));
return 0;
}
@ -658,7 +658,7 @@ void conn_free(struct connection *conn)
void conn_release(struct connection *conn)
{
if (conn->mux) {
conn->mux->destroy(conn->ctx);
CALL_MUX_NO_RET(conn->mux, destroy(conn->ctx));
}
else {
conn_stop_tracking(conn);
@ -3034,7 +3034,7 @@ static struct task *mux_stopping_process(struct task *t, void *ctx, unsigned int
list_for_each_entry_safe(conn, back, &mux_stopping_data[tid].list, stopping_list) {
if (conn->mux && conn->mux->wake)
conn->mux->wake(conn);
CALL_MUX_NO_RET(conn->mux, wake(conn));
}
return t;

View File

@ -250,7 +250,7 @@ static int hstream_htx_buf_rcv(struct connection *conn, struct hstream *hs)
htx_reset(htxbuf(&hs->req));
max = (IS_HTX_SC(hs->sc) ? htx_free_space(htxbuf(&hs->req)) : b_room(&hs->req));
sc_ep_clr(hs->sc, SE_FL_WANT_ROOM);
read = conn->mux->rcv_buf(hs->sc, &hs->req, max, 0);
read = CALL_MUX_WITH_RET(conn->mux, rcv_buf(hs->sc, &hs->req, max, 0));
cur_read += read;
if (!htx_expect_more(htxbuf(&hs->req))) {
fin = 1;
@ -313,7 +313,7 @@ static int hstream_htx_buf_snd(struct connection *conn, struct hstream *hs)
goto out;
}
nret = conn->mux->snd_buf(hs->sc, &hs->res, htxbuf(&hs->res)->data, 0);
nret = CALL_MUX_WITH_RET(conn->mux, snd_buf(hs->sc, &hs->res, htxbuf(&hs->res)->data, 0));
if (nret <= 0) {
if (hs->flags & HS_ST_CONN_ERROR ||
conn->flags & CO_FL_ERROR || sc_ep_test(sc, SE_FL_ERROR)) {
@ -873,7 +873,7 @@ static struct task *process_hstream(struct task *t, void *context, unsigned int
out:
if (!hs->to_write && !hs->req_body && htx_is_empty(htxbuf(&hs->res))) {
TRACE_DEVEL("shutting down stream", HS_EV_HSTRM_SEND, hs);
conn->mux->shut(hs->sc, SE_SHW_SILENT|SE_SHW_NORMAL, NULL);
CALL_MUX_NO_RET(conn->mux, shut(hs->sc, SE_SHW_SILENT|SE_SHW_NORMAL, NULL));
}
if (hs->flags & HS_ST_CONN_ERROR ||

View File

@ -3736,7 +3736,7 @@ static void fcgi_detach(struct sedesc *sd)
if (eb_is_empty(&fconn->streams_by_id)) {
if (!fconn->conn->owner) {
/* Session insertion above has failed and connection is idle, remove it. */
fconn->conn->mux->destroy(fconn);
CALL_MUX_NO_RET(fconn->conn->mux, destroy(fconn));
TRACE_DEVEL("outgoing connection killed", FCGI_EV_STRM_END|FCGI_EV_FCONN_ERR);
return;
}
@ -3749,7 +3749,7 @@ static void fcgi_detach(struct sedesc *sd)
/* Ensure session can keep a new idle connection. */
if (session_check_idle_conn(sess, fconn->conn) != 0) {
fconn->conn->mux->destroy(fconn);
CALL_MUX_NO_RET(fconn->conn->mux, destroy(fconn));
TRACE_DEVEL("outgoing connection killed", FCGI_EV_STRM_END|FCGI_EV_FCONN_ERR);
return;
}
@ -3780,7 +3780,7 @@ static void fcgi_detach(struct sedesc *sd)
if (!srv_add_to_idle_list(objt_server(fconn->conn->target), fconn->conn, 1)) {
/* The server doesn't want it, let's kill the connection right away */
fconn->conn->mux->destroy(fconn);
CALL_MUX_NO_RET(fconn->conn->mux, destroy(fconn));
TRACE_DEVEL("outgoing connection killed", FCGI_EV_STRM_END|FCGI_EV_FCONN_ERR);
return;
}

View File

@ -1197,7 +1197,7 @@ static int h1s_finish_detach(struct h1s *h1s)
if (!session_add_conn(sess, h1c->conn)) {
/* HTTP/1.1 conn is always idle after detach, can be removed if session insert failed. */
h1c->conn->owner = NULL;
h1c->conn->mux->destroy(h1c);
CALL_MUX_NO_RET(h1c->conn->mux, destroy(h1c));
goto released;
}
@ -1213,7 +1213,7 @@ static int h1s_finish_detach(struct h1s *h1s)
/* Ensure session can keep a new idle connection. */
if (session_check_idle_conn(sess, h1c->conn)) {
TRACE_DEVEL("outgoing connection rejected", H1_EV_STRM_END|H1_EV_H1C_END, h1c->conn);
h1c->conn->mux->destroy(h1c);
CALL_MUX_NO_RET(h1c->conn->mux, destroy(h1c));
goto released;
}
@ -1236,7 +1236,7 @@ static int h1s_finish_detach(struct h1s *h1s)
if (!srv_add_to_idle_list(objt_server(h1c->conn->target), h1c->conn, is_not_first)) {
/* The server doesn't want it, let's kill the connection right away */
h1c->conn->mux->destroy(h1c);
CALL_MUX_NO_RET(h1c->conn->mux, destroy(h1c));
TRACE_DEVEL("outgoing connection killed", H1_EV_STRM_END|H1_EV_H1C_END);
goto released;
}

View File

@ -5672,7 +5672,7 @@ static void h2_detach(struct sedesc *sd)
if (eb_is_empty(&h2c->streams_by_id)) {
if (!h2c->conn->owner) {
/* Session insertion above has failed and connection is idle, remove it. */
h2c->conn->mux->destroy(h2c);
CALL_MUX_NO_RET(h2c->conn->mux, destroy(h2c));
TRACE_DEVEL("leaving on error after killing outgoing connection", H2_EV_STRM_END|H2_EV_H2C_ERR);
return;
}
@ -5685,7 +5685,7 @@ static void h2_detach(struct sedesc *sd)
/* Ensure session can keep a new idle connection. */
if (session_check_idle_conn(sess, h2c->conn) != 0) {
h2c->conn->mux->destroy(h2c);
CALL_MUX_NO_RET(h2c->conn->mux, destroy(h2c));
TRACE_DEVEL("leaving without reusable idle connection", H2_EV_STRM_END);
return;
}
@ -5716,7 +5716,7 @@ static void h2_detach(struct sedesc *sd)
if (!srv_add_to_idle_list(objt_server(h2c->conn->target), h2c->conn, 1)) {
/* The server doesn't want it, let's kill the connection right away */
h2c->conn->mux->destroy(h2c);
CALL_MUX_NO_RET(h2c->conn->mux, destroy(h2c));
TRACE_DEVEL("leaving on error after killing outgoing connection", H2_EV_STRM_END|H2_EV_H2C_ERR);
return;
}

View File

@ -3013,7 +3013,7 @@ static void spop_detach(struct sedesc *sd)
if (eb_is_empty(&spop_conn->streams_by_id)) {
if (!spop_conn->conn->owner) {
/* Session insertion above has failed and connection is idle, remove it. */
spop_conn->conn->mux->destroy(spop_conn);
CALL_MUX_NO_RET(spop_conn->conn->mux, destroy(spop_conn));
TRACE_DEVEL("leaving on error after killing outgoing connection", SPOP_EV_STRM_END|SPOP_EV_SPOP_CONN_ERR);
return;
}
@ -3026,7 +3026,7 @@ static void spop_detach(struct sedesc *sd)
/* Ensure session can keep a new idle connection. */
if (session_check_idle_conn(sess, spop_conn->conn) != 0) {
spop_conn->conn->mux->destroy(spop_conn);
CALL_MUX_NO_RET(spop_conn->conn->mux, destroy(spop_conn));
TRACE_DEVEL("leaving without reusable idle connection", SPOP_EV_STRM_END);
return;
}
@ -3057,7 +3057,7 @@ static void spop_detach(struct sedesc *sd)
if (!srv_add_to_idle_list(objt_server(spop_conn->conn->target), spop_conn->conn, 1)) {
/* The server doesn't want it, let's kill the connection right away */
spop_conn->conn->mux->destroy(spop_conn);
CALL_MUX_NO_RET(spop_conn->conn->mux, destroy(spop_conn));
TRACE_DEVEL("leaving on error after killing outgoing connection", SPOP_EV_STRM_END|SPOP_EV_SPOP_CONN_ERR);
return;
}

View File

@ -241,7 +241,7 @@ struct task *rhttp_process(struct task *task, void *ctx, unsigned int state)
* directly.
*/
if (conn->mux && conn->mux->destroy) {
conn->mux->destroy(conn->ctx);
CALL_MUX_NO_RET(conn->mux, destroy(conn->ctx));
}
else {
conn_stop_tracking(conn);
@ -464,7 +464,7 @@ struct connection *rhttp_accept_conn(struct listener *l, int *status)
BUG_ON(!(conn->flags & CO_FL_ACT_REVERSING));
conn->flags &= ~CO_FL_ACT_REVERSING;
conn->flags |= CO_FL_REVERSED;
conn->mux->ctl(conn, MUX_CTL_REVERSE_CONN, NULL);
CALL_MUX_NO_RET(conn->mux, ctl(conn, MUX_CTL_REVERSE_CONN, NULL));
l->rx.rhttp.pend_conn = NULL;
*status = CO_AC_NONE;

View File

@ -1105,7 +1105,7 @@ static int qc_parse_pkt_frms(struct quic_conn *qc, struct quic_rx_packet *pkt,
if (objt_server(qc->conn->target) && !qc->conn->mux) {
/* This has as side effect to close the connection stream */
if (conn_create_mux(qc->conn, NULL) >= 0)
qc->conn->mux->wake(qc->conn);
CALL_MUX_NO_RET(qc->conn->mux, wake(qc->conn));
}
}
__fallthrough;

View File

@ -180,7 +180,7 @@ static int ha_quic_send_alert(SSL *ssl, enum ssl_encryption_level_t level, uint8
if (objt_server(qc->conn->target) && !qc->conn->mux) {
/* This has as side effect to close the connection stream */
if (conn_create_mux(qc->conn, NULL) >= 0)
qc->conn->mux->wake(qc->conn);
CALL_MUX_NO_RET(qc->conn->mux, wake(qc->conn));
}
}
@ -1029,7 +1029,7 @@ int qc_ssl_do_hanshake(struct quic_conn *qc, struct ssl_sock_ctx *ctx)
}
/* Wake up MUX after its creation. Operation similar to TLS+ALPN on TCP stack. */
qc->conn->mux->wake(qc->conn);
CALL_MUX_NO_RET(qc->conn->mux, wake(qc->conn));
}
else {
/* Wake up upper layer if the MUX is already initialized.

View File

@ -7247,7 +7247,7 @@ struct task *srv_cleanup_toremove_conns(struct task *task, void *context, unsign
while ((conn = MT_LIST_POP(&idle_conns[tid].toremove_conns,
struct connection *, toremove_list)) != NULL) {
conn->mux->destroy(conn->ctx);
CALL_MUX_NO_RET(conn->mux, destroy(conn->ctx));
}
return task;

View File

@ -138,7 +138,7 @@ void session_free(struct session *sess)
vars_prune_per_sess(&sess->vars);
conn = objt_conn(sess->origin);
if (conn != NULL && conn->mux)
conn->mux->destroy(conn->ctx);
CALL_MUX_NO_RET(conn->mux, destroy(conn->ctx));
HA_SPIN_LOCK(IDLE_CONNS_LOCK, &idle_conns[tid].idle_conns_lock);
list_for_each_entry_safe(pconns, pconns_back, &sess->priv_conns, sess_el) {

View File

@ -6960,7 +6960,7 @@ struct task *ssl_sock_io_cb(struct task *t, void *context, unsigned int state)
if (!ctx->conn->mux)
ret = conn_create_mux(ctx->conn, &closed_connection);
if (ret >= 0 && !woke && ctx->conn->mux && ctx->conn->mux->wake) {
ret = ctx->conn->mux->wake(ctx->conn);
ret = CALL_MUX_WITH_RET(ctx->conn->mux, wake(ctx->conn));
if (ret < 0)
closed_connection = 1;
}
@ -6991,7 +6991,7 @@ leave:
TRACE_DEVEL("adding conn back to session list", SSL_EV_CONN_IO_CB, conn);
if (!session_reinsert_idle_conn(conn->owner, conn)) {
/* session add conn failure */
conn->mux->destroy(conn->ctx);
CALL_MUX_NO_RET(conn->mux, destroy(conn->ctx));
t = NULL;
}
}
@ -7003,7 +7003,7 @@ leave:
}
else {
/* Do not store an idle conn if server in maintenance. */
conn->mux->destroy(conn->ctx);
CALL_MUX_NO_RET(conn->mux, destroy(conn->ctx));
t = NULL;
}
}

View File

@ -106,7 +106,7 @@ void se_shutdown(struct sedesc *sedesc, enum se_shut_mode mode)
sdo = se_opposite(sedesc);
if (sdo)
reason = &sdo->abort_info;
mux->shut(sedesc->sc, mode, reason);
CALL_MUX_NO_RET(mux, shut(sedesc->sc, mode, reason));
}
se_fl_set(sedesc, flags);
}
@ -393,7 +393,7 @@ static void sc_detach_endp(struct stconn **scp)
se_fl_set(sedesc, SE_FL_ORPHAN);
sedesc->sc = NULL;
sc->sedesc = NULL;
conn->mux->detach(sedesc);
CALL_MUX_NO_RET(conn->mux, detach(sedesc));
}
else {
/* It's too early to have a mux, let's just destroy
@ -1118,7 +1118,7 @@ int sc_conn_recv(struct stconn *sc)
goto abort_fastfwd;
}
sc_ep_fwd_kip(sc, sc_opposite(sc));
ret = conn->mux->fastfwd(sc, ic->to_forward, flags);
ret = CALL_MUX_WITH_RET(conn->mux, fastfwd(sc, ic->to_forward, flags));
if (ret < 0)
goto abort_fastfwd;
else if (ret > 0) {
@ -1189,7 +1189,7 @@ int sc_conn_recv(struct stconn *sc)
* SE_FL_RCV_MORE on the SC if more space is needed.
*/
max = channel_recv_max(ic);
ret = conn->mux->rcv_buf(sc, &ic->buf, max, cur_flags);
ret = CALL_MUX_WITH_RET(conn->mux, rcv_buf(sc, &ic->buf, max, cur_flags));
if (sc_ep_test(sc, SE_FL_WANT_ROOM)) {
/* SE_FL_WANT_ROOM must not be reported if the channel's
@ -1437,7 +1437,7 @@ int sc_conn_send(struct stconn *sc)
if (oc->flags & CF_STREAMER)
send_flag |= CO_SFL_STREAMER;
ret = conn->mux->resume_fastfwd(sc, send_flag);
ret = CALL_MUX_WITH_RET(conn->mux, resume_fastfwd(sc, send_flag));
if (ret > 0) {
sc->bytes_out += ret;
did_send = 1;
@ -1509,7 +1509,7 @@ int sc_conn_send(struct stconn *sc)
if ((sc->flags & SC_FL_SHUT_WANTED) && co_data(oc) == c_data(oc))
send_flag |= CO_SFL_LAST_DATA;
ret = conn->mux->snd_buf(sc, &oc->buf, co_data(oc), send_flag);
ret = CALL_MUX_WITH_RET(conn->mux, snd_buf(sc, &oc->buf, co_data(oc), send_flag));
if (ret > 0) {
did_send = 1;
c_rew(oc, ret);

View File

@ -1810,8 +1810,8 @@ enum tcpcheck_eval_ret tcpcheck_eval_send(struct check *check, struct tcpcheck_r
do_send:
TRACE_DATA("send data", CHK_EV_TCPCHK_SND|CHK_EV_TX_DATA, check);
if (conn->mux->snd_buf(sc, &check->bo,
(IS_HTX_CONN(conn) ? (htxbuf(&check->bo))->data: b_data(&check->bo)), 0) <= 0) {
if (CALL_MUX_WITH_RET(conn->mux, snd_buf(sc, &check->bo,
(IS_HTX_CONN(conn) ? (htxbuf(&check->bo))->data: b_data(&check->bo)), 0)) <= 0) {
if ((conn->flags & CO_FL_ERROR) || sc_ep_test(sc, SE_FL_ERROR)) {
ret = TCPCHK_EVAL_STOP;
TRACE_DEVEL("connection error during send", CHK_EV_TCPCHK_SND|CHK_EV_TX_DATA|CHK_EV_TX_ERR, check);
@ -1898,7 +1898,7 @@ enum tcpcheck_eval_ret tcpcheck_eval_recv(struct check *check, struct tcpcheck_r
while (sc_ep_test(sc, SE_FL_RCV_MORE) ||
(!(conn->flags & CO_FL_ERROR) && !sc_ep_test(sc, SE_FL_ERROR | SE_FL_EOS))) {
max = (IS_HTX_SC(sc) ? htx_free_space(htxbuf(&check->bi)) : b_room(&check->bi));
read = conn->mux->rcv_buf(sc, &check->bi, max, 0);
read = CALL_MUX_WITH_RET(conn->mux, rcv_buf(sc, &check->bi, max, 0));
cur_read += read;
if (!read ||
sc_ep_test(sc, SE_FL_WANT_ROOM) ||

View File

@ -7545,6 +7545,9 @@ void chunk_append_thread_ctx(struct buffer *output, const struct thread_exec_ctx
case TH_EX_CTX_FLT:
chunk_appendf(output,"flt '%s'", ctx->flt_conf->id);
break;
case TH_EX_CTX_MUX:
chunk_appendf(output,"mux '%s'", ctx->mux_ops->name);
break;
default:
chunk_appendf(output,"other ctx %p", ctx->pointer);
break;

View File

@ -117,7 +117,7 @@ out:
if (!ctx->conn->mux)
ret = conn_create_mux(ctx->conn, NULL);
if (ret >= 0 && !woke && ctx->conn->mux && ctx->conn->mux->wake)
ret = ctx->conn->mux->wake(ctx->conn);
ret = CALL_MUX_WITH_RET(ctx->conn->mux, wake(ctx->conn));
}
tasklet_free(ctx->wait_event.tasklet);
pool_free(xprt_handshake_ctx_pool, ctx);