Next Previous Contents

6. The Main Loop: comm_select()

At the core of Squid is the select(2) system call. Squid uses select() or poll(2) to process I/O on all open file descriptors. Hereafter we'll only use ``select'' to refer generically to either system call.

The select() and poll() system calls work by waiting for I/O events on a set of file descriptors. Squid only checks for read and write events. Squid knows that it should check for reading or writing when there is a read or write handler registered for a given file descriptor. Handler functions are registered with the commSetSelect function. For example:

        commSetSelect(fd, COMM_SELECT_READ, clientReadRequest, conn, 0);
In this example, fd is a TCP socket to a client connection. When there is data to be read from the socket, then the select loop will execute
        clientReadRequest(fd, conn);

The I/O handlers are reset every time they are called. In other words, a handler function must re-register itself with commSetSelect if it wants to continue reading or writing on a file descriptor. The I/O handler may be canceled before being called by providing NULL arguments, e.g.:

        commSetSelect(fd, COMM_SELECT_READ, NULL, NULL, 0);

These I/O handlers (and others) and their associated callback data pointers are saved in the fde data structure:

        struct _fde {
                ...
                PF *read_handler;
                void *read_data;
                PF *write_handler;
                void *write_data;
                close_handler *close_handler;
                DEFER *defer_check;
                void *defer_data;
        };
read_handler and write_handler are called when the file descriptor is ready for reading or writing, respectively. The close_handler is called when the filedescriptor is closed. The close_handler is actually a linked list of callback functions to be called.

In some situations we want to defer reading from a filedescriptor, even though it has data for us to read. This may be the case when data arrives from the server-side faster than it can be written to the client-side. Before adding a filedescriptor to the ``read set'' for select, we call defer_check (if it is non-NULL). If defer_check returns 1, then we skip the filedescriptor for that time through the select loop.

These handlers are stored in the FD_ENTRY structure as defined in comm.h. fd_table[] is the global array of FD_ENTRY structures. The handler functions are of type PF, which is a typedef:

    typedef void (*PF) (int, void *);
The close handler is really a linked list of handler functions. Each handler also has an associated pointer (void *data) to some kind of data structure.

comm_select() is the function which issues the select() system call. It scans the entire fd_table[] array looking for handler functions. Each file descriptor with a read handler will be set in the fd_set read bitmask. Similarly, write handlers are scanned and bits set for the write bitmask. select() is then called, and the return read and write bitmasks are scanned for descriptors with pending I/O. For each ready descriptor, the handler is called. Note that the handler is cleared from the FD_ENTRY before it is called.

After each handler is called, comm_select_incoming() is called to process new HTTP and ICP requests.

Typical read handlers are httpReadReply(), diskHandleRead(), icpHandleUdp(), and ipcache_dnsHandleRead(). Typical write handlers are commHandleWrite(), diskHandleWrite(), and icpUdpReply(). The handler function is set with commSetSelect(), with the exception of the close handlers, which are set with comm_add_close_handler().

The close handlers are normally called from comm_close(). The job of the close handlers is to deallocate data structures associated with the file descriptor. For this reason comm_close() must normally be the last function in a sequence to prevent accessing just-freed memory.

The timeout and lifetime handlers are called for file descriptors which have been idle for too long. They are further discussed in a following chapter.


Next Previous Contents