Do spisu tresci tematu 6

6.4.3 Funkcja systemowa flock()



Spis tresci


Opis funkcji flock()

Funkcja flock() udostepnia programiscie dostep do drugiego rodzaju blokady pliku. W Linuxie blokada ta jest umownie nazywana FLOCK (od nazwy funkcji systemowej). Blokady zakladane sa na caly plik, a nie na rekord jak w przypadku blokad typu POSIX.
Definicja funcji znajduje sie w pliku fs/locks.c i ma postac:

int flock(
    unsigned int fd    /* deskryptor pliku */
    unsigned int cmd   /* komenda */); 

W pliku include/asm/fcntl.h znajduja sie definicje komend:
#define LOCK_SH		1	/* blokada dzielona */
#define LOCK_EX		2	/* blokada wylaczna */
#define LOCK_NB		4	/* nie usypiaj w czasie blokowania */
#define LOCK_UN		8	/* usuwanie blokady */

Plik nie moze miec jednoczesnie blokad typu dzielonego i wylacznego. Blokada wylaczna moze byc tylko jedna na jednym pliku, a blokad dzielonych moze byc wiecej. Najczesciej blokady dzielonej uzywa sie przy czytaniu a wylacznej przy pisaniu do pliku. Funkcja zwraca 0, jesli zakonczyla sie sukcesem lub ujemna wartosc bledu. Implementacja blokad FLOCK jest znacznie prostsza niz w przypadku blokad typu POSIX, gdyz nie trzeba sprawdzac wszystkich blokad zalozonych na plik i znajdowac przeciecia z zakladana, a wystarczy sprawdzic pierwsza zalozona blokade, a wszystkie pozostale beda tego samego typu.
A oto wlasciwy algorytm zakladania i zdejmowania blokad FLOCK:
Algorytm flock_lock_file z pliku fs/locks.c
wejscie: flip     strutura file pliku, na ktory zakladamy blokade
         caller   struktura zawierajaca dane o zakladanej blokadzie
         wait     czy dozwolone jest usypianie procesu
wyjscie: o jesli sukces lub kod bledu

if (zalozona blokada typu POSIX)
   return (-EBUSY);
wez pierwsza blokade na plik;
while (sa jeszcze blokady zalozone)
   if (zalozona blokada nalezy do tego samego deskryptora)
      {
      if (zalozona blokada tego samego typu)
         return(0);
      zaznacz,ze zmieniamy typ zalozonej blokady;
      wyjdz z petli while;
      }
if (zmiana typu blokady)
   usun zalozona blokade;
if (polecenie usuniecia blokady)
   return (0);

etykieta repeat:

wez pierwsza blokade zalozona na plik;
if (blokada POSIX)
   return (-EBUSY);
while (sa jeszcze blokady)
   {
   if (zakladana blokada wywoluje konflikt z zalozona)
      {
      if (!wait)
         return (-EAGAIN);
      wstaw blokade na koncu kolejki spiacych na danej blokadzie;
      uspij proces na konfliktowej blokadzie;
      /* tu juz jestesmy obudzeni */
      ubudz inne procesy czekajace na tej samej blokadzie;
      goto repeat
      }
   }
wstaw nowa blokade na kolejke blokad;
return (0);

Nalezy pamietac o tym, ze blokady typu FLOCK sa zwiazane z deskryptorami plikow (ang. flick), czyli blokada jest dziedziczona wraz z deskryptorami po wywolaniu funkcji fork()exec(). Implikacja tego jest niemoznosc wskazania wlasciciela blokady, a wiec nie mozna faktycznie wykryc, czy doszlo do zastoju procesow.


Bibliografia

  1. Pliki zrodlowe Linuxa:
  2. Dokumentacja do linuxa:


Pytania i odpowiedzi

1. W starszych wersjach Linuxa funkcja flock() byla realizowana przez odpowiednie odwolanie do fcntl(). Czy dalej tak jest?
Rzeczywiscie kiedys tak bylo, jednak emulacja blokady pliku za pomoca zablokowania calego pliku jako rekordu prowadzila do niezgodnosci blokad ze specyfikacja. Blokowanie plikow wyspecyfikowane jest przez semantyke 4.4 BSD, a blokowanie rekordow przez semantyke POSIX. W 1995 roku zostaly do Linuxa wprowadzone dwie osobowosci (ang. personalities) blokad. Jednak po pewnym czasie Linus zdecydowal, ze nie bedzie mozliwe zakladanie roznych typow blokad na jeden plik. Ma to zapobiegac powstawaniu zastoju procesow bez mozliwosci wykrycia tej sytuacji.


Autor: Andrzej Boczek