/* * 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); }
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); }
/*------------------------------------------------------------------------* * 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); }