10Sstevel@tonic-gate /*
20Sstevel@tonic-gate * CDDL HEADER START
30Sstevel@tonic-gate *
40Sstevel@tonic-gate * The contents of this file are subject to the terms of the
5*10946SSangeeta.Misra@Sun.COM * Common Development and Distribution License (the "License").
6*10946SSangeeta.Misra@Sun.COM * You may not use this file except in compliance with the License.
70Sstevel@tonic-gate *
80Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
90Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing.
100Sstevel@tonic-gate * See the License for the specific language governing permissions
110Sstevel@tonic-gate * and limitations under the License.
120Sstevel@tonic-gate *
130Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each
140Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
150Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the
160Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying
170Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner]
180Sstevel@tonic-gate *
190Sstevel@tonic-gate * CDDL HEADER END
200Sstevel@tonic-gate */
210Sstevel@tonic-gate /*
22*10946SSangeeta.Misra@Sun.COM * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
230Sstevel@tonic-gate * Use is subject to license terms.
240Sstevel@tonic-gate */
250Sstevel@tonic-gate
260Sstevel@tonic-gate #include <stdlib.h>
270Sstevel@tonic-gate #include <limits.h>
280Sstevel@tonic-gate #include <sys/time.h>
290Sstevel@tonic-gate #include <sys/types.h>
300Sstevel@tonic-gate #include <sys/sysmacros.h>
310Sstevel@tonic-gate #include <sys/stropts.h> /* INFTIM */
320Sstevel@tonic-gate
330Sstevel@tonic-gate #include <libinetutil.h>
340Sstevel@tonic-gate #include "libinetutil_impl.h"
350Sstevel@tonic-gate
360Sstevel@tonic-gate static iu_timer_node_t *pending_delete_chain = NULL;
370Sstevel@tonic-gate
380Sstevel@tonic-gate static void destroy_timer(iu_tq_t *, iu_timer_node_t *);
390Sstevel@tonic-gate static iu_timer_id_t get_timer_id(iu_tq_t *);
400Sstevel@tonic-gate static void release_timer_id(iu_tq_t *, iu_timer_id_t);
410Sstevel@tonic-gate
420Sstevel@tonic-gate /*
430Sstevel@tonic-gate * iu_tq_create(): creates, initializes and returns a timer queue for use
440Sstevel@tonic-gate *
450Sstevel@tonic-gate * input: void
460Sstevel@tonic-gate * output: iu_tq_t *: the new timer queue
470Sstevel@tonic-gate */
480Sstevel@tonic-gate
490Sstevel@tonic-gate iu_tq_t *
iu_tq_create(void)500Sstevel@tonic-gate iu_tq_create(void)
510Sstevel@tonic-gate {
520Sstevel@tonic-gate return (calloc(1, sizeof (iu_tq_t)));
530Sstevel@tonic-gate }
540Sstevel@tonic-gate
550Sstevel@tonic-gate /*
560Sstevel@tonic-gate * iu_tq_destroy(): destroys an existing timer queue
570Sstevel@tonic-gate *
580Sstevel@tonic-gate * input: iu_tq_t *: the timer queue to destroy
590Sstevel@tonic-gate * output: void
600Sstevel@tonic-gate */
610Sstevel@tonic-gate
620Sstevel@tonic-gate void
iu_tq_destroy(iu_tq_t * tq)630Sstevel@tonic-gate iu_tq_destroy(iu_tq_t *tq)
640Sstevel@tonic-gate {
650Sstevel@tonic-gate iu_timer_node_t *node, *next_node;
660Sstevel@tonic-gate
670Sstevel@tonic-gate for (node = tq->iutq_head; node != NULL; node = next_node) {
680Sstevel@tonic-gate next_node = node->iutn_next;
690Sstevel@tonic-gate destroy_timer(tq, node);
700Sstevel@tonic-gate }
710Sstevel@tonic-gate
720Sstevel@tonic-gate free(tq);
730Sstevel@tonic-gate }
740Sstevel@tonic-gate
750Sstevel@tonic-gate /*
760Sstevel@tonic-gate * insert_timer(): inserts a timer node into a tq's timer list
770Sstevel@tonic-gate *
780Sstevel@tonic-gate * input: iu_tq_t *: the timer queue
790Sstevel@tonic-gate * iu_timer_node_t *: the timer node to insert into the list
800Sstevel@tonic-gate * uint64_t: the number of milliseconds before this timer fires
810Sstevel@tonic-gate * output: void
820Sstevel@tonic-gate */
830Sstevel@tonic-gate
840Sstevel@tonic-gate static void
insert_timer(iu_tq_t * tq,iu_timer_node_t * node,uint64_t msec)850Sstevel@tonic-gate insert_timer(iu_tq_t *tq, iu_timer_node_t *node, uint64_t msec)
860Sstevel@tonic-gate {
870Sstevel@tonic-gate iu_timer_node_t *after = NULL;
880Sstevel@tonic-gate
890Sstevel@tonic-gate /*
900Sstevel@tonic-gate * find the node to insert this new node "after". we do this
910Sstevel@tonic-gate * instead of the more intuitive "insert before" because with
920Sstevel@tonic-gate * the insert before approach, a null `before' node pointer
930Sstevel@tonic-gate * is overloaded in meaning (it could be null because there
940Sstevel@tonic-gate * are no items in the list, or it could be null because this
950Sstevel@tonic-gate * is the last item on the list, which are very different cases).
960Sstevel@tonic-gate */
970Sstevel@tonic-gate
980Sstevel@tonic-gate node->iutn_abs_timeout = gethrtime() + (msec * (NANOSEC / MILLISEC));
990Sstevel@tonic-gate
1000Sstevel@tonic-gate if (tq->iutq_head != NULL &&
1010Sstevel@tonic-gate tq->iutq_head->iutn_abs_timeout < node->iutn_abs_timeout)
1020Sstevel@tonic-gate for (after = tq->iutq_head; after->iutn_next != NULL;
1030Sstevel@tonic-gate after = after->iutn_next)
1040Sstevel@tonic-gate if (after->iutn_next->iutn_abs_timeout >
1050Sstevel@tonic-gate node->iutn_abs_timeout)
1060Sstevel@tonic-gate break;
1070Sstevel@tonic-gate
1080Sstevel@tonic-gate node->iutn_next = after ? after->iutn_next : tq->iutq_head;
1090Sstevel@tonic-gate node->iutn_prev = after;
1100Sstevel@tonic-gate if (after == NULL)
1110Sstevel@tonic-gate tq->iutq_head = node;
1120Sstevel@tonic-gate else
1130Sstevel@tonic-gate after->iutn_next = node;
1140Sstevel@tonic-gate
1150Sstevel@tonic-gate if (node->iutn_next != NULL)
1160Sstevel@tonic-gate node->iutn_next->iutn_prev = node;
1170Sstevel@tonic-gate }
1180Sstevel@tonic-gate
1190Sstevel@tonic-gate /*
1200Sstevel@tonic-gate * remove_timer(): removes a timer node from the tq's timer list
1210Sstevel@tonic-gate *
1220Sstevel@tonic-gate * input: iu_tq_t *: the timer queue
1230Sstevel@tonic-gate * iu_timer_node_t *: the timer node to remove from the list
1240Sstevel@tonic-gate * output: void
1250Sstevel@tonic-gate */
1260Sstevel@tonic-gate
1270Sstevel@tonic-gate static void
remove_timer(iu_tq_t * tq,iu_timer_node_t * node)1280Sstevel@tonic-gate remove_timer(iu_tq_t *tq, iu_timer_node_t *node)
1290Sstevel@tonic-gate {
1300Sstevel@tonic-gate if (node->iutn_next != NULL)
1310Sstevel@tonic-gate node->iutn_next->iutn_prev = node->iutn_prev;
1320Sstevel@tonic-gate if (node->iutn_prev != NULL)
1330Sstevel@tonic-gate node->iutn_prev->iutn_next = node->iutn_next;
1340Sstevel@tonic-gate else
1350Sstevel@tonic-gate tq->iutq_head = node->iutn_next;
1360Sstevel@tonic-gate }
1370Sstevel@tonic-gate
1380Sstevel@tonic-gate /*
1390Sstevel@tonic-gate * destroy_timer(): destroy a timer node
1400Sstevel@tonic-gate *
1410Sstevel@tonic-gate * input: iu_tq_t *: the timer queue the timer node is associated with
1420Sstevel@tonic-gate * iu_timer_node_t *: the node to free
1430Sstevel@tonic-gate * output: void
1440Sstevel@tonic-gate */
1450Sstevel@tonic-gate
1460Sstevel@tonic-gate static void
destroy_timer(iu_tq_t * tq,iu_timer_node_t * node)1470Sstevel@tonic-gate destroy_timer(iu_tq_t *tq, iu_timer_node_t *node)
1480Sstevel@tonic-gate {
1490Sstevel@tonic-gate release_timer_id(tq, node->iutn_timer_id);
1500Sstevel@tonic-gate
1510Sstevel@tonic-gate /*
1520Sstevel@tonic-gate * if we're in expire, don't delete the node yet, since it may
1530Sstevel@tonic-gate * still be referencing it (through the expire_next pointers)
1540Sstevel@tonic-gate */
1550Sstevel@tonic-gate
1560Sstevel@tonic-gate if (tq->iutq_in_expire) {
1570Sstevel@tonic-gate node->iutn_pending_delete++;
1580Sstevel@tonic-gate node->iutn_next = pending_delete_chain;
1590Sstevel@tonic-gate pending_delete_chain = node;
1600Sstevel@tonic-gate } else
1610Sstevel@tonic-gate free(node);
1620Sstevel@tonic-gate
1630Sstevel@tonic-gate }
1640Sstevel@tonic-gate
1650Sstevel@tonic-gate /*
1660Sstevel@tonic-gate * iu_schedule_timer(): creates and inserts a timer in the tq's timer list
1670Sstevel@tonic-gate *
1680Sstevel@tonic-gate * input: iu_tq_t *: the timer queue
1690Sstevel@tonic-gate * uint32_t: the number of seconds before this timer fires
1700Sstevel@tonic-gate * iu_tq_callback_t *: the function to call when the timer fires
1710Sstevel@tonic-gate * void *: an argument to pass to the called back function
1720Sstevel@tonic-gate * output: iu_timer_id_t: the new timer's timer id on success, -1 on failure
1730Sstevel@tonic-gate */
1740Sstevel@tonic-gate
1750Sstevel@tonic-gate iu_timer_id_t
iu_schedule_timer(iu_tq_t * tq,uint32_t sec,iu_tq_callback_t * callback,void * arg)1760Sstevel@tonic-gate iu_schedule_timer(iu_tq_t *tq, uint32_t sec, iu_tq_callback_t *callback,
1770Sstevel@tonic-gate void *arg)
1780Sstevel@tonic-gate {
1790Sstevel@tonic-gate return (iu_schedule_timer_ms(tq, sec * MILLISEC, callback, arg));
1800Sstevel@tonic-gate }
1810Sstevel@tonic-gate
1820Sstevel@tonic-gate /*
1830Sstevel@tonic-gate * iu_schedule_ms_timer(): creates and inserts a timer in the tq's timer list,
1840Sstevel@tonic-gate * using millisecond granularity
1850Sstevel@tonic-gate *
1860Sstevel@tonic-gate * input: iu_tq_t *: the timer queue
1870Sstevel@tonic-gate * uint64_t: the number of milliseconds before this timer fires
1880Sstevel@tonic-gate * iu_tq_callback_t *: the function to call when the timer fires
1890Sstevel@tonic-gate * void *: an argument to pass to the called back function
1900Sstevel@tonic-gate * output: iu_timer_id_t: the new timer's timer id on success, -1 on failure
1910Sstevel@tonic-gate */
1920Sstevel@tonic-gate iu_timer_id_t
iu_schedule_timer_ms(iu_tq_t * tq,uint64_t ms,iu_tq_callback_t * callback,void * arg)1930Sstevel@tonic-gate iu_schedule_timer_ms(iu_tq_t *tq, uint64_t ms, iu_tq_callback_t *callback,
1940Sstevel@tonic-gate void *arg)
1950Sstevel@tonic-gate {
1960Sstevel@tonic-gate iu_timer_node_t *node = calloc(1, sizeof (iu_timer_node_t));
1970Sstevel@tonic-gate
1980Sstevel@tonic-gate if (node == NULL)
1990Sstevel@tonic-gate return (-1);
2000Sstevel@tonic-gate
2010Sstevel@tonic-gate node->iutn_callback = callback;
2020Sstevel@tonic-gate node->iutn_arg = arg;
2030Sstevel@tonic-gate node->iutn_timer_id = get_timer_id(tq);
2040Sstevel@tonic-gate if (node->iutn_timer_id == -1) {
2050Sstevel@tonic-gate free(node);
2060Sstevel@tonic-gate return (-1);
2070Sstevel@tonic-gate }
2080Sstevel@tonic-gate
2090Sstevel@tonic-gate insert_timer(tq, node, ms);
2100Sstevel@tonic-gate
2110Sstevel@tonic-gate return (node->iutn_timer_id);
2120Sstevel@tonic-gate }
2130Sstevel@tonic-gate
2140Sstevel@tonic-gate /*
2150Sstevel@tonic-gate * iu_cancel_timer(): cancels a pending timer from a timer queue's timer list
2160Sstevel@tonic-gate *
2170Sstevel@tonic-gate * input: iu_tq_t *: the timer queue
2180Sstevel@tonic-gate * iu_timer_id_t: the timer id returned from iu_schedule_timer
2190Sstevel@tonic-gate * void **: if non-NULL, a place to return the argument passed to
2200Sstevel@tonic-gate * iu_schedule_timer
2210Sstevel@tonic-gate * output: int: 1 on success, 0 on failure
2220Sstevel@tonic-gate */
2230Sstevel@tonic-gate
2240Sstevel@tonic-gate int
iu_cancel_timer(iu_tq_t * tq,iu_timer_id_t timer_id,void ** arg)2250Sstevel@tonic-gate iu_cancel_timer(iu_tq_t *tq, iu_timer_id_t timer_id, void **arg)
2260Sstevel@tonic-gate {
2270Sstevel@tonic-gate iu_timer_node_t *node;
2280Sstevel@tonic-gate
2290Sstevel@tonic-gate if (timer_id == -1)
2300Sstevel@tonic-gate return (0);
2310Sstevel@tonic-gate
2320Sstevel@tonic-gate for (node = tq->iutq_head; node != NULL; node = node->iutn_next) {
2330Sstevel@tonic-gate if (node->iutn_timer_id == timer_id) {
2340Sstevel@tonic-gate if (arg != NULL)
2350Sstevel@tonic-gate *arg = node->iutn_arg;
2360Sstevel@tonic-gate remove_timer(tq, node);
2370Sstevel@tonic-gate destroy_timer(tq, node);
2380Sstevel@tonic-gate return (1);
2390Sstevel@tonic-gate }
2400Sstevel@tonic-gate }
2410Sstevel@tonic-gate return (0);
2420Sstevel@tonic-gate }
2430Sstevel@tonic-gate
2440Sstevel@tonic-gate /*
2450Sstevel@tonic-gate * iu_adjust_timer(): adjusts the fire time of a timer in the tq's timer list
2460Sstevel@tonic-gate *
2470Sstevel@tonic-gate * input: iu_tq_t *: the timer queue
2480Sstevel@tonic-gate * iu_timer_id_t: the timer id returned from iu_schedule_timer
2490Sstevel@tonic-gate * uint32_t: the number of seconds before this timer fires
2500Sstevel@tonic-gate * output: int: 1 on success, 0 on failure
2510Sstevel@tonic-gate */
2520Sstevel@tonic-gate
2530Sstevel@tonic-gate int
iu_adjust_timer(iu_tq_t * tq,iu_timer_id_t timer_id,uint32_t sec)2540Sstevel@tonic-gate iu_adjust_timer(iu_tq_t *tq, iu_timer_id_t timer_id, uint32_t sec)
2550Sstevel@tonic-gate {
2560Sstevel@tonic-gate iu_timer_node_t *node;
2570Sstevel@tonic-gate
2580Sstevel@tonic-gate if (timer_id == -1)
2590Sstevel@tonic-gate return (0);
2600Sstevel@tonic-gate
2610Sstevel@tonic-gate for (node = tq->iutq_head; node != NULL; node = node->iutn_next) {
2620Sstevel@tonic-gate if (node->iutn_timer_id == timer_id) {
2630Sstevel@tonic-gate remove_timer(tq, node);
2640Sstevel@tonic-gate insert_timer(tq, node, sec * MILLISEC);
2650Sstevel@tonic-gate return (1);
2660Sstevel@tonic-gate }
2670Sstevel@tonic-gate }
2680Sstevel@tonic-gate return (0);
2690Sstevel@tonic-gate }
2700Sstevel@tonic-gate
2710Sstevel@tonic-gate /*
2720Sstevel@tonic-gate * iu_earliest_timer(): returns the time until the next timer fires on a tq
2730Sstevel@tonic-gate *
2740Sstevel@tonic-gate * input: iu_tq_t *: the timer queue
2750Sstevel@tonic-gate * output: int: the number of milliseconds until the next timer (up to
2760Sstevel@tonic-gate * a maximum value of INT_MAX), or INFTIM if no timers are pending.
2770Sstevel@tonic-gate */
2780Sstevel@tonic-gate
2790Sstevel@tonic-gate int
iu_earliest_timer(iu_tq_t * tq)2800Sstevel@tonic-gate iu_earliest_timer(iu_tq_t *tq)
2810Sstevel@tonic-gate {
2820Sstevel@tonic-gate unsigned long long timeout_interval;
2830Sstevel@tonic-gate hrtime_t current_time = gethrtime();
2840Sstevel@tonic-gate
2850Sstevel@tonic-gate if (tq->iutq_head == NULL)
2860Sstevel@tonic-gate return (INFTIM);
2870Sstevel@tonic-gate
2880Sstevel@tonic-gate /*
2890Sstevel@tonic-gate * event might've already happened if we haven't gotten a chance to
2900Sstevel@tonic-gate * run in a while; return zero and pretend it just expired.
2910Sstevel@tonic-gate */
2920Sstevel@tonic-gate
2930Sstevel@tonic-gate if (tq->iutq_head->iutn_abs_timeout <= current_time)
2940Sstevel@tonic-gate return (0);
2950Sstevel@tonic-gate
2960Sstevel@tonic-gate /*
2970Sstevel@tonic-gate * since the timers are ordered in absolute time-to-fire, just
2980Sstevel@tonic-gate * subtract from the head of the list.
2990Sstevel@tonic-gate */
3000Sstevel@tonic-gate
3010Sstevel@tonic-gate timeout_interval =
3020Sstevel@tonic-gate (tq->iutq_head->iutn_abs_timeout - current_time) / 1000000;
3030Sstevel@tonic-gate
3040Sstevel@tonic-gate return (MIN(timeout_interval, INT_MAX));
3050Sstevel@tonic-gate }
3060Sstevel@tonic-gate
3070Sstevel@tonic-gate /*
3080Sstevel@tonic-gate * iu_expire_timers(): expires all pending timers on a given timer queue
3090Sstevel@tonic-gate *
3100Sstevel@tonic-gate * input: iu_tq_t *: the timer queue
3110Sstevel@tonic-gate * output: int: the number of timers expired
3120Sstevel@tonic-gate */
3130Sstevel@tonic-gate
3140Sstevel@tonic-gate int
iu_expire_timers(iu_tq_t * tq)3150Sstevel@tonic-gate iu_expire_timers(iu_tq_t *tq)
3160Sstevel@tonic-gate {
3170Sstevel@tonic-gate iu_timer_node_t *node, *next_node;
3180Sstevel@tonic-gate int n_expired = 0;
3190Sstevel@tonic-gate hrtime_t current_time = gethrtime();
3200Sstevel@tonic-gate
3210Sstevel@tonic-gate /*
3220Sstevel@tonic-gate * in_expire is in the iu_tq_t instead of being passed through as
3230Sstevel@tonic-gate * an argument to remove_timer() below since the callback
3240Sstevel@tonic-gate * function may call iu_cancel_timer() itself as well.
3250Sstevel@tonic-gate */
3260Sstevel@tonic-gate
3270Sstevel@tonic-gate tq->iutq_in_expire++;
3280Sstevel@tonic-gate
3290Sstevel@tonic-gate /*
3300Sstevel@tonic-gate * this function builds another linked list of timer nodes
3310Sstevel@tonic-gate * through `expire_next' because the normal linked list
3320Sstevel@tonic-gate * may be changed as a result of callbacks canceling and
3330Sstevel@tonic-gate * scheduling timeouts, and thus can't be trusted.
3340Sstevel@tonic-gate */
3350Sstevel@tonic-gate
3360Sstevel@tonic-gate for (node = tq->iutq_head; node != NULL; node = node->iutn_next)
3370Sstevel@tonic-gate node->iutn_expire_next = node->iutn_next;
3380Sstevel@tonic-gate
3390Sstevel@tonic-gate for (node = tq->iutq_head; node != NULL;
3400Sstevel@tonic-gate node = node->iutn_expire_next) {
3410Sstevel@tonic-gate
342*10946SSangeeta.Misra@Sun.COM /*
343*10946SSangeeta.Misra@Sun.COM * If the timeout is within 1 millisec of current time,
344*10946SSangeeta.Misra@Sun.COM * consider it as expired already. We do this because
345*10946SSangeeta.Misra@Sun.COM * iu_earliest_timer() only has millisec granularity.
346*10946SSangeeta.Misra@Sun.COM * So we should also use millisec grandularity in
347*10946SSangeeta.Misra@Sun.COM * comparing timeout values.
348*10946SSangeeta.Misra@Sun.COM */
349*10946SSangeeta.Misra@Sun.COM if (node->iutn_abs_timeout - current_time > 1000000)
3500Sstevel@tonic-gate break;
3510Sstevel@tonic-gate
3520Sstevel@tonic-gate /*
3530Sstevel@tonic-gate * fringe condition: two timers fire at the "same
3540Sstevel@tonic-gate * time" (i.e., they're both scheduled called back in
3550Sstevel@tonic-gate * this loop) and one cancels the other. in this
3560Sstevel@tonic-gate * case, the timer which has already been "cancelled"
3570Sstevel@tonic-gate * should not be called back.
3580Sstevel@tonic-gate */
3590Sstevel@tonic-gate
3600Sstevel@tonic-gate if (node->iutn_pending_delete)
3610Sstevel@tonic-gate continue;
3620Sstevel@tonic-gate
3630Sstevel@tonic-gate /*
3640Sstevel@tonic-gate * we remove the timer before calling back the callback
3650Sstevel@tonic-gate * so that a callback which accidentally tries to cancel
3660Sstevel@tonic-gate * itself (through whatever means) doesn't succeed.
3670Sstevel@tonic-gate */
3680Sstevel@tonic-gate
3690Sstevel@tonic-gate n_expired++;
3700Sstevel@tonic-gate remove_timer(tq, node);
3710Sstevel@tonic-gate destroy_timer(tq, node);
3720Sstevel@tonic-gate node->iutn_callback(tq, node->iutn_arg);
3730Sstevel@tonic-gate }
3740Sstevel@tonic-gate
3750Sstevel@tonic-gate tq->iutq_in_expire--;
3760Sstevel@tonic-gate
3770Sstevel@tonic-gate /*
3780Sstevel@tonic-gate * any cancels that took place whilst we were expiring timeouts
3790Sstevel@tonic-gate * ended up on the `pending_delete_chain'. delete them now
3800Sstevel@tonic-gate * that it's safe.
3810Sstevel@tonic-gate */
3820Sstevel@tonic-gate
3830Sstevel@tonic-gate for (node = pending_delete_chain; node != NULL; node = next_node) {
3840Sstevel@tonic-gate next_node = node->iutn_next;
3850Sstevel@tonic-gate free(node);
3860Sstevel@tonic-gate }
3870Sstevel@tonic-gate pending_delete_chain = NULL;
3880Sstevel@tonic-gate
3890Sstevel@tonic-gate return (n_expired);
3900Sstevel@tonic-gate }
3910Sstevel@tonic-gate
3920Sstevel@tonic-gate /*
3930Sstevel@tonic-gate * get_timer_id(): allocates a timer id from the pool
3940Sstevel@tonic-gate *
3950Sstevel@tonic-gate * input: iu_tq_t *: the timer queue
3960Sstevel@tonic-gate * output: iu_timer_id_t: the allocated timer id, or -1 if none available
3970Sstevel@tonic-gate */
3980Sstevel@tonic-gate
3990Sstevel@tonic-gate static iu_timer_id_t
get_timer_id(iu_tq_t * tq)4000Sstevel@tonic-gate get_timer_id(iu_tq_t *tq)
4010Sstevel@tonic-gate {
4020Sstevel@tonic-gate unsigned int map_index;
4030Sstevel@tonic-gate unsigned char map_bit;
4040Sstevel@tonic-gate boolean_t have_wrapped = B_FALSE;
4050Sstevel@tonic-gate
4060Sstevel@tonic-gate for (; ; tq->iutq_next_timer_id++) {
4070Sstevel@tonic-gate
4080Sstevel@tonic-gate if (tq->iutq_next_timer_id >= IU_TIMER_ID_MAX) {
4090Sstevel@tonic-gate if (have_wrapped)
4100Sstevel@tonic-gate return (-1);
4110Sstevel@tonic-gate
4120Sstevel@tonic-gate have_wrapped = B_TRUE;
4130Sstevel@tonic-gate tq->iutq_next_timer_id = 0;
4140Sstevel@tonic-gate }
4150Sstevel@tonic-gate
4160Sstevel@tonic-gate map_index = tq->iutq_next_timer_id / CHAR_BIT;
4170Sstevel@tonic-gate map_bit = tq->iutq_next_timer_id % CHAR_BIT;
4180Sstevel@tonic-gate
4190Sstevel@tonic-gate if ((tq->iutq_timer_id_map[map_index] & (1 << map_bit)) == 0)
4200Sstevel@tonic-gate break;
4210Sstevel@tonic-gate }
4220Sstevel@tonic-gate
4230Sstevel@tonic-gate tq->iutq_timer_id_map[map_index] |= (1 << map_bit);
4240Sstevel@tonic-gate return (tq->iutq_next_timer_id++);
4250Sstevel@tonic-gate }
4260Sstevel@tonic-gate
4270Sstevel@tonic-gate /*
4280Sstevel@tonic-gate * release_timer_id(): releases a timer id back into the pool
4290Sstevel@tonic-gate *
4300Sstevel@tonic-gate * input: iu_tq_t *: the timer queue
4310Sstevel@tonic-gate * iu_timer_id_t: the timer id to release
4320Sstevel@tonic-gate * output: void
4330Sstevel@tonic-gate */
4340Sstevel@tonic-gate
4350Sstevel@tonic-gate static void
release_timer_id(iu_tq_t * tq,iu_timer_id_t timer_id)4360Sstevel@tonic-gate release_timer_id(iu_tq_t *tq, iu_timer_id_t timer_id)
4370Sstevel@tonic-gate {
4380Sstevel@tonic-gate unsigned int map_index = timer_id / CHAR_BIT;
4390Sstevel@tonic-gate unsigned char map_bit = timer_id % CHAR_BIT;
4400Sstevel@tonic-gate
4410Sstevel@tonic-gate tq->iutq_timer_id_map[map_index] &= ~(1 << map_bit);
4420Sstevel@tonic-gate }
443