内核线程 + 下半部(软中断,工作队列)
来源:互联网 发布:网络高清视频监控系统 编辑:程序博客网 时间:2024/05/17 02:24
下半部目前包括软中断,tasklet,工作队列。
软中断:
- 编译器静态分配的;
- 不互相抢占;
- 只有中断处理程序可以抢占它;
- 相同类型软中断可以在不同的CPU上同时运行;
- 大部分软中断处理程序都通过采取单处理器数据或其他技巧来避免加锁。
tasklet:
建立在软中断之上;
可以动态生成;
root:/etc:# ps -ef
UID PID PPID C STIME TTY TIME CMD
root 1 0 0 04:33 ? 00:00:00 init [5]
root 2 1 0 04:33 ? 00:00:00 [ksoftirqd/0] -----------------软中断,其包括分很多类型:
(enum
{
HI_SOFTIRQ=0,
TIMER_SOFTIRQ, --------- 定时器
NET_TX_SOFTIRQ,
NET_RX_SOFTIRQ, --------- 网络系统,对时间要求严格,所以直接使用软中断。
BLOCK_SOFTIRQ,
TASKLET_SOFTIRQ,
SCHED_SOFTIRQ,
#ifdef CONFIG_HIGH_RES_TIMERS
HRTIMER_SOFTIRQ,
#endif
RCU_SOFTIRQ, /* Preferable RCU should always be the last softirq */
};)
root 3 1 0 04:33 ? 00:00:00 [watchdog/0]
root 4 1 0 04:33 ? 00:00:00 [events/0] ------------- 工作队列
root 5 1 0 04:33 ? 00:00:00 [khelper]
root 6 1 0 04:33 ? 00:00:00 [kthread]
root 35 6 0 04:33 ? 00:00:00 [kblockd/0]
root 49 6 0 04:33 ? 00:00:00 [pdflush]
root 50 6 0 04:33 ? 00:00:00 [pdflush]
root 51 6 0 04:33 ? 00:00:00 [kswapd0]
root 52 6 0 04:33 ? 00:00:00 [aio/0]
root 169 1 0 04:33 ? 00:00:00 [mtdblockd]
root 192 6 0 04:33 ? 00:00:00 [kjournald]
root 216 6 0 04:33 ? 00:00:00 [kjournald]
root 219 6 0 04:33 ? 00:00:00 [kjournald]
asmlinkage void __init start_kernel(void)
{
init_IRQ();
init_timers();
hrtimers_init();
softirq_init();
rest_init(); --------- 其中创建了initd和kthreadd两个内核线程,且kthreadd处于休眠状态。
}
1、
static __init int spawn_ksoftirqd(void)
{
void *cpu = (void *)(long)smp_processor_id();
int err = cpu_callback(&cpu_nfb, CPU_UP_PREPARE, cpu); --- 此时创建并阻塞内核线程ksoftirqd/0,ksoftirqd/1等
BUG_ON(err == NOTIFY_BAD);
cpu_callback(&cpu_nfb, CPU_ONLINE, cpu); --- 此时唤醒内核线程
register_cpu_notifier(&cpu_nfb);
return 0;
}
early_initcall(spawn_ksoftirqd); ---- 每个CPU都启动了一个"ksoftirqd/%d"内核线程。
static int __cpuinit cpu_callback(struct notifier_block *nfb,
unsigned long action,
void *hcpu)
{
int hotcpu = (unsigned long)hcpu;
struct task_struct *p;
switch (action) {
case CPU_UP_PREPARE:
case CPU_UP_PREPARE_FROZEN:
p = kthread_create(ksoftirqd, hcpu, "ksoftirqd/%d", hotcpu);
if (IS_ERR(p)) {
printk("ksoftirqd for %i failed\n", hotcpu);
return NOTIFY_BAD;
}
kthread_bind(p, hotcpu);
per_cpu(ksoftirqd, hotcpu) = p;
break;
case CPU_ONLINE:
case CPU_ONLINE_FROZEN:
wake_up_process(per_cpu(ksoftirqd, hotcpu));
break;
#ifdef CONFIG_HOTPLUG_CPU
case CPU_UP_CANCELED:
case CPU_UP_CANCELED_FROZEN:
if (!per_cpu(ksoftirqd, hotcpu))
break;
/* Unbind so it can run. Fall thru. */
kthread_bind(per_cpu(ksoftirqd, hotcpu),
any_online_cpu(cpu_online_map));
case CPU_DEAD:
case CPU_DEAD_FROZEN: {
struct sched_param param = { .sched_priority = MAX_RT_PRIO-1 };
p = per_cpu(ksoftirqd, hotcpu);
per_cpu(ksoftirqd, hotcpu) = NULL;
sched_setscheduler_nocheck(p, SCHED_FIFO, ¶m);
kthread_stop(p);
takeover_tasklets(hotcpu);
break;
}
#endif /* CONFIG_HOTPLUG_CPU */
}
return NOTIFY_OK;
}
2、kthreadd平时休眠,被唤醒创建对应的内核线程;
软中断softirq,工作队列workqueue等通过kthread_create_on_node接口,激活kthreadd线程,进而创建对应的内核线程。创建完后,继续休眠进程。
此内核线程的调度策略为SCHED_NORMAL,优先级为0。//不同内核版本实现不同。
struct
task_struct *kthread_create(
int
(*threadfn)(
void
*data),
133
void
*data,
134
const
char
namefmt[],
135
...)
136
{
137
struct
kthread_create_info create;
138
139
create.threadfn = threadfn;
140
create.data = data;
141
init_completion(&create.done);
142
143
spin_lock(&kthread_create_lock);
144
list_add_tail(&create.list, &kthread_create_list);
145
spin_unlock(&kthread_create_lock);
146
147
wake_up_process(kthreadd_task);
148
wait_for_completion(&create.done);
149
150
if
(!IS_ERR(create.result)) {
151
struct
sched_param param = { .sched_priority = 0 };
152
va_list
args;
153
154
va_start
(args, namefmt);
155
vsnprintf(create.result->comm,
sizeof
(create.result->comm),
156
namefmt, args);
157
va_end
(args);
158
/**
159
* root may have changed our (kthreadd's) priority or CPU mask.
160
* The kernel thread should not inherit these properties.
161
*/
162
sched_setscheduler_nocheck(create.result, SCHED_NORMAL, ¶m);
163
set_cpus_allowed_ptr(create.result, cpu_all_mask);
164
}
165
return
create.result;
166
}
167
EXPORT_SYMBOL(kthread_create);
3、软中断直接执行位置
- local_bh_enable
- irq_exit
- netif_rx_ni,接收到网络报文,如果不是在中断状态下,则执行软中断;否则退出;
4、软中断内核线程被创建成功后,默认为休眠状态,有很多唤醒时机:
- 在中断退出irq_exit时,如果不是在中断状态下,则执行软中断;否则,唤醒ksoftirqd去执行软中断;
- 软中断过多,一次执行不完,则唤醒ksoftirqd;(分do_softirq一次执行不完,软中断内核线程一次执行不完两种情况。)
- tasklet_schedule,如果不是在中断状态下,则唤醒ksoftirqd;如果是中断状态,则不执行,认为退出中断时会执行软中断。
- 内核线程 + 下半部(软中断,工作队列)
- Linux2.6内核--中断下半部实现方法 工作队列
- Linux2.6内核--中断下半部实现方法 工作队列
- 中断下半部-工作队列
- 中断下半部-工作队列
- 《深入理解Linux内核》软中断/tasklet/工作队列
- 《深入理解Linux内核》软中断/tasklet/工作队列
- 《深入理解Linux内核》软中断/tasklet/工作队列
- 《深入理解Linux内核》软中断/tasklet/工作队列
- 《深入理解Linux内核》软中断/tasklet/工作队列
- Linux内核中的软中断、tasklet和工作队列详解
- 《深入理解Linux内核》软中断/tasklet/工作队列
- 《深入理解Linux内核》软中断/tasklet/工作队列
- 《深入理解Linux内核》软中断/tasklet/工作队列
- 《深入理解Linux内核》软中断/tasklet/工作队列
- Linux内核中断底半部处理--工作队列
- tasklet 工作队列 内核定时器 内核线程
- 中断上半部,下半部/软中断/tasklet/工作队列
- VC6.0之Debug调试总结
- 风柔月清,吾爱在浅秋
- 排列组合——隔板法
- Linux(一)——从历史开始
- 如何安装CSF防火墙
- 内核线程 + 下半部(软中断,工作队列)
- tomcat6.0.35 作成系统服务 及jvm参数设置
- js 对象理解(1)
- 土坷垃的情怀
- 《编程之美》 4.11 扫雷游戏的概率
- 类的一些基本知识
- Lucene小练十三(IK分词器)
- HDU 1807 Super Jumping! Jumping! Jumping!
- SPOJ 1043 Can you answer these queries I(GSS1 线段树)