unix.c

/*
 * plik ma na celu prezentację podstawowych zagadnień z programowania w języku C / C++
 * prezentuje użyteczne funkcje charkterystyczne dla systemów zgodnych  z Unix'em
 *
 */

#include <stdio.h>
#include <signal.h>
#include <fcntl.h>
#include <time.h>

// funkcje obsługi sygnału
void sig_usr(int sig) {
  printf("Otrzymałem sygnał numer: %i\n", sig);
}

void akcja_sygnalu(int sig, siginfo_t *info, void *context) {
  printf("Otrzymałem sygnał numer: %i z kodem %d i wartością %d\n",
    sig, info->si_code, info->si_value.sival_int);
  // si_code okresla powód wysłania sygnału
}

main() {
  printf("Mój PID to %d\n", getpid());
  
  // obsługa sygnałów
  // do zdefiniowania obsługi sygnału - jego przechwycenia służy funkcja
  //signal( numer_sygnału, sposób_obsługi );
  // użytkownik ma do dyspozycji dwa nie zdefiniowane przez system sygnały: SIGUSR1, SIGUSR2
  // może też zmieniać obsługę innych (poza nieprzechwytywalnymi) ...
  
  // aby wysłać sygnał do samego siebie korzystamy z raise( sygnał );
  // co jest równoważne kill( getpid(), sygnał );
  // parę słów o sygnałach zawarłem też w fork.c
  
  // ustawiam prechwycenie sygnalu SIGUSR1 (pełną ich listę wypisuje kill -l)
  // lista z opisami dostepna na http://en.wikipedia.org/wiki/Signal_(computing)#List_of_signals
  signal(SIGUSR1, &sig_usr);
  signal(SIGUSR2, &sig_usr);
  // zamiast wskaźnika do funkcji możemy podac także SIG_IGN albo SIG_DFL
  // co oznacza odpowiednio ignorowanie tego sygnału lub jego domyślną obsługę
  
  
  // możliwe jest też maskowanie sygnałów
  sigset_t maska_sygnalow;
  if (sigemptyset(&maska_sygnalow)) // inicjalizujemy na pustą, na pełną byłoby sigfillset()
    puts("sigemptyset error");
  if (sigaddset(&maska_sygnalow, SIGINT)) // dodajemy sygnał do maski
    puts("sigaddset error");
  // można także usuwać - sigdelset() i sprawdzac czy jest obecny - sigismember()
  if (sigprocmask(SIG_SETMASK, &maska_sygnalow, NULL))
    puts("sigprocmask error");
  // w skutek tego program nie będzie reagował na Ctrl+C
  //
  // oprocz tego sa funckcje API sygnałowgo BSD:
  //  sigvec, sigblock, sigsetmask, siggetmask, sigmask
  
  // dostępny jest także machanizm kolejkowanej obsługi sygnałów
  // w którym także kolejne sygnały tego samego typu w oczekiwaniu
  // na odebranie gromadzone są w kolejce
  struct sigaction akcja_obslugi_sygnalu;
  akcja_obslugi_sygnalu.sa_flags = SA_SIGINFO;
  sigfillset(&akcja_obslugi_sygnalu.sa_mask);
  akcja_obslugi_sygnalu.sa_sigaction = &akcja_sygnalu;
  sigaction(SIGALRM, &akcja_obslugi_sygnalu, NULL);
  
  sigqueue(getpid(), SIGALRM, (const union sigval)123); 
  
  
  // możliwe jest także oczekiwanie na dowolny sygnał:
  puts("czekam na sygnal");
  pause();
  
  // lub na sygnał z zestawu okreslonego w taki sposób jak dla 
  // poprze sigwait(&zestaw, &sygnal);
  sigemptyset(&maska_sygnalow);
  sigaddset(&maska_sygnalow, SIGQUIT);
  int signum;
  puts("czekam na sygnal SIGQUIT");
  sigwait(&maska_sygnalow, &signum);
  if (signum == SIGQUIT)
    puts("dostalem SIGQUIT");
  
  // możemy sobie zarzyczyć także przesłania sygnału SIGALRM
  // za określoną ilość sekund (lub troche później):
  alarm(4);
  
  // funkcja open służy do otwierania dostępu do pliku przez deskryptor, patrz: man 2 open
  int deskryptor = open( "/tmp/plik", O_WRONLY );
  
  write(deskryptor, "Ala ma Kota", 12 ); // wpisuje 12 znaków z podanego ciągu
  // do czegoś okreslonego deskryptorem (w tym przykładzie jest to plik)
  
  // mamy też bliźniaczą funkcję read(deskryptor, bufor, ilosc) czytająca z deskryptora
  // do bufora zadana ilosc znaków oraz funkcję lseek(deskryptor, przesuniecie, tryb)
  // - przesówjącą się w pliku; tryb to SEEK_SET (nowa pozycja = przesuniecie),
  // SEEK_CUR (nowa pozycja = aktualna pozycja + przesuniecie),
  // SEEK_END (nowa pozycja = rozmiar_pliku + przesuniecie)
  
  close(deskryptor); // zamykamy deskryptor
  
  // mamy równierz trochę innych funkcji:
  // chown - zmiana użytkownika i grupy
  // chdir - zmaina aktualnego katalogu (odpowiednik komendy cd ...)
  // getcwd - zwraca aktualny katalog, tak jak getenv("PWD");
  // rmdir - usuwa pusty katalog
  
  // czas ...
  time_t czas = time(0);
    // czas mierzony w sekundach od początku epoki (czyli 1970-01-01 00:00:00 UTC),
    // patrz: man 2 time
    // możemy też korzystać z wywołania: time(&czas);
  printf("Od poczotku epoki upłyneło %d sekund\n", czas);

  // następnie możemy utworzyć struktórę zawierającą czas rozłożony:
  struct tm czas_rozlozony_utc;
  gmtime_r(&czas, &czas_rozlozony_utc);
  // jest też localtime zwracająca czas w lokalnej strefie czasowej oraz inne funkcje
  //  patrz man 3 gmtime
  struct tm czas_rozlozony_local;
  localtime_r(&czas, &czas_rozlozony_local);
  // uwaga na wywołanie czas_rozlozony_local=localtime(&czas);
  // może nadpisać ono strukturę czas_rozlozony_utc
  // (zwróci wskażnik do tego samego obszaru co poprzednie wywołanie)

  char czas_napis [100];
  // następnie możemy czas ten sformatować przy pomocy strftime
  strftime(czas_napis, sizeof(czas_napis), "%Y-%m-%d %H:%M:%S %Z (%s)", &czas_rozlozony_utc);
    // więcej o napisach formatujących - man 3 strftime
  printf("Mamy teraz (UTC): %s\n", czas_napis);

  strftime(czas_napis, sizeof(czas_napis), "%Y-%m-%d %H:%M:%S %Z (%s)", &czas_rozlozony_local);
  printf("Mamy teraz (local): %s\n", czas_napis);

  // albo odwołać się bezpośrednio do składowych struktury tm
  printf("Aktualna godzina w UTC to: %d\n", czas_rozlozony_utc.tm_hour);
  
  // wato zwrócić uwagę iż niektóre z pozycji napisu formatującego funkcji strftime korzystają z
  // strefy czasowej ustalonej w zmiennej środowiskowej co ma niemiłe skutki w połączeniu z gmtime()
  // jak widać na powyższym przykładzie timestamp dla czas_rozlozony_utc jest nie poprawny gdyż
  // funkcja ta zakłada że podana struktura jest czasu lokalnego u nas != UTC
  
  // aby zobaczyć to lepiej możemy zrobić to dla chwili zero
  // (która powinna odpowiadać 1970-01-01 00:00:00 UTC
  czas = 0;
  gmtime_r(&czas, &czas_rozlozony_utc);
  localtime_r(&czas, &czas_rozlozony_local);
  // należy pamiętać że funkcję powyzsze w wariancie bez _r są niebezpieczne przy wielowątkowości
  
  strftime(czas_napis, sizeof(czas_napis), "%Y-%m-%d %H:%M:%S %Z (%s)", &czas_rozlozony_utc);
  printf("Mamy teraz (UTC): %s\n", czas_napis);
  strftime(czas_napis, sizeof(czas_napis), "%Y-%m-%d %H:%M:%S %Z (%s)", &czas_rozlozony_local);
  printf("Mamy teraz (local): %s\n", czas_napis);
  
  // widzimy już że problem jest w funkcji wykonywanej na strókturze z rozłożonym czasem w UTC
  setenv("TZ", "UTC");
  strftime(czas_napis, sizeof(czas_napis), "%Y-%m-%d %H:%M:%S %Z (%s)", &czas_rozlozony_utc);
  printf("Mamy teraz (UTC): %s\n", czas_napis);
  strftime(czas_napis, sizeof(czas_napis), "%Y-%m-%d %H:%M:%S %Z (%s)", &czas_rozlozony_local);
  printf("Mamy teraz (local): %s\n", czas_napis);
  // daje to porpawny rezultat dla UTC oraz niepoprawny dla lokalnego ...
  // co ciekawe strefa czasowa (%Z) zawsze jest poprawna, należy więc uważać
  // gdy korzystamy z gmtime oraz napisów formatujących zależynych od strefy czasowej ...
  
  // mamy równierz funkcję mktime,
  //  która na podstawie struktury tm wyrazonej w czasie lokalnym tworzy timestamp

  // oraz funkcję gettimeofday pobierającą czas z większą dokładnością
  struct timeval czas2;
  gettimeofday(&czas2, NULL);
  printf("Od poczotku epoki upłyneło %d sekund i %d microsekund\n", czas2.tv_sec, czas2.tv_usec);
  // podobnie do gettimeofday działa clock_gettime(CLOCK_REALTIME, &time);
  
  
  while(sleep(60) > 0); // aby móc pobawić się sygnałami ...
    // while konieczny bo sygnal przerywa czekanie i nie jest ono kontynuowane
    // należy też wspomnieć iż ładniejszą metodą realizacji takiego zabronienia
    // zakończenia programu jest czekanie na jakis sygnal niz robienie sleep()
    // ale tu nam chodzi aby ten sleep sie kiedys zakonczyl ...
  
    // sleep(ilosc_sekund); - proces robi sobie przerwę przez zadaną liczbę sekund lub dłużej 
    //  (nie zajmuje czasu procesora w odróżnieniu od rozwiązań typu pętle itp.,
    //  otrzymanie sygnału skraca przerwę)
}

XHTML generated by highlight (http://www.andre-simon.de/) from unix.c



Copyright (c) 1999-2015, Robert Paciorek (http://www.opcode.eu.org/), BSD/MIT-type license


Redystrybucja wersji źródłowych i wynikowych, po lub bez dokonywania modyfikacji JEST DOZWOLONA, pod warunkiem zachowania niniejszej informacji o prawach autorskich. Autor NIE ponosi JAKIEJKOLWIEK odpowiedzialności za skutki użytkowania tego dokumentu/programu oraz za wykorzystanie zawartych tu informacji.

This text/program is free document/software. Redistribution and use in source and binary forms, with or without modification, ARE PERMITTED provided save this copyright notice. This document/program is distributed WITHOUT any warranty, use at YOUR own risk.

Valid XHTML 1.1 Dokument ten (URL: http://www.opcode.eu.org/programing/c_cpp/unix.c) należy do serwisu OpCode. Autorem tej strony jest Robert Paciorek, wszelkie uwagi proszę kierować na adres e-mail serwisu: webmaster@opcode.eu.org.
Data ostatniej modyfikacji artykulu: '2014-01-07 19:27:41 (UTC)' (data ta może być zafałszowana niemerytorycznymi modyfikacjami artykułu).