man
page, all of these subroutines are in chapter 2.
You can specify the chapter from which a topic is found. For example,
to look up the topic ``open'' in chapter 2, you execute the command
man 2 open
.
At this level, the interface to a file is represented by an integer.
In fact, 0 is hardwired to stdin
, 1 is hardwired to
stdout
and 2 is hardwired to stderr
. You can also
open new files using the function open
.
At this level, a programmer has much control of the access mode of a file. Just to list a few interesting ``status flags'':
O_ASYNC
: enables ``interrupt driven'' I/O operations
without having to set up interrupt vectors and etc. An
``interrupt'' at this application level is called a
signal. Signals in Linux is a big topic, and should be
discussed in another class.
O_DIRECT
: uses direct operations. There is no
buffering, no cache, nothing. This means each unit of
access (read or write) must conform to the logical block size
of the file system.
O_SYNC
: synchronous I/O means a process only regains
control after data is physically written to a device.
O_NONBLOCK
: this permits read and write operations to
be non-blocking. When this flag is selected, a write operation
returns immediately, even though the data may be transferred.
The read and write operations using this interface are primitive. The read operation requires the FD, number of bytes to attempt to read, and where in memory to read it to. The write operation requires the FD, number of bytes ready to be written, and where in memory to write from.
The family of subroutines that use FDs is quite rich. For example,
the subroutine fcntl
is very handy because it can control many
aspects of a FD. For example, it can set or release a lease on a file.
A ``lease'' is essentially a listener that calls a callback function
when a file is opened for read or write operations. fcntl
can
also monitor a directory so that any changes to the directory
triggers some code execution.
Another interesting function is select
. This subroutine permits
a program to ``wait'' for I/O activities on a number of files. In
other words, it blocks a process until at least one of the monitored
FDs have input (data ready to be read) or output (written data is
transferred) activities. This way, a single-threaded program can
handle the simultaneous operations of multiple files. select
returns a value that indicates which FDs (being monitored) had
activities. A famous single-threaded program that uses select
is the open source proxy cache squid
.
If you are interested in networking, you will also find
listen
, socket
, accept
, connect
and bind
useful.
socket
creates a socket, which can be connection-based,
datagram-based or some other options. bind
associates a
socket with a ``name''. A ``name'' can be a TCP/IP port at a
particular IP address.
listen
blocks a thread until there is an attempt to connect to
a socket. When listen
unblocks, the process should either
reject the connection, or use accept
to accept the connection.
Once a connection is accepted, it creates a new FD for that
connection. Note that a socket may generate multiple simultaneous
connections. A process may use connect
to initiate a connection.
For child-parent process communication, sockets are usually an overkill.
This is why ``pipes'' are usually used instead. A pipe is a pair of
FDs (one for writing, one for reading). The function pipe
is used to create pipes. pipe
is usually used in conjunction
with fork
so that a child process may communicate with a
parent process using a FD.
In summary, the FD interface is low level, but it provides a lot of options for special file handling.
Copyright © 2006-10-16 by Tak Auyeung