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