callb.c revision 168404
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/* 23 * Copyright 2004 Sun Microsystems, Inc. All rights reserved. 24 * Use is subject to license terms. 25 */ 26 27#pragma ident "%Z%%M% %I% %E% SMI" 28 29#include <sys/param.h> 30#include <sys/types.h> 31#include <sys/time.h> 32#include <sys/sysmacros.h> 33#include <sys/systm.h> 34#include <sys/proc.h> 35#include <sys/mutex.h> 36#include <sys/condvar.h> 37#include <sys/callb.h> 38#include <sys/kmem.h> 39#include <sys/cmn_err.h> 40#include <sys/debug.h> 41#include <sys/kobj.h> 42#include <sys/systm.h> /* for delay() */ 43#include <sys/taskq.h> /* For TASKQ_NAMELEN */ 44#include <sys/kernel.h> 45 46#define CB_MAXNAME TASKQ_NAMELEN 47 48/* 49 * The callb mechanism provides generic event scheduling/echoing. 50 * A callb function is registered and called on behalf of the event. 51 */ 52typedef struct callb { 53 struct callb *c_next; /* next in class or on freelist */ 54 kthread_id_t c_thread; /* ptr to caller's thread struct */ 55 char c_flag; /* info about the callb state */ 56 uchar_t c_class; /* this callb's class */ 57 kcondvar_t c_done_cv; /* signal callb completion */ 58 boolean_t (*c_func)(); /* cb function: returns true if ok */ 59 void *c_arg; /* arg to c_func */ 60 char c_name[CB_MAXNAME+1]; /* debug:max func name length */ 61} callb_t; 62 63/* 64 * callb c_flag bitmap definitions 65 */ 66#define CALLB_FREE 0x0 67#define CALLB_TAKEN 0x1 68#define CALLB_EXECUTING 0x2 69 70/* 71 * Basic structure for a callb table. 72 * All callbs are organized into different class groups described 73 * by ct_class array. 74 * The callbs within a class are single-linked and normally run by a 75 * serial execution. 76 */ 77typedef struct callb_table { 78 kmutex_t ct_lock; /* protect all callb states */ 79 callb_t *ct_freelist; /* free callb structures */ 80 int ct_busy; /* != 0 prevents additions */ 81 kcondvar_t ct_busy_cv; /* to wait for not busy */ 82 int ct_ncallb; /* num of callbs allocated */ 83 callb_t *ct_first_cb[NCBCLASS]; /* ptr to 1st callb in a class */ 84} callb_table_t; 85 86int callb_timeout_sec = CPR_KTHREAD_TIMEOUT_SEC; 87 88static callb_id_t callb_add_common(boolean_t (*)(void *, int), 89 void *, int, char *, kthread_id_t); 90 91static callb_table_t callb_table; /* system level callback table */ 92static callb_table_t *ct = &callb_table; 93static kmutex_t callb_safe_mutex; 94callb_cpr_t callb_cprinfo_safe = { 95 &callb_safe_mutex, CALLB_CPR_ALWAYS_SAFE, 0, 0, 0 }; 96 97/* 98 * Init all callb tables in the system. 99 */ 100void 101callb_init(void *dummy __unused) 102{ 103 callb_table.ct_busy = 0; /* mark table open for additions */ 104 mutex_init(&callb_safe_mutex, NULL, MUTEX_DEFAULT, NULL); 105 mutex_init(&callb_table.ct_lock, NULL, MUTEX_DEFAULT, NULL); 106} 107 108void 109callb_fini(void *dummy __unused) 110{ 111 callb_t *cp; 112 113 mutex_enter(&ct->ct_lock); 114 while ((cp = ct->ct_freelist) != NULL) { 115 ct->ct_freelist = cp->c_next; 116 ct->ct_ncallb--; 117 kmem_free(cp, sizeof (callb_t)); 118 } 119 ASSERT(ct->ct_ncallb == 0); 120 mutex_exit(&ct->ct_lock); 121 mutex_destroy(&callb_safe_mutex); 122 mutex_destroy(&callb_table.ct_lock); 123} 124 125/* 126 * callout_add() is called to register func() be called later. 127 */ 128static callb_id_t 129callb_add_common(boolean_t (*func)(void *arg, int code), 130 void *arg, int class, char *name, kthread_id_t t) 131{ 132 callb_t *cp; 133 134 ASSERT(class < NCBCLASS); 135 136 mutex_enter(&ct->ct_lock); 137 while (ct->ct_busy) 138 cv_wait(&ct->ct_busy_cv, &ct->ct_lock); 139 if ((cp = ct->ct_freelist) == NULL) { 140 ct->ct_ncallb++; 141 cp = (callb_t *)kmem_zalloc(sizeof (callb_t), KM_SLEEP); 142 } 143 ct->ct_freelist = cp->c_next; 144 cp->c_thread = t; 145 cp->c_func = func; 146 cp->c_arg = arg; 147 cp->c_class = (uchar_t)class; 148 cp->c_flag |= CALLB_TAKEN; 149#ifdef DEBUG 150 if (strlen(name) > CB_MAXNAME) 151 cmn_err(CE_WARN, "callb_add: name of callback function '%s' " 152 "too long -- truncated to %d chars", 153 name, CB_MAXNAME); 154#endif 155 (void) strncpy(cp->c_name, name, CB_MAXNAME); 156 cp->c_name[CB_MAXNAME] = '\0'; 157 158 /* 159 * Insert the new callb at the head of its class list. 160 */ 161 cp->c_next = ct->ct_first_cb[class]; 162 ct->ct_first_cb[class] = cp; 163 164 mutex_exit(&ct->ct_lock); 165 return ((callb_id_t)cp); 166} 167 168/* 169 * The default function to add an entry to the callback table. Since 170 * it uses curthread as the thread identifier to store in the table, 171 * it should be used for the normal case of a thread which is calling 172 * to add ITSELF to the table. 173 */ 174callb_id_t 175callb_add(boolean_t (*func)(void *arg, int code), 176 void *arg, int class, char *name) 177{ 178 return (callb_add_common(func, arg, class, name, curthread)); 179} 180 181/* 182 * A special version of callb_add() above for use by threads which 183 * might be adding an entry to the table on behalf of some other 184 * thread (for example, one which is constructed but not yet running). 185 * In this version the thread id is an argument. 186 */ 187callb_id_t 188callb_add_thread(boolean_t (*func)(void *arg, int code), 189 void *arg, int class, char *name, kthread_id_t t) 190{ 191 return (callb_add_common(func, arg, class, name, t)); 192} 193 194/* 195 * callout_delete() is called to remove an entry identified by id 196 * that was originally placed there by a call to callout_add(). 197 * return -1 if fail to delete a callb entry otherwise return 0. 198 */ 199int 200callb_delete(callb_id_t id) 201{ 202 callb_t **pp; 203 callb_t *me = (callb_t *)id; 204 205 mutex_enter(&ct->ct_lock); 206 207 for (;;) { 208 pp = &ct->ct_first_cb[me->c_class]; 209 while (*pp != NULL && *pp != me) 210 pp = &(*pp)->c_next; 211 212#ifdef DEBUG 213 if (*pp != me) { 214 cmn_err(CE_WARN, "callb delete bogus entry 0x%p", 215 (void *)me); 216 mutex_exit(&ct->ct_lock); 217 return (-1); 218 } 219#endif /* DEBUG */ 220 221 /* 222 * It is not allowed to delete a callb in the middle of 223 * executing otherwise, the callb_execute() will be confused. 224 */ 225 if (!(me->c_flag & CALLB_EXECUTING)) 226 break; 227 228 cv_wait(&me->c_done_cv, &ct->ct_lock); 229 } 230 /* relink the class list */ 231 *pp = me->c_next; 232 233 /* clean up myself and return the free callb to the head of freelist */ 234 me->c_flag = CALLB_FREE; 235 me->c_next = ct->ct_freelist; 236 ct->ct_freelist = me; 237 238 mutex_exit(&ct->ct_lock); 239 return (0); 240} 241 242/* 243 * class: indicates to execute all callbs in the same class; 244 * code: optional argument for the callb functions. 245 * return: = 0: success 246 * != 0: ptr to string supplied when callback was registered 247 */ 248void * 249callb_execute_class(int class, int code) 250{ 251 callb_t *cp; 252 void *ret = NULL; 253 254 ASSERT(class < NCBCLASS); 255 256 mutex_enter(&ct->ct_lock); 257 258 for (cp = ct->ct_first_cb[class]; 259 cp != NULL && ret == 0; cp = cp->c_next) { 260 while (cp->c_flag & CALLB_EXECUTING) 261 cv_wait(&cp->c_done_cv, &ct->ct_lock); 262 /* 263 * cont if the callb is deleted while we're sleeping 264 */ 265 if (cp->c_flag == CALLB_FREE) 266 continue; 267 cp->c_flag |= CALLB_EXECUTING; 268 269#ifdef CALLB_DEBUG 270 printf("callb_execute: name=%s func=%p arg=%p\n", 271 cp->c_name, (void *)cp->c_func, (void *)cp->c_arg); 272#endif /* CALLB_DEBUG */ 273 274 mutex_exit(&ct->ct_lock); 275 /* If callback function fails, pass back client's name */ 276 if (!(*cp->c_func)(cp->c_arg, code)) 277 ret = cp->c_name; 278 mutex_enter(&ct->ct_lock); 279 280 cp->c_flag &= ~CALLB_EXECUTING; 281 cv_broadcast(&cp->c_done_cv); 282 } 283 mutex_exit(&ct->ct_lock); 284 return (ret); 285} 286 287/* 288 * callers make sure no recursive entries to this func. 289 * dp->cc_lockp is registered by callb_add to protect callb_cpr_t structure. 290 * 291 * When calling to stop a kernel thread (code == CB_CODE_CPR_CHKPT) we 292 * use a cv_timedwait() in case the kernel thread is blocked. 293 * 294 * Note that this is a generic callback handler for daemon CPR and 295 * should NOT be changed to accommodate any specific requirement in a daemon. 296 * Individual daemons that require changes to the handler shall write 297 * callback routines in their own daemon modules. 298 */ 299boolean_t 300callb_generic_cpr(void *arg, int code) 301{ 302 callb_cpr_t *cp = (callb_cpr_t *)arg; 303 clock_t ret = 0; /* assume success */ 304 305 mutex_enter(cp->cc_lockp); 306 307 switch (code) { 308 case CB_CODE_CPR_CHKPT: 309 cp->cc_events |= CALLB_CPR_START; 310 while (!(cp->cc_events & CALLB_CPR_SAFE)) 311 /* cv_timedwait() returns -1 if it times out. */ 312 if ((ret = cv_timedwait(&cp->cc_callb_cv, 313 cp->cc_lockp, 314 callb_timeout_sec * hz)) == -1) 315 break; 316 break; 317 318 case CB_CODE_CPR_RESUME: 319 cp->cc_events &= ~CALLB_CPR_START; 320 cv_signal(&cp->cc_stop_cv); 321 break; 322 } 323 mutex_exit(cp->cc_lockp); 324 return (ret != -1); 325} 326 327/* 328 * The generic callback function associated with kernel threads which 329 * are always considered safe. 330 */ 331/* ARGSUSED */ 332boolean_t 333callb_generic_cpr_safe(void *arg, int code) 334{ 335 return (B_TRUE); 336} 337/* 338 * Prevent additions to callback table. 339 */ 340void 341callb_lock_table(void) 342{ 343 mutex_enter(&ct->ct_lock); 344 ASSERT(ct->ct_busy == 0); 345 ct->ct_busy = 1; 346 mutex_exit(&ct->ct_lock); 347} 348 349/* 350 * Allow additions to callback table. 351 */ 352void 353callb_unlock_table(void) 354{ 355 mutex_enter(&ct->ct_lock); 356 ASSERT(ct->ct_busy != 0); 357 ct->ct_busy = 0; 358 cv_broadcast(&ct->ct_busy_cv); 359 mutex_exit(&ct->ct_lock); 360} 361 362SYSINIT(sol_callb, SI_SUB_DRIVERS, SI_ORDER_FIRST, callb_init, NULL) 363SYSUNINIT(sol_callb, SI_SUB_DRIVERS, SI_ORDER_FIRST, callb_fini, NULL); 364