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