示例#1
0
/*
 * Start a kernel process.  This is called after a fork() call in
 * mi_startup() in the file kern/init_main.c.
 *
 * This function is used to start "internal" daemons and intended
 * to be called from SYSINIT().
 *
 * These threads are created MPSAFE.
 */
void
kproc_start(const void *udata)
{
	const struct kproc_desc	*kp = udata;
	int error;

	error = kthread_create((void (*)(void *))kp->func, NULL,
				kp->global_threadpp, kp->arg0);
	lwkt_setpri(*kp->global_threadpp, TDPRI_KERN_DAEMON);
	if (error)
		panic("kproc_start: %s: error %d", kp->arg0, error);
}
示例#2
0
void *
register_int(int intr, inthand2_t *handler, void *arg, const char *name,
		struct lwkt_serialize *serializer, int intr_flags, int cpuid)
{
    struct intr_info *info;
    struct intrec **list;
    intrec_t rec;
    int orig_cpuid;

    KKASSERT(cpuid >= 0 && cpuid < ncpus);

    if (intr < 0 || intr >= MAX_INTS)
	panic("register_int: bad intr %d", intr);
    if (name == NULL)
	name = "???";
    info = &intr_info_ary[cpuid][intr];

    /*
     * Construct an interrupt handler record
     */
    rec = kmalloc(sizeof(struct intrec), M_DEVBUF, M_INTWAIT);
    rec->name = kmalloc(strlen(name) + 1, M_DEVBUF, M_INTWAIT);
    strcpy(rec->name, name);

    rec->info = info;
    rec->handler = handler;
    rec->argument = arg;
    rec->intr = intr;
    rec->intr_flags = intr_flags;
    rec->next = NULL;
    rec->serializer = serializer;

    int_moveto_destcpu(&orig_cpuid, cpuid);

    /*
     * Create an emergency polling thread and set up a systimer to wake
     * it up.
     */
    if (emergency_intr_thread[cpuid].td_kstack == NULL) {
	lwkt_create(ithread_emergency, NULL, NULL,
		    &emergency_intr_thread[cpuid],
		    TDF_NOSTART | TDF_INTTHREAD, cpuid, "ithreadE %d",
		    cpuid);
	systimer_init_periodic_nq(&emergency_intr_timer[cpuid],
		    emergency_intr_timer_callback,
		    &emergency_intr_thread[cpuid],
		    (emergency_intr_enable ? emergency_intr_freq : 1));
    }

    /*
     * Create an interrupt thread if necessary, leave it in an unscheduled
     * state.
     */
    if (info->i_state == ISTATE_NOTHREAD) {
	info->i_state = ISTATE_NORMAL;
	lwkt_create(ithread_handler, (void *)(intptr_t)intr, NULL,
		    &info->i_thread, TDF_NOSTART | TDF_INTTHREAD, cpuid,
		    "ithread%d %d", intr, cpuid);
	if (intr >= FIRST_SOFTINT)
	    lwkt_setpri(&info->i_thread, TDPRI_SOFT_NORM);
	else
	    lwkt_setpri(&info->i_thread, TDPRI_INT_MED);
	info->i_thread.td_preemptable = lwkt_preempt;
    }

    list = &info->i_reclist;

    /*
     * Keep track of how many fast and slow interrupts we have.
     * Set i_mplock_required if any handler in the chain requires
     * the MP lock to operate.
     */
    if ((intr_flags & INTR_MPSAFE) == 0)
	info->i_mplock_required = 1;
    if (intr_flags & INTR_CLOCK)
	++info->i_fast;
    else
	++info->i_slow;

    /*
     * Enable random number generation keying off of this interrupt.
     */
    if ((intr_flags & INTR_NOENTROPY) == 0 && info->i_random.sc_enabled == 0) {
	info->i_random.sc_enabled = 1;
	info->i_random.sc_intr = intr;
    }

    /*
     * Add the record to the interrupt list.
     */
    crit_enter();
    while (*list != NULL)
	list = &(*list)->next;
    *list = rec;
    crit_exit();

    /*
     * Update max_installed_hard_intr to make the emergency intr poll
     * a bit more efficient.
     */
    if (intr < FIRST_SOFTINT) {
	if (max_installed_hard_intr[cpuid] <= intr)
	    max_installed_hard_intr[cpuid] = intr + 1;
    }

    if (intr >= FIRST_SOFTINT)
	swi_info_ary[intr - FIRST_SOFTINT] = info;

    /*
     * Setup the machine level interrupt vector
     */
    if (intr < FIRST_SOFTINT && info->i_slow + info->i_fast == 1)
	machintr_intr_setup(intr, intr_flags);

    int_moveto_origcpu(orig_cpuid, cpuid);

    return(rec);
}
示例#3
0
/*------------------------------------------------------------------------*
 *	usb_process
 *
 * This function is the USB process dispatcher.
 *------------------------------------------------------------------------*/
static void
usb_process(void *arg)
{
	struct usb_process *up = arg;
	struct usb_proc_msg *pm;
	struct thread *td;

#if 0 /* XXX Suspend here? */
	/* in case of attach error, check for suspended */
	USB_THREAD_SUSPEND_CHECK();
#endif

	/* adjust priority */
	td = curthread;
	lwkt_setpri(td, up->up_prio);
	lockmgr(up->up_lock, LK_EXCLUSIVE);

	up->up_curtd = td;

	while (1) {

		if (up->up_gone)
			break;

		/*
		 * NOTE to reimplementors: dequeueing a command from the
		 * "used" queue and executing it must be atomic, with regard
		 * to the "up_mtx" mutex. That means any attempt to queue a
		 * command by another thread must be blocked until either:
		 *
		 * 1) the command sleeps
		 *
		 * 2) the command returns
		 *
		 * Here is a practical example that shows how this helps
		 * solving a problem:
		 *
		 * Assume that you want to set the baud rate on a USB serial
		 * device. During the programming of the device you don't
		 * want to receive nor transmit any data, because it will be
		 * garbage most likely anyway. The programming of our USB
		 * device takes 20 milliseconds and it needs to call
		 * functions that sleep.
		 *
		 * Non-working solution: Before we queue the programming
		 * command, we stop transmission and reception of data. Then
		 * we queue a programming command. At the end of the
		 * programming command we enable transmission and reception
		 * of data.
		 *
		 * Problem: If a second programming command is queued while the
		 * first one is sleeping, we end up enabling transmission
		 * and reception of data too early.
		 *
		 * Working solution: Before we queue the programming command,
		 * we stop transmission and reception of data. Then we queue
		 * a programming command. Then we queue a second command
		 * that only enables transmission and reception of data.
		 *
		 * Why it works: If a second programming command is queued
		 * while the first one is sleeping, then the queueing of a
		 * second command to enable the data transfers, will cause
		 * the previous one, which is still on the queue, to be
		 * removed from the queue, and re-inserted after the last
		 * baud rate programming command, which then gives the
		 * desired result.
		 */
		pm = TAILQ_FIRST(&up->up_qhead);

		if (pm) {
			DPRINTF("Message pm=%p, cb=%p (enter)\n",
			    pm, pm->pm_callback);

			(pm->pm_callback) (pm);

			if (pm == TAILQ_FIRST(&up->up_qhead)) {
				/* nothing changed */
				TAILQ_REMOVE(&up->up_qhead, pm, pm_qentry);
				pm->pm_qentry.tqe_prev = NULL;
			}
			DPRINTF("Message pm=%p (leave)\n", pm);

			continue;
		}
		/* end if messages - check if anyone is waiting for sync */
		if (up->up_dsleep) {
			up->up_dsleep = 0;
			cv_broadcast(&up->up_drain);
		}
		up->up_msleep = 1;
		cv_wait(&up->up_cv, up->up_lock);
	}

	up->up_ptr = NULL;
	cv_signal(&up->up_cv);
	lockmgr(up->up_lock, LK_RELEASE);

	/* Clear the proc pointer if this is the last thread. */
	if (--usb_pcount == 0)
		usbproc = NULL;

	USB_THREAD_EXIT(0);
}