1*0Sstevel@tonic-gate /* 2*0Sstevel@tonic-gate * CDDL HEADER START 3*0Sstevel@tonic-gate * 4*0Sstevel@tonic-gate * The contents of this file are subject to the terms of the 5*0Sstevel@tonic-gate * Common Development and Distribution License, Version 1.0 only 6*0Sstevel@tonic-gate * (the "License"). You may not use this file except in compliance 7*0Sstevel@tonic-gate * with the License. 8*0Sstevel@tonic-gate * 9*0Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10*0Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 11*0Sstevel@tonic-gate * See the License for the specific language governing permissions 12*0Sstevel@tonic-gate * and limitations under the License. 13*0Sstevel@tonic-gate * 14*0Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 15*0Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16*0Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 17*0Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 18*0Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 19*0Sstevel@tonic-gate * 20*0Sstevel@tonic-gate * CDDL HEADER END 21*0Sstevel@tonic-gate */ 22*0Sstevel@tonic-gate /* 23*0Sstevel@tonic-gate * Copyright 2005 Sun Microsystems, Inc. All rights reserved. 24*0Sstevel@tonic-gate * Use is subject to license terms. 25*0Sstevel@tonic-gate */ 26*0Sstevel@tonic-gate 27*0Sstevel@tonic-gate #ifndef _SYS_CALLB_H 28*0Sstevel@tonic-gate #define _SYS_CALLB_H 29*0Sstevel@tonic-gate 30*0Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI" 31*0Sstevel@tonic-gate 32*0Sstevel@tonic-gate #include <sys/t_lock.h> 33*0Sstevel@tonic-gate #include <sys/thread.h> 34*0Sstevel@tonic-gate 35*0Sstevel@tonic-gate #ifdef __cplusplus 36*0Sstevel@tonic-gate extern "C" { 37*0Sstevel@tonic-gate #endif 38*0Sstevel@tonic-gate 39*0Sstevel@tonic-gate /* 40*0Sstevel@tonic-gate * definitions of callback classes (c_class) 41*0Sstevel@tonic-gate * 42*0Sstevel@tonic-gate * Callbacks belong in the same class if (1) their callback routines 43*0Sstevel@tonic-gate * do the same kind of processing (ideally, using the same callback function) 44*0Sstevel@tonic-gate * and (2) they can/should be executed at the same time in a cpr 45*0Sstevel@tonic-gate * suspend/resume operation. 46*0Sstevel@tonic-gate * 47*0Sstevel@tonic-gate * Note: The DAEMON class, in particular, is for stopping kernel threads 48*0Sstevel@tonic-gate * and nothing else. The CALLB_* macros below should be used to deal 49*0Sstevel@tonic-gate * with kernel threads, and the callback function should be callb_generic_cpr. 50*0Sstevel@tonic-gate * Another idiosyncrasy of the DAEMON class is that if a suspend operation 51*0Sstevel@tonic-gate * fails, some of the callback functions may be called with the RESUME 52*0Sstevel@tonic-gate * code which were never called with SUSPEND. Not a problem currently, 53*0Sstevel@tonic-gate * but see bug 4201851. 54*0Sstevel@tonic-gate */ 55*0Sstevel@tonic-gate #define CB_CL_CPR_DAEMON 0 56*0Sstevel@tonic-gate #define CB_CL_CPR_VM 1 57*0Sstevel@tonic-gate #define CB_CL_CPR_CALLOUT 2 58*0Sstevel@tonic-gate #define CB_CL_CPR_OBP 3 59*0Sstevel@tonic-gate #define CB_CL_CPR_FB 4 60*0Sstevel@tonic-gate #define CB_CL_PANIC 5 61*0Sstevel@tonic-gate #define CB_CL_CPR_RPC 6 62*0Sstevel@tonic-gate #define CB_CL_CPR_PROMPRINTF 7 63*0Sstevel@tonic-gate #define CB_CL_UADMIN 8 64*0Sstevel@tonic-gate #define CB_CL_CPR_PM 9 65*0Sstevel@tonic-gate #define CB_CL_HALT 10 66*0Sstevel@tonic-gate #define CB_CL_CPR_DMA 11 67*0Sstevel@tonic-gate #define CB_CL_CPR_POST_USER 12 68*0Sstevel@tonic-gate #define CB_CL_UADMIN_PRE_VFS 13 69*0Sstevel@tonic-gate #define CB_CL_UADMIN_POST_VFS CB_CL_UADMIN 70*0Sstevel@tonic-gate #define CB_CL_ENTER_DEBUGGER 14 71*0Sstevel@tonic-gate #define CB_CL_CPR_POST_KERNEL 15 72*0Sstevel@tonic-gate #define NCBCLASS 16 /* CHANGE ME if classes are added/removed */ 73*0Sstevel@tonic-gate 74*0Sstevel@tonic-gate /* 75*0Sstevel@tonic-gate * CB_CL_CPR_DAEMON class specific definitions are given below: 76*0Sstevel@tonic-gate */ 77*0Sstevel@tonic-gate 78*0Sstevel@tonic-gate /* 79*0Sstevel@tonic-gate * code for CPR callb_execute_class 80*0Sstevel@tonic-gate */ 81*0Sstevel@tonic-gate #define CB_CODE_CPR_CHKPT 0 82*0Sstevel@tonic-gate #define CB_CODE_CPR_RESUME 1 83*0Sstevel@tonic-gate 84*0Sstevel@tonic-gate typedef void * callb_id_t; 85*0Sstevel@tonic-gate /* 86*0Sstevel@tonic-gate * Per kernel thread structure for CPR daemon callbacks. 87*0Sstevel@tonic-gate * Must be protected by either a existing lock in the daemon or 88*0Sstevel@tonic-gate * a new lock created for such a purpose. 89*0Sstevel@tonic-gate */ 90*0Sstevel@tonic-gate typedef struct callb_cpr { 91*0Sstevel@tonic-gate kmutex_t *cc_lockp; /* lock to protect this struct */ 92*0Sstevel@tonic-gate char cc_events; /* various events for CPR */ 93*0Sstevel@tonic-gate callb_id_t cc_id; /* callb id address */ 94*0Sstevel@tonic-gate kcondvar_t cc_callb_cv; /* cv for callback waiting */ 95*0Sstevel@tonic-gate kcondvar_t cc_stop_cv; /* cv to checkpoint block */ 96*0Sstevel@tonic-gate } callb_cpr_t; 97*0Sstevel@tonic-gate 98*0Sstevel@tonic-gate /* 99*0Sstevel@tonic-gate * cc_events definitions 100*0Sstevel@tonic-gate */ 101*0Sstevel@tonic-gate #define CALLB_CPR_START 1 /* a checkpoint request's started */ 102*0Sstevel@tonic-gate #define CALLB_CPR_SAFE 2 /* thread is safe for CPR */ 103*0Sstevel@tonic-gate #define CALLB_CPR_ALWAYS_SAFE 4 /* thread is ALWAYS safe for CPR */ 104*0Sstevel@tonic-gate 105*0Sstevel@tonic-gate /* 106*0Sstevel@tonic-gate * Used when checking that all kernel threads are stopped. 107*0Sstevel@tonic-gate */ 108*0Sstevel@tonic-gate #define CALLB_MAX_RETRY 3 /* when waiting for kthread to sleep */ 109*0Sstevel@tonic-gate #define CALLB_THREAD_DELAY 10 /* ticks allowed to reach sleep */ 110*0Sstevel@tonic-gate #define CPR_KTHREAD_TIMEOUT_SEC 90 /* secs before callback times out -- */ 111*0Sstevel@tonic-gate /* due to pwr mgmt of disks, make -- */ 112*0Sstevel@tonic-gate /* big enough for worst spinup time */ 113*0Sstevel@tonic-gate 114*0Sstevel@tonic-gate #ifdef _KERNEL 115*0Sstevel@tonic-gate /* 116*0Sstevel@tonic-gate * 117*0Sstevel@tonic-gate * CALLB_CPR_INIT macro is used by kernel threads to add their entry to 118*0Sstevel@tonic-gate * the callback table and perform other initialization. It automatically 119*0Sstevel@tonic-gate * adds the thread as being in the callback class CB_CL_CPR_DAEMON. 120*0Sstevel@tonic-gate * 121*0Sstevel@tonic-gate * cp - ptr to the callb_cpr_t structure for this kernel thread 122*0Sstevel@tonic-gate * 123*0Sstevel@tonic-gate * lockp - pointer to mutex protecting the callb_cpr_t stuct 124*0Sstevel@tonic-gate * 125*0Sstevel@tonic-gate * func - pointer to the callback function for this kernel thread. 126*0Sstevel@tonic-gate * It has the prototype boolean_t <func>(void *arg, int code) 127*0Sstevel@tonic-gate * where: arg - ptr to the callb_cpr_t structure 128*0Sstevel@tonic-gate * code - not used for this type of callback 129*0Sstevel@tonic-gate * returns: B_TRUE if successful; B_FALSE if unsuccessful. 130*0Sstevel@tonic-gate * 131*0Sstevel@tonic-gate * name - a string giving the name of the kernel thread 132*0Sstevel@tonic-gate * 133*0Sstevel@tonic-gate * Note: lockp is the lock to protect the callb_cpr_t (cp) structure 134*0Sstevel@tonic-gate * later on. No lock held is needed for this initialization. 135*0Sstevel@tonic-gate */ 136*0Sstevel@tonic-gate #define CALLB_CPR_INIT(cp, lockp, func, name) { \ 137*0Sstevel@tonic-gate bzero((caddr_t)(cp), sizeof (callb_cpr_t)); \ 138*0Sstevel@tonic-gate (cp)->cc_lockp = lockp; \ 139*0Sstevel@tonic-gate (cp)->cc_id = callb_add(func, (void *)(cp), \ 140*0Sstevel@tonic-gate CB_CL_CPR_DAEMON, name); \ 141*0Sstevel@tonic-gate } 142*0Sstevel@tonic-gate 143*0Sstevel@tonic-gate #ifndef __lock_lint 144*0Sstevel@tonic-gate #define CALLB_CPR_ASSERT(cp) ASSERT(MUTEX_HELD((cp)->cc_lockp)); 145*0Sstevel@tonic-gate #else 146*0Sstevel@tonic-gate #define CALLB_CPR_ASSERT(cp) 147*0Sstevel@tonic-gate #endif 148*0Sstevel@tonic-gate /* 149*0Sstevel@tonic-gate * Some threads (like the idle threads) do not adhere to the callback 150*0Sstevel@tonic-gate * protocol and are always considered safe. Such threads must never exit. 151*0Sstevel@tonic-gate * They register their presence by calling this macro during their 152*0Sstevel@tonic-gate * initialization. 153*0Sstevel@tonic-gate * 154*0Sstevel@tonic-gate * Args: 155*0Sstevel@tonic-gate * t - thread pointer of the client kernel thread 156*0Sstevel@tonic-gate * name - a string giving the name of the kernel thread 157*0Sstevel@tonic-gate */ 158*0Sstevel@tonic-gate #define CALLB_CPR_INIT_SAFE(t, name) { \ 159*0Sstevel@tonic-gate (void) callb_add_thread(callb_generic_cpr_safe, \ 160*0Sstevel@tonic-gate (void *) &callb_cprinfo_safe, CB_CL_CPR_DAEMON, \ 161*0Sstevel@tonic-gate name, t); \ 162*0Sstevel@tonic-gate } 163*0Sstevel@tonic-gate /* 164*0Sstevel@tonic-gate * The lock to protect cp's content must be held before 165*0Sstevel@tonic-gate * calling the following two macros. 166*0Sstevel@tonic-gate * 167*0Sstevel@tonic-gate * Any code region between CALLB_CPR_SAFE_BEGIN and CALLB_CPR_SAFE_END 168*0Sstevel@tonic-gate * is safe for checkpoint/resume. 169*0Sstevel@tonic-gate */ 170*0Sstevel@tonic-gate #define CALLB_CPR_SAFE_BEGIN(cp) { \ 171*0Sstevel@tonic-gate CALLB_CPR_ASSERT(cp) \ 172*0Sstevel@tonic-gate (cp)->cc_events |= CALLB_CPR_SAFE; \ 173*0Sstevel@tonic-gate if ((cp)->cc_events & CALLB_CPR_START) \ 174*0Sstevel@tonic-gate cv_signal(&(cp)->cc_callb_cv); \ 175*0Sstevel@tonic-gate } 176*0Sstevel@tonic-gate #define CALLB_CPR_SAFE_END(cp, lockp) { \ 177*0Sstevel@tonic-gate CALLB_CPR_ASSERT(cp) \ 178*0Sstevel@tonic-gate while ((cp)->cc_events & CALLB_CPR_START) \ 179*0Sstevel@tonic-gate cv_wait(&(cp)->cc_stop_cv, lockp); \ 180*0Sstevel@tonic-gate (cp)->cc_events &= ~CALLB_CPR_SAFE; \ 181*0Sstevel@tonic-gate } 182*0Sstevel@tonic-gate /* 183*0Sstevel@tonic-gate * cv_destroy is nop right now but may be needed in the future. 184*0Sstevel@tonic-gate */ 185*0Sstevel@tonic-gate #define CALLB_CPR_EXIT(cp) { \ 186*0Sstevel@tonic-gate CALLB_CPR_ASSERT(cp) \ 187*0Sstevel@tonic-gate (cp)->cc_events |= CALLB_CPR_SAFE; \ 188*0Sstevel@tonic-gate if ((cp)->cc_events & CALLB_CPR_START) \ 189*0Sstevel@tonic-gate cv_signal(&(cp)->cc_callb_cv); \ 190*0Sstevel@tonic-gate mutex_exit((cp)->cc_lockp); \ 191*0Sstevel@tonic-gate (void) callb_delete((cp)->cc_id); \ 192*0Sstevel@tonic-gate cv_destroy(&(cp)->cc_callb_cv); \ 193*0Sstevel@tonic-gate cv_destroy(&(cp)->cc_stop_cv); \ 194*0Sstevel@tonic-gate } 195*0Sstevel@tonic-gate 196*0Sstevel@tonic-gate extern callb_cpr_t callb_cprinfo_safe; 197*0Sstevel@tonic-gate extern void callb_init(void); 198*0Sstevel@tonic-gate extern callb_id_t callb_add(boolean_t (*)(void *, int), void *, int, char *); 199*0Sstevel@tonic-gate extern callb_id_t callb_add_thread(boolean_t (*)(void *, int), 200*0Sstevel@tonic-gate void *, int, char *, kthread_id_t); 201*0Sstevel@tonic-gate extern int callb_delete(callb_id_t); 202*0Sstevel@tonic-gate extern void callb_execute(callb_id_t, int); 203*0Sstevel@tonic-gate extern void *callb_execute_class(int, int); 204*0Sstevel@tonic-gate extern boolean_t callb_generic_cpr(void *, int); 205*0Sstevel@tonic-gate extern boolean_t callb_generic_cpr_safe(void *, int); 206*0Sstevel@tonic-gate extern boolean_t callb_is_stopped(kthread_id_t, caddr_t *); 207*0Sstevel@tonic-gate extern void callb_lock_table(void); 208*0Sstevel@tonic-gate extern void callb_unlock_table(void); 209*0Sstevel@tonic-gate #endif 210*0Sstevel@tonic-gate 211*0Sstevel@tonic-gate #ifdef __cplusplus 212*0Sstevel@tonic-gate } 213*0Sstevel@tonic-gate #endif 214*0Sstevel@tonic-gate 215*0Sstevel@tonic-gate #endif /* _SYS_CALLB_H */ 216