static int mpm_state = AP_MPMQ_STARTING;
static apr_thread_mutex_t *timeout_mutex;
-APR_RING_HEAD(timeout_head_t, conn_state_t);
+
+struct event_conn_state_t {
+ /** APR_RING of expiration timeouts */
+ APR_RING_ENTRY(event_conn_state_t) timeout_list;
+ /** the expiration time of the next keepalive timeout */
+ apr_time_t expiration_time;
+ /** connection record this struct refers to */
+ conn_rec *c;
+ /** memory pool to allocate from */
+ apr_pool_t *p;
+ /** bucket allocator */
+ apr_bucket_alloc_t *bucket_alloc;
+ /** poll file descriptor information */
+ apr_pollfd_t pfd;
+ /** public parts of the connection state */
+ conn_state_t pub;
+};
+APR_RING_HEAD(timeout_head_t, event_conn_state_t);
+
struct timeout_queue {
struct timeout_head_t head;
int count;
* Macros for accessing struct timeout_queue.
* For TO_QUEUE_APPEND and TO_QUEUE_REMOVE, timeout_mutex must be held.
*/
-#define TO_QUEUE_APPEND(q, el) \
- do { \
- APR_RING_INSERT_TAIL(&(q).head, el, conn_state_t, timeout_list); \
- (q).count++; \
+#define TO_QUEUE_APPEND(q, el) \
+ do { \
+ APR_RING_INSERT_TAIL(&(q).head, el, event_conn_state_t, timeout_list); \
+ (q).count++; \
} while (0)
#define TO_QUEUE_REMOVE(q, el) \
(q).count--; \
} while (0)
-#define TO_QUEUE_INIT(q) \
- do { \
- APR_RING_INIT(&(q).head, conn_state_t, timeout_list); \
- (q).tag = #q; \
+#define TO_QUEUE_INIT(q) \
+ do { \
+ APR_RING_INIT(&(q).head, event_conn_state_t, timeout_list); \
+ (q).tag = #q; \
} while (0)
#define TO_QUEUE_ELEM_INIT(el) APR_RING_ELEM_INIT(el, timeout_list)
* 1 if connection is lingering
* may be called by listener or by worker thread
*/
-static int start_lingering_close(conn_state_t *cs)
+static int start_lingering_close(event_conn_state_t *cs)
{
apr_status_t rv;
if (ap_start_lingering_close(cs->c)) {
cs->expiration_time =
apr_time_now() + apr_time_from_sec(SECONDS_TO_LINGER);
q = &short_linger_q;
- cs->state = CONN_STATE_LINGER_SHORT;
+ cs->pub.state = CONN_STATE_LINGER_SHORT;
}
else {
cs->expiration_time =
apr_time_now() + apr_time_from_sec(MAX_SECS_TO_LINGER);
q = &linger_q;
- cs->state = CONN_STATE_LINGER_NORMAL;
+ cs->pub.state = CONN_STATE_LINGER_NORMAL;
}
apr_thread_mutex_lock(timeout_mutex);
TO_QUEUE_APPEND(*q, cs);
* Pre-condition: cs is not in any timeout queue and not in the pollset
* return: irrelevant (need same prototype as start_lingering_close)
*/
-static int stop_lingering_close(conn_state_t *cs)
+static int stop_lingering_close(event_conn_state_t *cs)
{
apr_status_t rv;
apr_socket_t *csd = ap_get_conn_socket(cs->c);
* 0 if it is still open and waiting for some event
*/
static int process_socket(apr_thread_t *thd, apr_pool_t * p, apr_socket_t * sock,
- conn_state_t * cs, int my_child_num,
+ event_conn_state_t * cs, int my_child_num,
int my_thread_num)
{
conn_rec *c;
if (cs == NULL) { /* This is a new connection */
listener_poll_type *pt = apr_pcalloc(p, sizeof(*pt));
- cs = apr_pcalloc(p, sizeof(conn_state_t));
+ cs = apr_pcalloc(p, sizeof(event_conn_state_t));
cs->bucket_alloc = apr_bucket_alloc_create(p);
c = ap_run_create_connection(p, ap_server_conf, sock,
conn_id, sbh, cs->bucket_alloc);
apr_pool_cleanup_register(c->pool, NULL, decrement_connection_count, apr_pool_cleanup_null);
c->current_thread = thd;
cs->c = c;
- c->cs = cs;
+ c->cs = &(cs->pub);
cs->p = p;
cs->pfd.desc_type = APR_POLL_SOCKET;
cs->pfd.reqevents = APR_POLLIN;
* When the accept filter is active, sockets are kept in the
* kernel until a HTTP request is received.
*/
- cs->state = CONN_STATE_READ_REQUEST_LINE;
+ cs->pub.state = CONN_STATE_READ_REQUEST_LINE;
}
else {
* like the Worker MPM does.
*/
ap_run_process_connection(c);
- if (cs->state != CONN_STATE_SUSPENDED) {
- cs->state = CONN_STATE_LINGER;
+ if (cs->pub.state != CONN_STATE_SUSPENDED) {
+ cs->pub.state = CONN_STATE_LINGER;
}
}
read_request:
- if (cs->state == CONN_STATE_READ_REQUEST_LINE) {
+ if (cs->pub.state == CONN_STATE_READ_REQUEST_LINE) {
if (!c->aborted) {
ap_run_process_connection(c);
*/
}
else {
- cs->state = CONN_STATE_LINGER;
+ cs->pub.state = CONN_STATE_LINGER;
}
}
- if (cs->state == CONN_STATE_WRITE_COMPLETION) {
+ if (cs->pub.state == CONN_STATE_WRITE_COMPLETION) {
ap_filter_t *output_filter = c->output_filters;
apr_status_t rv;
ap_update_child_status_from_conn(sbh, SERVER_BUSY_WRITE, c);
if (rv != APR_SUCCESS) {
ap_log_cerror(APLOG_MARK, APLOG_DEBUG, rv, c,
"network write failure in core output filter");
- cs->state = CONN_STATE_LINGER;
+ cs->pub.state = CONN_STATE_LINGER;
}
else if (c->data_in_output_filters) {
/* Still in WRITE_COMPLETION_STATE:
}
else if (c->keepalive != AP_CONN_KEEPALIVE || c->aborted ||
listener_may_exit) {
- c->cs->state = CONN_STATE_LINGER;
+ cs->pub.state = CONN_STATE_LINGER;
}
else if (c->data_in_input_filters) {
- cs->state = CONN_STATE_READ_REQUEST_LINE;
+ cs->pub.state = CONN_STATE_READ_REQUEST_LINE;
goto read_request;
}
else {
- cs->state = CONN_STATE_CHECK_REQUEST_LINE_READABLE;
+ cs->pub.state = CONN_STATE_CHECK_REQUEST_LINE_READABLE;
}
}
- if (cs->state == CONN_STATE_LINGER) {
+ if (cs->pub.state == CONN_STATE_LINGER) {
if (!start_lingering_close(cs))
return 0;
}
- else if (cs->state == CONN_STATE_CHECK_REQUEST_LINE_READABLE) {
+ else if (cs->pub.state == CONN_STATE_CHECK_REQUEST_LINE_READABLE) {
apr_status_t rc;
/* It greatly simplifies the logic to use a single timeout value here
apr_pollset_t * pollset)
{
listener_poll_type *pt = (listener_poll_type *) pfd->client_data;
- conn_state_t *cs = (conn_state_t *) pt->baton;
+ event_conn_state_t *cs = (event_conn_state_t *) pt->baton;
apr_status_t rc;
rc = ap_queue_push(worker_queue, cs->pfd.desc.s, cs, cs->p);
* Only to be called in the listener thread;
* Pre-condition: cs is in one of the linger queues and in the pollset
*/
-static void process_lingering_close(conn_state_t *cs, const apr_pollfd_t *pfd)
+static void process_lingering_close(event_conn_state_t *cs, const apr_pollfd_t *pfd)
{
apr_socket_t *csd = ap_get_conn_socket(cs->c);
char dummybuf[2048];
apr_size_t nbytes;
apr_status_t rv;
struct timeout_queue *q;
- q = (cs->state == CONN_STATE_LINGER_SHORT) ? &short_linger_q : &linger_q;
+ q = (cs->pub.state == CONN_STATE_LINGER_SHORT) ? &short_linger_q : &linger_q;
/* socket is already in non-blocking state */
do {
*/
static void process_timeout_queue(struct timeout_queue *q,
apr_time_t timeout_time,
- int (*func)(conn_state_t *))
+ int (*func)(event_conn_state_t *))
{
int count = 0;
- conn_state_t *first, *cs, *last;
+ event_conn_state_t *first, *cs, *last;
apr_status_t rv;
if (!q->count) {
return;
}
- AP_DEBUG_ASSERT(!APR_RING_EMPTY(&q->head, conn_state_t, timeout_list));
+ AP_DEBUG_ASSERT(!APR_RING_EMPTY(&q->head, event_conn_state_t, timeout_list));
cs = first = APR_RING_FIRST(&q->head);
- while (cs != APR_RING_SENTINEL(&q->head, conn_state_t, timeout_list)
+ while (cs != APR_RING_SENTINEL(&q->head, event_conn_state_t, timeout_list)
&& cs->expiration_time < timeout_time) {
last = cs;
rv = apr_pollset_remove(event_pollset, &cs->pfd);
apr_pool_t *ptrans; /* Pool for per-transaction stuff */
ap_listen_rec *lr;
int have_idle_worker = 0;
- conn_state_t *cs;
+ event_conn_state_t *cs;
const apr_pollfd_t *out_pfd;
apr_int32_t num = 0;
apr_interval_time_t timeout_interval;
/* one of the sockets is readable */
struct timeout_queue *remove_from_q = &write_completion_q;
int blocking = 1;
- cs = (conn_state_t *) pt->baton;
- switch (cs->state) {
+ cs = (event_conn_state_t *) pt->baton;
+ switch (cs->pub.state) {
case CONN_STATE_CHECK_REQUEST_LINE_READABLE:
- cs->state = CONN_STATE_READ_REQUEST_LINE;
+ cs->pub.state = CONN_STATE_READ_REQUEST_LINE;
remove_from_q = &keepalive_q;
/* don't wait for a worker for a keepalive request */
blocking = 0;
ap_log_error(APLOG_MARK, APLOG_CRIT, rc,
ap_server_conf,
"event_loop: unexpected state %d",
- cs->state);
+ cs->pub.state);
ap_assert(0);
}
}
int process_slot = ti->pid;
int thread_slot = ti->tid;
apr_socket_t *csd = NULL;
- conn_state_t *cs;
+ event_conn_state_t *cs;
apr_pool_t *ptrans; /* Pool for per-transaction stuff */
apr_status_t rv;
int is_idle = 0;