]>
Commit | Line | Data |
---|---|---|
9f0a21e6 MM |
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/condvar.h> | |
30 | ||
31 | #ifdef __cplusplus | |
32 | extern "C" { | |
33 | #endif | |
34 | ||
35 | /* | |
36 | * definitions of callback classes (c_class) | |
37 | * | |
38 | * Callbacks belong in the same class if (1) their callback routines | |
39 | * do the same kind of processing (ideally, using the same callback function) | |
40 | * and (2) they can/should be executed at the same time in a cpr | |
41 | * suspend/resume operation. | |
42 | * | |
43 | * Note: The DAEMON class, in particular, is for stopping kernel threads | |
44 | * and nothing else. The CALLB_* macros below should be used to deal | |
45 | * with kernel threads, and the callback function should be callb_generic_cpr. | |
46 | * Another idiosyncrasy of the DAEMON class is that if a suspend operation | |
47 | * fails, some of the callback functions may be called with the RESUME | |
48 | * code which were never called with SUSPEND. Not a problem currently, | |
49 | * but see bug 4201851. | |
50 | */ | |
51 | #define CB_CL_CPR_DAEMON 0 | |
52 | #define CB_CL_CPR_VM 1 | |
53 | #define CB_CL_CPR_CALLOUT 2 | |
54 | #define CB_CL_CPR_OBP 3 | |
55 | #define CB_CL_CPR_FB 4 | |
56 | #define CB_CL_PANIC 5 | |
57 | #define CB_CL_CPR_RPC 6 | |
58 | #define CB_CL_CPR_PROMPRINTF 7 | |
59 | #define CB_CL_UADMIN 8 | |
60 | #define CB_CL_CPR_PM 9 | |
61 | #define CB_CL_HALT 10 | |
62 | #define CB_CL_CPR_DMA 11 | |
63 | #define CB_CL_CPR_POST_USER 12 | |
64 | #define CB_CL_UADMIN_PRE_VFS 13 | |
65 | #define CB_CL_MDBOOT CB_CL_UADMIN | |
66 | #define CB_CL_ENTER_DEBUGGER 14 | |
67 | #define CB_CL_CPR_POST_KERNEL 15 | |
68 | #define CB_CL_CPU_DEEP_IDLE 16 | |
69 | #define NCBCLASS 17 /* CHANGE ME if classes are added/removed */ | |
70 | ||
71 | /* | |
72 | * CB_CL_CPR_DAEMON class specific definitions are given below: | |
73 | */ | |
74 | ||
75 | /* | |
76 | * code for CPR callb_execute_class | |
77 | */ | |
78 | #define CB_CODE_CPR_CHKPT 0 | |
79 | #define CB_CODE_CPR_RESUME 1 | |
80 | ||
81 | typedef void * callb_id_t; | |
82 | /* | |
83 | * Per kernel thread structure for CPR daemon callbacks. | |
84 | * Must be protected by either a existing lock in the daemon or | |
85 | * a new lock created for such a purpose. | |
86 | */ | |
87 | typedef struct callb_cpr { | |
88 | kmutex_t *cc_lockp; /* lock to protect this struct */ | |
89 | char cc_events; /* various events for CPR */ | |
90 | callb_id_t cc_id; /* callb id address */ | |
91 | kcondvar_t cc_callb_cv; /* cv for callback waiting */ | |
92 | kcondvar_t cc_stop_cv; /* cv to checkpoint block */ | |
93 | } callb_cpr_t; | |
94 | ||
95 | /* | |
96 | * cc_events definitions | |
97 | */ | |
98 | #define CALLB_CPR_START 1 /* a checkpoint request's started */ | |
99 | #define CALLB_CPR_SAFE 2 /* thread is safe for CPR */ | |
100 | #define CALLB_CPR_ALWAYS_SAFE 4 /* thread is ALWAYS safe for CPR */ | |
101 | ||
102 | /* | |
103 | * Used when checking that all kernel threads are stopped. | |
104 | */ | |
105 | #define CALLB_MAX_RETRY 3 /* when waiting for kthread to sleep */ | |
106 | #define CALLB_THREAD_DELAY 10 /* ticks allowed to reach sleep */ | |
107 | #define CPR_KTHREAD_TIMEOUT_SEC 90 /* secs before callback times out -- */ | |
108 | /* due to pwr mgmt of disks, make -- */ | |
109 | /* big enough for worst spinup time */ | |
110 | ||
111 | /* | |
112 | * | |
113 | * CALLB_CPR_INIT macro is used by kernel threads to add their entry to | |
114 | * the callback table and perform other initialization. It automatically | |
115 | * adds the thread as being in the callback class CB_CL_CPR_DAEMON. | |
116 | * | |
117 | * cp - ptr to the callb_cpr_t structure for this kernel thread | |
118 | * | |
dd4bc569 | 119 | * lockp - pointer to mutex protecting the callb_cpr_t struct |
9f0a21e6 MM |
120 | * |
121 | * func - pointer to the callback function for this kernel thread. | |
122 | * It has the prototype boolean_t <func>(void *arg, int code) | |
123 | * where: arg - ptr to the callb_cpr_t structure | |
124 | * code - not used for this type of callback | |
125 | * returns: B_TRUE if successful; B_FALSE if unsuccessful. | |
126 | * | |
127 | * name - a string giving the name of the kernel thread | |
128 | * | |
129 | * Note: lockp is the lock to protect the callb_cpr_t (cp) structure | |
130 | * later on. No lock held is needed for this initialization. | |
131 | */ | |
132 | #define CALLB_CPR_INIT(cp, lockp, func, name) { \ | |
133 | strlcpy(curthread->td_name, (name), \ | |
134 | sizeof (curthread->td_name)); \ | |
861166b0 | 135 | memset(cp, 0, sizeof (callb_cpr_t)); \ |
9f0a21e6 MM |
136 | (cp)->cc_lockp = lockp; \ |
137 | (cp)->cc_id = callb_add(func, (void *)(cp), \ | |
138 | CB_CL_CPR_DAEMON, name); \ | |
139 | cv_init(&(cp)->cc_callb_cv, NULL, CV_DEFAULT, NULL); \ | |
140 | cv_init(&(cp)->cc_stop_cv, NULL, CV_DEFAULT, NULL); \ | |
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 callb_id_t callb_add(boolean_t (*)(void *, int), void *, int, char *); | |
198 | extern callb_id_t callb_add_thread(boolean_t (*)(void *, int), | |
199 | void *, int, char *, kthread_id_t); | |
200 | extern int callb_delete(callb_id_t); | |
201 | extern void callb_execute(callb_id_t, int); | |
202 | extern void *callb_execute_class(int, int); | |
203 | extern boolean_t callb_generic_cpr(void *, int); | |
204 | extern boolean_t callb_generic_cpr_safe(void *, int); | |
205 | extern boolean_t callb_is_stopped(kthread_id_t, caddr_t *); | |
206 | extern void callb_lock_table(void); | |
207 | extern void callb_unlock_table(void); | |
208 | ||
209 | #ifdef __cplusplus | |
210 | } | |
211 | #endif | |
212 | ||
213 | #endif /* _SYS_CALLB_H */ |