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