Applying C - File Descriptors
Written by Harry Fairhead   
Monday, 24 August 2020
Article Index
Applying C - File Descriptors
Permissions & Random Access
fcntl
The Reader

To test this we need a simple reader which follows the same general pattern as the writer:

#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <unistd.h>
int main(int argc, char** argv) {
    struct flock lockread={0};
    lockread.l_type = F_RDLCK;
    lockread.l_whence = SEEK_SET;
    lockread.l_start = 10;
    lockread.l_len = 4;
    int value=0;
   
    int fd = open("/tmp/fd.txt", O_RDWR , 0600);
    for (;;) {
        lseek(fd, 10, SEEK_SET);
        
        lockread.l_type = F_RDLCK;
        fcntl(fd, F_SETLKW, &lockread);
       
        read(fd, &value, 4);
        lockread.l_type = F_UNLCK;
        fcntl(fd, F_SETLK, &lockread);
                
        if((value!=0x55555555) && (value!=~0x55555555)){
            printf("%x\n", value);
        }
        fflush(stdout);
    }
    close(fd);
}

In this case the process attempts to gain a read lock and then reads the value from the same four bytes that the writer process writes to. The call to fcntl is blocking, so if the read lock cannot be acquired the process waits. After reading the value we test to make sure that it is one of the two possible values that the writer process writes to the file.

If you compile both programs and run them you will see no errors printed. The reason is that the reading program cannot read the four bytes while the writing programming is updating the value and the writing program cannot write to the four bytes while the reading program is reading a value.

This use of locks may sound unnecessary, but if you remove the call to fcntl to acquire the lock in the writing program you will soon see that it is very necessary.

You will see values such as:

555aaaaa
555555aa
aaaa5555
555555aa
aaaa5555

These result when the writing program is in the middle of changing the value while the reading program is in the middle of reading the value.

Notice that the locks are per process and any threads within the process share the same set of locks. This also means that if a process closes a file then all of its locks are released, even if it still has other file descriptors open on the same file. In particular, if a library function opens and then closes the same file then all the locks are lost.

The fact that all the threads in a process share the same set of locks imposes some restrictions on what you can achieve. For example, if a single thread acts as the writer program, then with a other threads acting as readers, everything works. Either the process has a read lock or it has a write lock and only the writer or one of the reader thread can access the file. Where things go wrong is if two threads try to write to the same area of the file. In this case the process will have a write lock on the region and both threads will attempt to write at the same time. Put simply, you cannot stop multiple threads modifying the same region of the file at the same time.

If you need to use locks with threads and you want to protect your program from a loss of locks if a file is closed, you need to use open file description locks. This is a Linux-only facility; to use it you simply change the commands used in the fcntl call:

F_OFD_SETLK - acquire or release lock non-blocking

F_OFD_SETLKW - as F_OFD_SETLK but blocking, returns -1 if interrupted

F_OFD_GETLK - test to see if there is a lock of the type specified.

In the remainder of the chapter but not in this extract

  • Pipes
  • A Named Pipe Example
  • Anonymous Pipes
  • An Anonymous Pipe Example
  • File & Directory Operations
  • ioctl

Summary

  • If you think of a file as just a sequence or stream of bytes that can be read or written, then you have an idea that fits a great many sources and sinks of data.

  • This idea is so powerful that under Linux/Unix you can view almost all data as an example of a file.

  • C has a standard way of working with files – streams – and it provides a range of functions for working with file pointers such as fopen and fclose.

  • C files are buffered and this can cause unexpected behavior. Use fflush to make sure that buffers are written out.

  • Although not part of the C standard, file descriptors are part of Linux- and POSIX-compliant operating systems. They provide a lower-level, but OS-dependent, way of working with files.

  • File descriptor functions are similar to C file functions, but they don’t start with f and are simply open, close, read, write, and so on.

  • As C files are actually opened as file descriptors under POSIX operating systems, you can find the descriptor corresponding to a stream using fileno.

  • Files can be shared between processes.

  • The state of Linux/Unix file locking is not good, but you can lock a range of bytes within a file as long as you are aware of the problems.

  • A pipe is like a shared file but stored in memory. There are named and anonymous pipes.

  • There are a range of file and directory manipulation commands that allow you to do things like rename files.

 

 

Now available as a paperback or ebook from Amazon.

Applying C For The IoT With Linux

  1. C,IoT, POSIX & LINUX
  2. Kernel Mode, User Mode & Syscall
  3. Execution, Permissions & Systemd
    Extract Running Programs With Systemd
  4. Signals & Exceptions
    Extract  Signals
  5. Integer Arithmetic
    Extract: Basic Arithmetic As Bit Operations
  6. Fixed Point
    Extract: Simple Fixed Point Arithmetic
  7. Floating Point
  8. File Descriptors
    Extract: Simple File Descriptors 
    Extract: Pipes 
  9. The Pseudo-File System
    Extract: The Pseudo File System
    Extract: Memory Mapped Files ***NEW
  10. Graphics
    Extract: framebuffer
  11. Sockets
    Extract: Sockets The Client
    Extract: Socket Server
  12. Threading
    Extract:  Pthreads
    Extract:  Condition Variables
    Extract:  Deadline Scheduling
  13. Cores Atomics & Memory Management
    Extract: Applying C - Cores 
  14. Interupts & Polling
    Extract: Interrupts & Polling 
  15. Assembler
    Extract: Assembler

Also see the companion book: Fundamental C

<ASIN:1871962609>

<ASIN:1871962463>

<ASIN:1871962617>

<ASIN:1871962455>

Related Articles

Remote C/C++ Development With NetBeans

Raspberry Pi And The IoT In C

Getting Started With C/C++ On The Micro:bit

To be informed about new articles on I Programmer, sign up for our weekly newsletter, subscribe to the RSS feed and follow us on Twitter, Facebook or Linkedin.

Banner


Falco On Track To Version 1.0.0
02/04/2024

Falco is a cloud native runtime security tool for the Linux operating system, designed to detect abnormal behavior and warn of potential security threats in real-time. Now it's about to release its fi [ ... ]



Deno Improves JSR Support
08/04/2024

Deno has been updated to improve JSR support, and to build on the Temporal API introduced in version 1.4.  Deno is the JavaScript and TypeScript runtime from the creator of Node.js.


More News

raspberry pi books

 

Comments




or email your comment to: comments@i-programmer.info



Last Updated ( Monday, 24 August 2020 )