Atomicidad de `write (2)` a un sistema de archivos local

Aparentemente POSIX dice que

Un descriptor de archivo o una secuencia se llama un "identificador" en la descripción de archivo abierto a la que hace referencia; Una descripción de archivo abierto puede tener varios manejadores. [...] Toda la actividad de la aplicación que afecte al desplazamiento de archivo en el primer identificador se suspenderá hasta que se convierta nuevamente en el identificador de archivo activo. [...] Los manejadores no necesitan estar en el mismo proceso para que estas reglas se apliquen. -POSIX.1-2008

y

Si dos hilos en cada llamada [la función write ()], cada llamada verá todos los efectos especificados de la otra llamada, o ninguno de ellos. -POSIX.1-2008

Mi entendimiento de esto es que cuando el primer proceso emite unwrite(handle, data1, size1) y los problemas del segundo procesowrite(handle, data2, size2), las escrituras pueden ocurrir en cualquier orden pero ladata1 ydata2 debe ser prístino y contiguo.

Pero ejecutar el siguiente código me da resultados inesperados.

#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/wait.h>
die(char *s)
{
  perror(s);
  abort();
}

main()
{
  unsigned char buffer[3];
  char *filename = "/tmp/atomic-write.log";
  int fd, i, j;
  pid_t pid;
  unlink(filename);
  /* XXX Adding O_APPEND to the flags cures it. Why? */
  fd = open(filename, O_CREAT|O_WRONLY/*|O_APPEND*/, 0644);
  if (fd < 0)
    die("open failed");
  for (i = 0; i < 10; i++) {
    pid = fork();
    if (pid < 0)
      die("fork failed");
    else if (! pid) {
      j = 3 + i % (sizeof(buffer) - 2);
      memset(buffer, i % 26 + 'A', sizeof(buffer));
      buffer[0] = '-';
      buffer[j - 1] = '\n';
      for (i = 0; i < 1000; i++)
        if (write(fd, buffer, j) != j)
          die("write failed");
      exit(0);
    }
  }
  while (wait(NULL) != -1)
    /* NOOP */;
  exit(0);
}

Intenté ejecutar esto en Linux y Mac OS X 10.7.4 y usargrep -a '^[^-]\|^..*-' /tmp/atomic-write.log muestra que algunas escrituras no son contiguas o se superponen (Linux) o simplemente están dañadas (Mac OS X).

Añadiendo la banderaO_APPEND en elopen(2) llamada arregla este problema. Bien, pero no entiendo por qué. POSIX dice

O_APPEND Si se establece, el desplazamiento del archivo se establecerá al final del archivo antes de cada escritura.

Pero este no es el problema aquí. Mi programa de muestra nunca lo hacelseek(2) pero comparte la misma descripción de archivo y por lo tanto el mismo desplazamiento de archivo.

Ya he leído preguntas similares en Stackoverflow pero todavía no responden completamente mi pregunta.

Escritura atómica en archivo de dos procesos. No aborda específicamente el caso donde los procesos comparten el mismo.Descripción del archivo (A diferencia del mismo archivo).

¿Cómo se determina mediante programación si la llamada al sistema de "escritura" es atómica en un archivo en particular? dice que

loswrite La llamada como se define en POSIX no tiene ninguna garantía de atomicidad.

Pero comoantes citada tiene algunos Y lo que es más,O_APPEND parece activar esta garantía de atomicidad, aunque me parece que esta garantía debería estar presente incluso sinO_APPEND.

¿Puedes explicar más este comportamiento?

Respuestas a la pregunta(4)

Su respuesta a la pregunta