1
0
mirror of https://github.com/apache/httpd.git synced 2026-01-13 21:42:17 +03:00
Files
apache/server/mpm/eventopt/equeue.c
Jim Jagielski 7c3e75bdd0 Pull the event optimization MPM back into trunk. This
provides more eyes and allows work to continue on
it...

git-svn-id: https://svn.apache.org/repos/asf/httpd/httpd/trunk@1407533 13f79535-47bb-0310-9956-ffa450edef68
2012-11-09 16:41:12 +00:00

126 lines
3.2 KiB
C

/* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "equeue.h"
#include <apr_atomic.h>
#include <sched.h>
struct ap_equeue_t {
apr_uint32_t nelem;
apr_size_t elem_size;
uint8_t *bytes;
volatile apr_uint32_t writeCount;
volatile apr_uint32_t readCount;
};
static APR_INLINE apr_uint32_t count_to_index(ap_equeue_t *eq, apr_uint32_t count)
{
return (count & (eq->nelem - 1));
}
static APR_INLINE void* index_to_bytes(ap_equeue_t *eq, apr_uint32_t idx)
{
apr_size_t offset = idx * eq->elem_size;
return (void*)&eq->bytes[offset];
}
static APR_INLINE apr_uint32_t nearest_power(apr_uint32_t num)
{
apr_uint32_t n = 1;
while (n < num) {
n <<= 1;
}
return n;
}
#if 0
static void dump_queue(ap_equeue_t *eq)
{
apr_uint32_t i;
fprintf(stderr, "dumping %p\n", eq);
fprintf(stderr, " nelem: %u\n", eq->nelem);
fprintf(stderr, " esize: %"APR_SIZE_T_FMT"\n", eq->elem_size);
fprintf(stderr, " wcnt: %u\n", eq->writeCount);
fprintf(stderr, " rcnt: %u\n", eq->writeCount);
fprintf(stderr, " bytes: %p\n", eq->bytes);
for (i = 0; i < eq->nelem; i++) {
fprintf(stderr, " [%u] = %p\n", i, index_to_bytes(eq, i));
}
fprintf(stderr, "\n");
fflush(stderr);
}
#endif
apr_status_t
ap_equeue_create(apr_pool_t *p, apr_uint32_t nelem, apr_size_t elem_size, ap_equeue_t **eqout)
{
ap_equeue_t *eq;
*eqout = NULL;
eq = apr_palloc(p, sizeof(ap_equeue_t));
eq->nelem = nearest_power(nelem);
eq->bytes = apr_palloc(p, eq->nelem * elem_size);
eq->elem_size = elem_size;
eq->writeCount = 0;
eq->readCount = 0;
*eqout = eq;
return APR_SUCCESS;
}
void *
ap_equeue_reader_next(ap_equeue_t *eq)
{
if (apr_atomic_read32(&eq->writeCount) == eq->readCount) {
return NULL;
}
else {
apr_uint32_t idx = count_to_index(eq, apr_atomic_inc32(&eq->readCount));
return index_to_bytes(eq, idx);
}
}
void *
ap_equeue_writer_value(ap_equeue_t *eq)
{
apr_uint32_t idx;
while (1) {
apr_uint32_t readCount = apr_atomic_read32(&eq->readCount);
if (count_to_index(eq, eq->writeCount + 1) != count_to_index(eq, readCount)) {
break;
}
/* TODO: research if sched_yield is even worth doing */
sched_yield();
}
idx = count_to_index(eq, eq->writeCount);
return index_to_bytes(eq, idx);
}
void ap_equeue_writer_onward(ap_equeue_t *eq)
{
apr_atomic_inc32(&eq->writeCount);
}