1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License, Version 1.0 only 6 * (the "License"). You may not use this file except in compliance 7 * with the License. 8 * 9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10 * or http://www.opensolaris.org/os/licensing. 11 * See the License for the specific language governing permissions 12 * and limitations under the License. 13 * 14 * When distributing Covered Code, include this CDDL HEADER in each 15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16 * If applicable, add the following below this CDDL HEADER, with the 17 * fields enclosed by brackets "[]" replaced with your own identifying 18 * information: Portions Copyright [yyyy] [name of copyright owner] 19 * 20 * CDDL HEADER END 21 */ 22 /* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */ 23 /* All Rights Reserved */ 24 25 26 /* 27 * Copyright (c) 1997-1998 by Sun Microsystems, Inc. 28 * All rights reserved. 29 */ 30 31 #ifndef _SYS_CALLO_H 32 #define _SYS_CALLO_H 33 34 #pragma ident "%Z%%M% %I% %E% SMI" 35 36 #include <sys/t_lock.h> 37 #include <sys/taskq.h> 38 39 #ifdef __cplusplus 40 extern "C" { 41 #endif 42 43 typedef long callout_id_t; /* internal form of timeout_id_t */ 44 45 /* 46 * The callout mechanism provides general-purpose event scheduling: 47 * an arbitrary function is called in a specified amount of time. 48 */ 49 typedef struct callout { 50 struct callout *c_idnext; /* next in ID hash, or on freelist */ 51 struct callout *c_idprev; /* prev in ID hash */ 52 struct callout *c_lbnext; /* next in lbolt hash */ 53 struct callout *c_lbprev; /* prev in lbolt hash */ 54 callout_id_t c_xid; /* extended callout ID; see below */ 55 clock_t c_runtime; /* absolute run time */ 56 void (*c_func)(void *); /* function to call */ 57 void *c_arg; /* argument to function */ 58 kthread_id_t c_executor; /* thread executing callout */ 59 kcondvar_t c_done; /* signal callout completion */ 60 } callout_t; 61 62 /* 63 * The extended callout ID consists of the callout ID (as returned by 64 * timeout()) plus a bit indicating whether the callout is executing. 65 * 66 * The callout ID uniquely identifies a callout. It contains a table ID, 67 * indicating which callout table the callout belongs to, a bit indicating 68 * whether this is a short-term or long-term callout, and a running counter. 69 * The highest bit of the running counter is always set; this ensures that 70 * the callout ID is always non-zero, thus eliminating the need for an 71 * explicit wrap-around test during ID generation. 72 * 73 * The long-term bit exists to address the problem of callout ID collision. 74 * This is an issue because the system typically generates a large number of 75 * timeout() requests, which means that callout IDs eventually get recycled. 76 * Most timeouts are very short-lived, so that ID recycling isn't a problem; 77 * but there are a handful of timeouts which are sufficiently long-lived to 78 * see their own IDs reused. We use the long-term bit to partition the 79 * ID namespace into pieces; the short-term space gets all the heavy traffic 80 * and can wrap frequently (i.e., on the order of a day) with no ill effects; 81 * the long-term space gets very little traffic and thus never wraps. 82 */ 83 #define CALLOUT_EXECUTING (1UL << (8 * sizeof (long) - 1)) 84 #define CALLOUT_LONGTERM (1UL << (8 * sizeof (long) - 2)) 85 #define CALLOUT_COUNTER_HIGH (1UL << (8 * sizeof (long) - 3)) 86 #define CALLOUT_FANOUT_BITS 3 87 #define CALLOUT_TYPE_BITS 1 88 #define CALLOUT_NTYPES (1 << CALLOUT_TYPE_BITS) 89 #define CALLOUT_FANOUT (1 << CALLOUT_FANOUT_BITS) 90 #define CALLOUT_FANOUT_MASK (CALLOUT_FANOUT - 1) 91 #define CALLOUT_COUNTER_SHIFT (CALLOUT_TYPE_BITS + CALLOUT_FANOUT_BITS) 92 #define CALLOUT_COUNTER_LOW (1 << CALLOUT_COUNTER_SHIFT) 93 #define CALLOUT_TABLES CALLOUT_COUNTER_LOW 94 #define CALLOUT_TABLE_MASK (CALLOUT_TABLES - 1) 95 #define CALLOUT_TABLE(t, f) \ 96 (((t) << CALLOUT_FANOUT_BITS) + ((f) & CALLOUT_FANOUT_MASK)) 97 98 /* 99 * We assume that during any period of CALLOUT_LONGTERM_TICKS ticks, at most 100 * (CALLOUT_COUNTER_HIGH / CALLOUT_COUNTER_LOW) callouts will be generated. 101 */ 102 #define CALLOUT_LONGTERM_TICKS 0x4000 103 #define CALLOUT_BUCKETS 512 /* MUST be a power of 2 */ 104 #define CALLOUT_BUCKET_MASK (CALLOUT_BUCKETS - 1) 105 #define CALLOUT_HASH(x) ((x) & CALLOUT_BUCKET_MASK) 106 #define CALLOUT_IDHASH(x) CALLOUT_HASH((x) >> CALLOUT_COUNTER_SHIFT) 107 #define CALLOUT_LBHASH(x) CALLOUT_HASH(x) 108 109 #define CALLOUT_THREADS 2 /* keep it simple for now */ 110 111 #define CALLOUT_REALTIME 0 /* realtime callout type */ 112 #define CALLOUT_NORMAL 1 /* normal callout type */ 113 114 /* 115 * All of the state information associated with a callout table. 116 * The fields are ordered with cache performance in mind. 117 */ 118 typedef struct callout_table { 119 kmutex_t ct_lock; /* protects all callout state */ 120 callout_t *ct_freelist; /* free callout structures */ 121 clock_t ct_curtime; /* current time; tracks lbolt */ 122 clock_t ct_runtime; /* the callouts we're running now */ 123 taskq_t *ct_taskq; /* taskq to execute normal callouts */ 124 callout_id_t ct_short_id; /* most recently issued short-term ID */ 125 callout_id_t ct_long_id; /* most recently issued long-term ID */ 126 callout_t *ct_idhash[CALLOUT_BUCKETS]; /* ID hash chains */ 127 callout_t *ct_lbhash[CALLOUT_BUCKETS]; /* lbolt hash chains */ 128 } callout_table_t; 129 130 #ifdef _KERNEL 131 extern void callout_init(void); 132 extern void callout_schedule(void); 133 #endif 134 135 #ifdef __cplusplus 136 } 137 #endif 138 139 #endif /* _SYS_CALLO_H */ 140