a2cdcdd260232b58202b11a9bfc0103c9449ed52Paul Dagnelie/*
a2cdcdd260232b58202b11a9bfc0103c9449ed52Paul Dagnelie * CDDL HEADER START
a2cdcdd260232b58202b11a9bfc0103c9449ed52Paul Dagnelie *
a2cdcdd260232b58202b11a9bfc0103c9449ed52Paul Dagnelie * This file and its contents are supplied under the terms of the
a2cdcdd260232b58202b11a9bfc0103c9449ed52Paul Dagnelie * Common Development and Distribution License ("CDDL"), version 1.0.
a2cdcdd260232b58202b11a9bfc0103c9449ed52Paul Dagnelie * You may only use this file in accordance with the terms of version
a2cdcdd260232b58202b11a9bfc0103c9449ed52Paul Dagnelie * 1.0 of the CDDL.
a2cdcdd260232b58202b11a9bfc0103c9449ed52Paul Dagnelie *
a2cdcdd260232b58202b11a9bfc0103c9449ed52Paul Dagnelie * A full copy of the text of the CDDL should have accompanied this
a2cdcdd260232b58202b11a9bfc0103c9449ed52Paul Dagnelie * source. A copy of the CDDL is also available via the Internet at
a2cdcdd260232b58202b11a9bfc0103c9449ed52Paul Dagnelie * http://www.illumos.org/license/CDDL.
a2cdcdd260232b58202b11a9bfc0103c9449ed52Paul Dagnelie *
a2cdcdd260232b58202b11a9bfc0103c9449ed52Paul Dagnelie * CDDL HEADER END
a2cdcdd260232b58202b11a9bfc0103c9449ed52Paul Dagnelie */
a2cdcdd260232b58202b11a9bfc0103c9449ed52Paul Dagnelie/*
a2cdcdd260232b58202b11a9bfc0103c9449ed52Paul Dagnelie * Copyright (c) 2014 by Delphix. All rights reserved.
a2cdcdd260232b58202b11a9bfc0103c9449ed52Paul Dagnelie */
a2cdcdd260232b58202b11a9bfc0103c9449ed52Paul Dagnelie
a2cdcdd260232b58202b11a9bfc0103c9449ed52Paul Dagnelie#include <sys/bqueue.h>
a2cdcdd260232b58202b11a9bfc0103c9449ed52Paul Dagnelie#include <sys/zfs_context.h>
a2cdcdd260232b58202b11a9bfc0103c9449ed52Paul Dagnelie
a2cdcdd260232b58202b11a9bfc0103c9449ed52Paul Dagneliestatic inline bqueue_node_t *
a2cdcdd260232b58202b11a9bfc0103c9449ed52Paul Dagnelieobj2node(bqueue_t *q, void *data)
a2cdcdd260232b58202b11a9bfc0103c9449ed52Paul Dagnelie{
a2cdcdd260232b58202b11a9bfc0103c9449ed52Paul Dagnelie return ((bqueue_node_t *)((char *)data + q->bq_node_offset));
a2cdcdd260232b58202b11a9bfc0103c9449ed52Paul Dagnelie}
a2cdcdd260232b58202b11a9bfc0103c9449ed52Paul Dagnelie
a2cdcdd260232b58202b11a9bfc0103c9449ed52Paul Dagnelie/*
a2cdcdd260232b58202b11a9bfc0103c9449ed52Paul Dagnelie * Initialize a blocking queue The maximum capacity of the queue is set to
a2cdcdd260232b58202b11a9bfc0103c9449ed52Paul Dagnelie * size. Types that want to be stored in a bqueue must contain a bqueue_node_t,
a2cdcdd260232b58202b11a9bfc0103c9449ed52Paul Dagnelie * and offset should give its offset from the start of the struct. Return 0 on
a2cdcdd260232b58202b11a9bfc0103c9449ed52Paul Dagnelie * success, or -1 on failure.
a2cdcdd260232b58202b11a9bfc0103c9449ed52Paul Dagnelie */
a2cdcdd260232b58202b11a9bfc0103c9449ed52Paul Dagnelieint
a2cdcdd260232b58202b11a9bfc0103c9449ed52Paul Dagneliebqueue_init(bqueue_t *q, uint64_t size, size_t node_offset)
a2cdcdd260232b58202b11a9bfc0103c9449ed52Paul Dagnelie{
a2cdcdd260232b58202b11a9bfc0103c9449ed52Paul Dagnelie list_create(&q->bq_list, node_offset + sizeof (bqueue_node_t),
a2cdcdd260232b58202b11a9bfc0103c9449ed52Paul Dagnelie node_offset + offsetof(bqueue_node_t, bqn_node));
a2cdcdd260232b58202b11a9bfc0103c9449ed52Paul Dagnelie cv_init(&q->bq_add_cv, NULL, CV_DEFAULT, NULL);
a2cdcdd260232b58202b11a9bfc0103c9449ed52Paul Dagnelie cv_init(&q->bq_pop_cv, NULL, CV_DEFAULT, NULL);
a2cdcdd260232b58202b11a9bfc0103c9449ed52Paul Dagnelie mutex_init(&q->bq_lock, NULL, MUTEX_DEFAULT, NULL);
a2cdcdd260232b58202b11a9bfc0103c9449ed52Paul Dagnelie q->bq_node_offset = node_offset;
a2cdcdd260232b58202b11a9bfc0103c9449ed52Paul Dagnelie q->bq_size = 0;
a2cdcdd260232b58202b11a9bfc0103c9449ed52Paul Dagnelie q->bq_maxsize = size;
a2cdcdd260232b58202b11a9bfc0103c9449ed52Paul Dagnelie return (0);
a2cdcdd260232b58202b11a9bfc0103c9449ed52Paul Dagnelie}
a2cdcdd260232b58202b11a9bfc0103c9449ed52Paul Dagnelie
a2cdcdd260232b58202b11a9bfc0103c9449ed52Paul Dagnelie/*
a2cdcdd260232b58202b11a9bfc0103c9449ed52Paul Dagnelie * Destroy a blocking queue. This function asserts that there are no
a2cdcdd260232b58202b11a9bfc0103c9449ed52Paul Dagnelie * elements in the queue, and no one is blocked on the condition
a2cdcdd260232b58202b11a9bfc0103c9449ed52Paul Dagnelie * variables.
a2cdcdd260232b58202b11a9bfc0103c9449ed52Paul Dagnelie */
a2cdcdd260232b58202b11a9bfc0103c9449ed52Paul Dagnelievoid
a2cdcdd260232b58202b11a9bfc0103c9449ed52Paul Dagneliebqueue_destroy(bqueue_t *q)
a2cdcdd260232b58202b11a9bfc0103c9449ed52Paul Dagnelie{
a2cdcdd260232b58202b11a9bfc0103c9449ed52Paul Dagnelie ASSERT0(q->bq_size);
a2cdcdd260232b58202b11a9bfc0103c9449ed52Paul Dagnelie cv_destroy(&q->bq_add_cv);
a2cdcdd260232b58202b11a9bfc0103c9449ed52Paul Dagnelie cv_destroy(&q->bq_pop_cv);
a2cdcdd260232b58202b11a9bfc0103c9449ed52Paul Dagnelie mutex_destroy(&q->bq_lock);
a2cdcdd260232b58202b11a9bfc0103c9449ed52Paul Dagnelie list_destroy(&q->bq_list);
a2cdcdd260232b58202b11a9bfc0103c9449ed52Paul Dagnelie}
a2cdcdd260232b58202b11a9bfc0103c9449ed52Paul Dagnelie
a2cdcdd260232b58202b11a9bfc0103c9449ed52Paul Dagnelie/*
a2cdcdd260232b58202b11a9bfc0103c9449ed52Paul Dagnelie * Add data to q, consuming size units of capacity. If there is insufficient
a2cdcdd260232b58202b11a9bfc0103c9449ed52Paul Dagnelie * capacity to consume size units, block until capacity exists. Asserts size is
a2cdcdd260232b58202b11a9bfc0103c9449ed52Paul Dagnelie * > 0.
a2cdcdd260232b58202b11a9bfc0103c9449ed52Paul Dagnelie */
a2cdcdd260232b58202b11a9bfc0103c9449ed52Paul Dagnelievoid
a2cdcdd260232b58202b11a9bfc0103c9449ed52Paul Dagneliebqueue_enqueue(bqueue_t *q, void *data, uint64_t item_size)
a2cdcdd260232b58202b11a9bfc0103c9449ed52Paul Dagnelie{
a2cdcdd260232b58202b11a9bfc0103c9449ed52Paul Dagnelie ASSERT3U(item_size, >, 0);
a2cdcdd260232b58202b11a9bfc0103c9449ed52Paul Dagnelie ASSERT3U(item_size, <, q->bq_maxsize);
a2cdcdd260232b58202b11a9bfc0103c9449ed52Paul Dagnelie mutex_enter(&q->bq_lock);
a2cdcdd260232b58202b11a9bfc0103c9449ed52Paul Dagnelie obj2node(q, data)->bqn_size = item_size;
a2cdcdd260232b58202b11a9bfc0103c9449ed52Paul Dagnelie while (q->bq_size + item_size > q->bq_maxsize) {
a2cdcdd260232b58202b11a9bfc0103c9449ed52Paul Dagnelie cv_wait(&q->bq_add_cv, &q->bq_lock);
a2cdcdd260232b58202b11a9bfc0103c9449ed52Paul Dagnelie }
a2cdcdd260232b58202b11a9bfc0103c9449ed52Paul Dagnelie q->bq_size += item_size;
a2cdcdd260232b58202b11a9bfc0103c9449ed52Paul Dagnelie list_insert_tail(&q->bq_list, data);
a2cdcdd260232b58202b11a9bfc0103c9449ed52Paul Dagnelie cv_signal(&q->bq_pop_cv);
a2cdcdd260232b58202b11a9bfc0103c9449ed52Paul Dagnelie mutex_exit(&q->bq_lock);
a2cdcdd260232b58202b11a9bfc0103c9449ed52Paul Dagnelie}
a2cdcdd260232b58202b11a9bfc0103c9449ed52Paul Dagnelie/*
a2cdcdd260232b58202b11a9bfc0103c9449ed52Paul Dagnelie * Take the first element off of q. If there are no elements on the queue, wait
a2cdcdd260232b58202b11a9bfc0103c9449ed52Paul Dagnelie * until one is put there. Return the removed element.
a2cdcdd260232b58202b11a9bfc0103c9449ed52Paul Dagnelie */
a2cdcdd260232b58202b11a9bfc0103c9449ed52Paul Dagnelievoid *
a2cdcdd260232b58202b11a9bfc0103c9449ed52Paul Dagneliebqueue_dequeue(bqueue_t *q)
a2cdcdd260232b58202b11a9bfc0103c9449ed52Paul Dagnelie{
a2cdcdd260232b58202b11a9bfc0103c9449ed52Paul Dagnelie void *ret;
a2cdcdd260232b58202b11a9bfc0103c9449ed52Paul Dagnelie uint64_t item_size;
a2cdcdd260232b58202b11a9bfc0103c9449ed52Paul Dagnelie mutex_enter(&q->bq_lock);
a2cdcdd260232b58202b11a9bfc0103c9449ed52Paul Dagnelie while (q->bq_size == 0) {
a2cdcdd260232b58202b11a9bfc0103c9449ed52Paul Dagnelie cv_wait(&q->bq_pop_cv, &q->bq_lock);
a2cdcdd260232b58202b11a9bfc0103c9449ed52Paul Dagnelie }
a2cdcdd260232b58202b11a9bfc0103c9449ed52Paul Dagnelie ret = list_remove_head(&q->bq_list);
a2cdcdd260232b58202b11a9bfc0103c9449ed52Paul Dagnelie item_size = obj2node(q, ret)->bqn_size;
a2cdcdd260232b58202b11a9bfc0103c9449ed52Paul Dagnelie q->bq_size -= item_size;
a2cdcdd260232b58202b11a9bfc0103c9449ed52Paul Dagnelie mutex_exit(&q->bq_lock);
a2cdcdd260232b58202b11a9bfc0103c9449ed52Paul Dagnelie cv_signal(&q->bq_add_cv);
a2cdcdd260232b58202b11a9bfc0103c9449ed52Paul Dagnelie return (ret);
a2cdcdd260232b58202b11a9bfc0103c9449ed52Paul Dagnelie}
a2cdcdd260232b58202b11a9bfc0103c9449ed52Paul Dagnelie
a2cdcdd260232b58202b11a9bfc0103c9449ed52Paul Dagnelie/*
a2cdcdd260232b58202b11a9bfc0103c9449ed52Paul Dagnelie * Returns true if the space used is 0.
a2cdcdd260232b58202b11a9bfc0103c9449ed52Paul Dagnelie */
a2cdcdd260232b58202b11a9bfc0103c9449ed52Paul Dagnelieboolean_t
a2cdcdd260232b58202b11a9bfc0103c9449ed52Paul Dagneliebqueue_empty(bqueue_t *q)
a2cdcdd260232b58202b11a9bfc0103c9449ed52Paul Dagnelie{
a2cdcdd260232b58202b11a9bfc0103c9449ed52Paul Dagnelie return (q->bq_size == 0);
a2cdcdd260232b58202b11a9bfc0103c9449ed52Paul Dagnelie}