views:

41

answers:

2

At some point during my C programming adventures on Linux, I encountered flags (possibly ioctl/fcntl?), that make reads and writes on a file descriptor uninterruptible.

Unfortunately I cannot recall how to do this, or where I read it. Can anyone shed some light?

Update0

To refine my query, I'm after the same blocking and guarantees that fwrite() and fread() provide, sans userspace buffering.

A: 

Do you wish to disable interrupts while reading/writing, or guarantee that nobody else will read/write the file while you are?

For the second, you can use fcntl()'s F_GETLK, F_SETLK and F_SETLKW to acquire, release and test for record locks respectively. However, since POSIX locks are only advisory, Linux does not enforce them - it's only meaningful between cooperating processes.

The first task involves diving into ring zero and disabling interrupts on your local processor (or all, if you're on an SMP system). Remember to enable them again when you're done!

Michael Foukarakis
The first. I'm aware of the POSIX advisory locks, and also agree that these are not what I'm after.
Matt Joiner
A: 

You can avoid EINTR from read() and write() by ensuring all your signal handlers are installed with the SA_RESTART flag of sigaction().

However this does not protect you from short reads / writes. This is only possible by putting the read() / write() into a loop (it does not require an additional buffer beyond the one that must already be supplied to the read() / write() call.)

Such a loop would look like:

/* If return value is less than `count', then errno == 0 indicates end of file,
 * otherwise errno indicates the error that occurred. */
ssize_t hard_read(int fd, void *buf, size_t count)
{
    ssize_t rv;
    ssize_t total_read = 0;

    while (total_read < count)
    {
        rv = read(fd, (char *)buf + total_read, count - total_read);

        if (rv == 0)
            errno = 0;

        if (rv < 1)
            if (errno == EINTR)
                continue;
            else
                break;

        total_read += rv;
    }

    return rv;
}
caf