2011$BG/(B02$B7n(B15$BF|(B
$B>pJs2J3XN`(B $B%*%Z%l!<%F%#%s%0%7%9%F%`(B II
$BC^GHBg3X(B $B%7%9%F%`>pJs9)3X8&5f2J(B
$B%3%s%T%e!<%?%5%$%(%s%9@l96(B, $BEE;R!&>pJs9)3X7O(B
$B?7>k(B $BLw(B
<yas@is.tsukuba.ac.jp>
$B$3$N%Z!<%8$O!"
http://www.coins.tsukuba.ac.jp/~yas/coins/os2-2010/2011-02-15
$B$"$k$$$O!"
http://www.coins.tsukuba.ac.jp/~yas/
http://www.cs.tsukuba.ac.jp/~yas/
$B?^(B? $B3d$j9~$_=hM}$NA0H>ItJ,$H8eH>ItJ,(B
$B3d$j9~$_%O%s%I%i(B($BA0H>It(B)$B$H8eH>It$NLr3dJ,C4$NL\0B!#(B
$BCm0U(B1: Tasklet $B$O!"(Btask $B9=B$BN$H$O$^$C$?$/4X78$J$$!#L>A0$,$h$/$J$$!#(B
$BCm0U(B2: Softirq $B$H$$$&MQ8l$r!"3d$j9~$_=hM}$N8eH>It$H$$$&0UL#$G;H$&?M$b$$(B $B$k!#(B
$BCm0U(B3: $BEAE}E*$J(BUnix$B$G$O!"(Btop half $B$O!"%7%9%F%`!&%3!<%k$+$iGI@8$9$k>e0L(B $BAX$N=hM}!"(Bbottom half $B$O!"3d$j9~$_$+$iGI@8$9$k2<0LAX$N=hM}$N0UL#$G;H$o(B $B$l$k$3$H$,$"$k!#(BLinux $B$G$O!"(Btop half, bottom half $B$O!"3d$j9~$_=hM}$NA0(B $BH>ItJ,$H8eH>ItJ,$N0UL#$K;H$&!#(B
$B?^(B? $B%O!<%I%&%'%"$N3d$j9~$_$K$*$1$k%O%s%I%i$N
$B?^(B? Softirq$B$G$N%O%s%I%i$N
$B$3$NJQ?t$N%S%C%H(Bn$B$r(B1$B$K$9$k(B(raise)$B$K$O!"
void raise_softirq(unsigned int n)
$B$^$:!"3d$j9~$_$,6X;_$7!"(B
n $B$G;XDj$5$l$?(B Softirq $B$r$B"!(Bdo_softirq()
do_softirq()$B!!$O!"(Braise $B$5$l$?(B Softirq $B$,$"$l$P
$B"!(BSoftirq$B$NMxMQ>l=j(B
Softirq $B$N
$B0J2<$O!"%M%C%H%o!<%/=hM}$G$N(B Softirq $B$NMxMQNc!#Aw?.(B(TX, Transmit) $B$H
include/linux/interrupt.h
401: struct softirq_action
402: {
403: void (*action)(struct softirq_action *);
404: };
net/core/dev.c
6003: static int __init net_dev_init(void)
6004: {
...
6066: open_softirq(NET_TX_SOFTIRQ, net_tx_action);
6067: open_softirq(NET_RX_SOFTIRQ, net_rx_action);
...
6075: }
...
2557: static void net_tx_action(struct softirq_action *h)
2558: {
...
2612: }
...
3485: static void net_rx_action(struct softirq_action *h)
3486: {
...
3569: }
$B"!(Bksoftirqd(kernel soft IRQ daemon)
ksoftirqd $B$O!"(BSoftirq $B$d(B Tasklet $B$r
$BLdBj(B
Tasklet $B$G#1$D$N;E;v$O include/linux/interrupt.h 455: struct tasklet_struct 456: { 457: struct tasklet_struct *next; 458: unsigned long state; 459: atomic_t count; 460: void (*func)(unsigned long); 461: unsigned long data; 462: };
$B?^(B? Tasklet$B$K$*$1$k;E;v$N%-%e!<(B
kernel/softirq.c
351: struct tasklet_head
352: {
353: struct tasklet_struct *head;
354: struct tasklet_struct **tail;
355: };
356:
357: static DEFINE_PER_CPU(struct tasklet_head, tasklet_vec);
358: static DEFINE_PER_CPU(struct tasklet_head, tasklet_hi_vec);
include/linux/interrupt.h
501: static inline void tasklet_schedule(struct tasklet_struct *t)
502: {
503: if (!test_and_set_bit(TASKLET_STATE_SCHED, &t->state))
504: __tasklet_schedule(t);
505: }
kernel/softirq.c
360: void __tasklet_schedule(struct tasklet_struct *t)
361: {
362: unsigned long flags;
363:
364: local_irq_save(flags);
365: t->next = NULL;
366: *__get_cpu_var(tasklet_vec).tail = t;
367: __get_cpu_var(tasklet_vec).tail = &(t->next);
368: raise_softirq_irqoff(TASKLET_SOFTIRQ);
369: local_irq_restore(flags);
370: }
drivers/net/wireless/ath/ath9k/init.c
565: tasklet_init(&sc->intr_tq, ath9k_tasklet, (unsigned long)sc);
drivers/net/wireless/ath/ath9k/main.c
623: irqreturn_t ath_isr(int irq, void *dev)
624: {
...
738: tasklet_schedule(&sc->intr_tq);
...
741: return IRQ_HANDLED;
744: }
559: void ath9k_tasklet(unsigned long data)
560: {
...
621: }
$B?^(B? Work Queue$B$K$*$1$k;E;v$N%-%e!<(B
$B%-%e!<$K$D$J$,$l$k;E;v$O!"(BTasklet $B$N;E;v$H$[$H$s$IF1$8$G!"4X?t$X$N%]%$(B
$B%s%?(B func $B$H(B data $B$+$i$J$k!#=hM}$N
Work Queue $B%G%U%)%k%H$N%o!<%+!&%9%l%C%I$O!"(Bevents/n (n$B$O%W%m%;%C%5HV9f(B)
$B$H$h$P$l!"%W%m%;%C%5$4$H$K:n$i$l$k!##1$D$N%9%l%C%I$G!"MM!9$JMW5a85$N;E(B
$B;v$r$3$J$9!#(B
$BFH<+$N%o!<%+!&%9%l%C%I$r:n$k$3$H$b$G$-$k!#(B
F UID PID PPID PRI NI VSZ RSS WCHAN STAT TTY TIME COMMAND
4 0 1 0 15 0 2160 676 stext Ss ? 0:02 init [5]
...
1 0 8 1 10 -5 0 0 worker S< ? 0:00 [events/0]
1 0 9 1 10 -5 0 0 worker S< ? 0:00 [events/1]
...
$
$B"!(Bwork_struct$B9=B$BN(B
$B%o!<%/!&%-%e!<$GMQ$$$k(B 1 $B$D$N;E;v$O!"9=B$BN(B struct work_struct $B$GI=8=$5(B
$B$l$k!#(B
include/linux/workqueue.h
18: typedef void (*work_func_t)(struct work_struct *work);
...
79: struct work_struct {
80: atomic_long_t data;
81: struct list_head entry;
82: work_func_t func;
...
86: };
$B
struct work_struct my_work;
...
INIT_WORK(&my_work,my_work_handler);
$B"!(BWork Queue $B%O%s%I%i(B
Work Queue $B%O%s%I%i$O!"
void my_work_handler(struct work_struct *work)
{
...
}
$B"!(BWork $B$N
$B%O%s%I%i$r8F$S=P$7$?$$;~$K$O!"
schedule_work(&work);
$B$3$N7k2L!"(BINIT_WORK() $B$G@_Dj$7$?%O%s%I%i$,%o!<%+!&%9%l%C%I$K$h$j!V$=$N(B
$B$&$A!W$K8F$S=P$5$l$k!#(B
schedule_work() $B$G$O!"B(:B$K$B"!(Bflush_scheduled_work()
schedule_work() $B$GMW5a$7$?;E;v$,40N;$7$?$3$H$rBT$C$F!"$B"!(Bcreate_workqueue()
$BFH<+$N%o!<%+!&%9%l%C%I$H%-%e!<$r:n$j$?$$;~$K$O!"
struct workqueue_struct *create_workqueue(char *name)
$B%o!<%+!&%9%l%C%I$H%-%e!<$r:n@.$7!"(Bstruct workqueue_struct $B$X$N%](B
$B%$%s%?$rJV$9!#0z?t$O!"%o!<%+!&%9%l%C%I$NL>A0!#(B
int queue_work(struct workqueue_struct *queue, struct work_struct *work)
$B%-%e!<$K;E;v$r2C$($k!#(B
int queue_delayed_work(struct workqueue_struct *queue,
struct work_struct *work, unsigned long delay)
$B%-%e!<$K;E;v$r2C$($k!#$?$@$7!"(Bdelay $B$@$18e$K$B"#3d$j9~$_$N8eH>It$NA*Br(B
$B"#%/%$%:(B8
$B3d$j9~$_$N8eH>It!"(BSoftirq$B!"(BTasklet$B!"(BWork Queue
$B!zLdBj(B(801) $B3d$j9~$_8eH>$N=hM}(B
$B3d$j9~$_=hM}$r!"A0H>(B(top half)$B$H8eH>(B(bottom half)$B$KJ,$1$kM}M3$r4JC1$K@b(B
$BL@$7$J$5$$!#(B
$B!zLdBj(B(802) Tasklet$B$N=i4|2=(B
$B$G8F$S=P$7$?$$!#(B
void h(void) {
....
}
$B$3$l$r
irqreturn_t irq_handler(int irq, void *dev) {
/*$B6uMs(B(d)*/
return IRQ_HANDLED;
}
Last updated: 2011/02/15 11:50:45
Yasushi Shinjo / <yas@is.tsukuba.ac.jp>