mirror of https://github.com/tLDP/LDP
118 lines
7.3 KiB
Plaintext
118 lines
7.3 KiB
Plaintext
<sect1><title>Blocking Processes</title>
|
|
|
|
<indexterm><primary>blocking processes</primary></indexterm>
|
|
<indexterm><primary>processes</primary><secondary>blocking</secondary></indexterm>
|
|
|
|
<para>What do you do when somebody asks you for something you can't do right away? If you're a human being and you're
|
|
bothered by a human being, the only thing you can say is: <quote>Not right now, I'm busy. <emphasis>Go
|
|
away!</emphasis></quote>. But if you're a kernel module and you're bothered by a process, you have another possibility.
|
|
You can put the process to sleep until you can service it. After all, processes are being put to sleep by the kernel and
|
|
woken up all the time (that's the way multiple processes appear to run on the same time on a single CPU).</para>
|
|
|
|
<indexterm><primary>multi-tasking</primary></indexterm>
|
|
<indexterm><primary>busy</primary></indexterm>
|
|
<indexterm><primary>module_interruptible_sleep_on</primary></indexterm>
|
|
<indexterm><primary>interruptible_sleep_on</primary></indexterm>
|
|
<indexterm><primary>TASK_INTERRUPTIBLE</primary></indexterm>
|
|
<indexterm><primary>putting processes to sleep</primary></indexterm>
|
|
<indexterm><primary>sleep</primary><secondary>putting processes to</secondary></indexterm>
|
|
<indexterm><primary>waking up processes</primary></indexterm>
|
|
<indexterm><primary>processes</primary><secondary>waking up</secondary></indexterm>
|
|
<indexterm><primary>multitasking</primary></indexterm>
|
|
<indexterm><primary>scheduler</primary></indexterm>
|
|
|
|
<para>This kernel module is an example of this. The file (called <filename>/proc/sleep</filename>) can only be opened by a
|
|
single process at a time. If the file is already open, the kernel module calls
|
|
<function>wait_event_interruptible</function><footnote><para>The easiest way to keep a file open is to open it with
|
|
<command>tail -f</command>.</para></footnote>. This function changes the status of the task (a task is the kernel data
|
|
structure which holds information about a process and the system call it's in, if any) to
|
|
<parameter>TASK_INTERRUPTIBLE</parameter>, which means that the task will not run until it is woken up somehow, and adds
|
|
it to <structname>WaitQ</structname>, the queue of tasks waiting to access the file. Then, the function calls the
|
|
scheduler to context switch to a different process, one which has some use for the CPU.</para>
|
|
|
|
<para>When a process is done with the file, it closes it, and <function>module_close</function> is called. That function
|
|
wakes up all the processes in the queue (there's no mechanism to only wake up one of them). It then returns and the
|
|
process which just closed the file can continue to run. In time, the scheduler decides that the process has had enough
|
|
and gives control of the CPU to another process. Eventually, one of the processes which was in the queue will be given
|
|
control of the CPU by the scheduler. It starts at the point right after the call to
|
|
<function>module_interruptible_sleep_on</function><footnote><para>This means that the process is still in kernel mode --
|
|
as far as the process is concerned, it issued the <function>open</function> system call and the system call hasn't
|
|
returned yet. The process doesn't know somebody else used the CPU for most of the time between the moment it issued the
|
|
call and the moment it returned.</para></footnote>. It can then proceed to set a global variable to tell all the other
|
|
processes that the file is still open and go on with its life. When the other processes get a piece of the CPU, they'll
|
|
see that global variable and go back to sleep.</para>
|
|
|
|
<para> So we'll use <command> tail -f </command> to keep the file open in the background, while
|
|
trying to access it with another process (again in the background, so that we need not switch to
|
|
a different vt). As soon as the first background process is killed with <command> kill %1 </command>,
|
|
the second is woken up, is able to access the file and finally terminates. </para>
|
|
|
|
<indexterm><primary>signal</primary></indexterm>
|
|
<indexterm><primary>SIGINT</primary></indexterm>
|
|
<indexterm><primary>module_wake_up</primary></indexterm>
|
|
<indexterm><primary>module_sleep_on</primary></indexterm>
|
|
<indexterm><primary>sleep_on</primary></indexterm>
|
|
<indexterm><primary>ctrl-c</primary></indexterm>
|
|
|
|
<para>To make our life more interesting, <function>module_close</function> doesn't have a monopoly on waking up the
|
|
processes which wait to access the file. A signal, such as <keycombo
|
|
action="simul"><keycap>Ctrl</keycap><keycap>c</keycap></keycombo> (<parameter>SIGINT</parameter>) can also wake up a
|
|
process. <footnote> <para> This is because we used <function>module_interruptible_sleep_on</function>. We could have
|
|
used <function>module_sleep_on</function> instead, but that would have resulted is extremely angry users whose <keycombo
|
|
action="simul"><keycap>Ctrl</keycap><keycap>c</keycap></keycombo>s are ignored. </para> </footnote> In that case, we want
|
|
to return with <parameter>-EINTR</parameter> <indexterm><primary>EINTR</primary></indexterm> immediately. This is
|
|
important so users can, for example, kill the process before it receives the file.</para>
|
|
|
|
<indexterm><primary>processes</primary><secondary>killing</secondary></indexterm>
|
|
<indexterm><primary>O_NONBLOCK</primary></indexterm>
|
|
<indexterm><primary>non-blocking</primary></indexterm>
|
|
<indexterm><primary>EAGAIN</primary></indexterm>
|
|
<indexterm><primary>blocking, how to avoid</primary></indexterm>
|
|
|
|
<para>There is one more point to remember. Some times processes don't want to sleep, they want either to get what they
|
|
want immediately, or to be told it cannot be done. Such processes use the <parameter>O_NONBLOCK</parameter> flag when
|
|
opening the file. The kernel is supposed to respond by returning with the error code <parameter>-EAGAIN</parameter> from
|
|
operations which would otherwise block, such as opening the file in this example. The program
|
|
<command>cat_noblock</command>, available in the source directory for this chapter, can be used to open a file with
|
|
<parameter>O_NONBLOCK</parameter>.</para>
|
|
|
|
<screen>
|
|
hostname:~/lkmpg-examples/09-BlockingProcesses# insmod sleep.ko
|
|
hostname:~/lkmpg-examples/09-BlockingProcesses# cat_noblock /proc/sleep
|
|
Last input:
|
|
hostname:~/lkmpg-examples/09-BlockingProcesses# tail -f /proc/sleep &
|
|
Last input:
|
|
Last input:
|
|
Last input:
|
|
Last input:
|
|
Last input:
|
|
Last input:
|
|
Last input:
|
|
tail: /proc/sleep: file truncated
|
|
[1] 6540
|
|
hostname:~/lkmpg-examples/09-BlockingProcesses# cat_noblock /proc/sleep
|
|
Open would block
|
|
hostname:~/lkmpg-examples/09-BlockingProcesses# kill %1
|
|
[1]+ Terminated tail -f /proc/sleep
|
|
hostname:~/lkmpg-examples/09-BlockingProcesses# cat_noblock /proc/sleep
|
|
Last input:
|
|
hostname:~/lkmpg-examples/09-BlockingProcesses#
|
|
</screen>
|
|
|
|
<indexterm><primary>source file</primary><secondary>sleep.c</secondary></indexterm>
|
|
|
|
|
|
<example><title>sleep.c</title><programlisting><inlinegraphic fileref="lkmpg-examples/09-BlockingProcesses/sleep.c" format="linespecific"/></inlinegraphic></programlisting></example>
|
|
|
|
<example><title>cat_noblock.c</title><programlisting><inlinegraphic fileref="lkmpg-examples/09-BlockingProcesses/cat_noblock.c" format="linespecific"/></inlinegraphic></programlisting></example>
|
|
|
|
|
|
</sect1>
|
|
|
|
|
|
|
|
<!--
|
|
vim: tw=128
|
|
-->
|
|
|