Blame SOURCES/httpd-2.4.12-skiplist.patch

33b929
diff --git a/server/mpm/event/config.m4 b/server/mpm/event/config.m4
33b929
index c891c75..351f1ac 100644
33b929
--- a/server/mpm/event/config.m4
33b929
+++ b/server/mpm/event/config.m4
33b929
@@ -7,8 +7,6 @@ elif test $have_threaded_sig_graceful != yes; then
33b929
     AC_MSG_RESULT(no - SIG_GRACEFUL cannot be used with a threaded MPM)
33b929
 elif test $ac_cv_have_threadsafe_pollset != yes; then
33b929
     AC_MSG_RESULT(no - APR_POLLSET_THREADSAFE is not supported)
33b929
-elif test $apr_has_skiplist != yes; then
33b929
-    AC_MSG_RESULT(no - APR skiplist is not available, need APR 1.5.x or later)
33b929
 else
33b929
     AC_MSG_RESULT(yes)
33b929
     APACHE_MPM_SUPPORTED(event, yes, yes)
33b929
diff --git a/server/mpm/event/config3.m4 b/server/mpm/event/config3.m4
33b929
index 8aa1631..fa9b8af 100644
33b929
--- a/server/mpm/event/config3.m4
33b929
+++ b/server/mpm/event/config3.m4
33b929
@@ -2,6 +2,6 @@ dnl ## XXX - Need a more thorough check of the proper flags to use
33b929
 
33b929
 APACHE_SUBST(MOD_MPM_EVENT_LDADD)
33b929
 
33b929
-APACHE_MPM_MODULE(event, $enable_mpm_event, event.lo fdqueue.lo,[
33b929
+APACHE_MPM_MODULE(event, $enable_mpm_event, event.lo fdqueue.lo apr_skiplist.lo,[
33b929
     AC_CHECK_FUNCS(pthread_kill)
33b929
 ], , [\$(MOD_MPM_EVENT_LDADD)])
33b929
diff --git a/server/mpm/event/apr_skiplist.c b/server/mpm/event/apr_skiplist.c
33b929
new file mode 100644
6670f0
index 0000000..b4696bd
33b929
--- /dev/null
33b929
+++ b/server/mpm/event/apr_skiplist.c
6670f0
@@ -0,0 +1,721 @@
33b929
+/* Licensed to the Apache Software Foundation (ASF) under one or more
33b929
+ * contributor license agreements.  See the NOTICE file distributed with
33b929
+ * this work for additional information regarding copyright ownership.
33b929
+ * The ASF licenses this file to You under the Apache License, Version 2.0
33b929
+ * (the "License"); you may not use this file except in compliance with
33b929
+ * the License.  You may obtain a copy of the License at
33b929
+ *
33b929
+ *     http://www.apache.org/licenses/LICENSE-2.0
33b929
+ *
33b929
+ * Unless required by applicable law or agreed to in writing, software
33b929
+ * distributed under the License is distributed on an "AS IS" BASIS,
33b929
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
33b929
+ * See the License for the specific language governing permissions and
33b929
+ * limitations under the License.
33b929
+ */
33b929
+
33b929
+/*
33b929
+ * Modified to use APR and APR pools.
33b929
+ *  TODO: Is malloc() better? Will long running skiplists grow too much?
33b929
+ *  Keep the skiplist_alloc() and skiplist_free() until we know
33b929
+ *  Yeah, if using pools it means some bogus cycles for checks
33b929
+ *  (and an useless function call for skiplist_free) which we
33b929
+ *  can removed if/when needed.
33b929
+ */
33b929
+
33b929
+#include "apr_skiplist.h"
33b929
+
6670f0
+typedef struct {
6670f0
+    apr_skiplistnode **data;
6670f0
+    size_t size, pos;
6670f0
+    apr_pool_t *p;
6670f0
+} apr_skiplist_q; 
6670f0
+
33b929
+struct apr_skiplist {
33b929
+    apr_skiplist_compare compare;
33b929
+    apr_skiplist_compare comparek;
33b929
+    int height;
33b929
+    int preheight;
6670f0
+    size_t size;
33b929
+    apr_skiplistnode *top;
33b929
+    apr_skiplistnode *bottom;
33b929
+    /* These two are needed for appending */
33b929
+    apr_skiplistnode *topend;
33b929
+    apr_skiplistnode *bottomend;
33b929
+    apr_skiplist *index;
33b929
+    apr_array_header_t *memlist;
6670f0
+    apr_skiplist_q nodes_q,
6670f0
+                   stack_q;
33b929
+    apr_pool_t *pool;
33b929
+};
33b929
+
33b929
+struct apr_skiplistnode {
33b929
+    void *data;
33b929
+    apr_skiplistnode *next;
33b929
+    apr_skiplistnode *prev;
33b929
+    apr_skiplistnode *down;
33b929
+    apr_skiplistnode *up;
33b929
+    apr_skiplistnode *previndex;
33b929
+    apr_skiplistnode *nextindex;
33b929
+    apr_skiplist *sl;
33b929
+};
33b929
+
33b929
+static int get_b_rand(void)
33b929
+{
33b929
+    static int ph = 32;         /* More bits than we will ever use */
6670f0
+    static int randseq;
33b929
+    if (ph > 31) {              /* Num bits in return of rand() */
33b929
+        ph = 0;
6670f0
+        randseq = rand();
33b929
+    }
6670f0
+    return randseq & (1 << ph++);
33b929
+}
33b929
+
33b929
+typedef struct {
33b929
+    size_t size;
33b929
+    apr_array_header_t *list;
33b929
+} memlist_t;
33b929
+
33b929
+typedef struct {
33b929
+    void *ptr;
33b929
+    char inuse;
33b929
+} chunk_t;
33b929
+
33b929
+APR_DECLARE(void *) apr_skiplist_alloc(apr_skiplist *sl, size_t size)
33b929
+{
33b929
+    if (sl->pool) {
33b929
+        void *ptr;
33b929
+        int found_size = 0;
33b929
+        int i;
33b929
+        chunk_t *newchunk;
33b929
+        memlist_t *memlist = (memlist_t *)sl->memlist->elts;
33b929
+        for (i = 0; i < sl->memlist->nelts; i++) {
33b929
+            if (memlist->size == size) {
33b929
+                int j;
33b929
+                chunk_t *chunk = (chunk_t *)memlist->list->elts;
33b929
+                found_size = 1;
33b929
+                for (j = 0; j < memlist->list->nelts; j++) {
33b929
+                    if (!chunk->inuse) {
33b929
+                        chunk->inuse = 1;
33b929
+                        return chunk->ptr;
33b929
+                    }
33b929
+                    chunk++;
33b929
+                }
33b929
+                break; /* no free of this size; punt */
33b929
+            }
33b929
+            memlist++;
33b929
+        }
33b929
+        /* no free chunks */
6670f0
+        ptr = apr_palloc(sl->pool, size);
33b929
+        if (!ptr) {
33b929
+            return ptr;
33b929
+        }
33b929
+        /*
33b929
+         * is this a new sized chunk? If so, we need to create a new
33b929
+         * array of them. Otherwise, re-use what we already have.
33b929
+         */
33b929
+        if (!found_size) {
33b929
+            memlist = apr_array_push(sl->memlist);
33b929
+            memlist->size = size;
33b929
+            memlist->list = apr_array_make(sl->pool, 20, sizeof(chunk_t));
33b929
+        }
33b929
+        newchunk = apr_array_push(memlist->list);
33b929
+        newchunk->ptr = ptr;
33b929
+        newchunk->inuse = 1;
33b929
+        return ptr;
33b929
+    }
33b929
+    else {
6670f0
+        return malloc(size);
33b929
+    }
33b929
+}
33b929
+
33b929
+APR_DECLARE(void) apr_skiplist_free(apr_skiplist *sl, void *mem)
33b929
+{
33b929
+    if (!sl->pool) {
33b929
+        free(mem);
33b929
+    }
33b929
+    else {
33b929
+        int i;
33b929
+        memlist_t *memlist = (memlist_t *)sl->memlist->elts;
33b929
+        for (i = 0; i < sl->memlist->nelts; i++) {
33b929
+            int j;
33b929
+            chunk_t *chunk = (chunk_t *)memlist->list->elts;
33b929
+            for (j = 0; j < memlist->list->nelts; j++) {
33b929
+                if (chunk->ptr == mem) {
33b929
+                    chunk->inuse = 0;
33b929
+                    return;
33b929
+                }
33b929
+                chunk++;
33b929
+            }
33b929
+            memlist++;
33b929
+        }
33b929
+    }
33b929
+}
33b929
+
6670f0
+static apr_status_t skiplist_qpush(apr_skiplist_q *q, apr_skiplistnode *m)
6670f0
+{
6670f0
+    if (q->pos >= q->size) {
6670f0
+        apr_skiplistnode **data;
6670f0
+        size_t size = (q->pos) ? q->pos * 2 : 32;
6670f0
+        if (q->p) {
6670f0
+            data = apr_palloc(q->p, size * sizeof(*data));
6670f0
+            if (data) {
6670f0
+                memcpy(data, q->data, q->pos * sizeof(*data));
6670f0
+            }
6670f0
+        }
6670f0
+        else {
6670f0
+            data = realloc(q->data, size * sizeof(*data));
6670f0
+        }
6670f0
+        if (!data) {
6670f0
+            return APR_ENOMEM;
6670f0
+        }
6670f0
+        q->data = data;
6670f0
+        q->size = size;
6670f0
+    }
6670f0
+    q->data[q->pos++] = m;
6670f0
+    return APR_SUCCESS;
6670f0
+}
6670f0
+
6670f0
+static APR_INLINE apr_skiplistnode *skiplist_qpop(apr_skiplist_q *q)
6670f0
+{
6670f0
+    return (q->pos > 0) ? q->data[--q->pos] : NULL;
6670f0
+}
6670f0
+
6670f0
+static APR_INLINE void skiplist_qclear(apr_skiplist_q *q)
6670f0
+{
6670f0
+    q->pos = 0;
6670f0
+}
6670f0
+
6670f0
+static apr_skiplistnode *skiplist_new_node(apr_skiplist *sl)
6670f0
+{
6670f0
+    apr_skiplistnode *m = skiplist_qpop(&sl->nodes_q);
6670f0
+    if (!m) {
6670f0
+        if (sl->pool) {
6670f0
+            m = apr_palloc(sl->pool, sizeof *m);
6670f0
+        }
6670f0
+        else {
6670f0
+            m = malloc(sizeof *m);
6670f0
+        }
6670f0
+    }
6670f0
+    return m;
6670f0
+}
6670f0
+
6670f0
+static apr_status_t skiplist_free_node(apr_skiplist *sl, apr_skiplistnode *m)
6670f0
+{
6670f0
+    return skiplist_qpush(&sl->nodes_q, m);
6670f0
+}
6670f0
+
33b929
+static apr_status_t skiplisti_init(apr_skiplist **s, apr_pool_t *p)
33b929
+{
33b929
+    apr_skiplist *sl;
33b929
+    if (p) {
33b929
+        sl = apr_pcalloc(p, sizeof(apr_skiplist));
33b929
+        sl->memlist = apr_array_make(p, 20, sizeof(memlist_t));
6670f0
+        sl->pool = sl->nodes_q.p = sl->stack_q.p = p;
33b929
+    }
33b929
+    else {
33b929
+        sl = calloc(1, sizeof(apr_skiplist));
6670f0
+        if (!sl) {
6670f0
+            return APR_ENOMEM;
6670f0
+        }
33b929
+    }
33b929
+    *s = sl;
33b929
+    return APR_SUCCESS;
33b929
+}
33b929
+
33b929
+static int indexing_comp(void *a, void *b)
33b929
+{
33b929
+    void *ac = (void *) (((apr_skiplist *) a)->compare);
33b929
+    void *bc = (void *) (((apr_skiplist *) b)->compare);
33b929
+    return ((ac < bc) ? -1 : ((ac > bc) ? 1 : 0));
33b929
+}
33b929
+
33b929
+static int indexing_compk(void *ac, void *b)
33b929
+{
33b929
+    void *bc = (void *) (((apr_skiplist *) b)->compare);
33b929
+    return ((ac < bc) ? -1 : ((ac > bc) ? 1 : 0));
33b929
+}
33b929
+
33b929
+APR_DECLARE(apr_status_t) apr_skiplist_init(apr_skiplist **s, apr_pool_t *p)
33b929
+{
33b929
+    apr_skiplist *sl;
33b929
+    skiplisti_init(s, p);
33b929
+    sl = *s;
33b929
+    skiplisti_init(&(sl->index), p);
33b929
+    apr_skiplist_set_compare(sl->index, indexing_comp, indexing_compk);
33b929
+    return APR_SUCCESS;
33b929
+}
33b929
+
33b929
+APR_DECLARE(void) apr_skiplist_set_compare(apr_skiplist *sl,
33b929
+                          apr_skiplist_compare comp,
33b929
+                          apr_skiplist_compare compk)
33b929
+{
33b929
+    if (sl->compare && sl->comparek) {
33b929
+        apr_skiplist_add_index(sl, comp, compk);
33b929
+    }
33b929
+    else {
33b929
+        sl->compare = comp;
33b929
+        sl->comparek = compk;
33b929
+    }
33b929
+}
33b929
+
33b929
+APR_DECLARE(void) apr_skiplist_add_index(apr_skiplist *sl,
33b929
+                        apr_skiplist_compare comp,
33b929
+                        apr_skiplist_compare compk)
33b929
+{
33b929
+    apr_skiplistnode *m;
33b929
+    apr_skiplist *ni;
33b929
+    int icount = 0;
33b929
+    apr_skiplist_find(sl->index, (void *)comp, &m);
33b929
+    if (m) {
33b929
+        return;                 /* Index already there! */
33b929
+    }
33b929
+    skiplisti_init(&ni, sl->pool);
33b929
+    apr_skiplist_set_compare(ni, comp, compk);
33b929
+    /* Build the new index... This can be expensive! */
33b929
+    m = apr_skiplist_insert(sl->index, ni);
33b929
+    while (m->prev) {
33b929
+        m = m->prev;
33b929
+        icount++;
33b929
+    }
33b929
+    for (m = apr_skiplist_getlist(sl); m; apr_skiplist_next(sl, &m)) {
33b929
+        int j = icount - 1;
33b929
+        apr_skiplistnode *nsln;
33b929
+        nsln = apr_skiplist_insert(ni, m->data);
33b929
+        /* skip from main index down list */
33b929
+        while (j > 0) {
33b929
+            m = m->nextindex;
33b929
+            j--;
33b929
+        }
33b929
+        /* insert this node in the indexlist after m */
33b929
+        nsln->nextindex = m->nextindex;
33b929
+        if (m->nextindex) {
33b929
+            m->nextindex->previndex = nsln;
33b929
+        }
33b929
+        nsln->previndex = m;
33b929
+        m->nextindex = nsln;
33b929
+    }
33b929
+}
33b929
+
33b929
+static int skiplisti_find_compare(apr_skiplist *sl, void *data,
33b929
+                           apr_skiplistnode **ret,
33b929
+                           apr_skiplist_compare comp)
33b929
+{
33b929
+    int count = 0;
6670f0
+    apr_skiplistnode *m;
33b929
+    m = sl->top;
33b929
+    while (m) {
6670f0
+        if (m->next) {
6670f0
+            int compared = comp(data, m->next->data);
6670f0
+            if (compared == 0) {
6670f0
+                m = m->next;
6670f0
+                while (m->down) {
6670f0
+                    m = m->down;
6670f0
+                }
6670f0
+                *ret = m;
6670f0
+                return count;
6670f0
+            }
6670f0
+            if (compared > 0) {
6670f0
+                m = m->next;
6670f0
+                count++;
6670f0
+                continue;
33b929
+            }
33b929
+        }
6670f0
+        m = m->down;
6670f0
+        count++;
33b929
+    }
33b929
+    *ret = NULL;
33b929
+    return count;
33b929
+}
33b929
+
33b929
+APR_DECLARE(void *) apr_skiplist_find_compare(apr_skiplist *sli, void *data,
33b929
+                               apr_skiplistnode **iter,
33b929
+                               apr_skiplist_compare comp)
33b929
+{
6670f0
+    apr_skiplistnode *m;
33b929
+    apr_skiplist *sl;
6670f0
+    if (!comp) {
6670f0
+        if (iter) {
6670f0
+            *iter = NULL;
6670f0
+        }
6670f0
+        return NULL;
6670f0
+    }
33b929
+    if (comp == sli->compare || !sli->index) {
33b929
+        sl = sli;
33b929
+    }
33b929
+    else {
33b929
+        apr_skiplist_find(sli->index, (void *)comp, &m);
6670f0
+        if (!m) {
6670f0
+            if (iter) {
6670f0
+                *iter = NULL;
6670f0
+            }
6670f0
+            return NULL;
6670f0
+        }
33b929
+        sl = (apr_skiplist *) m->data;
33b929
+    }
6670f0
+    skiplisti_find_compare(sl, data, &m, sl->comparek);
6670f0
+    if (iter) {
6670f0
+        *iter = m;
6670f0
+    }
6670f0
+    return (m) ? m->data : NULL;
6670f0
+}
6670f0
+
6670f0
+APR_DECLARE(void *) apr_skiplist_find(apr_skiplist *sl, void *data, apr_skiplistnode **iter)
6670f0
+{
6670f0
+    return apr_skiplist_find_compare(sl, data, iter, sl->compare);
33b929
+}
33b929
+
33b929
+
6670f0
+APR_DECLARE(apr_skiplistnode *) apr_skiplist_getlist(apr_skiplist *sl)
6670f0
+{
6670f0
+    if (!sl->bottom) {
6670f0
+        return NULL;
6670f0
+    }
6670f0
+    return sl->bottom->next;
6670f0
+}
6670f0
+
33b929
+APR_DECLARE(void *) apr_skiplist_next(apr_skiplist *sl, apr_skiplistnode **iter)
33b929
+{
33b929
+    if (!*iter) {
33b929
+        return NULL;
33b929
+    }
33b929
+    *iter = (*iter)->next;
33b929
+    return (*iter) ? ((*iter)->data) : NULL;
33b929
+}
33b929
+
33b929
+APR_DECLARE(void *) apr_skiplist_previous(apr_skiplist *sl, apr_skiplistnode **iter)
33b929
+{
33b929
+    if (!*iter) {
33b929
+        return NULL;
33b929
+    }
33b929
+    *iter = (*iter)->prev;
33b929
+    return (*iter) ? ((*iter)->data) : NULL;
33b929
+}
33b929
+
6670f0
+static APR_INLINE int skiplist_height(const apr_skiplist *sl)
33b929
+{
6670f0
+    /* Skiplists (even empty) always have a top node, although this
6670f0
+     * implementation defers its creation until the first insert, or
6670f0
+     * deletes it with the last remove. We want the real height here.
6670f0
+     */
6670f0
+    return sl->height ? sl->height : 1;
33b929
+}
33b929
+
33b929
+APR_DECLARE(apr_skiplistnode *) apr_skiplist_insert_compare(apr_skiplist *sl, void *data,
33b929
+                                      apr_skiplist_compare comp)
33b929
+{
6670f0
+    apr_skiplistnode *m, *p, *tmp, *ret = NULL;
6670f0
+    int ch, nh = 1;
6670f0
+
6670f0
+    if (!comp) {
6670f0
+        return NULL;
33b929
+    }
6670f0
+
6670f0
+    ch = skiplist_height(sl);
33b929
+    if (sl->preheight) {
33b929
+        while (nh < sl->preheight && get_b_rand()) {
33b929
+            nh++;
33b929
+        }
33b929
+    }
33b929
+    else {
6670f0
+        while (nh <= ch && get_b_rand()) {
33b929
+            nh++;
33b929
+        }
33b929
+    }
6670f0
+
6670f0
+    /* Now we have in nh the height at which we wish to insert our new node,
6670f0
+     * and in ch the current height: don't create skip paths to the inserted
6670f0
+     * element until the walk down through the tree (which decrements ch)
6670f0
+     * reaches nh. From there, any walk down pushes the current node on a
6670f0
+     * stack (the node(s) after which we would insert) to pop back through
6670f0
+     * for insertion later.
33b929
+     */
33b929
+    m = sl->top;
33b929
+    while (m) {
33b929
+        if (m->next) {
6670f0
+            int compared = comp(data, m->next->data);
6670f0
+            if (compared == 0) {
6670f0
+                /* Keep the existing element(s) */
6670f0
+                skiplist_qclear(&sl->stack_q);
6670f0
+                return NULL;
6670f0
+            }
6670f0
+            if (compared > 0) {
6670f0
+                m = m->next;
6670f0
+                continue;
33b929
+            }
33b929
+        }
6670f0
+        if (ch <= nh) {
6670f0
+            /* push on stack */
6670f0
+            skiplist_qpush(&sl->stack_q, m);
33b929
+        }
6670f0
+        m = m->down;
6670f0
+        ch--;
33b929
+    }
33b929
+    /* Pop the stack and insert nodes */
33b929
+    p = NULL;
6670f0
+    while ((m = skiplist_qpop(&sl->stack_q))) {
6670f0
+        tmp = skiplist_new_node(sl);
33b929
+        tmp->next = m->next;
33b929
+        if (m->next) {
33b929
+            m->next->prev = tmp;
33b929
+        }
6670f0
+        m->next = tmp;
33b929
+        tmp->prev = m;
33b929
+        tmp->up = NULL;
33b929
+        tmp->nextindex = tmp->previndex = NULL;
33b929
+        tmp->down = p;
33b929
+        if (p) {
33b929
+            p->up = tmp;
33b929
+        }
6670f0
+        else {
6670f0
+            /* This sets ret to the bottom-most node we are inserting */
6670f0
+            ret = tmp;
6670f0
+        }
33b929
+        tmp->data = data;
33b929
+        tmp->sl = sl;
6670f0
+        p = tmp;
6670f0
+    }
6670f0
+
6670f0
+    /* Now we are sure the node is inserted, grow our tree to 'nh' tall */
6670f0
+    for (; sl->height < nh; sl->height++) {
6670f0
+        m = skiplist_new_node(sl);
6670f0
+        tmp = skiplist_new_node(sl);
6670f0
+        m->up = m->prev = m->nextindex = m->previndex = NULL;
33b929
+        m->next = tmp;
6670f0
+        m->down = sl->top;
6670f0
+        m->data = NULL;
6670f0
+        m->sl = sl;
6670f0
+        if (sl->top) {
6670f0
+            sl->top->up = m;
6670f0
+        }
6670f0
+        else {
6670f0
+            sl->bottom = sl->bottomend = m;
6670f0
+        }
6670f0
+        sl->top = sl->topend = tmp->prev = m;
6670f0
+        tmp->up = tmp->next = tmp->nextindex = tmp->previndex = NULL;
6670f0
+        tmp->down = p;
6670f0
+        tmp->data = data;
6670f0
+        tmp->sl = sl;
6670f0
+        if (p) {
6670f0
+            p->up = tmp;
6670f0
+        }
6670f0
+        else {
6670f0
+            /* This sets ret to the bottom-most node we are inserting */
33b929
+            ret = tmp;
33b929
+        }
33b929
+        p = tmp;
33b929
+    }
33b929
+    if (sl->index != NULL) {
33b929
+        /*
33b929
+         * this is a external insertion, we must insert into each index as
33b929
+         * well
33b929
+         */
33b929
+        apr_skiplistnode *ni, *li;
33b929
+        li = ret;
33b929
+        for (p = apr_skiplist_getlist(sl->index); p; apr_skiplist_next(sl->index, &p)) {
6670f0
+            apr_skiplist *sli = (apr_skiplist *)p->data;
6670f0
+            ni = apr_skiplist_insert_compare(sli, ret->data, sli->compare);
33b929
+            li->nextindex = ni;
33b929
+            ni->previndex = li;
33b929
+            li = ni;
33b929
+        }
33b929
+    }
33b929
+    sl->size++;
33b929
+    return ret;
33b929
+}
33b929
+
6670f0
+APR_DECLARE(apr_skiplistnode *) apr_skiplist_insert(apr_skiplist *sl, void *data)
33b929
+{
6670f0
+    return apr_skiplist_insert_compare(sl, data, sl->compare);
33b929
+}
33b929
+
33b929
+#if 0
33b929
+void skiplist_print_struct(apr_skiplist * sl, char *prefix)
33b929
+{
33b929
+    apr_skiplistnode *p, *q;
33b929
+    fprintf(stderr, "Skiplist Structure (height: %d)\n", sl->height);
33b929
+    p = sl->bottom;
33b929
+    while (p) {
33b929
+        q = p;
33b929
+        fprintf(stderr, prefix);
33b929
+        while (q) {
33b929
+            fprintf(stderr, "%p ", q->data);
33b929
+            q = q->up;
33b929
+        }
33b929
+        fprintf(stderr, "\n");
33b929
+        p = p->next;
33b929
+    }
33b929
+}
33b929
+#endif
33b929
+
33b929
+static int skiplisti_remove(apr_skiplist *sl, apr_skiplistnode *m, apr_skiplist_freefunc myfree)
33b929
+{
33b929
+    apr_skiplistnode *p;
33b929
+    if (!m) {
33b929
+        return 0;
33b929
+    }
33b929
+    if (m->nextindex) {
33b929
+        skiplisti_remove(m->nextindex->sl, m->nextindex, NULL);
33b929
+    }
33b929
+    while (m->up) {
33b929
+        m = m->up;
33b929
+    }
33b929
+    while (m) {
33b929
+        p = m;
33b929
+        p->prev->next = p->next;/* take me out of the list */
33b929
+        if (p->next) {
33b929
+            p->next->prev = p->prev;    /* take me out of the list */
33b929
+        }
33b929
+        m = m->down;
33b929
+        /* This only frees the actual data in the bottom one */
33b929
+        if (!m && myfree && p->data) {
33b929
+            myfree(p->data);
33b929
+        }
6670f0
+        skiplist_free_node(sl, p);
33b929
+    }
33b929
+    sl->size--;
33b929
+    while (sl->top && sl->top->next == NULL) {
33b929
+        /* While the row is empty and we are not on the bottom row */
33b929
+        p = sl->top;
33b929
+        sl->top = sl->top->down;/* Move top down one */
33b929
+        if (sl->top) {
33b929
+            sl->top->up = NULL; /* Make it think its the top */
33b929
+        }
6670f0
+        skiplist_free_node(sl, p);
33b929
+        sl->height--;
33b929
+    }
33b929
+    if (!sl->top) {
6670f0
+        sl->bottom = sl->bottomend = NULL;
6670f0
+        sl->topend = NULL;
33b929
+    }
6670f0
+    return skiplist_height(sl);
33b929
+}
33b929
+
33b929
+APR_DECLARE(int) apr_skiplist_remove_compare(apr_skiplist *sli,
33b929
+                            void *data,
33b929
+                            apr_skiplist_freefunc myfree, apr_skiplist_compare comp)
33b929
+{
33b929
+    apr_skiplistnode *m;
33b929
+    apr_skiplist *sl;
6670f0
+    if (!comp) {
6670f0
+        return 0;
6670f0
+    }
33b929
+    if (comp == sli->comparek || !sli->index) {
33b929
+        sl = sli;
33b929
+    }
33b929
+    else {
33b929
+        apr_skiplist_find(sli->index, (void *)comp, &m);
6670f0
+        if (!m) {
6670f0
+            return 0;
6670f0
+        }
33b929
+        sl = (apr_skiplist *) m->data;
33b929
+    }
33b929
+    skiplisti_find_compare(sl, data, &m, comp);
33b929
+    if (!m) {
33b929
+        return 0;
33b929
+    }
33b929
+    while (m->previndex) {
33b929
+        m = m->previndex;
33b929
+    }
33b929
+    return skiplisti_remove(sl, m, myfree);
33b929
+}
33b929
+
6670f0
+APR_DECLARE(int) apr_skiplist_remove(apr_skiplist *sl, void *data, apr_skiplist_freefunc myfree)
6670f0
+{
6670f0
+    return apr_skiplist_remove_compare(sl, data, myfree, sl->comparek);
6670f0
+}
6670f0
+
33b929
+APR_DECLARE(void) apr_skiplist_remove_all(apr_skiplist *sl, apr_skiplist_freefunc myfree)
33b929
+{
33b929
+    /*
33b929
+     * This must remove even the place holder nodes (bottom though top)
33b929
+     * because we specify in the API that one can free the Skiplist after
33b929
+     * making this call without memory leaks
33b929
+     */
33b929
+    apr_skiplistnode *m, *p, *u;
33b929
+    m = sl->bottom;
33b929
+    while (m) {
33b929
+        p = m->next;
6670f0
+        if (myfree && p && p->data) {
33b929
+            myfree(p->data);
6670f0
+        }
6670f0
+        do {
33b929
+            u = m->up;
6670f0
+            skiplist_free_node(sl, m);
33b929
+            m = u;
6670f0
+        } while (m);
33b929
+        m = p;
33b929
+    }
33b929
+    sl->top = sl->bottom = NULL;
6670f0
+    sl->topend = sl->bottomend = NULL;
33b929
+    sl->height = 0;
33b929
+    sl->size = 0;
33b929
+}
33b929
+
33b929
+APR_DECLARE(void *) apr_skiplist_pop(apr_skiplist *a, apr_skiplist_freefunc myfree)
33b929
+{
33b929
+    apr_skiplistnode *sln;
33b929
+    void *data = NULL;
33b929
+    sln = apr_skiplist_getlist(a);
33b929
+    if (sln) {
33b929
+        data = sln->data;
33b929
+        skiplisti_remove(a, sln, myfree);
33b929
+    }
33b929
+    return data;
33b929
+}
33b929
+
33b929
+APR_DECLARE(void *) apr_skiplist_peek(apr_skiplist *a)
33b929
+{
33b929
+    apr_skiplistnode *sln;
33b929
+    sln = apr_skiplist_getlist(a);
33b929
+    if (sln) {
33b929
+        return sln->data;
33b929
+    }
33b929
+    return NULL;
33b929
+}
33b929
+
33b929
+static void skiplisti_destroy(void *vsl)
33b929
+{
6670f0
+    apr_skiplist_destroy(vsl, NULL);
33b929
+}
33b929
+
33b929
+APR_DECLARE(void) apr_skiplist_destroy(apr_skiplist *sl, apr_skiplist_freefunc myfree)
33b929
+{
33b929
+    while (apr_skiplist_pop(sl->index, skiplisti_destroy) != NULL)
33b929
+        ;
33b929
+    apr_skiplist_remove_all(sl, myfree);
6670f0
+    if (!sl->pool) {
6670f0
+        while (sl->nodes_q.pos)
6670f0
+            free(sl->nodes_q.data[--sl->nodes_q.pos]);
6670f0
+        free(sl->nodes_q.data);
6670f0
+        free(sl->stack_q.data);
6670f0
+        free(sl);
6670f0
+    }
33b929
+}
33b929
+
33b929
+APR_DECLARE(apr_skiplist *) apr_skiplist_merge(apr_skiplist *sl1, apr_skiplist *sl2)
33b929
+{
33b929
+    /* Check integrity! */
33b929
+    apr_skiplist temp;
33b929
+    struct apr_skiplistnode *b2;
33b929
+    if (sl1->bottomend == NULL || sl1->bottomend->prev == NULL) {
33b929
+        apr_skiplist_remove_all(sl1, NULL);
33b929
+        temp = *sl1;
33b929
+        *sl1 = *sl2;
33b929
+        *sl2 = temp;
33b929
+        /* swap them so that sl2 can be freed normally upon return. */
33b929
+        return sl1;
33b929
+    }
33b929
+    if(sl2->bottom == NULL || sl2->bottom->next == NULL) {
33b929
+        apr_skiplist_remove_all(sl2, NULL);
33b929
+        return sl1;
33b929
+    }
33b929
+    /* This is what makes it brute force... Just insert :/ */
33b929
+    b2 = apr_skiplist_getlist(sl2);
33b929
+    while (b2) {
33b929
+        apr_skiplist_insert(sl1, b2->data);
33b929
+        apr_skiplist_next(sl2, &b2;;
33b929
+    }
33b929
+    apr_skiplist_remove_all(sl2, NULL);
33b929
+    return sl1;
33b929
+}
33b929
diff --git a/server/mpm/event/apr_skiplist.h b/server/mpm/event/apr_skiplist.h
33b929
new file mode 100644
6670f0
index 0000000..f56ff22
33b929
--- /dev/null
33b929
+++ b/server/mpm/event/apr_skiplist.h
6670f0
@@ -0,0 +1,263 @@
33b929
+/* Licensed to the Apache Software Foundation (ASF) under one or more
33b929
+ * contributor license agreements.  See the NOTICE file distributed with
33b929
+ * this work for additional information regarding copyright ownership.
33b929
+ * The ASF licenses this file to You under the Apache License, Version 2.0
33b929
+ * (the "License"); you may not use this file except in compliance with
33b929
+ * the License.  You may obtain a copy of the License at
33b929
+ *
33b929
+ *     http://www.apache.org/licenses/LICENSE-2.0
33b929
+ *
33b929
+ * Unless required by applicable law or agreed to in writing, software
33b929
+ * distributed under the License is distributed on an "AS IS" BASIS,
33b929
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
33b929
+ * See the License for the specific language governing permissions and
33b929
+ * limitations under the License.
33b929
+ */
33b929
+
33b929
+#ifndef APR_SKIPLIST_H
33b929
+#define APR_SKIPLIST_H
33b929
+/**
33b929
+ * @file apr_skiplist.h
33b929
+ * @brief APR skip list implementation
33b929
+ */
33b929
+
33b929
+#include "apr.h"
33b929
+#include "apr_portable.h"
33b929
+#include <stdlib.h>
33b929
+
33b929
+#ifdef __cplusplus
33b929
+extern "C" {
33b929
+#endif /* __cplusplus */
33b929
+
33b929
+/**
33b929
+ * @defgroup apr_skiplist Skip list implementation
33b929
+ * Refer to http://en.wikipedia.org/wiki/Skip_list for information
33b929
+ * about the purpose of and ideas behind skip lists.
33b929
+ * @ingroup APR
33b929
+ * @{
33b929
+ */
33b929
+
33b929
+/**
33b929
+ * apr_skiplist_compare is the function type that must be implemented 
33b929
+ * per object type that is used in a skip list for comparisons to maintain
6670f0
+ * order. A value <0 indicates placement after this node; a value of 0
6670f0
+ * indicates collision with this exact node; a value >0 indicates placement
6670f0
+ * before this node.
33b929
+ * */
33b929
+typedef int (*apr_skiplist_compare) (void *, void *);
33b929
+
33b929
+/**
33b929
+ * apr_skiplist_freefunc is the function type that must be implemented
33b929
+ * to handle elements as they are removed from a skip list.
33b929
+ */
33b929
+typedef void (*apr_skiplist_freefunc) (void *);
33b929
+
33b929
+/** Opaque structure used to represent the skip list */
33b929
+struct apr_skiplist;
33b929
+/** Opaque structure used to represent the skip list */
33b929
+typedef struct apr_skiplist apr_skiplist;
33b929
+
33b929
+/** 
33b929
+ * Opaque structure used to represent abstract nodes in the skip list
33b929
+ * (an abstraction above the raw elements which are collected in the
33b929
+ * skip list).
33b929
+ */
33b929
+struct apr_skiplistnode;
33b929
+/** Opaque structure */
33b929
+typedef struct apr_skiplistnode apr_skiplistnode;
33b929
+
33b929
+/**
33b929
+ * Allocate memory using the same mechanism as the skip list.
33b929
+ * @param sl The skip list
33b929
+ * @param size The amount to allocate
33b929
+ * @remark If a pool was provided to apr_skiplist_init(), memory will
33b929
+ * be allocated from the pool or from a free list maintained with
33b929
+ * the skip list.  Otherwise, memory will be allocated using the
33b929
+ * C standard library heap functions.
33b929
+ */
33b929
+APR_DECLARE(void *) apr_skiplist_alloc(apr_skiplist *sl, size_t size);
33b929
+
33b929
+/**
33b929
+ * Free memory using the same mechanism as the skip list.
33b929
+ * @param sl The skip list
33b929
+ * @param mem The object to free
33b929
+ * @remark If a pool was provided to apr_skiplist_init(), memory will
33b929
+ * be added to a free list maintained with the skip list and be available
33b929
+ * to operations on the skip list or to other calls to apr_skiplist_alloc().
33b929
+ * Otherwise, memory will be freed using the  C standard library heap
33b929
+ * functions.
33b929
+ */
33b929
+APR_DECLARE(void) apr_skiplist_free(apr_skiplist *sl, void *mem);
33b929
+
33b929
+/**
33b929
+ * Allocate a new skip list
33b929
+ * @param sl The pointer in which to return the newly created skip list
33b929
+ * @param p The pool from which to allocate the skip list (optional).
33b929
+ * @remark Unlike most APR functions, a pool is optional.  If no pool
33b929
+ * is provided, the C standard library heap functions will be used instead.
33b929
+ */
33b929
+APR_DECLARE(apr_status_t) apr_skiplist_init(apr_skiplist **sl, apr_pool_t *p);
33b929
+
33b929
+/**
33b929
+ * Set the comparison functions to be used for searching the skip list.
33b929
+ * @param sl The skip list
33b929
+ * @param XXX1 FIXME
33b929
+ * @param XXX2 FIXME
33b929
+ *
33b929
+ * @remark If existing comparison functions are being replaced, the index
33b929
+ * will be replaced during this call.  That is a potentially expensive
33b929
+ * operation.
33b929
+ */
33b929
+APR_DECLARE(void) apr_skiplist_set_compare(apr_skiplist *sl, apr_skiplist_compare XXX1,
33b929
+                             apr_skiplist_compare XXX2);
33b929
+
33b929
+/**
33b929
+ * Set the indexing functions to the specified comparison functions and
33b929
+ * rebuild the index.
33b929
+ * @param sl The skip list
33b929
+ * @param XXX1 FIXME
33b929
+ * @param XXX2 FIXME
33b929
+ *
33b929
+ * @remark If an index already exists, it will not be replaced and the
33b929
+ * comparison functions will not be changed.
33b929
+ */
33b929
+APR_DECLARE(void) apr_skiplist_add_index(apr_skiplist *sl, apr_skiplist_compare XXX1,
33b929
+                        apr_skiplist_compare XXX2);
33b929
+
33b929
+/**
33b929
+ * Return the list maintained by the skip list abstraction.
33b929
+ * @param sl The skip list
33b929
+ */
33b929
+APR_DECLARE(apr_skiplistnode *) apr_skiplist_getlist(apr_skiplist *sl);
33b929
+
33b929
+/**
33b929
+ * Return the next matching element in the skip list using the specified
33b929
+ * comparison function.
33b929
+ * @param sl The skip list
33b929
+ * @param data The value to search for
33b929
+ * @param iter A pointer to the returned skip list node representing the element
33b929
+ * found
33b929
+ * @param func The comparison function to use
33b929
+ */
33b929
+APR_DECLARE(void *) apr_skiplist_find_compare(apr_skiplist *sl,
33b929
+                               void *data,
33b929
+                               apr_skiplistnode **iter,
33b929
+                               apr_skiplist_compare func);
33b929
+
33b929
+/**
33b929
+ * Return the next matching element in the skip list using the current comparison
33b929
+ * function.
33b929
+ * @param sl The skip list
33b929
+ * @param data The value to search for
33b929
+ * @param iter A pointer to the returned skip list node representing the element
33b929
+ * found
33b929
+ */
33b929
+APR_DECLARE(void *) apr_skiplist_find(apr_skiplist *sl, void *data, apr_skiplistnode **iter);
33b929
+
33b929
+/**
33b929
+ * Return the next element in the skip list.
33b929
+ * @param sl The skip list
33b929
+ * @param iter On entry, a pointer to the skip list node to start with; on return,
33b929
+ * a pointer to the skip list node representing the element returned
33b929
+ * @remark If iter points to a NULL value on entry, NULL will be returned.
33b929
+ */
33b929
+APR_DECLARE(void *) apr_skiplist_next(apr_skiplist *sl, apr_skiplistnode **iter);
33b929
+
33b929
+/**
33b929
+ * Return the previous element in the skip list.
33b929
+ * @param sl The skip list
33b929
+ * @param iter On entry, a pointer to the skip list node to start with; on return,
33b929
+ * a pointer to the skip list node representing the element returned
33b929
+ * @remark If iter points to a NULL value on entry, NULL will be returned.
33b929
+ */
33b929
+APR_DECLARE(void *) apr_skiplist_previous(apr_skiplist *sl, apr_skiplistnode **iter);
33b929
+
33b929
+/**
6670f0
+ * Insert an element into the skip list using the specified comparison function
6670f0
+ * if it does not already exist.
33b929
+ * @param sl The skip list
33b929
+ * @param data The element to insert
33b929
+ * @param comp The comparison function to use for placement into the skip list
33b929
+ */
33b929
+APR_DECLARE(apr_skiplistnode *) apr_skiplist_insert_compare(apr_skiplist *sl,
33b929
+                                          void *data, apr_skiplist_compare comp);
33b929
+
33b929
+/**
6670f0
+ * Insert an element into the skip list using the existing comparison function
6670f0
+ * if it does not already exist (as determined by the comparison function)
33b929
+ * @param sl The skip list
33b929
+ * @param data The element to insert
33b929
+ * @remark If no comparison function has been set for the skip list, the element
33b929
+ * will not be inserted and NULL will be returned.
33b929
+ */
33b929
+APR_DECLARE(apr_skiplistnode *) apr_skiplist_insert(apr_skiplist* sl, void *data);
33b929
+
33b929
+/**
33b929
+ * Remove an element from the skip list using the specified comparison function for
6670f0
+ * locating the element. In the case of duplicates, the 1st entry will be removed.
33b929
+ * @param sl The skip list
33b929
+ * @param data The element to remove
33b929
+ * @param myfree A function to be called for each removed element
33b929
+ * @param comp The comparison function to use for placement into the skip list
33b929
+ * @remark If the element is not found, 0 will be returned.  Otherwise, the heightXXX
33b929
+ * will be returned.
33b929
+ */
33b929
+APR_DECLARE(int) apr_skiplist_remove_compare(apr_skiplist *sl, void *data,
33b929
+                               apr_skiplist_freefunc myfree, apr_skiplist_compare comp);
33b929
+
33b929
+/**
33b929
+ * Remove an element from the skip list using the existing comparison function for
6670f0
+ * locating the element. In the case of duplicates, the 1st entry will be removed.
33b929
+ * @param sl The skip list
33b929
+ * @param data The element to remove
33b929
+ * @param myfree A function to be called for each removed element
33b929
+ * @remark If the element is not found, 0 will be returned.  Otherwise, the heightXXX
33b929
+ * will be returned.
33b929
+ * @remark If no comparison function has been set for the skip list, the element
33b929
+ * will not be removed and 0 will be returned.
33b929
+ */
33b929
+APR_DECLARE(int) apr_skiplist_remove(apr_skiplist *sl, void *data, apr_skiplist_freefunc myfree);
33b929
+
33b929
+/**
33b929
+ * Remove all elements from the skip list.
33b929
+ * @param sl The skip list
33b929
+ * @param myfree A function to be called for each removed element
33b929
+ */
33b929
+APR_DECLARE(void) apr_skiplist_remove_all(apr_skiplist *sl, apr_skiplist_freefunc myfree);
33b929
+
33b929
+/**
33b929
+ * Remove each element from the skip list.
33b929
+ * @param sl The skip list
33b929
+ * @param myfree A function to be called for each removed element
33b929
+ */
33b929
+APR_DECLARE(void) apr_skiplist_destroy(apr_skiplist *sl, apr_skiplist_freefunc myfree);
33b929
+
33b929
+/**
6670f0
+ * Return the first element in the skip list, removing the element from the skip list.
33b929
+ * @param sl The skip list
33b929
+ * @param myfree A function to be called for the removed element
33b929
+ * @remark NULL will be returned if there are no elements
33b929
+ */
33b929
+APR_DECLARE(void *) apr_skiplist_pop(apr_skiplist *sl, apr_skiplist_freefunc myfree);
33b929
+
33b929
+/**
33b929
+ * Return the first element in the skip list, leaving the element in the skip list.
33b929
+ * @param sl The skip list
33b929
+ * @remark NULL will be returned if there are no elements
33b929
+ */
33b929
+APR_DECLARE(void *) apr_skiplist_peek(apr_skiplist *sl);
33b929
+
33b929
+/**
33b929
+ * Merge two skip lists.  XXX SEMANTICS
33b929
+ * @param sl1 One of two skip lists to be merged
33b929
+ * @param sl2 The other of two skip lists to be merged
33b929
+ */
33b929
+APR_DECLARE(apr_skiplist *) apr_skiplist_merge(apr_skiplist *sl1, apr_skiplist *sl2);
33b929
+
33b929
+/** @} */
33b929
+
33b929
+#ifdef __cplusplus
33b929
+}
33b929
+#endif
33b929
+
33b929
+#endif /* ! APR_SKIPLIST_H */