xref: /original-bsd/share/doc/psd/05.sysman/1.5.t (revision a1c2194a)
Copyright (c) 1983 The Regents of the University of California.
All rights reserved.

%sccs.include.redist.roff%

@(#)1.5.t 6.4 (Berkeley) 04/17/91

.sh Descriptors

The reference table

Each process has access to resources through descriptors. Each descriptor is a handle allowing the process 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 thus have multiple references, and are reference counted by the system.

Each process has a fixed size descriptor reference table, where the size is returned by the getdtablesize call: nds = getdtablesize(); result int nds; and guaranteed to be at least 20. The entries in the descriptor reference table are referred to by small integers; for example if there are 20 slots they are numbered 0 to 19. 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. The generic operations applying to many of these types are described in section 2.1. Naming contexts, files and directories are described in section 2.2. Section 2.3 describes communications domains and sockets. Terminals and (structured and unstructured) devices are described in section 2.4. Managing descriptor references

A duplicate of a descriptor reference may be made by doing new = dup(old); result int new; int old; returning a copy of descriptor reference old indistinguishable from the original. The 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 dup2(old, new); int old, new; The 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. This deallocation is also performed by: close(old); int old; Multiplexing requests

The system provides a standard way to do synchronous and asynchronous multiplexing of operations.

Synchronous multiplexing is performed by using the 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: #include <sys/types.h> nds = select(nd, in, out, except, tvp); result int nds; int nd; result fd_set *in, *out, *except; struct timeval *tvp; FD_ZERO(&fdset); FD_SET(fd, &fdset); FD_CLR(fd, &fdset); FD_ISSET(fd, &fdset); int fs; fs_set fdset; The 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.

\*(bu
A descriptor selects for input if an input oriented operation such as read or receive is possible, or if a connection request may be accepted (see section 2.3.1.4).
\*(bu
A descriptor selects for output if an output oriented operation such as write or send is possible, or if an operation that was ``in progress'', such as connection establishment, has completed (see section 2.1.3).
\*(bu
A descriptor selects for an exceptional condition if a condition that would cause a SIGURG signal to be generated exists (see section 1.3.2), or other device-specific events have occurred.

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 0, the select waits indefinitely.

Options affecting I/O on a descriptor may be read and set by the call: ._d dopt = fcntl(d, cmd, arg) result int dopt; int d, cmd, arg; /* interesting values for cmd */ #define F_SETFL 3 /* set descriptor options */ #define F_GETFL 4 /* get descriptor options */ #define F_SETOWN 5 /* set descriptor owner (pid/pgrp) */ #define F_GETOWN 6 /* get descriptor owner (pid/pgrp) */ The F_SETFL cmd may be used to set a descriptor in non-blocking I/O mode and/or enable signaling when I/O is possible. F_SETOWN may be used to specify a process or process group to be signaled when using the latter mode of operation or when urgent indications arise.

Operations on non-blocking descriptors will either complete immediately, note an 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 for and return; when making a connection on a socket, the operation may return indicating that the connection establishment is ``in progress''. The select facility can be used to determine when further output is possible on the terminal, or when the connection establishment attempt is complete. Descriptor wrapping.\(dg

.FS \(dg The facilities described in this section are not included in 4.3BSD. .FE A user process may build descriptors of a specified type by wrapping a communications channel with a system supplied protocol translator: new = wrap(old, proto) result int new; int old; struct dprop *proto; Operations on the descriptor old are then translated by the system provided protocol translator into requests on the underlying object old in a way defined by the protocol. The protocols supported by the kernel may vary from system to system and are described in the programmers manual.

Protocols may be based on communications multiplexing or a rights-passing style of handling multiple requests made on the same object. For instance, a protocol for implementing a file abstraction may or may not include locally generated ``read-ahead'' requests. A protocol that provides for read-ahead may provide higher performance but have a more difficult implementation.

Another example is the terminal driving facilities. Normally a terminal is associated with a communications line, and the terminal type and standard terminal access protocol are wrapped around a synchronous communications line and given to the user. If a virtual terminal is required, the terminal driver can be wrapped around a communications link, the other end of which is held by a virtual terminal protocol interpreter.