1303095Ssobomax/* 2303095Ssobomax * Copyright (c) 2004-2016 Maxim Sobolev <sobomax@FreeBSD.org> 3303095Ssobomax * All rights reserved. 4303095Ssobomax * 5303095Ssobomax * Redistribution and use in source and binary forms, with or without 6303095Ssobomax * modification, are permitted provided that the following conditions 7303095Ssobomax * are met: 8303095Ssobomax * 1. Redistributions of source code must retain the above copyright 9303095Ssobomax * notice, this list of conditions and the following disclaimer. 10303095Ssobomax * 2. Redistributions in binary form must reproduce the above copyright 11303095Ssobomax * notice, this list of conditions and the following disclaimer in the 12303095Ssobomax * documentation and/or other materials provided with the distribution. 13303095Ssobomax * 14303095Ssobomax * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15303095Ssobomax * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16303095Ssobomax * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17303095Ssobomax * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 18303095Ssobomax * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19303095Ssobomax * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20303095Ssobomax * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21303095Ssobomax * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22303095Ssobomax * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23303095Ssobomax * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24303095Ssobomax * SUCH DAMAGE. 25303095Ssobomax */ 26303095Ssobomax 27303095Ssobomax#include <sys/cdefs.h> 28303095Ssobomax__FBSDID("$FreeBSD$"); 29303095Ssobomax 30303095Ssobomax#include <err.h> 31303095Ssobomax#include <pthread.h> 32303095Ssobomax#include <stdint.h> 33303095Ssobomax#include <stdlib.h> 34303095Ssobomax 35303095Ssobomax#if defined(MKUZ_DEBUG) 36303095Ssobomax# include <assert.h> 37303095Ssobomax#endif 38303095Ssobomax 39303095Ssobomax#include "mkuzip.h" 40303095Ssobomax#include "mkuz_fqueue.h" 41303095Ssobomax#include "mkuz_conveyor.h" 42303095Ssobomax#include "mkuz_blk.h" 43303095Ssobomax#include "mkuz_blk_chain.h" 44303095Ssobomax 45303095Ssobomaxstruct mkuz_fifo_queue * 46303095Ssobomaxmkuz_fqueue_ctor(int wakeup_len) 47303095Ssobomax{ 48303095Ssobomax struct mkuz_fifo_queue *fqp; 49303095Ssobomax 50303095Ssobomax fqp = mkuz_safe_zmalloc(sizeof(struct mkuz_fifo_queue)); 51303095Ssobomax fqp->wakeup_len = wakeup_len; 52303095Ssobomax if (pthread_mutex_init(&fqp->mtx, NULL) != 0) { 53303095Ssobomax errx(1, "pthread_mutex_init() failed"); 54303095Ssobomax } 55303095Ssobomax if (pthread_cond_init(&fqp->cvar, NULL) != 0) { 56303095Ssobomax errx(1, "pthread_cond_init() failed"); 57303095Ssobomax } 58303095Ssobomax return (fqp); 59303095Ssobomax} 60303095Ssobomax 61303095Ssobomaxvoid 62303095Ssobomaxmkuz_fqueue_enq(struct mkuz_fifo_queue *fqp, struct mkuz_blk *bp) 63303095Ssobomax{ 64303095Ssobomax struct mkuz_bchain_link *ip; 65303095Ssobomax 66303095Ssobomax ip = mkuz_safe_zmalloc(sizeof(struct mkuz_bchain_link)); 67303095Ssobomax ip->this = bp; 68303095Ssobomax 69303095Ssobomax pthread_mutex_lock(&fqp->mtx); 70303095Ssobomax if (fqp->first != NULL) { 71303095Ssobomax fqp->first->prev = ip; 72303095Ssobomax } else { 73303095Ssobomax fqp->last = ip; 74303095Ssobomax } 75303095Ssobomax fqp->first = ip; 76303095Ssobomax fqp->length += 1; 77303095Ssobomax if (fqp->length >= fqp->wakeup_len) { 78303095Ssobomax pthread_cond_signal(&fqp->cvar); 79303095Ssobomax } 80303095Ssobomax pthread_mutex_unlock(&fqp->mtx); 81303095Ssobomax} 82303095Ssobomax 83303095Ssobomax#if defined(NOTYET) 84303095Ssobomaxint 85303095Ssobomaxmkuz_fqueue_enq_all(struct mkuz_fifo_queue *fqp, struct mkuz_bchain_link *cip_f, 86303095Ssobomax struct mkuz_bchain_link *cip_l, int clen) 87303095Ssobomax{ 88303095Ssobomax int rval; 89303095Ssobomax 90303095Ssobomax pthread_mutex_lock(&fqp->mtx); 91303095Ssobomax if (fqp->first != NULL) { 92303095Ssobomax fqp->first->prev = cip_l; 93303095Ssobomax } else { 94303095Ssobomax fqp->last = cip_l; 95303095Ssobomax } 96303095Ssobomax fqp->first = cip_f; 97303095Ssobomax fqp->length += clen; 98303095Ssobomax rval = fqp->length; 99303095Ssobomax if (fqp->length >= fqp->wakeup_len) { 100303095Ssobomax pthread_cond_signal(&fqp->cvar); 101303095Ssobomax } 102303095Ssobomax pthread_mutex_unlock(&fqp->mtx); 103303095Ssobomax return (rval); 104303095Ssobomax} 105303095Ssobomax#endif 106303095Ssobomax 107303095Ssobomaxstatic int 108303095Ssobomaxmkuz_fqueue_check(struct mkuz_fifo_queue *fqp, cmp_cb_t cmp_cb, void *cap) 109303095Ssobomax{ 110303095Ssobomax struct mkuz_bchain_link *ip; 111303095Ssobomax 112303095Ssobomax for (ip = fqp->last; ip != NULL; ip = ip->prev) { 113303095Ssobomax if (cmp_cb(ip->this, cap)) { 114303095Ssobomax return (1); 115303095Ssobomax } 116303095Ssobomax } 117303095Ssobomax return (0); 118303095Ssobomax} 119303095Ssobomax 120303095Ssobomaxstruct mkuz_blk * 121303095Ssobomaxmkuz_fqueue_deq_when(struct mkuz_fifo_queue *fqp, cmp_cb_t cmp_cb, void *cap) 122303095Ssobomax{ 123303095Ssobomax struct mkuz_bchain_link *ip, *newlast, *newfirst, *mip; 124303095Ssobomax struct mkuz_blk *bp; 125303095Ssobomax 126303095Ssobomax pthread_mutex_lock(&fqp->mtx); 127303095Ssobomax while (fqp->last == NULL || !mkuz_fqueue_check(fqp, cmp_cb, cap)) { 128303095Ssobomax pthread_cond_wait(&fqp->cvar, &fqp->mtx); 129303095Ssobomax } 130303095Ssobomax if (cmp_cb(fqp->last->this, cap)) { 131303095Ssobomax mip = fqp->last; 132303095Ssobomax fqp->last = mip->prev; 133303095Ssobomax if (fqp->last == NULL) { 134303095Ssobomax#if defined(MKUZ_DEBUG) 135303095Ssobomax assert(fqp->length == 1); 136303095Ssobomax#endif 137303095Ssobomax fqp->first = NULL; 138303095Ssobomax } 139303095Ssobomax } else { 140303095Ssobomax#if defined(MKUZ_DEBUG) 141303095Ssobomax assert(fqp->length > 1); 142303095Ssobomax#endif 143303095Ssobomax newfirst = newlast = fqp->last; 144303095Ssobomax mip = NULL; 145303095Ssobomax for (ip = fqp->last->prev; ip != NULL; ip = ip->prev) { 146303095Ssobomax if (cmp_cb(ip->this, cap)) { 147303095Ssobomax mip = ip; 148303095Ssobomax continue; 149303095Ssobomax } 150303095Ssobomax newfirst->prev = ip; 151303095Ssobomax newfirst = ip; 152303095Ssobomax } 153303095Ssobomax newfirst->prev = NULL; 154303095Ssobomax fqp->first = newfirst; 155303095Ssobomax fqp->last = newlast; 156303095Ssobomax } 157303095Ssobomax fqp->length -= 1; 158303095Ssobomax pthread_mutex_unlock(&fqp->mtx); 159303095Ssobomax bp = mip->this; 160303095Ssobomax free(mip); 161303095Ssobomax 162303095Ssobomax return bp; 163303095Ssobomax} 164303095Ssobomax 165303095Ssobomaxstruct mkuz_blk * 166303095Ssobomaxmkuz_fqueue_deq(struct mkuz_fifo_queue *fqp) 167303095Ssobomax{ 168303095Ssobomax struct mkuz_bchain_link *ip; 169303095Ssobomax struct mkuz_blk *bp; 170303095Ssobomax 171303095Ssobomax pthread_mutex_lock(&fqp->mtx); 172303095Ssobomax while (fqp->last == NULL) { 173303095Ssobomax pthread_cond_wait(&fqp->cvar, &fqp->mtx); 174303095Ssobomax } 175303095Ssobomax#if defined(MKUZ_DEBUG) 176303095Ssobomax assert(fqp->length > 0); 177303095Ssobomax#endif 178303095Ssobomax ip = fqp->last; 179303095Ssobomax fqp->last = ip->prev; 180303095Ssobomax if (fqp->last == NULL) { 181303095Ssobomax#if defined(MKUZ_DEBUG) 182303095Ssobomax assert(fqp->length == 1); 183303095Ssobomax#endif 184303095Ssobomax fqp->first = NULL; 185303095Ssobomax } 186303095Ssobomax fqp->length -= 1; 187303095Ssobomax pthread_mutex_unlock(&fqp->mtx); 188303095Ssobomax bp = ip->this; 189303095Ssobomax free(ip); 190303095Ssobomax 191303095Ssobomax return bp; 192303095Ssobomax} 193303095Ssobomax 194303095Ssobomax#if defined(NOTYET) 195303095Ssobomaxstruct mkuz_bchain_link * 196303095Ssobomaxmkuz_fqueue_deq_all(struct mkuz_fifo_queue *fqp, int *rclen) 197303095Ssobomax{ 198303095Ssobomax struct mkuz_bchain_link *rchain; 199303095Ssobomax 200303095Ssobomax pthread_mutex_lock(&fqp->mtx); 201303095Ssobomax while (fqp->last == NULL) { 202303095Ssobomax pthread_cond_wait(&fqp->cvar, &fqp->mtx); 203303095Ssobomax } 204303095Ssobomax#if defined(MKUZ_DEBUG) 205303095Ssobomax assert(fqp->length > 0); 206303095Ssobomax#endif 207303095Ssobomax rchain = fqp->last; 208303095Ssobomax fqp->first = fqp->last = NULL; 209303095Ssobomax *rclen = fqp->length; 210303095Ssobomax fqp->length = 0; 211303095Ssobomax pthread_mutex_unlock(&fqp->mtx); 212303095Ssobomax return (rchain); 213303095Ssobomax} 214303095Ssobomax#endif 215