17c478bd9Sstevel@tonic-gate /* 27c478bd9Sstevel@tonic-gate * CDDL HEADER START 37c478bd9Sstevel@tonic-gate * 47c478bd9Sstevel@tonic-gate * The contents of this file are subject to the terms of the 5*f635d46aSqiao * Common Development and Distribution License (the "License"). 6*f635d46aSqiao * You may not use this file except in compliance with the License. 77c478bd9Sstevel@tonic-gate * 87c478bd9Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 97c478bd9Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 107c478bd9Sstevel@tonic-gate * See the License for the specific language governing permissions 117c478bd9Sstevel@tonic-gate * and limitations under the License. 127c478bd9Sstevel@tonic-gate * 137c478bd9Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 147c478bd9Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 157c478bd9Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 167c478bd9Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 177c478bd9Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 187c478bd9Sstevel@tonic-gate * 197c478bd9Sstevel@tonic-gate * CDDL HEADER END 207c478bd9Sstevel@tonic-gate */ 217c478bd9Sstevel@tonic-gate /* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */ 227c478bd9Sstevel@tonic-gate /* All Rights Reserved */ 237c478bd9Sstevel@tonic-gate 247c478bd9Sstevel@tonic-gate 257c478bd9Sstevel@tonic-gate /* 26*f635d46aSqiao * Copyright 2008 Sun Microsystems, Inc. All rights reserved. 27*f635d46aSqiao * Use is subject to license terms. 287c478bd9Sstevel@tonic-gate */ 297c478bd9Sstevel@tonic-gate 307c478bd9Sstevel@tonic-gate #ifndef _SYS_CALLO_H 317c478bd9Sstevel@tonic-gate #define _SYS_CALLO_H 327c478bd9Sstevel@tonic-gate 337c478bd9Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI" 347c478bd9Sstevel@tonic-gate 357c478bd9Sstevel@tonic-gate #include <sys/t_lock.h> 367c478bd9Sstevel@tonic-gate #include <sys/taskq.h> 377c478bd9Sstevel@tonic-gate 387c478bd9Sstevel@tonic-gate #ifdef __cplusplus 397c478bd9Sstevel@tonic-gate extern "C" { 407c478bd9Sstevel@tonic-gate #endif 417c478bd9Sstevel@tonic-gate 427c478bd9Sstevel@tonic-gate typedef long callout_id_t; /* internal form of timeout_id_t */ 437c478bd9Sstevel@tonic-gate 447c478bd9Sstevel@tonic-gate /* 457c478bd9Sstevel@tonic-gate * The callout mechanism provides general-purpose event scheduling: 467c478bd9Sstevel@tonic-gate * an arbitrary function is called in a specified amount of time. 477c478bd9Sstevel@tonic-gate */ 487c478bd9Sstevel@tonic-gate typedef struct callout { 497c478bd9Sstevel@tonic-gate struct callout *c_idnext; /* next in ID hash, or on freelist */ 507c478bd9Sstevel@tonic-gate struct callout *c_idprev; /* prev in ID hash */ 517c478bd9Sstevel@tonic-gate struct callout *c_lbnext; /* next in lbolt hash */ 527c478bd9Sstevel@tonic-gate struct callout *c_lbprev; /* prev in lbolt hash */ 537c478bd9Sstevel@tonic-gate callout_id_t c_xid; /* extended callout ID; see below */ 547c478bd9Sstevel@tonic-gate clock_t c_runtime; /* absolute run time */ 55*f635d46aSqiao int64_t c_runhrtime; /* run time ticks since epoch */ 567c478bd9Sstevel@tonic-gate void (*c_func)(void *); /* function to call */ 577c478bd9Sstevel@tonic-gate void *c_arg; /* argument to function */ 587c478bd9Sstevel@tonic-gate kthread_id_t c_executor; /* thread executing callout */ 597c478bd9Sstevel@tonic-gate kcondvar_t c_done; /* signal callout completion */ 607c478bd9Sstevel@tonic-gate } callout_t; 617c478bd9Sstevel@tonic-gate 627c478bd9Sstevel@tonic-gate /* 637c478bd9Sstevel@tonic-gate * The extended callout ID consists of the callout ID (as returned by 647c478bd9Sstevel@tonic-gate * timeout()) plus a bit indicating whether the callout is executing. 657c478bd9Sstevel@tonic-gate * 667c478bd9Sstevel@tonic-gate * The callout ID uniquely identifies a callout. It contains a table ID, 677c478bd9Sstevel@tonic-gate * indicating which callout table the callout belongs to, a bit indicating 687c478bd9Sstevel@tonic-gate * whether this is a short-term or long-term callout, and a running counter. 697c478bd9Sstevel@tonic-gate * The highest bit of the running counter is always set; this ensures that 707c478bd9Sstevel@tonic-gate * the callout ID is always non-zero, thus eliminating the need for an 717c478bd9Sstevel@tonic-gate * explicit wrap-around test during ID generation. 727c478bd9Sstevel@tonic-gate * 737c478bd9Sstevel@tonic-gate * The long-term bit exists to address the problem of callout ID collision. 747c478bd9Sstevel@tonic-gate * This is an issue because the system typically generates a large number of 757c478bd9Sstevel@tonic-gate * timeout() requests, which means that callout IDs eventually get recycled. 767c478bd9Sstevel@tonic-gate * Most timeouts are very short-lived, so that ID recycling isn't a problem; 777c478bd9Sstevel@tonic-gate * but there are a handful of timeouts which are sufficiently long-lived to 787c478bd9Sstevel@tonic-gate * see their own IDs reused. We use the long-term bit to partition the 797c478bd9Sstevel@tonic-gate * ID namespace into pieces; the short-term space gets all the heavy traffic 807c478bd9Sstevel@tonic-gate * and can wrap frequently (i.e., on the order of a day) with no ill effects; 817c478bd9Sstevel@tonic-gate * the long-term space gets very little traffic and thus never wraps. 827c478bd9Sstevel@tonic-gate */ 837c478bd9Sstevel@tonic-gate #define CALLOUT_EXECUTING (1UL << (8 * sizeof (long) - 1)) 847c478bd9Sstevel@tonic-gate #define CALLOUT_LONGTERM (1UL << (8 * sizeof (long) - 2)) 857c478bd9Sstevel@tonic-gate #define CALLOUT_COUNTER_HIGH (1UL << (8 * sizeof (long) - 3)) 867c478bd9Sstevel@tonic-gate #define CALLOUT_FANOUT_BITS 3 877c478bd9Sstevel@tonic-gate #define CALLOUT_TYPE_BITS 1 887c478bd9Sstevel@tonic-gate #define CALLOUT_NTYPES (1 << CALLOUT_TYPE_BITS) 897c478bd9Sstevel@tonic-gate #define CALLOUT_FANOUT (1 << CALLOUT_FANOUT_BITS) 907c478bd9Sstevel@tonic-gate #define CALLOUT_FANOUT_MASK (CALLOUT_FANOUT - 1) 917c478bd9Sstevel@tonic-gate #define CALLOUT_COUNTER_SHIFT (CALLOUT_TYPE_BITS + CALLOUT_FANOUT_BITS) 927c478bd9Sstevel@tonic-gate #define CALLOUT_COUNTER_LOW (1 << CALLOUT_COUNTER_SHIFT) 937c478bd9Sstevel@tonic-gate #define CALLOUT_TABLES CALLOUT_COUNTER_LOW 947c478bd9Sstevel@tonic-gate #define CALLOUT_TABLE_MASK (CALLOUT_TABLES - 1) 957c478bd9Sstevel@tonic-gate #define CALLOUT_TABLE(t, f) \ 967c478bd9Sstevel@tonic-gate (((t) << CALLOUT_FANOUT_BITS) + ((f) & CALLOUT_FANOUT_MASK)) 977c478bd9Sstevel@tonic-gate 987c478bd9Sstevel@tonic-gate /* 997c478bd9Sstevel@tonic-gate * We assume that during any period of CALLOUT_LONGTERM_TICKS ticks, at most 1007c478bd9Sstevel@tonic-gate * (CALLOUT_COUNTER_HIGH / CALLOUT_COUNTER_LOW) callouts will be generated. 1017c478bd9Sstevel@tonic-gate */ 1027c478bd9Sstevel@tonic-gate #define CALLOUT_LONGTERM_TICKS 0x4000 1037c478bd9Sstevel@tonic-gate #define CALLOUT_BUCKETS 512 /* MUST be a power of 2 */ 1047c478bd9Sstevel@tonic-gate #define CALLOUT_BUCKET_MASK (CALLOUT_BUCKETS - 1) 1057c478bd9Sstevel@tonic-gate #define CALLOUT_HASH(x) ((x) & CALLOUT_BUCKET_MASK) 1067c478bd9Sstevel@tonic-gate #define CALLOUT_IDHASH(x) CALLOUT_HASH((x) >> CALLOUT_COUNTER_SHIFT) 1077c478bd9Sstevel@tonic-gate #define CALLOUT_LBHASH(x) CALLOUT_HASH(x) 1087c478bd9Sstevel@tonic-gate 1097c478bd9Sstevel@tonic-gate #define CALLOUT_THREADS 2 /* keep it simple for now */ 1107c478bd9Sstevel@tonic-gate 1117c478bd9Sstevel@tonic-gate #define CALLOUT_REALTIME 0 /* realtime callout type */ 1127c478bd9Sstevel@tonic-gate #define CALLOUT_NORMAL 1 /* normal callout type */ 1137c478bd9Sstevel@tonic-gate 1147c478bd9Sstevel@tonic-gate /* 1157c478bd9Sstevel@tonic-gate * All of the state information associated with a callout table. 1167c478bd9Sstevel@tonic-gate * The fields are ordered with cache performance in mind. 1177c478bd9Sstevel@tonic-gate */ 1187c478bd9Sstevel@tonic-gate typedef struct callout_table { 1197c478bd9Sstevel@tonic-gate kmutex_t ct_lock; /* protects all callout state */ 1207c478bd9Sstevel@tonic-gate callout_t *ct_freelist; /* free callout structures */ 1217c478bd9Sstevel@tonic-gate clock_t ct_curtime; /* current time; tracks lbolt */ 1227c478bd9Sstevel@tonic-gate clock_t ct_runtime; /* the callouts we're running now */ 123*f635d46aSqiao int64_t ct_curhrtime; /* current time ticks since epoch */ 1247c478bd9Sstevel@tonic-gate taskq_t *ct_taskq; /* taskq to execute normal callouts */ 1257c478bd9Sstevel@tonic-gate callout_id_t ct_short_id; /* most recently issued short-term ID */ 1267c478bd9Sstevel@tonic-gate callout_id_t ct_long_id; /* most recently issued long-term ID */ 1277c478bd9Sstevel@tonic-gate callout_t *ct_idhash[CALLOUT_BUCKETS]; /* ID hash chains */ 1287c478bd9Sstevel@tonic-gate callout_t *ct_lbhash[CALLOUT_BUCKETS]; /* lbolt hash chains */ 1297c478bd9Sstevel@tonic-gate } callout_table_t; 1307c478bd9Sstevel@tonic-gate 1317c478bd9Sstevel@tonic-gate #ifdef _KERNEL 1327c478bd9Sstevel@tonic-gate extern void callout_init(void); 1337c478bd9Sstevel@tonic-gate extern void callout_schedule(void); 1347c478bd9Sstevel@tonic-gate #endif 1357c478bd9Sstevel@tonic-gate 1367c478bd9Sstevel@tonic-gate #ifdef __cplusplus 1377c478bd9Sstevel@tonic-gate } 1387c478bd9Sstevel@tonic-gate #endif 1397c478bd9Sstevel@tonic-gate 1407c478bd9Sstevel@tonic-gate #endif /* _SYS_CALLO_H */ 141