static int dsi_event_thread(void *data) { struct mdss_dsi_event *ev; struct dsi_event_q *evq; struct mdss_dsi_ctrl_pdata *ctrl; unsigned long flag; struct sched_param param; u32 todo = 0; int ret; param.sched_priority = 16; ret = sched_setscheduler_nocheck(current, SCHED_FIFO, ¶m); if (ret) pr_err("%s: set priority failed\n", __func__); ev = (struct mdss_dsi_event *)data; /* event */ init_waitqueue_head(&ev->event_q); spin_lock_init(&ev->event_lock); while (1) { wait_event(ev->event_q, (ev->event_pndx != ev->event_gndx)); spin_lock_irqsave(&ev->event_lock, flag); evq = &ev->todo_list[ev->event_gndx++]; todo = evq->todo; ctrl = evq->ctrl; evq->todo = 0; ev->event_gndx %= DSI_EVENT_Q_MAX; spin_unlock_irqrestore(&ev->event_lock, flag); pr_debug("%s: ev=%x\n", __func__, todo); #if defined (CONFIG_FB_MSM_MDSS_DSI_DBG) xlog(__func__, todo, 0, 0, 0, 0, 0); #endif if (todo & DSI_EV_PLL_UNLOCKED) mdss_dsi_pll_relock(ctrl); if (todo & DSI_EV_MDP_FIFO_UNDERFLOW) { if (ctrl->recovery) { mdss_dsi_sw_reset_restore(ctrl); ctrl->recovery->fxn(ctrl->recovery->data); } } if (todo & DSI_EV_MDP_BUSY_RELEASE) { spin_lock(&ctrl->mdp_lock); ctrl->mdp_busy = false; mdss_dsi_disable_irq_nosync(ctrl, DSI_MDP_TERM); complete(&ctrl->mdp_comp); spin_unlock(&ctrl->mdp_lock); /* enable dsi error interrupt */ mdss_dsi_err_intr_ctrl(ctrl, DSI_INTR_ERROR_MASK, 1); } } return 0; }
/* * Spawn the kthread that invokes RCU callbacks. */ static int __init rcu_spawn_kthreads(void) { struct sched_param sp; rcu_kthread_task = kthread_run(rcu_kthread, NULL, "rcu_kthread"); sp.sched_priority = RCU_BOOST_PRIO; sched_setscheduler_nocheck(rcu_kthread_task, SCHED_FIFO, &sp); return 0; }
static int tegra_cpufreq_init_once(void) { struct sched_param sp; int rc = 0; mutex_lock(&init_mutex); if (rm_cpufreq) goto clean; if (NvRmOpenNew(&rm_cpufreq)!=NvSuccess) { pr_err("%s: unable to open NvRm\n", __func__); rc = -ENOSYS; goto clean; } clk_cpu = clk_get_sys(NULL, "cpu"); if (IS_ERR(clk_cpu)) { rc = PTR_ERR(clk_cpu); clk_cpu = NULL; goto clean; } rc = register_reboot_notifier(&dfs_reboot_nb); if (rc) { pr_err("%s: unable to regsiter DVFS reboot notifier\n", __func__); goto clean; } cpufreq_dfsd = kthread_create(tegra_cpufreq_dfsd, NULL, "cpufreq-dvfsd"); if (IS_ERR(cpufreq_dfsd)) { pr_err("%s: unable to start DVFS daemon\n", __func__); rc = PTR_ERR(cpufreq_dfsd); cpufreq_dfsd = NULL; goto clean; } sp.sched_priority = KTHREAD_IRQ_PRIO + 1; if (sched_setscheduler_nocheck(cpufreq_dfsd, SCHED_FIFO, &sp) < 0) pr_err("%s: unable to elevate DVFS daemon priority\n",__func__); clean: if (rc) { if (rm_cpufreq) NvRmClose(rm_cpufreq); if (clk_cpu) clk_put(clk_cpu); clk_cpu = NULL; rm_cpufreq = NULL; unregister_reboot_notifier(&dfs_reboot_nb); } mutex_unlock(&init_mutex); return rc; }
/** * kthread_create_on_node - create a kthread. * @threadfn: the function to run until signal_pending(current). * @data: data ptr for @threadfn. * @node: memory node number. * @namefmt: printf-style name for the thread. * * Description: This helper function creates and names a kernel * thread. The thread will be stopped: use wake_up_process() to start * it. See also kthread_run(). * * If thread is going to be bound on a particular cpu, give its node * in @node, to get NUMA affinity for kthread stack, or else give -1. * When woken, the thread will run @threadfn() with @data as its * argument. @threadfn() can either call do_exit() directly if it is a * standalone thread for which no one will call kthread_stop(), or * return when 'kthread_should_stop()' is true (which means * kthread_stop() has been called). The return value should be zero * or a negative error number; it will be passed to kthread_stop(). * * Returns a task_struct or ERR_PTR(-ENOMEM). */ struct task_struct *kthread_create_on_node(int (*threadfn)(void *data), void *data, int node, const char namefmt[], ...) { struct kthread_create_info create; create.threadfn = threadfn; create.data = data; create.node = node; init_completion(&create.done); spin_lock(&kthread_create_lock); list_add_tail(&create.list, &kthread_create_list); spin_unlock(&kthread_create_lock); wake_up_process(kthreadd_task); wait_for_completion(&create.done); if (!IS_ERR(create.result)) { static const struct sched_param param = { .sched_priority = 0 }; va_list args; va_start(args, namefmt); vsnprintf(create.result->comm, sizeof(create.result->comm), namefmt, args); va_end(args); /* * root may have changed our (kthreadd's) priority or CPU mask. * The kernel thread should not inherit these properties. */ sched_setscheduler_nocheck(create.result, SCHED_NORMAL, ¶m); set_cpus_allowed_ptr(create.result, cpu_all_mask); } return create.result; } EXPORT_SYMBOL(kthread_create_on_node); static void __kthread_bind(struct task_struct *p, unsigned int cpu) { /* It's safe because the task is inactive. */ do_set_cpus_allowed(p, cpumask_of(cpu)); p->flags |= PF_THREAD_BOUND; }
/* * hps task control interface */ int hps_task_start(void) { struct sched_param param = {.sched_priority = HPS_TASK_PRIORITY }; if (hps_ctxt.tsk_struct_ptr == NULL) { hps_ctxt.tsk_struct_ptr = kthread_create(_hps_task_main, NULL, "hps_main"); if (IS_ERR(hps_ctxt.tsk_struct_ptr)) return PTR_ERR(hps_ctxt.tsk_struct_ptr); sched_setscheduler_nocheck(hps_ctxt.tsk_struct_ptr, SCHED_FIFO, ¶m); get_task_struct(hps_ctxt.tsk_struct_ptr); wake_up_process(hps_ctxt.tsk_struct_ptr); hps_warn("hps_task_start success, ptr: %p, pid: %d\n", hps_ctxt.tsk_struct_ptr, hps_ctxt.tsk_struct_ptr->pid); } else { hps_warn("hps task already exist, ptr: %p, pid: %d\n", hps_ctxt.tsk_struct_ptr, hps_ctxt.tsk_struct_ptr->pid); } return 0; }
static int load_stats_start(void) { int err; struct sched_param param = { .sched_priority = 1 }; err = load_stats_sysfs(); if (err) return err; load_stats_wq = alloc_workqueue("cpuquiet-load_stats", WQ_HIGHPRI, 0); if (!load_stats_wq) return -ENOMEM; INIT_DELAYED_WORK(&load_stats_work, load_stats_work_func); input_boost_task = kthread_create ( load_stats_boost_task, NULL, "cpuquiet_input_boost_task" ); if (IS_ERR(input_boost_task)) pr_err("%s: failed to create input boost task\n", __func__); else { sched_setscheduler_nocheck(input_boost_task, SCHED_RR, ¶m); get_task_struct(input_boost_task); input_boost_task_alive = true; hotplug_info("%s: input boost task created\n", __func__); } first_call = true; total_time = 0; last_time = 0; load_stats_state = IDLE; load_stats_work_func(NULL); return 0; } struct cpuquiet_governor load_stats_governor = { .name = "load_stats", .start = load_stats_start, .device_free_notification = load_stats_device_free, .device_busy_notification = load_stats_device_busy, .stop = load_stats_stop, .touch_event_notification = load_stats_touch_event, .owner = THIS_MODULE, }; static int __init init_load_stats(void) { return cpuquiet_register_governor(&load_stats_governor); } static void __exit exit_load_stats(void) { cpuquiet_unregister_governor(&load_stats_governor); } MODULE_LICENSE("GPL"); module_init(init_load_stats); module_exit(exit_load_stats);
/* # echo @ut_type @ut_prio @ut_tid > utest */ static ssize_t pts_utest_write(struct file *flip, const char *ubuf, size_t cnt, loff_t *data) { char buf[32]; size_t copy_size = cnt; unsigned long val; int ut_type, ut_tid, ut_prio; int ret, i = 0, j; struct task_struct *p; if (cnt >= sizeof(buf)) copy_size = 32 - 1; buf[copy_size] = '\0'; if (copy_from_user(&buf, ubuf, copy_size)) return -EFAULT; do { } while (buf[i++] != ' '); buf[(i - 1)] = '\0'; ret = strict_strtoul(buf, 10, &val); ut_type = (int)val; j = i; do { } while (buf[i++] != ' '); buf[(i - 1)] = '\0'; ret = strict_strtoul((const char *)(&buf[j]), 10, &val); ut_prio = (int)val; ret = strict_strtoul((const char *)(&buf[i]), 10, &val); ut_tid = (int)val; printk("%s: unit test %s tid %d prio %d j %d i %d", __func__, (ut_type == PTS_USER) ? "user" : ((ut_type == PTS_KRNL) ? "kernel" : ((ut_type == PTS_BNDR) ? "binder" : "unknown")), ut_tid, ut_prio, j, i); /* start to test api */ p = find_task_by_vpid(ut_tid); if (!p) goto utest_out; if ((ut_prio >= 0) && (ut_prio < MAX_RT_PRIO)) { struct sched_param param; /* sched_priority is rt priority rather than effective one */ ut_prio = MAX_RT_PRIO-1 - ut_prio; param.sched_priority = ut_prio | MT_ALLOW_RT_PRIO_BIT; switch (ut_type) { case PTS_USER: sched_setscheduler_syscall(p, SCHED_RR, ¶m); break; case PTS_KRNL: sched_setscheduler_nocheck(p, SCHED_RR, ¶m); break; case PTS_BNDR: sched_setscheduler_nocheck_binder(p, SCHED_RR, ¶m); break; default: break; } } else { /* assume normal */ switch (ut_type) { case PTS_USER: set_user_nice_syscall(p, PRIO_TO_NICE(ut_prio)); break; case PTS_KRNL: set_user_nice(p, PRIO_TO_NICE(ut_prio)); break; case PTS_BNDR: set_user_nice_binder(p, PRIO_TO_NICE(ut_prio)); break; default: break; } } utest_out: return cnt; }
/** * kthread_create - create a kthread. * @threadfn: the function to run until signal_pending(current). * @data: data ptr for @threadfn. * @namefmt: printf-style name for the thread. * * Description: This helper function creates and names a kernel * thread. The thread will be stopped: use wake_up_process() to start * it. See also kthread_run(), kthread_create_on_cpu(). * * When woken, the thread will run @threadfn() with @data as its * argument. @threadfn() can either call do_exit() directly if it is a * standalone thread for which noone will call kthread_stop(), or * return when 'kthread_should_stop()' is true (which means * kthread_stop() has been called). The return value should be zero * or a negative error number; it will be passed to kthread_stop(). * * Returns a task_struct or ERR_PTR(-ENOMEM). */ struct task_struct *kthread_create(int (*threadfn)(void *data), void *data, const char namefmt[], ...) { struct kthread_create_info create; create.threadfn = threadfn; create.data = data; init_completion(&create.started); init_completion(&create.done); spin_lock(&kthread_create_lock); list_add_tail(&create.list, &kthread_create_list); spin_unlock(&kthread_create_lock); wake_up_process(kthreadd_task); wait_for_completion(&create.done); if (!IS_ERR(create.result)) { struct sched_param param = { .sched_priority = 0 }; va_list args; va_start(args, namefmt); vsnprintf(create.result->comm, sizeof(create.result->comm), namefmt, args); va_end(args); /* * root may have changed our (kthreadd's) priority or CPU mask. * The kernel thread should not inherit these properties. */ sched_setscheduler_nocheck(create.result, SCHED_NORMAL, ¶m); set_user_nice(create.result, KTHREAD_NICE_LEVEL); set_cpus_allowed_ptr(create.result, cpu_all_mask); } return create.result; } EXPORT_SYMBOL(kthread_create); /** * kthread_bind - bind a just-created kthread to a cpu. * @k: thread created by kthread_create(). * @cpu: cpu (might not be online, must be possible) for @k to run on. * * Description: This function is equivalent to set_cpus_allowed(), * except that @cpu doesn't need to be online, and the thread must be * stopped (i.e., just returned from kthread_create()). */ void kthread_bind(struct task_struct *k, unsigned int cpu) { /* Must have done schedule() in kthread() before we set_task_cpu */ if (!wait_task_inactive(k, TASK_UNINTERRUPTIBLE)) { WARN_ON(1); return; } set_task_cpu(k, cpu); k->cpus_allowed = cpumask_of_cpu(cpu); k->rt.nr_cpus_allowed = 1; k->flags |= PF_THREAD_BOUND; } EXPORT_SYMBOL(kthread_bind); /** * kthread_stop - stop a thread created by kthread_create(). * @k: thread created by kthread_create(). * * Sets kthread_should_stop() for @k to return true, wakes it, and * waits for it to exit. Your threadfn() must not call do_exit() * itself if you use this function! This can also be called after * kthread_create() instead of calling wake_up_process(): the thread * will exit without calling threadfn(). * * Returns the result of threadfn(), or %-EINTR if wake_up_process() * was never called. */ int kthread_stop(struct task_struct *k) { int ret; mutex_lock(&kthread_stop_lock); /* It could exit after stop_info.k set, but before wake_up_process. */ get_task_struct(k); trace_sched_kthread_stop(k); /* Must init completion *before* thread sees kthread_stop_info.k */ init_completion(&kthread_stop_info.done); smp_wmb(); /* Now set kthread_should_stop() to true, and wake it up. */ kthread_stop_info.k = k; wake_up_process(k); put_task_struct(k); /* Once it dies, reset stop ptr, gather result and we're done. */ wait_for_completion(&kthread_stop_info.done); kthread_stop_info.k = NULL; ret = kthread_stop_info.err; mutex_unlock(&kthread_stop_lock); trace_sched_kthread_stop_ret(ret); return ret; }
// Jagan- static ssize_t pcm_write(struct file *file, const char __user *buf, size_t count, loff_t *pos) { struct pcm *pcm = file->private_data; struct audio_client *ac; struct audio_buffer *ab; const char __user *start = buf; int xfer; #if 0 // Jagan+ if(!task_has_rt_policy(current)) { struct sched_param param = { .sched_priority = 99 }; printk(KERN_INFO "pcm_write to change to RT tid = %d\n", current->pid); if(sched_setscheduler_nocheck(current, SCHED_FIFO, ¶m )!=0) { printk(KERN_ERR "pcm_write fail to change to RT\n"); } } // Jagan- #endif if (!pcm->ac) pcm_ioctl(file, AUDIO_START, 0); ac = pcm->ac; if (!ac) return -ENODEV; while (count > 0) { ab = ac->buf + ac->cpu_buf; if (ab->used) if (!wait_event_timeout(ac->wait, (ab->used == 0), 5*HZ)) { audio_client_dump(ac); pr_err("[%s:%s] timeout. dsp dead?\n", __MM_FILE__, __func__); q6audio_dsp_not_responding(); } xfer = count; if (xfer > ab->size) xfer = ab->size; if (copy_from_user(ab->data, buf, xfer)) return -EFAULT; buf += xfer; count -= xfer; ab->used = 1; ab->actual_size = xfer; q6audio_write(ac, ab); ac->cpu_buf ^= 1; } return buf - start; } static int pcm_release(struct inode *inode, struct file *file) { struct pcm *pcm = file->private_data; if (pcm->ac) q6audio_close(pcm->ac); kfree(pcm); pr_info("[%s:%s] release\n", __MM_FILE__, __func__); // Jagan+ if (unlikely(1 == Is_first_boot_flag)) Is_first_boot_flag = 0; // Jagan- return 0; } static struct file_operations pcm_fops = { .owner = THIS_MODULE, .open = pcm_open, .write = pcm_write, .release = pcm_release, .unlocked_ioctl = pcm_ioctl, }; struct miscdevice pcm_misc = { .minor = MISC_DYNAMIC_MINOR, .name = "msm_pcm_out", .fops = &pcm_fops, }; static int __init pcm_init(void) { return misc_register(&pcm_misc); } device_initcall(pcm_init);
/* * this changes the io permissions bitmap in the current task. */ asmlinkage long sys_ioperm(unsigned long from, unsigned long num, int turn_on) { struct thread_struct *t = ¤t->thread; struct tss_struct *tss; unsigned int i, max_long, bytes, bytes_updated; if ((from + num <= from) || (from + num > IO_BITMAP_BITS)) return -EINVAL; #if defined(CONFIG_SCHED_BFS_AUTOISO) if (turn_on) { struct sched_param param = { .sched_priority = 0 }; if (!capable(CAP_SYS_RAWIO)) return -EPERM; /* Start X as SCHED_ISO */ sched_setscheduler_nocheck(current, SCHED_ISO, ¶m); } #else if (turn_on && !capable(CAP_SYS_RAWIO)) return -EPERM; #endif /* * If it's the first ioperm() call in this thread's lifetime, set the * IO bitmap up. ioperm() is much less timing critical than clone(), * this is why we delay this operation until now: */ if (!t->io_bitmap_ptr) { unsigned long *bitmap = kmalloc(IO_BITMAP_BYTES, GFP_KERNEL); if (!bitmap) return -ENOMEM; memset(bitmap, 0xff, IO_BITMAP_BYTES); t->io_bitmap_ptr = bitmap; set_thread_flag(TIF_IO_BITMAP); } /* * do it in the per-thread copy and in the TSS ... * * Disable preemption via get_cpu() - we must not switch away * because the ->io_bitmap_max value must match the bitmap * contents: */ tss = &per_cpu(init_tss, get_cpu()); if (turn_on) bitmap_clear(t->io_bitmap_ptr, from, num); else bitmap_set(t->io_bitmap_ptr, from, num); /* * Search for a (possibly new) maximum. This is simple and stupid, * to keep it obviously correct: */ max_long = 0; for (i = 0; i < IO_BITMAP_LONGS; i++) if (t->io_bitmap_ptr[i] != ~0UL) max_long = i; bytes = (max_long + 1) * sizeof(unsigned long); bytes_updated = max(bytes, t->io_bitmap_max); t->io_bitmap_max = bytes; /* Update the TSS: */ memcpy(tss->io_bitmap, t->io_bitmap_ptr, bytes_updated); put_cpu(); return 0; } /* * sys_iopl has to be used when you want to access the IO ports * beyond the 0x3ff range: to get the full 65536 ports bitmapped * you'd need 8kB of bitmaps/process, which is a bit excessive. * * Here we just change the flags value on the stack: we allow * only the super-user to do it. This depends on the stack-layout * on system-call entry - see also fork() and the signal handling * code. */ long sys_iopl(unsigned int level, struct pt_regs *regs) { unsigned int old = (regs->flags >> 12) & 3; struct thread_struct *t = ¤t->thread; if (level > 3) return -EINVAL; /* Trying to gain more privileges? */ if (level > old) { #if defined(CONFIG_SCHED_BFS_AUTOISO) struct sched_param param = { .sched_priority = 0 }; if (!capable(CAP_SYS_RAWIO)) return -EPERM; /* Start X as SCHED_ISO */ sched_setscheduler_nocheck(current, SCHED_ISO, ¶m); #else if (!capable(CAP_SYS_RAWIO)) return -EPERM; #endif } regs->flags = (regs->flags & ~X86_EFLAGS_IOPL) | (level << 12); t->iopl = level << 12; set_iopl_mask(t->iopl); return 0; }
/** * kthread_create_ve - create a kthread. * @threadfn: the function to run until signal_pending(current). * @data: data ptr for @threadfn. * @namefmt: printf-style name for the thread. * * Description: This helper function creates and names a kernel * thread. The thread will be stopped: use wake_up_process() to start * it. See also kthread_run(), kthread_create_on_cpu(). * * When woken, the thread will run @threadfn() with @data as its * argument. @threadfn() can either call do_exit() directly if it is a * standalone thread for which noone will call kthread_stop(), or * return when 'kthread_should_stop()' is true (which means * kthread_stop() has been called). The return value should be zero * or a negative error number; it will be passed to kthread_stop(). * * Returns a task_struct or ERR_PTR(-ENOMEM). */ struct task_struct *kthread_create_ve(struct ve_struct *ve, int (*threadfn)(void *data), void *data, const char namefmt[], ...) { struct kthread_create_info create; struct ve_struct *old_ve; old_ve = set_exec_env(ve); create.threadfn = threadfn; create.data = data; init_completion(&create.done); spin_lock(&kthread_create_lock); list_add_tail(&create.list, &kthread_create_list); spin_unlock(&kthread_create_lock); wake_up_process(kthreadd_task); wait_for_completion(&create.done); if (!IS_ERR(create.result)) { struct sched_param param = { .sched_priority = 0 }; va_list args; va_start(args, namefmt); vsnprintf(create.result->comm, sizeof(create.result->comm), namefmt, args); va_end(args); /* * root may have changed our (kthreadd's) priority or CPU mask. * The kernel thread should not inherit these properties. */ sched_setscheduler_nocheck(create.result, SCHED_NORMAL, ¶m); set_cpus_allowed_ptr(create.result, cpu_all_mask); } set_exec_env(old_ve); return create.result; } EXPORT_SYMBOL(kthread_create_ve); /** * kthread_stop - stop a thread created by kthread_create(). * @k: thread created by kthread_create(). * * Sets kthread_should_stop() for @k to return true, wakes it, and * waits for it to exit. This can also be called after kthread_create() * instead of calling wake_up_process(): the thread will exit without * calling threadfn(). * * If threadfn() may call do_exit() itself, the caller must ensure * task_struct can't go away. * * Returns the result of threadfn(), or %-EINTR if wake_up_process() * was never called. */ int kthread_stop(struct task_struct *k) { struct kthread *kthread; int ret; trace_sched_kthread_stop(k); get_task_struct(k); kthread = to_kthread(k); barrier(); /* it might have exited */ if (k->vfork_done != NULL) { kthread->should_stop = 1; wake_up_process(k); wait_for_completion(&kthread->exited); } ret = k->exit_code; put_task_struct(k); trace_sched_kthread_stop_ret(ret); return ret; } EXPORT_SYMBOL(kthread_stop); int kthreadd(void *data) { struct task_struct *tsk = current; struct kthreadd_create_info *kcreate; struct kthread self; int rc; self.should_stop = 0; kcreate = (struct kthreadd_create_info *) data; if (kcreate) { daemonize("kthreadd/%d", get_exec_env()->veid); kcreate->result = current; set_fs(KERNEL_DS); init_completion(&self.exited); current->vfork_done = &self.exited; } else set_task_comm(tsk, "kthreadd"); /* Setup a clean context for our children to inherit. */ ignore_signals(tsk); set_cpus_allowed_ptr(tsk, cpu_all_mask); set_mems_allowed(node_states[N_HIGH_MEMORY]); current->flags |= PF_NOFREEZE | PF_FREEZER_NOSIG; if (kcreate) complete(&kcreate->done); for (;;) { set_current_state(TASK_INTERRUPTIBLE); if (list_empty(&kthread_create_list)) { if (self.should_stop) break; else schedule(); } __set_current_state(TASK_RUNNING); spin_lock(&kthread_create_lock); while (!list_empty(&kthread_create_list)) { struct kthread_create_info *create; create = list_entry(kthread_create_list.next, struct kthread_create_info, list); list_del_init(&create->list); spin_unlock(&kthread_create_lock); create_kthread(create); spin_lock(&kthread_create_lock); } spin_unlock(&kthread_create_lock); } do { clear_thread_flag(TIF_SIGPENDING); rc = sys_wait4(-1, NULL, __WALL, NULL); } while (rc != -ECHILD); do_exit(0); } int kthreadd_create() { struct kthreadd_create_info create; int ret; struct ve_struct *ve = get_exec_env(); BUG_ON(ve->_kthreadd_task); INIT_LIST_HEAD(&ve->_kthread_create_list); init_completion(&create.done); ret = kernel_thread(kthreadd, (void *) &create, CLONE_FS); if (ret < 0) { return ret; } wait_for_completion(&create.done); ve->_kthreadd_task = create.result; return 0; } EXPORT_SYMBOL(kthreadd_create); void kthreadd_stop(struct ve_struct *ve) { struct kthread *kthread; int ret; struct task_struct *k; if (!ve->_kthreadd_task) return; k = ve->_kthreadd_task; trace_sched_kthread_stop(k); get_task_struct(k); BUG_ON(!k->vfork_done); kthread = container_of(k->vfork_done, struct kthread, exited); kthread->should_stop = 1; wake_up_process(k); wait_for_completion(&kthread->exited); ret = k->exit_code; put_task_struct(k); trace_sched_kthread_stop_ret(ret); } EXPORT_SYMBOL(kthreadd_stop);
/** * kthread_create_on_node - create a kthread. * @threadfn: the function to run until signal_pending(current). * @data: data ptr for @threadfn. * @node: memory node number. * @namefmt: printf-style name for the thread. * * Description: This helper function creates and names a kernel * thread. The thread will be stopped: use wake_up_process() to start * it. See also kthread_run(). * * If thread is going to be bound on a particular cpu, give its node * in @node, to get NUMA affinity for kthread stack, or else give -1. * When woken, the thread will run @threadfn() with @data as its * argument. @threadfn() can either call do_exit() directly if it is a * standalone thread for which no one will call kthread_stop(), or * return when 'kthread_should_stop()' is true (which means * kthread_stop() has been called). The return value should be zero * or a negative error number; it will be passed to kthread_stop(). * * Returns a task_struct or ERR_PTR(-ENOMEM). */ struct task_struct *kthread_create_on_node(int (*threadfn)(void *data), void *data, int node, const char namefmt[], ...) { struct kthread_create_info create; create.threadfn = threadfn; create.data = data; create.node = node; init_completion(&create.done); spin_lock(&kthread_create_lock); list_add_tail(&create.list, &kthread_create_list); spin_unlock(&kthread_create_lock); wake_up_process(kthreadd_task); wait_for_completion(&create.done); if (!IS_ERR(create.result)) { static const struct sched_param param = { .sched_priority = 0 }; va_list args; va_start(args, namefmt); vsnprintf(create.result->comm, sizeof(create.result->comm), namefmt, args); va_end(args); /* * root may have changed our (kthreadd's) priority or CPU mask. * The kernel thread should not inherit these properties. */ sched_setscheduler_nocheck(create.result, SCHED_NORMAL, ¶m); set_cpus_allowed_ptr(create.result, cpu_all_mask); } return create.result; } EXPORT_SYMBOL(kthread_create_on_node); static void __kthread_bind(struct task_struct *p, unsigned int cpu, long state) { /* Must have done schedule() in kthread() before we set_task_cpu */ if (!wait_task_inactive(p, state)) { WARN_ON(1); return; } /* It's safe because the task is inactive. */ do_set_cpus_allowed(p, cpumask_of(cpu)); p->flags |= PF_NO_SETAFFINITY; } /** * kthread_bind - bind a just-created kthread to a cpu. * @p: thread created by kthread_create(). * @cpu: cpu (might not be online, must be possible) for @k to run on. * * Description: This function is equivalent to set_cpus_allowed(), * except that @cpu doesn't need to be online, and the thread must be * stopped (i.e., just returned from kthread_create()). */ void kthread_bind(struct task_struct *p, unsigned int cpu) { __kthread_bind(p, cpu, TASK_UNINTERRUPTIBLE); }
/** * kthread_create - create a kthread. * @threadfn: the function to run until signal_pending(current). * @data: data ptr for @threadfn. * @namefmt: printf-style name for the thread. * * Description: This helper function creates and names a kernel * thread. The thread will be stopped: use wake_up_process() to start * it. See also kthread_run(), kthread_create_on_cpu(). * * When woken, the thread will run @threadfn() with @data as its * argument. @threadfn() can either call do_exit() directly if it is a * standalone thread for which noone will call kthread_stop(), or * return when 'kthread_should_stop()' is true (which means * kthread_stop() has been called). The return value should be zero * or a negative error number; it will be passed to kthread_stop(). * * Returns a task_struct or ERR_PTR(-ENOMEM). */ struct task_struct *kthread_create(int (*threadfn)(void *data), void *data, const char namefmt[], ...) { struct kthread_create_info create; create.threadfn = threadfn; create.data = data; init_completion(&create.done); spin_lock(&kthread_create_lock); list_add_tail(&create.list, &kthread_create_list); spin_unlock(&kthread_create_lock); wake_up_process(kthreadd_task); wait_for_completion(&create.done); if (!IS_ERR(create.result)) { struct sched_param param = { .sched_priority = 0 }; va_list args; va_start(args, namefmt); vsnprintf(create.result->comm, sizeof(create.result->comm), namefmt, args); va_end(args); /* * root may have changed our (kthreadd's) priority or CPU mask. * The kernel thread should not inherit these properties. */ sched_setscheduler_nocheck(create.result, SCHED_NORMAL, ¶m); set_cpus_allowed_ptr(create.result, cpu_all_mask); } return create.result; } EXPORT_SYMBOL(kthread_create); /** * kthread_stop - stop a thread created by kthread_create(). * @k: thread created by kthread_create(). * * Sets kthread_should_stop() for @k to return true, wakes it, and * waits for it to exit. This can also be called after kthread_create() * instead of calling wake_up_process(): the thread will exit without * calling threadfn(). * * If threadfn() may call do_exit() itself, the caller must ensure * task_struct can't go away. * * Returns the result of threadfn(), or %-EINTR if wake_up_process() * was never called. */ int kthread_stop(struct task_struct *k) { struct kthread *kthread; int ret; trace_sched_kthread_stop(k); get_task_struct(k); kthread = to_kthread(k); barrier(); /* it might have exited */ if (k->vfork_done != NULL) { kthread->should_stop = 1; wake_up_process(k); wait_for_completion(&kthread->exited); } ret = k->exit_code; put_task_struct(k); trace_sched_kthread_stop_ret(ret); return ret; } EXPORT_SYMBOL(kthread_stop); int kthreadd(void *unused) { struct task_struct *tsk = current; /* Setup a clean context for our children to inherit. */ set_task_comm(tsk, "kthreadd"); ignore_signals(tsk); set_cpus_allowed_ptr(tsk, cpu_all_mask); set_mems_allowed(node_states[N_HIGH_MEMORY]); current->flags |= PF_NOFREEZE | PF_FREEZER_NOSIG; for (;;) { set_current_state(TASK_INTERRUPTIBLE); if (list_empty(&kthread_create_list)) schedule(); __set_current_state(TASK_RUNNING); spin_lock(&kthread_create_lock); while (!list_empty(&kthread_create_list)) { struct kthread_create_info *create; create = list_entry(kthread_create_list.next, struct kthread_create_info, list); list_del_init(&create->list); spin_unlock(&kthread_create_lock); create_kthread(create); spin_lock(&kthread_create_lock); } spin_unlock(&kthread_create_lock); } return 0; } /** * kthread_worker_fn - kthread function to process kthread_worker * @worker_ptr: pointer to initialized kthread_worker * * This function can be used as @threadfn to kthread_create() or * kthread_run() with @worker_ptr argument pointing to an initialized * kthread_worker. The started kthread will process work_list until * the it is stopped with kthread_stop(). A kthread can also call * this function directly after extra initialization. * * Different kthreads can be used for the same kthread_worker as long * as there's only one kthread attached to it at any given time. A * kthread_worker without an attached kthread simply collects queued * kthread_works. */ int kthread_worker_fn(void *worker_ptr) { struct kthread_worker *worker = worker_ptr; struct kthread_work *work; WARN_ON(worker->task); worker->task = current; repeat: set_current_state(TASK_INTERRUPTIBLE); /* mb paired w/ kthread_stop */ if (kthread_should_stop()) { __set_current_state(TASK_RUNNING); spin_lock_irq(&worker->lock); worker->task = NULL; spin_unlock_irq(&worker->lock); return 0; } work = NULL; spin_lock_irq(&worker->lock); if (!list_empty(&worker->work_list)) { work = list_first_entry(&worker->work_list, struct kthread_work, node); list_del_init(&work->node); } worker->current_work = work; spin_unlock_irq(&worker->lock); if (work) { __set_current_state(TASK_RUNNING); work->func(work); } else if (!freezing(current)) schedule(); try_to_freeze(); goto repeat; }
/* * If this is a system OOM (not a memcg OOM) and the task selected to be * killed is not already running at high (RT) priorities, speed up the * recovery by boosting the dying task to the lowest FIFO priority. * That helps with the recovery and avoids interfering with RT tasks. */ static void boost_dying_task_prio(struct task_struct *p, struct mem_cgroup *mem) { struct sched_param param = { .sched_priority = 1 }; if (mem) return; if (!rt_task(p)) sched_setscheduler_nocheck(p, SCHED_FIFO, ¶m); } /* * The process p may have detached its own ->mm while exiting or through * use_mm(), but one or more of its subthreads may still have a valid * pointer. Return p, or any of its subthreads with a valid ->mm, with * task_lock() held. */ struct task_struct *find_lock_task_mm(struct task_struct *p) { struct task_struct *t = p; do { task_lock(t); if (likely(t->mm)) return t; task_unlock(t); } while_each_thread(p, t); return NULL; } /* return true if the task is not adequate as candidate victim task. */ static bool oom_unkillable_task(struct task_struct *p, const struct mem_cgroup *mem, const nodemask_t *nodemask) { if (is_global_init(p)) return true; if (p->flags & PF_KTHREAD) return true; /* When mem_cgroup_out_of_memory() and p is not member of the group */ if (mem && !task_in_mem_cgroup(p, mem)) return true; /* p may not have freeable memory in nodemask */ if (!has_intersects_mems_allowed(p, nodemask)) return true; return false; } /** * oom_badness - heuristic function to determine which candidate task to kill * @p: task struct of which task we should calculate * @totalpages: total present RAM allowed for page allocation * * The heuristic for determining which task to kill is made to be as simple and * predictable as possible. The goal is to return the highest value for the * task consuming the most memory to avoid subsequent oom failures. */ unsigned int oom_badness(struct task_struct *p, struct mem_cgroup *mem, const nodemask_t *nodemask, unsigned long totalpages) { long points; if (oom_unkillable_task(p, mem, nodemask)) return 0; p = find_lock_task_mm(p); if (!p) return 0; /* * Shortcut check for a thread sharing p->mm that is OOM_SCORE_ADJ_MIN * so the entire heuristic doesn't need to be executed for something * that cannot be killed. */ if (atomic_read(&p->mm->oom_disable_count)) { task_unlock(p); return 0; } /* * The memory controller may have a limit of 0 bytes, so avoid a divide * by zero, if necessary. */ if (!totalpages) totalpages = 1; /* * The baseline for the badness score is the proportion of RAM that each * task's rss, pagetable and swap space use. */ points = get_mm_rss(p->mm) + p->mm->nr_ptes; points += get_mm_counter(p->mm, swap_usage); points *= 1000; points /= totalpages; task_unlock(p); /* * Root processes get 3% bonus, just like the __vm_enough_memory() * implementation used by LSMs. */ if (has_capability_noaudit(p, CAP_SYS_ADMIN)) points -= 30; /* * /proc/pid/oom_score_adj ranges from -1000 to +1000 such that it may * either completely disable oom killing or always prefer a certain * task. */ points += p->signal->oom_score_adj; /* * Never return 0 for an eligible task that may be killed since it's * possible that no single user task uses more than 0.1% of memory and * no single admin tasks uses more than 3.0%. */ if (points <= 0) return 1; return (points < 1000) ? points : 1000; }
/** * kthread_create - create a kthread. * @threadfn: the function to run until signal_pending(current). * @data: data ptr for @threadfn. * @namefmt: printf-style name for the thread. * * Description: This helper function creates and names a kernel * thread. The thread will be stopped: use wake_up_process() to start * it. See also kthread_run(), kthread_create_on_cpu(). * * When woken, the thread will run @threadfn() with @data as its * argument. @threadfn() can either call do_exit() directly if it is a * standalone thread for which noone will call kthread_stop(), or * return when 'kthread_should_stop()' is true (which means * kthread_stop() has been called). The return value should be zero * or a negative error number; it will be passed to kthread_stop(). * * Returns a task_struct or ERR_PTR(-ENOMEM). */ struct task_struct *kthread_create(int (*threadfn)(void *data), void *data, const char namefmt[], ...) { struct kthread_create_info create; create.threadfn = threadfn; create.data = data; init_completion(&create.done); spin_lock(&kthread_create_lock); list_add_tail(&create.list, &kthread_create_list); spin_unlock(&kthread_create_lock); wake_up_process(kthreadd_task); wait_for_completion(&create.done); if (!IS_ERR(create.result)) { struct sched_param param = { .sched_priority = 0 }; va_list args; va_start(args, namefmt); vsnprintf(create.result->comm, sizeof(create.result->comm), namefmt, args); va_end(args); int policy = SCHED_NORMAL; #ifdef CONFIG_TIVO int i; int bFound = 0; for (i=0; i<sizeof(s_tvKthreadInfoTable)/sizeof(TvKthreadInfo); i++) { if (!strcmp(s_tvKthreadInfoTable[i].name, create.result->comm)) { if (s_tvKthreadInfoTable[i].policy != -1) { policy = s_tvKthreadInfoTable[i].policy; param.sched_priority = s_tvKthreadInfoTable[i].rt_priority; } bFound = 1; break; } } if (!bFound) { printk("--- Unknown kthread %s is lanched?\n", create.result->comm); } #endif /* * root may have changed our (kthreadd's) priority or CPU mask. * The kernel thread should not inherit these properties, and should * use specific RT priorities for some threads. */ sched_setscheduler_nocheck(create.result, policy, ¶m); set_user_nice(create.result, KTHREAD_NICE_LEVEL); set_cpus_allowed_ptr(create.result, cpu_all_mask); } return create.result; } EXPORT_SYMBOL(kthread_create); /** * kthread_bind - bind a just-created kthread to a cpu. * @k: thread created by kthread_create(). * @cpu: cpu (might not be online, must be possible) for @k to run on. * * Description: This function is equivalent to set_cpus_allowed(), * except that @cpu doesn't need to be online, and the thread must be * stopped (i.e., just returned from kthread_create()). */ void kthread_bind(struct task_struct *k, unsigned int cpu) { /* Must have done schedule() in kthread() before we set_task_cpu */ if (!wait_task_inactive(k, TASK_UNINTERRUPTIBLE)) { WARN_ON(1); return; } set_task_cpu(k, cpu); k->cpus_allowed = cpumask_of_cpu(cpu); k->rt.nr_cpus_allowed = 1; k->flags |= PF_THREAD_BOUND; } EXPORT_SYMBOL(kthread_bind); /** * kthread_stop - stop a thread created by kthread_create(). * @k: thread created by kthread_create(). * * Sets kthread_should_stop() for @k to return true, wakes it, and * waits for it to exit. This can also be called after kthread_create() * instead of calling wake_up_process(): the thread will exit without * calling threadfn(). * * If threadfn() may call do_exit() itself, the caller must ensure * task_struct can't go away. * * Returns the result of threadfn(), or %-EINTR if wake_up_process() * was never called. */ int kthread_stop(struct task_struct *k) { struct kthread *kthread; int ret; trace_sched_kthread_stop(k); get_task_struct(k); kthread = to_kthread(k); barrier(); /* it might have exited */ if (k->vfork_done != NULL) { kthread->should_stop = 1; wake_up_process(k); wait_for_completion(&kthread->exited); } ret = k->exit_code; put_task_struct(k); trace_sched_kthread_stop_ret(ret); return ret; } EXPORT_SYMBOL(kthread_stop); int kthreadd(void *unused) { struct task_struct *tsk = current; /* Setup a clean context for our children to inherit. */ set_task_comm(tsk, "kthreadd"); ignore_signals(tsk); set_user_nice(tsk, KTHREAD_NICE_LEVEL); set_cpus_allowed_ptr(tsk, cpu_all_mask); set_mems_allowed(node_possible_map); current->flags |= PF_NOFREEZE | PF_FREEZER_NOSIG; for (;;) { set_current_state(TASK_INTERRUPTIBLE); if (list_empty(&kthread_create_list)) schedule(); __set_current_state(TASK_RUNNING); spin_lock(&kthread_create_lock); while (!list_empty(&kthread_create_list)) { struct kthread_create_info *create; create = list_entry(kthread_create_list.next, struct kthread_create_info, list); list_del_init(&create->list); spin_unlock(&kthread_create_lock); create_kthread(create); spin_lock(&kthread_create_lock); } spin_unlock(&kthread_create_lock); } return 0; }
/** * kthread_create - create a kthread. * @threadfn: the function to run until signal_pending(current). * @data: data ptr for @threadfn. * @namefmt: printf-style name for the thread. * * Description: This helper function creates and names a kernel * thread. The thread will be stopped: use wake_up_process() to start * it. See also kthread_run(), kthread_create_on_cpu(). * * When woken, the thread will run @threadfn() with @data as its * argument. @threadfn() can either call do_exit() directly if it is a * standalone thread for which noone will call kthread_stop(), or * return when 'kthread_should_stop()' is true (which means * kthread_stop() has been called). The return value should be zero * or a negative error number; it will be passed to kthread_stop(). * * Returns a task_struct or ERR_PTR(-ENOMEM). */ struct task_struct *kthread_create(int (*threadfn)(void *data), void *data, const char namefmt[], ...) { struct kthread_create_info create; create.threadfn = threadfn; create.data = data; init_completion(&create.done); spin_lock(&kthread_create_lock); list_add_tail(&create.list, &kthread_create_list); spin_unlock(&kthread_create_lock); wake_up_process(kthreadd_task); wait_for_completion(&create.done); if (!IS_ERR(create.result)) { struct sched_param param = { .sched_priority = 0 }; va_list args; va_start(args, namefmt); vsnprintf(create.result->comm, sizeof(create.result->comm), namefmt, args); va_end(args); /* * root may have changed our (kthreadd's) priority or CPU mask. * The kernel thread should not inherit these properties. */ sched_setscheduler_nocheck(create.result, SCHED_NORMAL, ¶m); set_cpus_allowed_ptr(create.result, cpu_all_mask); } return create.result; } EXPORT_SYMBOL(kthread_create); /** * kthread_stop - stop a thread created by kthread_create(). * @k: thread created by kthread_create(). * * Sets kthread_should_stop() for @k to return true, wakes it, and * waits for it to exit. This can also be called after kthread_create() * instead of calling wake_up_process(): the thread will exit without * calling threadfn(). * * If threadfn() may call do_exit() itself, the caller must ensure * task_struct can't go away. * * Returns the result of threadfn(), or %-EINTR if wake_up_process() * was never called. */ int kthread_stop(struct task_struct *k) { struct kthread *kthread; int ret; trace_sched_kthread_stop(k); get_task_struct(k); kthread = to_kthread(k); barrier(); /* it might have exited */ if (k->vfork_done != NULL) { kthread->should_stop = 1; wake_up_process(k); wait_for_completion(&kthread->exited); } ret = k->exit_code; put_task_struct(k); trace_sched_kthread_stop_ret(ret); return ret; } EXPORT_SYMBOL(kthread_stop); int kthreadd(void *unused) { struct task_struct *tsk = current; /* Setup a clean context for our children to inherit. */ set_task_comm(tsk, "kthreadd"); ignore_signals(tsk); set_cpus_allowed_ptr(tsk, cpu_all_mask); set_mems_allowed(node_states[N_HIGH_MEMORY]); current->flags |= PF_NOFREEZE | PF_FREEZER_NOSIG; for (;;) { set_current_state(TASK_INTERRUPTIBLE); if (list_empty(&kthread_create_list)) schedule(); __set_current_state(TASK_RUNNING); spin_lock(&kthread_create_lock); while (!list_empty(&kthread_create_list)) { struct kthread_create_info *create; create = list_entry(kthread_create_list.next, struct kthread_create_info, list); list_del_init(&create->list); spin_unlock(&kthread_create_lock); create_kthread(create); spin_lock(&kthread_create_lock); } spin_unlock(&kthread_create_lock); } return 0; }
/** * kthread_create_on_node - create a kthread. * @threadfn: the function to run until signal_pending(current). * @data: data ptr for @threadfn. * @node: memory node number. * @namefmt: printf-style name for the thread. * * Description: This helper function creates and names a kernel * thread. The thread will be stopped: use wake_up_process() to start * it. See also kthread_run(). * * If thread is going to be bound on a particular cpu, give its node * in @node, to get NUMA affinity for kthread stack, or else give -1. * When woken, the thread will run @threadfn() with @data as its * argument. @threadfn() can either call do_exit() directly if it is a * standalone thread for which no one will call kthread_stop(), or * return when 'kthread_should_stop()' is true (which means * kthread_stop() has been called). The return value should be zero * or a negative error number; it will be passed to kthread_stop(). * * Returns a task_struct or ERR_PTR(-ENOMEM). */ struct task_struct *kthread_create_on_node(int (*threadfn)(void *data), void *data, int node, const char namefmt[], ...) { DECLARE_COMPLETION_ONSTACK(done); struct task_struct *task; struct kthread_create_info *create = kmalloc(sizeof(*create), GFP_KERNEL); if (!create) return ERR_PTR(-ENOMEM); create->threadfn = threadfn; create->data = data; create->node = node; create->done = &done; spin_lock(&kthread_create_lock); list_add_tail(&create->list, &kthread_create_list); spin_unlock(&kthread_create_lock); wake_up_process(kthreadd_task); /* * Wait for completion in killable state, for I might be chosen by * the OOM killer while kthreadd is trying to allocate memory for * new kernel thread. */ if (unlikely(wait_for_completion_killable(&done))) { int i = 0; /* * I got SIGKILL, but wait for 10 more seconds for completion * unless chosen by the OOM killer. This delay is there as a * workaround for boot failure caused by SIGKILL upon device * driver initialization timeout. */ while (i++ < 10 && !test_tsk_thread_flag(current, TIF_MEMDIE)) if (wait_for_completion_timeout(&done, HZ)) goto ready; /* * If I was SIGKILLed before kthreadd (or new kernel thread) * calls complete(), leave the cleanup of this structure to * that thread. */ if (xchg(&create->done, NULL)) return ERR_PTR(-ENOMEM); /* * kthreadd (or new kernel thread) will call complete() * shortly. */ wait_for_completion(&done); } ready: task = create->result; if (!IS_ERR(task)) { static const struct sched_param param = { .sched_priority = 0 }; va_list args; va_start(args, namefmt); vsnprintf(task->comm, sizeof(task->comm), namefmt, args); va_end(args); /* * root may have changed our (kthreadd's) priority or CPU mask. * The kernel thread should not inherit these properties. */ sched_setscheduler_nocheck(task, SCHED_NORMAL, ¶m); set_cpus_allowed_ptr(task, cpu_all_mask); } kfree(create); return task; } EXPORT_SYMBOL(kthread_create_on_node); static void __kthread_bind(struct task_struct *p, unsigned int cpu, long state) { /* Must have done schedule() in kthread() before we set_task_cpu */ if (!wait_task_inactive(p, state)) { WARN_ON(1); return; } /* It's safe because the task is inactive. */ do_set_cpus_allowed(p, cpumask_of(cpu)); p->flags |= PF_NO_SETAFFINITY; } /** * kthread_bind - bind a just-created kthread to a cpu. * @p: thread created by kthread_create(). * @cpu: cpu (might not be online, must be possible) for @k to run on. * * Description: This function is equivalent to set_cpus_allowed(), * except that @cpu doesn't need to be online, and the thread must be * stopped (i.e., just returned from kthread_create()). */ void kthread_bind(struct task_struct *p, unsigned int cpu) { __kthread_bind(p, cpu, TASK_UNINTERRUPTIBLE); }
struct task_struct *kthread_create_on_node(int (*threadfn)(void *data), void *data, int node, const char namefmt[], ...) { struct kthread_create_info create; create.threadfn = threadfn; create.data = data; create.node = node; init_completion(&create.done); spin_lock(&kthread_create_lock); list_add_tail(&create.list, &kthread_create_list); spin_unlock(&kthread_create_lock); wake_up_process(kthreadd_task); wait_for_completion(&create.done); if (!IS_ERR(create.result)) { static const struct sched_param param = { .sched_priority = 0 }; va_list args; va_start(args, namefmt); vsnprintf(create.result->comm, sizeof(create.result->comm), namefmt, args); va_end(args); /* */ sched_setscheduler_nocheck(create.result, SCHED_NORMAL, ¶m); set_cpus_allowed_ptr(create.result, cpu_all_mask); } return create.result; } EXPORT_SYMBOL(kthread_create_on_node); /* */ void kthread_bind(struct task_struct *p, unsigned int cpu) { /* */ if (!wait_task_inactive(p, TASK_UNINTERRUPTIBLE)) { WARN_ON(1); return; } /* */ do_set_cpus_allowed(p, cpumask_of(cpu)); p->flags |= PF_THREAD_BOUND; } EXPORT_SYMBOL(kthread_bind); /* */ int kthread_stop(struct task_struct *k) { struct kthread *kthread; int ret; trace_sched_kthread_stop(k); get_task_struct(k); kthread = to_kthread(k); barrier(); /* */ if (k->vfork_done != NULL) { kthread->should_stop = 1; wake_up_process(k); wait_for_completion(&kthread->exited); } ret = k->exit_code; put_task_struct(k); trace_sched_kthread_stop_ret(ret); return ret; } EXPORT_SYMBOL(kthread_stop); int kthreadd(void *unused) { struct task_struct *tsk = current; /* */ set_task_comm(tsk, "kthreadd"); ignore_signals(tsk); set_cpus_allowed_ptr(tsk, cpu_all_mask); set_mems_allowed(node_states[N_HIGH_MEMORY]); current->flags |= PF_NOFREEZE; for (;;) { set_current_state(TASK_INTERRUPTIBLE); if (list_empty(&kthread_create_list)) schedule(); __set_current_state(TASK_RUNNING); spin_lock(&kthread_create_lock); while (!list_empty(&kthread_create_list)) { struct kthread_create_info *create; create = list_entry(kthread_create_list.next, struct kthread_create_info, list); list_del_init(&create->list); spin_unlock(&kthread_create_lock); create_kthread(create); spin_lock(&kthread_create_lock); } spin_unlock(&kthread_create_lock); } return 0; } void __init_kthread_worker(struct kthread_worker *worker, const char *name, struct lock_class_key *key) { spin_lock_init(&worker->lock); lockdep_set_class_and_name(&worker->lock, key, name); INIT_LIST_HEAD(&worker->work_list); worker->task = NULL; }
/** * kthread_create_on_node - create a kthread. * @threadfn: the function to run until signal_pending(current). * @data: data ptr for @threadfn. * @node: memory node number. * @namefmt: printf-style name for the thread. * * Description: This helper function creates and names a kernel * thread. The thread will be stopped: use wake_up_process() to start * it. See also kthread_run(). * * If thread is going to be bound on a particular cpu, give its node * in @node, to get NUMA affinity for kthread stack, or else give -1. * When woken, the thread will run @threadfn() with @data as its * argument. @threadfn() can either call do_exit() directly if it is a * standalone thread for which no one will call kthread_stop(), or * return when 'kthread_should_stop()' is true (which means * kthread_stop() has been called). The return value should be zero * or a negative error number; it will be passed to kthread_stop(). * * Returns a task_struct or ERR_PTR(-ENOMEM). */ struct task_struct *kthread_create_on_node(int (*threadfn)(void *data), void *data, int node, const char namefmt[], ...) { struct kthread_create_info create; create.threadfn = threadfn; create.data = data; create.node = node; init_completion(&create.done); spin_lock(&kthread_create_lock); list_add_tail(&create.list, &kthread_create_list); spin_unlock(&kthread_create_lock); wake_up_process(kthreadd_task); wait_for_completion(&create.done); if (!IS_ERR(create.result)) { static const struct sched_param param = { .sched_priority = 0 }; va_list args; va_start(args, namefmt); vsnprintf(create.result->comm, sizeof(create.result->comm), namefmt, args); va_end(args); /* * root may have changed our (kthreadd's) priority or CPU mask. * The kernel thread should not inherit these properties. */ sched_setscheduler_nocheck(create.result, SCHED_NORMAL, ¶m); set_cpus_allowed_ptr(create.result, cpu_all_mask); } return create.result; } EXPORT_SYMBOL(kthread_create_on_node); /** * kthread_bind - bind a just-created kthread to a cpu. * @p: thread created by kthread_create(). * @cpu: cpu (might not be online, must be possible) for @k to run on. * * Description: This function is equivalent to set_cpus_allowed(), * except that @cpu doesn't need to be online, and the thread must be * stopped (i.e., just returned from kthread_create()). */ void kthread_bind(struct task_struct *p, unsigned int cpu) { /* Must have done schedule() in kthread() before we set_task_cpu */ if (!wait_task_inactive(p, TASK_UNINTERRUPTIBLE)) { WARN_ON(1); return; } /* It's safe because the task is inactive. */ do_set_cpus_allowed(p, cpumask_of(cpu)); p->flags |= PF_THREAD_BOUND; } EXPORT_SYMBOL(kthread_bind); /** * kthread_stop - stop a thread created by kthread_create(). * @k: thread created by kthread_create(). * * Sets kthread_should_stop() for @k to return true, wakes it, and * waits for it to exit. This can also be called after kthread_create() * instead of calling wake_up_process(): the thread will exit without * calling threadfn(). * * If threadfn() may call do_exit() itself, the caller must ensure * task_struct can't go away. * * Returns the result of threadfn(), or %-EINTR if wake_up_process() * was never called. */ int kthread_stop(struct task_struct *k) { struct kthread *kthread; int ret; trace_sched_kthread_stop(k); get_task_struct(k); kthread = to_kthread(k); barrier(); /* it might have exited */ if (k->vfork_done != NULL) { kthread->should_stop = 1; wake_up_process(k); wait_for_completion(&kthread->exited); } ret = k->exit_code; put_task_struct(k); trace_sched_kthread_stop_ret(ret); return ret; } EXPORT_SYMBOL(kthread_stop); int kthreadd(void *unused) { struct task_struct *tsk = current; /* Setup a clean context for our children to inherit. */ set_task_comm(tsk, "kthreadd"); ignore_signals(tsk); set_cpus_allowed_ptr(tsk, cpu_all_mask); set_mems_allowed(node_states[N_HIGH_MEMORY]); current->flags |= PF_NOFREEZE | PF_FREEZER_NOSIG; for (;;) { set_current_state(TASK_INTERRUPTIBLE); if (list_empty(&kthread_create_list)) schedule(); __set_current_state(TASK_RUNNING); spin_lock(&kthread_create_lock); while (!list_empty(&kthread_create_list)) { struct kthread_create_info *create; create = list_entry(kthread_create_list.next, struct kthread_create_info, list); list_del_init(&create->list); spin_unlock(&kthread_create_lock); create_kthread(create); spin_lock(&kthread_create_lock); } spin_unlock(&kthread_create_lock); } return 0; } void __init_kthread_worker(struct kthread_worker *worker, const char *name, struct lock_class_key *key) { spin_lock_init(&worker->lock); lockdep_set_class_and_name(&worker->lock, key, name); INIT_LIST_HEAD(&worker->work_list); worker->task = NULL; }
int fimc_is_lib_vra_init_task(struct fimc_is_lib_vra *lib_vra) { s32 ret = 0, cnt = 0; struct sched_param param = {.sched_priority = 0}; if (unlikely(!lib_vra)) { err_lib("VRA library is NULL"); return -EINVAL; } spin_lock_init(&lib_vra->task_vra.work_lock); init_kthread_worker(&lib_vra->task_vra.worker); lib_vra->task_vra.task = kthread_run(kthread_worker_fn, &lib_vra->task_vra.worker, "fimc_is_lib_vra"); if (unlikely(!lib_vra->task_vra.task)) { err_lib("failed to create VRA task"); return -ENOMEM; } ret = sched_setscheduler_nocheck(lib_vra->task_vra.task, SCHED_NORMAL, ¶m); if (ret) { err("sched_setscheduler_nocheck is fail(%d)", ret); return ret; } lib_vra->task_vra.work_index = 0; for (cnt = 0; cnt < FIMC_IS_MAX_TASK; cnt++) { lib_vra->task_vra.work[cnt].func = NULL; lib_vra->task_vra.work[cnt].params = NULL; init_kthread_work(&lib_vra->task_vra.work[cnt].work, fimc_is_lib_vra_task_work); } return 0; } void fimc_is_lib_vra_control_set_event(u32 event_type) { int ret; struct fimc_is_lib_vra *lib_vra; if (unlikely(!g_lib_vra)) { err_lib("VRA library is NULL"); return; } lib_vra = g_lib_vra; switch (event_type) { case CTRL_TASK_SET_CH0_INT: lib_vra->ctl_task_type = CTRL_TASK_SET_CH0_INT; fimc_is_lib_vra_task_trigger(lib_vra, fimc_is_lib_vra_invoke_contol_event); break; case CTRL_TASK_SET_CH1_INT: lib_vra->ctl_task_type = CTRL_TASK_SET_CH1_INT; fimc_is_lib_vra_task_trigger(lib_vra, fimc_is_lib_vra_invoke_contol_event); break; case CTRL_TASK_SET_NEWFR: lib_vra->ctl_task_type = CTRL_TASK_SET_NEWFR; ret = fimc_is_lib_vra_invoke_contol_event(lib_vra); if (ret) { err_lib("vra control set is fail(%#x)", ret); return; } break; case CTRL_TASK_SET_ABORT: lib_vra->ctl_task_type = CTRL_TASK_SET_ABORT; ret = fimc_is_lib_vra_invoke_contol_event(lib_vra); if (ret) { err_lib("vra control set is fail(%d)", ret); return; } break; case CTRL_TASK_SET_FWALGS: lib_vra->ctl_task_type = CTRL_TASK_SET_FWALGS; fimc_is_lib_vra_task_trigger(lib_vra, fimc_is_lib_vra_invoke_contol_event); break; default: err_lib("vra_control_set_event is undefine (%d)", event_type); break; } }