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.
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or https://opensource.org/licenses/CDDL-1.0.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
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]
22 * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
23 * Use is subject to license terms.
26 #include <sys/types.h>
27 #include <sys/param.h>
29 #include <sys/sysmacros.h>
30 #include <sys/systm.h>
32 #include <sys/mutex.h>
33 #include <sys/condvar.h>
34 #include <sys/callb.h>
36 #include <sys/cmn_err.h>
37 #include <sys/debug.h>
39 #include <sys/systm.h> /* for delay() */
40 #include <sys/taskq.h> /* For TASKQ_NAMELEN */
41 #include <sys/kernel.h>
43 #define CB_MAXNAME TASKQ_NAMELEN
46 * The callb mechanism provides generic event scheduling/echoing.
47 * A callb function is registered and called on behalf of the event.
49 typedef struct callb
{
50 struct callb
*c_next
; /* next in class or on freelist */
51 kthread_id_t c_thread
; /* ptr to caller's thread struct */
52 char c_flag
; /* info about the callb state */
53 uchar_t c_class
; /* this callb's class */
54 kcondvar_t c_done_cv
; /* signal callb completion */
55 boolean_t (*c_func
)(void *, int);
56 /* cb function: returns true if ok */
57 void *c_arg
; /* arg to c_func */
58 char c_name
[CB_MAXNAME
+1]; /* debug:max func name length */
62 * callb c_flag bitmap definitions
64 #define CALLB_FREE 0x0
65 #define CALLB_TAKEN 0x1
66 #define CALLB_EXECUTING 0x2
69 * Basic structure for a callb table.
70 * All callbs are organized into different class groups described
72 * The callbs within a class are single-linked and normally run by a
75 typedef struct callb_table
{
76 kmutex_t ct_lock
; /* protect all callb states */
77 callb_t
*ct_freelist
; /* free callb structures */
78 boolean_t ct_busy
; /* B_TRUE prevents additions */
79 kcondvar_t ct_busy_cv
; /* to wait for not busy */
80 int ct_ncallb
; /* num of callbs allocated */
81 callb_t
*ct_first_cb
[NCBCLASS
]; /* ptr to 1st callb in a class */
84 int callb_timeout_sec
= CPR_KTHREAD_TIMEOUT_SEC
;
86 static callb_id_t
callb_add_common(boolean_t (*)(void *, int),
87 void *, int, char *, kthread_id_t
);
89 static callb_table_t callb_table
; /* system level callback table */
90 static callb_table_t
*ct
= &callb_table
;
91 static kmutex_t callb_safe_mutex
;
92 callb_cpr_t callb_cprinfo_safe
= {
93 &callb_safe_mutex
, CALLB_CPR_ALWAYS_SAFE
, 0, {0, 0} };
96 * Init all callb tables in the system.
99 callb_init(void *dummy __unused
)
101 callb_table
.ct_busy
= B_FALSE
; /* mark table open for additions */
102 mutex_init(&callb_safe_mutex
, NULL
, MUTEX_DEFAULT
, NULL
);
103 mutex_init(&callb_table
.ct_lock
, NULL
, MUTEX_DEFAULT
, NULL
);
107 callb_fini(void *dummy __unused
)
112 mutex_enter(&ct
->ct_lock
);
113 for (i
= 0; i
< 16; i
++) {
114 while ((cp
= ct
->ct_freelist
) != NULL
) {
115 ct
->ct_freelist
= cp
->c_next
;
117 kmem_free(cp
, sizeof (callb_t
));
119 if (ct
->ct_ncallb
== 0)
121 /* Not all callbacks finished, waiting for the rest. */
122 mutex_exit(&ct
->ct_lock
);
123 tsleep(ct
, 0, "callb", hz
/ 4);
124 mutex_enter(&ct
->ct_lock
);
126 if (ct
->ct_ncallb
> 0)
127 printf("%s: Leaked %d callbacks!\n", __func__
, ct
->ct_ncallb
);
128 mutex_exit(&ct
->ct_lock
);
129 mutex_destroy(&callb_safe_mutex
);
130 mutex_destroy(&callb_table
.ct_lock
);
134 * callout_add() is called to register func() be called later.
137 callb_add_common(boolean_t (*func
)(void *arg
, int code
),
138 void *arg
, int class, char *name
, kthread_id_t t
)
142 ASSERT3S(class, <, NCBCLASS
);
144 mutex_enter(&ct
->ct_lock
);
146 cv_wait(&ct
->ct_busy_cv
, &ct
->ct_lock
);
147 if ((cp
= ct
->ct_freelist
) == NULL
) {
149 cp
= kmem_zalloc(sizeof (callb_t
), KM_SLEEP
);
151 ct
->ct_freelist
= cp
->c_next
;
155 cp
->c_class
= (uchar_t
)class;
156 cp
->c_flag
|= CALLB_TAKEN
;
158 if (strlen(name
) > CB_MAXNAME
)
159 cmn_err(CE_WARN
, "callb_add: name of callback function '%s' "
160 "too long -- truncated to %d chars",
163 (void) strlcpy(cp
->c_name
, name
, sizeof (cp
->c_name
));
166 * Insert the new callb at the head of its class list.
168 cp
->c_next
= ct
->ct_first_cb
[class];
169 ct
->ct_first_cb
[class] = cp
;
171 mutex_exit(&ct
->ct_lock
);
172 return ((callb_id_t
)cp
);
176 * The default function to add an entry to the callback table. Since
177 * it uses curthread as the thread identifier to store in the table,
178 * it should be used for the normal case of a thread which is calling
179 * to add ITSELF to the table.
182 callb_add(boolean_t (*func
)(void *arg
, int code
),
183 void *arg
, int class, char *name
)
185 return (callb_add_common(func
, arg
, class, name
, curthread
));
189 * A special version of callb_add() above for use by threads which
190 * might be adding an entry to the table on behalf of some other
191 * thread (for example, one which is constructed but not yet running).
192 * In this version the thread id is an argument.
195 callb_add_thread(boolean_t (*func
)(void *arg
, int code
),
196 void *arg
, int class, char *name
, kthread_id_t t
)
198 return (callb_add_common(func
, arg
, class, name
, t
));
202 * callout_delete() is called to remove an entry identified by id
203 * that was originally placed there by a call to callout_add().
204 * return -1 if fail to delete a callb entry otherwise return 0.
207 callb_delete(callb_id_t id
)
210 callb_t
*me
= (callb_t
*)id
;
212 mutex_enter(&ct
->ct_lock
);
215 pp
= &ct
->ct_first_cb
[me
->c_class
];
216 while (*pp
!= NULL
&& *pp
!= me
)
221 cmn_err(CE_WARN
, "callb delete bogus entry 0x%p",
223 mutex_exit(&ct
->ct_lock
);
229 * It is not allowed to delete a callb in the middle of
230 * executing otherwise, the callb_execute() will be confused.
232 if (!(me
->c_flag
& CALLB_EXECUTING
))
235 cv_wait(&me
->c_done_cv
, &ct
->ct_lock
);
237 /* relink the class list */
240 /* clean up myself and return the free callb to the head of freelist */
241 me
->c_flag
= CALLB_FREE
;
242 me
->c_next
= ct
->ct_freelist
;
243 ct
->ct_freelist
= me
;
245 mutex_exit(&ct
->ct_lock
);
250 * class: indicates to execute all callbs in the same class;
251 * code: optional argument for the callb functions.
252 * return: = 0: success
253 * != 0: ptr to string supplied when callback was registered
256 callb_execute_class(int class, int code
)
261 ASSERT3S(class, <, NCBCLASS
);
263 mutex_enter(&ct
->ct_lock
);
265 for (cp
= ct
->ct_first_cb
[class];
266 cp
!= NULL
&& ret
== NULL
; cp
= cp
->c_next
) {
267 while (cp
->c_flag
& CALLB_EXECUTING
)
268 cv_wait(&cp
->c_done_cv
, &ct
->ct_lock
);
270 * cont if the callb is deleted while we're sleeping
272 if (cp
->c_flag
== CALLB_FREE
)
274 cp
->c_flag
|= CALLB_EXECUTING
;
277 printf("callb_execute: name=%s func=%p arg=%p\n",
278 cp
->c_name
, (void *)cp
->c_func
, (void *)cp
->c_arg
);
279 #endif /* CALLB_DEBUG */
281 mutex_exit(&ct
->ct_lock
);
282 /* If callback function fails, pass back client's name */
283 if (!(*cp
->c_func
)(cp
->c_arg
, code
))
285 mutex_enter(&ct
->ct_lock
);
287 cp
->c_flag
&= ~CALLB_EXECUTING
;
288 cv_broadcast(&cp
->c_done_cv
);
290 mutex_exit(&ct
->ct_lock
);
295 * callers make sure no recursive entries to this func.
296 * dp->cc_lockp is registered by callb_add to protect callb_cpr_t structure.
298 * When calling to stop a kernel thread (code == CB_CODE_CPR_CHKPT) we
299 * use a cv_timedwait() in case the kernel thread is blocked.
301 * Note that this is a generic callback handler for daemon CPR and
302 * should NOT be changed to accommodate any specific requirement in a daemon.
303 * Individual daemons that require changes to the handler shall write
304 * callback routines in their own daemon modules.
307 callb_generic_cpr(void *arg
, int code
)
309 callb_cpr_t
*cp
= (callb_cpr_t
*)arg
;
310 clock_t ret
= 0; /* assume success */
312 mutex_enter(cp
->cc_lockp
);
315 case CB_CODE_CPR_CHKPT
:
316 cp
->cc_events
|= CALLB_CPR_START
;
317 #ifdef CPR_NOT_THREAD_SAFE
318 while (!(cp
->cc_events
& CALLB_CPR_SAFE
))
319 /* cv_timedwait() returns -1 if it times out. */
320 if ((ret
= cv_reltimedwait(&cp
->cc_callb_cv
,
321 cp
->cc_lockp
, (callb_timeout_sec
* hz
),
322 TR_CLOCK_TICK
)) == -1)
327 case CB_CODE_CPR_RESUME
:
328 cp
->cc_events
&= ~CALLB_CPR_START
;
329 cv_signal(&cp
->cc_stop_cv
);
332 mutex_exit(cp
->cc_lockp
);
337 * The generic callback function associated with kernel threads which
338 * are always considered safe.
341 callb_generic_cpr_safe(void *arg
, int code
)
343 (void) arg
, (void) code
;
347 * Prevent additions to callback table.
350 callb_lock_table(void)
352 mutex_enter(&ct
->ct_lock
);
353 ASSERT(!ct
->ct_busy
);
354 ct
->ct_busy
= B_TRUE
;
355 mutex_exit(&ct
->ct_lock
);
359 * Allow additions to callback table.
362 callb_unlock_table(void)
364 mutex_enter(&ct
->ct_lock
);
366 ct
->ct_busy
= B_FALSE
;
367 cv_broadcast(&ct
->ct_busy_cv
);
368 mutex_exit(&ct
->ct_lock
);
371 SYSINIT(sol_callb
, SI_SUB_DRIVERS
, SI_ORDER_FIRST
, callb_init
, NULL
);
372 SYSUNINIT(sol_callb
, SI_SUB_DRIVERS
, SI_ORDER_FIRST
, callb_fini
, NULL
);