1168404Spjd/* 2168404Spjd * CDDL HEADER START 3168404Spjd * 4168404Spjd * The contents of this file are subject to the terms of the 5185029Spjd * Common Development and Distribution License (the "License"). 6185029Spjd * You may not use this file except in compliance with the License. 7168404Spjd * 8168404Spjd * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9168404Spjd * or http://www.opensolaris.org/os/licensing. 10168404Spjd * See the License for the specific language governing permissions 11168404Spjd * and limitations under the License. 12168404Spjd * 13168404Spjd * When distributing Covered Code, include this CDDL HEADER in each 14168404Spjd * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15168404Spjd * If applicable, add the following below this CDDL HEADER, with the 16168404Spjd * fields enclosed by brackets "[]" replaced with your own identifying 17168404Spjd * information: Portions Copyright [yyyy] [name of copyright owner] 18168404Spjd * 19168404Spjd * CDDL HEADER END 20168404Spjd */ 21168404Spjd/* 22219089Spjd * Copyright 2009 Sun Microsystems, Inc. All rights reserved. 23168404Spjd * Use is subject to license terms. 24168404Spjd */ 25168404Spjd 26168404Spjd#include <sys/param.h> 27168404Spjd#include <sys/types.h> 28168404Spjd#include <sys/time.h> 29168404Spjd#include <sys/sysmacros.h> 30168404Spjd#include <sys/systm.h> 31168404Spjd#include <sys/proc.h> 32168404Spjd#include <sys/mutex.h> 33168404Spjd#include <sys/condvar.h> 34168404Spjd#include <sys/callb.h> 35168404Spjd#include <sys/kmem.h> 36168404Spjd#include <sys/cmn_err.h> 37168404Spjd#include <sys/debug.h> 38168404Spjd#include <sys/kobj.h> 39168404Spjd#include <sys/systm.h> /* for delay() */ 40168404Spjd#include <sys/taskq.h> /* For TASKQ_NAMELEN */ 41168404Spjd#include <sys/kernel.h> 42168404Spjd 43168404Spjd#define CB_MAXNAME TASKQ_NAMELEN 44168404Spjd 45168404Spjd/* 46168404Spjd * The callb mechanism provides generic event scheduling/echoing. 47168404Spjd * A callb function is registered and called on behalf of the event. 48168404Spjd */ 49168404Spjdtypedef struct callb { 50168404Spjd struct callb *c_next; /* next in class or on freelist */ 51168404Spjd kthread_id_t c_thread; /* ptr to caller's thread struct */ 52168404Spjd char c_flag; /* info about the callb state */ 53168404Spjd uchar_t c_class; /* this callb's class */ 54168404Spjd kcondvar_t c_done_cv; /* signal callb completion */ 55168404Spjd boolean_t (*c_func)(); /* cb function: returns true if ok */ 56168404Spjd void *c_arg; /* arg to c_func */ 57168404Spjd char c_name[CB_MAXNAME+1]; /* debug:max func name length */ 58168404Spjd} callb_t; 59168404Spjd 60168404Spjd/* 61168404Spjd * callb c_flag bitmap definitions 62168404Spjd */ 63168404Spjd#define CALLB_FREE 0x0 64168404Spjd#define CALLB_TAKEN 0x1 65168404Spjd#define CALLB_EXECUTING 0x2 66168404Spjd 67168404Spjd/* 68168404Spjd * Basic structure for a callb table. 69168404Spjd * All callbs are organized into different class groups described 70168404Spjd * by ct_class array. 71168404Spjd * The callbs within a class are single-linked and normally run by a 72168404Spjd * serial execution. 73168404Spjd */ 74168404Spjdtypedef struct callb_table { 75168404Spjd kmutex_t ct_lock; /* protect all callb states */ 76168404Spjd callb_t *ct_freelist; /* free callb structures */ 77168404Spjd int ct_busy; /* != 0 prevents additions */ 78168404Spjd kcondvar_t ct_busy_cv; /* to wait for not busy */ 79168404Spjd int ct_ncallb; /* num of callbs allocated */ 80168404Spjd callb_t *ct_first_cb[NCBCLASS]; /* ptr to 1st callb in a class */ 81168404Spjd} callb_table_t; 82168404Spjd 83168404Spjdint callb_timeout_sec = CPR_KTHREAD_TIMEOUT_SEC; 84168404Spjd 85168404Spjdstatic callb_id_t callb_add_common(boolean_t (*)(void *, int), 86168404Spjd void *, int, char *, kthread_id_t); 87168404Spjd 88168404Spjdstatic callb_table_t callb_table; /* system level callback table */ 89168404Spjdstatic callb_table_t *ct = &callb_table; 90168404Spjdstatic kmutex_t callb_safe_mutex; 91168404Spjdcallb_cpr_t callb_cprinfo_safe = { 92168404Spjd &callb_safe_mutex, CALLB_CPR_ALWAYS_SAFE, 0, 0, 0 }; 93168404Spjd 94168404Spjd/* 95168404Spjd * Init all callb tables in the system. 96168404Spjd */ 97168404Spjdvoid 98168404Spjdcallb_init(void *dummy __unused) 99168404Spjd{ 100168404Spjd callb_table.ct_busy = 0; /* mark table open for additions */ 101168404Spjd mutex_init(&callb_safe_mutex, NULL, MUTEX_DEFAULT, NULL); 102168404Spjd mutex_init(&callb_table.ct_lock, NULL, MUTEX_DEFAULT, NULL); 103168404Spjd} 104168404Spjd 105168404Spjdvoid 106168404Spjdcallb_fini(void *dummy __unused) 107168404Spjd{ 108168404Spjd callb_t *cp; 109185029Spjd int i; 110168404Spjd 111168404Spjd mutex_enter(&ct->ct_lock); 112185029Spjd for (i = 0; i < 16; i++) { 113185029Spjd while ((cp = ct->ct_freelist) != NULL) { 114185029Spjd ct->ct_freelist = cp->c_next; 115185029Spjd ct->ct_ncallb--; 116185029Spjd kmem_free(cp, sizeof (callb_t)); 117185029Spjd } 118185029Spjd if (ct->ct_ncallb == 0) 119185029Spjd break; 120185029Spjd /* Not all callbacks finished, waiting for the rest. */ 121185029Spjd mutex_exit(&ct->ct_lock); 122185029Spjd tsleep(ct, 0, "callb", hz / 4); 123185029Spjd mutex_enter(&ct->ct_lock); 124168404Spjd } 125185029Spjd if (ct->ct_ncallb > 0) 126185029Spjd printf("%s: Leaked %d callbacks!\n", __func__, ct->ct_ncallb); 127168404Spjd mutex_exit(&ct->ct_lock); 128168404Spjd mutex_destroy(&callb_safe_mutex); 129168404Spjd mutex_destroy(&callb_table.ct_lock); 130168404Spjd} 131168404Spjd 132168404Spjd/* 133168404Spjd * callout_add() is called to register func() be called later. 134168404Spjd */ 135168404Spjdstatic callb_id_t 136168404Spjdcallb_add_common(boolean_t (*func)(void *arg, int code), 137168404Spjd void *arg, int class, char *name, kthread_id_t t) 138168404Spjd{ 139168404Spjd callb_t *cp; 140168404Spjd 141168404Spjd ASSERT(class < NCBCLASS); 142168404Spjd 143168404Spjd mutex_enter(&ct->ct_lock); 144168404Spjd while (ct->ct_busy) 145168404Spjd cv_wait(&ct->ct_busy_cv, &ct->ct_lock); 146168404Spjd if ((cp = ct->ct_freelist) == NULL) { 147168404Spjd ct->ct_ncallb++; 148168404Spjd cp = (callb_t *)kmem_zalloc(sizeof (callb_t), KM_SLEEP); 149168404Spjd } 150168404Spjd ct->ct_freelist = cp->c_next; 151168404Spjd cp->c_thread = t; 152168404Spjd cp->c_func = func; 153168404Spjd cp->c_arg = arg; 154168404Spjd cp->c_class = (uchar_t)class; 155168404Spjd cp->c_flag |= CALLB_TAKEN; 156168404Spjd#ifdef DEBUG 157168404Spjd if (strlen(name) > CB_MAXNAME) 158168404Spjd cmn_err(CE_WARN, "callb_add: name of callback function '%s' " 159168404Spjd "too long -- truncated to %d chars", 160168404Spjd name, CB_MAXNAME); 161168404Spjd#endif 162168404Spjd (void) strncpy(cp->c_name, name, CB_MAXNAME); 163168404Spjd cp->c_name[CB_MAXNAME] = '\0'; 164168404Spjd 165168404Spjd /* 166168404Spjd * Insert the new callb at the head of its class list. 167168404Spjd */ 168168404Spjd cp->c_next = ct->ct_first_cb[class]; 169168404Spjd ct->ct_first_cb[class] = cp; 170168404Spjd 171168404Spjd mutex_exit(&ct->ct_lock); 172168404Spjd return ((callb_id_t)cp); 173168404Spjd} 174168404Spjd 175168404Spjd/* 176168404Spjd * The default function to add an entry to the callback table. Since 177168404Spjd * it uses curthread as the thread identifier to store in the table, 178168404Spjd * it should be used for the normal case of a thread which is calling 179168404Spjd * to add ITSELF to the table. 180168404Spjd */ 181168404Spjdcallb_id_t 182168404Spjdcallb_add(boolean_t (*func)(void *arg, int code), 183168404Spjd void *arg, int class, char *name) 184168404Spjd{ 185168404Spjd return (callb_add_common(func, arg, class, name, curthread)); 186168404Spjd} 187168404Spjd 188168404Spjd/* 189168404Spjd * A special version of callb_add() above for use by threads which 190168404Spjd * might be adding an entry to the table on behalf of some other 191168404Spjd * thread (for example, one which is constructed but not yet running). 192168404Spjd * In this version the thread id is an argument. 193168404Spjd */ 194168404Spjdcallb_id_t 195168404Spjdcallb_add_thread(boolean_t (*func)(void *arg, int code), 196168404Spjd void *arg, int class, char *name, kthread_id_t t) 197168404Spjd{ 198168404Spjd return (callb_add_common(func, arg, class, name, t)); 199168404Spjd} 200168404Spjd 201168404Spjd/* 202168404Spjd * callout_delete() is called to remove an entry identified by id 203168404Spjd * that was originally placed there by a call to callout_add(). 204168404Spjd * return -1 if fail to delete a callb entry otherwise return 0. 205168404Spjd */ 206168404Spjdint 207168404Spjdcallb_delete(callb_id_t id) 208168404Spjd{ 209168404Spjd callb_t **pp; 210168404Spjd callb_t *me = (callb_t *)id; 211168404Spjd 212168404Spjd mutex_enter(&ct->ct_lock); 213168404Spjd 214168404Spjd for (;;) { 215168404Spjd pp = &ct->ct_first_cb[me->c_class]; 216168404Spjd while (*pp != NULL && *pp != me) 217168404Spjd pp = &(*pp)->c_next; 218168404Spjd 219168404Spjd#ifdef DEBUG 220168404Spjd if (*pp != me) { 221168404Spjd cmn_err(CE_WARN, "callb delete bogus entry 0x%p", 222168404Spjd (void *)me); 223168404Spjd mutex_exit(&ct->ct_lock); 224168404Spjd return (-1); 225168404Spjd } 226168404Spjd#endif /* DEBUG */ 227168404Spjd 228168404Spjd /* 229168404Spjd * It is not allowed to delete a callb in the middle of 230168404Spjd * executing otherwise, the callb_execute() will be confused. 231168404Spjd */ 232168404Spjd if (!(me->c_flag & CALLB_EXECUTING)) 233168404Spjd break; 234168404Spjd 235168404Spjd cv_wait(&me->c_done_cv, &ct->ct_lock); 236168404Spjd } 237168404Spjd /* relink the class list */ 238168404Spjd *pp = me->c_next; 239168404Spjd 240168404Spjd /* clean up myself and return the free callb to the head of freelist */ 241168404Spjd me->c_flag = CALLB_FREE; 242168404Spjd me->c_next = ct->ct_freelist; 243168404Spjd ct->ct_freelist = me; 244168404Spjd 245168404Spjd mutex_exit(&ct->ct_lock); 246168404Spjd return (0); 247168404Spjd} 248168404Spjd 249168404Spjd/* 250168404Spjd * class: indicates to execute all callbs in the same class; 251168404Spjd * code: optional argument for the callb functions. 252168404Spjd * return: = 0: success 253168404Spjd * != 0: ptr to string supplied when callback was registered 254168404Spjd */ 255168404Spjdvoid * 256168404Spjdcallb_execute_class(int class, int code) 257168404Spjd{ 258168404Spjd callb_t *cp; 259168404Spjd void *ret = NULL; 260168404Spjd 261168404Spjd ASSERT(class < NCBCLASS); 262168404Spjd 263168404Spjd mutex_enter(&ct->ct_lock); 264168404Spjd 265168404Spjd for (cp = ct->ct_first_cb[class]; 266168404Spjd cp != NULL && ret == 0; cp = cp->c_next) { 267168404Spjd while (cp->c_flag & CALLB_EXECUTING) 268168404Spjd cv_wait(&cp->c_done_cv, &ct->ct_lock); 269168404Spjd /* 270168404Spjd * cont if the callb is deleted while we're sleeping 271168404Spjd */ 272168404Spjd if (cp->c_flag == CALLB_FREE) 273168404Spjd continue; 274168404Spjd cp->c_flag |= CALLB_EXECUTING; 275168404Spjd 276168404Spjd#ifdef CALLB_DEBUG 277168404Spjd printf("callb_execute: name=%s func=%p arg=%p\n", 278185029Spjd cp->c_name, (void *)cp->c_func, (void *)cp->c_arg); 279168404Spjd#endif /* CALLB_DEBUG */ 280168404Spjd 281168404Spjd mutex_exit(&ct->ct_lock); 282168404Spjd /* If callback function fails, pass back client's name */ 283168404Spjd if (!(*cp->c_func)(cp->c_arg, code)) 284168404Spjd ret = cp->c_name; 285168404Spjd mutex_enter(&ct->ct_lock); 286168404Spjd 287168404Spjd cp->c_flag &= ~CALLB_EXECUTING; 288168404Spjd cv_broadcast(&cp->c_done_cv); 289168404Spjd } 290168404Spjd mutex_exit(&ct->ct_lock); 291168404Spjd return (ret); 292168404Spjd} 293168404Spjd 294168404Spjd/* 295168404Spjd * callers make sure no recursive entries to this func. 296168404Spjd * dp->cc_lockp is registered by callb_add to protect callb_cpr_t structure. 297168404Spjd * 298168404Spjd * When calling to stop a kernel thread (code == CB_CODE_CPR_CHKPT) we 299168404Spjd * use a cv_timedwait() in case the kernel thread is blocked. 300168404Spjd * 301168404Spjd * Note that this is a generic callback handler for daemon CPR and 302168404Spjd * should NOT be changed to accommodate any specific requirement in a daemon. 303168404Spjd * Individual daemons that require changes to the handler shall write 304168404Spjd * callback routines in their own daemon modules. 305168404Spjd */ 306168404Spjdboolean_t 307168404Spjdcallb_generic_cpr(void *arg, int code) 308168404Spjd{ 309168404Spjd callb_cpr_t *cp = (callb_cpr_t *)arg; 310168404Spjd clock_t ret = 0; /* assume success */ 311168404Spjd 312168404Spjd mutex_enter(cp->cc_lockp); 313168404Spjd 314168404Spjd switch (code) { 315168404Spjd case CB_CODE_CPR_CHKPT: 316168404Spjd cp->cc_events |= CALLB_CPR_START; 317185029Spjd#ifdef CPR_NOT_THREAD_SAFE 318168404Spjd while (!(cp->cc_events & CALLB_CPR_SAFE)) 319168404Spjd /* cv_timedwait() returns -1 if it times out. */ 320219089Spjd if ((ret = cv_reltimedwait(&cp->cc_callb_cv, 321219089Spjd cp->cc_lockp, (callb_timeout_sec * hz), 322219089Spjd TR_CLOCK_TICK)) == -1) 323168404Spjd break; 324185029Spjd#endif 325168404Spjd break; 326168404Spjd 327168404Spjd case CB_CODE_CPR_RESUME: 328168404Spjd cp->cc_events &= ~CALLB_CPR_START; 329168404Spjd cv_signal(&cp->cc_stop_cv); 330168404Spjd break; 331168404Spjd } 332168404Spjd mutex_exit(cp->cc_lockp); 333168404Spjd return (ret != -1); 334168404Spjd} 335168404Spjd 336168404Spjd/* 337168404Spjd * The generic callback function associated with kernel threads which 338168404Spjd * are always considered safe. 339168404Spjd */ 340168404Spjd/* ARGSUSED */ 341168404Spjdboolean_t 342168404Spjdcallb_generic_cpr_safe(void *arg, int code) 343168404Spjd{ 344168404Spjd return (B_TRUE); 345168404Spjd} 346168404Spjd/* 347168404Spjd * Prevent additions to callback table. 348168404Spjd */ 349168404Spjdvoid 350168404Spjdcallb_lock_table(void) 351168404Spjd{ 352168404Spjd mutex_enter(&ct->ct_lock); 353168404Spjd ASSERT(ct->ct_busy == 0); 354168404Spjd ct->ct_busy = 1; 355168404Spjd mutex_exit(&ct->ct_lock); 356168404Spjd} 357168404Spjd 358168404Spjd/* 359168404Spjd * Allow additions to callback table. 360168404Spjd */ 361168404Spjdvoid 362168404Spjdcallb_unlock_table(void) 363168404Spjd{ 364168404Spjd mutex_enter(&ct->ct_lock); 365168404Spjd ASSERT(ct->ct_busy != 0); 366168404Spjd ct->ct_busy = 0; 367168404Spjd cv_broadcast(&ct->ct_busy_cv); 368168404Spjd mutex_exit(&ct->ct_lock); 369168404Spjd} 370168404Spjd 371219089Spjd#ifdef sun 372219089Spjd/* 373219089Spjd * Return a boolean value indicating whether a particular kernel thread is 374219089Spjd * stopped in accordance with the cpr callback protocol. If returning 375219089Spjd * false, also return a pointer to the thread name via the 2nd argument. 376219089Spjd */ 377219089Spjdboolean_t 378219089Spjdcallb_is_stopped(kthread_id_t tp, caddr_t *thread_name) 379219089Spjd{ 380219089Spjd callb_t *cp; 381219089Spjd boolean_t ret_val; 382219089Spjd 383219089Spjd mutex_enter(&ct->ct_lock); 384219089Spjd 385219089Spjd for (cp = ct->ct_first_cb[CB_CL_CPR_DAEMON]; 386219089Spjd cp != NULL && tp != cp->c_thread; cp = cp->c_next) 387219089Spjd ; 388219089Spjd 389219089Spjd ret_val = (cp != NULL); 390219089Spjd if (ret_val) { 391219089Spjd /* 392219089Spjd * We found the thread in the callback table and have 393219089Spjd * provisionally set the return value to true. Now 394219089Spjd * see if it is marked "safe" and is sleeping or stopped. 395219089Spjd */ 396219089Spjd callb_cpr_t *ccp = (callb_cpr_t *)cp->c_arg; 397219089Spjd 398219089Spjd *thread_name = cp->c_name; /* in case not stopped */ 399219089Spjd mutex_enter(ccp->cc_lockp); 400219089Spjd 401219089Spjd if (ccp->cc_events & CALLB_CPR_SAFE) { 402219089Spjd int retry; 403219089Spjd 404219089Spjd mutex_exit(ccp->cc_lockp); 405219089Spjd for (retry = 0; retry < CALLB_MAX_RETRY; retry++) { 406219089Spjd thread_lock(tp); 407219089Spjd if (tp->t_state & (TS_SLEEP | TS_STOPPED)) { 408219089Spjd thread_unlock(tp); 409219089Spjd break; 410219089Spjd } 411219089Spjd thread_unlock(tp); 412219089Spjd delay(CALLB_THREAD_DELAY); 413219089Spjd } 414219089Spjd ret_val = retry < CALLB_MAX_RETRY; 415219089Spjd } else { 416219089Spjd ret_val = 417219089Spjd (ccp->cc_events & CALLB_CPR_ALWAYS_SAFE) != 0; 418219089Spjd mutex_exit(ccp->cc_lockp); 419219089Spjd } 420219089Spjd } else { 421219089Spjd /* 422219089Spjd * Thread not found in callback table. Make the best 423219089Spjd * attempt to identify the thread in the error message. 424219089Spjd */ 425219089Spjd ulong_t offset; 426219089Spjd char *sym = kobj_getsymname((uintptr_t)tp->t_startpc, 427219089Spjd &offset); 428219089Spjd 429219089Spjd *thread_name = sym ? sym : "*unknown*"; 430219089Spjd } 431219089Spjd 432219089Spjd mutex_exit(&ct->ct_lock); 433219089Spjd return (ret_val); 434219089Spjd} 435219089Spjd#endif /* sun */ 436219089Spjd 437177253SrwatsonSYSINIT(sol_callb, SI_SUB_DRIVERS, SI_ORDER_FIRST, callb_init, NULL); 438168404SpjdSYSUNINIT(sol_callb, SI_SUB_DRIVERS, SI_ORDER_FIRST, callb_fini, NULL); 439