callb.c revision 185029
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 2007 Sun Microsystems, Inc.  All rights reserved.
23 * Use is subject to license terms.
24 */
25
26#pragma ident	"%Z%%M%	%I%	%E% SMI"
27
28#include <sys/param.h>
29#include <sys/types.h>
30#include <sys/time.h>
31#include <sys/sysmacros.h>
32#include <sys/systm.h>
33#include <sys/proc.h>
34#include <sys/mutex.h>
35#include <sys/condvar.h>
36#include <sys/callb.h>
37#include <sys/kmem.h>
38#include <sys/cmn_err.h>
39#include <sys/debug.h>
40#include <sys/kobj.h>
41#include <sys/systm.h>	/* for delay() */
42#include <sys/taskq.h>  /* For TASKQ_NAMELEN */
43#include <sys/kernel.h>
44
45#define	CB_MAXNAME	TASKQ_NAMELEN
46
47/*
48 * The callb mechanism provides generic event scheduling/echoing.
49 * A callb function is registered and called on behalf of the event.
50 */
51typedef struct callb {
52	struct callb	*c_next; 	/* next in class or on freelist */
53	kthread_id_t	c_thread;	/* ptr to caller's thread struct */
54	char		c_flag;		/* info about the callb state */
55	uchar_t		c_class;	/* this callb's class */
56	kcondvar_t	c_done_cv;	/* signal callb completion */
57	boolean_t	(*c_func)();	/* cb function: returns true if ok */
58	void		*c_arg;		/* arg to c_func */
59	char		c_name[CB_MAXNAME+1]; /* debug:max func name length */
60} callb_t;
61
62/*
63 * callb c_flag bitmap definitions
64 */
65#define	CALLB_FREE		0x0
66#define	CALLB_TAKEN		0x1
67#define	CALLB_EXECUTING		0x2
68
69/*
70 * Basic structure for a callb table.
71 * All callbs are organized into different class groups described
72 * by ct_class array.
73 * The callbs within a class are single-linked and normally run by a
74 * serial execution.
75 */
76typedef struct callb_table {
77	kmutex_t ct_lock;		/* protect all callb states */
78	callb_t	*ct_freelist; 		/* free callb structures */
79	int	ct_busy;		/* != 0 prevents additions */
80	kcondvar_t ct_busy_cv;		/* to wait for not busy    */
81	int	ct_ncallb; 		/* num of callbs allocated */
82	callb_t	*ct_first_cb[NCBCLASS];	/* ptr to 1st callb in a class */
83} callb_table_t;
84
85int callb_timeout_sec = CPR_KTHREAD_TIMEOUT_SEC;
86
87static callb_id_t callb_add_common(boolean_t (*)(void *, int),
88    void *, int, char *, kthread_id_t);
89
90static callb_table_t callb_table;	/* system level callback table */
91static callb_table_t *ct = &callb_table;
92static kmutex_t	callb_safe_mutex;
93callb_cpr_t	callb_cprinfo_safe = {
94	&callb_safe_mutex, CALLB_CPR_ALWAYS_SAFE, 0, 0, 0 };
95
96/*
97 * Init all callb tables in the system.
98 */
99void
100callb_init(void *dummy __unused)
101{
102	callb_table.ct_busy = 0;	/* mark table open for additions */
103	mutex_init(&callb_safe_mutex, NULL, MUTEX_DEFAULT, NULL);
104	mutex_init(&callb_table.ct_lock, NULL, MUTEX_DEFAULT, NULL);
105}
106
107void
108callb_fini(void *dummy __unused)
109{
110	callb_t *cp;
111	int i;
112
113	mutex_enter(&ct->ct_lock);
114	for (i = 0; i < 16; i++) {
115		while ((cp = ct->ct_freelist) != NULL) {
116			ct->ct_freelist = cp->c_next;
117			ct->ct_ncallb--;
118			kmem_free(cp, sizeof (callb_t));
119		}
120		if (ct->ct_ncallb == 0)
121			break;
122		/* Not all callbacks finished, waiting for the rest. */
123		mutex_exit(&ct->ct_lock);
124		tsleep(ct, 0, "callb", hz / 4);
125		mutex_enter(&ct->ct_lock);
126	}
127	if (ct->ct_ncallb > 0)
128		printf("%s: Leaked %d callbacks!\n", __func__, ct->ct_ncallb);
129	mutex_exit(&ct->ct_lock);
130	mutex_destroy(&callb_safe_mutex);
131	mutex_destroy(&callb_table.ct_lock);
132}
133
134/*
135 * callout_add() is called to register func() be called later.
136 */
137static callb_id_t
138callb_add_common(boolean_t (*func)(void *arg, int code),
139    void *arg, int class, char *name, kthread_id_t t)
140{
141	callb_t *cp;
142
143	ASSERT(class < NCBCLASS);
144
145	mutex_enter(&ct->ct_lock);
146	while (ct->ct_busy)
147		cv_wait(&ct->ct_busy_cv, &ct->ct_lock);
148	if ((cp = ct->ct_freelist) == NULL) {
149		ct->ct_ncallb++;
150		cp = (callb_t *)kmem_zalloc(sizeof (callb_t), KM_SLEEP);
151	}
152	ct->ct_freelist = cp->c_next;
153	cp->c_thread = t;
154	cp->c_func = func;
155	cp->c_arg = arg;
156	cp->c_class = (uchar_t)class;
157	cp->c_flag |= CALLB_TAKEN;
158#ifdef DEBUG
159	if (strlen(name) > CB_MAXNAME)
160		cmn_err(CE_WARN, "callb_add: name of callback function '%s' "
161		    "too long -- truncated to %d chars",
162		    name, CB_MAXNAME);
163#endif
164	(void) strncpy(cp->c_name, name, CB_MAXNAME);
165	cp->c_name[CB_MAXNAME] = '\0';
166
167	/*
168	 * Insert the new callb at the head of its class list.
169	 */
170	cp->c_next = ct->ct_first_cb[class];
171	ct->ct_first_cb[class] = cp;
172
173	mutex_exit(&ct->ct_lock);
174	return ((callb_id_t)cp);
175}
176
177/*
178 * The default function to add an entry to the callback table.  Since
179 * it uses curthread as the thread identifier to store in the table,
180 * it should be used for the normal case of a thread which is calling
181 * to add ITSELF to the table.
182 */
183callb_id_t
184callb_add(boolean_t (*func)(void *arg, int code),
185    void *arg, int class, char *name)
186{
187	return (callb_add_common(func, arg, class, name, curthread));
188}
189
190/*
191 * A special version of callb_add() above for use by threads which
192 * might be adding an entry to the table on behalf of some other
193 * thread (for example, one which is constructed but not yet running).
194 * In this version the thread id is an argument.
195 */
196callb_id_t
197callb_add_thread(boolean_t (*func)(void *arg, int code),
198    void *arg, int class, char *name, kthread_id_t t)
199{
200	return (callb_add_common(func, arg, class, name, t));
201}
202
203/*
204 * callout_delete() is called to remove an entry identified by id
205 * that was originally placed there by a call to callout_add().
206 * return -1 if fail to delete a callb entry otherwise return 0.
207 */
208int
209callb_delete(callb_id_t id)
210{
211	callb_t **pp;
212	callb_t *me = (callb_t *)id;
213
214	mutex_enter(&ct->ct_lock);
215
216	for (;;) {
217		pp = &ct->ct_first_cb[me->c_class];
218		while (*pp != NULL && *pp != me)
219			pp = &(*pp)->c_next;
220
221#ifdef DEBUG
222		if (*pp != me) {
223			cmn_err(CE_WARN, "callb delete bogus entry 0x%p",
224			    (void *)me);
225			mutex_exit(&ct->ct_lock);
226			return (-1);
227		}
228#endif /* DEBUG */
229
230		/*
231		 * It is not allowed to delete a callb in the middle of
232		 * executing otherwise, the callb_execute() will be confused.
233		 */
234		if (!(me->c_flag & CALLB_EXECUTING))
235			break;
236
237		cv_wait(&me->c_done_cv, &ct->ct_lock);
238	}
239	/* relink the class list */
240	*pp = me->c_next;
241
242	/* clean up myself and return the free callb to the head of freelist */
243	me->c_flag = CALLB_FREE;
244	me->c_next = ct->ct_freelist;
245	ct->ct_freelist = me;
246
247	mutex_exit(&ct->ct_lock);
248	return (0);
249}
250
251/*
252 * class:	indicates to execute all callbs in the same class;
253 * code:	optional argument for the callb functions.
254 * return:	 = 0: success
255 *		!= 0: ptr to string supplied when callback was registered
256 */
257void *
258callb_execute_class(int class, int code)
259{
260	callb_t *cp;
261	void *ret = NULL;
262
263	ASSERT(class < NCBCLASS);
264
265	mutex_enter(&ct->ct_lock);
266
267	for (cp = ct->ct_first_cb[class];
268	    cp != NULL && ret == 0; cp = cp->c_next) {
269		while (cp->c_flag & CALLB_EXECUTING)
270			cv_wait(&cp->c_done_cv, &ct->ct_lock);
271		/*
272		 * cont if the callb is deleted while we're sleeping
273		 */
274		if (cp->c_flag == CALLB_FREE)
275			continue;
276		cp->c_flag |= CALLB_EXECUTING;
277
278#ifdef CALLB_DEBUG
279		printf("callb_execute: name=%s func=%p arg=%p\n",
280		    cp->c_name, (void *)cp->c_func, (void *)cp->c_arg);
281#endif /* CALLB_DEBUG */
282
283		mutex_exit(&ct->ct_lock);
284		/* If callback function fails, pass back client's name */
285		if (!(*cp->c_func)(cp->c_arg, code))
286			ret = cp->c_name;
287		mutex_enter(&ct->ct_lock);
288
289		cp->c_flag &= ~CALLB_EXECUTING;
290		cv_broadcast(&cp->c_done_cv);
291	}
292	mutex_exit(&ct->ct_lock);
293	return (ret);
294}
295
296/*
297 * callers make sure no recursive entries to this func.
298 * dp->cc_lockp is registered by callb_add to protect callb_cpr_t structure.
299 *
300 * When calling to stop a kernel thread (code == CB_CODE_CPR_CHKPT) we
301 * use a cv_timedwait() in case the kernel thread is blocked.
302 *
303 * Note that this is a generic callback handler for daemon CPR and
304 * should NOT be changed to accommodate any specific requirement in a daemon.
305 * Individual daemons that require changes to the handler shall write
306 * callback routines in their own daemon modules.
307 */
308boolean_t
309callb_generic_cpr(void *arg, int code)
310{
311	callb_cpr_t *cp = (callb_cpr_t *)arg;
312	clock_t ret = 0;			/* assume success */
313
314	mutex_enter(cp->cc_lockp);
315
316	switch (code) {
317	case CB_CODE_CPR_CHKPT:
318		cp->cc_events |= CALLB_CPR_START;
319#ifdef CPR_NOT_THREAD_SAFE
320		while (!(cp->cc_events & CALLB_CPR_SAFE))
321			/* cv_timedwait() returns -1 if it times out. */
322			if ((ret = cv_timedwait(&cp->cc_callb_cv,
323			    cp->cc_lockp,
324			    callb_timeout_sec * hz)) == -1)
325				break;
326#endif
327		break;
328
329	case CB_CODE_CPR_RESUME:
330		cp->cc_events &= ~CALLB_CPR_START;
331		cv_signal(&cp->cc_stop_cv);
332		break;
333	}
334	mutex_exit(cp->cc_lockp);
335	return (ret != -1);
336}
337
338/*
339 * The generic callback function associated with kernel threads which
340 * are always considered safe.
341 */
342/* ARGSUSED */
343boolean_t
344callb_generic_cpr_safe(void *arg, int code)
345{
346	return (B_TRUE);
347}
348/*
349 * Prevent additions to callback table.
350 */
351void
352callb_lock_table(void)
353{
354	mutex_enter(&ct->ct_lock);
355	ASSERT(ct->ct_busy == 0);
356	ct->ct_busy = 1;
357	mutex_exit(&ct->ct_lock);
358}
359
360/*
361 * Allow additions to callback table.
362 */
363void
364callb_unlock_table(void)
365{
366	mutex_enter(&ct->ct_lock);
367	ASSERT(ct->ct_busy != 0);
368	ct->ct_busy = 0;
369	cv_broadcast(&ct->ct_busy_cv);
370	mutex_exit(&ct->ct_lock);
371}
372
373SYSINIT(sol_callb, SI_SUB_DRIVERS, SI_ORDER_FIRST, callb_init, NULL);
374SYSUNINIT(sol_callb, SI_SUB_DRIVERS, SI_ORDER_FIRST, callb_fini, NULL);
375