/* * CDDL HEADER START * * The contents of this file are subject to the terms of the * Common Development and Distribution License (the "License"). * You may not use this file except in compliance with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. * See the License for the specific language governing permissions * and limitations under the License. * * When distributing Covered Code, include this CDDL HEADER in each * file and include the License file at usr/src/OPENSOLARIS.LICENSE. * If applicable, add the following below this CDDL HEADER, with the * fields enclosed by brackets "[]" replaced with your own identifying * information: Portions Copyright [yyyy] [name of copyright owner] * * CDDL HEADER END */ /* * Copyright 2009 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ #ifndef _SYS_CALLB_H #define _SYS_CALLB_H #include #ifdef __cplusplus extern "C" { #endif /* * definitions of callback classes (c_class) * * Callbacks belong in the same class if (1) their callback routines * do the same kind of processing (ideally, using the same callback function) * and (2) they can/should be executed at the same time in a cpr * suspend/resume operation. * * Note: The DAEMON class, in particular, is for stopping kernel threads * and nothing else. The CALLB_* macros below should be used to deal * with kernel threads, and the callback function should be callb_generic_cpr. * Another idiosyncrasy of the DAEMON class is that if a suspend operation * fails, some of the callback functions may be called with the RESUME * code which were never called with SUSPEND. Not a problem currently, * but see bug 4201851. */ #define CB_CL_CPR_DAEMON 0 #define CB_CL_CPR_VM 1 #define CB_CL_CPR_CALLOUT 2 #define CB_CL_CPR_OBP 3 #define CB_CL_CPR_FB 4 #define CB_CL_PANIC 5 #define CB_CL_CPR_RPC 6 #define CB_CL_CPR_PROMPRINTF 7 #define CB_CL_UADMIN 8 #define CB_CL_CPR_PM 9 #define CB_CL_HALT 10 #define CB_CL_CPR_DMA 11 #define CB_CL_CPR_POST_USER 12 #define CB_CL_UADMIN_PRE_VFS 13 #define CB_CL_MDBOOT CB_CL_UADMIN #define CB_CL_ENTER_DEBUGGER 14 #define CB_CL_CPR_POST_KERNEL 15 #define CB_CL_CPU_DEEP_IDLE 16 #define NCBCLASS 17 /* CHANGE ME if classes are added/removed */ /* * CB_CL_CPR_DAEMON class specific definitions are given below: */ /* * code for CPR callb_execute_class */ #define CB_CODE_CPR_CHKPT 0 #define CB_CODE_CPR_RESUME 1 typedef void * callb_id_t; /* * Per kernel thread structure for CPR daemon callbacks. * Must be protected by either a existing lock in the daemon or * a new lock created for such a purpose. */ typedef struct callb_cpr { kmutex_t *cc_lockp; /* lock to protect this struct */ char cc_events; /* various events for CPR */ callb_id_t cc_id; /* callb id address */ kcondvar_t cc_callb_cv; /* cv for callback waiting */ kcondvar_t cc_stop_cv; /* cv to checkpoint block */ } callb_cpr_t; /* * cc_events definitions */ #define CALLB_CPR_START 1 /* a checkpoint request's started */ #define CALLB_CPR_SAFE 2 /* thread is safe for CPR */ #define CALLB_CPR_ALWAYS_SAFE 4 /* thread is ALWAYS safe for CPR */ /* * Used when checking that all kernel threads are stopped. */ #define CALLB_MAX_RETRY 3 /* when waiting for kthread to sleep */ #define CALLB_THREAD_DELAY 10 /* ticks allowed to reach sleep */ #define CPR_KTHREAD_TIMEOUT_SEC 90 /* secs before callback times out -- */ /* due to pwr mgmt of disks, make -- */ /* big enough for worst spinup time */ /* * * CALLB_CPR_INIT macro is used by kernel threads to add their entry to * the callback table and perform other initialization. It automatically * adds the thread as being in the callback class CB_CL_CPR_DAEMON. * * cp - ptr to the callb_cpr_t structure for this kernel thread * * lockp - pointer to mutex protecting the callb_cpr_t struct * * func - pointer to the callback function for this kernel thread. * It has the prototype boolean_t (void *arg, int code) * where: arg - ptr to the callb_cpr_t structure * code - not used for this type of callback * returns: B_TRUE if successful; B_FALSE if unsuccessful. * * name - a string giving the name of the kernel thread * * Note: lockp is the lock to protect the callb_cpr_t (cp) structure * later on. No lock held is needed for this initialization. */ #define CALLB_CPR_INIT(cp, lockp, func, name) { \ strlcpy(curthread->td_name, (name), \ sizeof (curthread->td_name)); \ bzero((caddr_t)(cp), sizeof (callb_cpr_t)); \ (cp)->cc_lockp = lockp; \ (cp)->cc_id = callb_add(func, (void *)(cp), \ CB_CL_CPR_DAEMON, name); \ cv_init(&(cp)->cc_callb_cv, NULL, CV_DEFAULT, NULL); \ cv_init(&(cp)->cc_stop_cv, NULL, CV_DEFAULT, NULL); \ } #ifndef __lock_lint #define CALLB_CPR_ASSERT(cp) ASSERT(MUTEX_HELD((cp)->cc_lockp)); #else #define CALLB_CPR_ASSERT(cp) #endif /* * Some threads (like the idle threads) do not adhere to the callback * protocol and are always considered safe. Such threads must never exit. * They register their presence by calling this macro during their * initialization. * * Args: * t - thread pointer of the client kernel thread * name - a string giving the name of the kernel thread */ #define CALLB_CPR_INIT_SAFE(t, name) { \ (void) callb_add_thread(callb_generic_cpr_safe, \ (void *) &callb_cprinfo_safe, CB_CL_CPR_DAEMON, \ name, t); \ } /* * The lock to protect cp's content must be held before * calling the following two macros. * * Any code region between CALLB_CPR_SAFE_BEGIN and CALLB_CPR_SAFE_END * is safe for checkpoint/resume. */ #define CALLB_CPR_SAFE_BEGIN(cp) { \ CALLB_CPR_ASSERT(cp) \ (cp)->cc_events |= CALLB_CPR_SAFE; \ if ((cp)->cc_events & CALLB_CPR_START) \ cv_signal(&(cp)->cc_callb_cv); \ } #define CALLB_CPR_SAFE_END(cp, lockp) { \ CALLB_CPR_ASSERT(cp) \ while ((cp)->cc_events & CALLB_CPR_START) \ cv_wait(&(cp)->cc_stop_cv, lockp); \ (cp)->cc_events &= ~CALLB_CPR_SAFE; \ } /* * cv_destroy is nop right now but may be needed in the future. */ #define CALLB_CPR_EXIT(cp) { \ CALLB_CPR_ASSERT(cp) \ (cp)->cc_events |= CALLB_CPR_SAFE; \ if ((cp)->cc_events & CALLB_CPR_START) \ cv_signal(&(cp)->cc_callb_cv); \ mutex_exit((cp)->cc_lockp); \ (void) callb_delete((cp)->cc_id); \ cv_destroy(&(cp)->cc_callb_cv); \ cv_destroy(&(cp)->cc_stop_cv); \ } extern callb_cpr_t callb_cprinfo_safe; extern callb_id_t callb_add(boolean_t (*)(void *, int), void *, int, char *); extern callb_id_t callb_add_thread(boolean_t (*)(void *, int), void *, int, char *, kthread_id_t); extern int callb_delete(callb_id_t); extern void callb_execute(callb_id_t, int); extern void *callb_execute_class(int, int); extern boolean_t callb_generic_cpr(void *, int); extern boolean_t callb_generic_cpr_safe(void *, int); extern boolean_t callb_is_stopped(kthread_id_t, caddr_t *); extern void callb_lock_table(void); extern void callb_unlock_table(void); #ifdef __cplusplus } #endif #endif /* _SYS_CALLB_H */