import fcntl


def read_lock_file(fd, block=False):
  """
  Locks are bound to processes. A terminated process unlocks. 
  Non-blocking, raises OSError if unable to obtain a lock.

  Note that any closing of a file descriptor for the locked file
  will release locks for all fds. This means you must open the file
  and reuse that FD from start to finish.
  """

  # https://docs.python.org/3/library/fcntl.html
  # "On at least some systems, LOCK_EX can only be used if the file 
  # descriptor refers to a file opened for writing."
  # Locks: LOCK_EX (exclusive), LOCK_SH (shared), LOCK_NB (non-blocking)
  mode = fcntl.LOCK_SH
  if not block:
    mode |= fcntl.LOCK_NB

  fcntl.lockf(fd.fileno(), mode)
  return fd