1 /* $NetBSD: callb.c,v 1.1 2009/03/26 22:11:45 ad Exp $ */
6 * The contents of this file are subject to the terms of the
7 * Common Development and Distribution License, Version 1.0 only
8 * (the "License"). You may not use this file except in compliance
11 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
12 * or http://www.opensolaris.org/os/licensing.
13 * See the License for the specific language governing permissions
14 * and limitations under the License.
16 * When distributing Covered Code, include this CDDL HEADER in each
17 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
18 * If applicable, add the following below this CDDL HEADER, with the
19 * fields enclosed by brackets "[]" replaced with your own identifying
20 * information: Portions Copyright [yyyy] [name of copyright owner]
25 * Copyright 2004 Sun Microsystems, Inc. All rights reserved.
26 * Use is subject to license terms.
29 #pragma ident "%Z%%M% %I% %E% SMI"
31 #include <sys/param.h>
32 #include <sys/types.h>
34 #include <sys/sysmacros.h>
35 #include <sys/systm.h>
37 #include <sys/mutex.h>
38 #include <sys/condvar.h>
39 #include <sys/callb.h>
41 #include <sys/cmn_err.h>
42 #include <sys/debug.h>
44 #include <sys/systm.h> /* for delay() */
45 #include <sys/taskq.h> /* For TASKQ_NAMELEN */
46 #include <sys/kernel.h>
48 #define CB_MAXNAME TASKQ_NAMELEN
51 * The callb mechanism provides generic event scheduling/echoing.
52 * A callb function is registered and called on behalf of the event.
54 typedef struct callb
{
55 struct callb
*c_next
; /* next in class or on freelist */
56 kthread_id_t c_thread
; /* ptr to caller's thread struct */
57 char c_flag
; /* info about the callb state */
58 uchar_t c_class
; /* this callb's class */
59 kcondvar_t c_done_cv
; /* signal callb completion */
60 boolean_t (*c_func
)(); /* cb function: returns true if ok */
61 void *c_arg
; /* arg to c_func */
62 char c_name
[CB_MAXNAME
+1]; /* debug:max func name length */
66 * callb c_flag bitmap definitions
68 #define CALLB_FREE 0x0
69 #define CALLB_TAKEN 0x1
70 #define CALLB_EXECUTING 0x2
73 * Basic structure for a callb table.
74 * All callbs are organized into different class groups described
76 * The callbs within a class are single-linked and normally run by a
79 typedef struct callb_table
{
80 kmutex_t ct_lock
; /* protect all callb states */
81 callb_t
*ct_freelist
; /* free callb structures */
82 int ct_busy
; /* != 0 prevents additions */
83 kcondvar_t ct_busy_cv
; /* to wait for not busy */
84 int ct_ncallb
; /* num of callbs allocated */
85 callb_t
*ct_first_cb
[NCBCLASS
]; /* ptr to 1st callb in a class */
88 int callb_timeout_sec
= CPR_KTHREAD_TIMEOUT_SEC
;
90 static callb_id_t
callb_add_common(boolean_t (*)(void *, int),
91 void *, int, char *, kthread_id_t
);
93 static callb_table_t callb_table
; /* system level callback table */
94 static callb_table_t
*ct
= &callb_table
;
95 static kmutex_t callb_safe_mutex
;
96 callb_cpr_t callb_cprinfo_safe
= {
97 &callb_safe_mutex
, CALLB_CPR_ALWAYS_SAFE
, 0, 0, 0 };
100 * Init all callb tables in the system.
103 callb_init(void *dummy __unused
)
105 callb_table
.ct_busy
= 0; /* mark table open for additions */
106 mutex_init(&callb_safe_mutex
, NULL
, MUTEX_DEFAULT
, NULL
);
107 mutex_init(&callb_table
.ct_lock
, NULL
, MUTEX_DEFAULT
, NULL
);
111 callb_fini(void *dummy __unused
)
115 mutex_enter(&ct
->ct_lock
);
116 while ((cp
= ct
->ct_freelist
) != NULL
) {
117 ct
->ct_freelist
= cp
->c_next
;
119 kmem_free(cp
, sizeof (callb_t
));
121 ASSERT(ct
->ct_ncallb
== 0);
122 mutex_exit(&ct
->ct_lock
);
123 mutex_destroy(&callb_safe_mutex
);
124 mutex_destroy(&callb_table
.ct_lock
);
128 * callout_add() is called to register func() be called later.
131 callb_add_common(boolean_t (*func
)(void *arg
, int code
),
132 void *arg
, int class, char *name
, kthread_id_t t
)
136 ASSERT(class < NCBCLASS
);
138 mutex_enter(&ct
->ct_lock
);
140 cv_wait(&ct
->ct_busy_cv
, &ct
->ct_lock
);
141 if ((cp
= ct
->ct_freelist
) == NULL
) {
143 cp
= (callb_t
*)kmem_zalloc(sizeof (callb_t
), KM_SLEEP
);
145 ct
->ct_freelist
= cp
->c_next
;
149 cp
->c_class
= (uchar_t
)class;
150 cp
->c_flag
|= CALLB_TAKEN
;
152 if (strlen(name
) > CB_MAXNAME
)
153 cmn_err(CE_WARN
, "callb_add: name of callback function '%s' "
154 "too long -- truncated to %d chars",
157 (void) strncpy(cp
->c_name
, name
, CB_MAXNAME
);
158 cp
->c_name
[CB_MAXNAME
] = '\0';
161 * Insert the new callb at the head of its class list.
163 cp
->c_next
= ct
->ct_first_cb
[class];
164 ct
->ct_first_cb
[class] = cp
;
166 mutex_exit(&ct
->ct_lock
);
167 return ((callb_id_t
)cp
);
171 * The default function to add an entry to the callback table. Since
172 * it uses curthread as the thread identifier to store in the table,
173 * it should be used for the normal case of a thread which is calling
174 * to add ITSELF to the table.
177 callb_add(boolean_t (*func
)(void *arg
, int code
),
178 void *arg
, int class, char *name
)
180 return (callb_add_common(func
, arg
, class, name
, curthread
));
184 * A special version of callb_add() above for use by threads which
185 * might be adding an entry to the table on behalf of some other
186 * thread (for example, one which is constructed but not yet running).
187 * In this version the thread id is an argument.
190 callb_add_thread(boolean_t (*func
)(void *arg
, int code
),
191 void *arg
, int class, char *name
, kthread_id_t t
)
193 return (callb_add_common(func
, arg
, class, name
, t
));
197 * callout_delete() is called to remove an entry identified by id
198 * that was originally placed there by a call to callout_add().
199 * return -1 if fail to delete a callb entry otherwise return 0.
202 callb_delete(callb_id_t id
)
205 callb_t
*me
= (callb_t
*)id
;
207 mutex_enter(&ct
->ct_lock
);
210 pp
= &ct
->ct_first_cb
[me
->c_class
];
211 while (*pp
!= NULL
&& *pp
!= me
)
216 cmn_err(CE_WARN
, "callb delete bogus entry 0x%p",
218 mutex_exit(&ct
->ct_lock
);
224 * It is not allowed to delete a callb in the middle of
225 * executing otherwise, the callb_execute() will be confused.
227 if (!(me
->c_flag
& CALLB_EXECUTING
))
230 cv_wait(&me
->c_done_cv
, &ct
->ct_lock
);
232 /* relink the class list */
235 /* clean up myself and return the free callb to the head of freelist */
236 me
->c_flag
= CALLB_FREE
;
237 me
->c_next
= ct
->ct_freelist
;
238 ct
->ct_freelist
= me
;
240 mutex_exit(&ct
->ct_lock
);
245 * class: indicates to execute all callbs in the same class;
246 * code: optional argument for the callb functions.
247 * return: = 0: success
248 * != 0: ptr to string supplied when callback was registered
251 callb_execute_class(int class, int code
)
256 ASSERT(class < NCBCLASS
);
258 mutex_enter(&ct
->ct_lock
);
260 for (cp
= ct
->ct_first_cb
[class];
261 cp
!= NULL
&& ret
== 0; cp
= cp
->c_next
) {
262 while (cp
->c_flag
& CALLB_EXECUTING
)
263 cv_wait(&cp
->c_done_cv
, &ct
->ct_lock
);
265 * cont if the callb is deleted while we're sleeping
267 if (cp
->c_flag
== CALLB_FREE
)
269 cp
->c_flag
|= CALLB_EXECUTING
;
272 printf("callb_execute: name=%s func=%p arg=%p\n",
273 cp
->c_name
, (void *)cp
->c_func
, (void *)cp
->c_arg
);
274 #endif /* CALLB_DEBUG */
276 mutex_exit(&ct
->ct_lock
);
277 /* If callback function fails, pass back client's name */
278 if (!(*cp
->c_func
)(cp
->c_arg
, code
))
280 mutex_enter(&ct
->ct_lock
);
282 cp
->c_flag
&= ~CALLB_EXECUTING
;
283 cv_broadcast(&cp
->c_done_cv
);
285 mutex_exit(&ct
->ct_lock
);
290 * callers make sure no recursive entries to this func.
291 * dp->cc_lockp is registered by callb_add to protect callb_cpr_t structure.
293 * When calling to stop a kernel thread (code == CB_CODE_CPR_CHKPT) we
294 * use a cv_timedwait() in case the kernel thread is blocked.
296 * Note that this is a generic callback handler for daemon CPR and
297 * should NOT be changed to accommodate any specific requirement in a daemon.
298 * Individual daemons that require changes to the handler shall write
299 * callback routines in their own daemon modules.
302 callb_generic_cpr(void *arg
, int code
)
304 callb_cpr_t
*cp
= (callb_cpr_t
*)arg
;
305 clock_t ret
= 0; /* assume success */
307 mutex_enter(cp
->cc_lockp
);
310 case CB_CODE_CPR_CHKPT
:
311 cp
->cc_events
|= CALLB_CPR_START
;
312 while (!(cp
->cc_events
& CALLB_CPR_SAFE
))
313 /* cv_timedwait() returns -1 if it times out. */
314 if ((ret
= cv_timedwait(&cp
->cc_callb_cv
,
316 callb_timeout_sec
* hz
)) == -1)
320 case CB_CODE_CPR_RESUME
:
321 cp
->cc_events
&= ~CALLB_CPR_START
;
322 cv_signal(&cp
->cc_stop_cv
);
325 mutex_exit(cp
->cc_lockp
);
330 * The generic callback function associated with kernel threads which
331 * are always considered safe.
335 callb_generic_cpr_safe(void *arg
, int code
)
340 * Prevent additions to callback table.
343 callb_lock_table(void)
345 mutex_enter(&ct
->ct_lock
);
346 ASSERT(ct
->ct_busy
== 0);
348 mutex_exit(&ct
->ct_lock
);
352 * Allow additions to callback table.
355 callb_unlock_table(void)
357 mutex_enter(&ct
->ct_lock
);
358 ASSERT(ct
->ct_busy
!= 0);
360 cv_broadcast(&ct
->ct_busy_cv
);
361 mutex_exit(&ct
->ct_lock
);