2N/A/*
2N/A * CDDL HEADER START
2N/A *
2N/A * The contents of this file are subject to the terms of the
2N/A * Common Development and Distribution License (the "License").
2N/A * You may not use this file except in compliance with the License.
2N/A *
2N/A * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
2N/A * or http://www.opensolaris.org/os/licensing.
2N/A * See the License for the specific language governing permissions
2N/A * and limitations under the License.
2N/A *
2N/A * When distributing Covered Code, include this CDDL HEADER in each
2N/A * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
2N/A * If applicable, add the following below this CDDL HEADER, with the
2N/A * fields enclosed by brackets "[]" replaced with your own identifying
2N/A * information: Portions Copyright [yyyy] [name of copyright owner]
2N/A *
2N/A * CDDL HEADER END
2N/A */
2N/A/*
2N/A * Copyright (c) 2009, 2011, Oracle and/or its affiliates. All rights reserved.
2N/A */
2N/A
2N/A/*
2N/A * Common implementation for priority queues. Currently we have only a single
2N/A * priority queue per handle, so this may be a little overboard, but this
2N/A * isolates the implementation and allows us to easily expand in the future.
2N/A */
2N/A
2N/A#include <shadow_impl.h>
2N/A
2N/Aint
2N/Ashadow_pq_enqueue(shadow_pq_t *pqp, void *p)
2N/A{
2N/A uint_t i, j;
2N/A uint64_t ip, jp;
2N/A
2N/A if (pqp->shpq_last + 1 == pqp->shpq_size) {
2N/A void **items;
2N/A uint_t size = pqp->shpq_size * 2;
2N/A
2N/A items = shadow_zalloc(sizeof (void *) * size);
2N/A if (items == NULL)
2N/A return (-1);
2N/A
2N/A bcopy(pqp->shpq_items, items, sizeof (void *) * pqp->shpq_size);
2N/A free(pqp->shpq_items);
2N/A pqp->shpq_items = items;
2N/A pqp->shpq_size = size;
2N/A }
2N/A
2N/A assert(pqp->shpq_last + 1 < pqp->shpq_size);
2N/A
2N/A i = ++pqp->shpq_last;
2N/A pqp->shpq_items[i] = p;
2N/A ip = pqp->shpq_priority(p);
2N/A
2N/A /*
2N/A * Bubble the node up until heap criteria are met.
2N/A */
2N/A for (; i != 1; i = j) {
2N/A j = i / 2;
2N/A jp = pqp->shpq_priority(pqp->shpq_items[j]);
2N/A
2N/A if (jp < ip)
2N/A break;
2N/A
2N/A /* Swap parent and child. */
2N/A p = pqp->shpq_items[i];
2N/A pqp->shpq_items[i] = pqp->shpq_items[j];
2N/A pqp->shpq_items[j] = p;
2N/A }
2N/A
2N/A return (0);
2N/A}
2N/A
2N/Astatic void
2N/Ashadow_pq_remove_common(shadow_pq_t *pqp, uint_t i)
2N/A{
2N/A uint_t c;
2N/A uint64_t ip, cp0, cp1, cp;
2N/A void *p;
2N/A
2N/A assert(i <= pqp->shpq_last && i != 0);
2N/A assert(pqp->shpq_items[i] != NULL);
2N/A
2N/A pqp->shpq_items[i] = pqp->shpq_items[pqp->shpq_last];
2N/A pqp->shpq_items[pqp->shpq_last] = NULL;
2N/A pqp->shpq_last--;
2N/A
2N/A if (pqp->shpq_last < i)
2N/A return;
2N/A
2N/A ip = pqp->shpq_priority(pqp->shpq_items[i]);
2N/A
2N/A for (; i * 2 <= pqp->shpq_last; i = c) {
2N/A if (pqp->shpq_items[i * 2 + 1] == NULL) {
2N/A if (pqp->shpq_items[i * 2] == NULL)
2N/A break;
2N/A c = i * 2;
2N/A cp = pqp->shpq_priority(pqp->shpq_items[c]);
2N/A } else {
2N/A assert(pqp->shpq_items[i * 2] != NULL);
2N/A cp0 = pqp->shpq_priority(pqp->shpq_items[i * 2]);
2N/A cp1 = pqp->shpq_priority(pqp->shpq_items[i * 2 + 1]);
2N/A
2N/A /* Choose the child with lower priority. */
2N/A if (cp0 < cp1) {
2N/A c = i * 2;
2N/A cp = cp0;
2N/A } else {
2N/A c = i * 2 + 1;
2N/A cp = cp1;
2N/A }
2N/A }
2N/A
2N/A if (ip <= cp)
2N/A break;
2N/A
2N/A /* Swap parent and (smaller) child. */
2N/A p = pqp->shpq_items[i];
2N/A pqp->shpq_items[i] = pqp->shpq_items[c];
2N/A pqp->shpq_items[c] = p;
2N/A }
2N/A
2N/A /*
2N/A * Try to shrink the table if it's more than four times the required
2N/A * size. If we can't allocate memory, just press on.
2N/A */
2N/A if (pqp->shpq_last * 4 < pqp->shpq_size) {
2N/A void **items;
2N/A uint_t size = pqp->shpq_size / 2;
2N/A while (size * 2 < pqp->shpq_size) {
2N/A size /= 2;
2N/A }
2N/A
2N/A items = shadow_alloc(sizeof (void *) * size);
2N/A if (items != NULL) {
2N/A bcopy(pqp->shpq_items, items, sizeof (void *) * size);
2N/A free(pqp->shpq_items);
2N/A pqp->shpq_items = items;
2N/A pqp->shpq_size = size;
2N/A }
2N/A }
2N/A}
2N/A
2N/Avoid *
2N/Ashadow_pq_dequeue(shadow_pq_t *pqp)
2N/A{
2N/A void *p;
2N/A
2N/A if (pqp->shpq_last == 0)
2N/A return (NULL);
2N/A
2N/A p = pqp->shpq_items[1];
2N/A shadow_pq_remove_common(pqp, 1);
2N/A return (p);
2N/A}
2N/A
2N/Avoid *
2N/Ashadow_pq_peek(shadow_pq_t *pqp)
2N/A{
2N/A if (pqp->shpq_last == 0)
2N/A return (NULL);
2N/A
2N/A return (pqp->shpq_items[1]);
2N/A}
2N/A
2N/A/*
2N/A * Remove an element from the heap. This is a O(n) operation so should not be
2N/A * used for common operations. This could be improved (to O(log n)) by having
2N/A * each node keep track of its index.
2N/A */
2N/Aint
2N/Ashadow_pq_remove(shadow_pq_t *pqp, void *p)
2N/A{
2N/A uint_t i;
2N/A
2N/A for (i = 1; i <= pqp->shpq_last; i++) {
2N/A if (pqp->shpq_items[i] == p) {
2N/A shadow_pq_remove_common(pqp, i);
2N/A return (0);
2N/A }
2N/A }
2N/A
2N/A return (-1);
2N/A}
2N/A
2N/Aint
2N/Ashadow_pq_iter(shadow_pq_t *pqp, int (*callback)(shadow_pq_t *, void *,
2N/A void *), void *data)
2N/A{
2N/A uint_t i;
2N/A int ret;
2N/A
2N/A for (i = 1; i <= pqp->shpq_last; i++) {
2N/A if ((ret = callback(pqp, pqp->shpq_items[i], data)) != 0)
2N/A return (ret);
2N/A }
2N/A
2N/A return (0);
2N/A}
2N/A
2N/Aint
2N/Ashadow_pq_init(shadow_pq_t *pqp, shadow_pq_priority_f *cb)
2N/A{
2N/A pqp->shpq_size = (1 << 2); /* must be a power of two */
2N/A pqp->shpq_last = 0;
2N/A pqp->shpq_priority = cb;
2N/A pqp->shpq_items = shadow_zalloc(sizeof (void *) * pqp->shpq_size);
2N/A
2N/A return (pqp->shpq_items == NULL ? -1 : 0);
2N/A}
2N/A
2N/Avoid
2N/Ashadow_pq_fini(shadow_pq_t *pqp)
2N/A{
2N/A free(pqp->shpq_items);
2N/A bzero(pqp, sizeof (shadow_pq_t));
2N/A}