static int stream_close_finished(void *ctx, h2_stream *stream) { assert(ctx); h2_session *session = (h2_session *)ctx; h2_task *task = stream->task; if (!task || h2_task_has_finished(task)) { ap_log_cerror(APLOG_MARK, APLOG_TRACE1, 0, session->c, "h2_session(%ld): reaping zombie stream(%d)", session->id, stream->id); h2_stream_set_remove(session->zombies, stream); h2_stream_destroy(stream); } return 1; }
static apr_status_t join_zombie_stream(h2_session *session, h2_stream *stream) { apr_status_t status = APR_SUCCESS; ap_log_cerror(APLOG_MARK, APLOG_DEBUG, 0, session->c, "h2_stream(%ld-%d): join zombie", session->id, (int)stream->id); h2_stream_set_remove(session->zombies, stream); if (session->before_stream_close_cb && stream->task) { status = session->before_stream_close_cb(session, stream, stream->task, 1); } h2_stream_destroy(stream); return status; }
apr_status_t h2_session_stream_destroy(h2_session *session, h2_stream *stream) { apr_pool_t *pool = h2_stream_detach_pool(stream); h2_mplx_stream_done(session->mplx, stream->id, stream->rst_error); h2_stream_set_remove(session->streams, stream->id); h2_stream_destroy(stream); if (pool) { apr_pool_clear(pool); if (session->spare) { apr_pool_destroy(session->spare); } session->spare = pool; } return APR_SUCCESS; }
static apr_status_t stream_destroy(h2_session *session, h2_stream *stream, uint32_t error_code) { if (!error_code) { ap_log_cerror(APLOG_MARK, APLOG_DEBUG, 0, session->c, "h2_stream(%ld-%d): handled, closing", session->id, (int)stream->id); if (stream->id > session->max_stream_handled) { session->max_stream_handled = stream->id; } } else { ap_log_cerror(APLOG_MARK, APLOG_DEBUG, 0, session->c, "h2_stream(%ld-%d): closing with err=%d %s", session->id, (int)stream->id, (int)error_code, nghttp2_strerror(error_code)); } h2_stream_set_remove(session->streams, stream); return h2_mplx_cleanup_stream(session->mplx, stream); }
static apr_status_t close_active_stream(h2_session *session, h2_stream *stream, int join) { apr_status_t status = APR_SUCCESS; ap_log_cerror(APLOG_MARK, APLOG_DEBUG, 0, session->c, "h2_stream(%ld-%d): closing", session->id, (int)stream->id); h2_stream_set_remove(session->streams, stream); if (session->before_stream_close_cb && stream->task) { status = session->before_stream_close_cb(session, stream, stream->task, join); } if (status == APR_SUCCESS) { h2_mplx_close_io(session->mplx, stream->id); h2_stream_destroy(stream); } else if (status == APR_EAGAIN) { h2_stream_set_add(session->zombies, stream); } return status; }
void h2_mplx_task_done(h2_mplx *m, int stream_id) { apr_status_t status = apr_thread_mutex_lock(m->lock); if (APR_SUCCESS == status) { h2_stream *stream = h2_stream_set_get(m->closed, stream_id); h2_io *io = h2_io_set_get(m->stream_ios, stream_id); ap_log_cerror(APLOG_MARK, APLOG_TRACE2, 0, m->c, "h2_mplx(%ld): task(%d) done", m->id, stream_id); if (stream) { /* stream was already closed by main connection and is in * zombie state. Now that the task is done with it, we * can free its resources. */ h2_stream_set_remove(m->closed, stream); stream_destroy(m, stream, io); } else if (io) { /* main connection has not finished stream. Mark task as done * so that eventual cleanup can start immediately. */ io->task_done = 1; } apr_thread_mutex_unlock(m->lock); } }