/[lkdp]/lkdp/pm/interrupts.tex
ViewVC logotype

Diff of /lkdp/pm/interrupts.tex

Parent Directory Parent Directory | Revision Log Revision Log | View Patch Patch

revision 1.2 by kdlinux2001, Thu Nov 21 13:08:15 2002 UTC revision 1.3 by kdlinux2001, Tue Dec 17 08:58:20 2002 UTC
# Line 1  Line 1 
1  \chapter{Interrupts}  \chapter{Interrupts}
2          \section{Interrupt Basics: IDT Table} \index{set\_gate}          \section{Interrupt Basics: IDT Table} \index{set\_gate}
3                   The interrupt machanism is initialised by the functions \textit{trap\_init()} and \textit{init\_IRQ()} during the system bootup as explained int the section ~\ref{init:sk}. The following functions are used to insert the gates in the IDT.              \textbf{\Large T}he interrupt mechanism is initialized by the functions \textit{trap\_init()} and \textit{init\_IRQ()} during the system bootup as explained in the section ~\ref{init:sk}. The following functions are used to insert the gates in the IDT. The function \textit{trap\_init()} sets the exception mechanism while \textit{init\_IRQ()} initializes up the interrupts.
4   % TODO gate explaination and ref.          \par Please, refer to appendix ~\ref{appendix1} for the details about these gates.
5          \begin{verbatim}          \begin{verbatim}
6    
7              set_intr_gate(n, addr);              set_intr_gate(n, addr);
# Line 45  Line 45 
45          \end{verbatim}          \end{verbatim}
46          The depth field is used to balance the irq enable and disable requests.          The depth field is used to balance the irq enable and disable requests.
47          \newline          \newline
48          The lock field is used to prevent concurrent accesss in SMP environment.          The lock field is used to prevent concurrent access in SMP environment.
49          \par    The handler field desribes the list of all interrupt functions as descibed in the structure hw\_irq\_controller. The structure is defined in \url{include/linux/irq.h}          \par    The handler field describes the list of all interrupt functions as descibed in the structure hw\_irq\_controller. The structure is defined in \url{include/linux/irq.h}
50                    
51          \subsection{hw\_interrupt\_type}          \subsection{hw\_interrupt\_type}
52          \begin{verbatim}          \begin{verbatim}
# Line 63  Line 63 
63          };          };
64    
65          \end{verbatim}          \end{verbatim}
66                  The \textit{typename} is the irq name that appears in the file "/proc/interrupts". While the remaining fiels are the functions pointers, which are invoked to interact with the hardware in responce to driver calls like \textit{request\_irq()} and \textit{free\_irq()} and others.                  The \textit{typename} is the irq name that appears in the file "/proc/interrupts". While the remaining fields are the functions pointers, which are invoked to interact with the hardware in response to driver calls like \textit{request\_irq()} and \textit{free\_irq()} and others.
67    
68          \par    The action field in \textit{hw\_desc\_t} desribes the linked list of interrupt actions that are performed when the interrupt occures. The structure is defined in \url{include/linux/interrupt.h}. Since, the irq line may be shared by multiple devices, the irq functions are stored in a linked list. This linked list is populated with every call using the request\_irq() function for a particular irq line. These functions are NOT the microprocessor level ISRs, but links to those functions.          \par    The action field in \textit{hw\_desc\_t} desribes the linked list of interrupt actions that are performed when the interrupt occurs. The structure is defined in \url{include/linux/interrupt.h}. Since, the irq line may be shared by multiple devices, the irq functions are stored in a linked list. This linked list is populated with every call using the request\_irq() function for a particular irq line. These functions are NOT the microprocessor level ISRs, but links to those functions.
69                    
70          \subsection{irqaction}          \subsection{irqaction}
71          \begin{verbatim}          \begin{verbatim}
# Line 95  Line 95 
95          \item[name] The name of the interrupt.          \item[name] The name of the interrupt.
96          \item[dev\_id] The devices on which, the current interrupt action is going to operate. This has different values in case of a shared interrupt line.          \item[dev\_id] The devices on which, the current interrupt action is going to operate. This has different values in case of a shared interrupt line.
97          \item[next] The typical next pointer of a linked list.          \item[next] The typical next pointer of a linked list.
   
98          \end{description}          \end{description}
99            
100            \section{Exception Processing}
101            The exceptions are generated by the CPU itself as a result of processing error or limitations. The exceptions handers are set by the \textit{trap\_init} function defined in \url{arch/i386/kernel/traps.c}. Refer to Section ~\ref{init:trap_init} for details. The entries registered by the set\_trap\_gate function are used as ENTRY points to index the code in \url{arch/i386/kernel/entry.S}.
102            \begin{verbatim}
103            Example : NMI
104    
105            set_trap_gate(2,&nmi);
106    
107            ENTRY(nmi)
108                    pushl %eax
109                    SAVE_ALL
110                    movl %esp, %edx
111                    pushl $0
112                    pushl %edx
113                    call do_nmi
114                    addl $8, %esp
115                    RESTORE_ALL
116    
117                    jmp error_code
118            \end{verbatim}
119    
120            All the exceptions perform the generic function by calling the function. The function name is obtained by appending the exception name to \textit{do\_*}. The code at label error\_code is used to save the exception code, function address on to the stack and call invoke the appropriate function. These functions are defined in \url{arch/i386/kernel/traps.c}.
121    
122            \begin{verbatim}
123            error_code:
124                    pushl %ds
125                    pushl %eax
126                    xorl %eax, %eax
127                    pushl %ebp
128                    pushl %edi
129                    pushl %esi
130                    pushl %edx
131                    decl %eax                   # eax = -1
132                    pushl %ecx
133                    pushl %ebx
134                    cld
135                    movl %es, %ecx
136                    movl ORIG_EAX(%esp), %esi   # get the error code
137                    movl ES(%esp), %edi         # get the function address
138                    movl %eax, ORIG_EAX(%esp)
139                    movl %ecx, ES(%esp)
140                    movl %esp, %edx
141                    pushl %esi                  # push the error code
142                    pushl %edx                  # push the pt_regs pointer
143                    movl $(__KERNEL_DS), %edx
144                    movl %edx, %ds
145                    movl %edx, %es
146                    GET_THREAD_INFO(%ebx)
147                    call *%edi
148                    addl $8, %esp
149                    preempt_stop
150                    jmp ret_from_exception
151            \end{verbatim}
152            When the function(exception handler) jumps to \textit{error\_code:}, it first pushes the address of the function to be called and then pushes all the CPU registers. The system call in \%eax is also stored in ORIG\_EAX. This value is used, during the re-execution of system calls. The segment registers \%ds, \%es contain the address of kernel segment while \%edi register is populated using the values in the stack(\%esp) and later used to invoke the exception handler. Note, the "\texit{cld}" instruction clears the direction flag from the eflags register, which autoincrements the \%esi, \%edi registers. Refer to intel architecture for details.
153            \par While returning from exception, the code pops up the stack address of user mode registers and jumps to \textit{ret\_from\_exception}, wherein it checks for signals and so on.
154    
155          \section{Interrupt Processing}          \section{Interrupt Processing}
156                  The interrupt handling is performed by the \textit{do\_IRQ} function defined in \url{arch/i386/kernel/irq.c}. The do\_IRQ is invoked for all device IRQs from the common\_interrupt handler defined in \url{arch/i386/kernel/entry.S}. The special cross-CPU SMP interrupts are handled by different interrupt handler.                  The interrupt handling is performed by the \textit{do\_IRQ} function defined in \url{arch/i386/kernel/irq.c}. The do\_IRQ is invoked for all device IRQs from the common\_interrupt handler defined in \url{arch/i386/kernel/entry.S}. The special cross-CPU SMP interrupts are handled by different interrupt handler.
157                    
# Line 106  Line 160 
160          common_interrupt:          common_interrupt:
161              SAVE_ALL                 /* save flags on stack */              SAVE_ALL                 /* save flags on stack */
162              GET_THREAD_INFO(%ebx)    /* read thread status  */              GET_THREAD_INFO(%ebx)    /* read thread status  */
163              INC_PRE_COUNT(%ebx)      /* counter incresed    */              INC_PRE_COUNT(%ebx)      /* counter increased    */
164                call do_IRQ                call do_IRQ
165              jmp ret_from_intr        /* RET from interrupt  */              jmp ret_from_intr        /* RET from interrupt  */
166    
# Line 178  out: Line 232  out:
232          }          }
233    
234          \end{verbatim}          \end{verbatim}
235                  After the initial sanity checks, the IRQ is handled by the \textit{handle\_IRQ\_event()} function defined in \url{arch/i386/kernel/irq.c}. The spinlock is released before calling the handle\_IRQ\_event function because the handler functions can be exceuted by any CPU. Then, the handler updates the IRQ status and invokes the "end" function to the requesting source interrupt controller by calling \textit{desc-\_> handler-\_>end()}.                  After the initial sanity checks, the IRQ is handled by the \textit{handle\_IRQ\_event()} function defined in \url{arch/i386/kernel/irq.c}. The spinlock is released before calling the handle\_IRQ\_event function because the handler functions can be executed by any CPU. Then, the handler updates the IRQ status and invokes the "end" function to the requesting source interrupt controller by calling \textit{desc-\_> handler-\_>end()}.
236          \par The softirq status is checked before returning from the interupt. Softirqs are explained in section ~\ref{int:softirq}. The return value of 1 is returned for CPU executing the interrupt while other CPUs return 0.          \par The softirq status is checked before returning from the interrupt. Softirqs are explained in section ~\ref{int:softirq}. The return value of 1 is returned for CPU executing the interrupt while other CPUs return 0.
237    
238          \subsection{Function handle\_IRQ\_event}          \subsection{Function handle\_IRQ\_event}
239          \par The handle\_IRQ\_event function is described below in parts.          \par The handle\_IRQ\_event function is described below in parts.
# Line 224  out: Line 278  out:
278          Then, the interrupt are enabled using \_\_cli() call. and the macro \textit{irq\_exit} decreaments the local number of interrupts running per CPU.          Then, the interrupt are enabled using \_\_cli() call. and the macro \textit{irq\_exit} decreaments the local number of interrupts running per CPU.
279    
280          \subsection{interrupt related CPU status} \label{int:cpustat} \index{irq\_cpustat}          \subsection{interrupt related CPU status} \label{int:cpustat} \index{irq\_cpustat}
281                  The kernel defines interrupt related CPU status in the irq\_cpustat\_t structure. The structure defines the values of following parametes running on each CPU. All of these parameters store the interrupt, bottom half, softirq, system calls status for the cpu. These fields are frequently accessed by the interrupt handling code to determine the state of cpu, whether it is running interrupts, to check the number of bottom halves running, to check pending status of softirqs and so on. The macros related to access these elements are defined in \url{include/linux/irq_cpustat.h}.                  The kernel defines interrupt related CPU status in the irq\_cpustat\_t structure. The structure defines the values of following parameters running on each CPU. All of these parameters store the interrupt, bottom half, softirq, system calls status for the cpu. These fields are frequently accessed by the interrupt handling code to determine the state of cpu, whether it is running interrupts, to check the number of bottom halves running, to check pending status of softirqs and so on. The macros related to access these elements are defined in \url{include/linux/irq_cpustat.h}.
282          \begin{verbatim}          \begin{verbatim}
283    
284          /*      include/asm/hardirq.h ; offset sensitive code */          /*      include/asm/hardirq.h ; offset sensitive code */
# Line 251  out: Line 305  out:
305          \end{verbatim}          \end{verbatim}
306    
307          \section{Top Half}          \section{Top Half}
308          Since, a interrupt handling involves substantial amount of work, keeping the interupts disabled for a long time in not desirable. Hence, interrupt handlers need to finish up quickly. Hence, interrupt handler is split into two halves. The \textit{top half} is the routine that actually responds to the interrupt. This is the handler registered with the funcion \textit{request\_irq}, while the bottom half is a routine that is scheduled by the top half to be executed later, at a safer time.          Since, a interrupt handling involves substantial amount of work, keeping the interrupts disabled for a long time in not desirable. Hence, interrupt handlers need to finish up quickly. Hence, interrupt handler is split into two halves. The \textit{top half} is the routine that actually responds to the interrupt. This is the handler registered with the function \textit{request\_irq}, while the bottom half is a routine that is scheduled by the top half to be executed later, at a safer time.
309          \par Thus, a given interrupt handler is divided into a top half and a bottom half. Whenever an interrupt is raised, only the top half portion of the interrupt handler is executed. It generally includes the status updating of the interrupt flags and acknowleding the interrupting device. The bottom half of an interrupt handler is the part that not need to be done right away. It is schedules at a safer time.          \par Thus, a given interrupt handler is divided into a top half and a bottom half. Whenever an interrupt is raised, only the top half portion of the interrupt handler is executed. It generally includes the status updating of the interrupt flags and acknowledging the interrupting device. The bottom half of an interrupt handler is the part that not need to be done right away. It is schedules at a safer time.
310          \par Advantages of this scheme are listed below:          \par Advantages of this scheme are listed below:
311          \begin{itemize}          \begin{itemize}
312          \item Interrupts remain disabled for a very less amount of time.          \item Interrupts remain disabled for a very less amount of time.
# Line 284  out: Line 338  out:
338    
339          \end{verbatim}          \end{verbatim}
340    
341          A bottom half is defined by using \textit{init\_bh} function, with the bh number and routine parameters and deleted by using \textit{remove\_bh} function. The init\_bh function sets the bh routine parameter in the appropriate position in \textit{bh\_base} array \footnote{The \textit{mb()} function is related to CPU ordering. For wak ordered intel CPUs, this function deals with the memory barriers. Refer to \url{include/asm-i386/system.h} for details.} while remove\_bh function sets it to NULL.          A bottom half is defined by using \textit{init\_bh} function, with the bh number and routine parameters and deleted by using \textit{remove\_bh} function. The init\_bh function sets the bh routine parameter in the appropriate position in \textit{bh\_base} array \footnote{The \textit{mb()} function is related to CPU ordering. For weak ordered intel CPUs, this function deals with the memory barriers. Refer to \url{include/asm-i386/system.h} for details.} while remove\_bh function sets it to NULL.
342          \par The bottom half is activated only when the \textit{mark\_bh()} function is called. The mark\_bh function performs following operations.          \par The bottom half is activated only when the \textit{mark\_bh()} function is called. The mark\_bh function performs following operations.
343    
344          \subsection{Function mark\_bh} \label{int:markbh}          \subsection{Function mark\_bh} \label{int:markbh}
# Line 364  out: Line 418  out:
418          The function checks whether the global bh spinlock is held by other cpu or the cpu is executing any other irq. If both of these conditions are false, if calls function to invoke the bottom half. When the function returns, the cpu releases the global bh spinlock.          The function checks whether the global bh spinlock is held by other cpu or the cpu is executing any other irq. If both of these conditions are false, if calls function to invoke the bottom half. When the function returns, the cpu releases the global bh spinlock.
419    
420          \section{Task Queues} \label{int:tqueue}          \section{Task Queues} \label{int:tqueue}
421          Task queues are often used in conjunction with bottom half handlers. Exmaple: the timer task queue is processed when the timer queue bottom half handler runs. Thus, task queues are dynamic extension to bottom halves. Please, refer to section ~\ref{int:bh} for functional description of bottom halves. Since , botton halves have some limitations:          Task queues are often used in conjunction with bottom half handlers. Example: the timer task queue is processed when the timer queue bottom half handler runs. Thus, task queues are dynamic extension to bottom halves. Please, refer to section ~\ref{int:bh} for functional description of bottom halves. Since , bottom halves have some limitations:
422          \begin{itemize}          \begin{itemize}
423          \item There are only a fixed number (32) of bottom halves.          \item There are only a fixed number (32) of bottom halves.
424          \item Each bottom half can only be associated with one handler function.          \item Each bottom half can only be associated with one handler function.
# Line 372  out: Line 426  out:
426          \end{itemize}          \end{itemize}
427               So, with task queues, arbitrary number of functions can be chained and processed one after another at a later time.               So, with task queues, arbitrary number of functions can be chained and processed one after another at a later time.
428          \subsection{struct tq\_struct} \index{tq\_struct}          \subsection{struct tq\_struct} \index{tq\_struct}
429          \newline \par The task structure is defined in \url{include/linux/tqueue.h} as follows:          \\ \par The task structure is defined in \url{include/linux/tqueue.h} as follows:
430          \begin{verbatim}          \begin{verbatim}
431    
432          struct tq_struct {          struct tq_struct {
# Line 395  out: Line 449  out:
449    
450          \par A task queue can be created using the \textit{DECLARE\_TASK\_QUEUE()} macro while a task onto it can be queued using the \textit{queue\_task()} function. The task queue then can be processed using \textit{run\_task\_queue()}.  The function run\_task\_queue() checks if the queue is active or not and calls the function from \url{kernel/softirq.c}.          \par A task queue can be created using the \textit{DECLARE\_TASK\_QUEUE()} macro while a task onto it can be queued using the \textit{queue\_task()} function. The task queue then can be processed using \textit{run\_task\_queue()}.  The function run\_task\_queue() checks if the queue is active or not and calls the function from \url{kernel/softirq.c}.
451    
         \subsection{Function run\_task\_queue}  
         When task queues are processed, the pointer to the first element in the queue is removed from the queue and replaced with a null pointer. In fact, this removal is an atomic operation, one that cannot be interrupted. Then each element in the queue has its handling routine called in turn.  
         % TODO run_task_queue task_queue = list_head Properties in tqueue.h  
   
452          \par  Linux predefines the following task queues which are consumed at well known points:          \par  Linux predefines the following task queues which are consumed at well known points:
453          \begin{description}          \begin{description}
454          \item[ tq\_timer ] \index{tq\_timer} The timer task queue, run on each timer interrupt and when releasing a tty device (closing or releasing a half opened terminal device). Since the timer handler runs in interrupt context, the tq\_timer tasks also run in interrupt context and thus cannot block.          \item[ tq\_timer ] \index{tq\_timer} The timer task queue, run on each timer interrupt and when releasing a tty device (closing or releasing a half opened terminal device). Since the timer handler runs in interrupt context, the tq\_timer tasks also run in interrupt context and thus cannot block.
# Line 410  out: Line 460  out:
460          \item[ tq\_disk ] Used by low level block device access (and RAID) to start the actual requests. This task queue is exported to modules but shouldn't be used except for the special purposes which it was designed for. Unless a driver uses its own task queues, it does not need to call \textit{run\_tasks\_queues()} to process the queue, except under circumstances explained below.          \item[ tq\_disk ] Used by low level block device access (and RAID) to start the actual requests. This task queue is exported to modules but shouldn't be used except for the special purposes which it was designed for. Unless a driver uses its own task queues, it does not need to call \textit{run\_tasks\_queues()} to process the queue, except under circumstances explained below.
461          \end{description}          \end{description}
462    
463            \subsection{Function run\_task\_queue}
464            \begin{verbatim}
465    
466             /**** kernel/timer.c *****/
467    
468            void tqueue_bh(void)
469            {
470                 run_task_queue(&tq_timer);
471            }
472    
473            void immediate_bh(void)
474            {
475                 run_task_queue(&tq_immediate);
476            }
477    
478            \end{verbatim}
479            The \texit{run\_task\_queue} function is invoked for a particular task queue from its associated bottom half. The function checks whether the task queue is active ( Active task queue is defined as a task queue with non-NULL list) and invokes \textit{\_\_run\_task\_queue()} function with the appropriate task queue as parameter. When task queues are processed, the pointer to the first element in the queue is removed from the queue and replaced with a null pointer. The function is explaine below:
480            \begin{verbatim}
481            void __run_task_queue(task_queue *list)
482            {
483                struct list_head head, *next;
484                unsigned long flags;
485    
486                spin_lock_irqsave(&tqueue_lock, flags);
487                list_add(&head, list);
488                list_del_init(list);     /*  1. */
489                spin_unlock_irqrestore(&tqueue_lock, flags);
490    
491                next = head.next;
492                while (next != &head) {  /*  2. */
493                    void (*f) (void *);
494                    struct tq_struct *p;
495                    void *data;
496    
497                    p = list_entry(next, struct tq_struct, list);  /*  3. */
498                    next = next->next;
499                    f = p->routine;
500                    data = p->data;    
501                    wmb();
502                    p->sync = 0;
503                    if (f)
504                        f(data);         /*  4. */
505                }
506            }
507    
508            \end{verbatim}
509            \begin{enumerate}
510            \item The function removes the first task queue for execution. In fact, this removal is an atomic operation, one that cannot be interrupted using the spin\_lock/unlock\_irqsave/restore pair.
511            \item The function scans all the elements of the list till the starting node. Note, that the list is implemented as circular linked list.
512            \item The macro list\_entry [ defined in \url{include/linux/list.h}] retrives the element of type "struct tq\_struct" from the "list" using the "next" pointer.
513            \item Then each element in the queue has its handling routine called using the routine(f) and data(data).
514            \end{enumerate}
515    
516          \section{tasklets} \label{int:tasklets} \index{tasklets}          \section{tasklets} \label{int:tasklets} \index{tasklets}
517          The term tasklet is somewhat misleading, because tasklets have nothing to do with active processes or tasks in the operating system. The tasklet architecture is defined below:          The term tasklet is somewhat misleading, because tasklets have nothing to do with active processes or tasks in the operating system. The tasklet architecture is defined below:
518          \begin{itemize}          \begin{itemize}
# Line 420  out: Line 523  out:
523    
524          \end{itemize}          \end{itemize}
525    
526          Tasklets are multithreaded analogues of bottom halves. Following information is directly taken fromt he \url{include/linux/interrupt.h}. Main feature differing tasklets from generic softirqs is that tasklet runs on only one cpu simultaneously while softirqs can run simultaneously on multiple cpus. Hence, while executing tasklet, it should be confirmed that the tasklet is NOT running on other cpu.          Tasklets are multithreaded analogues of bottom halves. Following information is directly taken from the \url{include/linux/interrupt.h}. Main feature differing tasklets from generic softirqs is that tasklet runs on only one cpu simultaneously while softirqs can run simultaneously on multiple cpus. Hence, while executing tasklet, it should be confirmed that the tasklet is NOT running on other cpu.
527          \par Main feature differing tasklets from bottom halves is that different tasklets may be run simultaneously on different CPUs. But, this is NOT true for bottom halves.          \par Main feature differing tasklets from bottom halves is that different tasklets may be run simultaneously on different CPUs. But, this is NOT true for bottom halves.
528          \par The properties of tasklets are listed below. We shall explain them later.  Properties:          \par The properties of tasklets are listed below. We shall explain them later.  Properties:
529    
530          \begin{enumerate}          \begin{enumerate}
531          \item If tasklet\_schedule() is called, then tasklet is guaranteed to be executed on some cpu at least once after this.          \item If tasklet\_schedule() is called, then tasklet is guaranteed to be executed on some cpu at least once after this.
532          \item If the tasklet is already scheduled, but its excecution is still not started, it will be executed only once.          \item If the tasklet is already scheduled, but its execution is still not started, it will be executed only once.
533          \item If this tasklet is already running on another CPU (or schedule is called from tasklet itself), it is rescheduled for later.          \item If this tasklet is already running on another CPU (or schedule is called from tasklet itself), it is rescheduled for later.
534          \item Tasklet is strictly serialized with respect to itself, but not w.r.t. another tasklets. If client needs some intertask synchronization, he makes it with spinlocks.          \item Tasklet is strictly serialized with respect to itself, but not w.r.t. another tasklets. If client needs some intertask synchronization, he makes it with spinlocks.
535          \end{enumerate}          \end{enumerate}
# Line 474  out: Line 577  out:
577          }          }
578    
579          \end{verbatim}          \end{verbatim}
580          The function checks if the interrupt is running or NOT. Killing a tasklet from interupt context is not recommended. Then, the function schedules the tasklet \footnote{\#define yield() sys\_sched\_yield() in \url{include/linux/sched.h}} while the tasklet state is TASKLET\_STATE\_SCHED.          The function checks if the interrupt is running or NOT. Killing a tasklet from interrupt context is not recommended. Then, the function schedules the tasklet \footnote{\#define yield() sys\_sched\_yield() in \url{include/linux/sched.h}} while the tasklet state is TASKLET\_STATE\_SCHED.
581          \par The important function related to tasklets is \textit{\_\_tasklet\_schedule()}. \index{tasklet\_schedule}          \par The important function related to tasklets is \textit{\_\_tasklet\_schedule()}. \index{tasklet\_schedule}
582          \begin{verbatim}          \begin{verbatim}
583    
# Line 589  out: Line 692  out:
692    
693          \end{verbatim}          \end{verbatim}
694    
695          The function \textit{open\_softirq} is used to populate softirq properties. This function is used from softirq\_init. Refer section ~\ref{init:softirq_init} for softirq initialization. The function sets the data and the parameters of the softirq strcture in the global array \textit{softirq\_vec}.          The function \textit{open\_softirq} is used to populate softirq properties. This function is used from softirq\_init. Refer section ~\ref{init:softirq_init} for softirq initialization. The function sets the data and the parameters of the softirq structure in the global array \textit{softirq\_vec}.
696          \begin{verbatim}          \begin{verbatim}
697    
698          static struct softirq_action softirq_vec[32] __cacheline_aligned_in_smp ;          static struct softirq_action softirq_vec[32] __cacheline_aligned_in_smp ;
# Line 679  out: Line 782  out:
782          \newline          \newline
783          \subsection{ksoftirqd} \label{int:softirqd} \index{softirqd}          \subsection{ksoftirqd} \label{int:softirqd} \index{softirqd}
784          Softirq daemon is introduced in later versions of kernel 2.4. By design, \textit{ksoftirqd} is only run when softirq load is so high that IRQ contexts are not able to handle it all. The current softirq code is such that the the daemon is invoked when the softirq handler misses any pending softirqs that got activated while running softirqs and those pending softirqs will only be processed in the next IRQ tick or whenever the softirqd is scheduled.          Softirq daemon is introduced in later versions of kernel 2.4. By design, \textit{ksoftirqd} is only run when softirq load is so high that IRQ contexts are not able to handle it all. The current softirq code is such that the the daemon is invoked when the softirq handler misses any pending softirqs that got activated while running softirqs and those pending softirqs will only be processed in the next IRQ tick or whenever the softirqd is scheduled.
785          \newline \par Thus, Softirqd is a successful attempt to solve the latency problem created by the current design of softirqs. The softirqd is run at low priority. Kernel developers suggest that to get optimal performance is obtained, when both softirqs and tasklets are avoided, and processing is done in the hardirq context.          \\ \par Thus, Softirqd is a successful attempt to solve the latency problem created by the current design of softirqs. The softirqd is run at low priority. Kernel developers suggest that to get optimal performance is obtained, when both softirqs and tasklets are avoided, and processing is done in the hardirq context.
786          \newline \par Following functions are related to the softirq daemon.          \\ \par Following functions are related to the softirq daemon.
787          \begin{itemize}          \begin{itemize}
788          \item sqawn\_ksoftirqd : Used to spawn softirq daemon by creating new kernel thread.          \item sqawn\_ksoftirqd : Used to spawn softirq daemon by creating new kernel thread.
789          \item wakeup\_softirqd : Used to wake up softirq daemon and execute pending softirqs.          \item wakeup\_softirqd : Used to wake up softirq daemon and execute pending softirqs.
790          \item ksoftirqd : Used as main sfotirq daemon action.          \item ksoftirqd\_task : This macro is used to bind the specified task (generally "\textit{current}" task) with the softirq daemon. \textit{ksoftirqd\_task} is part of cpu interrupt status. Refer to section ~\ref{int:cpustat} for details.
791            \item ksoftirqd : Used as main softirq daemon action.
792          \end{itemize}          \end{itemize}
793    
794          \subsection{ksoftirqd daemon}          \subsection{ksoftirqd daemon}
# Line 725  out: Line 829  out:
829                  __set_current_state(TASK_INTERRUPTIBLE);                  __set_current_state(TASK_INTERRUPTIBLE);
830              }              }
831          }          }
832    
833            /*****  spawn_softirqd function *****/
834    
835            static __init int spawn_ksoftirqd(void)
836            {
837                int cpu;
838                for (cpu = 0; cpu < smp_num_cpus; cpu++)
839                    if (kernel_thread(ksoftirqd, (void *) (long) cpu,
840                           CLONE_FS | CLONE_FILES | CLONE_SIGNAL) < 0)
841                        printk("spawn_ksoftirqd() failed for cpu %d\n", cpu);
842                    else
843                        while (!ksoftirqd_task(cpu_logical_map(cpu)))
844                            yield();
845                return 0;
846            }
847    
848          \end{verbatim}          \end{verbatim}
849          % TODO argument          The ksoftirq daemon is spawned for all cpus from the \textit{spawn\_softirqd} function. The spu number is passed as parameter to the daemon function. Thus, each cpu runs a ksoftirqd daemon. If the softirq daemon starts successfully, it invokes the \texit{yield()=sys\_sched\_yield} function to schedule itself and add the current task to the runqueue.
850          The function cpu\_logical\_map() is architecture dependant. For i386 arch, it just returns the cpu. Then, the softirq is converted to daemon by daemonize() function. The softirq task sets its priority \footnote{nice = 19, specifies process priority. [-19...0...19] range is allowed where -19 is lowest priority while +19 is tht highest priority.} and also sets the signal properties. The function \textit{set\_cpus\_allowed} \footnote{set\_cpus\_allowed is defined in \url{kernel/sched.c}. The function is SMP specific.} migrates the softirq process to proper CPU, so that the function is scheduled only on this CPU and not allowed to run on other CPUs. If that condition occurs, a BUG is reported. The comm field of the process structure stores the comment namely the daemon name.          \par  The function cpu\_logical\_map() is architecture dependant. For i386 arch, it just returns the cpu. Then, the softirq is converted to daemon by daemonize() function. The softirq task sets its priority \footnote{nice = 19, specifies process priority. [-19...0...19] range is allowed where -19 is lowest priority while +19 is the highest priority.} and also sets the signal properties. The function \textit{set\_cpus\_allowed} \footnote{set\_cpus\_allowed is defined in \url{kernel/sched.c}. The function is SMP specific.} migrates the softirq process to proper CPU, so that the function is scheduled only on this CPU and not allowed to run on other CPUs. If that condition occurs, a BUG is reported. The comm field of the process structure stores the comment namely the daemon name.
851          \newline \par Then the function enters a loop, wherein it continuously checks whether any softirqs are pending or not. If any softirqs are pending, the scheduler is called to run the process and its state is change to TASK\_RUNNING.          \\ \par Then the function enters a loop, wherein it continuously checks whether any softirqs are pending or not. If any softirqs are pending, the scheduler is called to run the process and its state is change to TASK\_RUNNING.

Legend:
Removed from v.1.2  
changed lines
  Added in v.1.3

savannah-hackers-public@gnu.org
ViewVC Help
Powered by ViewVC 1.1.26