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