4.8 File Control The fcntl function is a general-purpose function for retrieving and modifying the flags associated with an open file descriptor. The fildes argument of fcntl specifies the descriptor, and the cmd argument specifies the operation. The fcntl function may take additional parameters depending on the value of cmd. SYNOPSIS #include <fcntl.h> #include <unistd.h> #include <sys/types.h> int fcntl(int fildes, int cmd, /* arg */ ...); POSIX
The interpretation of the return value of fcntl depends on the value of the cmd parameter. However, if unsuccessful, fcntl returns 1 and sets errno. The following table lists the mandatory errors for fcntl.|
EACCES | cmd is F_SETLK and locking not allowed | EBADF | fildes is not a valid open file descriptor or file is not opened properly for type of lock | EINTR | cmd is F_SETLKW and function interrupted by a signal | EINVAL | cmd is invalid, or cmd is F_DUPFD and arg is negative or greater than or equal to OPEN_MAX, or cmd is a locking function and arg is invalid, or fildes refers to a file that does not support locking | EMFILE | cmd is F_DUPFD and OPEN_MAX descriptors for process are open, or no file descriptors greater than or equal to arg are available | ENOLCK | cmd is F_SETLK or F_SETLKW and locks would exceed limit | EOVERFLOW | one of values to be returned cannot be represented correctly, or requested lock offset cannot be represented in off_t | The fcntl function may only be interrupted by a signal when the cmd argument is F_SETLKW (block until the process acquires an exclusive lock). In this case, fcntl returns 1 and sets errno to EINTR. Section 4.4 and Section 4.5 discuss the select and poll functions that allow a process to block until any of a set of descriptors becomes available. However, both of these functions block while waiting for I/O, so no other work can be done during the wait.Table 4.3. POSIX values for cmd as specified in fcntl.h.|
F_DUPFD | duplicate a file descriptor | F_GETFD | get file descriptor flags | F_SETFD | set file descriptor flags | F_GETFL | get file status flags and access modes | F_SETFL | set file status flags and access modes | F_GETOWN | if fildes is a socket, get process or group ID for out-of-band signals | F_SETOWN | if fildes is a socket, set process or group ID for out-of-band signals | F_GETLK | get first lock that blocks description specified by arg | F_SETLK | set or clear segment lock specified by arg | F_SETLKW | same as FSETLK except it blocks until request satisfied | To perform nonblocking I/O, a program can call open with the O_NONBLOCK flag set. A program can also change an open descriptor to be nonblocking by setting the O_NONBLOCK flag, using fcntl. To set an open descriptor to perform nonblocking I/O, use the F_GETFL command with fcntl to retrieve the flags associated with the descriptor. Use inclusive bitwise OR of O_NONBLOCK with these flags to create a new flags value. Finally, set the descriptor flags to this new value, using the F_SETFL command of fcntl.Example 4.37 setnonblock.c The following function sets an already opened file descriptor fd for nonblocking I/O. #include <fcntl.h> #include <stdio.h> #include <unistd.h> int setnonblock(int fd) { int fdflags; if ((fdflags = fcntl(fd, F_GETFL, 0)) == -1) return -1; fdflags |= O_NONBLOCK; if (fcntl(fd, F_SETFL, fdflags) == -1) return -1; return 0; }
If successful, setnonblock returns 0. Otherwise, setnonblock returns 1 and sets errno.The setnonblock function of Example 4.37 reads the current value of the flags associated with fd, performs a bitwise OR with O_NONBLOCK, and installs the modified flags. After this function executes, a read from fd returns immediately if no input is available.Example 4.38 setblock.c The following function changes the I/O mode associated with file descriptor fd to blocking by clearing the O_NONBLOCK file flag. To clear the flag, use bitwise AND with the complement of the O_NONBLOCK flag. #include <fcntl.h> #include <stdio.h> #include <unistd.h> int setblock(int fd) { int fdflags; if ((fdflags = fcntl(fd, F_GETFL, 0)) == -1) return -1; fdflags &= ~O_NONBLOCK; if (fcntl(fd, F_SETFL, fdflags) == -1) return -1; return 0; }
If successful, setblock returns 0. If unsuccessful, setblock returns 1 and sets errno.Example 4.39 process_or_do_work.c The following function assumes that fd1 and fd2 are open for reading in nonblocking mode. If input is available from either one, the function calls docommand with the data read. Otherwise, the code calls dosomething. This implementation gives priority to fd1 and always handles input from this file descriptor before handling fd2. #include <errno.h> #include <unistd.h> #include "restart.h" void docommand(char *, int); void dosomething(void); void process_or_do_work(int fd1, int fd2) { char buf[1024]; ssize_t bytesread; for ( ; ; ) { bytesread = r_read(fd1, buf, sizeof(buf)); if ((bytesread == -1) && (errno != EAGAIN)) return; /* a real error on fd1 */ else if (bytesread > 0) { docommand(buf, bytesread); continue; } bytesread = r_read(fd2, buf, sizeof(buf)); if ((bytesread == -1) && (errno != EAGAIN)) return; /* a real error on fd2 */ else if (bytesread > 0) docommand(buf, bytesread); else dosomething(); /* input not available, do something else */ } }
|