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