FLOCK

The FLOCK function allows a file to be locked, preventing other processes or tests from reading or writing to it. This allows a file to be safely manipulated without interference from other concurrent operations. These concurrent operations might be in any of the following contexts:

  • A process on the same machine
  • A process on a different machine when the file is on a network share
  • Tests running on a different board in another tab in XJRunner
  • A different file handle open in the same test

There are two types of locks:

Read or Shared lock
A read lock means that the holder of the lock, or any other process that has the file open, can only read from the file. Any attempt to write to the file will fail and the FERROR flag will be set. Any number of read locks may be held for a particular file, hence the term shared lock.
Write or Exclusive lock
Only one write lock may be held for a particular file at any one time. The holder of the lock may both read and write to the file. Any other read or write with that file will fail.

A file is unlocked with the FUNLOCK function.

Syntax

FLOCK( FILE fileHandle, INT mode )

Parameters

fileHandle
An open file handle to the file to be locked. There are no restrictions on the mode with which the file was opened.
mode
The type of lock to take: it must be either 0 for a read/shared lock, or 1 for a write/exclusive lock.

Return value

An INT value specifying whether the file was locked successfully or not; 0 indicates that the file was locked, 1 indicates that the file is already locked.

Errors

A run-time error can occur when locking a file in the following circumstances:

  • The file has already been locked via the same file handle.
  • The file is inside an XJPack file.

Example

The following example shows how one might increment a serial number stored in a file atomically:

GLOBAL NEW_SERIAL_NUMBER()(INT failed)
  INT serial WIDTH 32;
  FILE fileHandle;
  INT result;

  failed := FALSE;

  // Open the file
  fileHandle := FOPEN("CurrentSerialNumber.txt", "r+");
  IF FERROR() THEN
    PRINT("Error opening CurrentSerialNumber.txt\n");
    failed := TRUE;
    RETURN;
  END;

  // Wait for the lock to become available.
  DO
    result := FLOCK(fileHandle, 1);
  WHILE result != 0
  END;

  // Read the previous serial number (serial numbers are 32 bits).
  serial := FGETI(fileHandle, 32);

  // Increment the serial number.
  serial := serial + 1;
  SERIAL_NUMBER := FORMAT(serial, "%i");

  // Return to the beginning of the file and write out the new serial number.
  FSEEK(fileHandle, 0, 0);

  FWRITE(fileHandle, serial);
  IF FERROR(fileHandle) THEN
    PRINT("Error writing to CurrentSerialNumber.txt\n");
    failed := TRUE;
    RETURN;
  END;

  FUNLOCK(fileHandle);
  FCLOSE(fileHandle);
END;