The Regents of the University of California. All rights reserved.
%sccs.include.redist.roff%
@(#)1.5.t 8.6 (Berkeley) 05/29/94
.Sh 2 Descriptors .Sh 3 "The reference table
Each process has access to resources through descriptors. Each descriptor is a handle allowing processes to reference objects such as files, devices and communications links.
Rather than allowing processes direct access to descriptors, the system introduces a level of indirection, so that descriptors may be shared between processes. Each process has a descriptor reference table, containing pointers to the actual descriptors. The descriptors themselves therefore may have multiple references, and are reference counted by the system.
Each process has a limited size descriptor reference table, where the current size is returned by the .Fn getdtablesize call: .Fd getdtablesize 0 "get descriptor table size nds = getdtablesize(); result int nds; and guaranteed to be at least 64. The maximum number of descriptors is a resource limit (see section .Xr 1.6.3 ). The entries in the descriptor reference table are referred to by small integers; for example if there are 64 slots they are numbered 0 to 63. .Sh 3 "Descriptor properties
Each descriptor has a logical set of properties maintained by the system and defined by its type. Each type supports a set of operations; some operations, such as reading and writing, are common to several abstractions, while others are unique. For those types that support random access, the current file offset is stored in the descriptor. The generic operations applying to many of these types are described in section .Xr 2.1 . Naming contexts, files and directories are described in section .Xr 2.2 . Section .Xr 2.3 describes communications domains and sockets. Terminals and (structured and unstructured) devices are described in section .Xr 2.4 . .Sh 3 "Managing descriptor references
A duplicate of a descriptor reference may be made by doing: .Fd dup 1 "duplicate an existing file descriptor new = dup(old); result int new; int old; returning a copy of descriptor reference old which is indistinguishable from the original. The value of new chosen by the system will be the smallest unused descriptor reference slot. A copy of a descriptor reference may be made in a specific slot by doing: .Fd dup2 2 "duplicate an existing file descriptor dup2(old, new); int old, new; The .Fn dup2 call causes the system to deallocate the descriptor reference current occupying slot new, if any, replacing it with a reference to the same descriptor as old.
Descriptors are deallocated by: .Fd close 1 "delete a descriptor close(old); int old; .Sh 3 "Multiplexing requests
The system provides a standard way to do synchronous and asynchronous multiplexing of operations. Synchronous multiplexing is performed by using the .Fn select call to examine the state of multiple descriptors simultaneously, and to wait for state changes on those descriptors. Sets of descriptors of interest are specified as bit masks, as follows: .Fd select 5 "synchronous I/O multiplexing nds = select(nd, in, out, except, tvp); result int nds; int nd; result fd_set *in, *out, *except; struct timeval *tvp; FD_CLR(fd, &fdset); FD_COPY(&fdset, &fdset2); FD_ISSET(fd, &fdset); FD_SET(fd, &fdset); FD_ZERO(&fdset); int fd; fs_set fdset, fdset2; The .Fn select call examines the descriptors specified by the sets in, out and except, replacing the specified bit masks by the subsets that select true for input, output, and exceptional conditions respectively (nd indicates the number of file descriptors specified by the bit masks). If any descriptors meet the following criteria, then the number of such descriptors is returned in nds and the bit masks are updated.
For these tests, an operation is considered to be possible if a call to the operation would return without blocking (even if the O_NONBLOCK flag were not set). For example, a descriptor would test as ready for reading if a read call would return immediately with data, an end-of-file indication, or an error other than EWOULDBLOCK.
If none of the specified conditions is true, the operation waits for one of the conditions to arise, blocking at most the amount of time specified by tvp. If tvp is given as NULL, the .Fn select waits indefinitely.
Options affecting I/O on a descriptor may be read and set by the call: .Fd fcntl 3 "file control dopt = fcntl(d, cmd, arg); result int dopt; int d, cmd, arg;
/* command values */ |
F_DUPFD /* return a new descriptor */ |
F_GETFD /* get file descriptor flags */ |
F_SETFD /* set file descriptor flags */ |
F_GETFL /* get file status flags */ |
F_SETFL /* set file status flags */ |
F_GETOWN /* get SIGIO/SIGURG proc/pgrp */ |
F_SETOWN /* set SIGIO/SIGURG proc/pgrp */ |
F_GETLK /* get blocking lock */ |
F_SETLK /* set or clear lock */ |
F_SETLKW /* set lock with wait */ |
Operations on non-blocking descriptors will either complete immediately, return the error EWOULDBLOCK, partially complete an input or output operation returning a partial count, or return an error EINPROGRESS noting that the requested operation is in progress. A descriptor which has signalling enabled will cause the specified process and/or process group be signaled, with a SIGIO for input, output, or in-progress operation complete, or a SIGURG for exceptional conditions.
For example, when writing to a terminal using non-blocking output, the system will accept only as much data as there is buffer space, then return. When making a connection on a socket, the operation may return indicating that the connection establishment is ``in progress''. The .Fn select facility can be used to determine when further output is possible on the terminal, or when the connection establishment attempt is complete.