Blog literacki, portal erotyczny - seks i humor nie z tej ziemi




1.7 Funkcje systemowe zwiazane z czasem

Spis tresci


    ll

    l: l


      ll

      ll

      ll

      ll

      ll

      l l


    ll


      ll

      ll

      ll

      ll

      ll


    l:l


      ll

      ll

      ll

      ll

      ll

      ll

      l l


    ll

    ll






Typy danych zwiazane z czasem

Oprocz standardowych typow danych beda nam potrzebne:



typedef long time_t

Czas mierzony w sekundach. Logiczniej byloby zdefiniowac go
jako unsigned long, uniemozliwiloby to ustawianie zlych wartosci i
rozszerzyloby dostepny zakres. Byc moze autorom chodzilo o mozliwosc
reprezentacji czasow sprzed 1 stycznia 1970 ? (patrz dalej)

typedef long clock_t

Czas mierzony w okresach przerwania zegarowego. Poniewaz "okres
przerwania zegarowego" to troche dluga nazwa, odtad bedziemy mowic
"takt zegara" lub po prostu "takt" (ang. tick).
Konwersja z taktow na czas rzeczywisty: zazwyczaj dlugosc jednego
okresu jest rowna 10 ms (1 / HZ), ale teoretycznie mozliwa jest jej modyfikacja
(zmienna tick i funkcja adjtimex()). Rowniez tutaj
chyba lepiej byloby uzyc unsigned long. Uwaga: liczba taktow
nie zawsze jest rowna ilosci obsluzonych przerwan zegarowych - czasami
z jakis powodow nalezy odlozyc obsluge przerwania i wtedy jadro moze wywolac
jedna procedure obslugi dla kilku zaleglych przerwan zegarowych. Wiecej
na ten temat powinno byc na stronie o przerwaniach
(1.6).

Uwaga: wymienione wyzej typy sa stosowane raczej sporadycznie i podane
wyzej opisy mozna stosowac tylko w jedna strone, tzn. jezeli zmienna jest
typu clock_t, to reprezentuje ilosc taktow, ale z faktu ze zmienna reprezentuje
ilosc taktow nie wynika, ze musi byc ona typu clock_t (np. zmienna
jiffies jest typu unsigned long, ale funkcja times()
zwraca ja juz jako clock_t).






Struktury danych zwiazane z czasem

Przy opisie struktur przyjeto nastepujaca zasade: jezeli struktura wystepuje
jako typ ktorejs ze zmiennych jadra, lub jako pole innej struktury spelniajacej
ten warunek, opisujemy znaczenie pol. Jezeli struktura wystepuje jedynie
w interfejsie funkcji systemowych (struktury tms i timex),
podajemy tylko jej definicje i odnosnik do miejsca zawierajacego opis odpowiadajacych
jej polom zmiennych.



timeval

(plik include/linux/time.h)



struct timeval {
long tv_sec; /* sekundy */
long tv_usec; /* mikrosekundy */
};




timespec

(plik include/linux/time.h)



struct timespec {
long tv_sec; /* sekundy */
long tv_nsec; /* nanosekundy */
};

Struktura ta ma w przyszlosci byc wykorzystywana przez procesy czasu
rzeczywistego, potrzebujace bardzo precyzyjnego okreslenia czasu. W wersji 2.0
Linuxa zaimplementowane zostaly jedynie funkcje konwersji z timespec
na clock_t (timespectojiffies()) i z powrotem
(jiffiestotimespec()), oraz funkcja sys_nanosleep(),
pozwalajaca procesom czasu rzeczywistego zasnac na krotki okres czasu (co
najwyzej 2ms, czyli 2000000ns) z duza dokladnoscia, bez zwalniania procesora
(nie nastepuje zmiana kontekstu i nie trzeba czekac na wywlaszczenie nowego
uzytkownika). Ze wzgledu na nikle (na razie) znaczenie praktyczne, nie
bedziemy ich tutaj omawiac







timezone

(plik include/linux/time.h)



struct timezone {
int tz_minuteswest;
int tz_dsttime;
};

Struktura ta okresla strefe czasowa. Znaczenie pol:




tz_minuteswest

Przesuniecie czasowe na zachod od Greenwich, mierzone w minutach.

tz_dsttime

DST = Daily Saving Time = czas letni. Pole to okresla tryb zmiany czasu
z letniego na zimowy.




task_struct

(plik include/linux/sched.h)



Struktura ta opisuje proces (patrz ).
Z jej pol wymienimy tylko piec, bezposrednio zwiazane z czasem:



struct task_struct {
/* ... */
long utime, stime, cutime, cstime, start_time;
/* ... */

};

utime

Czas CPU wykorzystany przez proces w trybie uzytkownika.

stime

Czas CPU wykorzystany przez proces w trybie jadra (systemowym).

cutime

Czas CPU wykorzystany przez potomkow procesu w trybie uzytkownika.
Uwaga: czasy potomkow zbierane sa przez proces macierzysty dopiero po wykonaniu
funkcji wait() lub podobnej. Tak wiec w rzeczywistosci nie jest
to "sumaryczny czas potomkow", lecz "sumaryczny czas potomkow
ktorzy zakonczyli prace" (i nie istnieja nawet w stanie TASK_ZOMBIE)
.

cstime

Czas CPU wykorzystany przez potomkow procesu w trybie systemowym. Uwaga
jak wyzej.

start_time

Czas rozpoczecia wykonywania procesu (mierzony od zaladowania systemu).

Wszystkie czasy podane sa w taktach (okresach) zegara, by uproscic
obsluge tych zmiennych: podczas przerwania zegarowego jadro po prostu sprawdza,
ktory proces sie aktualnie wykonywal i w jakim trybie, a nastepnie zwieksza
odpowiednie pole o 1 (to stwierdzenie nie jest do konca scisle - patrz
uwaga przy opisie typu clock_t).





tms

(plik include/linux/times.h)



struct tms {
clock_t tms_utime;
clock_t tms_stime;
clock_t tms_cutime;
clock_t tms_cstime;
};

Struktura ta wystepuje jako interfejs funkcji .
Znaczenie pol - patrz opis .





timex

(plik include/linux/timex.h)



struct timex {
unsigned int modes; /* tablica bitowa modyfikacji */
long offset; /* roznica faz [us] */
long freq; /* roznica czestotliwosci [ppm] */
long maxerror; /* maksymalny blad [us] */
long esterror; /* szacowany blad [us] */
int status; /* status synchronizacji */
long constant; /* stala pll */
long precision; /* (RO) dokladnosc zegara [us] */
long tolerance; /* (RO) stand odchyl czestotliwosci [ppm] */
struct timeval time; /* (RO) aktualny czas */
long tick; /* dlugosc taktu [us] */
long ppsfreq; /* (RO) (pps) czestotliwosc sygnalu */
long jitter; /* (RO) (pps) ? */
int shift; /* (RO) (pps) ? */
long stabil; /* (RO) (pps) stabilnosc sygnalu [ppm] */
long jitcnt; /* (RO) (pps) ? */
long calcnt; /* (RO) (pps) czas kalibrowania */
long errcnt; /* (RO) (pps) blad kalibrowania */
long stbcnt; /* (RO) (pps) odchylenia anormalne */
int :32; int :32; int :32; int :32;
int :32; int :32; int :32; int :32;
int :32; int :32; int :32; int :32;
};


Struktura ta jest wykorzystywana w interfejsie funkcji ,
sluzacej do synchronizacji zegara z zegarem zewnetrznym. Wszystkie pola,
z wyjatkiem modes, maja swoje odpowiedniki w zmiennych jadra,
najwazniejsze sa omowione w rozdziale Zmienne -
synchronizacja z zegarem zewnetrznym. Pola z komentarzem (RO)
sa przeznaczone tylko do odczytu (Read Only), pola z komentarzem (pps)
sa wykorzystywane tylko wtedy, gdy do synchronizacji uzywamy urzadzenia
generujacego sygnal PPS.




modes

Tablica bitowa okreslajace ktore z pol chcemy modyfikowac. Tylko superuser
ma prawo modyfikowac jakiekolwiek pola, i nawet on nie moze modyfikowac
wszystkich. Pola niemodyfikowalne sa zaznaczone wyzej jako (RO).
Dopuszczalne modyfikacje:

#define ADJ_OFFSET 0x0001 /* roznica faz */
#define ADJ_FREQUENCY 0x0002 /* roznica czestotliwosci */
#define ADJ_MAXERROR 0x0004 /* maksymalny blad */
#define ADJ_ESTERROR 0x0008 /* szacowany blad */
#define ADJ_STATUS 0x0010 /* status synchronizacji */
#define ADJ_TIMECONST 0x0020 /* stala PLL */
#define ADJ_TICK 0x4000 /* dlugosc taktu */
#define ADJ_OFFSET_SINGLESHOT 0x8001 /* dozwolona roznica faz *
* wieksza niz pol sekundy */


Dodatkowe ograniczenia




    lPole tick mozna modyfikowac co najwyzej o 10% wzgledem wartosci
    standardowej (jadro zaklada, ze jezeli jego sekunda i sekunda zegara zewnetrznego
    roznia sie o wiecej niz 10%, to cos jest bardzo nie w porzadku i precyzyjna
    synchronizacja jest w ogole bez sensu). Proba przekroczenia tego limitu
    powoduje blad EINVAL.l


    lPole offset jest ograniczone przez wartosc stalej MAXPHASE.
    Jezeli podamy wartosc spoza zakresu -MAXPHASE<offset<+MAXPHASE,
    i w polu modes nie zaznaczymy ADJ_OFFSET_SINGLESHOT,
    to rowniez wystapi blad EINVAL.l










Wybrane zmienne i stale jadra



Przerwanie zegarowe

#define HZ 100

Czestotliwosc przerwania zegarowego w herzach.

long tick = 1000000 / HZ;

Dlugosc taktu, czyli okresu przerwania zegarowego w mikrosekundach.
Standartowo rowny 10000 us = 10 ms, moze byc nieznacznie modyfikowany funkcja
adjtimex().



Aktualny czas


volatile struct timeval xtime;

Aktualny czas z dokladnoscia do mikrosekundy, znaczenie pol - patrz
opis struktury timeval. Jest to tak zwany czas uniwersalny (UTC = Coordinated
Universal Time) - czas ktory minal od polnocy (00:00) 1 stycznia 1970 roku
czasu GMT. Konwersja do czasu lokalnego i ewentualna zmiana z zimowego
na letni dokonywana jest juz na poziomie funkcji uzytkownika, jadro zawsze
pracuje w czasie uniwersalnym.

unsigned long volatile jiffies = 0;

Czas od momentu zaladowania systemu w taktach zegara.

#define CURRENT_TIME (xtime.tv_sec)

Czas UTC z dokladnoscia do sekundy (makro uzywane miedzy innymi przez
funkcje time()).




Strefa czasowa


struct timezone sys_tz = { 0, 0};

Strefa czasowa w ktorej unieszczony jest system, znaczenie pol - patrz
opis struktury timezone. Standartowo czas zimowy Greenwich, moze byc modyfikowany
funkcja settimeofday(). W zasadzie zmienna ta nie jest wykorzystywana
przez jadro - jest to tylko informacja dla uzytkownika; wyjatek zostanie
opisany przy okazji funkcji settimeofday().




Zuzycie CPU

struct task_struct task[NR_TASKS];

Tablica procesow. Zawiera miedzy innymi zuzycie czasu CPU przez poszczegolne
procesy - patrz opis struktury
i funkcji .



Synchronizacja z zegarem zewnetrznym

Jezeli dysponujemy zegarem zewnetrznym, mozemy, za pomoca funkcji adjtimex(),
sprobowac zsynchronizowac z nim nasz zegar wewnetrzny. Zegary uwazamy za
zsynchronizowane, gdy "wybijaja" sekundy jednoczesnie (oczywiscie
z pewna ustalona tolerancja). Niestety, sprawna synchronizacja wymaga duzej
ilosci dodatkowych zmiennych i dosyc skomplikowanego algorytmu (autorstwa
Davida Mills'a). Ze wzgledu na znaczna objetosc, ograniczymy sie tutaj
do pobieznego omowienia wybranych zmiennych:



int time_state = TIME_ERROR;

Status synchronizacji. Gdy nie ma z czym synchronizowac, lub zegar
jest rozstrojony, time_state = TIME_ERROR (lub TIME_BAD
w starszych wersjach). Gdy jest synchronizowany, time_state = TIME_OK.
Pozostale wartosci dotycza sytuacji zwiazanych z wstawianiem / usuwaniem
dodatkowej sekundy.

int time_status = STA_UNSYNC;

Tablica bitowa zawierajaca dodatkowe informacje na temat statusu,
oraz polecenia dla zegara. Wybrane bity z tej tablicy (oznaczone RO) dotycza
statusu sprzetu i przeznaczone sa tylko do czytania):

#define STA_INS 0x0010 /* wstaw dodatkowa sekunde */
#define STA_DEL 0x0020 /* pomin jedna sekunde */
#define STA_UNSYNC 0x0040 /* zegar nie jest synchronizowany */
#define STA_PPSSIGNAL 0x0100 /* (RO) dostepny jest sygnal PPS */
#define STA_CLOCKERR 0x1000 /* (RO) wystapil sprzetowy blad zegara */


long time_precision = 1;

Dokladnosc zegara (w mikrosekundach).

#define MAXPHASE 512000L

Maksymalna roznica w fazie pomiedzy zegarami, rowna 512000us, czyli
w przyblizeniu pol sekundy.

long time_offset = 0;

Aktualne przesuniecie w fazie wzgledem zegara zewnetrznego (w mikrosekundach).
Jadro bedzie staralo sie uzgodnic fazy, przesuwajac kolejne przerwania
zegarowe o niewielka wartosci (time_adjust_step), odpowiednio
zmniejszajac wartosc time_offset. Z oczywistych wzgledow ograniczone
przez MAXPHASE: -MAXPHASE<time_offset<+MAXPHASE

int tickadj = 500/HZ;

Gorne ograniczenie na wartosc time_adjust_step (patrz nizej).
W sytuacji normalnej (tick = 1000000/HZ), oznacza to roznice pomiedzy
kolejnymi okresami nie wieksze niz 1%.

long time_adjust_step = 0;

Dokonywana przez jadro, wyliczana na nowo przy kazdym przerwaniu, modyfikacja
dlugosci taktu (w mikrosekundach). Uwaga: nie nalezy jej mylic z mozliwoscia
zewnetrzej modyfikacji dlugosci taktu (wartosci zmiennej tick).
Pierwsza jest stosowana, gdy nalezy uzgodnic czestotliwosci zegarow, druga
- gdy oba zegary juz pracuja z mniej wiecej ta sama czestotliwoscia, ale
nalezy jeszcze uzgodnic fazy (time_offset). Tak wiec w rzeczywistosci
dlugosc taktu wynosi tick+time_adjust_step.

long time_tolerance = MAXFREQ;

Tolerancja (maksymalne odchylenie) od sredniej czestotliwosci zegara
wewnetrznego wyrazona w ppm (parts per milion; 1ppm = 0.0001%).

long time_freq = 0;

Roznica czestotliwosci pomiedzy zegarami (w ppm).

long esterror = MAXPHASE;

Szacowane odchylenie wartosci time_offset od rzeczywistej
roznicy faz.

long maxerror = MAXPHASE;

Maksymalne odchylenie wartosci time_offset od rzeczywistej
roznicy faz.

To nie wszystko: do synchronizacji mozemy uzyc rowniez podlaczanego
przez zlacze RS232 urzadzenia generujacego sygnal PPS (pulse-per-second).
Zmienne zwiazane z jego obsluga latwo rozpoznac - poprzedzone sa prefiksem
pps_.



Patrz takze: oraz opis funkcji
.








Funkcje systemowe

Algorytmy ponizej opisanych funkcji sa raczej trywialne - zazwyczaj
ograniczaja sie do odczytania / zapisania wartosci odpowiednich zmiennych.
Osoby zainteresowane implementacja tych funkcji zapraszamy do skorzystania
z odpowiednich odnosnikow do kodu. Czytajac kod zrodlowy warto wiedziec,
ze:




    lverify_area() - to funkcja sprawdzajaca czy wywolujacy
    funkcje ma prawo odczytu (VERIFY_READ) lub zapisu (VERIFY_WRITE)
    we wskazanym obszarze. Oczywiscie, funkcja ta nie sprawdza czy proces wlasciwie
    zaalokowal ten obszar.l


    lcli() i sti() - to funkcje odpowiednio
    blokujace i odblokowywujace przerwania. Warto zauwazyc, ze zawsze gdy funkcja
    modyfikuje jednoczesnie pare zmiennych zwiazanych z czasem, wylacza przerwania
    - gdyby w trakcie modyfikacji nadeszlo np. przerwanie zegarowe, moglo by
    to prowadzic do niepozadanych efektow.l







Funkcja

- odczytanie aktualnego czasu systemowego (z dokladnoscia do 1 sekundy).



DEFINICJA: time_t time(int *tloc)
WYNIK: aktualny czas mierzony w sekundach od 00:00 1.01.1970 UTC

Funkcja odczytuje zawartosc zmiennej xtime.tv_sec, wykorzystujac
makro CURRENT, i zwraca ja jako wynik. Dodatkowo, jezeli tloc
!= NULL, probuje ja zapisac pod wskazywany adres.



Funkcja

- ustawienie aktualnego czasu systemowego (z dokladnoscia do 1 sekundy).



DEFINICJA: int stime(int * tptr)
WYNIK: 0 w przypadku sukcesu
-1, gdy blad: errno = EPERM (wywolujacy nie jest superuserem)

Funkcja sprawdza czy wywolujacy funkcje jest superuserem (tylko on ma
prawo modyfikacji czasu systemowego), nastepnie z wylaczonymi przerwaniami
modyfikuje odpowiednie zmienne:



xtime.tv_sec = value; /* wartosc wskazywana przez tptr */
xtime.tv_usec = 0;
time_state = TIME_ERROR;
time_maxerror = MAXPHASE;
time_esterror = MAXPHASE;

Po takiej ingerencji, system uwaza zegar za rozstrojony (TIME_ERROR).







Funkcja

- odczytanie aktualnego czasu i strefy czasowej



DEFINICJA: int gettimeofday(struct timeval * tv, struct timezone * tz)
WYNIK: 0

Dzialanie:



if(tv != NULL)
skopiuj zawartosc zmiennej xtime
pod adres wskazywany przez tv;
if(tz != NULL)
skopiuj zawartosc zmiennej sys_tz
pod adres wskazywany przez tz;






Funkcja

- ustawienie aktualnego czasu i strefy czasowej



DEFINICJA: int settimeofday(struct timeval * tv, struct timezone * tz)
WYNIK: 0 w przypadku sukcesu
-1, gdy blad: errno = EPERM (wywolujacy nie jest superuserem)

Dzialanie:



static int firsttime = 1;
if(wywolujacy nie jest superuserem)
zwroc blad EPERM;
if(tv != NULL)
skopiuj zawartosc struktury wskazywanej przez tv
na zmienna xtime;
if(tz != NULL)
{
skopiuj zawartosc struktury wskazywanej przez tz
na zmienna sys_tz;
if(firsttime)
{
firsttime = 0;
if(tv == NULL)
{
zablokuj przerwania;
xtime.tv_sec += sys_tz.tz_minuteswest * 60;
odblokuj przerwania;
}
}
}


Od dzialania oczywistego widzimy tutaj jeden wyjatek. Jezeli przy pierwszym
ustawianiu strefy czasowej po zaladowaniu systemu nie podamy aktualnego
czasu, jadro interpretuje to nastepujaco: do tej pory zegar chodzil w czasie
lokalnym, i nalezy go niezwlocznie przestawic na UTC. Jest to zreszta jedyna
sytuacja w ktorej strefa czasowa ma jakikolwiek wplyw na dzialanie lub
zmienne jadra.





Funkcja

- odczytanie lub ustawienie parametrow synchronizacji z zegarem zewnetrznym



DEFINICJA: int adjtimex(struct timex * buf)
WYNIK: status synchronizacji w przypadku sukcesu
TIME_OK - zegar jest synchronizowany
TIME_ERROR - zegar nie jest synchronizowany
-1, gdy blad: errno = EPERM (tylko superuser moze modyfikowac)
EINVAL (niedozwolona wartosc jednego z pol)


Funkcja modyfikuje wskazane przez pole buf->modes zmienne
na wartosci okreslone przez odpowiednie pola. Po dokonaniu wszystkich modyfikacji
funkcja uaktualnia zawartosc struktury wskazywanej przez buf,
i zwraca status synchronizacji. Kliknij ,
by obejrzec zawartosc struktury timex i dopuszczane modyfikacje,
oraz , by poczytac wiecej o synchronizacji.






Funkcja

- odczytanie danych o zuzyciu czasu procesora przez proces i jego potomkow




DEFINICJA: clock_t times(struct tms * tbuf)
WYNIK: liczba taktow od momentu zaladowania systemu

Funkcja kopiuje zawartosc odpowiednich pol struktury task_struct,
wskazywanej przez wskaznik current (aktualnie wykonujacy sie proces)
pod adres wskazywany przez tms. Patrz opis struktur
i . Jako
wynik zwraca zawartosc zmiennej jiffies, czyli czas od momentu
zaladowania systemu mierzony w taktach zegara.





Funkcja

- ustawienie (i/lub ew. wylaczenie) sygnalu pobudki.



DEFINICJA: unsigned int alarm(unsigned int seconds)
WYNIK: liczba sekund pozostala do wywolania poprzedniego alarmu
0, gdy nie bylo takowego

Efektem wywolania tej funkcji jest:




    lWylaczenie poprzedniego alarmu. Czas pozostaly do jego wywolania, zaokraglony
    w gore do pelnych sekund zostanie zwrocony jako wynik funkcji (w gore, by
    odroznic przypadek, gdy do wywolania alarmu zostalo mniej niz sekunda, od
    przypadku gdy alarmu w ogole nie bylo).l


    lJezeli seconds>0, ustawienie nowego alarmu. Po uplywie
    odpowiedniej ilosci sekund, jadro wysyla do procesu sygnal pobudki (SIGALRM).
    Jak taki sygnal przechwycic i wykorzystac ? Zapraszamy do tematu 1.5... l






Kody zrodlowe programow demonstracyjnych

Teksty trzech prostych programow w C demonstrujacych
dzialanie funkcji i pozwalajacych na obejrzenie aktualnego stanu
odpowiednich zmiennych jadra:



ll
ll
ll

Uwaga: kompilujac times.c zmien nazwe, lub wywoluj program
wynikowy przez ./times, istnieje bowiem rowniez polecenie shella o
tej samej nazwie.








Bibliografia


lPliki zrodlowe Linuxa: l


    l
    (definicje stalych, struktur i makr)l


    l
    l


    ll

    ll

    l
    (czestotliwosc pracy zegara)l


    l (implementacja
    funkcji alarm(), inicjacja wiekszosci zmiennych) l


    l (implementacja
    funkcji times())l


    l (implementacje
    pozostalych funkcji systemowych)l







Autor: Aleksander Buczynski


  • zanotowane.pl
  • doc.pisz.pl
  • pdf.pisz.pl
  • qualintaka.pev.pl
  •