OpenDNSSEC-signer  1.3.8
/build/buildd/opendnssec-1.3.8/signer/src/scheduler/fifoq.c
Go to the documentation of this file.
00001 /*
00002  * $Id$
00003  *
00004  * Copyright (c) 2011 NLNet Labs. All rights reserved.
00005  *
00006  * Redistribution and use in source and binary forms, with or without
00007  * modification, are permitted provided that the following conditions
00008  * are met:
00009  * 1. Redistributions of source code must retain the above copyright
00010  *    notice, this list of conditions and the following disclaimer.
00011  * 2. Redistributions in binary form must reproduce the above copyright
00012  *    notice, this list of conditions and the following disclaimer in the
00013  *    documentation and/or other materials provided with the distribution.
00014  *
00015  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
00016  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
00017  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
00018  * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
00019  * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
00020  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
00021  * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
00022  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
00023  * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
00024  * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
00025  * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
00026  *
00027  */
00028 
00034 #include "config.h"
00035 #include "daemon/worker.h"
00036 #include "scheduler/fifoq.h"
00037 #include "shared/allocator.h"
00038 #include "shared/log.h"
00039 
00040 #include <ldns/ldns.h>
00041 
00042 static const char* fifoq_str = "fifo";
00043 
00044 
00049 fifoq_type*
00050 fifoq_create(allocator_type* allocator)
00051 {
00052     fifoq_type* fifoq;
00053     if (!allocator) {
00054         ods_log_error("[%s] unable to create: no allocator available",
00055             fifoq_str);
00056         return NULL;
00057     }
00058     ods_log_assert(allocator);
00059 
00060     fifoq = (fifoq_type*) allocator_alloc(allocator, sizeof(fifoq_type));
00061     if (!fifoq) {
00062         ods_log_error("[%s] unable to create: allocator failed", fifoq_str);
00063         return NULL;
00064     }
00065     ods_log_assert(fifoq);
00066 
00067     fifoq->allocator = allocator;
00068     fifoq_wipe(fifoq);
00069     lock_basic_init(&fifoq->q_lock);
00070     lock_basic_set(&fifoq->q_threshold);
00071     lock_basic_set(&fifoq->q_nonfull);
00072     return fifoq;
00073 }
00074 
00075 
00080 void
00081 fifoq_wipe(fifoq_type* q)
00082 {
00083     size_t i = 0;
00084 
00085     for (i=0; i < FIFOQ_MAX_COUNT; i++) {
00086         q->blob[i] = NULL;
00087         q->owner[i] = NULL;
00088     }
00089     q->count = 0;
00090     return;
00091 }
00092 
00093 
00098 void*
00099 fifoq_pop(fifoq_type* q, worker_type** worker)
00100 {
00101     void* pop = NULL;
00102     size_t i = 0;
00103 
00104     if (!q) {
00105         return NULL;
00106     }
00107     if (q->count <= 0) {
00108         return NULL;
00109     }
00110 
00111     pop = q->blob[0];
00112     *worker = q->owner[0];
00113     for (i = 0; i < q->count-1; i++) {
00114         q->blob[i] = q->blob[i+1];
00115         q->owner[i] = q->owner[i+1];
00116     }
00117     q->count -= 1;
00118 
00119     if (q->count <= (size_t) FIFOQ_MAX_COUNT * 0.1) {
00120         /* notify waiting workers that they can start queuing again */
00121         lock_basic_broadcast(&q->q_nonfull);
00122     }
00123     return pop;
00124 }
00125 
00126 
00131 ods_status
00132 fifoq_push(fifoq_type* q, void* item, worker_type* worker, int* tries)
00133 {
00134     if (!item) {
00135         ods_log_error("[%s] unable to push item: no item", fifoq_str);
00136         return ODS_STATUS_ASSERT_ERR;
00137     }
00138     ods_log_assert(item);
00139     if (!q) {
00140         ods_log_error("[%s] unable to push item: no queue", fifoq_str);
00141         return ODS_STATUS_ASSERT_ERR;
00142     }
00143     ods_log_assert(q);
00144 
00145     if (q->count >= FIFOQ_MAX_COUNT) {
00146         /* #262 if drudgers remain on hold, do additional broadcast */
00147         if (*tries > FIFOQ_TRIES_COUNT) {
00148             lock_basic_broadcast(&q->q_threshold);
00149             ods_log_debug("[%s] queue full, notify drudgers again", fifoq_str);
00150             /* reset tries */
00151             *tries = 0;
00152         }
00153         return ODS_STATUS_UNCHANGED;
00154     }
00155 
00156     q->blob[q->count] = item;
00157     q->owner[q->count] = worker;
00158     q->count += 1;
00159     if (q->count == 1) {
00160         lock_basic_broadcast(&q->q_threshold);
00161         ods_log_deeebug("[%s] threshold %u reached, notify drudgers",
00162             fifoq_str, q->count);
00163     }
00164     return ODS_STATUS_OK;
00165 }
00166 
00167 
00172 void
00173 fifoq_cleanup(fifoq_type* q)
00174 {
00175     allocator_type* allocator;
00176     lock_basic_type q_lock;
00177     cond_basic_type q_threshold;
00178     cond_basic_type q_nonfull;
00179 
00180     if (!q) {
00181         return;
00182     }
00183     ods_log_assert(q);
00184     allocator = q->allocator;
00185     q_lock = q->q_lock;
00186     q_threshold = q->q_threshold;
00187     q_nonfull = q->q_nonfull;
00188 
00189     allocator_deallocate(allocator, (void*) q);
00190     lock_basic_off(&q_threshold);
00191     lock_basic_off(&q_nonfull);
00192     lock_basic_destroy(&q_lock);
00193     return;
00194 }