Úno
5

Operační systémy (IOS) – Projekt č. 1 a 2

By majlan  //  Bash, C, FIT VUT  //  Komentářů: 0

První projekt se psal v unixovém bashi, tvořily jej dva skripty, první na práci s regulárními výrazy a druhý na práci s archivy. Druhý projekt řešil problém spícího holiče s použitím podprocesů.

Hodnocení:
3. projekt – 13/15
4. projekt – 14/15

Je zakázáno kopírovat tyto zdrojové kódy! Veškeré projekty procházejí kontrolou na plagiátorství, takže se nepokoušejte použít mé kódy a to ani tak, že přepíšete názvy proměnných, nepomůže to. Výsledkem opisování je předvolání před komisi a většinou také odebrání zápočtu, takže vzhledem k tomu, že jsem nezpochybnitelným autorem následujících kódů, uškodíte pouze sami sobě.

Přejít na projekt č. 1 – hltrace
Přejít na projekt č. 2

Projekt č. 1 – ardiff

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
#!/bin/sh
export LC_ALL=C
 
# IOS - Projekt 1, skript ardiff
# Autor: Milan Seitler (xseitl01@stud.fit.vutbr.cz)
#
# Popis skriptu: Skript ardiff zaznamenava rozdily dvou archivu, ktere uklada
# do adresarove struktury a zpetne rekonstruuje puvodni archivy za pouziti
# rozdiloveho archivu
 
#promenne pro osetreni parametru
napoveda=false
patch=false
rozdil=false
reverze=false
vystup=""
vypis=false
 
#vygenerujeme docasny adresar
temp=`mktemp -d /tmp/tempf.XXXXX`/
temp=${temp}
 
nazev1="a"
nazev2="b"
 
#odchyceni signalu
trap preruseni INT
trap preruseni KILL
trap preruseni TERM
 
#######################################################################################
###################################DEFINICE FUNKCI#####################################
 
#pokud dojde k preruseni, vymazeme docasne soubory a ukoncime program
preruseni(){
  rm -rf $temp$nazev1/* ; rmdir $temp$nazev1  2> /dev/null
  rm -rf $temp$nazev2/* ; rmdir $temp$nazev2  2> /dev/null
  rm -rf "$temp"c/* ; rmdir "$temp"c  2> /dev/null
  rm -rf $temp* ; rmdir $temp 2> /dev/null
  exit 1
}
 
#je treba zjistit typ archivu a pouzit odpovidajici unpack funkci
rozbal(){
  archiv=$(file $1)
  echo $archiv | grep -q ".*: POSIX tar.*"
  if [ $? -eq 0 ] ; then
    mkdir -p "$temp$2"
    tar -xf $1 -C "$temp$2"
  else
    echo $archiv | grep -q ".*: bzip2.*"
    if [ $? -eq 0 ] ; then
      mkdir -p "$temp$2"
      tar -jxf $1 -C "$temp$2"
    else
      echo $archiv | grep -q ".*: gzip.*"
      if [ $? -eq 0 ] ; then
        mkdir -p "$temp$2"
        tar -zxf $1 -C "$temp$2"
      else
        echo $archiv | grep -q ".*: Zip.*"
        if [ $? -eq 0 ] ; then
          mkdir -p "$temp$2"
          unzip -q $1 -d "$temp$2"
        fi
      fi
    fi
  fi
}
 
#funkce zabali vysledny archiv, pred zabalenim jeste smaze prazdne adresare
zabal(){
  archiv=$1
  #zjistime priponu souboru
  pripona=$(echo $archiv | sed "s/.*\(...\)/\1/g")
  cd c
  #archiv nesmi obsahovat prazdne slozky
  find . -type d | tail -r | while read slozka ; do
    rmdir "$slozka" 2> /dev/null
  done
  #zvolime odpovidajici balici funkci
  case $pripona in
    tar)
      tar -cf ../vystupni.archiv * ;;
    tgz|.gz)
      tar -zcf ../vystupni.archiv * ;;
    bz2)
      tar -jcf ../vystupni.archiv * ;;
    zip|ZIP)
      zip -rq ../vystupni.archiv ./ ;;
    *)
      #pri nespravnem typu archivu smazeme docasne soubory a ukoncime program
      echo "Typ vysledneho archivu neni podporovan."
      rm -rf $temp$nazev1/* ; rmdir $temp$nazev1  2> /dev/null
      rm -rf $temp$nazev2/* ; rmdir $temp$nazev2  2> /dev/null
      rm -rf "$temp"c/* ; rmdir "$temp"c  2> /dev/null
      rm -rf $temp* ; rmdir $temp 2> /dev/null
      exit 1 ;;
  esac
  cd ..
}
 
#nacte nazvy adresaru, kterej se jmenuji stejne jako nejaky soubor
najdi_dupl(){
  vysl=""
  slozky=`diff -aqrNl "$temp$nazev1/" "$temp$nazev2/" | grep "^File .*" | sed "s#^File $temp$nazev1\/\(.*\).* is a .* while .* is a.*#\1#"`
  slozky=${slozky}
 
  #projdeme vsechny shody
  for slozka in "$slozky" ; do
  slozka=$(echo "$slozka" | sed "s/^\( *\)//g" | sed '/^$/d')
  if [ "$slozka" != "" ] ; then
  #testujeme v kterem archivu je soubor a v kterem adresar
  ls -ld "$temp$nazev1/$slozka" | grep -q "^d.*"
  if [ $? -eq 0 ] ; then
    vysl="$vysl "$(find -L "$temp$nazev1/$slozka" | sed "s#$temp$nazev1\/##g")
  fi
 
  ls -ld "$temp$nazev2/$slozka" | grep -q "^d.*"
  if [ $? -eq 0 ] ; then
    vysl="$vysl "$(find -L "$temp$nazev2/$slozka" | sed "s#$temp$nazev2\/##g")
  fi
  fi
  done
 
  #ltrim
  vysl=$(echo "$vysl" | sed "s/^\( *\)//g" | sed '/^$/d')
 
  echo "$vysl"
}
 
#zobrazi seznam vsech souboru, ktere jsou v danych archivech odlisne
rozdilne_soubory(){
  vysl=$(najdi_dupl)
 
  #zobrazi ostatni rozdilne soubory
  vysl="$vysl
  "$(diff -aqrNlP $temp$nazev1/ $temp$nazev2/ | grep "^Files .*" | sed "s#Files $temp$nazev1\/\(.*\) and .*#\1#")
  #ltrim
  vysl=$(echo "$vysl" | sed "s/^\( *\)//g" | sed '/^$/d')
  echo -n "$vysl"
}
 
#######################################################################################
###################################</DEFINICE FUNKCI>##################################
 
#zpracovani parametru
while getopts ":lcpro:" param ; do
  case "$param" in
  l) vypis=true ;;
  c) rozdil=true ;;
  p) patch=true ;;
  r) reverze=true ;;
  o) vystup="$OPTARG" ;;
  [?]) napoveda=true ;;
  esac
done
 
#nebyly zadany zadne parametry
if [ $# -eq 0 ] ; then
  napoveda=true
fi
 
if [ "$napoveda" = false ] ; then
  #nacteme nazvy archivu
  shift $(($OPTIND - 1))
  soubor1=$1
  soubor2=$2
 
  #rozbalim oba soubory do docasnych adresaru
  rozbal "$soubor1" "$nazev1"
  rozbal "$soubor2" "$nazev2"
fi
 
#parametr -l
if [ "$vypis" = true -a "$rozdil" = false -a "$patch" = false -a "$reverze" = false -a "$vystup" = "" -a "$napoveda" = false ] ; then
  rozdilne_soubory
#parametry -c -o
elif [ "$vypis" = false -a "$rozdil" = true -a "$patch" = false -a "$reverze" = false -a "$vystup" != "" -a "$napoveda" = false ] ; then
  #zjistime rozdilne soubory
  seznam=$(rozdilne_soubory)
  soubory=""
  #presuneme se do temp adresare
  aktual=$(pwd)
  cd $temp
  mkdir c
  echo "$seznam" | while read pol ; do
    #pokud se v ceste k souboru nachazi alespon jedna slozka
    echo "$pol" | grep -q "/"
    if [ $? -eq 0 ] ; then
      #vyrizneme jeji nazev a vytvorime k ni cestu
      slozka=$(echo "$pol" | sed "s/\(.*\)\/.*$/\1/g")
      mkdir -p "c/$slozka"
    fi
    #zapiseme zmeny jednotlivych souboru
    diff -auN "$nazev1/$pol" "$nazev2/$pol" > "c/$pol.patch" 2> /dev/null
  done
 
  stejne=$(najdi_dupl)
  #prepise hlavicku diff souboru
  echo "$stejne" | while read pol ; do
    if [ -s "a/$pol" -a ! -d "a/$pol" ] ; then
      diff -au "a/$pol" "/dev/null" | sed "s#\([+-][+-]*\) /dev/null\([^0-9]*\)\(.*\)#\1 b/${pol}\21970-01-01 01:00:00.000000000 +0100#g" > "c/$pol.patch"
    fi
    if [ -s "b/$pol" -a ! -d "b/$pol" ] ; then
      diff -au "/dev/null" "b/$pol" | sed "s#\([+-][+-]*\) /dev/null\([^0-9]*\)\(.*\)#\1 a/${pol}\21970-01-01 01:00:00.000000000 +0100#g" > "c/$pol.patch"
    fi
  done
 
  zabal $vystup
  #vysledny archiv presuneme na pozadovane umisteni
  cd $aktual
  cp "$temp""vystupni.archiv" "$archiv"
  rm "$temp""vystupni.archiv"
  rm -rf "$temp"c/* ; rmdir "$temp"c
#parametry -p -o
elif [ "$vypis" = false -a "$rozdil" = false -a "$patch" = true -a "$vystup" != "" -a "$napoveda" = false ] ; then
  #parametr -r (pokud neni zadan)
  if [ "$reverze" = false ] ; then
    aktual=$(pwd)
    #odskocime do docasneho adresare
    cd $temp
    slozky=$(find "b/" -type f)
    #projdeme vsechny soubory, na originalni soubor aplikujeme patch
    echo "$slozky" | while read slozka ; do
      slozka=$(echo "$slozka" | sed "s#b\/##")
      orig=$(echo "$slozka" | sed "s/\.patch$//g")
      cesta=$(echo "$orig" | grep "/" | sed "s/\(.*\)\/.*$/\1/g")
      mkdir -p "$a/$cesta" 2> /dev/null
      patch -fs "a/$orig" "b/$slozka"
    done
 
    #obsah noveho archivu zkopirujeme, funkce zabal tvori archiv ze slozky c
    mkdir c
    cp -r a/* c
 
    zabal $vystup
    cd $aktual
    #uklid docasnych souboru
    cp "$temp""vystupni.archiv" "$archiv"
    rm "$temp""vystupni.archiv"
    rm -rf "$temp"c/* ; rmdir "$temp"c
  else
    #reverzni mod
    znova_sl=""
    aktual=$(pwd)
    #odskocime do docasneho adresare
    cd $temp
    slozky=$(find "b/" -type f)
    #nejprve se patch aplikuje na vsechny soubory, ktere jsou soubory v obou archivech
    echo "$slozky" | while read slozka ; do
      slozka=$(echo "$slozka" | sed "s#b\/##g")
      orig=$(echo "$slozka" | sed "s/.patch$//g")
      if [ -f "a/$orig" -a -f "b/$slozka" ] ; then
        adresar=$(echo "$orig" | grep "/" | sed "s/\(.*\)\/.*$/\1/g")
        mkdir -p "a/$adresar" 2>/dev/null
        touch "a/$orig"
        patch -fsR "a/$orig" "b/$slozka" 2>/dev/null
      else
        #ukladame cestu pro soubor/slozka problem
        znova_sl="$znova_sl
$slozka"
      fi
      #je to potreba si data ze subshellu ulozit
      echo "$znova_sl" > seznam.slozek
    done
 
    znova_sl=$(cat seznam.slozek)
    rm seznam.slozek
    #nyni pouzijeme patch na zbyvajici soubory
    znova_sl=$(echo "$znova_sl" | sed "1d")
    echo "$znova_sl" | while read znova ; do
      orig=$(echo "$znova" | sed "s/.patch$//g")
      patch -fsR "a/$orig" "b/$znova" 2>/dev/null
    done
 
    #obsah noveho archivu zkopirujeme, funkce zabal tvori archiv ze slozky c
    mkdir c
    cp -r a/* c
    zabal $vystup
    cd $aktual
    #uklid docasnych souboru
    cp "$temp""vystupni.archiv" "$archiv"
    rm "$temp""vystupni.archiv"
    rm -rf "$temp"c/* ; rmdir "$temp"c
  fi
#neplatna kombinace parametru
else
  echo "ardiff vypisuje zmeny archivu, vytvari rozdilovy archiv nebo aplikuje rozdilovy
archiv na zdrojovy archiv.
Pouziti: ardiff [volby] archiv1 archiv2
Volby:
  -o SOUBOR   Pokud je cilem skriptu vytvorit archiv, bude vytvoren do souboru
              se jmenem SOUBOR (plati pro -c a -p).
  -l          Vypis seznamu souboru, ktere se v zadanych archivech lisi.
  -c          Vytvoreni rozdiloveho archivu.
  -p          Aplikace rozdiloveho archivu (argument archiv2) na zdrojovy archiv
              (argument archiv1).
  -r          Prepnuti do reverzniho rezimu (plati pro -p)."
  #pokud byly vytvoreny docasne soubory, je nutne je smazat
    rm -rf $temp$nazev1/* ; rmdir $temp$nazev1  2> /dev/null
    rm -rf $temp$nazev2/* ; rmdir $temp$nazev2  2> /dev/null
    rm -rf "$temp"c/* ; rmdir "$temp"c  2> /dev/null
    rm -rf $temp* ; rmdir $temp 2> /dev/null
  exit 1
fi
 
#uklid docasnych souboru
rm -rf $temp$nazev1/* ; rmdir $temp$nazev1  2> /dev/null
rm -rf $temp$nazev2/* ; rmdir $temp$nazev2  2> /dev/null
rm -rf $temp* ; rmdir $temp 2> /dev/null
 
exit 0

Projekt č. 1 – hltrace

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
#!/bin/sh
export LC_ALL=C
 
# IOS - Projekt 1, skript hltrace
# Autor: Milan Seitler (xseitl01@stud.fit.vutbr.cz)
#
# Popis skriptu: Skript hltrace slouzi jako textovy filtr, ktery zvyraznuje
# syntaxi vystupu z programu strace a uklada ji jako webovou stranku
 
#"vynulujeme" syscall
syscall="&!#"
napoveda=false
 
#nacteni parametru
if [ $# -eq 1 ] || [ $# -gt 2 ] ; then
  napoveda=true
fi
 
if [ $# -eq 2 ] ; then
  if [ $1 != "-s" ] ; then
    napoveda=true
  else
    syscall=$2
  fi
fi
 
#pri neplatne kombinaci vypiseme napovedu
if [ $napoveda = true ] ; then
  echo "hltrace zvyrazni syntax stopy od strace.
Pouziti: hltrace [volby] <stopa.strace >stopa.html
Volby:
  -s SYSCALL  Specialne zvyrazni volani SYSCALL." 1>&2
  exit 1
else
#vypiseme hlavicku
  echo "<html>
<style>
.pid { color:darkred; }
.ts { color:navy; }
.number { color:red; }
.const { color:green; }
.string { color:blue; }
.hlcall { text-decoration:none; font-weight:bold; color:black; }
.call { text-decoration:none; color:olive; }
</style>
<body><pre>"
 
#ze standardniho vstupu nacteme text a postupne filtrujeme
  cat /dev/stdin | sed "s/&/\&/g" | sed "s/</\</g" | sed "s/>/\>/g" | #nahrazeni <>&
   sed "s/\(\"[^\"]*\"\)/<span class=\"string\">\1<\/span>/g" | #retezce
   sed "s/\([[| ,({=]\)\([A-Z][A-Z0-9_]*\)\([]} |,()]\)/\1<span class=\"const\">\2<\/span>\3/g" | #konstanty
   sed "s/\([[| ,({=]\)\([A-Z][A-Z0-9_]*\)\([]} |,()]\)/\1<span class=\"const\">\2<\/span>\3/g" | #konstanty
   sed "s/\([ (]\)\(0x[a-f0-9]*\)/\1<span class=\"number\">\2<\/span>/g" | sed "s/ = \([-0-9][0-9]*\)/ = <span class=\"number\">\1<\/span>/g" | #hexa a cisla s =
   sed "s/(\([-0-9][0-9]*\)/(<span class=\"number\">\1<\/span>/g" | sed "s/ \([-0-9][0-9]*\)\([,)]\)/ <span class=\"number\">\1<\/span>\2/g" | #decimalni cisla
   sed "s/\($syscall\)(/<a href=\"http:\/\/www.kernel.org\/doc\/man-pages\/online\/pages\/man2\/\\1.2.html\" class=\"hlcall\">\1<\/a>(/g" | #nahradi hlcall
   sed "s/\([0-9a-z_][0-9a-z_]*\)(/<a href=\"http:\/\/www.kernel.org\/doc\/man-pages\/online\/pages\/man2\/\\1.2.html\" class=\"call\">\1<\/a>(/" | #ostatni volani
   sed "s/^\([0-9][0-9]*\)\([ ][ ]*\)\([0-9][0-9\.]*\)/<span class=\"pid\">\1<\/span>\2<span class=\"ts\">\3<\/span>/g" | #nahrazuje pid a ts
   sed "s/^\([0-9][0-9]*\)\([ ][ ]*\)/<span class=\"pid\">\1<\/span>\2/g" |
   sed "s/^\([0-9][0-9\.]*\)/<span class=\"ts\">\1<\/span>/g"
 
  #zbyva vypsat paticku
  echo "<:/pre></body></html>"
fi
exit 0

Projekt č. 2

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
/******************************************************
******************IOS - projekt c. 2*******************
** Autor: Milan Seitler (xseitl01@stud.fit.vutbr.cz)
** Datum vytvoreni: duben 2011
**
** Popis programu: Progrsm demonstruje synchronizaci procesu
** pri problemu spiciho holice. S vyuzitim semaforu a sdilene
** pameti zabranuje synchronizacnim problem jako deadlock ci
** hladoveni.
**
** Parametry programu: barbers Q GenC GenB N F
** Q - pocet zidli v cekarne
** GenC - rozsah pro generovani zakazniku [ms]
** GenB - rozsah pro generovani doby obsluhy [ms]
** N - pocet vygenerovanych zakazniku
** F - nazev vystupniho souboru, v pripade "-" -> stdout
**
**
** Literatury precteno: mnoho, probdeno noci: 0
** propadnuto zoufalstvi: 2x, pouzito tuzky a papiru: mnohokrat
******************************************************/
 
#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
#include <ctype.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <sys/wait.h>
#include <semaphore.h>
#include <pthread.h>
#include <unistd.h>
#include <time.h>
#include <fcntl.h>
#include <sys/stat.h>
#include <sys/mman.h>
#include <string.h>
 
 
#define E_OK 0
#define E_SEM 1
#define E_SHM 2
#define E_PARAM 3
 
typedef struct parametry {
  int q; // pocet zidli
  int GenC, GenB; // rozsah pro generovani zakazniku a doby obsluhy (O-Gen[BC])
  int N; // pocet zakazniku
  char *F; // nazev vystupniho souboru, pokud je "-" => vypise na stdout
} Tparam;
 
// deklarujeme promenne pro vsechny semafory
sem_t *s_cekarna, *s_holic, *s_zakaznici, *s_strihani, *s_citac, *s_citac_z, *s_zapis, *s_zidle;
FILE *vypis = NULL; // a taky ukazatel na soubor
 
int barber_pid = 0; // budeme ukladat id procesu holice
// ukazatele na sdilenou pamet
int *cislo_procesu = NULL, *cislo_zakaznika = NULL, *volne_zidle = NULL,  *pocet_hotovych = NULL;
// pro navratove funkce shmget
int shm_cp_id = 0, shm_cz_id = 0, shm_zidle_id = 0, shm_hotovo_id = 0;
 
// deklarace funkci
int nacti_parametry(int argc, char *argv[], Tparam *x);
void holic(Tparam param);
void zakaznik();
int zvys_cislo_akce(int *cislo); // zvysi pocitadlo o jednicku, vraci hodnotu pred zvysenim
int nacti_zdroje(void); // alokuje pamet, inicializuje semafory
void uvolni_zdroje(void); // uvolni sdilenou pamet, znici semafory
void ukonci_program(int sig); // v pripade preruseni bezpecne ukonci program
 
int main(int argc, char *argv[]) {
  pid_t pid_holice, pid_zakaznika;
 
  Tparam param; // struktura pro ulozeni parametru programu
  int i = 0; // pruchod poctem zakazniku N
  int rozsah = 0; // promenna pro generovani nahodne doby obsluhy
 
  // handlery pro zachyceni signalu
  signal(SIGTERM, ukonci_program);
  signal(SIGINT, ukonci_program);
 
  srand(time(0)); // abychom generovali opravdu nahodna cisla
 
  // parametry ukladame do struktury
  if(nacti_parametry(argc, argv, &param) == E_PARAM) {
    return E_PARAM;
  }
  int potomci[param.N];
 
  // otevreme vystupni soubor, v pripade chyby vypis na stdout
  if(strcmp(param.F, "-") != 0) {
    if((vypis = fopen(param.F, "w+")) == NULL) {
      fprintf(stderr, "Nepovedlo se otevrit vystupni soubor. Program bude ukoncen.\n");
      uvolni_zdroje();
      return EXIT_FAILURE;
    }
  } else {
    vypis = stdout;
  }
 
  // pro spravny zapis do souboru
  setbuf(vypis, NULL);
 
  // alokace pameti a inicializace semaforu
  int zdroje = nacti_zdroje();
  if(zdroje != E_OK) {
    if(zdroje == E_SEM) {
      fprintf(stderr, "Nastala chyba pri vytvareni semaforu. Program bude ukoncen.\n");
    } else {
      fprintf(stderr, "Nastala chyba pri alokaci pameti. Program bude ukoncen.\n");
    }
    uvolni_zdroje();
    return EXIT_FAILURE;
  }
 
  // nastavime citace
  *cislo_procesu = 1;
  *cislo_zakaznika = 1;
  *volne_zidle = param.q;
  *pocet_hotovych = 0;
 
  // spustime proces holice
  pid_holice = fork();
  if(pid_holice == 0) {
 
    // potomek, tedy holic
    holic(param);
 
  } else if (pid_holice > 0) {
 
    pid_holice = pid_holice;
    // proces rodice
    for(i = 0; i < param.N; i++) {
      // spoustime procesy zakazniku
      // generujeme prodlevu mezi zakazniky
      if(param.GenC != 0) {
        rozsah = (random() % (param.GenC + 1));
      } else {
        rozsah = 0;
      }
      usleep(rozsah * 1000);
      pid_zakaznika = fork();
      if(pid_zakaznika == 0) {
 
        // proces zakaznika
        zakaznik();
 
      } else if(pid_zakaznika > 0) {
        // pokracovani procesu rodice (hlavniho procesu)
        potomci[i] = pid_zakaznika;
      } else {
        fprintf(stderr, "Nepovedlo se vytvorit zakaznika. Program bude ukoncen.\n");
        ukonci_program(0);
      }
    }
 
  } else {
    fprintf(stderr, "Nepovedlo se vytvorit holice. Program bude ukoncen.\n");
    uvolni_zdroje();
    exit(EXIT_FAILURE);
  }
 
  // pockame na zakazniky
  for(i = 0; i < param.N; i++) {
    waitpid(potomci[i], NULL, 0);
  }
 
  // pozor na zombie holice!
  if(param.q == 0) {
    kill(barber_pid, SIGTERM);
  }
 
  uvolni_zdroje();
 
  return EXIT_SUCCESS;
}
 
int nacti_parametry(int argc, char *argv[], Tparam *x) {
  int error = E_OK;
  char *stop = NULL;
 
  // celkem 6 parametru (5 + nazev programu)
  if(argc == 6) {
    // postupne overime jednotlive parametry
    if(isdigit(*argv[1])) {
      x->q = strtoul(argv[1], &stop, 10);
    } else {
      error = E_PARAM;
    }
    if(isdigit(*argv[2])) {
      x->GenC = strtoul(argv[2], &stop, 10);
    } else {
      error = E_PARAM;
    }
    if(isdigit(*argv[3])) {
      x->GenB = strtoul(argv[3], &stop, 10);
    } else {
      error = E_PARAM;
    }
    if(isdigit(*argv[4])) {
      x->N = strtoul(argv[4], &stop, 10);
    } else {
      error = E_PARAM;
    }
    x->F = argv[5];
    // konec overovani parametru
  } else {
    error = E_PARAM;
  }
 
  if(error == E_PARAM) {
    printf("Byla zadana neplatna kombinace parametru. Program bude ukoncen.\n");
  }
 
  return error;
}
 
void holic(Tparam param) {
  int rozsah = 0;
 
  // proces holice provadi jen urcity pocet iteraci
  while(*pocet_hotovych < param.N) {
    fflush(vypis);
    sem_wait(s_zapis);
    fprintf(vypis, "%d: barber: checks\n", zvys_cislo_akce(cislo_procesu));
    sem_post(s_zapis);
    sem_wait(s_zakaznici);
    sem_wait(s_cekarna);
    // pokud je v cekarne zakaznik, uvolnime jedno misto a pustime jej dale
    if(*volne_zidle < param.q) {
      (*volne_zidle)++;
    }
    sem_wait(s_zapis);
    fprintf(vypis, "%d: barber: ready\n", zvys_cislo_akce(cislo_procesu));
    sem_post(s_zapis);
    fflush(vypis);
    sem_post(s_holic);
    sem_wait(s_zidle);
    sem_post(s_cekarna);
    // nyni probihani strihani vlasu
    if(param.GenB != 0) {
      rozsah = (random() % (param.GenB + 1));
    } else {
      rozsah = 0;
    }
    usleep(rozsah * 1000);
    sem_wait(s_zapis);
    fprintf(vypis, "%d: barber: finished\n", zvys_cislo_akce(cislo_procesu));
    sem_post(s_zapis);
    fflush(vypis);
    sem_post(s_strihani);
    (*pocet_hotovych)++; // poznacime "uspokojeneho" zakaznika
  }
 
  exit(0);
}
 
void zakaznik() {
  int lok_cislo = 0; // ulozime si cislo zakaznika do pomocne promenne
 
  sem_wait(s_citac_z);
  // je treba si ulozit cislo zakaznika do lokalni promenne, aby nedoslo ke kolizim
  lok_cislo = *cislo_zakaznika;
  (*cislo_zakaznika)++;
  sem_post(s_citac_z);
  sem_wait(s_zapis);
  fprintf(vypis, "%d: customer %d: created\n", zvys_cislo_akce(cislo_procesu), lok_cislo);
  sem_post(s_zapis);
  fflush(vypis);
  sem_wait(s_cekarna);
  sem_wait(s_zapis);
  fprintf(vypis, "%d: customer %d: enters\n", zvys_cislo_akce(cislo_procesu), lok_cislo);
  sem_post(s_zapis);
  fflush(vypis);
  // pokud je v cekarne jeste misto, zakaznik se posadi
  if(*volne_zidle > 0) {
    (*volne_zidle)--;
    sem_post(s_zakaznici);
    sem_post(s_cekarna);
    sem_wait(s_holic);
    sem_wait(s_zapis);
    fprintf(vypis, "%d: customer %d: ready\n", zvys_cislo_akce(cislo_procesu), lok_cislo);
    sem_post(s_zapis);
    sem_post(s_zidle); // zakaznik useda do holicskeho kresla
    fflush(vypis);
    sem_wait(s_strihani);
    sem_wait(s_zapis);
    fprintf(vypis, "%d: customer %d: served\n", zvys_cislo_akce(cislo_procesu), lok_cislo);
    sem_post(s_zapis);
    fflush(vypis);
  } else { // pokud v cekarne neni misto, zakaznik odchazi
    sem_wait(s_zapis);
    fprintf(vypis, "%d: customer %d: refused\n", zvys_cislo_akce(cislo_procesu), lok_cislo);
    sem_post(s_zapis);
    fflush(vypis);
    sem_post(s_cekarna);
    (*pocet_hotovych)++; // i odmitnuty zakaznik je pro nase potreby "uspokojeny"
  }
  exit(0);
}
 
int zvys_cislo_akce(int *cislo) { // funkce zajistuje bezpecne navyseni pocitadla akci
  int puvodni = 0;
 
  sem_wait(s_citac);
  puvodni = *cislo;
  (*cislo)++;
  sem_post(s_citac);
 
  return puvodni;
}
 
int nacti_zdroje(void) {
  int error = E_OK;
 
  // -------------------- inicializace semaforu -----------------------
  // s_holic = semafor holice
  // s_zakaznici = semafor zakazniku
  // s_strihani = semafor oznamuje zakaznikovi konec strihani
  // s_cekarna = semafor cekarny
  // s_citac = vylucny pristup k citaci akci
  // s_citac = vylucny pristup k citaci zakazniku
  // s_zapis = vylucny pristup k souboru
  // s_zidle = semafor hlida, aby se nepredbihali zakaznici na ceste do kresla
  if((s_holic = mmap(NULL, sizeof(sem_t), PROT_READ | PROT_WRITE, MAP_ANONYMOUS | MAP_SHARED, 0, 0)) == MAP_FAILED) { error = E_SEM; }
  if((s_zakaznici = mmap(NULL, sizeof(sem_t), PROT_READ | PROT_WRITE, MAP_ANONYMOUS | MAP_SHARED, 0, 0)) == MAP_FAILED) { error = E_SEM; }
  if((s_strihani = mmap(NULL, sizeof(sem_t), PROT_READ | PROT_WRITE, MAP_ANONYMOUS | MAP_SHARED, 0, 0)) == MAP_FAILED) { error = E_SEM; }
  if((s_cekarna = mmap(NULL, sizeof(sem_t), PROT_READ | PROT_WRITE, MAP_ANONYMOUS | MAP_SHARED, 0, 0)) == MAP_FAILED) { error = E_SEM; }
  if((s_citac = mmap(NULL, sizeof(sem_t), PROT_READ | PROT_WRITE, MAP_ANONYMOUS | MAP_SHARED, 0, 0)) == MAP_FAILED) { error = E_SEM; }
  if((s_citac_z = mmap(NULL, sizeof(sem_t), PROT_READ | PROT_WRITE, MAP_ANONYMOUS | MAP_SHARED, 0, 0)) == MAP_FAILED) { error = E_SEM; }
  if((s_zapis = mmap(NULL, sizeof(sem_t), PROT_READ | PROT_WRITE, MAP_ANONYMOUS | MAP_SHARED, 0, 0)) == MAP_FAILED) { error = E_SEM; }
  if((s_zidle = mmap(NULL, sizeof(sem_t), PROT_READ | PROT_WRITE, MAP_ANONYMOUS | MAP_SHARED, 0, 0)) == MAP_FAILED) { error = E_SEM; }
 
 
  if(error == E_OK) {
    if(sem_init(s_holic, 1, 0) == -1) { error = E_SEM; }
    if(sem_init(s_zakaznici, 1, 0) == -1) { error = E_SEM; }
    if(sem_init(s_strihani, 1, 0) == -1) { error = E_SEM; }
    if(sem_init(s_cekarna, 1, 1) == -1) { error = E_SEM; }
    if(sem_init(s_citac, 1, 1) == -1) { error = E_SEM; }
    if(sem_init(s_citac_z, 1, 1) == -1) { error = E_SEM; }
    if(sem_init(s_zapis, 1, 1) == -1) { error = E_SEM; }
    if(sem_init(s_zidle, 1, 0) == -1) { error = E_SEM; }
  }
  // -------------------- konec inicializace semaforu -----------------
 
  if(error == E_OK) {
    // -------------------- alokace pameti ------------------------------
    // shm_cp_id = id pameti pro cislo procesu
    // shm_cz_id = id pameti pro cislo zakaznika
    // shm_zidle_id = id pameti pro pocet volnych zidli
    // shm_hotovo_id = id pameti pro pocitani "hotovych" zakazniku
    if((shm_cp_id = shmget(IPC_PRIVATE, sizeof(int), IPC_CREAT | IPC_EXCL | 0666)) == -1) { error = E_SHM; }
    if((cislo_procesu = (int *) shmat(shm_cp_id, NULL, 0)) == NULL) { error = E_SHM; }
 
    if((shm_cz_id = shmget(IPC_PRIVATE, sizeof(int), IPC_CREAT | IPC_EXCL | 0666)) == -1) { error = E_SHM; }
    if((cislo_zakaznika = (int *) shmat(shm_cz_id, NULL, 0)) == NULL) { error = E_SHM; }
 
    if((shm_zidle_id = shmget(IPC_PRIVATE, sizeof(int), IPC_CREAT | IPC_EXCL | 0666)) == -1) { error = E_SHM; }
    if((volne_zidle = (int *) shmat(shm_zidle_id, NULL, 0)) == NULL) { error = E_SHM; }
 
    if((shm_hotovo_id = shmget(IPC_PRIVATE, sizeof(int), IPC_CREAT | IPC_EXCL | 0666)) == -1) { error = E_SHM; }
    if((pocet_hotovych = (int *) shmat(shm_hotovo_id, NULL, 0)) == NULL) { error = E_SHM; }
    // -------------------- konec alokace pameti ------------------------
  }
 
  return error;
}
 
void uvolni_zdroje(void){
  fclose(vypis);
  int error = E_OK;
 
  if(sem_destroy(s_holic) == -1) { error = E_SEM; }
  if(sem_destroy(s_zakaznici) == -1) { error = E_SEM; }
  if(sem_destroy(s_strihani) == -1) { error = E_SEM; }
  if(sem_destroy(s_cekarna) == -1) { error = E_SEM; }
  if(sem_destroy(s_citac) == -1) { error = E_SEM; }
  if(sem_destroy(s_citac_z) == -1) { error = E_SEM; }
  if(sem_destroy(s_zapis) == -1) { error = E_SEM; }
  if(sem_destroy(s_zidle) == -1) { error = E_SEM; }
 
  if(error == E_SEM) { fprintf(stderr, "Nepovedlo se smazat semafor.\n"); }
 
  if(shmctl(shm_cp_id, IPC_RMID, NULL) == -1) { error = E_SHM; }
  if(shmctl(shm_cz_id, IPC_RMID, NULL) == -1) { error = E_SHM; }
  if(shmctl(shm_zidle_id, IPC_RMID, NULL) == -1) { error = E_SHM; }
  if(shmctl(shm_hotovo_id, IPC_RMID, NULL) == -1) { error = E_SHM; }
 
  if(error == E_SHM) { fprintf(stderr, "Nepovedlo se uvolnit alokovanou pamet.\n"); }
}
 
void ukonci_program(int sig) {
  uvolni_zdroje();
  kill(barber_pid, SIGTERM);
  kill(getppid(), SIGTERM);
  exit(EXIT_FAILURE);
}

Vyjádři svůj názor



Zajímá vás cokoliv o mobilních aplikacích? Uvažujete o spolupráci? Kontaktujte mne na seitler@reinto.cz

O mně

Jmenuji se Milan Seitler a jsem spoluzakladatelem společnosti Reinto s.r.o., ve které se věnujeme mobilním i webovým aplikacím a marketingu.

Zabývám se celým procesem tvorby mobilních a webových aplikací. Nejvíce se věnuji návrhu aplikace a UX/UI designu. Kladu velký důraz na jednoduchost a srozumitelnost uživatelského rozhraní.

Zajímám se o online i offline podnikání, fascinují mě úspěšní lidé, kteří se nebojí tvrdé práce. Mou hlavní motivací je konkurence, která mě vždy nutí jít do všeho naplno, protože nerad prohrávám.

Mám rád hudbu, knížky, sport a cestování.

milan@seitler.cz

Odkazy

Inzerujte zde!

Kupte si odkaz! PR 3, SR 2

Inzerujte zde!

Kupte si odkaz! PR 3, SR 2

Inzerujte zde!

Kupte si odkaz! PR 3, SR 2

Partner links