You are on page 1of 610

Msodik, tdolgozott kiads

A sztalos Mr k
B n y sz G b or
L e v e n dov szky T ih am r
Alkalmazott informatika sorozat
Asztalos Mrk
Bnysz Gbor Levendovszky
Tihamr
programozs
Asztalos Mrk Bnysz Gbor Levendovszky Tihamr
L in ux pr ogr am ozs
Msodik, tdolgozott kiads
Asztalos Mrk
Bnysz Gbor
Levendovszky Tihamr
L in ux programozs
Msodik, tdolgozott kiads
2012
Linux programozs
Msodik, tdolgozott kiads
Asztalos Mrk, Bnysz Gbor, Levendovszky Tihamr
Alkalmazott informatika sorozat
Budapesti Mszaki s Gazdasgtudomnyi Egyetem
Villamosmrnki s Informatikai Kar
Automatizlsi s Alkalmazott Informatikai Tanszk
Alkalmazott Informatika Csoport
C Asztalos Mrk, Bnysz Gbor, Levendovszky Tihamr, 2012.
Sorozatszerkeszt: Charaf Hassan
Lektor: Vlgyesi Pter
ISBN 978-963-9863-29-3
ISSN 1785-363X
Minden jog fenntartva. Jelen knyvet, illetve annak rszeit a kiad enge-
dlye nlkl tilos reproduklni, adatrgzt rendszerben trolni, brmi-
lyen formban vagy eszkzzel elektronikus ton vagy ms mdon kzlni.
SZAK Kiad Kft. Az 1795-ben alaptott Magyar Knyvkiadk s Knyvterj esztk
Egyeslsnek a tagj a 2060 Bicske, Difa u. 3.
Tel.: 36-22-565-310 Fax: 36-22-565-311 www.szak.hu
e-mail: info@szak.hu http://www.facebook.com/szakkiado

Kiadvezet: Kis dm, e-mail adam.kis@szak.hu Fszerkesz-
t: Kis Balzs, e-mail: balazs.kis@szak.hu
Tartalomjegyzk
Elsz a msodik kiadshoz ....................................... xv
1. Bevezets .......................................................... 1
1.1. A Linux ................................................................................................. 1
1.2. A szabad szoftver s a Linux trtnete ........................................ 2
1.2.1. FSF ................................................................................................ 2
1.2.2. GPL ................................................................................................ 3
1.2.3. GNU ............................................................................................... 4
1.2.4. Linux-kernel .................................................................................. 4
1.2.5. A Linux rendszer .......................................................................... 6
1.2.6. Linux-disztribcik ....................................................................... 6
1.3. Informciforrsok ........................................................................... 8
2. Betekints a Linux-kernelbe ................................. 11
2.1. A Linux-kernel felptse .............................................................. 11
2.2. A Linux elindulsa .......................................................................... 13
2.3. Processzek ......................................................................................... 14
2.3.1. A Linux-processzekhez kapcsold informcik ....................... 15
2.3.2. A processz llapotai .................................................................... 17
2.3.3. Azonostk ................................................................................... 18
2.3.4. Processzek ltrehozsa s terminlsa ..................................... 19
2.3.5. A programok futtatsa ............................................................... 20
2.3.6. temezs ..................................................................................... 21
2.3.6.1. Klasszikus temezs .......................................................... 21
2.3.6.2. Az O(1) temezs ................................................................ 23
2.3.6.3. Teljesen igazsgos temez ............................................... 24
2.3.6.4. Multiprocesszoros temezs .............................................. 25
2.3.7. Megszaktskezels .................................................................... 25
2.3.8. Valsidejsg .............................................................................. 26
2.3.9. Id s idztk ............................................................................. 26
2.4. Memriakezels ............................................................................... 27
2.4.1. A virtulismemria-kezels ........................................................ 27
2.4.2. Lapozs ........................................................................................ 28
Tartalomjegyzk
vi
2.4.3. A lapozs implementcija a Linuxon ....................................... 29
2.4.4. Igny szerinti lapozs ................................................................. 31
2.4.5. Lapcsere ...................................................................................... 32
2.4.6. Megosztott virtulis memria .................................................... 34
2.4.7. Msols rskor (COW technika) ............................................... 34
2.4.8. A hozzfrs vezrlse ................................................................ 35
2.4.9. A lapkezels gyorstsa .............................................................. 35
2.5. A virtulis llomnyrendszer ....................................................... 36
2.5.1. Az llomnyabsztrakci .............................................................. 36
2.5.2. Specilis llomnyok .................................................................. 38
2.5.2.1. Eszkzllomnyok .............................................................. 38
2.5.2.2. Knyvtr ............................................................................. 40
2.5.2.3. Szimbolikus hivatkozs ...................................................... 40
2.5.2.4. Csvezetk .......................................................................... 40
2.5.2.5. Socket .................................................................................. 41
2.5.3. Az inode ....................................................................................... 41
2.5.4. Az llomnylerk ....................................................................... 44
2.6. A Linux programozsi fellete ..................................................... 44
3. Programknyvtrak ksztse ............................... 47
3.1 . Statikus programknyvtrak ...................................................... 47
3.2. Megosztott programknyvtrak .................................................. 55
3.2.1. Megosztott programknyvtr ksztse ..................................... 56
3.2.2. Megosztott programknyvtrak hasznlata ............................. 60
3.2.3. Megosztott programknyvtrak dinamikus betltse .............. 63
3.3. Megosztott knyvtrak C++ nyelven .......................................... 69
3.3.1. Programknyvtrbeli C++-osztlyok hasznlata ...................... 69
3.3.2. C++-objektumok dinamikus betltse
programknyvtrbl ................................................................... 72
3.4. A megosztott knyvtrak mkdsi mechanizmusai ............. 77
3.4.1. A betlttt program .................................................................... 78
3.4.2. Statikus knyvtrat tartalmaz program linkelse s
betltse ...................................................................................... 80
3.4.3. Megosztott knyvtr linkelse s betltse ............................... 83
3.4.3.1. A cmtartomny kezelse ................................................... 83
3.4.3.2. A megosztott knyvtrak megvalstsnak
alapkoncepcii ..................................................................... 85
3.4.3.3. A megosztott knyvtrakkal kapcsolatos
linkels s betlts .............................................................. 87
3.4.3.4. Dinamikusan linkelt megosztott knyvtr
linkelse s betltse .......................................................... 89
3.4.4. A programknyvtrak hasznlatnak optimalizlsa ............. 89
Tartalomjegyzk
vii
4. llomny- s I/O kezels ..................................... 95
4.1. Egyszer llomnykezels ............................................................ 95
4.1.1. Az llomnyler ......................................................................... 96
4.1.2. llomnyok megnyitsa ............................................................. 97
4.1.3. llomnyok bezrsa .................................................................. 98
4.1.4. rs, olvass s pozicionls az llomnyban ........................... 99
4.1.5. Rszleges s teljes olvass ........................................................ 101
4.1.6. Az rsmvelet finomhangolsa ............................................... 103
4.1.7. llomnyok rvidtse .............................................................. 106
4.1.8. llomnyok tirnytsa .......................................................... 106
4.2. Inode-informcik ........................................................................ 108
4.2.1. Inode-informcik lekrdezse ................................................. 109
4.2.2. Jogok lekrdezse ..................................................................... 110
4.2.3. Jogok lltsa ............................................................................ 111
4.2.4. Tulajdonos s csoport belltsa .............................................. 112
4.2.5. Az idblyeg belltsa ............................................................. 112
4.3. Tovbbi llomnymveletek...................................................... 113
4.3.1. Eszkzllomnyok s pipe bejegyzsek ltrehozsa ............... 113
4.3.2. Merev hivatkozs ltrehozsa .................................................. 114
4.3.3. Szimbolikus hivatkozs ltrehozsa ........................................ 115
4.3.4. llomnyok trlse ................................................................... 116
4.3.5. llomnyok tnevezse ............................................................ 116
4.4. Knyvtrmveletek ..................................................................... 117
4.5. Csvezetkek ................................................................................. 120
4.5.1. Nvtelen csvezetkek .............................................................. 121
4.5.2. Megnevezett csvezetkek ........................................................ 123
4.6. Blokkolt s nem blokkolt I/O ..................................................... 126
4.7. A multiplexelt I/O mdszerei ..................................................... 129
4.7.1. Multiplexels a select() fggvnnyel ........................................ 129
4.7.2. Multiplexels a poll() fggvnnyel ........................................... 134
4.7.3. A multiplexelsi mdszerek sszehasonltsa ......................... 139
4.8. llomnyok lekpezse a memriba ...................................... 139
4.9. llomnyzrols ........................................................................... 143
4.9.1. Zrolllomnyok ..................................................................... 144
4.9.2. Rekordzrols ........................................................................... 145
4.9.3. Ktelez zrols ........................................................................ 148
4.10. Kapcsolat a magas szint llomnykezelssel .................... 149
4.11. Soros kommunikci ................................................................. 150
4.11.1. Kanonikus feldolgozs ............................................................ 151
4.11.2. Nem kanonikus feldolgozs .................................................... 154
Tartalomjegyzk
viii
5. Prhuzamos programozs .................................. 157
5.1. Processzek ...................................................................................... 157
5.2. Processzek kztti kommunikci (IPC) ................................ 165
5.2.1. Szemaforok ................................................................................ 166
5.2.2. zenetsorok .............................................................................. 178
5.2.3. Megosztott memria ................................................................. 185
5.3. Processzek a Linux rendszerben .............................................. 189
5.3.1. Feladatvezrls ......................................................................... 191
5.3.2. Dmonok .................................................................................... 193
5.3.3. Programok indtsa shellbl ..................................................... 197
5.3.4. Jogosultsgok ............................................................................ 198
5.3.5. Felhasznli nevek s csoportnevek ........................................ 200
5.4. Szlak .............................................................................................. 202
5.4.1. Szlak ltrehozsa .................................................................... 203
5.4.2. Szlak ltrehozsa C++ nyelven .............................................. 207
5.4.3. Szlak attribtumai ................................................................. 210
5.4.4. Szlbiztos fggvnyek .............................................................. 212
5.4.5. Szl lelltsa ............................................................................ 217
5.4.6. Szlak s a fork/exec hvsok .................................................. 220
5.5. POSIX-szinkronizci .................................................................. 221
5.5.1. Klcsns kizrs (mutex) ........................................................ 221
5.5.2. Feltteles vltozk .................................................................... 227
5.5.3. Szemaforok ................................................................................ 233
5.5.4. Spinlock ..................................................................................... 236
5.5.5. Tovbbi lehetsgek: POSIX megosztott memria s
zenetsorok ............................................................................... 238
5.6. Jelzsek ........................................................................................... 238
5.6.1. A jelzsklds s -fogads folyamata ....................................... 239
5.6.2. Jelzsek megvalstsa ............................................................. 245
5.6.3. A jelzskezel s a fprogram egymsra hatsa ..................... 247
5.6.4. Jelzsek s a tbbszl processz .............................................. 250
5.6.5. Jelzsek programozsa ............................................................. 250
5.6.5.1. Jelzsek kldse ............................................................... 251
5.6.5.2. Jelzsek letiltsa s engedlyezse.
Fggben lv jelzsek ..................................................... 253
5.6.5.3. A jelzsek kezelse ........................................................... 254
5.6.5.4. Szinkron jelzskezels ...................................................... 258
5.6.6. A SIGCHLD jelzs .................................................................... 262
Tartalomjegyzk
ix
6. Hlzati kommunikci ..................................... 265
6.1. A socket ........................................................................................... 265
6.2. Az sszekttets-alap kommunikci ................................... 267
6.2.1. A kapcsolat felptse ............................................................... 268
6.2.2. A socket cmhez ktse ............................................................. 268
6.2.3. Vrakozs a kapcsoldsra ...................................................... 269
6.2.4. Kapcsolds a szerverhez ......................................................... 269
6.2.5. A kommunikci ....................................................................... 270
6.2.6. A kapcsolat bontsa .................................................................. 270
6.2.7. Tovbbi kapcsolatok kezelse a szerverben ............................ 271
6.3. Az sszekttets nlkli kommunikci ................................. 272
6.3.1. A kommunikci ....................................................................... 273
6.3.2. A connect() hasznlata .............................................................. 274
6.3.3. A socket lezrsa ...................................................................... 275
6.4. Unix domain socket ..................................................................... 275
6.4.1. Unix domain socket cmek ....................................................... 275
6.4.2. Unix domain socket adatfolyam szerveralkalmazs .............. 276
6.4.3. Unix domain socket adatfolyam kliensalkalmazs ................. 278
6.4.4. Unix domain socket datagram kommunikci ........................ 280
6.4.5. Nvtelen Unix domain socket .................................................. 280
6.4.6. A Linux absztrakt nvtere ....................................................... 280
6.5. IP ...................................................................................................... 282
6.5.1. Rviden az IP-hlzatokrl ...................................................... 282
6.5.2. Az IP protokoll rtegzdse ...................................................... 284
6.5.3. IPv4-es cmzs ........................................................................... 285
6.5.4. IPv4-es cmosztlyok ................................................................ 286
6.5.5. IPv4-es specilis cmek ............................................................. 287
6.5.6. IPv6-os cmzs ........................................................................... 288
6.5.7. Portok ........................................................................................ 289
6.5.8. A hardverfgg klnbsgek feloldsa .................................... 290
6.5.9. A socketcm megadsa .............................................................. 290
6.5.10. Loklis cm megadsa ............................................................ 293
6.5.11. Nv- s cmfelolds ................................................................. 294
6.5.11.1. A getaddrinfo() fggvny ................................................ 294
6.5.11.2. A getnameinfo() fggvny ............................................... 298
6.5.12. sszekttets-alap kommunikci ...................................... 302
6.5.12.1. TCP kliens-szerver plda ............................................... 304
6.5.12.2. TCP szerver alkalmazs ................................................ 308
6.5.12.3. TCP-kliensalkalmazs ................................................... 315
6.5.13. sszekttets nlkli kommunikci .................................... 317
6.5.13.1. UDP-kommunikci-plda ............................................. 317
6.5.13.2. Tbbes klds ................................................................. 320
Tartalomjegyzk
x
6.6. Socketbelltsok ......................................................................... 326
6.7. Segdprogramok ........................................................................... 330
6.8. Tvoli eljrshvs ....................................................................... 331
6.8.1. Az RPC-modell .......................................................................... 332
6.8.2. Verzik s szmok ..................................................................... 332
6.8.3. Portmap ..................................................................................... 333
6.8.4. Szllts ..................................................................................... 333
6.8.5. XDR ........................................................................................... 333
6.8.6. rpcinfo ........................................................................................ 334
6.8.7. rpcgen ........................................................................................ 334
6.8.8. Helyi eljrs talaktsa tvoli eljrss ................................ 335
7. Fejleszts a Linux-kernelben .............................. 339
7.1. Verzifggsg .............................................................................. 340
7.2. A kernel- s az alkalmazsfejleszts eltrsei ....................... 341
7.2.1. Felhasznli zemmd kernelzemmd ............................. 342
7.3. Kernelmodulok ............................................................................. 343
7.3.1. Hello modul vilg ...................................................................... 344
7.3.2. Fordts ..................................................................................... 346
7.3.3. A modulok betltse s eltvoltsa ......................................... 347
7.3.3.1. insmod/rmmod ................................................................. 347
7.3.3.2. modprobe ........................................................................... 347
7.3.4. Egymsra pl modulok ......................................................... 348
7.4. Paramtertads a modulok szmra ..................................... 351
7.5. Karakteres eszkzvezrl ........................................................... 353
7.5.1. F- s mellkazonost (major s minor number) ................... 354
7.5.2. Az eszkzllomnyok dinamikus ltrehozsa ......................... 355
7.5.3. llomnymveletek .................................................................. 356
7.5.4. Hasznlatszmll .................................................................... 357
7.5.5. Hello vilg driver ................................................................... 358
7.5.6. Az open s a release fggvnyek ............................................... 362
7.5.7. A mellkazonost (minor number) hasznlata ...................... 363
7.5.8. Az ioctl() implementcija ........................................................ 366
7.6. A /proc llomnyrendszer ........................................................... 370
7.7. A hibakeress mdszerei ............................................................ 375
7.7.1. A printk() hasznlata ................................................................ 375
7.7.2. A /proc hasznlata ................................................................... 376
7.7.3. Kernelopcik ............................................................................. 377
7.7.4. Az Oops zenet .......................................................................... 378
7.7.4.1. Az Oops zenet rtelmezse kernel esetben............... 379
7.7.4.2. Az Oops zenet rtelmezse kernelmodul
esetben ............................................................................. 380
Tartalomjegyzk
xi
7.7.5. Magic SysRq .............................................................................. 381
7.7.6. A gdb program hasznlata ....................................................... 382
7.7.7. A kgdb hasznlata .................................................................... 382
7.7.8. Tovbbi hibakeressi mdszerek ............................................. 383
7.8. Memriakezels a kernelben ..................................................... 384
7.8.1. Cmtpusok ................................................................................ 384
7.8.2. Memriaallokci ...................................................................... 384
7.9. A prhuzamossg kezelse ......................................................... 386
7.9.1. Atomi mveletek ....................................................................... 387
7.9.2. Ciklikus zrols (spinlock) ....................................................... 389
7.9.3. Szemafor (semaphore) .............................................................. 391
7.9.4. Mutex ......................................................................................... 392
7.9.5. Olvas/r ciklikus zrols (spinlock) s szemafor
(semaphore) ............................................................................... 393
7.9.6. A nagy kernelzrols ................................................................ 394
7.10. I/O mveletek blokkolsa ......................................................... 395
7.10.1. Elaltats .................................................................................. 396
7.10.2. Felbreszts ............................................................................. 397
7.10.3. Plda ........................................................................................ 398
7.11. A select() s a poll() tmogatsa .............................................. 403
7.12. Az mmap tmogatsa ................................................................. 404
7.13. I/O portok kezelse ..................................................................... 407
7.14. I/O memria kezelse ................................................................. 408
7.15. Megszaktskezels .................................................................... 410
7.15.1. Megszaktsok megosztsa .................................................... 412
7.15.2. A megszaktskezel fggvnyek megktsei ....................... 412
7.15.3. A megszakts tiltsa s engedlyezse ................................ 412
7.15.4. A szoftvermegszakts ............................................................ 413
7.15.5. A BH-mechanizmus ................................................................ 414
7.15.5.1. A kisfeladat (tasklet) ...................................................... 414
7.15.5.2. Munkasor ........................................................................ 417
7.16. A kernelszlak ............................................................................. 421
7.17. Vrakozs ..................................................................................... 423
7.17.1. Rvid vrakozsok .................................................................. 423
7.17.2. Hossz vrakozs ................................................................... 424
7.18. Idztk ......................................................................................... 425
7.19. Eszkzvezrl modell ................................................................ 426
7.19.1. A busz ...................................................................................... 426
7.19.2. Eszkz- s eszkzvezrl lista ................................................ 428
7.19.3. sysfs .......................................................................................... 429
7.19.4. Buszattribtumok exportlsa .............................................. 429
Tartalomjegyzk
xii
7.19.5. Az eszkzvezrl ..................................................................... 430
7.19.6. Eszkzvezrl attribtumok exportlsa .............................. 433
7.19.7. Az eszkz ................................................................................. 433
7.19.8. Az eszkz attribtumainak exportlsa ................................ 435
7.19.9. Plda ........................................................................................ 436
7.20. Tovbbi informcik ................................................................. 438
8. A Qt keretrendszer programozsa ........................ 439
8.1. Az X Window rendszer ................................................................. 439
8.1.1. Az X Window rendszer felptse ............................................. 439
8.1.2. X Windows kliensalkalmazsok ............................................... 440
8.1.3. Asztali krnyezet ...................................................................... 441
8.2. Fejleszts Qt alatt ......................................................................... 442
8.2.1. Hello Vilg! ................................................................................ 443
8.2.2. Projektllomnyok .................................................................... 447
8.2.3. A QObject szolgltatsai ........................................................... 448
8.2.4. A QtCore modul ......................................................................... 449
8.3. A Qt esemnykezels-modellje .................................................. 450
8.3.1. Szignlok ltrehozsa ............................................................... 452
8.3.2. Szlotfggvnyek ltrehozsa .................................................... 454
8.3.3. Szignlok s szlotok sszekapcsolsa ...................................... 455
8.3.4. Szlot az tmeneti objektumokban ............................................ 457
8.3.5. A Meta Object Compiler ........................................................... 458
8.4. Ablakok s vezrlk ..................................................................... 459
8.4.1. Dialgusablakok ksztse ....................................................... 460
8.4.2. A Qt vezrlkszlete ................................................................. 466
8.4.3. Sajt alkalmazsablakok ......................................................... 467
8.4.4. A fablak programozsa ........................................................... 469
8.4.5. Lokalizci ................................................................................ 479
8.4.6. Sajt vezrlk ksztse ............................................................ 483
8.5. A dokumentum/nzet architektra .......................................... 489
8.5.1. Az alkalmazs szerepe .............................................................. 491
8.5.2. A dokumentumosztly .............................................................. 493
8.5.3. A nzetosztlyok ....................................................................... 497
8.5.4. Tovbbi osztlyok ..................................................................... 503
8.6. Tovbbi technolgik .................................................................. 509
8.6.1. Tbbszl alkalmazsfejleszts ............................................... 509
8.6.2. Adatbziskezels ....................................................................... 516
8.6.3. Hlzati kommunikci ............................................................ 521
8.7. sszefoglals ................................................................................. 530
Tartalomjegyzk
xiii
A fggelk: Fejleszteszkzk ................................. 533
A.1. Szvegszerkesztk ....................................................................... 533
A.1.1. Emacs ........................................................................................ 533
A.1.2. vi (vim) ...................................................................................... 534
A.1.3. nano (pico) ................................................................................ 534
A.1.4. joe .............................................................................................. 534
A.1.5. mc .............................................................................................. 534
A.1.6. Grafikus szvegszerkesztk ..................................................... 535
A.2. Fordtk ......................................................................................... 535
A.2.1. GNU Compiler Collection ........................................................ 536
A.2.1. gcc .............................................................................................. 536
A.2.3. LLVM ........................................................................................ 540
A.3. Make ................................................................................................ 541
A.3.1. Megjegyzsek ............................................................................ 542
A.3.2. Explicit szablyok .................................................................... 542
A.3.3. Hamis trgy .............................................................................. 544
A.3.4. Vltozdefincik ...................................................................... 545
A.3.5. A vltoz rtkadsnak specilis esetei ................................ 546
A.3.6. Tbbsoros vltozk definilsa ................................................ 547
A.3.7. A vltoz hivatkozsnak specilis esetei .............................. 547
A.3.8. Automatikus vltozk .............................................................. 548
A.3.9. Tbbszrs cl ........................................................................... 549
A.3.10. Mintaszablyok ...................................................................... 550
A.3.11. Klasszikus ragozsi szablyok .............................................. 551
A.3.12. Implicit szablyok .................................................................. 552
A.3.13. Specilis trgyak .................................................................... 553
A.3.14. Direktvk ............................................................................... 554
A.4. Make alternatvk ........................................................................ 554
A.4.1. Autotools ................................................................................... 555
A.4.2. CMake ....................................................................................... 555
A.4.3. qmake ........................................................................................ 555
A.4.4. SCons ........................................................................................ 556
A.5. IDE ................................................................................................... 556
B fggelk: Hibakeress ......................................... 557
B.1. gdb ................................................................................................... 557
B.1.1. Plda a gdb hasznlatra ........................................................ 558
B.1.2. A gdb leggyakrabban hasznlt parancsai ............................... 561
B.1.3. A gdb indtsa .......................................................................... 561
B.1.4. Trspontok: breakpoint, watchpoint, catchpoint ................... 562
B.1.5. Data Display Debugger (DDD) ................................................ 566
B.1.6. Az IDE-k beptett hibakeresje ............................................. 567
Tartalomjegyzk
xiv
B.2. Memriakezelsi hibk .............................................................. 568
B.2.1. Malloc hibakeresk .................................................................. 569
B.2.1.1. Memriaterlet tlrsa .................................................. 570
B.2.1.2. Elrs .............................................................................. 571
B.2.1.3. Felszabadtott terlet hasznlata ................................... 571
B.2.1.4. Memriaszivrgs ............................................................ 571
B.2.1.5. A malloc hibakeresk korltai ........................................ 571
B.2.2. Electric Fence ............................................................................ 572
B.2.2.1. Az Electric Fence hasznlata ........................................... 572
B.2.2.2. A Memory Alignment kapcsol ........................................ 574
B.2.2.3. Az elrs .......................................................................... 574
B.2.2.4. Az Electric Fence tovbbi lehetsgei ............................. 575
B.2.2.5. Erforrsignyek .............................................................. 575
B.2.3. DUMA ....................................................................................... 576
B.3. Valgrind ......................................................................................... 576
B.3.1. Memcheck .................................................................................. 577
B.3.1.1. A memcheck modul mkdse ......................................... 578
B.3.2. Helgrind .................................................................................... 580
B.4. Rendszerhvsok monitorozsa: strace .................................. 582
B.5. Knyvtrfggvnyhvsok monitorozsa: ltrace ................. 582
B.6. Tovbbi hasznos segdeszkzk .............................................. 582
Trgymutat ........................................................ 585
Irodalomjegyzk ................................................... 593





Elszamsodikkiadshoz
Knyvnk els kiadsa ta a Linux fejldse tretlen. A begyazott szoftver-
rendszerek egyre nagyobb trhdtsnak ksznheten a Linux npszersge
is egyre n, ezen bell szmos mobileszkz kztk okostelefonok opercis
rendszerv vlt. Ezzel egytt az opercis rendszer programozsi fellete is
sokat fejldtt. Ezrt dntttnk gy, hogy a knyv els kiadsa alapos tdol-
gozsra, illetve kiegsztsre szorul. Munknk sorn csaknem minden fejeze-
tet trtunk, aktuliss tettnk, a kernel programozsval kapcsolatos rszt
teljesen jrartuk.
A Linux a kzelmltban volt hszves, az interneten nagyon sok cikk, pl-
daprogram s kzssgi oldalak llnak rendelkezsre. A Linux nagyon sokban
kveti a POSIX-szabvnyt, amely szmos tovbbi dokumentciforrst jelent.
gy vlemnynk szerint egy Linuxrl szl knyv akkor a leghasznosabb, ha
rendszerezi a programozshoz szksges ismereteket, a rendszer mkdst
mutatja be, s a programozs logikja vezeti a trgyalst. Knyvnkben gy
prblunk hathats segtsget nyjtani: az olvast bevezetjk a rendszer m-
kdsbe, nemcsak a mit? s hogyan? krdsekre adunk vlaszt programrszle-
tekkel illusztrlva, hanem a mirt? krdsre fektetjk a hangslyt, s arra
ptve mutatjuk be a tbbit. A legtbb esetben egy plda motivlja a bemuta-
tand megoldst, amelyet kln kiemelnk.
Feladat Ksztsnk megosztott knyvtrat a kerektst vgz fggvnynkkel.
A klnsen fontos kvetkeztetseket, j tancsokat tmutatkban ssze-
gezzk.
tmutat Ha a programozs szmunkra tbb mint ksz pldakdok sszefslse, majd azok
prblkozssal trtn kijavtsa, s idt sznunk a mkds megrtsre, sokkal bonyolul-
tabb hibkat sokkal elbb szrevesznk, ez kpess tesz minket Linux alatti szoftver terve-
zsre is.
Az els hat fejezet a Linux rendszer C nyelven hvhat alapfunkciit trgyalja,
egy fejezet a kernelmodulok ksztsrl szl, mg az utols fejezet az XWindow
rendszer programozst mutatja be C++ nyelven Qt-krnyezetben. A knyv
alapjt a Budapesti Mszaki s Gazdasgtudomnyi Egyetem Villamosmr-
nki s Informatikai Karn vlaszthat Linux-programozs tantrgy el-
Elszamsodikkiadshoz
xvi
adsai s laborfoglalkozsai kpezik. A knyv els fejezetei azt felttelezik,
hogy az olvas tisztban van a C s C++ nyelvek alapjaival, az alapvet adat-
struktrkkal, s rendelkezik az elemi programozstechnikai ismeretekkel,
amelyek pldul az [1,2,3] irodalmi hivatkozsnak megfelel knyv feldolgo-
zsnak eredmnyeknt szerezhetk meg. Olyan olvaskra is szmtunk,
akik Linux alatt prblnak elszr komolyabban programozni, ezrt a fonto-
sabb fejleszteszkzket s magt az opercis rendszert teljesen az alapoktl
trgyaljuk, s a fggvnyhvsokat olyan rszletessggel mutatjuk be, hogy
azokat kzvetlenl fel lehessen hasznlni. Ahol csak tehettk, az egyes funk-
cikat egyszer pldkkal illusztrltuk. Remnyeink szerint azok, akik fel-
dolgozzk a knyv els hat fejezett, kpesek lesznek arra, hogy nllan
megtalljk s rtelmezzk azokat a tovbbi Linuxszal kapcsolatos inform-
cikat, amelyekre szksgk van a fejleszts sorn. Ebben a kiadsban kl-
nsen a szoftvertervezket prbljuk segteni: bemutatjuk, hogy a Linux ltal
biztostott megoldsok milyen logikt kvetnek, melyek a jrhat utak, s
mik ezek elnyei/htrnyai, valamint melyik mdszer mikor hatkony.
Azok szmra, akik ipari projektet indtannak, bemutatunk nhny
olyan eszkzt (grafikus fejleszti krnyezet A fggelk, a memriaszivr-
gst feldert programok, hibakeresk B fggelk), amelyek nlkl hosz-
szabb programok rsa nehzkes s hosszan tart volna.
A grafikus fejleszts bemutatsakor dntennk kellett, hiszen a szmos
eszkzkszlet mindegyikt nem mutathatjuk be. Vlasztsunk a Qt-re esett
mivel elterjedt mind asztali, mind begyazott krnyezetben, valamint jl
strukturlt fejleszti eszkzkszlet.
gy gondoljuk, hogy a grafikus felhasznli fellet programozsa s terve-
zse ma mr kiforrottnak mondhat, gy ha valaki egy krnyezetet megismer,
gyakorlatt minimlis vltoztatsokkal ms rendszerekben is alkalmazni tud-
ja. A Qt alatti programozssal foglalkoz rszek halad C++-programozi szin-
tet feltteleznek. A C++ nyelv szksges elemeit a [2] irodalmi hivatkozs els
12 fejezete, illetve a [3] hivatkozs ismerteti.
A knyvet tanknyvknt hasznlk szmra a kvetkez fejezetek feldol-
gozst javasoljuk:
Linuxot hasznl C kurzus: A fggelk, (bevezets a nyelvi elemek-
be, szabvnyos knyvtri fggvnyek, pldul [1] alapjn): 4, 5, 6.
Opercis rendszerek alapjai kurzus gyakorlati illusztrlsa: 15.
Linux-programozsi kurzus: A fggelk , B fggelk, 18.
Tovbbra is igyekeztnk, hogy az egyes fejezetek a lehetsgekhez mrten s
a tma jellegtl fggen nll egszet alkossanak, esetleges rvidebb ismt-
lsek rn is.
Az itt lert tananyag szmonkrse a tma jellege miatt klnsen nehz-
kes. Ezt megknnytend a szmon krhet fogalmakra, valamint a fontosabb
mondanivalra vastag betkkel hvtuk fel a figyelmet. A foly szvegben
Elszamsodikkiadshoz
xvii
gyakran hivatkozunk a programkdban szerepl vltozkra, konstansokra,
makrkra stb. Ezeket dlt betkkel szedtk az elklnthetsg miatt. A prog-
ramrszleteket, a parancssorba beviend parancsokat s szkripteket szrke
httr jelzi.
A szerzk trekedtek arra, hogy a knyvben szerepl kdrszek elektroni-
kusan is hozzfrhetk legyenek, ezek a pldk az albbi oldalon rhetk el:
http://szak.hu/linux.
Jelen munkban felhasznltuk a Linux sajt dokumentciit, gy az info
s a man oldalakat, a POSIX-szabvnyokat. Az egyes forrsokat a knyv jel-
lege s a trgyals folyamatossga miatt nem jelltk kln, az irodalomjegy-
zkben sszegeztk ket.
Az egyes j fogalmaknak magyar megfeleli mellett kerek zrjelben k-
zljk azok angol megfelelit a tovbbi tjkozds megknnytshez.
Elsknt szeretnnk megksznni Vlgyesi Pternek klnsen gondos
lektori munkjt s rtkes tancsait. Ksznjk Lattman Zsolt, Szilvsi
Sndor, Horvth Pter s Babjk Benjamin visszajelzseit s a kzirat
egyes rszeinek tolvasst. Ksznjk tovbb Laczk Krisztina olvas-
szerkeszti munkjt, amely jelentsen nvelte a kzirat szvegnek ignyes-
sgt s rthetsgt, valamint Mamira Gyrgynek a kzirat trdelst.
Ksznetnket szeretnnk kifejezni Szilvsi Sndornak a fedlbort
kls megjelensnek az elksztsrt, az Institute for Software Integrated
Systems kutatintzetnek (Vanderbilt Egyetem, Nashville, Tennessee, USA),
valamint az Automatizlsi s Alkalmazott Informatikai Tanszk (Budapesti
Mszaki s Gazdasgtudomnyi Egyetem) Alkalmazott Informatika Csoport-
jnak, hallgatinknak s a SZAK Kiad munkatrsainak.
Vgl pedig tovbbra is bzunk abban, hogy ez a knyv sokak szmra
lesz megbzhat segtsg tanulmnyaik s munkik sorn, s remnyeink
szerint akad nhny olyan olvas, aki szabadidejt nem kml, lelkes tagja
lesz a szabad szoftverek nkntes fejlesztgrdjnak.


Budapest, 2012. oktber

A szerzk

ELS FEJEZET
Bevezets
1.1. A Linux
A Linux sznak tbb jelentse is van. Mszaki rtelemben pontos defincija
a kvetkez:
A Linux szabadon terjeszthet, Unix1-szer opercisrendszer -kernel.
A legtbb ember a Linux sz hallatn azonban a Linux-kernelen alapul tel-
jes opercis rendszerre gondol. gy ltalban az albbiakat rtjk rajta:
A Linux szabadon terjeszthet, Unix-szer opercis rendszer, amely
tartalmazza a kernelt, a rendszereszkzket, a programokat s a teljes
fejleszti krnyezetet.
A tovbbiakban mi is a msodik jelentst vesszk alapul, vagyis a Linuxot
mint opercis rendszert mutatjuk be.
A Linux kivl, ingyenes platformot ad a programok fejlesztshez.
Az alapvet fejleszteszkzk a rendszer rszt kpezik. Unix-szersgbl ad-
dan programjainkat knnyen tvihetjk majdnem minden Unix- s Unix-szer
rendszerre. Tovbbi elnyei a kvetkezk:
A teljes opercis rendszer forrskdja szabadon hozzfrhet, hasz-
nlhat, vizsglhat s szksg esetn mdosthat.
Ebbe a krbe beletartozik a kernel is, gy komolyabb, a kernel mdos-
tst ignyl problmk megoldsra is lehetsgnk nylik.
A Unix egy 1960-as vekben keletkezett tbbfelhasznls opercis rendszer, amelynek
nagy rszt C nyelven rtk az AT&T cgnl. vtizedekig a legnpszerbb opercis
rendszerek egyike volt. A System V az AT&T ltal fejlesztett Unix alapverzijnak a ne-
ve. A msik jelents vltozat a kaliforniai Berkeley Egyetemhez ktdik, ez a Berkeley
Software Distribution, rviden BSD.
1. fejezet: Bevezets
A Linux fejlesztse nem profitorientlt fejlesztk kezben van, gy fej-
ldsekor csak mszaki szempontok dntenek, marketinghatsok
nem befolysoljk.
A Linux-felhasznlk s -fejlesztk tbora szles s lelkes. Ennek k-
vetkeztben az interneten nagy mennyisg segtsg s dokumentci
tallhat.
Az elnyei mellett termszetesen meg kell emltennk a htrnyait is. A de-
centralizlt fejleszts s a marketinghatsok hinybl addan a Linux nem
rendelkezik olyan egysges, felhasznlbart kezeli fellettel, mint a ver-
senytrsai, belertve a fejleszti eszkzk fellett is. Ennek ellenslyozsra
az egyes disztribcik kszti tbbnyire trekednek arra, hogy a kezkbl
kiadott rendszer egysges, jl hasznlhat felletet nyjtson. m a disztrib-
cik mennyisge ugyanakkor megneheztheti a fejlesztk dolgt, ha minden
rendszeren tmogatni szeretnk a programcsomagjukat.
2

Mindezek figyelembevtelvel azonban a Linux gy is kivl lehetsgeket
nyjt a fejlesztsekhez, elssorban a grafikus felhasznli fellettel nem ren-
delkez programok terletn, de hathats tmogatst biztost grafikus kli-
ensalkalmazsok szmra is.
A Linux rendszerek hasznlata a begyazott eszkzk terletn a legjelen-
tsebb. Szmos olyan eszkzt tallhatunk manapsg az otthonokban, amelyek-
rl sokszor nem is tudjuk, hogy rajtuk egy Linux rendszer teszi a httrben a
dolgt (pldul otthoni router, DVD felvev/lejtsz, fnykpezgpek stb.).
A begyazott alkalmazsok egy kln csoportjt alkotjk a mobiltelefo-
nok. A Linux rendszer szmos mobiltelefon opercis rendszernek is az alapja.
Ezek egy rsze lnyegben csak a kernelt s a fbb fejleszti knyvtrakat
hasznlja (pldul az Android), de tallhatunk olyat is, amelyik szinte egy
teljes linuxos szmtgpnek felel meg.
1.2. A szabad szoftver s a Linux trtnete
1.2.1. FSF
A szmtstechnika hajnaln a cgek kis jelentsget tulajdontottak a szoft-
vereknek. Elssorban a hardvert akartk eladni, a szoftvereket csak jrul-
kosan adtk hozz, zleti jelentsget nem tulajdontottak neki. Ez azt ered-
mnyezte, hogy a forrskdok, az algoritmusok szabadon terjedhettek.
2
A klnbz disztribcik okozta problmban segtsget nyjt a ksbb emltett LSB-
projekt.
2
1.2. A szabad szoftver s a Linux trtnete
m ez az idszak nem tartott sokig, a gyrtk hamar rjttek a szoftver-
ben rejl zleti lehetsgekre, s ezzel beksznttt a zrt forrskd progra-
mok korszaka. Ez lnyegben azt jelenti, hogy a szoftverek forrskdjt, mint
szellemi termkeket, a cgek levdik, s zleti titokknt szigoran rzik.
Ezek a vltozsok nem nyertk el az akkoriban a Massachusettsi Msza-
ki Egyetemen (Massachusetts Institute of Technology, MIT) dolgoz Richard
Stallman tetszst. gy megalaptotta a Free Software Foundation (FSF) el-
nevezs szervezetet a massachusettsi Cambridge-ben. Az FSF clja a szaba-
don terjeszthet szoftverek fejlesztse lett.
1.2.2. GPL
Az FSF nevben a free" szabadsgot jelent, nem ingyenessget. Stallman hi-
te szerint a szoftvernek s a hozztartoz dokumentcinak, forrskdnak
szabadon hozzfrhetnek s terjeszthetnek kell lennie. Ennek elsegtsre
megalkotta (nmi segtsggel) a General Public License-t (GPL, magyarul: l-
talnos felhasznli licenc), amelyet 1989-tl hasznltak.
A GPL hrom f irnyelve a kvetkez:
1. Mindenkinek, aki GPL-es szoftvert kap, megvan a joga arra, hogy in-
gyenesen tovbbadja a forrskdjt. (Leszmtva a terjesztsi klts-
geket.)
2 . Minden szoftver, amely GPL-es szoftverbl szrmazik, szintn GPL-es
kell, hogy legyen.
3. A GPL-es szoftver birtokosnak megvan a joga ahhoz, hogy a szoftve-
reit olyan felttelekkel terjessze, amelyek nem llnak konfliktusban a
GPL-lel.
A GPL egyik jellemzje, hogy nem nyilatkozik az rrl. Vagyis a GPL-es szoft-
vertermkeinket szabadon rtkesthetjk. Egyetlen kikts az, hogy a forrs-
kd ingyenesen jr a szoftverhez. A vev ezutn azonban szabadon terjesztheti
a programot s a forrskdjt. Az internet elterjedsvel ez azt eredmnyezte,
hogy a GPL-es szoftvertermkek ra alacsony lett (sok esetben ingyenesek),
de lehetsg nylik ugyanakkor arra is, hogy a termkhez kapcsold szolgl-
tatsokat, tmogatst trts ellenben nyjtsk.
A GPL licenc 2 -es verzija 1991 nyarn szletett meg, s a szoftverek je-
lents rsze ezt hasznlja.
Mivel a megktsek nagyon szigornak bizonyultak a fejleszti knyvt-
rakkal kapcsolatban, ezrt megszletett az LGPL licenc (eredetileg Library
General Public License, ksbb GNU Lesser General Public License) krlbell
a GPLv2 -vel egy idben. Az LPGL els vltozata a 2 -es verziszmot kapta.
3
1. fejezet: Bevezets
Idkzben azonban megjelentek olyan gyrtk, akik kreatvan" rtelmez-
tk a GPLv2 licencet. A szveget betartottk, m az alapelvet megsrtettk.
3

A problmk orvoslsra 2 007 nyarn jelent meg a GPLv3. A GPLv3 fogadta-
tsa azonban vegyes volt, ezrt sokan maradtak a GPLv2 -nl.
A GPLv3-mal prhuzamosan egy j licenc is szletett reaglva a kor kih-
vsaira, nevezetesen a hlzaton fut alkalmazsokra, ilyenek pldul a webes
alkalmazsok. Ez az j licenc az AGPLv3 (Affero General Public License).
1.2.3. GNU
Az FSF ltal tmogatott legfbb mozgalom a GNU's Not Unix (rviden GNU)
projekt, amelynek az a clja, hogy szabadon terjeszthet Unix-szer opercis
rendszert hozzon ltre. Ez a projekt nagyon sokat adott hozz a Linux rend-
szerhez. Csak a legfontosabbakat emltve: a C fejleszti knyvtr, a GNU
Compiler Collection, amely a legelterjedtebb fordt eszkzcsomag, a GDB,
amely a f hibakeres program, tovbb szmos, a rendszer alapjaknt szol-
gl segdprogram.
1.2.4. Linux-kernel
A Linux-kernel trtnete 1991-re nylik vissza. Linus Torvalds, a helsinki
egyetem dikja ekkor kezdett bele a projektbe. Eredetileg az Andrew S. Ta-
nenbaum ltal tanulmnyi clokra ksztett Minix opercis rendszert hasz-
nlta a gpn. A Minix az opercis rendszerek mkdst, felptst volt
hivatott bemutatni, ezrt egyszernek, knnyen rtelmezhetnek kellett ma-
radnia Emiatt nem tudta kielgteni Linus Torvalds ignyeit, aki ezrt bele-
vgott egy sajt, Unix-szer opercis rendszer fejlesztsbe.
Eredetileg a Linux-kernelt gyenge licenccel ltta el, amely csak annyi
korltozst tartalmazott, hogy a Linux-kernel nem hasznlhat fel zleti c-
lokra. m ezt rvidesen GPL-re cserlte. A GPL felttelei lehetv tettk ms
fejlesztknek is, hogy csatlakozzanak a projekthez.
4
A MINIX kzssg jelen-
ts mrtkben tmogatta a munkt. Abban az idben nagy szksg volt egy
szabad kernelre, mivel a GNU-projekt kernelrsze mg nem kszlt el, a BSD
rendszerrel kapcsolatban pedig jogi problmk merltek fel. A pereskeds k-
zel kt vig gtolta a szabad BSD-vltozatok fejlesztst. Ez a krnyezet
nagyban hozzjrult a Linux megszletshez.
Egyes cgek, br betartottk a GPLv2 licencet, s kiadtk az ez al tartoz forrskdo-
kat, a hardverben azonban olyan trkkket alkalmaztak, mint a digitlis alrst, amely-
lyel megakadlyoztk, hogy rajtuk kvl brki ms j szoftververzit fordthasson s
telepthessen az eszkzre. A szakzsargonban ez a mdszer tivoization" nven terjedt el,
mivel a TiVo cg alkalmazta elszr.
4
A Linux-kernel jelenleg a GPLv2 licencet hasznlja.
4
1.2. A szabad szoftver s a Linux trtnete
A Linux-kernel fejldsnek llomsai a kvetkezk:
1991. szeptember: a Linux 0.01-es verzija megjelent az ftp.funet.fi
szerveren, amely a finn egyetemi hlzat llomnyszervere.
1991. oktber: Linux 0.02 .
1991. december: Linux 0.11 az els nhord Linux. Vagyis a Linux-
kernel ettl kezdve fordthat a Linux rendszeren. A korbbi fejlesz-
tsek Minix alatt trtntek.
1992 . februr: Linux 0.12 az els GPL licences kernel.
1992 . mrcius: Linux 0.95 az X Windows rendszert tltettk Li-
nuxra, gy mr grafikus felletet is kapott.
1994 . mrcius: Linux 1.0.0 a gyors fejldst ltva hamarabb vrta
mindenki, de kellett mg nhny fejleszti verzi, mire elg rett
vlt a rendszer. Ez a kernel is mg csak egy processzort s csak i386-
os architektrt tmogatott.
1995. mrcius: Linux 1.2 .0 a Linux megrkezett ms architektrk-
ra is. Az Alpha, az SPARC s a MIPS rendszerek is bekerltek a t-
mogatott platformok kz.
1996. jnius 9: Linux 2 .0.0 megjelent a tbbprocesszoros rendszerek
tmogatsa (SMP).
1999. janur 2 5: Linux 2 .2 .0 javult az SMP tmogatsa, megjelent a
tmogatott rendszerek kztt az m68k s a PowerPC.
2 001. janur 4 : Linux 2 .4 .0 megjelent az ISA PnP-, az USB- s a PC-
krtya- (PC card) tmogats. Tovbb a tmogatott architektrk k-
z bekerlt a PA-RISC. Ez a verzi abban is ms a korbbiaknl, hogy
a felgyorsult fejlds hatsra mr a stabil vltozatnak is egyre tbb
jdonsgot kellett tvennie, ilyen pldul a Bluetooth, az LVM, a
RAID, az ext3 llomnyrendszer.
2 003. december 17: Linux 2 .6.0 megvltozott, felgyorsult a fejleszt-
si modell. Nincs kln stabil s fejleszti vonal, hanem sokkal rvi-
debb ciklusokban ebbe a vonulatba kerl bele minden jts. Emellett
szmos jtst s j architektrk tmogatst hozta ez a verzi,
ezrt ezek felsorolsra jelen keretek kzt nem vllalkozunk.
2 011. jlius 2 2 : Linux 3.0 a Linux 2 0 ves vfordulja alkalmbl je-
lent meg. A verzivlts jelkpes, mivel a fejlesztsek folyamatosan
belekerltek a 2 .6.x kernelekbe. gy az j verzi technikai jtst nem
hozott a 2 .6.39-es verzihoz kpest. Megvltozott a verziszm felp-
tse, mivel a fejlesztsi modell szksgtelenn tette a hrom szintet.
5
1. fejezet: Bevezets
1.2.5. A Linux rendszer
A Linux-projekt mr a kezdetektl szorosan sszefondott a GNU-projekttel.
A GNU-projekt forrskdjai fontosak voltak a Linux-kzssg szmra a
rendszerk felptshez. A rendszer tovbbi jelents rszletei a kaliforniai
Berkley Egyetem nylt Unix-forrskdjaibl, illetve az X konzorciumtl szr-
maznak.
A klnbz Unix-fajtk egysgestett programozi felletnek ltrehoz-
sra szletett meg a C nyelven definilt POSIX- (Portable Operating System
Interface) szabvny a sz vgn az X a Unix vilgra utal , amelyet a Li-
nux implementlsakor is messzemenkig figyelembe vettek.
Szintn a Unix-fajtk egysgestsre jtt ltre a SUS (Single UNIX Spec-
ification), amely egy szabvnygyjtemny. A SUS aktulis verziinak a mag-
jt a POSIX-szabvnyok alkotjk. A SUS definilja a headerllomnyokat, a
rendszerhvsokat, a knyvtri fggvnyeket s az alapvet segdprogramo-
kat, amelyeket egy Unix rendszernek nyjtania kell. Emellett informcikat
tartalmaz a szabvnyok mgtt ll megfontolsokrl is.
6

A Linux hasonlan ms nylt opercis rendszerekhez nem rendelkezik a
SUS Unix tanstvnyval. Ennek oka rszben a tanstvny megszerzs-
nek kltsge, msrszt a Linux gyors fejldse, amely tovbbi extrakltsget
jelentene a tanstvny megtartshoz. Ugyanakkor a rendszer fejleszti tre-
kednek a SUS-szabvnyok teljestsre. Ezen okokbl a Linuxra a Unix-szer
(Unix-like) jelzt hasznljuk.
1.2.6. Linux-disztribcik
Az els Linux-disztribci (terjesztsi csomag) megjelense eltt, ha valaki
Linux-hasznl akart lenni, akkor jl kellett ismernie a Unix rendszereket, a
Linux felptst, konfigurlst, elindulsnak a folyamatt. Ennek az az
oka, hogy a hasznlnak kellett a komponensekbl felptenie a rendszert.
Belthatjuk, hogy ez jelents akadlyt jelentett a rendszer elterjedsben, hi-
szen a kezdknek nem sok eslyk volt megismerni a rendszert.
Ezrt, amint a Linux rendszert a Linux-fejlesztin kvl msok is elkezdtk
hasznlni, megj elentek az els disztribcik. A korai disztribcik tbbnyire
lelkes egynek csomagjai voltak. Nhny a korai disztribcikbl: Boot-root,
MCC Interim Linux, TAMU, SLS, Yggdrasil Linux/GNU/X.
5
Jelenleg a POSIX-szabvny az IEEE Std 1003.1-2 008 szabvnyt jelenti, amelyet POSIX.1-
2 008-knt rvidtenek. A POSIX-implementcik eltrhetnek, ugyanis a szabvny csak fe-
lletet hatroz meg, nem megvalstst. Legegyszerbben a man oldalak vgn talljuk
meg egy adott fggvny POSIX-kompatibilitst.
6
Jelenleg a SUS 3-as verzija a legelterjedtebb, amely a POSIX:2 001-es szabvnyon alapul.
Az a rendszer amelyik ezt teljesti az jogosult a UNIX 03 cmke hasznlatra. A POSIX:2 008 a
SUSv4 alapjt szolgltatja.
6
1.2. A szabad szoftver s a Linux trtnete
Az els jelents disztribci az 1993-ban megjelent Slackware volt, amelyet
az SLS-disztribcibl alaktott ki Patrick Volkerding. A Slackware tekinthet
az els olyan csomagnak, amelyet mr komolyabb httrtuds nlkl is lehetett
installlni s hasznlni. Megszletse nagyban elsegtette a Linux terjedst,
npszersgnek a nvekedst.? A Slackware egyben az alapjt szolgltatta
tbb ksbbi rendszernek is, pldul a Red Hatnek s a SuSE-nek.
A Slackware mellett azonban az SLS miatti elgedetlensg egy msik
disztribci megszletshez is hozzjrult. Ian Murdock elindtotta a Debian
projektet (a disztribci neve a felesge, Debra s sajt keresztnevnek ssze-
olvasztsa). A Debian szintn 1993-ban szletett, m az els 1.x verzi csak
1996 nyarn jelent meg. A Debian szmos tovbbi disztribci alapjaknt
szolglt s szolgl mai is.
A Red Hat Linux-disztribci 1994 novemberben jelent meg az 1.0-s ver-
zival. Ez volt az els olyan disztribci, amely az RPM csomagkezeljt
hasznlta. Ez nagy elrelpst jelentett, ugyanis sokkal knnyebb tette a
szoftvercsomagok adminisztrlst, teleptst, frisstst. Ez is hozzjrult
a Linux tovbbi elterjedshez, mert felhasznlbart, teljes rendszert bizto-
stott. Emellett a Red Hat cg olyan szint tmogats nyjtott a termkhez,
amely lehetv tette, hogy a cgek is komolyan fontolra vegyk a rendszer
hasznlatt. 2 003-ban a Red Hat Linux ebben a formjban megsznt. He-
lyette a Red Hat Enterprise Linux (RHEL) rendszert ajnlja a cg vllalati
krnyezetbe, illetve letre hvta s tmogatja a Fedora Projectet, amely a Fe-
dora disztribcit tartja karban. Az zleti vilgban az RHEL az egyik legnp-
szerbb disztribci.
Napjaink egyik leggyakrabban hasznlt Linux-disztribcija a Debian-
alap Ubuntu. A disztribci egy dl-afrikai humanista filozfirl kapta a
nevt, amelynek lnyege a msok irnti embersgessg: azrt vagyok az, aki
vagyok, amirt mi mindannyian azok vagyunk, akik vagyunk". A rendszert
a dl-afrikai Mark Shuttleworth alaptotta Canonical Ltd. fejleszti, amely a
termktmogatst pnzrt rulja, ugyanakkor az opercis rendszer ingye-
nes. Az els verzi 2 004 oktberben jelent meg.
Az eddig emltett disztribcikat szmos jabb is kvette, amelyek kln-
bz clok mentn fejldtek. gy lehetsgnk van kicsi s gyors, nagy s ltv-
nyos, stabil s kevsb aktulis vagy nem annyira stabil, de minden jdonsgot
tartalmaz rendszert is vlasztani. A disztribcik listja rendkvl hossz, gy
nem is vllalkozunk a felsorolsukra. Az interneten megtallhatjuk a neknk
legszimpatikusabbat.
m ha magyar nyelv s magyarok ltal gondozott disztribcit szeret-
nnk, akkor erre is van lehetsgnk az UHU Linux- (http: / / uhulinux.hu)
disztribci rvn. Az oktatsi intzmnyek szmra kifejlesztett SuliX
(http: / / www.sulix.hu) szintn ebbe a kategriba tartozik.
7
Jelen rs szerzje is a Slackware disztribcija rvn tallkozott elszr a Linux rend-
szerrel 1993 vgn.
7
1. fejezet: Bevezets
A Linux-disztribcik ltalban a fejleszti knyvtrakat, a fordtkat, az
rtelmezket, a parancsrtelmezket, az alkalmazsokat, a segdprogramo-
kat, a konfigurcis s csomagkezel eszkzket s mg sok ms komponenst
is tartalmaznak a Linux-kernel mellett. Az alapelemek tbbnyire megegyeznek
a disztribcikban, csak eltr verzikkal, illetve kisebb-nagyobb mdostsok-
kal tallkozhatunk. Az opcionlis fejleszti knyvtrak mr nem minden diszt-
ribciban lelhetk fel, de forrsbl lefordthatjuk ket hozzjuk.
8

Mivel a klnbz Linux-disztribcik nagymrtkben eltrhetnek egyms-
tl, ezrt felhasznlk s a fejlesztk szmra jelents problmt jelenthet a
klnbzsgek kezelse. Felismerve a problmt a Linux-disztribcik ksz-
ti ltrehoztk az LSB (Linux Standard Base) projektet, amelynek clja a rend-
szerstruktra egysgestse s szabvnyostsa. Ennek eredmnye az is, hogy
a klnbz Linux rendszereken nagyjbl egysges knyvtrstruktrkkal ta-
llkozunk. Az LSB a korbban emltett POSIX- s SUS-specifikcikat veszi
alapul, illetve ezek mellett szmos nylt szabvnyra is pt. Fejlesztknt
az LSB-projekt hatalmas segtsget nyjt neknk, mivel gy egysgesen kezel-
hetjk a Linux rendszert, s a szoftvereink szmos disztribcin lesznek m-
kdkpesek.
A knyv tematikjnak kialaktsakor trekedtnk arra, hogy lehetsg
szerint disztribcifggetlenek legynk. gy a trgyalt tmakrk minden
disztribci esetn alkalmazhatk, illetve a fejleszti eszkzket is gy v-
lasztottuk ki, hogy lehetleg ltalnosan elrhetk legyenek. m a pldaprog-
ramok fordtsakor idnknt tallkozhatunk azzal a problmval, hogy egyes
disztribcik esetben a knyvtrstruktra eltrhet. Viszont az LSB-t kvet
disztribciknl ennek minimlis az eslye.
1.3. Informciforrsok
A Linux trtnete sorn mindig is ktdtt az internethez. Internetes kzs-
sg ksztette, fejlesztette, terjesztette, gy a dokumentcik nagy rsze is az
interneten tallhat. Ezrt a legfbb informciforrsnak is az internetet te-
kinthetjk.
A Linux-vilg egyik klasszikus informciforrsa a Linux Documentation
Project (Linux dokumentcis projekt, LDP). Az LDP elsdleges feladata magas
szint, ingyenes dokumentcik fejlesztse a GNU/Linux opercis rendszer
szmra. Cljuk minden Linuxszal kapcsolatos tmakr lefedse a megfelel
dokumentumokkal. Br sok dokumentum nem teljesen aktulis, ennek elle-
8
Gyakran elhangzik a krds: melyik a legjobb disztribci? Szerintnk ilyen nincs, csak
olyan, amely elg kzel ll a felhasznl egyni ignyeihez, s mr nem kell olyan sokat
dolgoznia rajta, hogy teljesen a sajt kpre alaktsa. Ha rosszul vlaszt kiindulsi ala-
pot, akkor tbb munkja lesz vele.
8
1.3. Informciforrsok
nre is az egyik legjelentsebb informciforrsnak tekinthet. Az egyes Li-
nux-disztribtorok sokszor nagyon komoly s jl hasznlhat dokumentcit
ksztenek. m ezek a dokumentcik tbbnyire az adott disztribci haszn-
latrl, adminisztrlsrl szlnak. Szoftverfejlesztsrl ritkn tallunk do-
kumentcikat. Az LDP ltal elksztett dokumentumok a kvetkez cmen
tallhatk meg: http:/ / www.tldp.org / .
A kziknyvoldalak (manual page, rvidtve man page) a Unix klasszi-
kus elektronikus dokumentcis formja, amelyet a Linux is rklt. Ezek az
oldalak eredetileg a man segdprogrammal jelenthetk meg, de manapsg
HTML s egyb formtumban is elrhet. Emiatt magyarul szmos elnevez-
sk van, legtbben az angol elnevezst hasznljk, rott formban sokszor csak
kziknyv" hasznlatos. Az els kziknyveket a Unix szerzi rtk a hetvenes
vek legelejn. A tagolsa egysges, a POSIX-szabvny is ezzel a felptssel r-
ja le az egyes interfszeket, ezek a lersok kziknyvek formjban is ren-
delkezsre llnak sokszor kiegsztve az adott platformra jellemz tovbbi
informcival, esetleg eltrsekkel. Ez a mai napig az egyik legfontosabb do-
kumentci. Az info formtumot a GNU vezette be, ez kpes linkeket s egyb
formzsokat is kezelni.
A HOWTO-k egy-egy konkrt problma megoldst nyjtjk. Szmos
formtumban (HTML, PostScript, PDF, egyszer szveg) elrhetk. Az t-
mutat (guide) kifejezs az LDP ltal ksztett knyveket jelli. Ezek egy-egy
tmakr bvebb kifejtst tartalmazzk.
Fejlesztknt a fejleszti knyvtrak dokumentciinak vehetjk a leg-
nagyobb hasznt. Minden fejleszti knyvtr honlapjn tallunk minimlisan
egy API-dokumentcit. Gyakran tallkozhatunk azonban komoly lersok-
kal, gyakorlpldkkal is.
Az LWN (http:/ / lwn.net) a Linux-vilg hrlapja. Igyekszik sszegyjteni
minden jdonsgot a Linux vilgbl. Az ltalnos hrek mellett a Develop-
ment rovatbl tjkozdhatunk a legjabb fejleszti hrekrl, mg a Kernel
rovat a kernelfejleszts irnt rdekldknek szolgl friss informcikkal.
Ha a feladatunkkal elakadnnk, szmos frumot tallhatunk az interneten
, ahol feltehetjk a krdseinket. Radsul sokszor az is elfordul, hogy
msok mr feltettk a krdst, s mr meg is vlaszoltk. gy ha elakadunk,
akkor gyakran a legnagyobb segtsget a webes keresk jelentik, amelyek
megtalljk a kvnt frumbejegyzseket, st a kziknyvek s a howtok k-
ztt is kpesek keresni.
9
MSODIK FEJEZET
Betekints a Linux-
kernelbe
Ebben a fejezetben a Linux-kernel egyes rszeivel ismerkednk meg. A kvet-
kez ismeretek nem elengedhetetlenek ahhoz, hogy a knyv tovbbi fejezetei-
ben tallhat pldaprogramokat kzvetlenl felhasznljuk, a fejezetek megr-
tshez azonban igen. Ezek a tudnivalk megvilgtjk, hogy mi zajlik le a
rendszer bels magjban a programunk futsa kzben, gy hasznos httr-
informcit szolgltathatnak a fejlesztk szmra. Ez a fejezet teht egyfajta
ttekintst kvn nyjtani. A tovbbi, specializlt rszekben sokszor rszlete-
sebben trgyaljuk az itt bemutatottakat.
2.1. A Linux-kernel felptse
Egy opercis rendszer magjnak strukturlis felptsnl kt alapvet szls-
sges vlasztsunk van. Vlaszthatunk a mikrokernel- s a monolitikus-
kernel-struktra
kztt. A lnyegi klnbsg a kett kztt az, hogy milyen
szolgltatsokat valstanak meg a felhasznli cmtrben, illetve a kernel
cmterben. A mikrokernel csak a legszksgesebb opercisrendszer-szolgl-
tatsokat futtatja a kernelben, mg a tbbit a rugalmassg rdekben a fel-
hasznli cmtartomnyban implementlja. Ezzel szemben a monolitikus
kernelben a legtbb szolgltats a kernel rszeknt fut a nagyobb teljest-
mny rdekben. A kett kztt flton a hibrid kernel tallhat. Vegytiszta
megoldsok egyre kevsb vannak: a mikrokernel-architektrkon a jobb tel-
jestmny miatt bizonyos alacsony szint szolgltatsokat thelyeznek a ker-
nelbe (pl. a grafikusvezrlk). A monolitikus kernel esetben rszben a
rugalmassg, rszben a teljestmnymaximalizls rdekben tesznek t
funkcikat a felhasznli tartomnyba. A Linux a monolitikuskernel-megkze-
ltshez ll kzelebb, a gykerei oda nylnak vissza.
2 . fejezet: Betekints a Linux-kernelbe
A mikrokernel s monolitikus kernel kategritl fggetlenl a modern
opercis rendszerek kernele dinamikusan betlthet modulokbl pl fel, gy
hasznlat kzben az ignyeknek megfelelen bvthet vagy cskkenthet.
A struktrk alapjainak megismerse utn nzzk meg, milyen rszekre
oszthatjuk fel a Linux-kernelt. (Ez a feloszts vzlatos, a knnyebb rthetsg
rdekben nem tr ki a rendszer minden rszletre.)

Felhasznli processzek









Fejleszti knyvtrak (pl glibc)






Kernel




Rendszerhvsok




Processzkezel




llomnyrendszerek


temez







Hlzati rteg

Memria-
kezel




Egyb alrendszerek )



IPC





Perifrik kezelse


Hardver
2.1. bra. A kernel vzlatos felptse
A felhasznli programok a rendszerhvsokon keresztl krhetik a kerneltl
a kvnt szolgltatsokat. Ezeket a rendszerhvsokat a programok ltalban
a rendszerknyvtrak segtsgvel rik el.
A fjlrendszerek magasabb szint absztrakcit nyjtanak a perifrik
kezelsre. Ennek az alrendszernek a segtsgvel kezelhetnk llomnyokat,
knyvtrakat az egyes eszkzkn (ilyen llomnyrendszerek az ext4 , a proc,
az MSDOS, az NTFS, az iso-9660, az NFS stb.), de a fjlkezes mveleteivel
frhetnk hozz pldul a soros portokhoz is.
A hlzati rteg a klnbz hlzati protokollok implementcijt tar-
talmazza (IPv4 , IPv6 IPX, Ethernet stb.).
12
2.2. A Linux elindulsa
A perifriakezel
alrendszer az eszkzk alacsony szint kezelst va-
lstja meg. Hozztartozik a httrtrolk, az I/O eszkzk, a soros/prhuza-
mos s az egyb portok kezelse.
A folyamatkezel alrendszer tbb, a processzek kezelsvel kapcsolatos
funkcit valst meg:
A Linux tbbfeladatos (multitask) rendszer, ez azt jelenti, hogy tbb
processzt futtat prhuzamosan (tbbprocesszoros rendszer) vagy kv-
zi prhuzamosan, vltogatva (egyprocesszoros rendszer). Azt, hogy az
egyes processzek mikor jussanak a processzorhoz, az temez dnti el.
A processzeknek ltalban szksgk van arra, hogy egymssal kom-
munikljanak. Ezt az IPC- (Interprocess Communication, processzek
kztti kommunikci) alrendszer teszi lehetv.
A fizikai memria kiosztst a processzek kztt a memriakezel al-
rendszer vgzi el.
A kvetkez fejezetekben fknt a processzkezel alrendszer egyes rszeivel, az
temezs mkdsvel, illetve a memriakezels elmletvel ismerkednk meg.
Az IPC-alrendszerre nem trnk ki; lehetsgeit, hasznlatt ksbb trgyaljuk.
2.2. A Linux elindulsa
Egy opercis rendszer betltdse, elindulsa els pillantsra mindig kicsit
rejtlyes dolognak tnik. ltalban ha egy, a httrtroln lv programot
szeretnnk betlteni, lefuttatni, akkor berjuk a nevt a parancsrtelmezbe,
vagy rkattintunk az ikonjra, s az opercis rendszer elindtja. m hogyan
trtnik mindez, amikor a gp indulsakor magt az opercis rendszert sze-
retnnk betlteni, elindtani?
A Linux-kernel betltst s elindtst az gynevezett kernelbetlt vg-
zi el. Ilyen program a LILO (The Linux Loader), a LOADLIN, a Grub s mg
sorolhatnnk. A program betltshez szksg van egy kis hardveres segt-
sgre is. ltalban a gp csak olvashat memrijban van egy kis program
(az x86-os architektra esetben ennek a neve BIOS vagy (U)EFI), amely
megtallja, betlti s futtatja ezt a kernelbetltt. Vagyis sszegezve: egy
rvid, begetett program lefut, s elindt egy valamivel nagyobb betltprog-
ramot. Ez a betltprogram pedig elindt egy mg nagyobb programot, neve-
zetesen az opercis rendszer kernelprogramjt.
9

9
Lehetsg van arra, hogy a betltprogramokat mg tovbb lncoljuk. Ezltal lehetv
vlik a tbb opercis rendszert tartalmaz gpeken, hogy indulskor kivlaszthassuk a
szmunkra szksgeset.
13
2. fejezet: Betekints a Linux-kernelbe
A kernel manapsg ltalban tmrtett formban van a lemezeken, s
kpes nmagt kitmrteni. gy az els lps a kernel kitmrtse, majd
a kd feldolgozsa a kitmrtett kernel kezdcmtl folytatdik. Ezt kveti a
hardver inicializlsa (memriakezel, megszaktstblk stb.), majd az els
C-fggvny (start_kernel()) meghvsa. Ez a fggvny, amely egyben a 0-s
azonostj processz belpsi pontja, inicializlja a kernel egyes rszeit.
Az inicializci vgn a 0-s processz elindt egy kernelszlat (a neve nit),
majd egy resjrati ciklusba (idle loop) kezd, gy a tovbbiakban a 0-s pro-
cessz szerepe mr elhanyagolhat.
Az nit kernelszlnak vagy processznek a processzazonostja az 1. Ez a
rendszer els igazi processze. Elvgez mg nhny belltst (elindtja a fjl-
rendszert szinkronizl s lapcserekezel folyamatokat, felleszti a rendszer-
konzolt, felcsatolja [mount] a gykr-llomnyrendszert [root file system]),
majd lefuttatja a rendszerinicializl programot (nem keverend a korbban
emltett processzel). Ez a program az adott disztribcitl fggen a kvetke-
zk valamelyike: /etc/init, /bin/init, /sbin/init.
10
Az nit program az /etc/ inittab11
konfigurcis llomny segtsgvel j, immr felhasznli processze-
ket hoz ltre, s ezek tovbbi j processzeket. Pldul a getty processz ltrehozza
a login processzt, amikor a felhasznl bejelentkezik. Ezek a processzek mind
az nit kernelszl leszrmazottai.
2.3. Processzek
A processz egy mkds kzbeni program. Ebbl addan a programkdot s
a hozztartoz erforrsokat tartalmazza.
A processzek meghatrozott feladatokat hajtanak vgre az opercis
rendszeren bell. A feladat lersa az a program, amely gpi kd utastsok
s adatok egyttesbl ll. Ezeket a lemezeken troljuk, gy a program nma-
gban passzv entits.
Ezzel szemben a processz mr dinamikus entits. Folyamatosan vltozik,
ahogy a processzor egyms utn futtatja az egyes utastsokat. A program
kdja s adatai mellett a processz tartalmazza a programszmllt, a CPU-
regisztereket, tovbb a processz vermt, amely az tmeneti adatokat (fgg-
vnyparamterek, visszatrsi cmek, elmentett vltozk) trolja.
10
Ha egyik helyen sem tallja meg a rendszer az nit programot, akkor megprblja feldol-
gozni az /etc/rc llomnyt, s elindt egy shellt, hogy a rendszergazda megjavthassa a
rendszert.
11
A Linux rendszereken elterjedben van az esemnyalap, upstart nev nit implement-
ci. Ez a megolds a hagyomnyos System V nit programhoz kpest eltr konfigurcis
megoldsokat alkalmaz.
14
2.3. Processzek
A Linux tbbfeladatos (multitask) opercis rendszer, a processzek sajt
jogokkal rendelkez elklntett feladatok (task), amelyeket a Linux prhu-
zamosan futtat. Egy processz sszeomlsa nem okozza a rendszer ms pro-
cesszeinek az sszeomlst. Minden klnll processz a sajt virtulis cm-
tartomnyban fut, s nem kpes ms processzekre hatni. Kivtelt kpeznek
ez all a biztonsgos, kernel ltal kezelt mechanizmusok, amelyekkel a pro-
cesszek magvalsthatjk az egyms kztti kommunikcit.
letciklusa sorn egy processz szmos rendszererforrst hasznlhat
(CPU, memria, llomnyok, fizikai eszkzk stb.). A Linux feladata az, hogy
ezeket a hozzfrseket knyvelje, kezelje, s igazsgosan elossza a konkurl
processzek kztt.
2.3.1. A Linux-processzekhez kapcsold informcik
A Linux minden processzhez hozzrendel egy ler adatstruktrt,
12
az eb-
ben szerepl adatok jellemzik az adott processzt, s befolysoljk a mkdst.
Ez a feladatokat ler adatstruktra nagy s komplex, m feloszthat nhny
funkcionlis terletre:
llapot
A processz a futsa sorn a krlmnyektl fggen klnbz llapo-
tokba kerlhet, ezeket az llapotokat a 2.3.2. alfejezetben trgyaljuk.
Azonostk
A rendszerben minden processznek van egyedi azonostja. Ezen tl
minden processz rendelkezik felhasznli s csoportazonostkkal.
Ezek szablyozzk az llomnyokhoz s az eszkzkhz val hozzf-
rst a rendszerben. (Bvebben lsd a 2.3.3. alfejezetben.)
Kapcsolatok
A Linuxban egyetlen processz sem fggetlen a tbbitl. Az nit pro-
cesszt leszmtva minden processznek van szlje. Az j processzek
nem ltrejnnek, hanem a korbbiakbl msoldnak, klnozdnak.
Minden processzler adatstruktra tartalmaz hivatkozsokat a sz-
lprocesszre s a leszrmazottakra. Ezt a kapcsoldsi ft a pstree pa-
ranccsal nzhetjk meg.
temezsi informci
Az temeznek szksge van bizonyos informcikra: priorits, sta-
tisztikai informcik stb., hogy igazsgosan dnthessen, hogy melyik
processz kerljn sorra. Az temezst a 2.3.6. alfejezet trgyalja.
1,
A ler adatstruktra tpusa megtallhat a kernelforrsban. A neve task_struct, s az
include/linux/sched.h llomnyban tallhat.
15
2. fejezet: Betekints a Linux-kernelbe
Memriainformcik
A processz memriafoglalsval kapcsolatos informcik (kd-, adat-,
veremszegmensek) tartoznak ide.
Fjlrendszer
A processzek megnyithatnak s bezrhatnak llomnyokat. A pro-
cesszler adatstruktra tartalmazza az sszes megnyitott llomny
lerjt, tovbb az aktulis, gynevezett munkaknyvtrnak
(working directory) a mutatjt.
Processzek kztti kommunikci
A Linux tmogatja a klasszikus Unix IPC-mechanizmusokat (jelz-
sek, csvezetkek, szemaforok) s a System V IPC-mechanizmusokat
is (megosztott memria, szemafor, zenetsor). Egy kifejezetten a Unix
opercis rendszerekre jellemz processzek kzti aszinkron kommu-
nikcis forma a jelzs (signal). A jelzst kld processz nem vrako-
zik a kzbestsre, klds utn folytatja futst. Jelzs rkezsekor a
fogad processz norml futsa megszakad, s vagy a processz ltal
megadott, vagy az alaprtelmezett jelzskezel fggvny fut le. Ezek
utn a processz ott folytatja a futst, ahol abbahagyta. A futs meg-
szaktst, a jelzskezel futtatst, majd a futs folytatst a kernel
teljes mrtkben kezeli. A jelzshez tartozik egy egsz szm, amely a
jelzs kivltsnak okt adja meg. Ezt az egsz szmot szimbolikus
konstanssal adjuk meg, rtke a signal.h llomnyban tallhat.
A szimbolikus konstansok SIG eltaggal kezddnek. Pldul nullval
val oszts esetn a kernel SIGFPE jelzst kld a mveletet futtat
processznek, illetve akkor, ha egy processz futst azonnal meg sze-
retnnk szaktani, SIGKILL jelzst kldnk neki.
Id s idztk
A kernel naplzza a processzek ltrehozsi s CPU-felhasznlsi ide-
jt. A Linux tmogatja tovbb az intervallumidztk hasznlatt a
processzekben, amelyeket belltva jelzseket kaphatunk bizonyos id
elteltvel. Ezek lehetnek egyszeri vagy periodikusan ismtld rtes-
tsek. (Bvebben lsd a 2.3.8. alfejezetben.)
Processzorspecifikus adatok (Context)
A folyamat a futsa sorn hasznlja a processzor regisztereit, a ver-
met stb. Ez a processz krnyezete, s amikor feladatvltsra kerl
sor, ezeket az adatokat le kell menteni a processzt ler adatstrukt-
rba. Amikor a processz jraindul, innen lltdnak vissza az adatok.
16
Esemny
bekvetkezik
Esemnyre
vr
Ltrehozs
Jelzs Jelzs
Megsznik
Futs
vge
2.3. Processzek
2.3.2. A processz llapotai
A futs sorn a processzek klnbz llapotokba juthatnak. Az llapot fgg-
het a processz aktulis teendjtl s a kls hatsoktl. A processz aktulis
llapott a processzhez rendelt ler struktra llapotler vltozja trolja.
Linux alatt egy processz lehetsges llapotai a kvetkezk:
A processz ppen fut az egyik processzoron. (Az llapotvltoz rtke:
RUNNING.)
A processz futsra ksz, de msik foglalja a processzort, ezrt vra-
kozik a listban. (Az llapotvltoz rtke ilyenkor is: RUNNING.)
A processz egy erforrsra vagy esemnyre vrakozik. Ilyenkor attl
fggen kap rtket az llapotvltoz, hogy a vrakozst megszakthat-
ja egy jelzs (INTERRUPTABLE), vagy sem (UNINTERUPTABLE).
A jelzssel nem megszakthat llapot egyik alesete az, amikor a kriti-
kus, a folyamat lellst eredmnyez jelzsek mg megszakthatjk a
vrakozst (KILLABLE).
A processz felfggesztve n, ltalban a SIGSTOP jelzs kvetkezt-
ben. Ez az llapot hibajavtskor jellemz, de a terminlban futtatott
folyamatnl a CTRL + Z billenty kombincival szintn elrhetjk.
(Az llapotvltoz rtke: STOPPED.)
A processz ksz az elmlsra (mr nem l, de mg nem halott: zom-
bi), de valami oknl fogva mg mindig foglalja a ler adat struktr-
jt. (Az llapotvltoz rtke: ZOMBIE.)
Az llapotok kapcsolatait a 2.2. bra szemllteti:
2.2. bra. A processz llapotatmenet -diagramja
17
2. fejezet: Betekints a Linux-kernelbe
A processzeket a fenti llapotdiagram szerint az temez (scheduler) kezeli.
Az temezsi algoritmusokat s a processzekhez tartoz adatterleteket a
2.3.6. alfejezetben trgyaljuk bvebben.
2.3.3. Azonostk
A Linux-kernel minden processzhez egy egyedi azonostt rendel: pid (process
ID). Ksbb ezzel az azonostszmmal hivatkozhatunk a processzre.
Minden folyamat egy processzcsoport tagja, amelynek azonostjt a pgid
(process group ID) mez tartalmazza. Amikor a folyamat ltrejn, a szlfo-
lyamat pgid azonostjt rkli, m ez ksbb mdosthat. A processzcsoport
arra hasznlhat, hogy tagjainak egyszerre kldjnk jelzseket, vagy valame-
lyik tagjnak befejezdsre vrakozzunk.
A konvenci szerint a pgid azonost szmrtke a csoport els tagjnak
pid rtkvel egyezik meg. j csoportot is gy tudunk ltrehozni, ha a pgid
rtkt a folyamat pid rtkre lltjuk. Ekkor a folyamatunk a csoport veze-
tje lesz. A csoport vezetjnek szerepe annyiban specilis, hogy ha vget r,
akkor a csoport tbbi tagja egy SIGHUP jelzst kap. (Bvebben lsd az 5.6.
Jelzsek cm alfejezetben.) A jelzs hatsra a folyamatok dnthetnek arrl,
hogy lellnak-e (alaprtelmezett), vagy folytatjk a futsukat.
Tbb processzcsoport sszekombinlhat egy munkamenett (session).
Minden folyamatnak a munkameneten bell azonos a sessionid rtke.
Linux alatt a szlak specilis folyamatoknak szmtanak. Ezrt fontos a
rendszer szmra annak knyvelse, hogy mely szlak tartoznak egybe, egy
folyamathoz. Az sszetartoz szlakat a szlcsoportok tartalmazzk. A folya-
mat szlcsoport-azonostja a tgid.
A Linux, mint minden ms Unix rendszer, felhasznli- s csoportazono-
stkat hasznl az llomnyok hozzfrsi jogosultsgnak az ellenrzsre.
A Linux rendszerben minden llomnynak van tulajdonosa s jogosultsgi
belltsai. A legegyszerbb jogok a read, a write s az execute. Ezeket rendel-
jk hozz a felhasznlk hrom osztlyhoz: ezek a tulajdonos, a csoport s a
rendszer tbbi felhasznlja. A felhasznlk mindhrom osztlyra kln be-
llthat mindhrom jog.
Termszetesen ezek a jogok valjban nem a felhasznlra, hanem a fel-
hasznl azonostjval fut processzekre rvnyesek. Ebbl kvetkezen a
processzek az albbi azonostkkal rendelkeznek:
uid, gid
A felhasznl felhasznli s csoportazonosti, amelyekkel a pro-
cessz fut.
Effektv uid s gid
Ezeket az azonostkat hasznlja a rendszer annak vizsglatra, hogy
a processz hozzfrhet-e az llomnyhoz. Klnbzhetnek a valdi
felhasznltl s csoporttl. Ezeket a programokat nevezzk setuidos,
18
2 .3. Processzek
illetve csoportllts esetn setgides programoknak. Segtsgkkel
korltozott hozzfrst nyjthatunk a rendszer egyes vdett, csak a
rendszergazda szmra hozzfrhet rszeihez.
Fjlrendszer-uid s -gid
Ezek norml esetben megegyeznek a valdi azonostkkal, s a fjl-
rendszerhez val hozzfrsi jogosultsgokat szablyozzk. Elssorban
az NFS-fjlrendszereknl
13
van rjuk szksg, amikor a felhasznli
zemmd NFS-szervernek klnbz llomnyokhoz kell hozzfr-
nie az adott felhasznl nevben. Ebben az esetben csak a fjlrend-
szer-azonostk vltoznak.
Mentett uid s gid
Olyan programok hasznljk, amelyek a processz azonostit rendszer-
hvsok ltal megvltoztatjk. A valdi uid s gid elmentsre szol-
glnak, hogy ksbb visszallthatk legyenek.
2.3.4. Processzek ltrehozsa s terminlsa
j processzt egy korbbi processz lemsolsval hozhatunk ltre. Ez a fork
rendszerhvssal valsthat meg. A msolat teljesen megegyezik az eredetivel,
csak a processzazonostban klnbznek. Az eredeti processzt szlprocessz-
nek, a msolatot, a leszrmazottat gyerekprocessznek nevezzk. Termszete-
sen, ha ksbb az egyes processzek mdostanak a bels vltozikon, akkor ez
a msik processznl mr nem rvnyesl.
A valsgban a gyerekfolyamat ltrehozsakor nem trtnik tnyleges
msols. Helyette a Linux a COW metdust hasznlja (lsd ksbb a 2.4.7. al-
fejezetben).
Ha egy program egy msik programot akar futtatni, akkor sincs ms t: a
processznek le kell msolnia magt, s a gyerekprocessz tlti be a futtatand
msik programot. Ezrt gyakori az a forgatknyv, hogy az j folyamat ltre-
hozsa utn egy rendszerhvssal azonnal betltnk egy j programot, s azt
futtatjuk. Ilyenkor az eredeti folyamat memrijnak a lemsolsa felesleges.
Erre az esetre szolgl a vfork fggvny, amelyben a memria msolsa he-
lyett a rendszer megosztja a memrit a szl s a gyerek kztt addig, amg
a gyerek betlt egy j programkdot. Erre az tmeneti idre a szlfolyamat
blokkoldik. Amita a Linux a COW metdust hasznlja a fork rendszerh-
vsnl, azta a vfork elnye valjban mr elhanyagolhat, gy nem jellemz
a hasznlata.
13
Az NFS (Network File System) elssorban Unix rendszereknl hasznlt hlzati fjl-
rendszer.
19
2 . fejezet: Betekints a Linux-kernelbe
A Linux mind a fork, mind a vfork rendszerhvst valjban a clone rend-
szerhvssal valstja meg. A clone ltrehoz egy j folyamatot a szlfolyamat-
bl, s lehetv teszi, hogy megadjunk, mely memriaterleteken osztozzon a
kt folyamat. Mint lthat, a fork s a vfork fggvnyek valjban a clone
specializlt esetei. A clone teszi lehetv a kernelszint szlkezels imple-
mentcijt is Linux alatt.
14

A gyerekfolyamat a szl teljes msa, csak a pid s a ppid rtkekben tr
el tle. Ezen kvl nem rkldnek mg az llomnyzrolsok s az aktulis
jelzsek.
Ha a gyerekfolyamat a programkdjnak a vgre rt, vagy terminl jelle-
g jelzst kap, akkor ezt a tnyt egy SIGCHLD jelzssel jelzi a szl szmra,
befejezi a futst, s zombi llapotba kerl. Addig zombi llapotban marad,
amg a szljnek tadja az eredmnyt. Ameddig a szl ezt nem veszi t t-
le, addig a gyerekfolyamat zombi llapotban vrakozik.
Felvetdik a krds, mi trtnik akkor, ha a szl fejezi be hamarabb a
futst, s nem a gyerek. A gyerek ilyenkor rva lesz, s az nit veszi t a sz-
l szerept. Amikor a gyerekfolyamat vgzett, akkor az nit tveszi tle a visz-
szatrsi rtkt, gy teljesen megsznhet.
2.3.5. A programok futtatsa
A Linuxban, mint a tbbi Unix rendszerben, a programokat s a parancsokat
ltalban a parancsrtelmez futtatja. A parancsrtelmez egy felhasznli
processz, amelynek a neve shell.
Linuxos rendszereken tbb parancsrtelmez kzl vlaszthatunk (sh,
bash, tcsh stb.). A parancsrtelmezk tartalmaznak nhny beptett paran-
csot. A tbbi begpelt utastst mint programnevet rtelmezik. A parancsknt
megadott llomnynvvel keresnek egy futtathat llomnyt a PATH kr-
nyezeti vltoz ltal megadott knyvtrakban. Ha megtalljk, akkor betltik
s lefuttatjk. A parancsrtelmez a fent emltett fork metdussal lemsolja
magt, s a megtallt llomny az j, leszrmazott processzben fut. Norml
esetben a parancsrtelmez megvrja a gyerekprocessz futsnak a vgt, s
csak ezutn adja vissza a vezrlst a felhasznlnak, de lehetsg van a pro-
cesszt a httrben is futtatni.
A futtathat fjl tbbfle binris vagy szveges parancsllomny (script) le-
het. A parancsllomnyt az els sorban megadott program (amely ltalban
egy parancsrtelmez), ennek hinyban az ppen hasznlt parancsrtelmez
rtelmezi.
14
Mint lthat, Linux alatt a szlak nincsenek szigoran megklnbztetve a processzektl .
A szlak valjban kzs memrin osztoz processzek sajt processzazonostval.
2 0
2 .3. Processzek
A binris llomnyok informcikat tartalmaznak az opercis rendszer
szmra, hogy rtelmezni s futtatni tudja ket, tovbb tartalmazzk a
programkdot s az adatokat. A Linux alatt a leggyakrabban hasznlt binris
formtum az ELF.
15
A tmogatott binris formtumokat a kernel fordtsakor vlaszthatjuk
ki, vagy utlag modulknt illeszthetjk be az rtelmezsket. Az ltalnosan
hasznlt formtumok az a.out, az ELF, de pldul a Java class fjlok felisme-
rst is bekapcsolhatjuk.
2.3.6. temezs
A Linux rendszerek prhuzamosan tbb folyamatot futtathatnak. Ritka az az
eset, amikor a processzorok szmt nem haladja meg a folyamatok szma.
Ezrt, hogy az egyes processzek tbb-kevsb prhuzamosan futhassanak,
az opercis rendszernek folyamatosan vltogatnia kell, hogy melyik processz
kapja meg a processzort. Az temez feladata az, hogy szablyozza a procesz-
szorid kiosztst az egyes folyamatok szmra.
Ahhoz, hogy az temezs felhasznli szempontbl knyelmes legyen,
szksg van arra, hogy a felhasznl az egyes folyamatok prioritst szab-
lyozhassa, s az szemszgbl nzve a processzek prhuzamosan fussanak.
A rossz temezsi algoritmus az opercis rendszert dcgss, lassv tehe-
ti, az egyes processzek tlzott hatssal lehetnek egymsra a processzorid el-
osztsa sorn. Ezrt a Linux fejleszti nagy figyelmet fordtottak az temez
kialaktsra.
A processzek vltogatsval kapcsolatban kt krds merl fel.
Mikor cserljnk le egy processzt?
Ha mr eldntttk, hogy lecserlnk egy processzt, melyik legyen az
a processz, amelyik a kvetkez lpsben megkaphatja a CPU-t?
Ezekre a krdsekre adunk vlaszt a tovbbiakban.
2.3.6.1. Klasszikus temezs
A klasszikus Linux-temezs idosztsos rendszert hasznl. Ez azt jelenti, hogy
az temez az idt kis szeletekre osztja (time-slice), s ezekben az idszeletekben
valamilyen kivlaszt algoritmus alapjn adja meg az egyes processzeknek a fu-
ts lehetsgt. m az egyes processzeknek nem kell kihasznlniuk az egsz
15
Az ELF (Executable and Linkable Format, futtathat s linkelhet formtum) binris
formtumot eredetileg a System V Release 4 UNIX-verziban vezettk be. Ksbb a Li-
nux fejleszti is tvettk, mert a bels felptse sokkal flexibilisebb, mint a rgebbi a.out
formtum. Ezen kvl egy hatkony debug formtuma is ltezik, amelynek neve DWARF
(Debugging With Attribute Record Format), amely dinamikusan egy lncolt listban t-
rolja a hibakeresshez szksges informcit.
2 1
2. fejezet: Betekints a Linux-kernelbe
idszeletet, akr le is mondhatnak a processzorrl, ha ppen valamilyen rend-
szeresemnyre kell vrakozniuk. Ezek a vrakozsok a rendszerhvsokon
bell vannak, amikor a processz ppen kernelzemmdban fut.
16

A Linuxban a nem fut processzeknek nincs eljoga az ppen fut pro-
cesszekkel szemben, nem szakthatjk meg a fut folyamatokat annak rde-
kben, hogy tvegyk a processzort. Vagyis az idszeleten bell csak a fut
folyamatok mondhatnak le a processzorrl nkntes alapon, s adhatjk t
egymsnak a futs lehetsgt.
A fenti kt alapelv gondoskodik arrl, hogy megfelel idpontban kvet-
kezzen be a vlts. A msik feladat a kvetkez processz kivlasztsa a fu-
tsra kszek kzl. Ezt a vlasztsi algoritmust a kernelen bell a schedule()
fggvny implementlja.
A klasszikus temezs hrom stratgit (policy) tmogat: a szoksos Unix
temezsi mdszert s kt, vals idej (real-time) processzek temezsre
szolgl algoritmust. A vals idej processz a szoksos rtelmezs szerint azt
jelenten, hogy az opercis rendszer garantlja, hogy az adott processz egy
megadott, rvid idn bell megkapja a processzort, amikor szksge van r,
gy reaglhat a kls esemnyekre. Ezt hvjuk hard real-time"-nak. m
a Linux csak egy gynevezett soft real-time" megkzeltst tmogat, amely a
vals idej processzeket a kivlaszts sorn elre veszi, gy a lehetsg szerinti
legkisebb ksleltetssel juttatja processzorhoz. Mg a klasszikus temezsnl
jelents az eltrs a Linux soft real-time megoldsa s egy hard real-time rend-
szer kztt, a manapsg hasznlatos megoldsoknl mr nem olyan les a ha-
trvonal. (Ezt a tmakrt rszletesen lsd a 2.3.8. alfejezetben.)
A Linux a kvetkez futtatand processz kivlasztshoz prioritsos te-
mezalgoritmust hasznl. A norml processzek kt prioritsrtkkel rendel-
keznek: statikus s dinamikus prioritssal. A vals idej processzekhez a
Linux trol mg egy prioritsrtket is, a vals idej prioritst (real time
priority). Ezek a prioritsrtkek egyszer egsz szmok, amelyeknek a segt-
sgvel a kivlasztalgoritmus slyozza az egyes processzeket.
A statikus priorits
A nvben szerepl statikus sz jelentse az, hogy rtke nem vltozik
az id fggvnyben, csak a felhasznl mdosthatja. A processzin-
formcik kztt a neve nice, amely arra utal, hogy az temez milyen
kedves" lesz a processzel, s mennyire knlja processzoridvel.
16
Minden processz rszben felhasznli zemmdban, rszben kernelzemmdban fut.
A felhasznli zemmdban jval kevesebb lehetsge van a processznek, mint kernel-
zemmdban, ezrt bizonyos erforrsok, rendszerszolgltatsok ignybevtelhez t kell
kapcsolnia. Ilyenkor az tkapcsolshoz a processz egy rendszerhvst hajt vgre (a Linux
felhasznli kziknyv [manual] 2 . szekcija tartalmazza ezeket, pldul: read()). Ezen a
ponton a kernel futtatja a processz tovbbi rszt.
2 2
2.3. Processzek
A dinamikus priorits
A dinamikus priorits lnyegben egy szmll, rtke a processz fu-
tsnak fggvnyben vltozik. Segtsgvel az temez nyilvntart-
ja, hogy a processz mennyi futsi idt hasznlt el a neki kiutaltbl.
Ha pldul egy adott processz sokig nem jutott hozz a CPU-hoz, ak-
kor a dinamikus prioritsi rtke magas lesz. A processzinformcik
kztt a neve counter, vagyis szmll.
A vals idej priorits
Jelzi, hogy a processz vals idej, gy minden norml processzt ht-
trbe szort a vlasztskor. Tovbbi funkcija, hogy a vals idej pro-
cesszek kztti prioritsviszonyt megmutassa. A processzinformcik
kztt a neve rt_priority.
Norml processzek esetben a Linux temezsi algoritmusa az idt korsza-
kokra (epoch) bontja. A korszak elejn minden processz kap egy meghatrozott
mennyisg idegysget, vagyis a kernel a szmlljt egy, a statikus priorit-
sbl meghatrozott rtkre lltja Amikor egy processz fut, ezeket az idegy-
sgeket hasznlja el, vagyis a szmllja cskken. Ha elfogyott az idegysge,
akkor mr csak a kvetkez ciklusban futhat legkzelebb. Egy korszaknak ak-
kor van vge, amikor minden RUNNING llapot processznek elfogyott az
idegysge (teht a vrakoz processzek nem szmtanak). Ilyenkor j kor-
szak kezddik a processzek letben. Ezzel a mdszerrel elrhet, hogy sszer
idn bell minden processz kapjon tbb-kevesebb futsidt, vagyis egyiket se
heztessk ki.
A FIFO vals idej temezs esetn csak a vals idej prioritsnak van
szerepe az temezsben. A legnagyobb priorits processzek kzl a sorban a
legels futhat egszen addig, amg t nem adja msnak a futs lehetsgt
(vrakoznia kell, vagy vget rt), vagy nagyobb priorits processz nem
ignyli a processzort.
A krbeforg (round-robin) vals idej temezsi algoritmus a FIFO to-
vbbfejlesztett vltozata. Mkdse hasonlt a FIFO temezshez, m egy pro-
cessz csak addig futhat, amg a neki kiutalt idegysge el nem fogy, vagyis a
szmlljnak az rtke el nem ri a 0-t. Ilyenkor a sor vgre kerl, s a rend-
szer megint kiutal szmra idegysgeket. Ezltal lehetv teszi a CPU igazs-
gos elosztst az azonos vals idej prioritssal rendelkez processzek kztt.
2.3.6.2. Az 0(1) temezs
Az 0(1) temezs a 2 .6-os kernellel egytt jelent meg. A Java virtulis gpek
miatt volt r szksg a sok prhuzamosan fut szl kvetkeztben. Mivel a
korbbi temezalgoritmus futsi ideje egyenes arnyban llt a processzek/
szlak szmval, ezrt nagy mennyisg szl esetn a hatkonysga jelent-
sen cskkent. Az 0(1) temez erre a problmra jelentett megoldst, mivel
az temezsi algoritmus futsideje nem nvekszik a processzek szmval. Ezt a
Linux gy oldja meg, hogy prioritsi szintekbe rendezi a processzeket, amely
23
2. fejezet: Betekints a Linux-kernelbe
egy ktszeresen lncolt lista. Egy bittrkp alapjn az temez nagyon gyorsan
meg tudja tallni azt a legmagasabb prioritsi szintet, ahol processz vrakozik.
Ezutn az ezen a prioritsi szinten elhelyezked els processzt kell futtatnia.
A bittrkp mrete csak a prioritsi szintek szmtl fgg, a processzek szm-
tl nem.
2.3.6.3. Teljesen igazsgos temez
A teljesen igazsgos temez (Completely Fair Scheduler, CFS) a 2 .6.2 3-as
kerneltl kezdden az ltalnos kernel alaprtelmezett temezalgoritmusa.
A klasszikus temezsi algoritmushoz kpest az egyik legjelentsebb eltrse,
hogy a futsi id arnyra koncentrl. A CFS olyan krkrs priorits te-
mez, amely a processzek idszeletnek arnyt prblja igazsgoss tenni.
Idelis esetben, ha van N darab processznk, mindegyik a rendelkezsre ll
id 1 /N-ed rszben fut. Ezt a szmtst egy adott idtartamra kalkulljuk
ki, a neve cllappangsi id (target latency). Ha ez az id 30 ms, s hrom
processznk van, N = 3, mindegyik processzre 1/3 arnyban jut id, vagyis
mindegyik 10 ms-ig fut. A processzek kztti vlts idignye elhanyagolhat.
Ha azonban tl sok processz fut a rendszerben, ttelezzk fel, hogy 100, ak-
kor 0,3 ms-onknt kellene vltani, ez pedig mr nem kifizetd. Ezrt ennek
az algoritmusnak van egy minimlis felbontsa (minimum granularity),
amely al nem megy az temezs. Ha ez az rtk 1 ms, akkor mind a 100 pro-
cessz 1 ms-ig fut. Termszetesen ebben az esetben az algoritmus mr nem is
nevezhet igazsgosnak mg az idarny tekintetben sem.
A nice
rtkek abszolt rtke nem szmt, a relatv rtkek alapjn az
algoritmus egy arnyszmot szmol. Kt processz esetn nulla, s egy 5 nice
rtk ugyanolyan arnyban fut, mint egy 10 s 15 rtk.
Az algoritmus implementcija azt az idt trolja, amennyit a processz
legutoljra futott, pontosabban ezt mg elosztja a processzek szmval. Ezt
az rtket virtulis futsidnek (virtual runtime) nevezzk, amely nanosze-
kundum felbonts. Ezt az rtket az temez folyamatosan karbantartja. Ide-
lis esetben ez az rtk ugyanannyi lenne minden azonos priorits processz
esetben. Egy vals processzornl ezt gy lehet ellenslyozni, hogy mindig a
legkisebb virtulis futsidej processzt futtatjuk. A CFS is pontosan gy tesz.
Ahhoz, hogy megtallja a legkisebb rtket, a vrakozsi listt egy telje-
sen kiegyenslyozott piros-fekete binris fban trolja. Ennek a leggyakrab-
ban hasznlt bal oldali elemt gyorsttrazza is a hatkonysg rdekben.
Az temezs ennl az algoritmusnl O(log n) komplexits, m tnyleges
rtke kisebb, mint a korbbi temeznl volt. A taszkok vltsa konstans
id, viszont a levltott taszk beillesztse a binris fba O(log
n) idt ignyel.
Az temez tovbbi jtsa a korbbakkal szemben, hogy az temezsi
stratgik implementcija modulris felpts lett. gy szabadon bvthet
tovbbi algoritmusokkal. Ugyanakkor tartalmaz egy j stratgit is, amely-
nek neve batch". Ez lehetv teszi olyan alkalmazsok futtatst, amelyeket
24
2.3. Processzek
hosszabban rdemes futtatni a processzoron, ugyanakkor nem ignylik a
gyakori meghvst, mert nem kell felhasznli esemnyekre reaglniuk. Ezek
tbbnyire szerveralkalmazsok.
A CFS-temezben is az trtnik, hogy a vals idej folyamatok megel-
zik a norml temezseket. Ugyanakkor, mivel nincsenek idszeletek, ezrt
a rendszer szinte azonnal vlthat, ha egy vals idej folyamat futsra kssz
vlik. A gyorsttrazs miatt a taszkvlts is rvid id alatt vgrehajtdik.
2.3.6.4. Multiprocesszoros temezs
Szimmetrikus multiprocesszoros (SMP) krnyezetben az temezsi metdust
kicsit mdostani kell. Ilyenkor minden processzor kln, sajt magnak fut-
tatja az temez funkcit, m a processzoroknak clszer informcikat cse-
rlnik a rendszer teljestmnynek a nvelse rdekben.
Amikor az temez kiszmolja az adott processz slyozst, azt is figye-
lembe kell vennie, hogy korbban a processz ugyanazon a processzoron futott-e,
vagy egy msikon. Azok a processzek, amelyek az adott CPU-n futottak, mindig
elnyt lveznek, mivel a CPU-hardver gyorsttra mg mindig tartalmazhat
rjuk vonatkoz informcikat. Ezzel a mdszerrel az opercis rendszer n-
velni tudja a tallatok szmt a gyorsttrakban.
Ezzel kapcsolatban azonban felvetdik egy problma. Tegyk fel, hogy az
temez tallkozik azzal az esettel, hogy egy processz prioritsa nagyobb,
mint a tbbi, m korbban egy msik processzoron futott. Ilyenkor vagy el-
vesztjk gyorsttrakban visszamarad informcik lehetsgt, vagy nem
hasznljuk ki az SMP-architektrbl add lehetsget, hogy a rr pro-
cesszoron futtassuk a processzt.
A Linux-SMP a dilemma feloldsra egy adaptv empirikus szablyt alkal-
maz. Ez egy olyan kompromisszum, amely fgg a processzorok gyorsttrnak
a mrettl. Ha a gyorsttr nagyobb, akkor a rendszer jobban ragaszkodik
ahhoz, hogy egy processz mindig ugyanazon a processzoron fusson.
2.3.7. Megszaktskezels
A Linuxban kt megszaktskezel-tpust klnbztetnk meg. A gyors"
megszaktskezel letiltja a megszaktsokat, ezrt gyorsra kell elkszte-
nnk. A lass" megszaktskezel nem tiltja le a megszaktsokat, mert az
ltala ignyelt hosszabb futsidre ez nem lenne j tlet.
Azrt, hogy a megszaktskezel rutinok gyorsan lefuthassanak, a Linux-
fejlesztk egy olyan megoldst alkalmaznak, amely a feladatot kt rszre v-
lasztja szt:
Fels rsz (Top hal f)
Ez a tnyleges megszaktskezel rutin. A feladata az, hogy az adato-
kat gyorsan letrolja az utlagos feldolgozshoz, majd bejegyezze a
msik fl futtatsra vonatkoz krelmt.
25
2. fejezet: Betekints a Linux-kernelbe
Als rsz (Bottom hal})
Ez a rsz tnylegesen mr nem a megszaktskezelben fut le, hanem
utna kicsivel. A komolyabb, idignyesebb szmtsokat itt vgezzk
el. Technikailag kt eszkz kzl vlaszthatunk az als rsz imple-
mentcija sorn: kisfeladat (Tasklet), munkasor (Work queue).
2.3.8. Valsidejsg
Jelenleg mr arnylag kevs eltrs van a norml s a vals idej kernel k-
ztt. gy nem kritikus helyeken a norml kernelt is nyugodtan vlaszthatjuk
a begyazott rendszereinkhez Nzzk meg, melyek azok az elemek, amelyek
mindezt lehetv teszik.
Mint lthattuk, a CFS-temez nanoszekundum felbonts, gy na-
gyon gyors reakcit tesz lehetv, s a taszkvlts is konstans idt
ignyel.
A kernelszlak a 2 .6-os kernelben megszakthatk, gy egy hosszabb
mvelet sem tudja lefogni a processzort.
A szinkronizlsokat optimalizltk a kernelben, hogy a lehet legke-
vsb akadlyozzk egymst a fut processzek.
A vals idej (RT) kernelt a norml kernelbl egy javtfolt- (patch) halmaz
segtsgvel llthatjuk el. A vals idej kernel az albbi tovbbi funkcikkal
rendelkezik:
Tartalmaz egy direkt hozzfrsi lehetsget a fizikai memrihoz.
Tartalmaz nhny memriakezelsbeli mdostst.
A gyenge pontok feldertsre pedig tartalmaz egy ksleltetsmonito-
roz eszkzt (Latency tracer).
2.3.9. Id s idztk
A kernel knyveli a processzek ltrehozsi idpontjt, s az letk sorn fel-
hasznlt CPU-idt. Ezeknek az idknek a mrtkegysge trtnelmileg a
jiffy (pillanat), amelynek norml mrtkegysgben rtelmezett rtke a ker-
nel belltstl fgg. A rendszer knyveli a processznek a kernel-, illetve fel-
hasznli zemmdban tlttt idejt.
Ezek mellett a knyvelsek mellett a Linux tmogatja az intervallumidzt-
ket is. A processz ezeket felhasznlhatja, hogy klnbz jelzseket kldessen
magnak, amikor lejrnak. Hromfle intervallumidztt klnbztetnk meg:
26
2.4. Memriakezels
Real
Az idzt vals idben dolgozik, s lejrtakor egy SIGALRM jelzst
kld.
Virtual
Az idzt csak akkor mkdik, amikor a processz fut, s lejrtakor
egy SIGVTALRM jelzst kld.
Profile
Az idzt egyrszt a processz futsi idejben mkdik, msrszt ak-
kor, amikor a rendszer a processzhez tartoz mveleteket hajt vgre.
Lejrtakor egy SIGPROF jelzst kld. Elssorban arra hasznljk,
hogy lemrjk, a processz mennyi idt tlt a felhasznli, illetve a
kernelzemmdban.
Egy vagy akr tbb idztt is hasznlhatunk egyszerre. Bellthatjuk ket
egy-egy jelzsre vagy ismtldre is. A Linux kezeli az sszes szksges in-
formcit a processz adatstruktrjban. Rendszerhvsokkal konfigurlhat-
juk, indthatjuk, lellthatjuk s olvashatjuk ket.
2.4. Memriakezels
A memria a CPU utn a msik legfontosabb erforrs, gy a memriakezel
alrendszer az opercis rendszerek egyik legfontosabb eleme.
2.4.1. A virtulismemria-kezels
A kezdetek ta gyakran felmerl a problma, hogy tbb memrira van szks-
gnk, mint amennyit a gpnk fizikailag tartalmaz. Ugyanakkor a rendelkez-
snkre ll a merevlemez, amely ugyan lassabban kezelhet, de nagy kapacitssal
rendelkezik. Ezrt j lenne, hogy amikor kifutunk a szabad memriaterletbl,
akkor a memria egyes, nem hasznlt rszeit tmenetileg a merevlemezre he-
lyezhetnnk, gy felszabadulhatna a szksges hely a programok szmra.
A virtulismemria-kezels az a mdszer, amely ezt biztostja szmunkra
a memria s a merevlemez felhasznlsval nagyobb memriaterlet elrst
teszi lehetv a processzeknek, mint amennyi szabad fizikai memria valjban
rendelkezsnkre ll. Mindezt radsul gy oldjuk meg, hogy a processz szmra
az egsz memriaterlet egysgesen kezelhet s tltsz legyen.
27
2. fejezet: Betekints a Linux-kernelbe
2.4.2. Lapozs
A virtulismemria-kezels megvalstsnak egyik, jelenleg legelterjedteb-
ben hasznlt mdszere a memrialapozs technikja. A rendszer memrijt
tartomnyokra, gynevezett lapokra (page) osztjuk. Ezeket a lapokat a ker-
nel egymstl fggetlenl mozgathatja a memria s a merevlemez kztt.
Termszetesen a lapok kezelse tbbletadminisztrcival jr. A rendszernek
nyilvn kell tartania, hogy az egyes lapok ppen hol helyezkednek el. Szksg
esetn a lapokat ki kell rnia a httrtrolra, vagy betltenie, s az egszet
le kell kpeznie a processz szmra hasznlhat formra.
De a lapozs a memriakorltok lekzdsnl tbbet is nyjt. A lapszer-
vezs memrit vdelmi clokra is felhasznlhatjuk. A rendszerben minden
processz sajt virtulismemria-terlettel rendelkezik. Ezek a cmtartomnyok
teljesen elklnlnek egymstl, gy az egyik fut folyamatnak nem lehet hat-
sa a msikra. Tovbb a hardver virtulismemria-kezel mechanizmusa le-
hetv teszi, hogy a lapokhoz vdelmi attribtumokat rendeljnk, gy
egyes memriaterleteket teljesen rsvdett tehessnk.
Nzzk meg, hogyan is mkdik a lapozs (paging) mdszere a gyakor-
latban. A 2.3 bra egy egyszerstett pldt mutat be, amelyben kt processz
virtulismemria-terlett kpezzk le a fizikai memrira. (A Linux ennl
bonyolultabb, tbblpcss lekpezst hasznl, errl ksbb lesz sz.)
A processz a mkdse sorn folyamatosan hasznlja a memrit. Ott ta-
llhat a kdja, amelyeket a processzor kiolvas s vgrehajt, de ott trolja az
adatait is. Ezek az adatok mind a memria egy-egy trolegysgben helyez-
kednek el, amelyekre cmekkel hivatkozhatunk. A virtulis memria haszn-
latakor ezek a cmek mind virtulis cmek a virtulis memriban. (Vagyis
minden processznek van egy sajt virtulis birodalma".)
Ezeket a virtulis cmeket a memriakezel egysg (Memory Manage-
ment Unit, MMU) alaktja fizikai cmekk. Az MMU a korszer rendszereknl
a processzor rsze. Az talaktst az opercis rendszer ltal karbantartott
informcis tblk alapjn vgzi el, amelyeknek neve laptbla.
Ennek a folyamatnak a megknnytsre a virtulis s a fizikai memria
egyenl mret (Intel x86-os architektra esetn 4 kB-os) lapokra tagoldik.
Minden lap rendelkezik egy sajt egyedi lapazonost szmmal (Page
Frame Number).
Pldnkban a virtulis cm kt rszbl tevdik ssze. Egy eltolsbl (off-
set) s egy lapazonost szmbl (Page Frame Number, PFN). Ha a lapok
mrete 4 kB, akkor az als 12 bit adja az eltolst, a felette lv bitek a lap
szmt.
Minden alkalommal, amikor a processzor egy virtulis cmet kap, sztv-
lasztja ezeket a rszeket, majd a virtulis lapazonostt megkeresi a laptblban,
s tkonvertlja a lap fizikai kezdcmre. Ezek utn az eltols segtsgvel
a laptbla alapjn mr megtallja a memriban a krdses fizikai cmet.
28
2.4. Memriakezels
Processz X Processz Y
VPFN 7 VPFN 7
Processz X Processz Y
Lap tbla Lap tbla
VPFN 6
VPFN laptb-
lval

-411
VPFN 5 VPFN 5
VPFN 4 PFN 4 VPFN 4
VPFN 3 PFN 3 VPFN 3
VPFN 2 PFN 2 VPFN 2
VPFN 1 PFN 1 VPFN 1
VPFN 0 PFN 0 VPFN 0
VIRTULIS FIZIKAI VIRTULIS
MEMRIA MEMRIA MEMRIA
2.3. bra. Avirtulis memria lekpezse fizikai memrira
A pldnkban (2.3. bra) kt processz van, s mindkt processz sajt laptb-
lval rendelkezik. Ezek a laptblk az adott processz virtulis lapjait a me-
mria fizikai lapjaira kpezik le.
Minden laptblabejegyzs az a
elt-
r
ttribtumokat tartalmazza:
Az adott tblabejegyzs rvnyes-e.
A fizikai lapazonost (PFN).
Hozzfrsi informci: az adott lap kezelsvel kapcsolatos inform-
cik, rhat-e, kd vagy adat.
2.4.3. A lapozs implementcija a Linuxon
A virtulis cm lekpezst fizikai cmm az MMU vgzi. Az MMU a procesz-
szor rsze, ebbl kvetkezen a cm lekpezse az egyes architektrkon elt-
r lehet.
Az x86-os architektra esetn a virtulis cmbl a fizikai cm ktszint
lekpezssel kaphat meg (lsd
me-
mrialapot.

Mint lthat, a virtulis cm ebben az esetben 3 rszre bonthat: lapknyv-
trindex, laptblaindex, eltols. A lapknyvtr (page directory) a laptblkra
mutat hivatkozsok tmbje. A lapknyvtrindex ebbl a tmbbl vlaszt
ki egy laptblt. A laptbla tartalmazza a hivatkozsokat a fizikai memria
egyes lapjaira. A laptblaindex ebbl meghatroz egy elemet, vagyis egy me-
mrialapot. A fizikai cm ennek a lapnak a cmbl s az eltols sszegbl
szmthat. A virtulis cm ilyen mdon kpezhet le fizikai cmm.
29
2. fejezet: Betekints a Linux-kernelbe
Virtulis cm Fizikai memria
Lapknyvtr index Laptblaindex
Eltols
(offset)
Lapknyvtr Laptbla
2.4. bra. Ktszint lekpezs (x86 32bit)
Egyes 64 bites architektrkon, mint pldul az Alpha, egy ilyen felosztsban a
lapknyvtr s laptblatmbk nagyon nagy mretek lennnek, ezrt a rend-
szertervezk bevezettk a hromszint lekpezst. Ezt a 2.5. brn lthatjuk.
Virtulis cm Fizikai memria
Lapknyvtr-
index
Kzp-
lapknyvtrindex
Laptblaindex offset
Lapknyvtr Kzps Laptbla
lapknyvtr
2.5. bra. Hromszint lekpezs (Alpha)
30
2.4. Memriakezels
Ahogy az brbl is lthat, a lekpezs alapelve megegyezik az elzekben
trgyalt ktszint lekpezssel, csak kiegszl egy tovbbi szinttel. A lap-
knyvtr s a laptbla kz beiktattunk egy kzps lapknyvtrat (page
middle directory), tovbb a virtulis cm is ngy rszre tagoldik. A lap-
knyvtrbejegyzsek gy a kzps lapknyvtrakra hivatkoznak, amelynek
a bejegyzsei laptblkra mutatnak. A fizikai cm, hasonlan az elzhz, a
laptbla ltal tartalmazott lapcmbl s az eltols sszegbl addik.
A Linux-kernel fejleszti termszetesen egysgesre szerettk volna elk-
szteni az MMU-k kezelst, fggetlenl az architektrk klnbsgeitl.
Ezrt a Linux-kernel a hromszint lekpezst alkalmazta. Ahhoz azonban,
hogy ez az x86-os architektrkon is mkdjn, egy kis trkkhz kellett fo-
lyamodni: az x86-os rendszerek esetn a kzps lapknyvtr csak egy elemet
tartalmaz, gy a hromszint lekpezs ktszintv egyszersdik.
Ezt kvettk az ia64 -es rendszerek, ahol mr a ngyszint lekpezst
tmogatja a hardver. Eleinte a kernelfejlesztk trkkkkel a hromszint le-
kpezst alkalmaztk ezeken a rendszereken is, m ezzel mestersgesen kor-
ltoztk a folyamatok maximlis virtulis cmtert 512 GB-ra. A kernel miatt
korltozni a hardver kpessgt nem tnt clszernek, ezrt ksbb talak-
tottk a lekpezalgoritmust ngyszintre. gy a virtulis cm felptse az
ia64 -es rendszerek esetben a 2.6. bra szerint alakul.
PGD PUD PMD PTE
Eltols


PGD Lapknyvtr (Page Global Directory)
PUD Fels lapknyvtr (Page Upper Directory)
PMD Kzps lapknyvt
al gorit-
musban
Directory)
PTE Laptbla (Page Table)
2.6. bra. A virtulis cm felptse ia64-es rendszerek esetn
gy a jelenlegi kernel a platformfggetlen virtulismemria-kezel algorit-
musban a ngyszint lekpezst hasznlja, amelyet az egyszerbb architek-
trk esetben illeszt az adott rendszerhez.
2.4.4. Igny szerinti lapozs
A vals lettel ellenttben a lustasg a szmtgpek vilgban sokszor igen
elnys tulajdonsg. Ugyanis ha csak akkor vgez el egyes mveleteket a gp,
amikor tnyleg szksges, akkor ezzel rendszeridt takartunk meg a tbbi
feladat szmra, gy a rendszernk teljestmnye nvekszik.
31
2 . fejezet: Betekints a Linux-kernelbe
Ez az elmlet, tltetve a memriakezels vilgba, jelentheti azt, hogy
csak akkor tlti be a rendszer a lapot a httrtrolrl, amikor egy processz
hivatkozik r, ignyli az informcit. Pldul egy adatbzis-kezel program-
nl elg, ha csak azokat az adatokat tartja a memriban, amelyekre ppen
szksg van. Ezt a technikt igny szerinti lapozsnak (demand paging)
nevezzk.
Amikor egy processz olyan laphoz prbl hozzfrni, amelyik ppen nem
tallhat meg a memriban, az MMU egy laphibt (page fault) generl,
amellyel rtesti az opercis rendszert a problmrl
17

Ha a hivatkozott virtulis cm nem rvnyes, az azt jelenti, hogy a pro-
cessz olyan cmre hivatkozott, amelyre nem lett volna szabad. Ilyenkor az
opercis rendszer a tbbi vdelmben megsznteti a processzt.
Ha a hivatkozott virtulis cm rvnyes, de a lap nem tallhat ppen a
memriban, az opercis rendszernek be kell hoznia a hivatkozott lapot
a httrtrolrl. Termszetesen ez a folyamat eltart egy ideig, ezrt a pro-
cesszor addig egy msik processzt futtat tovbb. A beolvasott lap kzben be-
rdik a merevlemezrl a fizikai memriba, s bekerl a megfelel bejegyzs
a laptblba. Ezek utn a processz a meglls helytl fut tovbb. Ilyenkor
termszetesen a processzor mr el tudja vgezni a lekpezst, gy folytatdhat
a feldolgozs.
A Linux az igny szerinti lapozs mdszert hasznlja a processzek kd-
jnak a betltsnl is. Amikor a programot lefuttatjuk, akkor a rendszer
nem tlti be a teljes kdot a fizikai memriba, csak az elejt, mg a marad-
kot csak lekpezi a folyamat virtulismemria-terletre. Ahogy a kd fut, s
laphibkat okoz, a Linux gy hozza be a kd tbbi rszt is. Ez ltalban sz-
szessgben is gyorsabb, mint betlteni a teljes programot, mert a nagyobb
programok esetben gyakran csak egy rsze fut le a kdnak.
2.4.5. Lapcsere
Amikor a processznek jabb virtulis lapok behozsra van szksge, s nincs
szabad hely a fizikai memriban, az opercis rendszernek helyet kell terem-
tenie. Ezt gy teszi meg, hogy egyes lapokat eltvolt a fizikai memribl.
Ha az eltvoltand lap kdot vagy olyan adatrszeket tartalmaz, ame-
lyek nem mdosultak, akkor nem szksges a lapot lementeni. Ilyenkor ez
egyszeren eldobhat, s legkzelebb, amikor szksg lesz r, megtallhat a
httrtroln.
Ha azonban a lap mdosult, akkor az opercis rendszernek el kell trol-
nia a tartalmt, hogy ksbb elhozhassa. Ezeket a lapokat nevezzk pisz-
kos lapnak (dirty page), s az llomnyt, ahova az MMU az eltvoltskor
17
Az illeglis memria-hozzfrsek (pl. csak olvashat lapra rs) szintn laphibt ered-
mnyeznek (ezt lsd ksbb).
32
2 .4 . Memriakezels
elmenti ket, lapcserellomnynak (swap file).
18
A hozzfrs a lapcse-
reeszkzhz nagyon hossz ideig tart a rendszer sebessghez kpest, ezrt
az opercis rendszernek az optimalizci rdekben mrlegelnie kell.
Ha a lapcsere-algoritmus nem elg hatkony, elfordulhat, hogy egyes la-
pok folyamatosan cserldnek, s ezzel pazaroljk a rendszer idejt. Hogy ezt
elkerljk, az algoritmusnak lehetleg a fizikai memriban kell tartania
azokat a lapokat, amelyeken a processzek ppen dolgoznak, vagy ksbb dol-
gozni fognak. Ezeket a lapokat hvjuk munkahalmaznak (working set).
Ugyanakkor az algoritmusnak elg egyszernek kell lennie, hogy ne ignyel-
jen tl sok rendszeridt a vlaszts.
A kernel dntshoz munkjt tmogat algoritmusok sokszor bele van-
nak ptve a processzorokba. A kernel ezek kzl ugyanakkor csak azokat az
algoritmusokat hasznlhatja fel, amelyeket minden processzor ismer, a tbbit
szoftverben kell implementlnia.
A Linux az gynevezett Least Recently Used (LRU, legrgebben hasz-
nlt") lapozsi technikt alkalmazza a lapok kivlasztsra. Ebben a sm-
ban a rendszer nyilvntart egy lapok kztti sorrendet az alapjn, hogy mikor
frtek hozz utoljra az adott laphoz. Minl rgebben frtek hozz egy laphoz,
annl inkbb sor kerl r a kvetkez lapcseremveletnl.
A laphozzfrsi sorrendet egy lncolt listban lehetne kezelni. Ha hozzf-
rnk egy laphoz, akkor a hivatkozst a lncolt lista elejre tesszk. Ezltal
a hivatkozsnak a listban elfoglalt helye megmutatja, hogy milyen sorrend-
ben frtnk hozz a lapokhoz. Ha azonban minden laphozzfrs esetn fris-
stennk a lncolt listt, akkor ez hasznlhatatlan mrtkben lasstan a
memria-hozzfrs sebessgt.
19

Ezrt az elbb emltett egyszer metdussal szemben a Linux egy mdos-
tott durva lptk LRU-technikt hasznl. Ez a megolds alapveten kt m-
veleten alapul. Amikor egy folyamat hozzfr egy laphoz, akkor ezt egy jelzbit
belltsval jelzi a rendszer. Ezt a mveletet minden jelenlegi architektra
hardveresen tmogatja, gy gyorsan mkdik. Msrszt elg egyszer ahhoz,
hogy szksg esetn szoftveresen is megvalsthat legyen.
A msik mvelet kt lncolt lista nyilvntartsa. Az egyik lista az aktv
lapokat, a msik az inaktv lapokat tartja nyilvn. A lapok mindkt irnyban
vndorolnak a kt lista kztt. A vlts alapja a hozzfrsi bit llapota.
A kernel bizonyos idkznknt megvizsglja az elbb emltett hozzfrst
jelz bit llapott. Ha a lap idig az inaktv listban szerepelt, akkor tkerl
az aktv lista elejre. Ha idig aktv volt, s a legutbbi vizsglat ta nem fr-
tek hozz, akkor az inaktv lista elejre kerl. Ha ezek utn a legrgebben
18
A lapcserellomny nem felttlen fjl, lehet partci vagy akr kln merevlemez is.
Ezrt clszerbb egysgesen eszkznek nevezni. A Linux tbb lapcsereeszkzt is tud
hasznlni egyszerre. Ezeket priorits szerint rendezi. Amg meg nem telik, a legnagyobb
priorits eszkzt hasznlja, majd a kvetkezvel folytatja.
19
A megolds a gyakorlatban azrt sem implementlhat, mert a kernelnek rtestst kel-
lene kapnia minden memrialap-hozzfrsrl. Ez a hardver tmogatsa nlkl nem old-
hat meg.
33
2. fejezet: Betekints a Linux-kernelbe
hasznlt lapra vagyunk kvncsiak, akkor az inaktv lista vgn talljuk meg.
Nem biztos, hogy az inaktv lista vgn a sorrend teljesen korrekt az utols
hozzfrs idpontja szerint, de nincs is szksgnk abszolt pontos eredmny-
re. Mindegyik ott tallhat laphoz rgen frtek hozz. Ez a kis pontatlansg
nem zavar, hiszen ennek kvetkeztben az algoritmusunk nagysgrendekkel
gyorsabb, mint a korbban trgyalt pontos algoritmus.
2.4.6. Megosztott virtulis memria
A virtulismemria-kezels lehetv teszi tbb processznek, hogy egy kzs
memriaterleten osztozzanak. Ehhez csak arra van szksg, hogy bejegyez-
znk a processzek laptbliba egy kzs fizikai lapra val hivatkozst, gy
kpezve le ezt a lapot a virtulis cmterletre. Termszetesen ugyanazt a la-
pot a kt virtulis cmtartomnyban kt klnbz helyre is lekpezhetjk.
Ez a megosztott memriakezels lehetsget ad a folyamatoknak, hogy a
kzs memriaterleten adatokat cserljenek. Ugyanakkor a megfelel m-
kds rdekben szinkronizlsi mdszereket is hasznlni kell.
A Linux a szlkezelst is a megosztott virtulis memria segtsgvel imp-
lementlja. (Errl mr volt sz a 2.3.4. alfejezetben.) Ilyenkor a processzek k-
zs memrin osztoznak, s mint szlakat hasznlhatjuk ket.
2.4.7. Msols rskor (COW technika)
A Linux a megosztott memrit nemcsak adattvitelre, illetve a szlak imp-
lementcijnl hasznlja, hanem a folyamatok msolsnak gyorstsra is
(fork). Elmletileg egy j folyamat ltrehozsakor a szlfolyamat cmtere
lemsoldik, s ez alkotja a gyerek cmtert. A valsgban nem ez trtnik,
mert ez nagyon lass s nagy memriaigny folyamat lenne. Helyette a Li-
nux a msols rskor (copy on write, COW) technikjt hasznlja.
Amikor a gyerekfolyamathoz le kellene msolni a szlfolyamat memria-
tartalmt, valjban a rendszer csak a virtulismemria-lekpezshez hasznlt
laptblkat msolja le. gy a gyerekfolyamat cmterbe ugyanazok a fizikai la-
pok kpzdnek le, mint amelyeket a szl hasznl. m a folyamatok elkln-
tse rdekben a lapok csak olvashatk lesznek mindkt folyamat szmra.
Ha valamelyik folyamat rni prblja a lapot, ez egy hozzfrsi hibt okoz.
A hiba lekezelrutinja tudja a hiba okt, ezrt a lapot lemsolja, s lecserli a
virtulis memriban. Ettl kezdve mindkt folyamat ismt tudja rni a lapot,
illetve a msolatt.
34
2.4. Memriakezels
2.4.8. A hozzfrs vezrlse
A laptblabejegyzsek az eddig trgyaltak mellett hozzfrsi informcikat
is tartalmaznak Amikor az MMU egy bejegyzs alapjn a virtulis cmeket
fizikai cmekk alaktja t, prhuzamosan ellenrzi azokat a hozzfrsi in-
formcikat is, hogy az adott processz szmra a mvelet engedlyezett-e,
vagy sem.
Tbb oka is lehet, amirt korltozzuk a hozzfrst egyes memriaterletek-
hez. Egyes terletek (pldul a programkd trolsra szolgl memriarsz)
csak olvashat lehet, ezrt az opercis rendszernek meg kell akadlyoznia, hogy
a processz adatokat rhasson a kdjba. Ezzel szemben azoknak a lapoknak,
amelyek adatokat tartalmaznak, rhatnak kell lennik, de futtatni nem sza-
bad a memria tartalmt. Meg kell akadlyoznunk tovbb, hogy a processzek
hozzfrhessenek a kernel adataihoz, a biztonsg rdekben ezeket csak rend-
szerhvsokon keresztl rhetik el.
A Linux az albbi jogokat tartja nyilvn egy lappal kapcsolatban (ezeket
kpezi le az adott architektrn rvnyes jogokra):
a lap bent van-e a fizikai memriban;
olvashat-e;
rhat-e;
futtathat-e;
a lap a kernel cmterhez vagy a felhasznl cmterhez tartozik-e;
a lapot mdostottk-e (dirty), gy ki kell-e majd rni a lapcserello-
mnyba;
a laphoz hozzfrtek-e;
tovbbi, a gyorsttrakkal kapcsolatos belltsok.
2.4.9. A lapkezels gyorstsa
Ha egy virtulis cmet megprblunk lekpezni fizikai cmm, akkor lthat,
hogy ez tbb memria-hozzfrst is ignyel, mire vgigjutunk az sszes szin-
ten. Jllehet idig azt mondtuk, hogy a memria olvassa arnylag gyors m-
velet, valjban elmarad a CPU sebessge mgtt. gy a laplekpezs mveletei
visszafoghatjk a rendszer teljestmnyt. Hogy ezt megakadlyozzk, a
rendszermrnkk gyorsttrakat integrltak az MMU-ba. Ezek neve:
Translation Look-aside Buffer (TLB, flretekint fordtsbuffer": a flre-
tekints" az alternatv keressi mdra utal).
35
2. fejezet: Betekints a Linux-kernelbe
A TLB trolja a legutbbi laplekpezsek eredmnyt. Amikor egy virtu-
lis cmet kell lefordtania az MMU-nak, akkor elszr egyez TLB-bejegyzst
keres. Ha tall, akkor a segtsgvel azonnal lefordthatja a fizikai cmre, s
ezzel jelents gyorsulst rhet el.
A Linuxnak a TLB kezelsvel kapcsolatosan nincs sok teendje. Egyet-
len feladata, hogy rtestse az MMU-t, ha valamelyik trolt lekpezs mr
nem rvnyes.
2.5. A virtulis llomnyrendszer
Ebben a fejezetben bemutatjuk az Unix-vilg egyik legfontosabb absztrakci-
jt, az llomnyabsztrakcis felletet. Ennek a felletnek a programozst
a 4. llomny-s I/O kezels fejezetben, az llomnykezelsnl mutatjuk be,
a fellet megvalstst pedig a 7. Fejleszts a Linux-kernelben fejezetben
rszletezzk.
2.5.1. Az llomnyabsztrakci
Az els Unix rendszer egyik jtst, amely mg ma is thatja az sszes oper-
cis rendszert, a hagyomny a kvetkezkppen foglalja ssze minden llo-
mny (everything is a file"). Ez a taln kiss leegyszerstett megfogalmazs
azt takarja, hogy a klnbz 1/O perifrik sok tekintetben gy hasznlhatk,
mint az llomnyok. Ha egy folyamat hasznlni szeretn ket, jeleznie kell ezt
a szndkt a kernelnek, amely egy llomnylert ad vissza. Ezek utn mind
az llomnyokat, mind a perifrikat rjuk, olvassuk, majd bezrjuk.
Az implementci szintjn ez gy jelenik meg, hogy az llomnyok meg-
nyitsakor egy llomnylert kapunk vissza, s ugyanazokkal a fggvnyek-
kel rhatjuk, illetve olvashatjuk az llomnyokat.
Ez az tlet nagyon knyelmess tette a perifrik s az llomnyok kztti
tjrhatsgot. A billentyzet is egy llomny, amelyrl csak olvashatunk, a
terminl kimenete egy olyan llomny, amelyet csak rhatunk. Ezrt egy prog-
ram kimenete lehet egy llomny vagy egy terminl, ez mindssze a megnyitott
llomnylertl fgg. St kt program kztti kommunikcit megvalst cs-
vezetk hasznlata is egy llomnylerval vgzett rs s olvass.
Termszetesen rgtn felmerl az a problma, hogy az rson s az olvas-
son kvl szmos mvelet van (pldul pozicionls), amelyre szmos eszkz
(pldul a billentyzet) nem alkalmas. St mr az elz bekezdsben felfigyel-
hettnk arra, hogy a billentyzetet reprezentl lert csak olvashatjuk, mg
a terminl lerjt csak rhatjuk.
36
2.5. A virtulis llomnyrendszer
Ez egyltaln nem zavar, hiszen br vannak klnbsgek, mi a hasonl-
sgokat szeretnnk kiaknzni. Egy bemeneti llomny, amelybl csak olva-
sunk, lecserlhet a billentyzetre anlkl, hogy egyetlen olvasst vgz
fggvnyt lecserlnnk a programunkban.
A tovbbiakban az llomny s a fjl szavakat a Linux filozfijval ssz-
hangban absztrakt rtelemben hasznljuk mind llomnyrendszerbeli llo-
mnyok, mind 1/0 eszkzk lehetnek a ler mgtt.
Az llomnyabsztrakcis fellet az sszes llomny- s I/O mvelet uni-
ja, sszessge. Ez az albbi mveleteket jelenti:
Olvass (read): byte-ok olvassa egy adott mret bufferba.
rs (write): egy adott mret buffer kirsa.
Pozicionls (llseek): az aktulis pozci mdostsa.
Aszinkron olvass s rs (aio_read, aio_write): POSIX aszinkron I/O
mveletek.
Knyvtr tartalmnak olvassa (readdir): ha az llomny knyvtr,
akkor a tartalmt adja vissza.
Vrakozs llomnymveletre (poll): ha az olvassi vagy rsi mve-
let ppen nem hajthat vgre, akkor tudunk vrakozni a felttel telje-
slsre.
I/O vezrls (ioctl): specilis mveletek, belltsok az llomnyra.
Lekpezs a memriba (mmap): az llomnyt vagy annak egy rszt
lekpezhetjk a virtulis memriba, gy memriamveletekkel rhat-
juk s olvashatjuk. Ha az llomny eszkz, akkor a segtsgvel lehe-
tsg van megosztott memria kialaktsra az alkalmazs s az
eszkzmeghajt kztt.
Megnyits (open): az llomny megnyitsa. A kernel a megnyits
alapjn tudja, hogy az llomny hasznlatban van.
Lezrs (close): az llomny lezrsa.
Szinkronizls (sync, fsync, fflush, aio_fsync ): ha bufferelt rst al-
kalmazunk, akkor a buffer tartalmt azonnal kirja.
llomnyzrols (flock): ha tbb folyamat hasznln az llomnyt,
akkor a zrolsokkal szinkronizlhatjuk a hozzfrst.
Ismt hangslyozzuk, hogy ritka az az eszkz vagy llomny-rendszerbeli l-
lomny, amely az sszes mveletet kpes lenne megvalstani. Ha egy ker-
nelobjektum megvalstja az llomnyabsztrakcis interfszt, akkor legalbb
egy mveletet tmogat a fentiek kzl. Egy lerra meghvhatjuk a fenti
fggvnyek brmelyikt. Ha a mvelet nem lenne tmogatva, akkor hibaze-
nettel trne vissza, amelyet a programunkban lekezelhetnk.
37
2. fejezet: Betekints a Linux-kernelbe
sszefoglalva az eddigieket: az llomnylerk akkor cserlhetk fel, ha
csak a mindegyikk ltal tmogatott mveleteket hasznljuk. Vagyis az
llomnyabsztrakcis fellet az mveletek unija, a mveletek metszete
mentn pedig ugyanazokkal a fggvnyekkel hasznlhatunk tbb klnbz
llomnytpust.
Ezek utn vegyk sorra az llomnytpusokat. Ezek az albbiak:
egyszer llomnyok (regular files),
specilis llomnyok (special files).
Az egyszer llomnyok a hagyomnyos, llomny-rendszerbeli llomnyokat
jelentik. Egy llomny-rendszerbeli llomny mveletei fggenek az llo-
mny tpustl. Az Ext3-as llomnyrendszer egyszer llomnyai az albbi
mveleteket tmogatjk:
megnyits, lezrs;
olvass, rs;
aszinkron olvass, rs;
pozicionls;
I/O kontroll;
memriba val lekpezs;
szinkronizls.
A specilis llomnyok olyan nem hagyomnyos llomnyok, amelyek megva-
lstjk az llomnyabsztrakcis fellet legalbb egy mvelett.
2.5.2. Specilis llomnyok
A Linux szmos olyan llomnytpust is hasznl, amely a hagyomnyos rtelem-
ben vve nem llomny, m implementlja az llomnyabsztrakcis interfszt.
2.5.2.1. Eszkzllomnyok
Az eszkzkhz val hozzfrs eszkzllomnyokon (device file) keresztl
trtnik. Az eszkzllomnyoknak kt tpusa van: blokkos eszkzllomny
(block device file) s karakteres eszkzllomny (character device file).
A karakteres eszkzllomnyok az ltalnosabban hasznlt eszkzinter-
fszek. Az llomnyabsztrakcis interfsznek akr minden fggvnyt tmo-
gathatjk attl fggen, hogy az eszkzre rtelmezhetk-e.
A blokkos eszkzllomnyok specilisabbak, s csak az albbi mvelete-
ket tmogatjk:
38
2.5. Avirtulis llomnyrendszer
megnyits, bezrs;
olvass, rs;
aszinkron olvass, rs;
pozicionls;
I/O vezrls;
memriba val lekpezs;
szinkronizls.
Jllehet a karakteres s a blokkos eszkzket megadhatjuk a fenti mdon a
rajtuk rtelmezett mveletekkel, a mkdsk alapjn rthetjk meg ket
igazn. Az llomnyabsztrakcis fellet tulajdonkppen fggvnypointerek
halmaza: sszerendeli a mveleteket azok megvalstsval. A mveleteket
gynevezett eszkzvezrlk (device drivers) valstjk meg. Ha pldul meg-
hvjuk az open rendszerhvst, akkor ez a kernelben gy van implementlva,
hogy megkeresi az adott llomnylerhoz tartoz eszkzvezrl fggvnymuta-
t listjt, s kivlasztja az openhez tartoz bejegyzst. Ha az open mveletet
nem valstja meg az adott eszkzvezrl, akkor ez a mutat nulla. Ebben az
esetben a kernel az open rendszerhvs visszatrsi rtkben jelzi a hibt. Ha
az eszkzvezrl megvalstja a megnyitsi mveletet, akkor a vizsglt mutat
egy kezelfggvnyre mutat, amelyet a rendszerhvs implementcija meghv.
Az eszkzvezrlk a kernel rszt alkotjk. Gyakran gynevezett kernelmodul-
ban implementljuk ket (lsd a 7.3. Kernelmodulok cm alfejezetet).
A karakteres eszkzvezrlk, amint nevk is mutatja, byte-onknti rst-
olvasst tesznek lehetv. A karakteres eszkzk egyszeren megadjk a t-
mogatott mveletekre mutat fggvnymutatkat, a kernel pedig kzvetlenl
meghvja ket.
A blokkos eszkzvezrlk felptse specilisabb, mivel olyan eszkzkhz
kszltek, amelyeknl nem frhetnk hozz egy-egy byte-hoz kzvetlenl,
hanem csak byte-ok csoportjt, blokkokat tudunk kezelni. Erre j plda a me-
revlemez, amelyhez ha byte-onknt frnnk hozz, akkor ez drasztikusan le-
lasstan a rendszert. Az eszkzvezrl felptse sokkal bonyolultabb, mert
kztes gyorsttrakat kell alkalmaznia a blokkok trolsra, illetve aszink-
ron mechanizmusokat a blokkok mozgatsra. Az llomnyabsztrakcis inter-
fszt sem kzvetlenl valstjk meg: ezt a kernel valstja meg helyettk, s
egy mveletsort hoz ltre szmukra, amelyben felsorakoztatja a krseket.
Ekzben a kernel szmos optimalizcit is elvgez. A blokkos eszkzvezrlk
tetszleges sorrendben szolglhatjk ki a mveletsorban tallhat mveleteket.
Jllehet vannak eszkzk, amelyek se nem blokkosak, se nem karaktere-
sek (pldul a hlzati krtya), az eszkzvezrlk nagy tbbsge jl megval-
sthat valamelyik eszkzvezrl-tpussal.
39
2. fejezet: Betekints a Linux-kernelbe
2.5.2.2. Knyvtr
A knyvtr olyan specilis llomny, amely a benne lv llomnyok listjt
tartalmazza. A rgi Unix rendszerekben az implementcik megengedtk,
hogy a programok az egyszer llomnyok kezelsre szolgl fggvnyekkel
hozz is frjenek a knyvtrllomnyokhoz. A knnyebb kezelhetsgrt
azonban egy specilis rendszerhvskszlet kerlt az jabb rendszerekbe.
(Ezeket lsd a 4.4. Knyvtrmveletek alfejezetben.)
2.5.2.3. Szimbolikus hivatkozs
A szimbolikus hivatkozs (symbolic link, symlink, soft link) olyan specilis
llomny, amely egy msik llomny elrsi informciit tartalmazza. Ami-
kor megnyitjuk, a rendszer rzkeli, hogy szimbolikus hivatkozs, kiolvassa
az rtkt, s megnyitja a hivatkozott llomnyt. Ezt a mveletet a szimboli-
kus hivatkozs kvetsnek hvjuk. A rendszerhvsok alaprtelmezett eset-
ben kvetik a szimbolikus hivatkozsokat.
2.5.2.4. Csvezetk
A csvezetk (pipe) a Unix-vilg legegyszerbb IPC-mechanizmusa. Mint a
neve is elrulja, egy virtulis csvezetket kpez memriban, amelynek v-
geire egy-egy llomnylerval hivatkozhatunk. ltalban az egyik processz
informcikat r bele az egyik oldaln, mg egy msik processz a msik vgn
a bersi sorrendben kiolvassa az adatokat. Mivel a kt processz prhuzamo-
san kezeli, ezrt kis memriaterletre van szksg kztes trolknt.
A parancsrtelmez a csvezetkeket a processzek kztti I/O tirnyts-
ra, mg sok ms program az alprocesszeikkel val kommunikcira hasznlja.
Kt tpust klnbztetjk meg: nvtelen (unnamed) s megnevezett
(named) csvezetkeket. A nvtelen csvezetkek akkor jnnek ltre, amikor
szksg van rjuk, s amikor mindkt oldal lezrja, akkor eltnnek. Azrt
nvtelenek, mert nem ltszdnak a fjlrendszerben, nincsen nevk. A megne-
vezett csvezetkek ezzel szemben fjlnvvel jelennek meg a fjlrendszerben,
s a processzek ezzel a nvvel frhetnek hozzjuk. A csvezetkeket FIFO-
nak is nevezik, mivel az adatok FIFO- (first in, first out, elsknt berakott
elem vehet ki elszr) rendszerben kzlekednek rajta.
Hangslyozand, hogy az llomnyabsztrakcis fellet hasznlata nem
felttlenl jelenti azt, hogy az llomny megjelenik az llomnyrendszerben.
Erre j pldt nyjtanak a nvtelen csvezetkek s a socketek.
40
2 .5. A virtulis llomnyrendszer
2.5.2.5. Socket
A socketek hasonltanak a csvezetkekre. IPC-csatornaknt hasznlhatk a
folyamatok kztt, m flexibilisebbek, mint a csvezetkek. Ktirnyak, s
lehetv teszik a kommunikcit kt, klnbz gpen fut processz kztt is.
Vagyis ezekkel valsthatjuk meg a hlzati kommunikcit (lsd a ksbbi
fejezetekben).
A socketek llomnyknt kezelhetk, mint a tbbi specilis llomny is,
m a rendszer tartalmaz olyan fggvnyeket is, amelyek specilisan a socke-
tekhez kszltek.
Az llomnyrendszerben tallkozhatunk gynevezett socketllomnyokkal.
Ez a Unix Domain Socket protokoll (lsd a 6.4. Unix domain socket alfejezet-
ben) cmzsi mechanizmusnak a rsze, s kt folyamat kztti socketkapcsolat
felptsben lt el feladatot. Kzvetlenl az llomnyt nem hasznljuk, csak
meghatrozott rendszerhvsok paramtereknt.
A socketllomny csak a Unix Domain Socket protokoll esetn tlt be sze-
repet. Ms protokolloknl a socketmechanizmus nem hasznlja az llomny-
rendszert.
2.5.3. Az inode
Az llomny egyetlen egyedi azonostja az inode (information node, infor-
mcis csompont). Kulcsszerepet tlt be a kernel llomnykezelsben.
Az llomny inode-ja tartalmaz szinte minden informcit az llomnyrl, be-
lertve a jogokat, a mrett, a hivatkozsok szmt. Ez all kt informci
kpez kivtelt:
az llomny neve,
az llomny adattartalma, mivel az inode csak a mutatt tartalmazza
az llomnyhoz tartoz adatblokkokra, magt az adatot nem.
2 0

Az llomnyok neve a knyvtrakban van eltrolva. A knyvtrllomny nv
s inode-szm sszerendelseket tartalmaz. Vagyis amikor egy llomny tar-
talmt meg akarjuk nzni, akkor megadjuk a nevt. A kernel a knyvtrl-
lomnyban megkeresi a nvhez rendelt inode-ot. Az inode-ban tallt mutat
alapjn pedig elrkeznk a tnyleges adathoz. Ezt a lekpezst a 2.7. bra je-
lenti meg.
2 0
A Linux-kernel 3.2 -es verzijtl az ext4 -es llomnyrendszer tartalmazza az gyneve-
zett inline data funkcit, amely lehetv teszi, hogy nagyon kis adatmennyisg esetn az
inode szabad terletn troldjon az llomny tartalma. Ez sok kis llomny esetben
szmottev trhely-megtakartst eredmnyez.
41
2. fejezet: Betekints a Linux-kernelbe
Knyvtr
Knyvtri
fjli inode1
fj l2 inode2
inode inode1

Jogosultsg
Tulajdonos
Csoport
Adatindex
inode
inode2
Jogosultsg
Tulajdonos
Csoport
Adatindex
2.7. bra. llomnynvtl az adatig
Lehetsgnk van arra is, hogy ugyanarra az inode-ra ms nvvel is hivat-
kozzunk, akr msik knyvtrbl. Ezt nevezzk merev hivatkozsnak
(kard link) (lsd a 2.8. brt).
Knyvtr
Knyvtri
fjlt inode1
fjl2 inode2
Knyvtr
Knyvtrt
113 inode1
inode
inode1
Jogosultsg
Tulajdonos
Csoport
Adatindex
2.8. bra. Merev hivatkozs
Az inode-szmnak azonban csak egy llomnyrendszeren bell van rtelme.
Ezrt merev hivatkozst csak egy partcin bell hozhatunk ltre. Partcik
kztt csak a korban emltett szimbolikus hivatkozs hasznlhat (lsd a
2.9. brt).
42
22.52. A virtulis llomnyrendszer
Knyvtr
Knyvtrt
fj 11
fjl2 inode2


Knyvt inode1
yvtrt
fil3 inode3
inode
inodei
Jogosultsg
Tulajdonos
Csoport
Adatindex
inode
inode2
Jogosultsg
Tulajdonos
Csoport
Link nv
2.9. bra. Szimbolikus hivatkozs
Az inode tartalmazza a r hivatkoz llomnynevek, vagyis a merev hivatko-
zsok szmt. Ezt hvjuk link countnak (a kapcsolatok szma) Amikor egy
llomnyt trlnk, akkor valjban egy merev hivatkozst trlnk, s ez a
szm cskken eggyel. Ha elri a 0 rtket, s egyetlen folyamat sem tartja
ppen nyitva az llomnyt, akkor tnylegesen trldik, s a hely felszabadul.
Viszont ha legalbb egy folyamat nyitva tartja, csak akkor trtnik meg a
trolhely felszabadtsa, miutn mindenki bezrta.
2 1

Az inode trolsnak mdja s tartalma a hasznlt llomnyrendszer
fggvnye. Jelentsen eltrhet a klnbz llomnyrendszer-tpusoknl. m
ennek lekezelst nem hrthatjuk az alkalmazsokra. Ezrt a kernel a me-
mriban csak egyfle reprezentcit hasznl, amelyet in-core inode-nak
e tall-
koznak.
a almazsok minden e tall-
koznak.
a reprezentcival tall-
koznak. A merevlemezen trolt inode-okat on-disk inode-nak nevezzk.
Amikor egy processz megnyitja az llomnyt, az on-disk inode betltdik, s a
kernelben tallhat llomnyrendszer-kezel rutinok automatikusan in-core
inode-d alaktjk. A lekpezst visszafel is elvgzik, amikor az in-core inode
mdosul. A megfeleltethet rtkeket visszakonvertljk, s lementik az on-
disk inode-ba.
Az on-disk s az in-core inode nem teljesen ugyanazt az informcit tartal-
mazza. Pldul csak az in-core inode knyveli az adott llomnyhoz kapcsold
folyamatok szmt. Nhny llomnytpus, pldul a nvtelen csvezetk, nem
rendelkezik on-disk inode-dal, csak a memriban ltezik.
2 1
Ilyenkor nem trldik tnylegesen az llomny tartalma, csak specilis esetekben. Val-
jban csak jra felhasznlhatnak lesznek nyilvntva afjl3 kok.
4 3
22. fejezet: Betekints a Linux-kernelbe
2.5.4. Az llomnylerk
Az alkalmazsok szmra az llomnyt tbbnyire az llomnyler reprezen-
tlja Amikor egy llomnyt megnyitunk, akkor a kernel visszaad egy kis
egsz szmot (int), amely a tovbbiakban az llomnnyal kapcsolatos mvele-
tek sorn hivatkozsknt szolgl az llomnyra.
Az llomnyler csak a folyamaton bell van rtelmezve. Ha ugyanazt az
llomnyt egy msik folyamatban is megnyitjuk, akkor lehet, hogy msik l-
lomnylert kapunk. Az llomnylerk konkrt szmrtke valjban az l-
lomnyok megnyitsnak sorrendjtl fgg. A kernel 0-tl kezdden kezdi
kiosztani a folyamat szmra. m az els hrom ler foglalt.
0: bemenet
1 kimenet
2 : hibakimenet
Ezt kveten az jabb llomnymegnyitsok sorn egyre nagyobb szmokat
kapunk vissza. Lehetsgnk van arra is, hogy llomnylerkat kicserljnk
egymssal. gy az is megoldhat, hogy a 0, 1, 2 lerk mgtt az llomnyt ki-
cserljk, s gy a folyamat bemenett vagy kimenett pldul egy csveze-
tkre cserljk le. Ezt a kimenet/bemenet tirnytsnak nevezzk (lsd
rszletesen a 4.1.8. llomnyok tirnytsa cm alfejezetben).
A bemenetet, a kimenetet s a hibakimenetet nemcsak a programban,
hanem akr mr indtsnl a shell parancsban is tirnytatjuk:
ere
A fenti pldban az els program kimenett egy csvezetkre ktjk, amelynek a
msik vgt a sort program bemenetre csatlakoztatjuk. A sort program bc-
sorrendbe rendezi a sorokat, majd a kimenett egy llomnyba irnytjuk t.
2.6. A Linux programozsi fellete
A Linux programozsi felletnek kt jl elklnthet szintje van: az egyik a
kernel fellete, a msik az erre pl, felhasznli zemmdban fut knyv-
trak. A kernel felhasznli zemmdban hvhat funkciit rendszerhv-
soknak (system call, rviden syscall) nevezzk, ezek sszessge adja a kernel
programozsi fellett. A rendszerhvsok teszik lehetv az tjrst a felhasz-
nli s a kernelzemmd kztt: ezeket ugyanis felhasznli zemmdban
hvjuk, de kernelzemmdban futnak. Mivel az zemmdok kztti vlts
architektrafgg, ezrt az implementci rszletei is klnbznek az egyes
architektrkon.
44
- -- write() libc hvs
22.62. A Linux programozsi fellete
A rendszerhvst egyedi szm, a rendszerhvsszm (syscall number)
azonostja. Erre azrt van szksg, mert az zemmdok kztti tkapcsols-
kor nem hagyomnyos fggvnyhvst vgznk: a kernelnek egy belpsi
pontja van, amely a memrin s a regisztereken keresztl veszi t az adato-
kat, kztk a rendszerhvsszmot. Ez utbbi segtsgvel egy tblzatbl ki-
vlasztja, majd meghvja a megfelel rendszerhvs-kezelt. A Linux rklte
a rendszerhvsait a Unix rendszerektl, amely meglehetsen stabil s kifor-
rott felletet ad. Ezrt nagyon ritkn vezetnek be j rendszerhvsokat. Ha
mgis szksgnk lenne erre, a Linux makrkkal teszi egyszerv j rend-
szerhvs ksztst. Ezt a 2.10. bra szemllteti.
A rendszerhvsok meghvshoz tisztznunk kell az
alkalmazsprog-
ramozi fellet (Application Programming Interface, API) s a binris al-
kalmazsfellet (Application Binary Interface, ABI) fogalmt. Ezekre a
fogalmakra magyarul is az angol rvidtst hasznljuk.
Az API forrskdszint felletet definil, a Linux estben C-fggvnyek
prototpusait, illetve azok viselkedst, a Linux esetn kziknyvoldalakat.
Jllehet a rendszerhvsokat kzvetlenl is hvhatnnk, hiszen azok is C-
fggvnyek, a Linuxot a C-programknyvtr (C library, libc) API-jn ke-
resztl programozzuk. Ennek az API-nak tlnyom rsze POSIX-szabvny,
de a Unix/Linux opercis rendszerek estben elg kzel van a rendszerhv-
sok biztostotta API-hoz. Sok esetben a libc fggvny maga a rendszerhvs.
Ugyanakkor nem minden libc fggvny felel meg kzvetlenl egy rendszerh-
vsnak. A libc fl szmtalan API ll rendelkezsre, sokuk interpreter s vir-
tulis gp formjban, ezltal teszi lehetv a C-nl magasabb szint nyelvek
hasznlatt. A szabvnyos C++-knyvtr is a libc-re pt.
Felhasznli zemmd
teml_handler() rendszersysteml_handler
sys_write() rendszerhvs
Kernel zemmd
2.10. bra. A rendszerhvs folyamata
Mint a neve is sugallja, az ABI a binris kompatibilits feltteleit rja le, ide
tartoznak a hvsi konvencik, a regiszterek hasznlata, byte-sorrend. Az
ABI
lnyegben a fordtt s a linkert rinti. Mg a Linux
API nagy rszt a
POSIX-szabvny definilja, az ABI- k specifikcija architektrafgg. Ez a
specifikci fellelhet az interneten, gyakorlatban arra ptnk, hogy egy
adott platformon a gcc csomag ismeri s tmogatja a Linux ABI-jt.
45
HARMADIK FEJEZET
Programknyvtrak
ksztse
A programknyvtrak alapjainak ismerete elengedhetetlen egy Linux rend-
szer testreszabshoz, elksztsk s felhasznlsuk nlkl pedig nem kp-
zelhet el nagyobb program. Ha bepl modulokat (plugin) szeretnnk
megvalstani, vagy a programunk architektrjt lecserlhet binris kom-
ponensekre ptjk fel, ugyancsak a programknyvtrak nyjtjk az implemen-
tci httert. Ebben a fejezetben ttekintjk a programknyvtrak alapjait,
majd programozsi krdseiket trgyaljuk meg C nyelven, vgl kitrnk a
C++-osztlyokat tartalmaz programknyvtrakkal kapcsolatos megoldsokra.
A fejezetet egy halad tmakr zrja: megvizsgljuk a programbetlts folya-
matt, valamint ennek keretben a sebessgoptimalizl eszkzk mkdst is.
3.1 . Statikus programknyvtrak
Bevezetsknt nzznk meg egy egyszer pldt:
/*
ceiling.c*/
include<stdio.h>
doubleceil(double);
intmain()
{
doublex;
printf("Keremazx-et:");
scanf("%lf",&x);
printf("ceil(x)=%6.4f\n",ceil(x));
return0;
}
32. fejezet: Programknyvtrak ksztse
double cei 1 (doubl e x)
{
double i x=(int)x;
return ix<x ? ix+1 : ix;
}
Ennek fordtsa a kvetkez:
gcc-oceilingceiling.c
A fggvnyt a C nyelv konvencii szerint deklarcira s defincira bontottuk.
A deklarci megadja a fggvny nevt, argumentumainak s visszatrsi r-
tknek a tpust2 . Ez tulajdonkppen az sszes adat, amelyre a fordtnak
egy fggvny meghvshoz szksge van. A definci a fggvnnyel kapcso-
latos minden informcit tartalmazza.
Ha a hvshoz elg a deklarci, akkor a defincit akr kln llomnyba
is tehetjk. A ceiling.c llomny tovbbra is felhasznlja a ceil fggvnyt:
7* ceiling.c */
#i ncl ude <stdi o.
double ceil (doubl e) ;
int mai n()
{
double x;
pri ntf("Kerem az x- et: ");
scanf ("%1 f" , &x);
pri ntf("ceil (x) = %6. 4f \ n" , cei 1 (x)) ;
return 0;
A ceilfunc.c llomny pedig tartalmazza a meghvand ceil fggvnyt: /*
ceil func.c */
double cei 1 (doubl e x)
{
double i x=(i nt)x ;
return ix<x?ix+1: x;
48
32.12. Statikus programknyvtrak
Ezt az albbiak szerint fordtjuk (az els kt sor a fordtt hvja, termszete-
sen felcserlhet):
2 2

gcc-cceilfunc.c
gcc-cceiling.c
gcc-oceilingceiling.oceilfunc.o
A 3.1. bra mutatja a fordts egsznek a folyamatt.
ceilfunc.c
Fordt (Compiler)
ceilfunc2.o
ceiling2.c
Fordt (Compiler)
ceiling.o
gcc -c
gcc -o
Linker
ceiling
3.1. bra. A fordts egsznek folyamata
Amikor a fordt a ceiling.c llomnyt fordtja, assembly kdot generl az
egyes utastsokbl Amikor a fggvnyhvshoz rkezik, akkor a deklarci-
bl tudja, hogy milyen paramtereket kell tadnia a fggvnynek. Egy dolgot
azonban nem tud: mi lesz a ceil fggvny cme? Ezt ilyenkor mg nem csak a
fordt nem tudja kiszmolni: a vgleges program struktrja nlkl a cmet
nem lehet megmondani. Ugyanis s ennek szemlltetsre fordtottunk a
gcc tbbszri futtatsval az egyes llomnyok fordtsa teljesen fggetle-
nl fut: a ceiling.c fordtsa teljesen fggetlen a ceilingfunc.c llomny ford-
tstl, a compilert akr prhuzamosan is lefuttathatjuk.
22
A gcc tulajdonkppen egy olyan ltalnos program (compiler driver"), amely a parancs-
sori argumentumai alapjn kivlasztja, hogy melyik eszkzt kell meghvni, s hogyan.
Az eszkzk sokflk: lehetnek szmos nyelv fordtprogramjai (esetnkben a C/ C++
fordt), az assembler s a linker. Mi magunk is kiegszthetjk a gcc-t klnbz eszk-
zkkel2 . A fordt-assembler-linker szekvencia a leggyakoribb forgatknyv.
49
3. fejezet: Programknyvtrak ksztse
Mivel teht a cm nem ismert, a fordt jobb hjn elhelyez egy ceil szimb-
lumot
2 3
a cm helyre, s ezzel elvgezte az sszes feladatt. A fordt kimenett
trgykd llomnynak (object file) nevezzk, s alaprtelmezetten .o-ra
vgzdik.
Ebbl szinte egyenesen kvetkeznek a linker fbb feladatai. Elszr egyms
utn kell raknia az egyes fggvnyek kdjait a trgykd llomnyokbl, majd
vgrehajtani az thelyezsbl add cmmdostsokat. Msodszor fel kell ol-
dania a fordt ltal htrahagyott szimblumhivatkozsokat, jelen esetben a
ceil szimblumot, a memriahelyeket kijell szimblumdefincikkal. Ez azt je-
lenti, hogy meg kell keresnie az sszes szimblumot s szimblumhivatkozst,
majd ssze kell prostania ket. Harmadszor el kell ksztenie a futtathat l-
lomnyt az adott platform ltal tmogatott formtumnak megfelelen.
Az els fordtk idejn az egsz forrskdot egyszerre kellett lefordtani,
m ez sok idt vett ignybe. A folyamatot gy lehetett gyorstani, hogy a
program egyes rszeinek fordtsa kln is megvalsult. A C/C++ programo-
zsi nyelveknl ez az jelenti, hogy a fordt kln dolgozza fel az egyes forrs-
llomnyokat, gy csak azokat az llomnyokat kell jrafordtani, ahol a for-
rsllomny frissebb, mint a fordt kimenete, vagyis a trgykd llomny.
gy a nem vltoztatott forrskdokat nem kell fordtani, elg csak linkelni.
Ha fggvnyknyvtrunkat szeretnnk msok szmra is hozzfrhetv
tenni, elg csak a lefordtott verzit odaadnunk, ezzel gyorsthatjuk a ford-
tst, hiszen a fggvnyknyvtrunk implementcijt nagy valsznsg sze-
rint nem szeretn mdostani az ezt felhasznl programoz.
2 4

Ha strukturlni szeretnnk a forrskdunkat, tipikusan tbb llomnyban
rjuk meg a fggvnyeket. A fentiek alapjn annyi trgykd llomny jn lt-
re, ahny forrsllomnyunk van. Ez kiss knyelmetlen, hiszen sokszor az
sszes fggvny egyetlen fggvnyknyvtrat alkot. Erre ad megoldst a sta-
tikus programknyvtr (static library), amely lnyegben sszefztt
trgykd fjlokbl ll. A statikus programknyvtrakat a linker fzi a fut-
tathat programhoz, gy az egsz fggvnyknyvtr kdja a futtathat prog-
ram rszv vlik.
2 3
Jllehet az eredeti C-fordtk egy alhzst is tettek a fggvny neve el ma mr rg el-
avult okokbl (a FORTRAN s az assembly nyelv rutinokkal val nvtkzs elkerlsre
vezettk be), az ELF formtumot tmogat fordtk mr nem kvetik ezt a gyakorlatot: a
szimblum a fggvny neve. A C++ esetn a fggvnynevek tlterhelse teszi szksges-
s, hogy az argumentumlista tpusaival egsztsk ki a fggvnyneveket, gy a linker
szintjn is megklnbztethetv vlnak a tlterhelt fggvnynevek. A C++-szabvny ezt
az gynevezett nvelferdtst (name mangling) a fordtkra bzza, amelyek ezzel a lehe-
tsggel teljesen klnbz mdon oldjk meg a krdst2 . Arra azonban a legtbb fordt
figyel, hogy a C-, illetve C++-nvelferdtssel fordtott fggvnyek ne tkzhessenek a
linker szintjn2 .
2 4
Termszetesen a gyakorlatban mellkelik a hibakeresshez szksges informcikat is,
valamint nagyon sokszor a forrst is, amely megknnyti a hibakeresst, vagy lehetsget
biztost a testreszabsra.
50
32.1 . Statikus programknyvtrak
A pldhoz visszatrve statikus programknyvtrat ksztnk a ceilfunc
llomnyunkbl:
ar rcs libceilfunc.a ceilfunc.o
Mindenkppen meg kell jegyeznnk, hogy egyetlen llomnybl teljesen feles-
leges statikus knyvtrat kszteni, hiszen az egsz koncepcit arra talltk
ki, hogy a trgykd llomnyokat ssze lehessen fzni s egy llomnyknt
rendelkezsre bocstani. ltalnos esetben a tovbbi trgykd llomnyokat
szkzzel elvlasztva sorolhatjuk fel az ar program argumentumlistjban.
Az ar segdprogram tulajdonkppen tetszleges llomnyok archivls-
ra alkalmas, ugyanakkor ritkn hasznljuk msra. Ezt az archvumot nevez-
zk statikus programknyvtrnak. A statikus programknyvtr szerkeze-
tileg egy rvid llomnyfejlcbl ll, amely az llomny formtumt jelzi
(!<arch>" karaktersorozat), majd az llomnyok kvetkeznek. Minden llo-
mnyt egy fejlc elz meg, amely az llomnyra vonatkoz informcit (llo-
mnynv, legutols mdosts dtuma, felhasznl s a felhasznli csoport
azonostja, jogosultsgok, llomnymret) tartalmazza. Szmunkra a tovb-
biakban elg, ha a statikus programknyvtrra mint trgykd llomnyok
halmazra gondolunk. A statikus knyvtrak neve ltalban a libxxx.a kon-
vencit kveti, ahol az xxx a knyvtr ltalunk adott neve, esetnkben ceil.
Statikus knyvtrat az albbiak szerint linkelhetnk a programunkhoz:
gcc -o ceili ng ceil ing .o -L2. -1 cei 1 func
Ehhez kt kapcsolt hasznltunk: az L kapcsol megadja azokat az llomny-
rendszerbeli knyvtrakat, ahol a programknyvtrak tallhatk, jelen eset-
ben ez az aktulis knyvtr. Az 1 kapcsol a programknyvtr nevt adja
meg: a lib eltagot s az .a vgzdst elhagyva. A paramterezsben fontos,
hogy ezek a kapcsolk a trgykd llomnyok felsorolsa utn kvetkezze-
nek. A statikus knyvtrak kezelshez a linkernek tulajdonkppen annyival
kell tbbet tudnia az eddigieknl, hogy kpes legyen rtelmezni (kicsomagol-
ni") a statikus knyvtrt reprezentl archvumot. A linker tartalmaz egy
olyan logikt, amely kivlasztja azokat a trgykd llomnyokat, amelyekre
szksg van, s csak azokat fordtja bele a futtathat programba.
A knyvtrban tallhat fggvnyek s globlis vltozk hasznlathoz
termszetesen meg kell adni a fggvnyek s a globlis vltozk deklarcijt a
fordt szmra. Az elbbit a pldban bemutatott mdon tehetjk meg, vlto-
zk esetben az extern kulcsszt hasznljuk. Ezeket a deklarcikat clszer
sszefogni egy .h llomnyban. Vagyis ha az fvkonyvtar fggvnyknyvtrun-
kat statikus knyvtrknt tesszk kzz, akkor tipikusan kt llomnyt bocs-
tunk a programknyvtr felhasznlinak a rendelkezsre: az fvkonyvtar.h-t a
deklarcik szmra, a libfvkonyvtar.a pedig a statikus knyvtr maga.
51
3 2 .fej ezet:P rogramk ny v t rak k sz t se
Ezek utn mr csak egy dolgot kell megvizsglnunk: ha adott egy stati-
kus knyvtr binris formtumban, hogyan tudjuk megnzni azt, hogy ez a
knyvtr milyen szimblumokat definil. Ez hasznos lehet akkor, ha nem
tudjuk, hogy egy adott .h llomnyhoz melyik knyvtr tartozik, vagy megke-
ressk azt a knyvtrat, amely tartalmaz egy adott szimblumot (tipikusan
fggvnyt), vagy csak szmzni akarjuk a felesleges knyvtrakat a progra-
munkbl. Ehhez nzzk meg az albbi pldt:
#include<math.h>
introundingMethod=0;
externinterrorCode;
doubleround(doublex)
{
doubleix;
intsign=x<0?-1:1;;
if(roundingMethod<0
11roundingMethod>2 )
errorCode=-1;
return0;
}
else
{
errorCode=0;
ix=(int)x;
switch(roundingMethod)
{
case0://felk erek it
returnx-ix<=0 ix:ix+1;
case1://lek erek it
returnx ix>=0?ix:ix-1;
case2 ://k erek ites
if(fabs(x-ix)>0.5)
{
returnix+sign;
else
{
returnix;
return0;
52
32.1 2. Statikus programknyvtrak
A fenti knyvtr egy kerektsi algoritmust foglal magban. A knyvtrban
egy globlis vltoz adja meg, hogy felfel, lefel vagy hagyomnyos mdon
kerektsen. Azoknak az llomnyoknak, amelyek szeretnk hasznlni ezt a
vltozt, externknt kell deklarlniuk. gy a knyvtrunkhoz tartoz .h llo-
mny a kvetkez:
/*round.h*/
externintroundingMethod;
doubleround(double);
A hibakd ppen ellenkez logikt kvet: az errorCode vltozt a fprogram
definilja, nem a knyvtr, gy ezt a programknyvtrban externnek deklarl-
juk. Ezek a megoldsok rgiek, nem is kvetendk, ugyanakkor nem plda
nlkliek.
2 5

A teljessg kedvrt bemutatunk egy pldt a fprogramra:
/*roundmain.c*/
#include"round.h"
interrorCode=0;//Errehiv atk ozik maj dak ny v t rbeliextern
intmain()
{
doublex=4.2 ;
roundingMethod=0;
printf("%lf\n", round(x));
roundingMethod=1;
printf("%lf\n", round(x));
roundingMethod=2 ;
printf("%lf\n", round(x));
roundingMethod=3 ;
round(x);
printf("%d\n",errorcode);
//
//
//
//
5.000000
4.000000
4.000000
-1
}
2 5
Tbbszl programokban ezek a globlis vltozk problmt okozhatnak. A rounding-
Method clszeren a round f
5.4 2 .4 .
y egy tovbbi paramtere lenne. Ha kt szlbl hvjuk
a round fggvnyt, a hibakdok sszekeveredhetnek. Ezrt, ha nem visszatrsi rtkkel
vagy kivtelkezelssel, hanem tovbbra is megosztott globlis adattal oldjuk meg a hiba-
kezelst, akkor az 5.4 .4 . Szlbiztos fggvnyek alfejezetben trgyalt szlspecifikus adat-
knt rdemes trolni a hibt s a hozzfrst fggvnyhvson keresztl megoldani.
53
32. fejezet: Programknyvtrak ksztse
Nzzk meg a fordts folyamatt. Elsknt a programknyvtrat fordtjuk le:
gcc - c round.c
ar rcs libround.a round.o
Majd a fprogramot:
gcc -c roundmai n .c
Vgl pedig a linkels kvetkezik:
2 6

gcc -o roundmain roundmai n .o -L. -1 round
Ezutn vizsgljuk meg a knyvtrban tallhat szimblumokat az nm segd-
programmal:
nmlibround.a
round.o:
uerrorCode
00000000T round
00000000B roundingMethod
Ha megnzzk az nm parancs dokumentcijt, a szimblumok tulajdonsga-
ira az angol bc betinek mintegy a felt felhasznlja. Szmunkra azonban
hrom eset fontos. A T azt jelenti, hogy egy fggvnyt definiltunk az adott
knyvtrban,
2 7
ezt a fggvnyt a programknyvtr felhasznlja hvhatja.
Az U valjban egy szimblumhivatkozst jelent: ez a szimblum nincsen de-
finilva (undefined) ebben a programknyvtrban. Ide tartoznak az extern
vltozk s azok a meghvott fggvnyek, amelyek ms programknyvtrban
vagy trgykd llomnyokban tallhatk.
2 6
Jogosan merl fel az a krds, hogy hol van a fabs fggvny definilva, mirt nem ka-
punk linkerhibt2 . Ugyanis a math.h-t tartalmazza az llomnyunk, m az ezzel jr ma-
tematikai programknyvtrat nem linkeltk hozz az /m kapcsolval2 . A megolds az,
hogy a fabs makrknt definiland, vagyis nem jelenik meg kln fggvnyknt, a ford-
t mr csak a behelyettestett makrtrzset ltja2 . Ugyanakkor pldul a sin fggvny
nem makr: ha azt hasznlnnk, akkor linkelskor hozz kellene adnunk a fent emltett
kapcsolt a gcc paramterlistjhoz2 .
2 7
A T a text rvidtse: ez az llomny azon szekcijnak a neve, amely a futtathat kdot
tartalmazza2 . Az elnevezs eredete homlyos, ugyanakkor ismers a gcc linker hibazene-
teibl: ott a 2.text a futtathat kd szekcijnak kezdett jelli, s megadja, hogy attl
szmtva melyik utasts hivatkozik a nem tallt szimblumra2 .
54
32.22. Megosztott programknyvtrak
Az bc tbbi betje fknt a vltozkra vonatkozik, s azt rja le, milyen
jelleg adatterletre tlti be ket az opercis rendszer betltrutinja.
2 8
Ha
egy szimblum nagybet, akkor ez azt jelenti, hogy globlis, vagyis kvlrl
hozzfrhet, a kisbet pedig azt jelenti, hogy loklis, vagyis kvlrl nem
hasznlhat.
2 9
Ez utbbit a C nyelv static kulcsszavval rhetjk el mind a
fggvnyek, mind a vltozk esetben. sszefoglalva: ha a knyvtr nagybe-
tvel definilja ezeket a vltozkat, hivatkozhatunk rjuk.
Az nm segdprogram a trgykd llomnyokra is mkdik:
$nm roundmain.o
00000000 B errorCode
00000000 T main
u printf
u round
u roundingMethod
A fprogram termszetesen definilja a main fggvnyt s az errorCode glo-
blis vltozt, tovbb hivatkozik a printf, a round s a roundingMethod
szimblumokra. Ugyanakkor felmerl a krds: hol tallhat a printf kdja?
Az stdio.h-ban definilt fggvnyek a libc elnevezs knyvtrban vannak, de
az -lc kapcsolt ekkor, a futtathat llomnyok ksztsnl nem kell kln
szerepeltetnnk a gcc argumentumai kztt: a szabvnyos C-programknyv-
trat a linker alaprtelmezetten hozzadja a programunkhoz
3.2. Megosztott programknyvtrak
Ha a fggvnyknyvtrunkat frissteni szeretnnk, kijavtunk benne pldul
nhny hibt, akkor a statikus programknyvtrat hasznl programot jra
kell linkelni: a linkernek az j verzit kell hozzfznie a programhoz A stati-
kus knyvtrbl a szksges trgykd llomnyok ltal tartalmazott kd be-
lekerl a futtathat programba. gy pldul, ha tbb program hasznl egy
2 8
Leszmtva V s W betket, amelyek a gyenge (weak) szimblumokat jelzik. A gyenge
szimblumok felldefinilhat globlis szimblumok: ha valahol mshol definilva van
egy ugyanolyan nev nem gyenge globlis szimblum, akkor azt hasznlja a linker, ha
nem, akkor a gyenge szimblumot, vltoz esetn nullra inicializlva. Ha kt ugyano-
lyan nev nem gyenge globlis szimblumot definilunk, az linkerhibt eredmnyez.
Gyenge fggvnyeket a gcc-vel az albbi mdon adhatunk meg: void _attribute_((weak))
func(void)Q. Ebben az esetben, ha valahol mshol definilunk egy nem gyenge func nev
fggvnyt, akkor a linker ezt hasznlja, s nem a fenti, res trzst, egybirnt azonban
a fenti fggvnyt2 . Ezzel hatkonyan rhatunk fell alaprtelmezett viselkedst2 . Vltozk
esetn ugyangy az _attribute_((weak)) nem szabvnyos gcc-kiterjesztssel rhatjuk el
a gyenge viselkedst.
2 9
Itt csak globlis szimblumokrl beszlnk, a loklist nem a fggvnyen belli", hanem
a modulra nzve csak bellrl lthat rtelemben hasznljuk.
55
32 . fejezet: Programknyvtrak ksztse
statikus programknyvtrban lv fggvnyt, pldul a mr emltett printf-et,
s minden fontosabb kategribl egy fggvnyt, akkor az egsz libc knyvtr
annyi pldnyban szerepel a memriban s a merevlemezen, ahny program
hasznlja.
Ennek elkerlshez az szksges, hogy a programknyvtrunkat kln l-
lomnyban helyezzk el: egy pldnyban troljuk a merevlemezen, amennyire
lehetsges, egy pldnyban tltjk be a memriba a knyvtr megoszthat r-
szeit, gy az sszes program ezt a pldnyt hasznlja. Ezt az llomnyt meg-
osztott programknyvtrnak (shared library) nevezzk. A megosztott
programknyvtrat az els, ezt hasznl program indtsakor vagy az els
programknyvtrbeli fggvny hasznlata eltt tltjk be dinamikusan, s
a betlts kzben vgezzk el a szimblumfeloldst, amely klasszikus esetben
a linker feladata. Ezrt a megosztott knyvtrakat dinamikus linkels prog-
ramknyvtraknak (Dynamically Linked Libraries, DLL) is nevezik.
Ezek alapjn nyilvnval, hogy a program futtatshoz nem elg a fut-
tathat llomny, szksgnk van a programknyvtrat tartalmaz llo-
mnyra is. Ezt a megoldst az opercis rendszerek ltal felajnlott fgg-
vnyknyvtrakra is alkalmazhatjuk: gy egyszeren megoldhat a Linux
frisstse a mr teleptett programok vltoztatsa nlkl.
A kvetkezkben ismertetjk a megosztott knyvtrakat. A lersban
megfigyelhetjk, hogy a megosztott knyvtrak kszti megtettek minden t-
lk telhett, hogy a forrskdot ne kelljen vltoztatni, ha statikus program-
knyvtrak helyett megosztott knyvtrakat szeretnnk hozzlinkelni a
programunkhoz.
3.2.1. Megosztott programknyvtr ksztse
Feladat Ksztsnk megosztott knyvtrat a kerektst vgz fggvnynkkel.
A megolds figyelemre mlt eleme az, hogy a forrsllomnyokat nem kell
mdostani. Kt fontos vltozs van:
mskpp kell fordtani a programknyvtrat, s
konfigurlni kell a krnyezetet, hogy a program futsi idben megta-
llja a knyvtrat.
A konkrt fordts lpseinek rszletezse eltt meg kell rtennk a megosz-
tott knyvtrak nvkonvencijt. Egy megosztott knyvtr elnevezse azrt
fontos, mert szmos program hasznlhatja ugyanannak a programknyvtr-
nak a klnbz verziit, s kellemetlen lenne, ha sszekeverednnek.
30

A megosztott programknyvtrakat tartalmaz llomnyok neve az albbi
3
A Windows opercis rendszereknl ez a jelensg a DLL-pokol" (DLL hell) nevet kapta.
Linux alatt ezt az elnevezsi konvencik betartsval kerljk el.
56
3.2. Megosztott programknyvtrak
sma szerint pl fel: libxxx.so.y.w.z, ahol y a fverziszm, w a mellkverzi-
szm, z pedig a kibocstottverzi-szm (release), az xxx pedig a knyvtr lta-
lunk adott neve. Az so a megosztott trgykd llomny" kifejezst (shared
object lile) rvidti. A kibocstott verzi szma ltalban minden egyes nyil-
vnos fordtssal nvekszik, a mellkverziszm a fontosabb javtsokat jelzi.
A fverziszm a legfontosabb, a msik kett opcionlis. Ha a futtathat
programtl kln llomnyban troljuk a programknyvtr kdjt, akkor az
esetleges javtsok utn elg csak a programknyvtr llomnyt kicserlni
az j verzira. Nyilvnval, hogy a mdostsok csak bizonyos keretek kztt
mozoghatnak, hiszen pldul a fprogram szmt bizonyos szimblumokra,
amelyeket nem tvolthatunk el, illetve a fggvnyeket tovbbra is meg kell
tudnia hvni. Vizsgljuk meg, melyek ezek a keretek pontosan. Mivel csak a
linkels dinamikus, a fordts nem, ezrt a fordt ltal hasznlt informci
nem vltozhat. Ez gyakorlatilag a hasznlt vltozk tpust s a fggvnyek
prototpust jelenti. Vagyis ha a fggvnyek trzsben hibt javtunk, vagy j
loklis fggvnyeket/vltozkat adunk a knyvtrhoz, akkor a mr lefordtott
program tovbbra is mkdik a knyvtrral, nem kell jrafordtanunk. Rvi-
den sszegezve: a knyvtrnak a program fel mutatott fellete, vagyis az in-
terfsze nem vltozik. A fverziszm lnyegben az interfsz vltozst jelzi.
Azonos fverziszm knyvtraknak azonos interfszknek kell lennie. Va-
gyis ha megvltozik a fverziszm, akkor az elz verziszm knyvtrral
fordtott programok futsa nagy valsznsggel hibt jelezve megszakad.
Nzzk meg a kvetkez szitucit. A merevlemezen ugyanannak a prog-
ramknyvtrnak klnbz verzii tallhatk egy knyvtrban, hiszen a k-
lnbz programok klnbz verzikat hasznlnak:
libround.so.1.0.1
libround.so.1.0.2
libround.so.1.1.0
libround.so.2 .0.0
Tegyk fel, hogy a roundmain programunk az egyes fverziszm inter-
fsszel lett fordtva. Azt szeretnnk, hogy a legfrissebb egyes fverziszm
programknyvtrat hasznlja (libround.so.1.1.0). Ezt legknnyebben egy ndi-
rekcival oldhatjuk meg: ltrehozunk egy libround.so.1 nev szimbolikus lin-
ket, amely mindig a legfrissebb programknyvtrra (libround.so.1.1.0) mutat.
A roundmain programnak a szimbolikus linket adjuk meg. Ha kijavtunk egy
hibt az egyes fverzij programknyvtrban (libround.so.1.2.0), akkor a
frissts az j programknyvtr bemsolst jelenti az adott knyvtrba, va-
lamint a libround.so.1 szimbolikus link tlltst erre a legfrissebb verzira.
A szimbolikus linket so-nvnek
3 1
(soname) nevezzk, mg a programknyv-
tr fjlrendszerbeli nevt fizikai nvnek.
31
Kiejtse esonv".
57
3. fejezet: Programknyvtrak ksztse
Programknyvtrat tartalmaz llomny
(libxxx.so.1.3.5)
Szimbolikus link Szimbolikus link

So-nv
(libxxx.so.1)

Linkernv
(libxxx.so)

Ezt hasznlja a programunk, Ezt hasznlja gcc, alatta cserlhetjk
alatta cserlhetjk a fizikai a fizikai llomnyt:
llomnyt. Ltszik, hogy a f gcc -Ixxx
verziszmot megtartjuk, Ha mindig a legfrissebbet szeretnnk
mert ha az vltozik,
fordtani, a szimbolikus linket az
akkor mr a programnak is so-nvre lltjuk.
vltoznia kell (jrafordts).
3 .2 . bra.A programknyvtrak elnevezsi konvencija
A 3.2. bra bal oldala a programknyvtr eddig ismertetett hasznlatt il-
lusztrlja. A jobb oldal azokat rinti, akik fordtani szeretnnek. Hasonlan
a statikus knyvtrakhoz, a gcc paramterei kztt gy hivatkozunk a prog-
ramknyvtrra, hogy elhagyjuk a kiterjesztst (jelen esetben ez nem .a,
hanem .so) s a lib eltagot. Ha azonos nev statikus s dinamikus program-
knyvtrat tall a linker, automatikusan az so kiterjeszts dinamikus prog-
ramknyvtrat veszi figyelembe, hacsak nem alkalmazzuk a static kapcsolt.
Mindez azt jelenti, hogy ksztennk kell egy jabb szimbolikus linket,
amelynek az alakja libround.so , hogy ha a linkernek az -lround paramtert
adjuk meg, akkor megtallja. Ezt a szimbolikus linket linkernvnek (linker
name)
nevezzk. Arra a verzira lltjuk, amelyiket hozz szeretnnk linkelni a
programunkhoz. Ha egy adott interfsz legfrissebb verzijt szeretnnk hasz-
nlni (ez fordul el leggyakrabban), akkor egyszeren az so-nvre lltjuk.
Nzzk meg, hogy mkdik ez a gyakorlatban. Elsknt fordtsuk le a
programknyvtrat. A fordtt az albbi mdon paramterezzk:
gcc - fPIC -c -Wall round.c
Az egyetlen klnbsg -fPIC kapcsol, amely a pozcifggetlen kd generlst
rja el. (Ennek pontos jelentsre ksbb mg visszatrnk.) Ez a kapcsol
programknyvtrak esetben csak nhny architektrn nem alaprtelme-
zett, az Intel-architektra azonban nincsen ezek kztt.
58
3.2. Megosztott programknyvtrak
Ezek utn a linkels kvetkezik:
gcc-shared-w1,-soname,libround.so.1
-olibround.so.1.0.1round.o-1c
Itt megadjuk a gcc-nek, hogy megosztott programknyvtrat szeretnnk k-
szteni. A -W/ kapcsolval a vessz utni karaktersorozatot a gcc a linkernek
tovbbtja. Ez esetben gy adjuk meg a linkernek az so-nevet. A tbbi param-
ter ismers, ezttal a libc alapknyvtrat rdemes kln megadnunk. Eddig
teht elksztettnk egy olyan programknyvtrat, amely a libround.so.1.0.1
llomnyban tallhat, s nyilvnval, hogy erre a libround.so.1 so-nvvel hi-
vatkozunk. Ezek utn fel kell lltani a szimbolikus linket Ezt legegyszerb-
ben az ldconfig segdprogrammal tehetjk meg:
/sbin/ldconfig -n .
A segdprogram alapfunkcija szerint a rendszer szoksos knyvtraiban (pl-
dul /lib, /usr/lib) tallhat, tovbb az letc/ld.so.conf llomnyban felsorolt
llomny-rendszerbeli knyvtrakban lv programknyvtrakra elkszti a
szimbolikus linkeket, majd az opercis rendszer programknyvtrakat tar-
talmaz gyorsttrban (cache) helyezi el 'ket. Ez a gyorsttr egy olyan bi-
nris llomny (letc/ld.so.cache), amely lnyegben a programknyvtrak
so-nevt, llomnyformtumt s teljes elrsi tvonalt tartalmazza. gy a
programbetlt gyorsan megtallja a hivatkozott programknyvtrakat
Termszetesen a parancssorban is megadhatunk llomny-rendszerbeli
knyvtrakat, amelyekhez ugyangy szimbolikus link kszl, s amelyek
hozzaddnak a gyorsttrhoz. A gyorsttr ltal hivatkozott program-
knyvtrakat a
isbin/ldconfig - p
parancs segtsgvel rathatjuk ki. Pldaknt a libm bejegyzst mutatjuk
meg:
libm.so.6(libc6, OSABI : Linux2 .2 .5)=>/lib/libm.so.6
A libm matematikai knyvtr a libm.so.6 so-nevet kapja, libc6-os formtum, a
Linux 2 .2 .5 binris interfszt ignyli, s a szimbolikus link a /lib/libm.so.6 el-
rsi tvonalon tallhat.
Ha az -n, kapcsolt hasznljuk, akkor a segdprogram csak a megadott l-
lomny-rendszerbeli knyvtrakban tallhat programknyvtrakhoz kszt
szimbolikus linket, s nem frissti a gyorsttrat. Pldnkban az aktulis
knyvtrat adtuk meg, s ennek hatsra ltrejtt a fizikai llomnyra muta-
t szimbolikus link:
libround.so.1->libround.so.1.0.1
59
3 .fej ezet:P rogramk ny v t rak k sz t se
Mivel a linker belefordtotta az so-nevet a programknyvtrba, az ldconfig
automatikusan el tudta kszteni a szimbolikus linket.
32
Jelen esetben a
programunk mellett troljuk a knyvtrat, s ksbb rszletezend okok mi-
att nem adtuk hozz a gyorsttrhoz.
rdemes megjegyezni, hogy a statikus knyvtrhoz kpest a program-
knyvtr C-kdjt nem kellett megvltoztatnunk, mindssze a fordt argu-
mentumai vltoztak meg. Ugyangy a .h s a binris llomnyokat kell tadni
a programknyvtr hasznljnak. Tovbbi klnbsg az, hogy le kell futtat-
nunk az ldconfig segdprogramot legalbb a szimbolikus link elksztshez.
3.2.2. Megosztott programknyvtrak hasznlata
A kvetkezkben nzzk meg a programknyvtrak hasznlatt Itt mg any-
nyi vltoztatssal sem kell szmolnunk, mint fentebb: a programknyvtr
nevt kell megadnunk a linkernek ezttal is a lib s a kiterjeszts nlkl.
Ha pldul a linker egy -lround argumentumot kap, az -L kapcsolval
megadott knyvtrakban elszr egy libround.so llomnyt keres, majd ha
nem tall, akkor egy libround.a-t. Ahhoz, hogy a fenti parancs mkdjn, lt-
re kell hozni a libround.so llomnyt, amely termszetesen egy szimbolikus
link, s kzvetlenl vagy kzvetve a programknyvtrat tartalmaz llo-
mnyra mutat. Ezt a szimbolikus linket, ahogy korbban mr volt rla sz,
nevezzk linkernvnek, ugyanis azt lltja be, hogy a linker melyik fizikai
programknyvtrat tartalmaz llomnyt hasznlja fel. Ha mindig az aktu-
lis verzit szeretnnk hasznlni, akkor az so-nv szimbolikus linkjre lltjuk
a linkernevet is:
ln -slibround.so.1libround.so
Ezzel ltrejtt az albbi szimbolikus link:
libround.so->libround.so.1
Ha msik verzit szeretnnk hozzlinkelni a programunkhoz, a linkernevet
megad szimbolikus linket a megfelel verzit tartalmaz llomnyra lltjuk
be. Ezek utn futtassuk a linkert:
gcc-oroundmainroundmain.o-L.-lround
32
A Linux opercis rendszer szmos programknyvtr-formtumot tmogat (ez a libm
esetn a libc6 volt), amely mgtt kln formtumok llnak. A libc6 a legjabb ELF for-
mtumot jelenti. Az ldconfig ezt a hivatkozott libc verzi alapjn prblja kitallni Ez az
oka annak, hogy a programknyvtr linkelsekor expliciten megadtuk az -/c kapcsolt.
Az ldconfig egyszerre tbb formtumot is kpes kezelni ugyanazon a rendszeren.
60
3.2. Megosztott programknyvtrak
Vgl mr csak a program futtatsa marad Ekkor azonban a kvetkez tr-
tnik:
. /roundmain
./roundmain:errorwhileloadingsharedlibraries:libround.so.1:
cannotopensharedobj ectfile: No suchfileor
directory
Jl lthat, hogyha az opercis rendszer nem tallja a hivatkozott program-
knyvtrakat, hibazenetet kapunk. A kvetkezkben megvizsgljuk, hogyan
lehet ezt a problmt orvosolni.
Els'knt nzzk meg az LD_LIBRARY PATH krnyezeti vltozt, amely
a programknyvtrak keressi tvonalait tartalmazza. Az aktulis knyvt-
rat hozzadjuk, s a programunk azonnal fut:
LD_LIBRARY_P ATH=.:$LD_LIBRARY_P ATH
Ez a krnyezeti vltoz a legels lloms, amikor az opercis rendszer a
programbetlts sorn elkezdi keresni a megosztott programknyvtrat. Ha
ezen elrsi tvonalak valamelyikben megtallja az adott programknyvt-
rat, betlti. Termszetesen minl tbb tvonalat tartalmaz ez a krnyezeti
vltoz, annl tbb knyvtrat kell megvizsglni a betlts sorn, s ez jelen-
tsen lassthatja a rendszert. Ennek a krnyezeti vltoznak a hasznlatval
lecserlhetnk" mr ltez programknyvtrakat: mivel a rendszer itt keresi
elszr a betltend programknyvtrakat, elbb tallja meg az LD_LIB-
RARY PATH elrsi tvonalaiban tallhat programknyvtrakat, mint a
mshol tallhatakat. Ugyanakkor ez ritkn clunk, legtbbszr, ha meg-
adunk egy tvonalat, amellyel vletlenl lecserlnk egy azonos so-nvvel
rendelkez knyvtrat, akkor rejtlyesen szllnak el" betlts kzben a ko-
rbban jl mkd programok. Radsul egyes 64 bites rendszereken me gje-
lennek az LD_LIBRARY PATH 64 s az LD_LIBRARY_PATH_32 krnyezeti
vltozk tovbb fokozva a nehzsgeket.
33

Ha valamely, a rendszer ltal alaprtelmezett knyvtrba msoljuk a
programknyvtrat, majd az elz fejezetben megismerteknek megfelelen
futtatjuk az ldconfig segdprogramot, vagy szintn az ldconfig segtsgvel
csak egyszeren hozzadjuk a programknyvtrat a gyorsttrhoz, ez meg-
oldst jelenthet a problmra. Ugyanakkor tl sok programknyvtr lasstja
a rendszer mkdst, mert a gyorsttr mrete megn. Mivel nagyon sok
program, kztk az opercis rendszer egyes rszei is, a gyorsttrat hasz-
nlja sajt programknyvtrai betltshez, ezrt a rendszer mkdst is le-
lassthatjuk. A megoldst tovbb rontja, ha hlzaton szeretnnk elhelyezni a
programknyvtrat: ekkor mind a lasssg, mind a hlzati llomnyrend-
szer elrhetsge problmt jelent.
33
Egy konkrt rendszeren az strace segdprogrammal indtva a programot az open rend-
szerhvs-prblkozsokbl egyszeren kiderthet, hogy milyen nev programknyvt-
rak betltsvel prblkozott a dinamikus linker.
61
3. fejezet: Programknyvtrak ksztse
Ugyanakkor, ha egyedl a mi programunk futtatott pldnyai hasznljk
a knyvtrat, kihagyhatjuk a rendszerszint megoldsokat a programknyv-
traink betltshez. A Linux ltal hasznlt llomnyformtumok lehetv
teszik, hogy a programunk binris llomnyban megadjuk az ltala felhasz-
nlt megosztott programknyvtrak keressi tvonalt, amelyet a program-
knyvtr futsi idej keressi tvonalnak (runtime library search path,
RPATH) neveznk. Ez az tvonal lehet relatv is. Pldnkban azt a megol-
dst vlasztjuk, hogy a libround.so.1 programknyvtr a roundmain prog-
rammal egy knyvtrban lesz. Ezrt az -rpath (vagy rviden -R) linkerkapcso-
lval hozzadjuk az aktulis knyvtrat a keressi tvonalhoz:
gcc -o roundmain roundmain.o -L. -lround -w1, -rpath .
A - W1 gcc kapcsol itt is arra szolgl, hogy az utna kvetkez karaktersoro-
zatot tadja a linkernek parancssori argumentumknt.
tmutat Lehetleg ne hasznljuk az LD_LIBRARY_PATH varinsait. Ha a programknyvtrat
tbb klnbz program hasznlja, adjuk hozz a gyorsttrhoz. Alaprtelmezetten hasznl-
juk az RPATH adta lehetsgeket.
A teljessg kedvrt megjegyezzk, hogy elvileg a linker is tmogatja a betl-
tshez hasznlt opcikat a linkernv alapjn elnevezett szimbolikus link
megtallshoz, de tapasztalataink szerint ez nem minden rendszeren mk-
dik, ellenttben az ltalunk bemutatott megoldssal. ltalban elmondhat,
hogy legalbb a gyorsttrat vagy az alaprtelmezett llomny-rendszerbeli
knyvtrakat a legtbb linker felhasznlja, hiszen pldul a libc s a libm is
gy rhet el a legknnyebben, s ezek elrhetsgt egyik rendszeren sem
kell megadni."
A gcc korbban bemutatott paramterezsnl egyrtelmen tetten rhet-
jk, ahogy a linker sszeprostja a programknyvtrban tallhat, a fprog-
ram ltal hivatkozott szimblumokat. St a korbban tapasztalt hibazenet
arrl rulkodik, hogy a linker kdot generl annak a programnak az elejre,
amely betlti a knyvtrat, illetve hibazenetet ad, ha nem tallja. Az gy
hasznlt programknyvtrat statikusan linkelt megosztott program-
knyvtrnak (statically linked shared library) nevezzk.
Ha a megosztott programknyvtr hasznl valamilyen erforrst, amelyet
betltskor le kell foglalnia, tovbb amikor a programknyvtrat az operci-
s rendszer eltvoltja a memribl, akkor fel kell szabadtania, megadha-
tunk kt fggvnyt, amely pontosan a fenti esetekben hvdik meg:
34
A linker ltal alaprtelmezetten (nem az L kapcsolval) figyelembe vett knyvtrakat
a linker konfigurcis llomnynak, az gynevezett linkerszkriptnek (linker script) a
SEARCH DIR bejegyzse tartalmazza. A linker PC-ken alaprtelmezetten a beptett
linkerszkriptet hasznlja, amelyet az ld verbose paranccsal rathatunk ki.
62
3.2. Megosztott programknyvtrak
extern void ni
-
L H b(void) attribute_ ((constructor));
extern void cl eanupLi b(voi d) attribute_ ((destructor));
void initLib(void)
{
printf("Betoltes\n");
}
void cl eanupLi b(void)
{
pri ntf("Ki tol tes\n") ;
}
A fggvnyek neve nem szmt, csak az, hogy externknt definiljuk, s megje-
lljk a constructor s a destructor nev gcc attribtummal. Mivel a program-
knyvtrak itt megismert betltse a main fggvny meghvsa eltt trtnik,
illetve felszabadtsa a programbl val kilpskor zajlik, ezek a fggvnyek
is ekkor hvdnak meg.
A fentiek alapjn lnyeges gyakorlati jelentsge van annak, hogy felde-
rtsk, hogy egy adott program vagy programknyvtr milyen ms program-
knyvtrakat hasznl. Erre szolgl az ldd segdprogram:
35

ldd ./roundmain
libround.so.1 => ./libround.so.1 (0x006c7000)
libc.so.6 => /lib/t1s/libc.so.6 (0x009dd000)
/lib/ld-linux.so.2 => /libild-linux.so.2 (0x009c4000)
ldd ./libround.so
libc.so.6 => /lib/t1s/libc.so.6 (0x00815000)
/lib/ld-linux.so.2 => /lib/ld-linux.so.2 (0x009c4000)
A programknyvtrban tallhat szimblumokat a statikus programknyvt-
raknl megismert nm segdprogrammal rathatjuk ki.
3.2.3. Megosztott programknyvtrak dinamikus
betltse
Feladat Mdostsuk gy a kerekt fprogramunkat, hogy ne csak a sajt kerektalgoritmu-
sunkat tudja hasznlni, hanem ms programozk is rhassanak kerektalgoritmusokat: ezeket
bepl modulnak (plug-in) nevezzk.
35
List Dynamic Dependecies: kb. listzd ki a dinamikus fggsgeket.
63
3 .fej ezet:P rogramk ny v t rak k sz t se
A feladathoz meg kell oldanunk azt, hogy a lefordtott fprogram kpes
legyen olyan programknyvtrakat betlteni, amelyek mg nem llnak ren-
delkezsre linkelsi idben. A statikus knyvtrakkal ez termszetesen kivi-
telezhetetlen. Az elz fejezetben a megosztott programknyvtrat a linker
nv szerint hozzfzte a programunkhoz, az adott nev programknyvtrhoz
pedig automatikusan betltkdot generlt, amely a program indulsakor
megkereste s betlttte a knyvtrat. Termszetesen gyeskedhetnnk az
LD_LIBRARY PATH vltozval, hogy klnbz helyrl tltse be az ugyano-
lyan nev, de klnbz programknyvtrunkat, vagy fellrhatnnk az adott
knyvtrat, jtszhatnnk az so-nvvel, m ezeket a megoldsokat egyrtel-
men nevezhetjk ignytelennek. Ez akkor vlik nyilvnvalv, ha egy na-
gyobb program klnbz rszeiben klnbz bepl modulokat szeretnnk
hasznlni.
Szerencsre lehetsgnk van arra, hogy futs kzben igny szerint be-
tltsnk egy megadott nev programknyvtrat, s annak fggvnyeire s
kvlrl elrhet vltozira nv szerint hivatkozhassunk. A programknyvt-
rat hasznlat utn el is tvolthatjuk a memribl. Nzzk meg, milyen
fggvnyekkel lehetsges ez:
constchar*pluginP ath="./libround.so.1";
handle=dlopen(pluginP ath, RTLD_LAZY);
if(!handle)
{
fputs(dlerror(),stderr);
exit(1);
Pldnkban sztringkonstansknt definiljuk a programknyvtr elrsi tvo-
nalt, a gyakorlatban legtbbszr ezt konfigurcis llomnybl vagy felhasz-
nli adatbevitel alapjn kapjuk meg. Ezutn megnyitjuk a programknyvtrat
a dlopen segtsgvel. Ez a fggvny vgzi el a dinamikus linkelst, amelyet
az elz fejezet pldjban a linker vgzett el, valamint a betltst. Ha a
programknyvtr tovbbi programknyvtrakat hasznl, azokat is automati-
kusan betlti a hivatkozsaikkal egytt tetszleges mlysgig. A bemutatott
dinamikus betlts sorn a program indulsakor nem tltdik be a program-
knyvtr, csak akkor, amikor a vezrls elri a dlopen fggvnyt. Vagyis ha a
megosztott programknyvtr nem tallhat, a program elindul, mindssze
a dlopen fggvny visszatrsi rtke lesz NULL. Ellenkez esetben egy lert
(handle) kapunk, amelyet a programknyvtron vgzett mveletek sorn t
kell adnunk paramterknt. Ha valami hiba trtnik, bvebb informcival a
dlerror fggvny szolgl, amely a hiba lerst adja vissza C-tpus sztring-
knt. Ez a hibakezelsi mdszer rvnyes a programknyvtr tovbbiakban
ismertetett fggvnyeire is.
Nzzk meg, hogy a program betltse utn hogyan frhetnk hozz a
program fggvnyeihez:
64
3.2. Megosztott programknyvtrak
double(*round)(double);
round=dlsy m(handle,"round");
if((error=dlerror()) ! = NULL)
{
fputs(error,stderr);
exit(1);
printf("%lf\n",round(3 .14));
A fenti programrszletben a round fggvnyhez frnk hozz. Elsknt defi-
nilunk egy fggvnypointert, amely egy double argumentumlistj double
visszatrsi rtk fggvnyre mutat. A fordtnak szksge van a fggvny
prototpusra (lsd korbban is). Ennek megadsa elkerlhetetlen, hiszen csak
a linkelst/betltst vgezzk dinamikusan, a fordtst nem. Egy program-
knyvtrbeli fggvnyre mutat mutatt a dlsym fggvnnyel szerezhetnk.
A fggvny meghvsa ezek utn gy trtnik, mint brmelyik mutatjval az
adott fggvny meghvsa. A dlsym tulajdonkppen egy adott szimblum kez-
dcmt adja vissza, legyen az fggvny vagy vltoz. gy a programknyvtr
roundingMethod nev globlis vltozjhoz nagyon hasonlan frhetnk hozz:
int*roundingMethod;
roundingMethod=dlsy m(handle,"roundingMethod");
if((error=dlerror())!=NULL)
{
fputs(error,stderr);
exit(1);
*roundingMethod=1;
A fordtnak ezttal is szksge van a vltoz tpusra, amelyet ezttal is po-
interknt definilunk; ugyanazzal az indirekcival frhetnk hozz a pointer
tartalmhoz, mint ltalban. Ha itt rossz tpust adunk meg, akkor a fgg-
vnyhvst elkszt kdrszlet ltal a veremben elhelyezett adatstruktra
klnbz lesz a fggvny ltal vrttl, s ez szinte brmilyen furcsa mk-
dst eredmnyezhet. Mindig gondosan figyeljnk a fprogramban megadott
pointer s a programknyvtrbeli fggvny egyezsre.
A dlsym nemcsak az ltalunk betlttt programknyvtrban tallhat
szimblumokat adja vissza, hanem a programknyvtr ltal hasznlt prog-
ramknyvtrak szimblumait is tetszleges mlysgig.
Ha nem hasznljuk a programknyvtrat, akkor fel kell szabadtanunk,
ennek hatsra ha a program kzvetlenl vagy ms betlttt program-
knyvtrakon keresztl nem hivatkozik a programknyvtrra az opercis
rendszer eltvoltja a programknyvtrat a memribl. A felszabadtst a
dlclose fggvny vgzi el:
dlclose(handle);
65
3. fejezet: Programknyvtrak ksztse
Trjnk vissza a dlopen fggvnyhez. A fggvny msodik paramtereknt
szablyozhatjuk azt, hogy a programknyvtrban tallhat szimblumokat
(lsd a 3.4.3.4. Dinamikusan linkelt megosztott knyvtr linkelse s betltse
alfejezetet) mikor oldja fel a dinamikus linker Ha azt szeretnnk, hogy a
dlopen meghvsakor trtnjen a szimblumfelolds, akkor az RTLD_NOW r-
tket hasznljuk. Ilyenkor, ha a valamelyik szimblumfelolds nem sikerl,
a dlopen hibval tr vissza. Ha a nem definilt szimblumhoz val hozzf-
rskor szeretnnk a szimblum feloldst, akkor az RTLD_LAZY jelzbitet
adjuk t a fggvnynek.
tmutat Ha nem szeretnnk a betltst a szimblum-hozzfrs sebessgre optimalizlni, va-
lamint rrnk az egyes szimblum-hozzfrsnl lekezelni a hibkat, hasznljunk az RTLD_LAZY-t.
A teljes program forrskdja a kvetkez:
// dynamic_roundmai n c
#include <stdio h>
#include <d
-
I fcn h>
#include "round. h"
int errorcode;
const char* pluginPath = "./libround.so.1";
-
int mai n(i nt argc, char **argv)
{
void *handle;
double ("round)(double);
int* roundingMethod;
char *error;
/" Megnyitjuk a konyvtarat.
handle = dlopen(pluginPath,
i f(! handle)
{
* /
RTLD_LAZY);
fputs(dlerror(), stderr) ;
exit(1);
}
/* Hozzaferunk a round szimbol umhoz "/
round = dl sym(handl e , "round");
if((error = dlerror()) ! = NULL)
{
fputs(error, stderr);
exit(1);
66
3. 2. Megosztottprogramk ny v t rak
/*Hozzaferunk aroundingmethodszimbolumhoz.*/
roundingmethod=dlsy m(handle,"roundingmethod");
if((error=dlerror())!= NULL)
{
fputs(error,stderr);
exit(1);
doublex=4.2 ;
*roundingmethod=0;
printf("%1f\n",round(x));
*roundingmethod=1;
printf("%1f\n"round(x));
*roundingmethod=2 ;
printf("%lf\n",round(x));
*roundingmethod=3 ;
round(x);
printf("%d\n",errorCode);
/*felszabaditj uk ak ony v tarat
dlclose(handle);
}
Fordtskor hozz kell linkelnnk a programunkhoz a dinamikus linker
knyvtrt, ez a fentiekben ismertetett fggvnyeket tartalmaz program-
knyvtr (libdl.so):
gccdy namic_roundmain.c-ody namic_roundmain-1d1
Amikor azonban futtatjuk a programot, hibazenetet kapunk:
./libround.so.1:undefinedsy mbol:errorCode
A fggsg ugyanis esetnkben ktirny: nemcsak a programknyvtrban
lv szimblumokat kell feloldani, hanem a programknyvtrban externknt
definilt errorCode szimblumot is. gy tudjuk rvenni a linkert, hogy a f-
program publikus szimblumait tegye elretv a dinamikusan betlttt prog-
ramknyvtrak szmra, hogy a gcc-nek megadjuk az -rdynamic kapcsolt:
gccdy namic_roundmain.c-ody namic_roundmain-1dl-rdy namic
67
3. fejezet: Programknyvtrak ksztse
Ha azt szeretnnk, hogy a programknyvtrunk hasonlkppen megosztan a
klsleg hozzfrhet szimblumait az ltala hasznlt programknyvtrak-
kal, hasznljuk az RTLD_GLOBAL jelzbitet a dlopen paramtereknt VAGY
kapcsolatban a tbbi jelzbittel.
tmutat Valjban ez egy elgg ritkn hasznlt megolds, mindezzel inkbb a dinamikusan
betlttt programknyvtrak lehetsgeit szeretnnk illusztrlni. Ha a programknyvtrnak
szksge van fprogrambeli vltozkra vagy fggvnyekre, azt lehetleg pointerekkel adjuk t
a programknyvtr fggvnyeinek.
Ismt hangslyozzuk, hogy a betlts teljesen dinamikus, a programnak nin-
csen fggsge a megosztott knyvtrra. Programunk csak a libc-tt (printf s
trsai), valamint a dinamikus programbetlttl (dynamic loader) fgg
(dlopen s hasonlkat tartalmaz programknyvtr).
ldd /dynamic_roundmain
libdl.so.2 => /lib/libdl.so.2 (0x00afb000)
1ibc.so.6 => /lib/t1s/libc.so.6 (0x009dd000)
/lib/ld-linux.so.2 => /lib/ld-linux.so.2 (0x009c4000)
Mindebbl kvetkezik, hogy ha megadtunk konstruktort, illetve destruktort a
programknyvtrnak, akkor az a programknyvtrat elsknt betlt dlopen,
illetve az utolsknt felszabadt dlclose hatsra hvdik meg. Az gy hasz-
nlt programknyvtrat dinamikusan linkelt megosztott program-
knyvtrnak (dynamically linked shared library) nevezzk, de hasznlatos
a dinamikusan betlttt programknyvtr (dynamically loaded shared
library) elnevezs is. Mind a statikusan, mind a dinamikusan linkelt jelz a
megosztott programknyvtr felhasznlsnak a mdjt jelenti, a megosztott
knyvtr szmra ez nem jelent klnbsget, csupn a fprogram szmra.
Dinamikus esetben a fprogram fggvnyhvsokkal tlti be s tvoltja el a
programknyvtrat, a szimblumfeloldst fggvnypointereken keresztl
vgzi: a szimblumhivatkozs a fggvnypointer, a dlsym ltal visszaadott
rtk a szimblumdefinci helye. Statikus esetben a linker gondoskodik rla,
hogy a programknyvtrakat betltse az indul program, s a szimblumfel-
oldst is elvgzi.
Ebben a fejezetben ismertettk a C nyelv programozs egyik legrugalma-
sabb architektrjt: hogyan lehet olyan bepl modulokat rni, amelyekrl
elg csak a benne lv fggvnyek nevt s argumentumlistjt, illetve a vlto-
zk nevt s tpust ismernnk, a knyvtr kivlasztst s gy a konkrt
implementcit megadhatjuk futsi idben. Felmerl a krds, hogy ltezik-e
olyan megolds, ahol mg ennl is kevesebb informci is elg lenne, pldul
megkrdezhetnnk a knyvtrat, milyen fggvnyei vannak, ezeknek melyek
az argumentumai, s milyen tpusak.
68
3.3. Megosztott knyvtrak C++ nyelven
A vlasz sajnos nemleges, ezzel ugyanis elrtk a C nyelv hatrait: a struk-
trk adattagjainak felptse s a fggvnyek argumentumai elvesznek a for-
dts sorn: pointermveletekk vagy veremkezel utastsokk alakulnak,
amelyekbl lehetetlen visszanyerni a fenti krdsekre kaphat vlaszokat.
36

3.3. Megosztott knyvtrak C++ nyelven
Az elz fejezetekben lttuk, hogy a programknyvtrak hasznlatt lehetv
tv mechanizmusok a fordts utn, a linkels s a betlts folyamatnak
rszeknt aktivldnak. A C++-szimblumok linkerszint reprezentcija
nmileg eltr a C nyelvektl. Ebben a fejezetben bemutatjuk, hogy miknt
kezelhetjk ezeket a klnbsgeket.
Mivel a C++ objektumorientlt nyelv, gy a programok alapvet adat-
struktri az osztlyok, nem pedig a fggvnyek, mint a C-programokban.
Ezrt az elvrsaink is msok: mg az elz fejezetben az adott prototpus
C-fggvnyek implementcijt kicserlhettk egy jabb verzij program-
knyvtrban, a C++ esetben ugyanolyan interfsz (ugyanolyan publikus tag-
vltozkkal s tagfggvnyekkel rendelkez) osztlyokkal szeretnnk ugyanezt
megtenni. Jllehet erre a problmra nem lehet igazn elegns C/C++ megol-
dst javasolni, az albbiakban bemutatjuk a lehetsgeket.
3.3.1. Programknyvtrbeli C++-osztlyok hasznlata
A C++ nyelv lehetv teszi a fggvnynevek tlterhelst (function over-
loading), ez azt jelenti, hogy ugyanazt a fggvnynevet klnbz paramter-
listval tbbszr is felhasznlhatjuk. Mivel a sok ugyanolyan nev szimblum
linkerhibhoz vezetne, a C++ ezt a nvelferdts (name mangling) hasznla-
tval oldja meg. Ez azt jelenti, hogy a fordt az argumentumlista tpusait be-
lepti a fggvnynvbe. Erre szabvnyos eljrs nincs, minden fordt sajt
megoldst vlaszthat, s vlaszt is a tapasztalatok szerint. Ennek kvetkez-
tben a C++-fggvnyek szimblumneveit nemcsak hogy nem egyszer kita-
llni a fggvnynv alapjn, de mg a sokat tapasztalt programozi szem
szmra sem tl eszttikus a ltvny.
A nvelferdts a statikus knyvtrak esetn akkor okozhat problmt, ha
az egyik llomnyt C-fordtval, a msikat C++-fordtval fordtjuk. St ugya-
nez a problma a klnbz C++-fordtk esetben is. Ekkor a linker szintjn
ugyanazok a prototpusok msknt ltszdhatnak, ezrt a linker nem tudja sz-
szeprostani a fggvny hvst a fggvny implementcijval, s nem defi-
36
Ez a problma vezetett el a Java- s .NET-krnyezetek nler adatstruktrihoz.
69
3. fejezet: Programknyvtrak ksztse
nilt szimblumot jelez. Ez a problma programknyvtrak hasznlata nlkl
is ugyangy elkerlhet klnbz fordtval fordtott trgykd llomnyok
linkelsekor. A nem dinamikusan betlttt, megosztott programknyvtr ese-
tn is hasonl a helyzet: azonos fordtnl a linker elvgzi az sszeprostst.
Nzznk egy pldt.
Feladat rjunk C++-osztlyt, amelynek egyetlen fggvnye felfel kerekti a megadott beme-
netet. Az osztlyt megosztott programknyvtrban helyezzk el.
Elsknt ksztsk el az osztlyt. Az osztlydeklarcit kln .h llomnyban
helyezzk el:
// rounder.h
class Rounder
{
publ i c :
int Round(doubl e) ;
};
Az osztly egyetlen fggvnynek a defincijt tartalmazza a rounder.cpp l-
lomny:
#include <math.h>
#include <stdio.h>
#include "rounder.h"
int Rounder::Round(double x)
{
doubl e ix;
ix =(int)x;
return ix < x ? ix+1 : ix;
}
Ezekbl az llomnyokbl megosztott knyvtrat ksztnk a mr jl ismert
mdon, de ezttal C++-fordtval:
g++ -c rounder.cpp
g++ -shared -w1,-soname,librounder.so.1
-o librounder.so.1.0.1 \ rounder.o -lc
/sbin/ldconfig -n .
70
3.3. Megosztott knyvtrak C++ nyelven
Ezutn elksztjk a fprogramot a roundermain.cpp llomnyban:
#i ncl ude "rounder . h"
#i ncl ude <iostream>
using namespace std;
int mai n()
{
double x=4.2;
Rounder r;
cout r.Round(x)endl;
}
A fprogramot a szoksos mdon fordtjuk:
-orounder de rmai n cp - lrounder
Ha visszatekintnk a forrskdra, lthat, hogy a fprogram csak az osztly-
deklarcit ismeri, a fggvnyek implementcijt nem. A fordt tudja, hogyan
kell a C++-fggvnyeket kezelni, a linker pedig sszeprostja a megfelelen
fordtott szimblumhivatkozsokat az implementcival.
A dinamikus linkels programknyvtraknl ppen az okoz problmt,
hogy C-fggvnypointereket hasznlunk (ez a dlsym visszatrsi rtke), gy
a fordt nem ismeri fel, hogy C++-fggvnyekrl van sz, s nem kpes he-
lyettnk kezelni. A linkerszint nevek elferdtsi konvencijn tl rgtn egy
msik problmba is tkznk. A C++-osztlyok nem statikus tagfggvnyei-
nek az adott objektumpldnyra mutat pointert (this pointer") is t kell ad-
nunk. Mind a nvelferdtst, mind a this pointer tadst rdemes a fordtra
bznunk, nincs rtelme kzzel" hamistanunk, mert a fordtkat nem ktik
szabvnyok, az implementci egyik verzirl a msikra vltozhat, st elviek-
ben akr egy fggvny hozzadsa is mdosthatja a nvelferdtst. A nvelfer-
dtsre, illetve a C++-tagfggvnyek hvsra a dlsym nem nyjt tmogatst.
Kvetkezskppen C++-tagfggvnyeket kzvetlenl nem rhetnk el a dlsym
fggvny hasznlatval.
Nvelferdts esetn a megoldst az jelenti, ha megadjuk a fordtnak,
hogy egyes fggvnyeknl ne hasznljon nvelferdtst. Ezt az extern C"
kulcsszval rhetjk el.
extern "C" double round (doubl e x)
{
}
71
3. fejezet: Programknyvtrak ksztse
Termszetesen, ha egy fggvnyt extern C"-vel deklarltunk, akkor nem
terhelhetjk tl. Ezt a megoldst azonban tagfggvnyekre nem alkalmaz-
hatjuk.
tmutat Ha programknyvtrban tallhat C++-osztlyokat szeretnnk felhasznlni, rjunk
extern C" fggvnyeket, amelyek pldnyostjk az osztlyokat, s felszabadtjk a ltreho-
zott objektumokat.
Az eddigiekre ptve a kvetkez fejezetben bemutatjuk, hogyan tudunk di-
namikusan betlttt programknyvtrak C++-objektumaihoz hozzfrni.
3.3.2. C++-objektumok dinamikus betltse
programknyvtrbl
Feladat Az elz feladat kerektst vgz megosztott programknyvtrt mdostsuk gy, hogy
dinamikusan is betlthet legyen. Ksztsk el a dinamikus betltst vgz fprogramot is.
Mint ahogy a fggvnyek esetben, itt is egy indirekci segt: mg a fggv-
nyeknl fggvnypointert hasznltunk, itt az osztlyra mutat pointerrel
dolgozunk. Termszetesen az osztly deklarcijra tovbbra is szksg van
a fprogramban is, ez alapjn az informci alapjn veszi szre a fordt, hogy
egy C++-osztly tagfggvnyt kell hvnia, s gy kezelni tudja helyettnk a
C++-sajtossgokat. A fggvny implementcijt viszont elrejtjk a fprog-
ram ell, ez adja a megosztott knyvtr erejt: brmikor lecserlhetjk egy
msik implementcival. Ennek azonban az az ra, hogy nem hasznlhatjuk
a new opertort, ugyanis ennek a fordtsa azt felttelezi, hogy a konstruktor
cme rendelkezsre ll linkelsi idben, ez pedig a dinamikus linkels
knyvtrak esetben mr nem teljesl. A pldnyostst teht a program-
knyvtr egy fggvnyben kell elvgeznnk. Mivel ezt a fggvnyt meg sze-
retnnk hvni a fprogrambl, extern C"-nek deklarljuk. Ennek jegyben
gy egszthetjk ki a rounder.h llomnyt:
extern"c"Rounder*create();
extern"c"v oiddestroy (Rounder*);
ty pedefRounder*(*create_t)();
ty pedefv oid(*destroy _t)(Rounder*);
Elreltan a pointertpusokat is deklarljuk, hiszen azokkal a dlsym fgg-
vnymutatkkal tr vissza, amelyeket konvertlnunk kell a fggvny tpus-
ra. Az eddigiek alapjn a fprogram egyszer:
72
3.3. Megosztott knyvtrak C++ nyelven
#include"rounder.h"
#include<stdio.h>
#include<iostream>
#include<dlfcn.h>
usingnamespacestd;
constchar*pluginP ath="./librounder.so.1";
intmain(intargc,char**argv )
{
v oid*handle;
create_tcreateFuncP tr;
destroy _tdestroy FuncP tr;
char*error;
//Megny itj uk ak ony v tarat.
handle=dlopen(pluginP ath,RTLD_LAZY);
if(!handle)
{
fputs(dlerror(),stderr);
exit(1);
}
//Hozzaferunk acreateszimbolumhoz.
createFuncP tr=(create_t)dlsy m(handle,"create");
if((error=dlerror())!=NULL)
{
fputs(error,stderr);
exit(1);
}
//Hozzaferunk adestroy szimbolumhoz.
destroy FuncP tr=(destroy _t)dlsy m(handle,"destroy ");
if((error=dlerror())!=NULL)
{
fputs(error,stderr);
exit(1);
}
doublex=4.2 ;
//Letrehozunk egy Roundertipusuobj ek tumot
Rounder*r=(*createFuncP tr)();
coutr->Round(x)endl;
//Felszabaditj uk aRounderobj ek tumot
(*destroy FuncP tr)(r);
73
3. fejezet: Programknyvtrak ksztse
//Felszabaditj uk ak ony v tarat
dlclose(handle);
}
A dlsym visszatrsi rtkt explicit tpuskonverzival kell az adott tpusra
alaktani, mert a C++ a C nyelvvel ellenttben szigoran tpusos nyelv.
Fordtskor azonban linkertl jv hibazenetet kapunk:
(.text+0x107): functionmain':
undefinedreferenceto'Rounder::Round(double)
1

collect2 :ldreturned1exitstatus
A linker nem kpes elrni a tagfggvnyt, mert az a programknyvtrban
van definilva. Nem dinamikusan betlttt knyvtr esetn a linker megta-
llta a teljes osztlydefincit a programknyvtrban, itt azonban linkelsi
idben nem tudunk semmit a fggvny implementcijrl, gy annak cmrl
sem. A linker teht joggal jelzi, hogy nem tallja a fggvnyt. Eddigi ismere-
teink alapjn mshogyan is eljuthattunk volna erre a kvetkeztetsre: mr
egyszer fggvnyek esetben is a fggvnypointer alapjn tudtunk hozz-
frni a fggvnyekhez, itt azonban csak az osztlyhoz frnk hozz mutat-
val, a fggvnyhez nem.
Ltszlag ekkor el is akadunk, hiszen visszartnk a kiindulsi probl-
mhoz: C++-tagfggvnyekhez nem tudunk pointeren keresztl hozzfrni,
mskpp pedig a linker problmt jelez. Ha az implementcit belerjuk a
fggvnyekbe, akkor mr az egsz osztlyt temeltk a fprogramba. Egy
olyan megoldsra van szksgnk, amely esetn
nem kell megadnunk a fggvny trzst, csak a deklarcijt,
mgis tudunk pointert definilni az osztlyra, s meg tudjuk hvni a
fggvnyeit.
A C++-ban a tisztn virtulis fggvny pontosan ilyen nyelvi konstrukci.
Vagyis ltrehozunk egy kizrlag virtulis fggvnyeket tartalmaz absztrakt
osztlyt, amelyet mind a fprogramban, mind a programknyvtrban defini-
lunk. A ltrehozst vgz fggvny ugyanakkor egy leszrmazott osztlyt pl-
dnyost (az absztrakt osztlyt nem is tudn), s ezt adja vissza az absztrakts-
osztly-tpus mutatn keresztl. Mindezek fnyben a programknyvtrat az
albbiak szerint valsthatjuk meg. A kzs rounder.h tartalmazza az abszt-
rakt osztlyt s a nvelferdts nlkli fggvnyeket:
cl ass Rounder
{
public:
v irtualintRound(double)=0;
v irtual~Rounder(){ }
;
74
3.3. Megosztott knyvtrak C++ nyelven
extern "c" Rounder*create();
extern"C"v oiddestroy (Rounder*);
ty pedefRounder*(*create_t)();
ty pedefv oid(*destroy _t)(Rounder*);
Mivel az osztly leszrmazottjait Rounder tpus pointeren keresztl szaba-
dtjuk fel, virtulis destruktort is definilunk. Elviekben ez is lehetne tisztn
virtulis, de a C++-ban a tisztn virtulis destruktor szintaxisa meglehetsen
tlthatatlan. A programknyvtrat gy implementltuk:
#include<math.h>
#include<stdioh>
#include"rounderh"
classupRounder:publicRounder
{
intRound(double);
};
intupRounder::Round(doublex)
doubleix;
ix=(int)x;
returnix<x?ix+1:ix;
extern"C"Rounder*create()
{
returnnewUpRounder();
extern "c" v oiddestroy (Rounder*obj ect)
deleteobj ect;
Leszrmaztattunk egy UpRounder osztlyt, s abban adtuk meg az imple-
mentcit. A create fggvny egy ilyen osztlyt hoz ltre, s Rounder tpus
mutatknt adja vissza. A fprogram a leszrmazottbl annyit lt", ameny-
nyit a Rounder sosztly megmutat.
Ez a megolds elg rugalmas. Ha tbb kerektsi algoritmusunk van,
mindegyiknek szrmaztatunk egy osztlyt a Rounder osztlybl (pldul a
DownRoundert, amely lefel kerekt), s hozzadjuk az implementcit.
A create fggvnyt paramterezni lehet (pldul az eddigi roundingMethod
paramtert adjuk neki t, s az ennek megfelel algoritmust tartalmaz osz-
tlyt pldnyostja). A fprogramot ehhez egyltaln nem kell mdostani. Ha
binris (lefordtott) formban szeretnnk kzreadni az algoritmusainkat, akkor
75
3. fejezet: Programknyvtrak ksztse
egy algoritmus egy megosztott knyvtrba kerlne, s a fprogram
pluginPatha
nem konstans lenne, hanem az algoritmusnak megfelel programknyvtrne-
vet tartalmazn.
Nagyon fontos a felszabadts krdse. Lthattuk, hogy az objektumokat
csak pointeren keresztl rhetjk el. Ez egyben sokszor dinamikus memria-
kezelst is jelent, amely knnyen memriaszivrgshoz vezethet. Itt azonban
nem azrt hasznlunk pointereket, hogy a felhasznland memria mrett
futs kzben hatrozzuk meg. Ha a fprogramban definiltuk volna az osz-
tlyt, egy loklis vltoz is elegend lett volna. A mutatk jelenlte magbl a
mechanizmusbl ered: a polimorfizmus C++-ban pointeren keresztl rhet
e1,
37
amelyhez a tisztn virtulis fggvnyek adta lehetsgeit hasznltuk ki
a megoldshoz. Vagyis pointert kell visszaadnunk, hogy mkdjn az imple-
mentcivlasztst lehetv tv polimorfizmus a dinamikus betltsnl. Mivel
loklis vltozra nem adhatunk vissza pointert, erre a problmra egy lehets-
ges megolds a dinamikus foglals s felszabadts. Egy msik megoldsknt
termszetesen ltrehozhatunk globlis vltozkat, tmbket, ekkor arra kell
figyelnnk, hogy a fprogram ne hvjon delete-et a pointerekre. A dinamiku-
san ltrehozott pointereket esetleg tmbben trolhatjuk, s a programknyv-
tr destruktorfggvnyben felszabadthatjuk a htrahagyott objektumokat.
tmutat
Mindig klns vatossggal kell kezelnnk a programknyvtrban dinamikusan le-
foglalt objektumok felszabadtst.
Ha tbb program hasznlja ugyanazt a programknyvtrat, ez nem jelent k-
lnsebb bonyodalmat: a programknyvtrak adatterlete minden program
szmra kln, egymstl fggetlenl ltrejn (mg a fggvnyeken belli
statikus vltoz is). A szlak ugyanakkor osztoznak az adatterleten, ilyen-
kor ugyanahhoz az objektumhoz val konkurens hozzfrst szablyozni kell.
Ha egy objektumot tbben hasznlnak, rdemes referenciaszmllst beve-
zetni, pldul a szabvnyos shared_ptr C++-sablon hasznlatval.
Felmerlhet a krds, hogy mirt kell ezt ilyen bonyolultan csinlni. Mi-
rt kell absztrakt osztlyt ltrehoznunk, s mirt kell az osztlyhoz pointeren
keresztl hozzfrnnk? Nem lehet a dinamikus betltst kiegszteni egy
olyan funkcival, amely le tudja krdezni, hogy milyen osztlyok vannak egy
programknyvtrban, annak milyen metdusai vannak, illetve ltrehozha-
tunk-e egy pldnyt az adott nev osztlybl, s meghvhatnnk egy adott
nev fggvnyt? A vlasz rviden: nem. Sajnos mindez a C++ nyelv megk-
tseibl ered.
38
A C++ nyelv fordtsnl az osztlyok adatstruktri elvesz-
37
Elrhet referencin keresztl is, de az mg tbb problmt okoz a felszabadtsnl.
38
Persze a C++ nyelvet ki lehetne egszteni ezekkel a funkcikkal. Ugyanakkor a nagyobb
szoftvercgek gy gondoltk, hogy rdemesebb ltrehozni egy teljesen j krnyezetet,
amely ezeknek a kihvsoknak jra tgondoltan, j gondolkodsmdot tmogatva felel
meg. A Sun kifejlesztette a Java nyelvet, mg a Microsoft (az elbbitl nem teljesen fg-
getlenl) a .NET platformot valstotta meg.
76
3.4. A megosztott knyvtrak mkdsi mechanizmusai
nek, az adathozzfrs, illetve a fggvnyhvs csak a kezdcmek (pl. this) s
a memriacm-klnbsgek (eltolsok") szintjn trtnik meg, s ezekbl az
eredeti adatstruktra nem llapthat meg. A linkels fzisban a fggvny-
nevek s a globlis szimblumok mg megjelennek (azrt lehet nv szerint le-
krdezni ket), viszont az osztlyokra vonatkoz informci mr nincsen meg.
Ez nem is annyira meglep, hiszen a linkert alapveten a C nyelvhez ksz-
tettk, s ksbb egsztettk ki a C++-hoz szksges funkcionalitssal.
Mindezekbl kvetkezik, hogy az osztly elrshez s a hvshoz szks-
ges informcit mind a fprogram, mind a kliens oldaln meg kell adnunk
(ezt tartalmazza a .h llomny osztlydefincija, valamint a globlis fggv-
nyek prototpusa), mert ezt a fordts sorn a fordtnak le kell kpeznie c-
mekre s eltolsokra, lehetleg mindkt oldalon ugyangy. Ha az osztlyhoz
hozzvesznk egy j tagvltozt vagy egy virtulis tagfggvnyt, megvltoz-
hatnak az eredeti eltolsok. Ezrt klnsen figyeljnk arra, hogy amit pl-
dnk sorn is kvettnk kln .h llomnyban adjuk meg a mindkt oldalon
hasznlt absztraktosztly-defincit, s mindkt oldalon ugyanazt az llo-
mny hasznljuk, klnben a lefordtott program s a programknyvtr flre-
cmzi a memrit. Vagyis ha egy j verzit szeretnnk ltrehozni a kerektsi
algoritmusbl, a fprogrambl pedig nem, akkor az absztrakt osztlyt ne vl-
toztassuk meg, klnben a fprogramot is jra kell fordtanunk. Ha viszont
meg tudjuk oldani azt, hogy ugyanabbl az absztrakt osztlybl szrmazta-
tunk le a programknyvtr jabb verziiban is, a programknyvtrat rugal-
masan, a fprogramtl fggetlenl cserlhetjk. Ezrt ebben az esetben nem
vltoztatjuk meg a programknyvtr f verziszmt.
tmutat Ha a knyvtrbl j verzit adunk ki, ellenrizzk, hogy az eredeti programmal
megegyez absztrakt osztlyt hasznl-e. Ha nem, a fprogramot is jra kell fordtanunk, s
abbl is j verzit kell kiadnunk, valamint a programknyvtr f verziszmt is meg kell vl-
toztatnunk.
3.4. A megosztott knyvtrak mkdsi
mechanizmusai
Az eddigiek alapjn lthat, hogy a dinamikus programknyvtrak miatt a
linkels s a programbetlts kztt nehz les hatrt hzni. Ezrt a rszlete-
sebb trgyalst a linkertl kezdjk. Elszr bemutatjuk egy olyan nll
program betltst, amely nem tartalmaz megosztott knyvtrat. Ez a linke-
ls s betlts legegyszerbb esete. Utna megvizsgljuk, hogyan mkdik
ugyanez a folyamat megosztott, illetve dinamikus knyvtrak esetben. Azt
felttelezzk, hogy itt a fordt s a linker kimenete az Executable and Link-
able Format (ELF) llomnyformtumot kveti, s ez legtbbszr teljesl is.
77
3. fejezet: Programknyvtrak ksztse
3.4.1. A betlttt program
A linkels s a betlts folyamatnak megrtshez vizsgljuk meg elszr
azt, hogy milyen krnyezetbe kell betltennk a programot. Eltekintve az
egyszerbb, fknt begyazott rendszerekben hasznlatos architektrktl, a
hardver biztostja a virtulismemria-kezelst (lsd a 2.4. Memriakezels al-
fejezet). Rviden ez a kvetkez'ket jelenti. A szoftver (belertve a gpi kd
szintet) virtulis cmekkel dolgozik, amelyet a hardver laptblkon keresztl
a fizikai memrira kpez le. Minden processznek kln virtulis cmtarto-
mnya van, amelyhez csak a processz frhet hozz. Amikor az opercis rend-
szer vlt a processzek kztt, a taszkvlts rszeknt betlti az aktuliss vl
processz virtulis cmtartomnyt. Amikor egy processz elindul, a Linux res
virtulis cmtartomnyt rendel hozz. Ebbe az res cmtartomnyba csak
a kernel kpzdik le, m csak a cmtartomny vgre. Ez lehetv teszi, hogy
a linker egy lland kezdcmre betltd programot ksztsen.
A program betltshez ugyancsak kihasznljuk a virtulis memria adta
lehetsgeket. A lapkezels virtulis trkezels esetben nemcsak az ltal-
nos swapterletre kpezhetnk le egy lapot, hanem egy llomny-rendszerbeli
llomny adott rszre is, vagyis magra a betltend programot tartalmaz
llomny egyes rszeire. Ez azt jelenti, hogy az llomny a memrialap swap-
terletv vlik. A virtulismemria-kezelssel sszhangban, amikor elszr
hozzfrnk a laphoz, akkor laphiba generldik, s az llomny betltdik a
memriba. Ha vltoztatjuk a memria tartalmt, az llomny csak akkor
vltozik, amikor a virtulismemria-kezel rendszer lecserli a lapot, s a
vltozsokat kirja az llomnyba. gy az llomny nincs mindig szinkronban
a memrival. A memriakezel egy egyszer vdelmi mechanizmust is lehe-
tv tesz, amely egyben hatkonysgnvelst is eredmnyezhet. Egy lap lehet
csak olvashat, csak rhat, rhat s olvashat, illetve ezek kombinlhatk a
futtathat tulajdonsggal. Ha ezeket a szablyokat megsrtjk, jelzst ka-
punk (segmentation fault). A csak olvassra hasznlt memrialapot nem kell
visszarni az llomnyba: vagyis egy csak olvashat s futtathat lap idelis
vlaszts a program futtathat kdjnak a betltsre. Ehhez termszetesen
arra van szksg, hogy a betltend llomny strukturlva legyen: a futtat-
hat kdot kln, folytonos szekcikban (section) kell trolnunk, amelyhez
memrialapokat rendelhetnk. A kdot tartalmaz szekcikhoz egy csak ol-
vashat s futtathat lapot rendelnk. Ha a program megprblja fellrni a
sajt kdjt, azonnal hibt kapunk: ez biztonsgosabb teszi a futtatst eset-
leges pointerhibk, illetve tmadsok esetn. A program adatterlett azon-
ban mr nem tudjuk ilyen egyszeren kezelni.
Ha az adatokat tartalmaz lapot olvashatknt s rhatknt jelljk
meg, akkor a vltoztatsok megjelennek a programot tartalmaz llomny-
ban is, ez pedig egyrtelmen nem kvnt mellkhats. Erre megolds lehet a
msols rskor (copy-on-write) mdszer, amely a vltozst az eredeti llo-
mny helyett a swapterletre rja ki. Ez a technika az els memriarsi m-
78
3.4. A megosztott knyvtrak mkdsi mechanizmusai
veletig ugyangy mkdik, mint a csak olvashat lap. gy ez a mdszer k-
lnsen takarkos, ha az rsra mgsem kerl sor. Ha az llomnyt a msols
rskor technikjval kpezzk le a memriba mivel a memrialap vlto-
zsai az els rs utn a swapterletre rdnak ki , a vltozs csak a processz
sajt cmtern keresztl ltszik, a tbbi, ugyanazt az llomnyt lekpez fo-
lyamat nem ltja a vltozsokat. Ezrt a msols rskor lekpezst privt
lekpezsnek is nevezzk.
39
Ha a program adatokat tartalmaz szekciit r-
hat s olvashat, msols rskor lekpezssel rendeljk hozz a memrihoz,
akkor a vltozsok nem rdnak vissza az llomnyba, s csak akkor msol-
dik le a lap, ha vltoztatunk az adatokon, tovbb a memriakezel gy dnt,
hogy a lap helyre msikat hoz be a httrtrrl.
A globlis jelleg adatokat kt rszre kell vlasztanunk: az explicit m-
don, kezdeti rtket megadva inicializlt, illetve az inicializlatlan adatokra.
Az inicializlt adatot tartalmaz szekcit ugyanis memrialaphoz kell ren-
delni, mg az inicializlatlan adatnak elg egy adott mret cmtartomnyt
foglalni. Ez utbbit a C specifikcival (az inicializlatlan globlis s statikus
vltozk kezdeti rtke nulla) sszhangban a programbetlt lenullzza.
A dinamikus vltozknak fenntartott heapnek, illetve a veremnek tovbbi
adatterleteket foglalunk, ezeket nem nullzzuk le.
Termszetesen a valsgban az llomny szmos tovbbi informcit tar-
talmaz, pldul a nyomkvetst tmogat bejegyzseket, amelyekre nincs
szksg a betltshez, st nem is tltdnek be a memriba. Ezeket nem le-
foglalhat (non-allocable) szekciknak nevezzk, szemben az eddig trgyalt,
lefoglalhat (allocable) szekcikka1.
4 9

A betlttt programrl egy pillanatfelvtelt" az albbiak szerint foglalha-
tunk ssze:
4 1

Mivel a virtulis memriakezels segtsgvel gyorsthatjuk a betltst,
a programokat szekcikra osztottuk, gy klnvlasztottuk a kdot az
adattl, illetve sztvlasztottuk az adatokon bell az inicializlt s
nem inicializlt adatot.
A kdot futtathat s csak olvashat lapokhoz rendeltk, mg az inici-
alizlt adatterletet msols rskor lekpezssel rendeltk a mem-
rialapokhoz. A nem inicializlt adat szmra lapokat hoztunk ltre,
amelyeket lenullztunk.
A heapnek s a veremnek tovbbi virtuliscm-tartomnyokat foglal-
tunk le
39
Ezek a lehetsgek szmunkra is rendelkezsre llnak, rszletes hasznlatukat lsd a
4.8. llomnyok lekpezse a memriba alfejezetben.
4
A nem lefoglalhat szekcikat eltvolthatjuk a strip segdprogrammal a --strip-unneeded
kapcsol segtsgvel.
4
' Az egyes virtulismemriacm-tartomnyt s a rjuk lekpezett szekcik sszerendelst
a gdb programnv utn az info files paranccsal rathatjuk ki.
79
3. fejezet: Programknyvtrak ksztse
Minden processznek kln virtuliscm-tartomnya van, gy nem je-
lent problmt, ha kt processz ugyanazt a virtulis cmet hasznlja.
A program kezdcme teht lehet mindig ugyanaz a cm. Indtskor
a kernel res virtuliscm-tartomnyt rendel a processzhez, vagyis a
cmtartomny vgn elhelyezked kernelt leszmtva egyik virtulis
cm sem foglalt. A lnyeg az, hogy a linker s a programbetlt egy
cmben megegyezzen, ott, ahol a program kezddik, s erre a cmre
tltsk be a programot.
3.4.2. Statikus knyvtrat tartalmaz program
linkelse s betltse
Nzzk meg, hogyan jutunk el a linkertl elindulva a fenti pillanatfelvte-
lig". Mivel a kdot, az inicializlt s a nem inicializlt adatterletet meg kell
klnbztetnnk, clszer, ha mr maga a fordt klnvlasztja ket.
Az inicializlt adatot C nyelven az albbi vltozdeklarcik adjk:

inicializlt globlis vltozk (belertve a statikus globlis vltozkat),

inicializlt loklis statikus vltozk (ezekbl a fordt globlis vlto-


zkat kszt).
A nem inicializlt adat az fenti vltoztpusok nem inicializlt vltozataibl n:
nem inicializlt globlis vltozk (belertve a statikus globlis vlto-
zkat),

nem inicializlt loklis statikus vltozk (ezekbl a fordt globlis


vltozkat kszt).
tmutat
rdemes a globlis vltozk (ebben az rtelemben a statikus loklis vltozk is ide
tartoznak) adatterleteire gy tekinteni, mint amelyeknek a programbetlt foglal helyet. Ha
inicializljuk ket, akkor a virtulismemria-kezel hajtja vgre az inicializlst az llomnybl,
ha nem, akkor a lenullzott memriaterletre kerlnek. A loklis vltozkat maga a program ke-
zeli mkds kzben a vermen, amelyre a programfuts sorn visszatrsi rtkek s egyb lla-
potinformcik is kerlnek, s a verem mrete a futs sorn llandan vltozik. gy a vermet
lehetetlen indulskor egyszer s mindenkorra inicializlni, erre csak a futs sorn folyamatosan
kerlhetne sor, amely viszont nem tl hatkony.
42
Ez a magyarzata annak, hogy a globlis/sta-
tikus vltozk mirt inicializldnak automatikusan, a loklis vltozk pedig mirt nem.
42
Vannak nyelvek s futtatkrnyezetek, amelyek inicializljk a loklis vltozkat, a C fi-
lozfijban ez indokolatlan pazarls lenne.
80
3.4 . A megosztott knyvtrak mkdsi mechanizmusai
A trgykd llomnyban a kdrsz neve text, az inicializlt adat neve data,
mg a nem inicializlt adatterlet bss.
4 3
A linker feladata az, hogy
az azonos tpus szekcikat sszefzze,
az thelyezs miatt megvltozott cmekre val hivatkozst kijavtsa,
s a klnbz trgykd llomnyok kzti hivatkozsokat az ssze-
fztt programban feloldja.
A linker feladata alapveten ktkrs. Az els krben ez az informciszer-
zsre irnyul: a linker felmri az egyes trgykd llomnyokban tallhat
szekcik mrett, valamint sszegyjti az egyes trgykd llomnyokban ta-
llhat defincikat, illetve referencikat egy gynevezett statikus szimb-
lumtblzatba (symbol table), rviden szimblumtblzatba.
A msodik krben a linker cmeket rendel az egyes szimblumokhoz az
els krben gyjttt informci alapjn, s meghatrozza a szekci mrett."
Beolvassa a trgykd llomnyok egyes szekciit, majd sszefzi a megfelel
szekcikat. Ezek utn a szimblumtblzat alapjn sszeprostja a szimb-
lumhivatkozsokat s a szimblumdefincikat. Ezt a mveletet szimblum-
feloldsnak (symbol resolution) nevezzk. Ha nem sikerl feloldania egy
ers szimblumot, vagy tbb lehetsg kzl kellene vlasztania, akkor hiba-
zenetet ad." A linker a szimblumfeloldskor nyert prosts ismeretben a
cmhivatkozsokat (adathivatkozsok modulon belli cmekre, ugrutastsok,
hivatkozsok globlis vltozkra stb.) trja a gpi kdban. Ezt a mveletet
thelyezsnek (relocation) nevezzk. Ezek utn a linker elkszti a futtat-
hat kimeneti llomnyt, amely esetnkben ugyanolyan szekcikbl ll, mint
a trgykd llomnyok.
A gyenge szimblumok kezelse kln eljrst ignyel. A gyenge szimb-
lumdefincik, ahogy korbban mr volt rla sz, egy fggvny alaprtelme-
zett mkdst vagy egy vltoz alaprtelmezett helyt (gy kezdeti rtkt)
jelentik, amelyeket egy ers szimblum fellr. A kernel egy ltalnos rsz-
ben pldul megad egy gyenge fggvnyt res trzzsel, amelyet az egyes pro-
cesszorspecifikus llomny ers fggvnye fellr.
4 3 A Block Started by Symbol (szimblummal kezdd blokk) eredete az 1950-es vekig nylik
vissza, eredeti hasznlata egy nem inicializlt adatterletet kijell assembly utasts volt.
4 4
A virulismemria-kezeln keresztli betlts miatt a szekcik mretnl figyelembe kell
venni a laphatrokat, a linker a virtulis cmek tgondolt hozzrendelsvel memrit
takarthat meg, s a futst is gyorsthatja.
45
A definicik s a szimblumhivatkozsok sszeprostsnl add hibk a tipikus lin-
kerhibk. A linker ilyenkor mr nem fr hozz a forrskdhoz, ezrt csak annyit tud
megllaptani, hogy az adott trgykd llomny text szekcijnak kezdettl adott eltols-
ra van egy olyan szimblumhivatkozs, amelyet nem kpes feloldani. Ebbl kvetkezen a
hibazenet is ennyi informcit tartalmaz. A gyenge szimblumok kivtelt kpeznek ez
all a szably all.
81
3. fejezet: Programknyvtrak ksztse
Ezeket a linker az albbi mdon kezeli. Ha tbb gyenge szimblum lte-
zik, s egy ers (tbb ers nem lehet, mert az a fentiek alapjn hiba), akkor a
linker az erset vlasztja. Ha tbb gyenge szimblumot adunk meg, erset
pedig nem, a linker nknyesen vlaszt egyet. Szimblumhivatkozsokat is
deklarlhatunk gyengnek:
externv oidfggv ny (v oid)_attribute_((weak ));
Ilyenkor nem problma, ha a szimblumot nem definiljuk, ekkor az rtkt a
linker nullra lltja. A szimblum ellenrzsvel pldul futsidben eldnt-
hetjk, hogy hozzlinkeltek-e egy bizonyos szimblumot a programunkhoz
Ha megnzzk a programjaink szimblumait, lthat, hogy a gcc C/C++ inf-
rastruktrja l a gyenge szimblumok fent ismertetett lehetsgeivel.
Nem volt sz mg ngy specilis szekcirl, amelyek mind a trgykd,
mind a futtathat llomnyban megjelenhetnek. Ezek a kvetkezk: nit, fini,
ctors, dtors. Az ti nit, illetve a fini olyan inicializl/tisztogat fggvnyek,
amelyek a main fggvny eltt/utn hvdnak meg. Az nit s a fini szekcik
tulajdonkppen text szekcik, gy is kezeli ket a linker s a programbetlt.
Mi is definilhatunk ilyen fggvnyeket a gcc constructorldestructor attribtu-
mval, pontosan gy, ahogy a megosztott knyvtraknl. Ilyenkor a linker
sszefzi az inicializl/tisztogat fggvnyeket, s mindegyiket meghvja
a main eltt. Mindkt gcc attribtumnak van egy olyan vltozata, amelyben a
hvsi sorrendet is llthatjuk.
A ctor s a dtor szekcik a C++ nyelvet tmogatjk. A C++-ban a globlis
vltozk (idertve a statikus tagvltozkat is) konstruktorait a main fgg-
vny eltt kell meghvni, tovbb ezek destruktorait a main fggvny utn.
A ctor s a dtor szekcik a konstruktorok/destruktorok cmeit tartalmazza
egyms utn. Az egyes trgykd llomnyok listit a linker sszefzi. A lin-
ker automatikusan elhelyez egy inicializl/tisztogat fggvnyt az initl fini
szekciban, amely vgigmegy a tmbn, s meghvja a konstruktorokat/de-
struktorokat. Maguk a konstruktorok s a destruktorok a text szekciban
vannak (ltrehozhatunk egy statikus tagvltozt s egy nem statikus tagvl-
tozt ugyanabbl az osztlybl), st a gyakorlatban az inicializl/tisztogat
fggvny csak annyit csinl, hogy meghv egy norml, textben tallhat fgg-
vnyt, amely elvgzi a bejrst s a fggvnyhvsokat. Ezzel eljutottunk a
linker feladatainak vgre: a futtathat llomny elkszlt.
Amikor elindtjuk a programot a programbetlt (program loader) be-
tlti a programot. A programbetlt a kernel rsze. Elsknt beolvassa a fut-
tatand llomnyban tallhat fejlceket. Ezek alapjn el tudja dnteni,
mekkora cmtartomnyt kell lefoglalnia. Kvetkez lpsknt lefoglalja a cm-
tartomnyt, s ltrehozza az sszerendelst az llomny szekcii s a virtulis
cmtartomny kztt. Ezutn a bss-nek megfelel terlet lenullzsa kvet-
kezik, ezt pedig a verem ltrehozsa kveti. Utols eltti lpsknt a prog-
rambetlt sszelltja a program argumentumait s a krnyezeti vltozkat.
Vgl a programbetlt elindtja a programot: elszr az inicializl rutinok
82
3.4. A megosztott knyvtrak mkdsi mechanizmusai
futnak le, majd a main fggvny kapja meg a vezrlst. Mivel a statikus
knyvtrak lnyegben trgykd llomnyok fejlc-informcival elhelyezve
egyms utn egy llomnyban, a linker alapveten ugyangy oldja fel ket,
mint a trgykd llomnyokat: mindegyiket sszefzi egy programm. gy a
statikus knyvtrak nem alkotnak kln kategrit a betlts vonatkozs-
ban, st a fejlc-informci beolvasstl eltekintve a linkels szempont-
jbl sem.
3.4.3. Megosztott knyvtr linkelse s betltse
A statikus linkels, ahogy lttuk, azt jelenti, hogy a linkernek megadjuk,
hogy milyen knyvtrakat hasznlunk, gy linkelsi idben megtrtnhet a
szimblumfelolds. Dinamikus programknyvtrak esetn az egyetlen komp-
likci abbl fakad, hogy a programknyvtr s a program ezttal ms
llomnybl tltdik be. Ezrt a szimblumfeloldsnak egy rszt betlts
kzben kell elvgezni. Mivel ez hagyomnyosan a linker feladata, a megosz-
tott programknyvtrat betlt programot futsidej dinamikus linker-
nek (run-time dynamic linker, RTDL) vagy rviden dinamikus linkernek
nevezzk.
A msik fontos dolog, hogy mind a program, mind a programknyv-
tr szimblumfeloldst a linker maradktalanul elvgzi. Az alapelv
a kvetkez. A fprogramban azok a szimblumok, amelyeknek a defincija a
programknyvtrban van, egy tblzat bejegyzsn keresztl hvdnak meg,
s a tblzatot kell csak inicializlni.
4 6
A dinamikus linker feladata csak az,
hogy a programknyvtrban tallhat szimblumok definciinak a helyt
megtallja, s azok cmt berja a tblzatba. A vltozkat mind a kt helyen
definiljuk, s futsi idben csak az egyiket hasznljuk.
Annak, hogy a programknyvtrat kln llomnyban helyezzk el, leg-
kzvetlenebb elnye a megoszts: ugyanazt a futtathat kdot (text) tbb prog-
ram is lekpezheti csak olvashat mdon a sajt virtulis cmtartomnyra. gy
ugyanaz a fizikaimemria-cmtartomny csak egy pldnyban tartalmazza a
kdot, s ezt a tartomnyt minden, ugyanazt a programknyvtrat hasznl
processz lekpezi a sajt virtulis cmtartomnyba, akr teljesen ms hely-
re. Az adatszekcikat a processzek a msols rskor technikjval kpezik le
kln fizikai memrit felhasznlva.
3.4.3.1. A cmtartomny kezelse
A megosztott knyvtrak legnagyobb problmja a cmtartomny kezelse.
A programot a kernel mindig ugyanolyan kezdcmmel tlti be (lsd a 3.4.1.
A betlttt program alfejezetben). Mivel kt program szmos klnbz meg-
4 6
A mechanizmus hasonlt a C++ virtulis fggvnytblihoz.
83
3. fejezet: Programknyvtrak ksztse
osztott knyvtrat tartalmazhat klnbz betltsi sorrenddel, knnyen el-
fordulhat, hogy az egyik virtulis cm tartomnyba mr betlttt program-
knyvtr szmra ugyanott mr nincsen hely a msik processz cmtartom-
nyban Ekkor a programknyvtrat t kell helyezni, ez pedig azt jelenti,
hogy tbbek kztt a futtathat kdban t kell rni a fggvnyek s a globlis
adatok cmeit. Ha ezt megtesszk, akkor mr nem tudjuk csak olvashatknt
lekpezni a text szekcit, hiszen meg kellett vltoztatni, st ami mg rosz-
szabb nem oszthatjuk meg kzs fizikai memrin a futtathat kdot.
Az egyik megolds erre a problmra az, hogy a megosztott knyvtrakat
kszt programoz (az opercis rendszer programknyvtrainak ksztit is
belertve) vlaszt egy cmtartomnyt, amely nem tkzik a tbbi program-
knyvtrral. Ha egy program esetn mgis tkzs trtnik, akkor el kell v-
gezni az thelyezst, s viselni kell a kvetkezmnyeit.
4 7

A msik megolds az, hogy nmi idvesztesg rn olyan kdot ksz-
tnk, amely nem fgg attl, hogy milyen cmtartomnyra tltdik be, vagyis
brhova vltoztats nlkl betlthet. Az gy fordtott programkdot pozci-
fggetlen kdnak (Position Independent Code, PIC) vagy pozcifggetlen
futtathat llomnynak (Position Independent Executable)
48
nevezzk.
A pozcifggetlen kdot a linker gy kszti el, mintha a nulla virtulis
memriacmre tltdne be. Mivel az ugrutastsok ltalban relatvak vala-
milyen futsi idben belltott regiszterhez vagy az aktulis pozcihoz kpest,
gy ezek nem jelentenek problmt. Az adatok elrsekor mr nem ugyanez a
helyzet. Ennek megoldsra bevezetnk egy tblzatot, amelyben eltroljuk
az adatokra mutat pointereket, s a kdba csak a tblzat kezdcmhez vi-
szonytott eltolst fordtjuk bele. Ezt a tblzatot globlis eltolstblzat-
nak (global offset table, GOT) nevezzk. A GOT kln szekciknt jelenik
meg a programknyvtr kdjban, s ugyangy kpzdik le a memriba,
mint az adat. A tblzat struktrjt (milyen adat legyen benne hnyadik he-
lyen) a linker lltja ssze, a tblzatot a betlts rszeknt a dinamikus
linker tlti ki.
A kvetkez krds az, hogy miknt tallja meg a kd a GOT kezdcmt.
Erre a megolds az, hogy a GOT szekcit rgtn a text szekci utn tltjk be
a memriba, gy a kdhoz kpesti relatv cme lland lesz, amelyet mr lin-
kelsi id'ben ki lehet szmolni. Termszetesen nem clszer, ha minden, glo-
blis adattagra hivatkoz utastsnak ki kellene szmolni a GOT kezdcmt,
ezrt ezt egy regiszterben troljuk.
4 9
Mivel a fprogram msra hasznlja ezt a
regisztert, a programknyvtrnak minden egyes fggvnyhvsa elejn be
kell lltania. Mivel minden fggvny tudja a GOT hozz viszonytott kezd-
cmt, hozzadja ezt az aktulis programszmllhoz, s az eredmnyt elhe-
4 7
Ezt a megoldst kvetik a Microsoft Windows opercis rendszerek.
4 8
Itt a futtathat llomny" alatt a futtathat kdot tartalmaz llomnyt" rtjk, vagyis
a megosztott programknyvtrakat. Programot is fordthatunk pozcifggetlenl, de en-
nek nem sok rtelme van, hiszen elnye nincs, viszont lassabb s nagyobb lesz a kd.
4 8
x86 esetn tipikusan az EBX regiszterben.
84
3.4. A megosztott knyvtrak mkdsi mechanizmusai
lyezi a kitntetett regiszterben. A fentiekbl kvetkezik, hogy a pozcifgget-
len kd nagyobb s lassabb, mint a pozcifgg megfelelje. Ebben szerepet
jtszik a GOT karbantartsa, egy regiszter folyamatos lefoglalsa, a globlis
adathozzfrshez szksges indirekci a GOT-on keresztl, valamint a fggv-
nyekben ki kell szmolni s el kell menteni a GOT kezdcmt egy regiszterbe.
3.4.3.2. A megosztott knyvtrak megvalstsnak
alapkoncepcii
Eddig eljutottunk oda, hogy a dinamikus linker a programknyvtrat brmi-
lyen memriacmre betltheti, ehhez nem kell trnia a futtathat kdot, csak
a GOT-ot kell sszelltania. A kvetkez krds az, hogy a fprogram hogyan
fr hozz a programknyvtr ltal megosztott szimblumokhoz.
A fggvnyeknl ez egy ugrtbla bevezetsvel trtnik. Az ugrtbla a
fprogramban helyezkedik el. Az ugrtblt eljrslinkelsi tblzatnak
(Procedure Linkage Table, PLT) nevezzk Amikor a program meghv egy
programknyvtrbeli fggvnyt, megkeresi a cmt a PLT-ben. A PLT-ben k-
ln nem troljuk el a cmet, hanem a GOT-ot hasznljuk helyette.
5
Ennek az
az elnye, hogy csak egy tblban kell cmfeloldst vgeznnk, illetve a PLT-t
csak olvashatan kpezhetjk le a virtulis memrira, st futtatni is tudjuk.
Ez azt is jelenti, hogy nemcsak a pozcifggetlen kd esetben hasznlunk
GOT-ot, hanem PLT esetn is. A PLT tartalmazza a fggvnynek megfelel
GOT-beli bejegyzs cmt, a bejegyzs rtke pedig az a fggvnypointer, ame-
lyen keresztl meghvdik a programknyvtrbeli fggvny.
A rszletek kiss bonyolultabbak, de minden lpst megindokoljuk. Egy
fggvnyhez tartoz PLT-bejegyzs gyakorlatilag egy gpi kd programrsz-
let, amely a kvetkezkppen nz ki:
1. ugrs a GOT megfelel bejegyzsre;
2 . az eljrs szimblumnak a szimblumtblban val helyt lenyom-
juk a verembe (a dinamikus linker hasznlja majd fel);
3. meghvjuk a dinamikus linkert.
A GOT tbljt gy inicializljuk, hogy a 2 . pontra ugorjon vissza. Vagyis be-
tlts utn az 1. pontban elugrunk a GOT megfelel bejegyzsre, majd visz-
szaugrunk a 2 . pontra, majd a 3. pontban meghvjuk a dinamikus linkert,
amely megkeresi a fggvnyt, s belltja a GOT bejegyzst a fggvnyre.
Tovbbi hvsok esetn csak az 1. pont hvdik meg, hiszen a GOT bejegyzse
mr a meghvand fggvnyre mutat. Ennek a kiss krlmnyes megolds-
nak tbb elnye is van. Ha egy programknyvtrbeli fggvny sosem hvdik
meg, nem kell elvgezni r a nvfeloldst, s a GOT-ot sem rogatjuk felesle-
gesen. Tovbb, ha valamilyen csoda" folytn mr linkelsi idben kiderlne
5
Egyes implementcik erre kln szekcit hoznak ltre (plt.got).
85
3. fejezet: Programknyvtrak ksztse
a helyes cm, akkor azt a linker kzvetlenl be tudn rni a GOT-ba, s nem
futna le feleslegesen a dinamikus linker. (Mindezt lsd a 3.4.4. A program-
knyvtrak hasznlatnak optimalizlsa alfejezetben.)
Az egyb szimblumoknl az jelenti a problmt, hogy a fprogramban
linkelsi idben fel kell oldanunk a szimblumokat, mert azt hagyomnyos
mdon tltjk be. Esetnkben ilyen a roundingMethod vltoz. Ezrt a linker
a programban is helyet foglal a vltozknak (mivel a vltoz inicializlatlan
globlis adat, mind a programknyvtr, mind a program bss-jn megjelenik),
majd a programknyvtr kdjban thelyezendnek jelli meg azt a vltozt,
amelyet a dinamikus linker betltskor a programbeli vltozra llt, a prog-
ramknyvtrban tallhat vltozt teht nem hasznljuk. Dinamikus linkels-
kor nincs ilyen jelleg hivatkozs. gy, ha ugyanazt a knyvtrat dinamikus
linkelssel tltjk be, a linker egyszeren a programknyvtrban tallhat
verzit hasznlja, erre oldja fel a szimblumot. Clszer azonban elkerlni
ezt a lehetsget s csak fggvnyeket megosztani a programknyvtrbl.
Nzzk meg, hogyan jutunk el a betlttt programig s programknyvtrig.
Elszr ismertetjk a fontosabb alapkoncepcikat, majd megvizsgljuk, hogyan
hasznlja ezeket a linker a program, illetve a programknyvtr linkelsekor.
A linker, ahogy lttuk, a szimblumfeloldst gy oldotta meg, hogy szim-
blumtblzatot ksztett minden trgykd llomnyhoz, s miutn egy
llomnyba szerkesztette az egyes trgykd llomnyokat a szimblumtb-
lzatok alapjn prostotta ssze a definilt s a hivatkozott szimblumokat.
Mivel a megosztott programknyvtrak kln llomnyban vannak, a megosz-
tott szimblumok feloldst a betlts folyamn kell elvgezni. Ez gyakorlatilag
azt jelenti, hogy a programknyvtr kvlrl is lthat szimblumaibl ll di-
namikus szimblumtblzatot (dynamic symbol table) elhelyezzk a prog-
ramknyvtrat tartalmaz binris llomnyban a dynsym szekciban. Ennek
elemei a szimblum neve, a lthatsga, a mrete s a definci helye. A linker
teht sszegyjti azokat a szimblumokat, amelyeket a GOT tbljban kell
elhelyeznie. Az eddigiek alapjn tudjuk, hogy ezek a pozcifggetlen kdban
(programknyvtrban) a globlis adatok, a megosztott knyvtrat felhasznl
futtathat llomnyok (program vagy tovbbi megosztott knyvtrakat haszn-
l megosztott knyvtrak) megosztott knyvtrakban definilt funkcii. Ezeket
a linker elhelyezi a dinamikus szimblumtblzatban.
A betlts sorn a dinamikus linkernek vgig kell mennie az egyes szek-
cikon, s t kell helyeznie a szimblumokat. Ezrt szekciknt szksg van
egy tblzatra, amely megmutatja, hogy milyen pozcinl tallhatk a felol-
dand szimblumreferencik. A szimblumdefinci helyt meg kell keresni a
szimblumtblban, s be kell lltani a megfelel cmet. Ezt a tblzatot
thelyzstblzatnak (relocation table) nevezzk.
51
Tartalmazza a szimb-
lum helyt az adott szekciban, azt, hogy miknt szmtsuk ki a berand t-
helyezett rtket, ha megvan a cm (pldul, ha kzvetlenl rjuk bele a
cmet, az eredeti betltsi cm s a tulajdonkppeni betltsi cm klnbsgt
5i
Ezek a rel-lel kezdd szekcikban tallhatk meg.
86
3.4. A megosztott knyvtrak mkdsi mechanizmusai
le kell belle vonni), tovbb a szimblum nevt. A betlts sorn meg kell
keresnnk a szimblumot a szimblumtblzatban. Ennek felgyorstsra a
linker elhelyez egy hashtblt a hash szekciban.
Ezek utn mr csak nhny ltalnos informcira van szksg, ezt a
linker a dynamic szekciban helyezi el nv-rtk prok formjban. A prog-
ramknyvtr fontosabb dinamikus informcii az so-nv, a tblzatok cme,
az inicializl s a tisztogat kdrszlet, valamint a statikusan linkelt knyv-
trak nevei. A program fontosabb informcii az so-nven kvl ugyanazok,
mint a programknyvtrak.
A linker a kimeneti llomnyban elhelyez mg egy fontos informcit, ne-
vezetesen a dinamikus linker nevt. Erre azrt van szksg, mert a dinami-
kus linker nem a kernel rsze, egy rendszeren tbb dinamikus linker is le-
het.
52
Ezt az interp szekciban tallhatjuk.
3.4.3.3. A megosztott knyvtrakkal kapcsolatos linkels s
betlts
Elszr nzzk meg a programknyvtrakat. Ehhez a linkernek az albbi l-
pseket kell megtennie:
sszefzi s thelyezi a trgykd llomnyokat.
Megkeresi az exportlt szimblumokat.
Elkszti a fent emltett tblzatokat.
Elkszti a kimeneti llomnyt.
A programknyvtrban a dinamikus szimblumtblzatban megtallhatk az
egyes exportlt szimblumok s ezek definciinak a cmei. Mivel egy program
tbb programknyvtrat hasznl, valamint a programknyvtrak is hasz-
nlhatnak tovbbi programknyvtrakat, a betltskor a dinamikus linker
ltrehoz egy szimblumtblzatokbl ll lncolt listt, amelyben gyorsan
vgrehajthat a keress. Ha a program egy szimblumot keres, a dinamikus
linker a fenti informcik alapjn vissza tudja adni a krt szimblum cmt.
Vizsgljuk meg a msik oldalt is, s nzznk meg egy programknyvtrat
hasznl programot. Tegyk fel, hogy a programknyvtrunk a round fgg-
vnyt exportlja. Ekkor a programunkban a linker ltrehozza szmra a PLT-
bejegyzst. Ez a szimblum egy PLT-beli fggvny, gy a dinamikus linker az
elz bekezdsben rszletezetteknek megfelelen a kiszmolt rtket rja bele a
GOT-ba a fggvny els hvsakor (lsd rszletesen az elz fejezetben). Tte-
lezzk fel, hogy a fprogramban lertuk az albbi sort:
round(3.14);
52
Az ltalunk hasznlt dinamikus linker a glibc rsze, az ppen aktulis verzi neve: ld-
linux.so.2.
87
3. fejezet: Programknyvtrak ksztse
A round szimblum nincs sehol definilva, csak a knyvtrban, viszont a lin-
ker tudja, hogy a PLT-ben ott van. gy a linker a fggvnyhvs utastsa
utn egyszeren berja a PLT megfelel , bejegyzsnek a cmt, amely ahogy
lttuk lnyegben egy gpi kd programrszlet, amely gondoskodik a
fggvny meghvsrl. gy nincs definilatlan vltoznk, mert feloldottuk,
teht nem kell tudnunk, hogy hova tltdik be a knyvtr, mert a kdban
nem hivatkozunk r, mindssze a dinamikus linkernek hvsonknt ki kell
tltenie a GOT-ot. Az elrendezst a 3.3. bra mutatja.
GOT 1-1: ...
GOT


7




round
/7 ltalunk rt kd





Programknyvtr


Program
3.3. bra. Programknyvtr s az ezt felhasznl program
A program s a programknyvtr kztti nyilat betlts utn, futs kzben
igny szerint a dinamikus linker lltja be, a tbbi a linker dolga.
A vltozk szmra nem tudunk ilyen egyszer megoldst. A vltozhi-
vatkozsokat nem lehet gpi kd programokra cserlni. Nem marad ms,
mint belerni 'ket a programba s a knyvtr hivatkozst tlltani. Ehhez
a linker egy szimblumdefincit generl. Ezt az egyszer defincit, amely a
linker ltal automatikusan egy programknyvtrbl az ezt hasznl futtatha-
t llomny szmra legenerlt s ahhoz hozzlinkelt kdrszletek sszess-
gt jelenti, programknyvtrcsonknak (stub library) nevezzk.
53

53
Microsoft Windows opercis rendszereken a linker ezt kln statikus llomnyban
programknyvtrknt (.lib) ltre is hozza. Linux alatt a linker automatikusan belegene-
rlja a programknyvtrat hasznl futtathat llomnyba az lknyvtrnv kapcsol
hatsra, gy nem hoz ltre kln llomnyt.
88
3.4. A megosztott knyvtrak mkdsi mechanizmusai
Ezutn kvetkezik a betlts folyamata. Elszr a kernel kapja meg a ve-
zrlst az execve rendszerhvson keresztl. A kernel megnyitja az llomnyt,
s meghvja a formtumnak megfelel fggvnyt, esetnkben az ELF-et betlt
rutint, amely beolvassa a teljes ELF-fejlcet, majd lekpezi a szekcikat a
memriba. Ezutn megkeresi az interpreter (rtelmez) szekcit, s ha van in-
terpreter, megnyitja, ltrehoz szmra egy szlat, s futtatja. Ezzel a kernel fe-
ladata lezrul, a betltsi folyamat az interpreterben folytatdik felhasznli
zemmdban. A dinamikus linker a dynamic szekci alapjn megkeresi a
szksges programknyvtrakat. Ha ez nem sikerl, akkor a mr az elz fe-
jezetekben ltott hibazenetet kapjuk, s a program futsa megszakad. A di-
namikus knyvtr megfelel rszeit a dinamikus linker lekpezi a memrira,
majd elvgzi az thelyezseket. Vgigjrja az thelyezstblzatot, s a hash-
tbla segtsgvel megkeresi a dinamikusszimblumtblzat-bejegyzst, ahon-
nan kiolvassa az egyes szimblumok definciit, pontosabban azok helyt, s
berja a megfelel cmeket a hivatkozsokhoz. Ennek rszeknt kitlti a GOT-
ot is s a memriabeli szimblumtblzatot is. Ezutn a dinamikus linker
visszatr, s a program az inicializlrutinok utn megkezdi a futst.
3.4.3.4. Dinamikusan linkelt megosztott knyvtr linkelse s
betltse
A dinamikusan linkelt knyvtr abban klnbzik a statikusan linkelt
knyvtrtl, hogy a linker a program linkelse kzben nem tud a knyvtrrl.
Nem tudja, hogy be kell tltenie indulskor, illetve fel kell szabadtania bez-
rskor, ezrt neknk kell meghvnunk a dinamikus linker
dlopen s dlclose
fggvnyt. Nem tud PLT- s GOT-tblzatokat kszteni, illetve a fggvny-
hvs helyre nem tudja becsempszni a PLT-bejegyzsre val ugrst. Ezrt a
dinamikus linkert neknk kell meghvni (dlsym) s megkrdezni az adott
szimblum cmt. Ez ugyangy a dinamikus szimblumtbla alapjn trt-
nik, mint amikor a PLT-bl hvtuk a dinamikus linkert.
A dlopen
RTLD_LAZY kapcsoljval a fggvnyek szimblumfeloldst
ksleltetjk. A linker csak azokra a szimblumokra kszti el a szimblum-
tblzat-bejegyzst, amelyekre dlsym hvson keresztl hivatkozunk.
3.4.4. A programknyvtrak hasznlatnak
optimalizlsa
A statikus programknyvtrak hasznlatnak nincs klnsebb htrnya a
trgykd llomnyokhoz kpest. A linkels utn gyakorlatilag nincsen k-
lnbsg a kett kztt. A gcc -s kapcsoljval s a strip segdprogrammal
eltvolthatjuk a felesleges informcit a programbl linkels utn a szimb-
lumtblzatra, kibocsts utn pedig a nyomkvetsi informcira nem lesz
szksgnk. Ha tovbb szeretnnk optimalizlni az llomny mrett a
.com-
89
3. fejezet: Programknyvtrak ksztse
ment-tel s a .note-tal kezdd szekcikat is eltvolthatjuk (-R szekcinv
kapcsol), ezek a fordt s a tmogatott platformmal kapcsolatos informcit
tartalmazzk. A statikus knyvtrakat tartalmaz programnak nincsen ext-
rakltsge sem betltskor, sem futsi idben. Ugyanakkor nem vltoztathat-
juk a knyvtr kdjt a program nlkl, nem oszthatjuk meg a programok
kztt, gy sem a httrtrral, sem a memrival nem tl takarkos. A statikus
knyvtrak a program rszei, mindig a programmal egytt tltdnek be, s a
program futsa sorn vgig bent maradnak a memriban. A dinamikusan lin-
kelt megosztott knyvtrak esetben szablyozhatjuk, hogy mikor szeretnnk
betlteni, illetve felszabadtani ket. A gcc -static kapcsoljval krhetjk,
hogy a libc s az egyb programknyvtrak statikus verzijt linkelje a prog-
ramhoz, feltve, ha ez rendelkezsre ll. A fordthoz tartoz programknyv-
traknl a statikus verzi is adott.
tmutat Ha a betltsre s a hasznlatra szeretnnk optimalizlni, a memria-, illetve a le-
mezhasznlatnak nincsen jelentsge, gy a statikus knyvtrak jelentik az optimlis megoldst.
A strip segdprogramot megosztott knyvtrakra is alkalmazhatjuk. Ilyenkor
rdemes az --strip -unneeded kapcsolt hasznlnunk. Ezzel a belltssal csak
statikus szimblumtblzatot tvoltjuk el, amelyre nincsen szksg az t-
helyezskor, hiszen ahhoz a dinamikus szimblumtblt hasznljuk.
A dinamikus knyvtraknl lttuk, hogy a globlis vltozk (illetve a lo-
klis statikus vltozk) kln elbnst ignyelnek, ezrt csak annyit hasznl-
juk 'ket, amennyire felttlenl szksg van.
A megosztott programknyvtrakat tartalmaz programok betltse elg
sok tbbletfeladatot vesz ignybe. Ismt egy programot s egy ltala felhasz-
nlt programknyvtrat felttelezve sszegezzk ezeket a feladatokat.
A program oldaln az albbi tennivalk vannak:
Be kell tlteni a programknyvtrakat a program futsa eltt.
Az els hasznlatkor kell hvnunk a dinamikus linkert, hogy a szimb-
lumtbla alapjn visszaadja a programknyvtrbeli szimblum helyt.
A programknyvtr oldaln az albbiakat kell elvgeznnk a betlts s a fu-
ts folyamn:
A programknyvtrak linkelse kzben azt felttelezzk, hogy a nulla
memriacmre tltdik be. Ezrt a dinamikus linkernek tipikusan a
GOT-ot, de ms adatokat is t kell helyeznie. Az thelyezs sokszor
relatv, ilyenkor csak azt kell tudnunk, hogy a nulla cmhez kpest
hova tltdtt be a knyvtr.
A komplikltabb thelyezshez szksg van annak ismeretre, hogy a
szimblum hol tallhat adottan. A szimblumtbla sztringalap, ti-
pikusan C++ esetn igen hossz sztringeket tartalmaz, ezrt mg
hashtblval optimalizlva is elg kltsges a keress.
90
3.4. A megosztott knyvtrak mkdsi mechanizmusai
Termszetesen ezeken kvl a GOT- s a PLT-tblzatok is helyet foglalnak,
a fggvnyhvs a PLT-n keresztl trtnik, s a GOT-ot is hasznlja, az
utbbin keresztl frnk hozz a globlis adatokhoz is. Mg ezek architek-
turlis dntsek, amelyeket nem tudunk megvltoztatni, a fenti pontokban
sszefoglalt lpseket optimalizlni tudjuk.
A szimblumtblzatot ignyl thelyezst az thelyezstblzat gyes
szervezsvel tudjuk gyorstani. Eredetileg az thelyezsek a szegmens kez-
dettl szmtott pozci szerint vannak sorrendezve. Ha ezt kiegsztjk gy,
hogy ha egy thelyezs fgg egy szimblumtl, akkor az attl a szimblumtl
fgg thelyezseket rgtn mg rakjuk, ezzel jelentsen cskkenthetjk a
sztringalap szimblumkeresst. Ehhez elg csak a legutols szimblum defi-
ncijra emlkezni. Ezt a jlfslt" elrendezst a gcc -z combreloc kapcsol-
jval rhetjk el, amely alaprtelmezetten be van kapcsolva.
Tegyk fel, hogy tudjuk a betltend knyvtr kezdcmt. Ekkor az
albbi egyszerstseket vgezhetjk el:
A program oldaln kitlthetjk a GOT-ot, hiszen tudjuk, hogy a szim-
blumok hova tltdnek be. gy nem kell meghvnunk a dinamikus
linkert.
A programknyvtr kezdcmt bellthatjuk, gy az egyszer the-
lyezseket nem kell vgrehajtanunk. Ezzel a betltst nagyban gyor-
stottuk.
Az egsz gondolatmenet arra pl, hogy programok ltal hasznlt program-
knyvtraknak fix cmet adunk, errl az sszes program tud, s ez a cm
egyik programban sem jelent tkzst a programkddal vagy ms program-
knyvtrakkal.
Ha viszont a programknyvtr cme megvltozik, a program GOT-jba bert
rtkek rossz cmre mutatnak. Ezt elkerlend, hozzadunk egy tovbbi prog-
ramknyvtrlistt tartalmaz szekcit (gnu.liblist) amely eltrolja ezt az infor-
mcit. Vilgos, hogy ezeket a lpseket a dinamikus linkernek is tmogatnia
kell. Ha pldul egy knyvtr kezdcmt megvltoztatjuk, a GOT-ot alaprtel-
mezettre kell inicializlni (visszaugrs a PLT-bejegyzsre), valamint ha a meg-
vltoztatott programknyvtr cme mr foglalt, akkor azt t kell helyezni.
A fentiekben trgyalt optimalizcis stratgit a prelink segdprogram-
mal valsthatjuk meg. A fenti lpsekhez kapcsoldan a prelink az albbi
feladatokat vgzi el:
A megadott knyvtrakban sszegyjti a programokat s program-
knyvtrakat
Sztosztja a cmtartomnyt a programknyvtrak kztt, hozzjuk
rendel egy kezdcmet, majd elvgzi az thelyezst a kezdcmre.
A programokhoz hozzadja a programknyvtrlistt tartalmaz szekcit.
91
3. fejezet: Programknyvtrak ksztse
Hozzadja az llomnyokhoz a visszalltshoz szksges informci-
t: a prelink kpes visszalltani az sszes feldolgozott llomnyt azok
eredeti llapotba.
A prelink nem tudja kezelni a dinamikusan linkelt megosztott knyvtrakat,
hiszen a futtathat kdot tartalmaz text szekcit nem elemzi, mshol pedig
nincs nyoma az gy hasznlt programknyvtraknak
A rendszer sokkal sebezhetbb, hogyha a tmad ismeri a programknyv-
trak, tipikusan a libc kezdcmt. Ez ellen a kezdcmek vletlenszer meg-
vlasztsval, gynevezett cmtartomny-randomizls (address space
randomization) segtsgvel szoks vdekezni. A prelink segdprogram is k-
pes vletlenszersget hozzadni a cmtartomny sztosztsnl. Termsze-
tesen ezutn mindig ugyanarra a cmre tltdik be a programknyvtr,
hiszen ebben rejlik a sebessgnvekeds, viszont ez a cm csak a rendszeren
bell ismert. m ez lehetv teszi, hogy gyetlenl megrt programok elrul-
hassk a libc cmt, amelyet gy fel lehet hasznlni biztonsgkritikus prog-
ramok feltrsnl. Erre megolds lehet, hogy a biztonsgkritikus programok
egy msik libc msolatot hasznlnak, vagy az, ha nem hasznlunk prelinket.
A prelink mkdsnek megismersvel lthatjuk, hogy a sebessgnve-
keds fgg az thelyezsek szmtl, a GOT mrettl s szmos egyb t-
nyeztl. Teljesen felesleges csodt vrni tle, elkpzelhet, hogy a nvekeds
minimlis, de az is elfordulhat, hogy jelents. A mrst az LD_DEBUG kr-
nyezeti vltoz belltsval (tartalmaznia kell a statistics sztringet) vgez-
zk el:
exportt0_0E8uG=statistics
./roundmain
8645:
8645:runtimelink erstatistics:
8645:totalstartuptimeindy namicloader:53 2 4449clock cy cles
8645:timeneededforrelocation:13 79679clock cy cles(2 5.9%)
8645:numberofrelocations:92
8645:numberofrelocationsfromcache:5
8645:numberofrelativ erelocations:12 66
8645:timeneededtoloadobj ects:2 3 2 3 63 9clock cy cles(43 .6%)
Ezek utn hozzadjuk a programknyvtrat s a fprogramot tartalmaz llo-
mny-rendszerbeli knyvtrat a prelink konfigurcis llomnyhoz, s lefut-
tatjuk a programot. A prelink lefuttatsa utn az albbi statisztikt kapjuk:
9179:
9179:runtimelink erstatistics:
9179:totalstartuptimeindy namicloader:446468490clock cy cles
9179:timeneededforrelocation:4562 3 9clock cy cles(.1%)
9179:numberofrelocations:0
9179:numberofrelocationsfromcache:2 1
9179:numberofrelativ erelocations:0
9179:timeneededtoloadobj ects:3 756481clock cy cles(.8%)
92
3.4. A megosztott knyvtrak mkdsi mechanizmusai
A dinamikus linkernek ez elg hossz futsa volt, amely nagyban fgg az
opercis rendszer llapottl, de rzkelheten az thelyezs kevesebb ideig
tartott. Ugyanakkor, mint az sejthet volt, az ilyen egyszer programot s
programknyvtrat lthatan nem rdemes prelinkelni.
A prelink programot jelenleg szleskren hasznljk, tbbek kztt a
bash s szmos segdprogram is.
93
NEGYEDIKFEJEZET
llomny- s I/O kezels
Az llomny (file) a Unix-vilg egyik legltalnosabb erforrs-absztrakcija
(lsd a 2.5.1. Az llomnyabsztrakci alfejezetben). Az olyan erforrsok,
mint a memria, a merevlemez, a hlzati kapcsolatok, a kommunikcis por-
tok, az IPC-csatornk mind llomnyknt jelennek meg. Ez azt jelenti, hogy a
klnbz erforrsokat az opercis rendszer fltt llomnyknt ltjuk, va-
gyis lnyegben ugyanazokkal a fggvnyekkel s lerval kezeljk ket, mint
a fjlokat. Ezt a kernel gy valstja meg, hogy megengedi azt, hogy egy llo-
mnylerra a legfontosabb ltalnos llomny- s erforrs-mveletet elvgz
fggvnyeket meghvjuk, s ha ppen olyat hvunk, amelyet az adott tpus
llomny nem tmogat (pldul csak olvashat hardvereszkz), hibazenetet
kapunk.
Az interfszek ltalnostsval egyszersdik a programozk feladata,
illetve egyes erforrsok kezelse kompatibiliss vlik ms erforrsokkal.
Ebben a fejezetben az llomnyabsztrakcis fellet felhasznli oldalt, va-
gyis a mveletek hasznlatt mutatjuk be. A fellet megvalstsval a 7.5.
Karakteres eszkzvezrl alfejezet foglalkozik.
4.1. Egyszer llomnykezels
Az egyszer llomnyok az llomnyrendszerben tallhat llomnyokat je-
lentik az egyb, fent emltett specilis llomnyokkal szemben. Az llomny-
kezel rendszerhvsok egyik csoportjt azok a fggvnyek alkotjk, amelyek
llomnylerkat hasznlnak. Az llomnykezel rendszerhvsok msik
alakja, amikor paramterknt az llomny nevt adjuk meg, s gy krnk az
llomnyra vonatkoz mveleteket.
A C s a Unix sszefondsa miatt az itt rszletesen bemutatott mdszere-
ket alacsony szint llomnykezelsnek (low-level file handling) hvjk, el-
lenttben a magas szint llomnykezelssel (high-level file handling),
amely az stdio.h-ban tallhat fggvnyekkel trtnik, egsz azonost he-
lyett egy FILE struktrra mutat pointerrel. (A kett kztti kapcsolatot
lsd a 4.10. Kapcsolat a magas szint llomnykezelssel alfejezetben.)
4 . fejezet: llomny- s I/O kezels
A legtbb fggvny kapcsn felmerl egy eredetileg globlis vltoz, az
errno (error number, kb. hibakd"), amely a hiba azonostszmt adja meg.
Amikor egy fggvny az eredmnyt visszatrsi rtkben adja vissza, akkor
a 1 megklnbztetett rtk azt jelenti, hogy hiba trtnt, s az errno tar-
talmazza a hiba rszletesebb kdjt. A vltoz rtknek szveges magyar-
zatt a perror fggvnyel ratjuk ki. Figyeljnk arra, hogy az errno rtkt
szmos fggvny, kztk a printf is mdosthatja, ezrt rgtn, miutn szre-
vettk, hogy a fggvnynk 1-gyel trt vissza, hvjuk meg a perrort, vagy t-
roljuk el az errno rtkt egy msik vltozban, s ezutn prbljuk kiratni.
Jllehet az errno eredetileg globlis vltoznak indult, a szlak hasznlata
ta kln errno ltezik minden szlra."
4.1.1. Az llomnyler
A fut programok szempontjbl a kvetkezt tapasztalhatjuk Amikor egy
processz hozzfrst szerez egy llomnyhoz, vagyis megnyitja, a kernel egy
llomnylert (file descriptor) ad vissza, amelynek segtsgvel a processz
a ks'bbi mveletek sorn hivatkozhat az llomnyra. Az llomnylerk pozi-
tv egsz szmok, amelyek a processz ltal megnyitott llomnyok tmbjnek
indexeknt szolglnak, s a megnyits sorrendjben mindig eggyel nagyobb r-
tket kapunk.
Az els hrom ler (0, 1 s 2 ) specilis clokat szolgl, s minden processz
indtsa eltt automatikusan ltrejn. Ezek az llomnyok brmilyen, az llo-
mnyabsztrakcis felletet megvalst eszkzk lehetnek, de van egy tipikus,
alaprtelmezett rtkk. Az els (0) a szabvnyos bemenet lerja, ahonnan a
program az interaktv bemenetet kapja. Ez alaprtelmezsben a billentyzet.
A msodik (1 ) a processz szabvnyos kimenete, a program futsa sorn keletke-
zett kimenet ide irnytdik. A hibajelentsek kimeneteknt szolgl a harmadik
(2) szabvnyos hibakimenet lerja. Mindkt kimenet tipikusan a kpernyt je-
lenti. A szabvnyos C-knyvtr kveti ezt a szerkezetet, gy kimeneti, bemeneti
fggvnyei (pl. printf, scanf) automatikusan ezeket a lerkat hasznljk.
Hogy ne kelljen szmokat hasznlnunk, az unistd.h headerfjl tartalmazza
az STDIN FILENO, az STDOUT FILEN s az STDERR_FILENO makr-
kat, amelyekkel ezeket az elre definilt lerkat elrhetjk a programunkbl.
54
Szlak megosztott adatterletn jn ltre (lsd az 5.4.4. Szlbiztos fggvnyek alfejezetet).
96
4 .1. Egyszer llomnykezels
4.1.2. llomnyok megnyitsa
Az llomnyok megnyitsra az albbi hrom fggvny ll rendelkezsnkre:
#include<sy s/ty pes.h>
#include<sy s/stat.h>
#include<fcntl.h>
intopen(constchar*pathname,intflags);
intopen(constchar*pathname,intflags,mode_tmode);
intcreat(constchar*pathname,mode_tmode);
Az open() fggvny a megadott llomny lerjval tr vissza, amely a legki-
sebb, nem hasznlt ler lesz. Ha rtke kisebb, mint 0, akkor az llomny
megnyitsa meghisult, ilyenkor a szoksos mdon az errno globlis vltoz
tartalmazza a hibakdot.
A flags paramter tartalmazza a hozzfrsi ignynket, illetve korltozza
a ksbb hasznlhat fggvnyek krt. rtke az albbi vlasztsi lehets-
gek kzl az egyik: O_RDONLY (csak olvashat), O_RDWR (rhat s olvas-
hat), O_WRONLY (csak rhat). Tovbb ezt kiegsztheti akr tbb is az
albbi jelz'bitek kzl bites VAGY kapcsolattal hozzfzve (4.1. tblzat).
4.1. tblzat. Az llomny-ltrehozs jelzbitjei
O_CREAT Ha az llomny nem ltezik, akkor egyszer fjlknt ltrehozza.
O_EXCL
Az O_CREAT opcival egytt hasznlatos. Az open0 hibval tr
vissza, ha az llomny mr ltezik.
A megnyitott fjl nem lesz a processz kontrolterminlja Csak
O_NOCTTY akkor rvnyesl, ha a processz nem rendelkezik kontroltermi-
nllal, s egy terminleszkzt nyit meg.
O_TRUNC Ha az llomny ltezik, akkor tartalma trldik, s a mrete O lesz.
O_APPEND
Az llomny vghez fzi rskor az adatokat. (A vletlen hozz-
frs ilyenkor is engedlyezve van.)
O_NONBLOCK
Az llomnymveletek nem blokkoljk a processzt. Az egyszer
llomnyok esetben a mveletek mindig vrakoznak, mert a le-
mezmveletek gyorsak. m egyes llomnytpusoknl a vlaszid
nem meghatrozott. Pldul egy csvezetk vonatkozsban, ha
nincs bejv adat, ez norml esetben blokkolja a processzt az olva-
ssi mveletnl. Ezzel az opcival azonban ilyenkor azonnal visz-
szatr, s hibt jelez.
Ezzel az opcival elrhet, hogy az rsmvelet vgeztvel az
O_SYNC adat valban ki legyen rva a lemezre. (Lsd a 4.1.6. Az rsm-
velet finomhangolsa alfejezetet.)
97
4. fejezet: llomny- s I/O kezels
Opci Jelents
O_NOFOLLOW
Ha a megadott llomny valjban szimbolikus hivatkozs, ak-
kor hibval tr vissza.
O_DIRECTORY
Ha a megadott elrsi tvonal nem knyvtr, akkor hibval tr
vissza.
Minimalizlja a kernel ltal biztostott rsmvelet-optimaliz-
O_DIRECT cit, ezzel lehetsget ad a programoknak, hogy sajt optimali-
zcis algoritmusaikat hasznljk (direct I/O).
A mode paramter tartalmazza a hozzfrsi jogosultsgokat j llomnyok
ltrehozsakor. Az open() fggvnynl ennek csak az O_CREAT opci eset-
ben van rtelme. Ezt megadhatjuk makrkkal is, de ltalban egy nullval
kezdd, oktlis konstans, amelynek els szmjegye a ltrehoz tulajdonos, a
msodik a tulajdonos csoportjnak, a harmadik pedig a tbbieknek a jogait
tartalmazza. Egy oktlis szmjegy hrom bitbl ll: az els az olvassi, a m-
sodik az rsi, a harmadik a futtatsi jog megltt jelenti, ha egybe van llt-
va. Ez utbbinak az llomny tpustl fgg rtelemezse lehet: knyvtr
esetn a tartalmhoz val hozzfrst jelenti, futtathat llomnyok esetn
azok elindtst.
tmutat O_CREAT opcii
-
lt sose feledkezznk el a jogosultsgokrl, mert akkor a fggvny
viselkedse nem definilt.
A belltott jogosultsgok processzhez tartoz umask (file mode creation
mask, llomny-ltrehozsi maszk) arra szolgl, hogy a felhasznl nehogy
vletlenl tl sok jogot adjon egy llomnynak. Az umaskban belltott bite-
ket az open (s tbb ms) fggvny nem lltja be, vagyis a belltott jog a
(mode & umask). Ha pldul az umask rtke oktlisan 002 (ltalban ez az
alaprtelmezett), akkor, ha a 777 vagy a 776 jogosultsgot adjuk meg, az
umask miatt mindkt esetben csak 774 -re lltdik be.
A creatO fggvny egyenrtk az albbi fggvnnyel:
open(pathname, 0....CREATO_WRONLY10TRUNC MOde)
4.1.3. llomnyok bezrsa
Az llomnyok bezrsa azon kevs fggvnyek kz tartozik, amely az sz-
szes llomnytpusra megegyezik:
98
4.1.Egy szer llom ny k ezel s
A fggvny lezrja az llomnylert, gy az nem hivatkozik tbb az llomnyra,
nem hasznlhatjuk tovbb. Tovbb felszabadtja az llomnylerhoz tartoz
buffereket s az egyb erforrsokat, megsznteti az llomny minden zrol-
st. (Errl bvebben lsd a 4.9. llomnyzrols alfejezetet.)
Egyetlen fontos dolgot rdemes megjegyezni: a fggvny lehet sikertelen.
Nhny fjlrendszer (pl. NFS) ugyanis nem rja ki a vltoztatsokat rgtn a
merevlemezre (lsd a 4.1.6. Az rsmvelet finomhangolsa alfejezetet), gy
amikor az llomnyt bezrjuk, a mg ki nem rt adatokat a lemezre kell m-
solni. Ha ez a vgs rsi mvelet sikertelen, akkor a close0 fggvny hibval
tr vissza. gy amennyiben nem hasznljuk a 4.1.6. Az rsmvelet finomhan-
golsa alfejezetben ismertetett szinkron rsi mdot (O_SYNC), akkor mindig
ellenriznnk kell a visszatrsi rtkt, mg ha nagyon ritkn is kvetkezik
be ilyen hiba.
4.1.4. rs, olvass s pozicionls az llomnyban
Az llomnybl val olvassnak, illetve az llomnyba val rsnak tbb md-
ja van. A legegyszerbb olvassi s rsi mvelet igen hasonlt a paramtereit
tekintve:
#include<unistd.h>
ssize_tread(intfd,v oid*buf,size_tcount);
ssize_twrite(intfd,constv oid"buf,size_tcount);
Mindkett tartalmaz egy llomnylert (fd), egy mutatt az adatbufferre
(buf) s a buffer hosszt (count). A readO fggvny beolvassa az adatokat az
llomnybl, s a bufferbe rja ket. A write() a count mennyisg byte-ot a
bufferbl az llomnyba rja. Mindkt fggvny az tvitt byte-ok szmt adja
vissza, vagy hiba esetn 1-et.
/*hellov ilag2 .c-A "Hellov ilag!"szov egetazak tualis
k ony v tarhelloallomany abairj a.*/
#include<stdio.h>
#include<stdlib.h>
#include<unistd.h>
#include<fcntl.h>
#include<errno.h>
intmain(v oid)
{
intfd;
99
4. fejezet: llomny- s I/O kezels
/*Megny itj aazallomany t,letrehozza,hanemletezik ,
estorliatartalmat.*/
if((fd=open("hello", O_CREATIO_TRUNCIO_WRONLY, 0644))<0)
{
perror ("open") ;
return 1;
}
/*13 k arak tert,aszov eget,k iirj uk azallomany ba.*/
if(write(fd,"Hellov ilag!\n",13 )!=13 )
perror("write");
return 1;
}
cl ose(fd) ;
return 0;
Az rst s az olvasst vgz fggvnyek rszleteire a kvetkez fejezetben
mg visszatrnk.
A Linux-llomnyokat kt rszre oszthatjuk: pozicionlhat (seekable) s
nem pozicionlhat, szekvencilis (non-seekable) llomnyokra. A szekven-
cilis llomnyok FIFO-csatornk, amelyek nem tmogatjk a vletlen hoz-
zfrst, az adatok nem jraolvashatk, illetve nem fellrhatk. A pozicionl-
hat llomnyok lehetv teszik az rsi vagy az olvassi mveleteket az
llomny teljes terletn. A csvezetkek, a karakteres eszkzk szekvencilis
llomnyok, a blokkos eszkzk s az egyszer llomnyok pozicionlhatk.
Hacsak nem hasznljuk az O_APPEND jelzbitet, egy llomny aktulis
pozcija a megnyits utn az llomny eleje Amikor olvasunk vagy runk, az
a mvelet utols byte-ja utni pozci lesz az aktulis. Amennyiben egy prog-
ram ki akarja hasznlni a vletlen hozzfrs lehetsgeit, az rsi s az olva-
ssi mveletek eltt be kell lltania az llomnyon belli aktulis pozcit.
Erre szolgl az lseek() fggvny:
#i ncl ude <uni std .h>
off_t 1 seek(i nt fd, off_t offset, int whence) ;
A fggvny az fd lerj llomny aktulis pozcijt elmozgatja offset byte-nyit a
whence pozcihoz kpest; a whence rtkeit a 4.2. tblzat foglalja ssze.
4 .2 . tblzat. A pozicionls viszonytsi pontjai
Opci Jelents
SEEK SET Az llomny eleje
SEEK CUR Az aktulis pozci
SEEK_END Az llomny vge
100
4.1. Egyszer llomnykezels
Az utbbi kt rtk (SEEK CUR s SEEK END) esetn az offset rtke negatv
is lehet. Ilyenkor termszetesen a pozci az ellenkez irnyba mdosul. Pld-
ul, ha az llomny vgtl vissza 5 byte-nyira szeretnnk lltani a mutatt:
lseek(fd, -5, SEEK_END);
Az lseek() visszatrsi rtke az aktulis pozci az llomny elejtl, illetve
1 hiba esetn. Ezltal pldul az
size=lseek(fd, 0, SEEK_END);
egyszer megolds az llomny mretnek lekrdezsre (a fggvny a virtu-
lis mretet adja vissza, amely tartalmazza az albb rszletezett lyukakat is).
Habr a klnbz processzek, amelyek egyszerre hasznljk az llo-
mnyt, nem mdosthatjk egyms aktulis pozcirtkt, ez nem jelenti azt,
hogy biztonsgosan tudjk prhuzamosan rni a fjlt knnyen fellrhatjk
egyms adatait. Fontos az is, hogy tbb processz esetn az 0 APPEND opci
nem gondoskodik arrl, hogy az rsmveletek atomiak legyenek.
A POSIX-szabvny lehetv teszi, hogy az aktulis pozcit nagyobb r-
tkre lltsuk, mint az llomny vge. Ilyenkor az llomny a megadott rt-
kre nvekszik, s ide kerl az llomny vge. Ekkor a rendszer nem allokl
a kimaradt terletnek lemezhelyet, s nem is rja ki, csak az llomny logikai
mrete mdosul. Az llomny ezen terleteit lyukaknak (gap) nevezzk.
A lyuk terletrl val olvasskor 0 rtk byte-okat kapunk. Az rs sorn a
hasznlt terletekre megtrtnik a tnyleges allokci. Az ilyen lyukas llo-
mnyok leginkbb akkor hasznlatosak, amikor az adat pozcija is inform-
cit hordoz, s takarkoskodunk a lemezterlettel. Ilyenek lehetnek pldul
a hashtblk. Msik gyakori plda a Peer-to-Peer (P2 P) rendszerekben haszn-
latos nem szekvencilis llomnyletlts. Ilyenkor a letlts kezdetn a teljes
llomnyterletet alloklni kellene, hogy brmelyik rszletet a helyre rhas-
suk ksbb. m a lyukakkal elkerlhet a tnyleges allokls, s ez a hely
megtakartsa mellett nagyban gyorstja is az eljrst.
Az olvass- s rsmveletek automatikusan frisstik az aktulis pozcit.
Ha ezt nem szeretnnk, hasznljuk a pread s a pwrite hvsokat, amelyek
nem vltoztatjk meg az aktulis pozcit. Ha ezekkel a fggvnyekkel runk/
olvasunk, a kvetkez mvelet ugyanarrl a pozcirl indul, a msodik rs
fellrja az elz eredmnyt, a msodik olvass pedig ugyanazt olvassa ki.
4.1.5. Rszleges s teljes olvass
Sokszor elfordul, hogy a beolvasand adat mrett nem tudjuk. Nem szeret-
nnk lekrdezni az egyszer llomny mrett, ugyanis ha a billentyzetrl
olvasunk, akkor nem tudjuk, hogy a felhasznl hny karaktert gpel be, il-
letve hlzati kapcsolat esetn nem tudjuk a msik fl ltal tkldtt byte-ok
szmt. Ekkor vlasszuk a kvetkez megoldst. Lefoglalunk egy buffert,
101
4.fej ezet: llom ny - sI/Ok ezel s
pldul egy kilobyte-nyit. Mindig egybuffernyit olvasunk, s azt dolgozzuk fel.
Fontos, hogy ellenrizzk, hogy a buffer tartalma mennyiben rvnyes. Ha az
olvass hibval tr vissza (-1), egyltaln nem, egybknt pedig a beolvasott
byte-ok szmt jelent visszatrsi rtk adja meg, hogy a buffer els hny
byte-jt hasznlhatjuk fel. Az olvass visszatrhet nullval is. Ez azt jelenti,
hogy elrtk az llomny vgt. Ez nem hiba, mindssze azt jelenti, hogy el-
fogyott az adat.
Ha az olvass sikeres, s a beolvasott adat megtlti a buffert, teljes olva-
ssnak (complete read) nevezzk, ha nem, akkor rszleges olvassnak
(partjai read).
Feladat rj unk programot,amely beolv assaaszabv ny osbemenetenmegadottadatok at, s
v issza rj ak etaszabv ny osk imenetre.
A megolds az eddigiek fnyben az albbi lehet:
/*olv as.c-Standardbemenetrololv assorok at,esk iirj aa
k eperny ore.
#include<std o.h>
#include<unistd.h>
#include<errno.h>
i ntmain(v o d)
{
charbuf[102 4];
intlen;
/*Halen>0,ak k orv ank iirandoadat.*/
while((len=read(STDIN_FILENO,buf,sizeof(buf)))!=0)
{
if(1en==-1)
if(errno==EINTR)
{
continue;//uj ramegprobalj uk
}
perror("read");
return-1;
if(write(STDOUT_FILENO,buf,len)==-1)
{
perror("write");
return-1;
return0;
102
4.1. Egyszer llomnykezels
A megoldsban a hibakezels nmi magyarzatra szorul. Elkpzelhet, hogy
mieltt az olvassmvelet brmilyen adatot beolvasott volna, jelzs rkezik.
Ilyenkor az olvassmveletet ismt megprblhatjuk. Ezt az esetet gy tud-
juk azonostani, hogy az errno az EINTR rtket veszi fel.
A fenti programban az llomny vgig olvasunk, ha a read fggvny l-
lomnyvge karaktert olvas, nullval tr vissza; ekkor a ciklus mr nem fut
le. A terminlon Ctrl + D billentykombincival rhatjuk be az llomny v-
ge karaktert. Tudjuk, hogy ha a visszatrsi rtk nagyobb, mint nulla, ez a
beolvasott adat mrett jelenti.
tmutat Mindig fordtsunk klns figyelmet arra, hogy a read visszatrsi rtke, ne pedig
a megadott buffermret alapjn elemezzk a buffert. Ha sztringet olvasunk, ne felejtsk el a
lezrkaraktert a buffer vgn elhelyezni.
Az olvasshoz hasonlan az rs is lehet rszleges, de ez egyszer llomnyok
esetben sohasem fordul el. Specilis llomnyoknl (pldul csvezetkek,
lsd a 4.5. Csvezetkek alfejezetet) megeshet, hogy a write az adatnak csak
egy rszt rta ki, s egy ciklusban jra ki kell rnunk a maradkot. Ezt a
mdszert a megnevezett csvezetkeknl ismertetjk.
Ha elre tudjuk, hogy miknt szeretnnk hasznlni az llomnyt, jelents
teljestmnyjavulst rhetnk el a posixjadvise fggvnnyel. Ennek segtsg-
vel az llomny egyes rgiira megadhatjuk a hasznlat mdjt, pldul azt,
hogy az llomny egy rgijt hasznljuk vagy nem hasznljuk, a kzeljvben
hasznljuk egyszer vagy tbbszr, esetleg szekvencilisan frnk hozz.
Megjegyzend mg, hogy ha adatszerkezetnk tmbkbl ll (pldul
mtrixokat szeretnnk kirni/beolvasni), akkor ezek kirsa, illetve beolvas-
sa hatkonyabb a bufferek tmbjt kezel writev s readv fgvnyekkel, ame-
lyek egyben atomi vgrehajtst is biztostanak.
4.1.6. Az rsmvelet finomhangolsa
Az rsmvelet mlyebb megrtshez meg kell ismernnk, hogy a Linux ho-
gyan, milyen lpsekben optimalizlja ezt a mveletet.
Mivel a merevlemezek sebessge tbb nagysgrenddel kisebb a processzor
sebessgnl, rdemes az ppen mdostott llomnyokat a memriban tar-
tani. Erre a Linux egy lemezgyorsttrat (disk cache) hoz ltre, amelyet lap-
trnak (page cache) neveznk. A gyorsttr virtulismemria-lapokbl ll,
ezek tartalma az egy lemezen tallhat blokk adatai. Az sszerendelst a la-
pok s a blokkok kztt az gynevezett I/O bufferek troljk."
55
A lapkezels virtulis trolkkal val integrci eredmnyekppen a bufferek tartalmt
memrialapok jelentik, a buffereknek csak az sszerendelst kell kezelnik, a kernelnek
az adatot nem kell kln trolnia.
103
4. fejezet: llomny- s I/O kezels
Olvasskor a kernel megnzi, hogy az adott blokkhoz tartoz lap bent
van-e a laptrban. Ha igen, akkor ezzel tr vissza. Ha nem, akkor a kernel
betlti az llomny krt inode-jt a laptrba mivel egy llomnyt ltalban
szekvencilisan olvasunk az llomny folytatst kijell inode-dal egytt.
gy az olvass elszr a memriabeli inode-ot keresi, ha nincs bent a memri-
ban, akkor behozza, ahogy a kvetkez inode-ot is (elretekint lapozsi
stratgia). Mivel a virtulis memriban mindig a legfrissebb lap van, ez
mindig a legfrissebb adatot tallja meg, s nem jelent problmt, hogy az rs
ltal okozott vltozs nem jelenik meg a lemezen. A write fggvny csak n-
hny ellenrzst vgez, lemsolja a kirand adatot a laptr megfelel lapj-
ra, ezutn visszatr.
A memrialapok kirst a httrtrolra tiszttszlak (flusher threads)
vgzik akkor, ha elfogy a memria, a kiratlan adatok egy adott idinterval-
lumnl hosszabb ideig vannak a memriban,
56
valamint az sync, illetve az
fsync rendszerhvs hatsra.
Az albbiakban megnzzk, hogy a kernel hogyan rja ki az adatokat a
lemezre. A kernel gynevezett blokkos eszkzvezrlkn (lsd a 2.5.2.1. Esz-
kzllomnyok alfejezetet) keresztl rja ki a lapokat. Ez azt jelenti, hogy az
adatokat a kernel nem adatfolyamban juttatja el a lemezre rst elvgz esz-
kzvezrlhz, hanem egy feladatsorban feladatokat rendel neki. Az optimali-
zls miatt mind a kernel, mind az eszkzvezrl felcserlheti a feladatok
sorrendjt. A kernel I/O temez (I/O scheduler) alrendszere megprblja
gy elrendezni az adatokat, hogy az egymshoz kzeli blokkokra vonatkoz
rsmveleteket sszegyjti, a lemezmeghajt hardver mkdsnek megfele-
l sorrendbe rakja, gy az eszkzvezrl egytt rja ket ki a lemezre.
Ez a megolds ktsgkvl gyors, de van nhny htrnya is. Az els
problma a ksleltetett rs kvetkezmnye. Ha az rs rgtn visszatrt, nem
tudunk hibazenetet adni, hiszen a write fggvny mr rg visszatrt, st el-
fordulhat, hogy a program futsa is befejezdtt, mire a kernel httrszlai
elvgzik a kirst.
A msik problma a sorrend. Ha minden adat kirdott, a sorrend soha-
sem jelent problmt vagy inkonzisztens viselkedst, de ha a rendszer pl-
dul ramsznet miatt sszeomlik, akkor kellemetlen kvetkezmnyek
lehetnek.
A fejezet tovbbi rszben megmutatjuk, hogy miknt knyszerthetjk a
kernelt arra, hogy minden vltoztatst azonnal rjon ki a lemezre. Lnyeges,
hogy ezeket a mdszereket csak indokolt esetben hasznljuk, mert jelentsen
lelasstjk a programunkat, illetve a rendszer mkdst. A fentiekben rsz-
letesen ismertetett bufferelt rs s olvass ugyanis nagyon hatkony, s nl-
klk jelents teljestmnycskkensre szmthatunk.
Ezt a /proc/sys/vm/dirty_expire_centisecs llomnyban llthatjuk be szzadmsodper-
cekben.
104
int
4.1. Egyszer llomnykezels
Mivel ebben az esetben nem hasznlunk buffereket, a lemez tartalma tel-
jesen sszhangban, ms szval szinkronban van a kirt tartalommal. Ezrt
ezt az llomnykezelst szinkronizlt I/O-nak (synchronized I/O) nevezzk.
Elsknt kt fggvny mutatunk be:
Mindkt fggvny kirja a megadott ler ltal kijellt llomnyt a merevle-
mezre. Az rsmvelet vgt meg is vrja, csak ezutn tr vissza. Ha a merev-
lemeznek hardveres gyorsttra van, ezt a fggvny nem tudja kezelni, ezrt
elfordulhat, hogy az adat csak a gyorsttrig jut, gy a lemezre nem rdik
ki. Amg az fsync az llomnyhoz tartoz metaadatot is kirja (idblyek s
egyb inode-adatok), az fsyncdata csak az adatot szinkronizlja. Ugyanakkor
egyik sem szinkronizlja az llomnyhoz tartoz knyvtrbejegyzst, gy el-
fordulhat, hogy egy llomny tnevezse utn az llomny a merevlemezen
teljesen friss, de egy rendszersszeomls utn nem rhet el, mert a knyv-
trbejegyzs csak a memriban ltezett.
Az egsz rendszer sszes buffert az albbi fggvnnyel rathatjuk ki a
merevlemezre:
vold syne(vi<d)
A fggvny linuxos implementcija megvrja, amg a kernel kirja a bufferek
tartalmt. rtelemszeren ez nem kevs idt vesz ignybe, gy a mdszer
egyltaln nem hatkony, csak nagyon indokolt esetben rdemes hasznlni,
ott, ahol valamilyen oknl fogva az fsync s az fdatasync nem alkalmazhat.
A harmadik megolds az llomny megnyitshoz kapcsoldik: az open
fggvny msodik paramterben bekapcsoljuk az O_SYNC jelzbitet. Ilyen-
kor a kernel minden egyes rs utn kirja a lemezre az adatot, mintha egy
fsync fggvnyt hvtunk volna, jllehet az implementci valamivel hatko-
nyabb. Ilyenkor az rsmvelet sebessge jelentsen lecskken.
tmutat A fenti mdszerek kzl igny s teljestmny szerint vlaszthatunk. Ha az rsm-
veletek tranzakcikba szervezhetk, nem fontos, hogy mindegyik eredmnye azonnal kird-
jon, elg csak a tranzakci vgeztvel, akkor rdemes egy fsync/fdatasync hvssal elvgezni a
kirst. Ha minden rsmveletet azonnal szeretnnk kirni, akkor az SYNC jelzbitet rdemes
alkalmazni.
105
4. fejezet: llomny- s I/O kezels
4.1.7. llomnyok rvidtse
Ha az llomnyok vgre runk, akkor a rendszer automatikusan nveli a
hosszukat. Fell is rhatjuk az adatokat. Mit tegynk azonban akkor, ha az
llomny vgn tallhat informcira egyltaln nincs szksgnk, s le
szeretnnk rvidteni ket? Erre szolglnak a kvetkez fggvnyek:
#include<unistd.h>
inttruncate(constchar*path,off_tlength);
intftruncate(intfd,off_tlength);
Hasznlatukkal az llomny mrett a length paramterben megadottra m-
dosthatjuk. Az llomny levgott rsze elvsz. m ha a length rtke na-
gyobb, mint az llomny aktulis mrete, akkor megnveli a virtulis mretet
gy, hogy az adott ponton lyuk keletkezik az llomnyban.
4.1.8. llomnyok tirnytsa
Ahogy sz volt rla, a 0-s, 1-es, 2 -es sorszm llomnylerknak klnleges
szerepk van: ezek a program szabvnyos bemenett, kimenett s hibaki-
menett jelentik. Megnyitva a processz rendelkezsre llnak indulskor.
Ahogy j llomnyt nyitunk meg, a kernel a legkisebb, a processzben mg
nem foglalt azonostt rendeli az llomnyhoz; ez az el'bbiek alapjn legalbb
3. Mi akkor a helyzet, ha azt szeretnnk, hogy pldul a szabvnyos kimene-
tnk egy llomny legyen? Ekkor arra van szksg, hogy az 1-es llomnyle-
rt lecserljk a megnyitott llomny lerjra.
Feladat rjunk programot, amely tirnytja a szabvnyos kimenetet egy llomnyba, majd
v issza ll tj a.
Elsknt el kell mentennk az eredeti kimenetet. Ezt a dup fggvnnyel tud-
juk megtenni, amely kszt egy msolatot az llomnylerrl. A fggvny a
dupliklt llomnyler szmra is a lehet legkisebb rendelkezsre ll azo-
nostt rendeli:
/*Elmentj uk azeredetik imenetet*/
out=dup(1);
fd=open("test", O_CREATIO_WRONLY, 0664);
if(fd -1)
{
perror("open");
return -1;
106
4.1. Egyszer llomnykezels
Ezek utn a dup2 fggvny segtsgvel lezrjuk az eddigi 1-es lert, s az fd
lert az 1-es lerv tesszk:
res = dup2 (fd , 1) ;
f(res == -1)
{
perror("1. dup2") ;
return -1;
pr ntf("Hello \n");
ffl ush (stdout) ;
/* Lezarjuk az al 1 omanyt
close(1) ;
Rgtn runk is az j llomnyba. Mivel a printf magas szint hvs, ezrt ki
kell rtennk a buffert, nehogy csak a ler visszalltsa utn rja ki a
sztringet. Meg kell jegyezni, hogy ebben a pldban szndkosan hasznlunk
szmot a szabvnyos kimenet azonostjra az elegnsabb STDOUT FILEN
helyett, mert a magyarzatokban ptnk az rtkre. A Hello! zenet a test
nev llomnyba rdik. Az rs utn lezrjuk az 1-es kimenetet, amely jelen
esetben a test nev llomny.
Ezek utn visszalltjuk a kimenetet. Ezt ktflekppen is megtehetjk.
Elsknt a dup2 fggvnyt hasznljuk. Ez ugyan lezrja ismt az llomnyt,
m azrt rdemes eltte mr lezrni, mert a lezrs hibazeneteit a dup2
nem adja tovbb:
res = dup2 (out , 1) ;
close (out) ;
A msik megolds a dup fggvny hasznlata:
dup(out) ;
cl ose (out) ;
Mivel a lezrs utn az 1-es lesz a legkisebb rendelkezsre ll azonost, a
dup ebbe msolja bele az eredeti out ler tartalmt. Az ezt kvet printf h-
vsok mr az eredeti kimenetre rjk ki az adatot.
rdemes megfigyelni, hogy mindkt esetben lezrtuk az outot, hiszen mr
nem volt r szksgnk. Ez jobban rvilgt a close fggvny mkdsre.
A close els kzeltsben az llomnylert szabadtja fel. Ha a processzben
nincs tbb llomnyler ugyanarra az llomnyra, akkor felszabadtja az l-
lomnyhoz tartoz erforrsokat. St ha egy trlt llomnyra ez volt az utol-
s nyitott ler, akkor az llomny vgleg trldik.
A fentiekhez hasonl megfontolsbl egyszerbben is tirnythatjuk a
kimenetet, feltve, hogy nem kell visszalltanunk:
107
close(1);
fd=open("test",0_cREATI0_wR0NLY,0664);
i f(fd==-1)
{
perror("open");
return-1;
write(1,hello,sizeof(hello)-1);
/*Lezarj uk azallomany t*/
close(fd);
4. fejezet: Allomny- s I/O kezels
Mivel a kimenetet lezrtuk, az open az 1-es azonostt rendeli hozz, amely a
szabvnyos kimenet.
A szabvnyos lerkat egymsra is tirnythatjuk. A szabvnyos hiba-
kimenetet a szabvnyos kimenetre az albbiak szernt irnythatjuk t:
- duP2 01
Meg kell jegyeznnk, hogy a dup ltal visszaadott llomnylert az exec
fggvnycsald meghvsa esetn rkli a gyermekprocessz, mg akkor is, ha
az eredeti lert az fnctl fggvnnyel gy lltottuk be, hogy ebben az esetben
lezrdjon.
rdekessgkppen megemltjk, hogy a shell is ezekkel a fggvnyekkel
vgzi az tirnytst. Amikor a shell elindt egy programot, fork hvssal elllt-
ja sajt maga egy j pldnyt, a gyermekprocesszt, amely rtelemszeren rk-
li az llomnylerkat is, kztk az eredeti 0-s, 1-es, 2 -es lerkat. Ha a shellben
tirnytottuk a kimenetet, a gyermekprocessz lezrja az tirnytand azonos-
tt, majd megnyitja az llomnyt, ahogy mi is tettk. Ezek utn meghvja az
exec fggvnycsald megfelel tagjt, ezzel elindtja az j folyamatot.
4.2. Inode-informcik
A 2.5.3. Az inode alfejezetben mr megismertk az inode-ok fogalmt. Ez l-
nyegben teht egy ler adatstruktra, amely az adott llomny paramtereit
tartalmazza. A kvetkezkben megismerkednk nhny fggvnnyel, amely-
lyel az inode-okat kezelhetjk.
108
4 .2 . Inode-informcik
4.2.1. Inode-informcik lekrdezse
A Linux az albbi hrom fggvnyt tmogatja az in,ode-informcik elrshez:
#incl ude <unistd.h>
intstat(constchar*file_name,structstat*buf);
intlstat(constchar*file_name,structstat*buf);
intfstat(intfd,structstat*buf);
Ezek a fggvnyek a megadott llomny inode-informcit adjk vissza.
Hasznlatukhoz nem kell semmilyen hozzfrsi jog az adott llomnyra, de
mind az llomnyt tartalmaz knyvtrra, mind pedig az oda vezet knyvt-
rakra rendelkeznnk kell keressi joggal.
Az els fggvny, a stat(), a file_name paramter ltal megadott llomny
inode-informciit adja vissza. Ha szksges, kveti a szimbolikus hivatko-
zst. Ha ez utbbi funkcit el szeretnnk kerlni, akkor az lstatQ fggvnyt
kell hasznlnunk. A legutols vltozat, az fstatO fggvny, amely a megnyi-
tott llomnyok inode-informciinak elrst teszi lehetv.
A struct stat a 4.3. tblzatban, tallhat elemeket tartalmazza.
4 .3. tblzat. A stat struktra elemei
Tipus
Mez Lers
dev_1 st_dev Az llomnyt tartalmaz eszkz azonostja
ino_t st_ino Az llomny on-disk inode-szma
mode_t st_mode Az llomny jogai s tpusa
st_nlink A referencik szma erre az inode-ra
uid_t st_uid Az llomny tulajdonosnak felhasznlazonostja
(user ID)
gid t st_gid Az llomny csoportazonostja (group ID)
dev_t st_rdev Ha az llomny specilis eszkzler, akkor ez a
mez tartalmazza a f- s mellkazonostt
off t st_size Az llomny mrete byte-tokban
unsigned long st_blksize A fjlrendszer blokkmrete
unsigned long st_blocks Az llomny ltal alloklt blokkok szma
time_t st_atime Az llomnyhoz val legutols hozzfrs idpontja
time_t st_mtime Az llomny legutols mdostsi idpontja
time_t st_ctime A legutols vltoztats idpontja az llomnyon
vagy az inode-informcin
109
4 . fejezet: llomny- s I/O kezels
Ezek alapjn az llomnynak hrom mrete lehet: van virtulis mrete a
lyukakkal, st_size a vals mrete, s vgl a vals helyfoglalsa a blokkos l-
lomnyrendszerben (st_blocks*st_size).
4.2.2. Jogok lekrdezse
Habr az inode-lerstruktra st_mode eleme tartalmazza az llomny jogait,
amellyel meghatrozhatjuk, mihez van jogunk, s mihez nincs, ezen inform-
cik kinyerse azonban nem kifejezetten knyelmes. Szerencsre a kernel
leegyszersti ezt a feladatot egy olyan rendszerhvs segtsgvel, amely
meghatrozza a hozzfrsi jogainkat.
Egy egyszer fggvnnyel le is krdezhetjk ezeket:
Ez a rendszerhvs ellenrzi, hogy az adott processz olvashatja vagy rhatja-e
a pathname paramterknt megadott llomnyt,
57
illetve, hogy egyltaln l-
tezik-e. Ha a megadott nv valjban egy szimbolikus hivatkozs, akkor az
ltala mutatott llomny jogait vizsglja a fggvny.
A mode paramter a kvetkez rtkekbl egyet vagy tbbet is tartal-
mazhat. Ezeket a 4.4 tblzat foglalja ssze.
4 .4 . tblzat. A hozzfrs mdjai
rtk Jelents
F_OK Az llomny ltezik-e, elrhet-e?
R_OK
W_OK
X_OK
A processz olvashatja-e az llomnyt?
A processz rhatja-e az llomnyt?
A processz futtathatja-e az llomnyt? (Knyvtr esetn ez a keressi jog.)
Termszetesen a vizsglatot befolysolja, hogy az elrsi tban megadott
knyvtrakra rendelkeznk-e keressi joggal.
57
Az access() a vals uid s gid alapjn ellenrzi a hozzfrst, s nem az effektv azonos-
tk alapjn.
110
4.2. Inode-informcik
4.2.3. Jogok lltsa
Az llomnyok hozzfrsi jogai a chmodO rendszerhvssal mdosthatk:
ncl ude <sys/stat h>
int chmod(const char *path, mode_t mode);
int fchmod(int fd, mode_t mode);
Habr a chmod() paramtere az llomny elrsi tvonala s neve, fontos,
hogy valjban inode-informcikat lltunk be. Vagyis ha az adott llomny-
ra tbb merev hivatkozs ltezik (lsd a 4.3.2. Merev hivatkozs ltrehozsa
alfejezetet), akkor a tbbi hivatkozsnl szerepl jogok is vltoznak.
A mode paramter a hozzfrs-vezrl bitek kombincija. Mint az open
fggvnynl mr volt sz rla, tipikus, hogy ezt a programozk oktlisan ad-
jk meg, m megtehetjk a kvetkez, a 4.5. tblzat rtkeinek kombinci-
jval is.
4 .5. tblzat. A mode paramter jelzbitjei
Ertk nvvel rtk szmmal Jelents
S_ISUID 04 000 setuid
S_ISGID 02 000 setgid
S_ISVTX 01000 sticky bit
S_IRUSR (S_IREAD) 004 00 Tulajdonos olvashatja
S IWUSR (S_IWRITE) 002 00 Tulajdonos rhatja
S_IXUSR (S _IEXEC) 00100 Tulajdonos futtathatja, kereshet
benne
S_IRGRP 0004 0 Csoport olvashatja
SIWGRP 0002 0 Csoport rhatja
S_IXGRP 00010 Csoport futtathatja, kereshet benne
S_IROTH 00004 Mindenki olvashatja
S_IWOTH 00002 Mindenki rhatja
SIXOTH 00001 Mindenki futtathatja, kereshet benne
Csak a root felhasznl s az llomny tulajdonosa jogosult a jogok lltsra.
Ha ezzel a fggvnyhvssal msok prblkoznak, akkor EPERM hibazene-
tet kapnak.

111
4. fej ezet: llom ny -s I/O k ezel s
4.2.4. Tulajdonos s csoport belltsa
Mint a jogok, az llomny tulajdonosa s csoportja is az inode-struktrban
troldik. Egy rendszerhvs szolgl mindkett belltsra:
#include<unistd.h>
intchown(constchar*path,uid_towner,gid_tgroup);
intlchown(constchar*path,uid_towner,gid_tgroup);
intfchown(intfd,uid_towner,gid_tgroup);
Az owner s a group paramterek adjk meg az j tulajdonost s csoportot.
Ha brmelyikk -1, akkor nem vltozik a bellts.
Mind a tulajdonos, mind a root felhasznl mdosthatja az llomny cso-
portjt. m mg az els esetben a tulajdonosnak az j csoport tagjnak kell
lennie, a msodik esetben, amikor a root felhasznl lltja be, akkor ilyen
megktsek nincsenek.
4.2.5. Az idblyeg belltsa
Az llomny tulajdonosa llthatja be az mtime (legutols tartalommdosts
ideje) s az atime (legutols hozzfrs deje) informcikat (lsd a 4.3. tbl-
zat inode-mezit tartalmaz rszt a 4.2.1. Inode-informcik lekrdezse alfe-
jezetben). Ez lehetv teszi az olyan archivl programoknak, mint a tar,
hogy visszallthassk az llomny idblyegt arra az rtkre, amely az arc-
hivlsnl szerepelt.
Kt lehetsgnk van az idblyeg-informcik belltsra: a utime() s
a utimesQ. A utime0 a System V rendszerbl szrmazik, innen tvette a
POSIX is. A utimeso a BSD rendszerekbl ered. A kt fggvny egyenrtk,
csak az idblyeg megadsa klnbzik:
#include<utime.h>
intutime(constchar*filename,structutimbuf*buf);
#include<sy s/time.h>
~E.q
",
i ntutimes(char*filename,structtimev al*tv p);
A POSIX utime() ltal hasznlt .struct utimbuf (amely a utime.h llomnyban
van definilva) struktrja a kvetkez:
112
4.3. Tovbbi llomnymveletek
struct utimbuf
time_t acti me;
time_t modti me;
A BSD utimes() fggvnye az idblyeget a struct timeval struktrval rja le
(ez a sys / tirne.h llomnyban van definilva):
struct ti meval
long tv_sec ;
long tv_usec ;
Ebbl a struktrbl egy ktelem tmbt kell ltrehoznunk s tadnunk pa-
ramterknt. Ennek a tmbnek a nulladik index eleme az atime, mg az els
index eleme az mtime rtket tartalmazza.
Ha brmelyik fggvnynek msodik paramterknt NULL rtket adunk
meg, akkor mindkt idblyeg az aktulis idpontra lltdik be.
4.3. Tovbbi llomnymveletek
Ebben a fejezetben a szimbolikus hivatkozsok, az eszkzkezel llomnyok s a
FIFO-bejegyzsek kezelshez szksges rendszerhvsokkal foglalkozunk.
4.3.1. Eszkzllomnyok s pipe bejegyzsek
ltrehozsa
Ahogy lttuk, az openo fggvny lehetv teszi a processznek, hogy j, egy-
szer llomnyokat hozzon ltre. A specilis llomnyok esetben az open()
fggvny paramterlistja nem tudja tvenni az sszes szksges informci-
t. Ezrt a specilis llomnyok ltrehozshoz tovbbi fggvnyekre van
szksg. A processzek a fjlrendszeren az mknod() rendszerhvs segtsgvel
hozhatnak ltre megnevezett csvezetkeket s eszkztpus llomnyokat:
#i ncl ude <fcntl .
#i ncl ude <uni std h>
int mknod(const char *pathname, mode_t mode, dev_t dev);
113
4. fejezet: llomny- s I/O kezels
A pathname a ltrehozand bejegyzs neve. A mode a hozzfrsi jogokat
(amelyet a uma,sk rtke mdost) s az llomny tpust hatrozza meg. l-
lomnytpusnak a 4.6. tblzatban tallhat rtkek adhatk meg.
4.6. tblzat. Az mknod llomny tpusa
rtk
S_IFREG
S_IFCHR
S_IFBLK
S_IFIFO
Jelents
Norml llomny
Karaktertpus eszkzllomny
Blokktpus eszkzllomny
Megnevezett csvezetk
Az utols dev paramter az S_IFCHR vagy az S_LFBLK md esetn megadja
a f- s mellkazonostkat (major s minor szmok) a ltrehozand eszkzl-
lomnyhoz. Az eszkz tpusa s fazonostja megadja a kernelnek, hogy me-
lyik eszkzkezelt hvja meg. A mellkazonost az eszkzmeghajtn belli
sztvlasztsra szolgl, ha az adott eszkzkezel tbb eszkzt is kiszolgl.
Csak a root hozhat ltre eszkztpus llomnyokat.
Az sys/sysmacros.h llomny tartalmaz hrom makrt a dev paramter
belltsra. A makedev() fggvny els paramtere a fazonost, a msodik a
mellkazonost, s ezekbl ltrehozza a dev_t rtket. A major() s minor()
makrk a dev_t rtkbl kiszmoljk az eszkz f-, illetve mellkazonostjt.
4.3.2. Merev hivatkozs ltrehozsa
Amikor a fjlrendszerben tbb llomnynv hivatkozik ugyanarra az inode-
ra, akkor ezeket az llomnyokat merev hivatkozsnak (kard link) nevez-
zk. Minden hivatkozsnak ugyanabban az llomnyrendszerben kell lennie.
Ezek a hivatkozsok teljesen egyenrtkek, illetve egyik trlse nem vezet
az llomny trlshez.
A link() rendszerhvs szolgl a merev hivatkozsok ltrehozsra:
A111111
intlink (constchar*oldpath,constchar*newpath);,
Az oldpath a mr ltez llomnynevet tartalmazza, a newpath az j merev
hivatkozs neve. Az j nv ugyangy hasznlhat ezek utn, mint a rgi,
ugyanis ugyanarra az llomnyra hivatkoznak a merev hivatkozs ltreho-
zsa utn mr nem lehet megmondani, hogy melyik volt az eredeti.
Azok a felhasznlk hozhatnak ltre j hivatkozst egy llomnyra,
akiknek van hozzolvassi joga, tovbb rsi joga arra a knyvtrra, ahova a
hivatkozst ltrehozza, valamint futtatsi joga a knyvtrra, ahol az eredeti
#include .unistd.h.
114
4.3. Tovbbi llomnymveletek
llomny van. Knyvtrakra val hivatkozst csak a root hozhat ltre, m ez
ersen ellenjavallt, mert az llomnyrendszert kevsb ttekinthetv s ne-
hezen kezelhetv teszi.
43.3. Szimbolikus hivatkozs ltrehozsa
A szimbolikus hivatkozs (symbolic link) flexibilisebb, mint egy merev hi-
vatkozs. Mg az utbbinl minden hivatkozs egyenrang, a szimbolikus
hivatkozs tulajdonkppen egy nll llomny, amelyik egy msik, gyneve-
zett clllomnyra mutat. Vagyis akkor, ha az adott llomnyt letrljk, a
szimbolikus hivatkozs az rvnytelen clllomnyra mutat. Hasznlata mind
knyvtrak, mind ltrehozhat partcik kztt is megengedett, st igen gyakori.
A rendszerhvsok tbbsge automatikusan kveti a szimbolikus hivatko-
zsokat, hogy megtallja az inode-ot, kivve, ha olyan vltozatukat hasznljuk,
amelyek ezt eleve kizrjk. Linux alatt a kvetkez fggvnyek nem kvetik
a szimbolikus hivatkozsokat:
chown()
lstat()
readlink()
renameQ
unlink()
Szimbolikus hivatkozsokat a symlink() rendszerhvssal hozhatunk ltre:
#include<unistd.h>
intsy mlink (constchar*oldpath,constchar*newpath); _
A fggvny ltrehoz egy newpath nev szimbolikus hivatkozst az oldpath l-
lomnyra.
A szimbolikus hivatkozs ltal mutatott llomnyt az albbi fggvnnyel
olvashatjuk ki:
#include <unistd.h>
ntreadlink (constchar*path,char*buf, size_tbufsize);
A szimbolikus hivatkozs neve a buf paramterbe kerl, ha belefr. A bufsize
tartalmazza a buf hosszt byte-okban. ltalban a PATH MAX mret
buffert hasznljuk, hogy elfrjen benne a kvnt tartalom. A fggvny egyik
furcsasga, hogy nem tesz a sztring vgre `\0' karaktert, vagyis a buf tar-
talma nem korrekt C sztring. Visszatrsi rtke a visszaadott byte-ok szma
vagy 1 hiba esetn. A szimbolikus link kvetshez nem kell semmilyen jo-
gosultsg, csupn ennek mdostshoz.
115
4. fejezet: llomny- s I/O kezels
4.3.4. llomnyok trlse
Az llomnyok trlse tulajdonkppen az inode-ra mutat hivatkozsok trl-
se, s csak akkor jelenti az llomny tnyleges trlst, hogyha az llomnyra
mutat utols merev hivatkozst is letrltk, ugyanis nincs olyan fggvny,
amely az llomnyt vglegesen trli, csak olyan, amely eltvolt egy merev
hivatkozst. Ezt a fggvnyt unlinkO-nek nevezik:
Ha a hivatkozs az utols volt az llomnyra, de mg egyes processzek nyitva
tartjk, akkor egszen addig megmarad, amg a legutols llomnylert is
lezrjuk. Ha az llomnynv egy szimbolikus hivatkozst takar, akkor ez le-
trldik.
Ha a nv egy socketre, csvezetkre vagy egyb ms eszkzre hivatkozik,
akkor ugyancsak letrldik. m azok a processzek, amelyek ekkor mg nyitva
tartjk a lert, tovbbra is hasznlhatjk az ilyen tpus llomnyokat.
4.3.5. llomnyok tnevezse
Az llomny nevt s elrsi tjt egszen addig megvltoztathatjuk, amg az
j elrsi t is ugyanarra a fizikai partcira hivatkozik. Ha mr egy ltez
nevet adtunk meg j nvknt, akkor elszr ezt a hivatkozst megsznteti a
rendszer, s utna hajtja vgre az tnevezst. A rename0 rendszerhvs ga-
rantltan atomi, vagyis minden processz egyszerre csak az egyik nevn lt-
hatja az llomnyt: nincs olyan eset, hogy egyszerre mindkt nven vagy
egyik nven sem lthat. Mivel az llomnymegnyitsok lnyegben az inode-
hoz ktdnek, ezrt ha ms processzek ppen nyitva tartjk az llomnyt,
akkor nincs rjuk hatssal az tnevezse. Szmukra tovbbra is gy mk-
dik, mintha nem is vltozott volna az llomny neve.
A rendszerhvs alakja a kvetkez:
#include<stdio.h>
intrename(constchar*oldpath,const char*newpath);
Meghvs utn az oldpath nev hivatkozs neve newpath lesz.
116
# nclude
4.4. Knyvtrmveletek
4.4. Knyvtrmveletek
A Linux a knyvtrakat az llomnyok rendszerezsre hasznlja. Ahogy sz
volt mr rla, a knyvtrbejegyzsek csak egyszer mutatk az on-disk inode-
okra. Minden lnyeges informci az inode-okban troldik. A knyvtrak l-
lomnyokat s tovbbi knyvtrakat tartalmazhatnak. Minden llomnynak
van egy szlknyvtra. Ez all egyetlenegy, az gynevezett gykrknyvtr
a kivtel, amelyre a / szimblummal hivatkozunk, amely az egsz knyvtr-
struktra eredete, gykere. Jllehet knyvtrak specilis llomnyknt lt-
szanak az llomnyrendszerben, s kezelskre szmos specializlt fggvny
ll a rendelkezsnkre, a knyvtrakat ugyangy megnyithatjuk az open
rendszerhvssal. Az albbi knyvtrfggvnyek kzl j nhnynak kt va-
ricija van: az egyik a knyvtr elrsi tvonalt vrja nulla vg sztring
formjban, a msik az open fggvny ltal visszaadott lert. Mindkt vari-
ci ugyanazt a feladatot vgzi el, a klnbsg csupn a knyvtr megads-
ban rejlik.
A getcwd0 fggvny lehetv teszi, hogy a processzek megllaptsk az
aktulis munkaknyvtrat:
Az els paramter, a buf, egy bufferre mutat, amely a knyvtr elrsi tvo-
nalt tartalmazza. Ha a knyvtr elrsi tvonala hosszabb, mint size-1 byte
(a 1 azrt szksges, hogy egy ' \ 0' karakterrel le tudja zrni), akkor a fgg-
vny ERANGE hibval tr vissza. Ha a hvs sikeres, akkor a buf tartalmaz-
za az informcit, hiba esetn az rtke NULL. rdemes MAX PATH mret
bufferrel prblkozni, ez szmos llomnyrendszeren megfelel, de ltalban
nem garantlhat, hogy annl rvidebb lesz a knyvtr neve.
Linux alatt, ha a paramter aktulis rtke NULL, akkor a szksges
mret helyet alloklja a szmra, s visszaadja az rtket. m ebben az
esetben a visszaadott sztringet free0-vel fel kell szabadtanunk.
Az aktulis knyvtr megvltoztatshoz kt rendszerhvs ll rendelke-
zsnkre:
#include <unistd.h>
int chdir(const char *path);
i nt fchdir(int fd);
117
4.fej ezet: llom ny - sI/Ok ezel s
Az els fggvny az llomnynevet hasznlja argumentumknt, a msodik
egy megnyitott knyvtr lerjt. Mindkt esetben a megadott knyvtr lesz
az j munkaknyvtr. Ezek a fggvnyek akkor trnek vissza hibval, ha a
megadott knyvtr valjban nem knyvtr, vagy pedig a processznek nin-
csenek meg a jogai a hasznlathoz.
Habr a rendszernek csak egyetlen igazi gykrknyvtra van, az 1"
knyvtr jelentse vltozhat az egyes processzeknl. Ezt a lehetsget a prog-
ramfejlesztk ltalban vdelmi okokbl hasznljk. gy a program a jogai el-
lenre sem tud hozzfrni a teljes fjlrendszerhez, csak az j gykrknyvtr
alknyvtraihoz. Pldul egy ftp dmon esetben, ha a gykrknyvtrat a
/home/ ftp knyvtrra lltjuk, akkor az I" knyvtr ezt a knyvtrat jelenti,
s az L." knyvtrvlts sem vezet ki ebbl az alknyvtrbl. A processz a
kvetkez rendszerhvssal egyszeren tllthatja a gykrknyvtrat, ha
rendelkezik rendszergazdai jogosultsgokkal:
#include<unistd.h>
intchroot(constchar*path);
A paramternek megadott knyvtr lesz az j gykrknyvtr. Ez a rend-
szerhvs ugyanakkor nem mdostja az aktulis munkaknyvtrat. gy a
processz tovbbra is hozzfrhet a tartalmhoz, illetve innen relatve minden
ms knyvtrhoz. Ezrt a chroot() fggvnyhvst kveten ltalban a mun-
kaknyvtrat is az adott knyvtrra lltjuk a chdir("/') rendszerhvssal. Ha
ezt nem tennnk, az a fent emltett alkalmazsok krben knnyen biztons-
gi problmkhoz vezethetne.
j knyvtrat az albbi rendszerhvssal hozhatunk ltre:
#include<unistd.h>
intmk dir(constchar*pathname,mode_tmode);

Ez a paramterknt megadott pathname knyvtrat hozza ltre a mode vl-
tozban megadott jogokkal (amelyet a umask rtke mdost). Ha a pathname
egy mr ltez llomny, vagy a megadott elrsi t valamelyik eleme nem
knyvtr vagy szimbolikus hivatkozs egy knyvtrra, akkor a rendszerhvs
hibval tr vissza.
Knyvtrat letrlni a kvetkez egyszer rendszerhvssal tudunk:
#include<unistd.h>
intrmdir(constchar*pathname);
11111 111
Ahhoz, hogy ez a fggvny mkdjn, a knyvtrnak resnek kell lennie. El-
lenkez esetben ENOTEMPTY hibazenetet kapunk vissza.
118
4.4.K ny v t rmv eletek
Egy programnak sokszor szksge van egy adott knyvtr llomnyainak
a listjra. A Linux erre a feladatra is ad egy fggvnygyjtemnyt, amely
lehetv teszi a knyvtrbejegyzsek kezelst.
A knyvtrakat megnyitni s bezrni a kvetkez rendszerhvsokkal
tudjuk:
#include<sy s/ty pes.h>
#include<dirent.h>
DIR*opendir(constchar*name);
intclosedir(DIR*dir);
Az opendir() egy mutatval tr vissza, amely a knyvtr lerjaknt hasznlatos a
mveletek sorn. Amikor a knyvtrat megnyitottuk, az egyes bejegyzseket
szekvencilisan, fggvnyhvsok sorozatval rhetjk el. Erre a readdirO fgg-
vny szolgl:
#include<sy s/ty pes.h>
#include<dirent.h>
structdirent*readdir(DIR*dir);
A visszatrsi rtkknt kapott dirent struktra a sorban kvetkez llomny
lerst tartalmazza. (Ebben a listban nem szerepelnek a knyvtrak, tovbb
a lista rendezetlen. Ha rendezett llomnylistra van szksgnk, akkor ezt
magunknak kell rendezni, erre a readdir() fggvny nem nyjt tmogatst.)
A dirent struktra tbb mezt is tartalmaz, az egyik hordozhat eleme a
d_name mez, amely az llomny nevt tartalmazza, a msik pedig a d_ino
mezt, amely az llomny inode-szmt foglalja magban. A tbbi elem rend-
szerspecifikus:
/*ezls.c-Kilistazzaazak tualisk ony v tartartalmat.*/
#include<errno.h>
#include<sy s/ty pes.h
#include<dirent.h>
# nclude<stdio.h>
ntmain(v oid)
{
DIR*k ony v tar;
structdirent*elem;
/*Azak tualisk ony v tarat(".")megny itj uk .*/
if((k ony v tar=opendir("."))==NULL)
perror("opendir");
return1;
119
4. fejezet: llomny- s I/O kezels
/*Azerrno-t0-raallitj uk areaddir()hibadetek talasahoz.*/
errno=0,
while((elem=readdir(k ony v tar))!=NULL)
{
puts(elem->d_name);
/*Aputs()modosithatj aazerrno-t,ezert
v isszaallitj uk .*/
errno=0;
if(errno)
perror("readdir");
return1;
closedir(k ony v tar);
return0;
rdemes megfigyelni a pldban az errno kezelst. A readdir() fggvny
ugyanis mind hiba esetn, mind a knyvtrlista vgn NULL-lal tr vissza.
Ahhoz hogy klnbsget tudjunk tenni a kett kztt, le kell ellenriznnk az
errno rtkt. Tovbb arra is gyelnnk kell, nehogy vletlenl ms fggv-
nyek (esetnkben a puts) ltal tlltott rtket vizsgljunk. Ezrt minden
readdir hvs eltt gondosan trljk az errno rtkt.
4.5. Csvezetkek
A csvezetkek (pipe) kommunikcit megvalst specilis llomnyok, ame-
lyek az rsmveletek sorrendjt megtartva tovbbtjk az informcit (FIFO,
first-in-first-out, elszr be-elszr ki") Amilyen sorrendben belertuk az ada-
tokat a csvezetkbe, olyan sorrendben tudjuk kiolvasni ket. A csvezetkeket
processzek/szlak kzti kommunikcira hasznljk. Jllehet ennek a tma-
krnek kln fejezetet szenteltnk, a csvezetkeket az llomnyabsztrakcis
felleten trtn hozzfrs miatt itt rszletezzk. A csvezetkeknek, mint
minden FIFO-sornak, van mrete, ezt a limits.h-ban deklarlt PIPE_BUF
makr adja meg. Ha a csvezetk megtelik, akkor az rsmveletek blokko-
ldnak addig, ameddig nem kezdjk kiolvasni belle az adatokat.
A csvezetkbe val rs vagy belerja az sszes adatot a csvezetkbe, vagy
blokkoldik. Ha az egy rsmvelettel kirand adat mrete nem haladja meg a
csvezetk mrett, akkor ms folyamatok ltal rt adattal sem keveredhet.
Az albbiakban bemutatjuk a csvezetkek kt tpust. Ezek a ltrehozs
s a megnyits mdjban klnbznek, utna ugyanazok a szablyok rv-
nyesek rjuk.
12 0
4.5. Csvezetkek
4.5.1. Nvtelen csvezetkek
A nvtelen csvezetkeket (unnamed pipe) a kernel a memriban hozza
ltre. A nvtelen csvezetkeknek kt vgpontjuk van, az egyik csak olvashat,
a msik csak rhat. A csvezetk a megnyitsa utn a kt vgpontjn egy-
egy llomnylerval rhet el. Nvtelen csvezetket a kvetkez rendszer-
hvssal hozhatunk ltre:
#include <uni std h>
int pipe(int fds[2]);
A fggvny a csvezetk kt vgt reprezentl llomnylerval tr vissza,
az fds[0] csak olvashat, az fds[1] csak rhat. Ezeket az llomnylerkat
ugyangy hasznlhatjuk, mint az egyszer llomnyokt: hasonlkppen a
read s a write fggvnyekkel rhatjuk s olvashatjuk, valamint ugyangy le
kell zrnunk ket a close fggvnnyel. A nvtelen csvezetkek automatiku-
san megsemmislnek, ha minden lerjukat bezrjuk. Ezek utn nzznk
meg egy pldt.
Feladat rjunk olyan programot, amely ltrehoz egy nvtelen csvezetket, majd egy gyer-
mekprocesszt, amely a csvezetkbe rja a szmokat nulltl kilencig. Eredeti programunk ol-
vassa ki a csvezetkbl a belert adatokat, s rja k a szabvnyos kimenetre.
A feladat egy lehetsges megoldsa az albbi:
#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>
int main()
{
int fds [2] ;
pid_t pid;
int res, i;
/* Letrehozunk egy uj csovezeteket */
res =pipe (fds);
if (res < 0) /* Na nem sikerult */
perror("pipe");
return -1;
/* Fork - uj processz letrehozasa
* 1
pici =fork();
121
4. fejezet: llomny- s I/O kezels
if
(pid<0)
/*Sik ertelenfork */
perror("fork ");
return-2 ;
if(pid==0)
{
/* A gy ermek processzbenv agy unk -ittcsak irunk */
close(fds[0]);
for(i=0; i< 10; i++)
write(fds[1], ,sizeof(int));
close(fds[1]);
return0;/*Gy ermek processzk ilep"/
else
/* A szuloprocesszbenittfoly tatj uk -ittcsak olv asunk */
close(fds[1]);
while((res=read(fds[0],&i,sizeof(i)))>0)
{
printf("%d\n",i);
if(res<0)
{
perror("read");
close(fds[0]);
intstatus;
wait(&status);/*v arunk agy ermek processzv egere
return0;/*szuloprocesszk ilep*/
A fenti program megnyitja a nvtelen csvezetket, majd ltrehozza a gyer-
mekprocesszt. A megolds kulcseleme az, hogy a gyermekprocessz is rkli a
folyamat llomnylerit, gy a csvezetkhez mind a szl, mind a gyermek
hozzfr. Pontosan ez az oka annak, hogy a nvtelen csvezetket olyan
processzek kztt hasznljuk, amelyeknek van kzs szlje: a megnyitott l-
lomny lerjt csak gy lehet tadni a processzek kztt.
A fent hasznlt rs- s olvassmveleteket jelentsen leegyszerstettk.
Ezek megfelel hasznlatra a ksbbiekben mg visszatrnk.
Az eredeti s taln mig a legfontosabb terlete a nvtelen csvezetkek-
nek a shell ilyen irny szolgltatsa:
catround.cpp1more'
122
4.5. Csvezetkek
Ekkor a shell ltrehoz egy nvtelen csvezetket, a cat segdprogram kimenett
az 5.3.3. Programok indtsa shellbl alfejezetben rszletezett mdon tirnyt-
ja a csvezetk rhat vgpontjra, mg a more segdprogram bemenett a cs-
vezetk csak olvashat vgpontjra.
Ha fggetlen processzek kztt szeretnnk FIFO-kommunikcit ltre-
hozni, akkor megnevezett csvezetket kell hasznlnunk.
4.5.2. Megnevezett csvezetkek
A megnevezett csvezetkek (named pipes), amelyeket FIFO-nak is ne-
veznek, olyan csvezetkek, amelyek az llomnyrendszerben is megjelennek.
A megnevezett csvezetket ellenttben nvtelen megfeleljvel egyszerre
tbb minden rhatja s olvashatja. Fontos megemlteni, hogy a megnevezett
csvezetket csak akkor rhatjuk, ha mr meg van nyitva olvassra, egyb-
knt SIGPIPE jelzst kapunk.
58

Az llomnyrendszerben megjelen llomnyra rdemes gy tekintennk,
hogy mindssze arra szolgl, hogy kt vagy tbb egymstl teljesen fggetlen
processz meg tudja nyitni. Az llomny neve az a kzs pont, ahol a pro-
cesszek kapcsoldni tudnak. Ezen kvl az llomnyon keresztl csak a jogo-
sultsgokat llthatjuk be. Maga az adatszerkezet ugyangy a kernelen bell
ltezik, nem troldik adat az llomnyrendszerben.
Megnyits utn a megnevezett csvezetk ugyangy viselkedik, mint a
nvtelen: ugyanazokkal a fggvnyekkel rhatjuk s olvashatjuk: ha betelik,
az rsmvelet blokkoldik. Ha egy processz rja s olvassa a csvezetket,
rdemes kln figyelmet fordtani a versenyhelyzetekre: nehogy a processz a
sajt olvassi mveletre vrjon egy blokkolt rsi mveletben, vagy fordtva.
Feladat rjunk egy olyan programot, amely ltrehoz egy megnevezett csvezetket, s a tar-
talmt kiirja a szabvnyos kimenetre. Ksztsnk egy msik programot is, amely csatlakozik a
csvezetkhez, s belerja a szmokat.
Ahogy sz volt mr rla, megnevezett csvezetket ltrehozhatunk az raknod
fggvnnyel, ha megadjuk az S_IFIFO jelzbitet. Egyszerbb azonban, ha az
mkfifo-t hasznljuk. A ltrehozs utn termszetesen meg kell nyitni az a
csvezetket. Az olvasst a szoksos mdon vgezzk:
#include<sy s/ty pes.h>
#include<sy s/stat.h>
#include<stdio.h>
#include <fcntl.h>
#include <errno.h>
58
Legalbbis a dokumentcik ezt lltjk, mi azt tapasztaltuk, hogy az rsmvelet blok-
koldott.
123
4 fejezet: llomny- s I/O kezels
#defineBUFF_SIZE102 4
intmain(intargc,char*argv [])
{
ntfd;
intres;
charbuff[BUFF_SIZE];
res=mk fifo(argv [1],0600);
i f(res--1)
perror("mk fifo");
return-1;
}
fd=open(argv [1], O_RDONLY);
if(fd== -1)
f
perror("open");
return-1;
while((res=read(fd,buff,BuFF_SizE-1))!=0)
{
if(res==-1)
{
11.
if(errno==EINTR)
{
continue;
}
perror("read");
break ;
}
buff[res]='\0';
printf("%s\n",buff);
}
close(fd);
return0;
Sztring olvassnl fel kell hvni a figyelmet arra, hogy mindig zrjuk le a
sztringet a sztring vgt jelz karakterrel. Ne bzzunk a csvezetk msik ol-
daln lv programban, mert elkpzelhet, hogy hibsan rtk meg, vagy az
adat tbb rszletben jn t.
59
gy a sztring vge karaktert nem kldjk t, s
nem is szmtunk r.
65
Tipikusan ez trtnik, ha az adatmennyisg nagyobb, mint a csvezetk mrete.
12 4
4.5.Csv ezet k ek
Ezek utn a programot sajt forrskdjnak kratsra is rvehetjk:
$rmpipex
$./namedpipel./pipex 8 i
[1]3 817
S catnamedpipel.c>./pipex
A program ltrehozta az albbi llomnyt az aktulis knyvtrban:
Slspipex-1
prw 1tihamerstaff0sep800:2 3 pipex
Az els p azt jelzi, hogy az llomny tpusa csvezetk (pipe"). Ezutn elk-
szthetjk a csvezetk msik oldaln az rsmveletet vgz programot. Ez
nem okoz klnsebb meglepetst:
intmain(intargc,char*argv [])
{
ntfd;
intlen,res;
char*buffer="Hello!";
len=strlen(buffer)-1;//Nemk uldj uk atalezarok arak tert
fd=open(argv [1],O_WRONLY);
i f(fd==-1)
{
perror("open");
return-1;
}
if((res=write(fd,buffer,len))==-1)
perror("write");
close(fd);
return0;
] .11
111
~---
-
-
rdemes megfigyelni, hogy ha elindtjuk az olvasst vgz programot, amg
nem rkezik adat, a read fggvny nem tr vissza: vrakozik. Ez problmt
jelenthet, ha egyszerre tbb csvezetket szeretnnk figyelni. Ez a problma
nagyon gyakran elfordul: kezelst a kvetkez fejezetben mutatjuk be.
12 5
4. fejezet: llomny- s I/O kezels
4.6. Blokkolt s nem blokkolt I/O
Nzzk meg az albbi pldt.
Feladat rjunk programot, amely kt csvezetkrl (pipel s pipe2) olvas adatot folyamato-
san, s ezeket kirja a szabvnyos kimenetre.
Elsknt deklarljuk a szksges vltozkat, kzttk lerkat, s a buffert,
majd megnyitjuk az llomnyt:
intfds[2 ];
charbuf[2 048];
intfdix;
nt res;
/*Olv asasramegny itj uk apipelespipe2 allornany ok at,ha
leteznek .*/
i f((fds[0]=open("pipel",O_RDONLY))<0)
011
1

Ezek utn felvltva olvassuk a csvezetkeket:


fdix=0;
while(1)
/*Haazadatrendelk ezesreall,beolv assuk ,es
megj elenitj uk */
res=read(fds[fdix],buf,sizeof(buf)-1);
if(res==0)
printf("Apipe%dlezarult\n",fdix+1);
return0;
}
elseif(res<0)
perror("read");
return1;
perror("openpipel");
return1;
}
if((fds[1]=open("pipe2 ",O_RDONLY))<0)
{
perror("openpipe2 ");
return1;
}
126
4.6. Blokkolt s nem blokkolt I/O
buf [res] =' \O' ;
printf("Pipe%d: %s", fdix+1, buf);
/* Amasik le ro kerul sorra. */
fdi x=(fdix+1)%2;
A csvezetkekkel foglalkoz fejezetben lttuk, hogy ha akkor olvasunk a cs-
vezetkbl, amikor nincsen rajta adat (a msik oldal nem kldtt semmit), az
olvassmvelet blokkoldik: adatra vrakozik, s csak akkor tr vissza, ha
a csvezetk msik oldaln rsmvelet trtnik. A kommunikcinak ezt a
mdjt blokkolt 1/0-nak (blocking I/O) nevezzk. Ez nemcsak azt jelenti,
hogy a programunk ki van szolgltatva egy msik program knye-kedvnek,
hanem azt is, hogy kt I/O kommunikciban nem vehetnk rszt egyszerre.
Ugyanis ha adatra vrakozunk az egyik csvezetk vgn, nem tudunk figyelni
arra, hogy milyen adatok jnnek egy msik csvezetken, vagy hogy a felhasz-
nl milyen billentyzetparancsot ad ki a billentyzeten, esetleg a hlzaton.
A megolds kzenfekv: krjk meg a kernelt, hogy ne blokkolja az olva-
ssmveleteinket. Ezt nern blokkold (nonblocking) 1/0-nak nevezzk.
Ha az llomnyokat az O_NONBLOCK opcival nyitjuk meg, akkor az
rsi-olvassi mveletek nem blokkoljk az olvass- s az rsmveleteket.
Ilyenkor a readO rendszerhvs azonnal visszatr. Ha nem llt rendelkezsre
olvasand adat, akkor az olvassi s rsi mveletek 1-et adnak vissza, s az
errno vltozt EAGAIN-ra lltjk. rs esetn ez azt jelenti, hogy mg egy-
szer meg kell ismtelnnk a mveletet.
6

Feladat Mdostsuk az elz programot gy, hogy nem blokkold 1/0-t hasznlunk.
Ehhez az llomny megnyitst az O_NONBLOCK jelzbittel vgezzk:
/* Olvasasra megnyitjuk a pipel es pipe2 allomanyokat, ha
leteznek. */
if((fds[0]=open("ppe1", O_RDONLYj O_NONBLOCK)) < 0)
{
perror("open pipel");
return 1;
}
if((fds[1]--open("pipe2", O_RDONLY O_NONBLOCK)) < 0)
{
perror("open ppet");
return 1;
Olvass esetn kezelnnk kell azt az esetet is, amikor nincs beolvasott adat
(az errno rtke EAGAIN):
60
Ez egyszer llomnyok esetben sosem fordul el.
12 7
4. fejezet: llomny- s I/O kezels
fdix=0;
while(1)
I
/* Ha az adat rendelkezesre all, beolvassuk, es
megjelenitjuk *I
res=read(fds[fdix], buf, sizeof(buf) - 1);
if(res > 0)
buf[res] = \O';
prntf("Pipe%d: %s", fdix+1, buf);
I
else if(res ==0)
printf("A pipe%d lezarult\n", fdix+1);
return 0;
else if((res < 0) && (errno 1= EAGAI N))
I
perror("read");
return 1;
I
/* A masik leiro kerul sorra. */
fdix=(fdix+1)%2;
I
A nem blokkolt read() abban az esetben, amikor a csvezetken nem ll ren-
delkezsre olvasand adat, de a csvezetk msik oldalt nyitva tartjuk,
EAGAIN hibazenetet ad visszatrsi rtkknt. A csvezetk msik oldal-
nak lezrst az elz pldhoz hasonlan a 0 visszatrsi rtk jelzi. A nem
blokkolt I/O kezels megadja ugyan a lehetsgt, hogy az egyes llomnyle-
rk kztt gyorsan vltogassunk, de ennek az az ra, hogy a program folya-
matosan olvasgatja mindkt lert, s ezzel terheli a rendszert, mg akkor is,
amikor nincs kommunikci. Ezrt ezt a mdszert egyltaln nem rdemes
alkalmaznunk.
Az idelis megolds az, hogy az opercis rendszernek megadjuk, hogy
milyen llomnylerkat szeretnnk olvasni, s a rendszer rtest az adat ren-
delkezsre llsrl, tovbb a program erre az rtestsre reaglva olvas.
Fontos megjegyezni: annak rdekben, hogy az rtestsre val vrakozs
kzben elkerljk a blokkolt olvassnl tapasztalt elhanyagolt" llomnyle-
rk problmjt, a programban a minket rdekl sszes llomnylerra
egyszerre s egy helyen kell vrakoznunk. Itt klnsen jl megfigyelhet az
llomnyabsztrakci ereje: minden olyan objektum elrhet llomnyknt,
amelyre rdemes vrakozni. A biztonsg kedvrt" ilyenkor nem blokkold
llomnymveleteket hasznlunk. Ezt a megoldst I/O multiplexelsnek
(I/O multiplexing) nevezzk, amelyet a Linux tbbflekppen is tmogat.
Az albbiakban ezeket vesszk sorra.
128
4.7. A multiplexelt I/O mdszerei
4.7. A multiplexelt I/O mdszerei
Az elz fejezetben lttuk, hogy ha egyszerre tbb adatforrssal szeretnnk
kommuniklni, akkor multiplexelt 1/0-ra van szksgnk. Ez minden esetben
a kvetkez forgatknyvet jelenti:
A) Megkrjk a kernelt, hogy rtestsen, ha az llomnyler kszen ll
valamilyen I/O mveletre.
B) Vrakozunk az rtestsre. Ilyenkor a processz vrakozik" llapotba
kerl, nem veszi el a processzoridt ms taszkoktl.
C) Az rtests felbreszti a processzt, ekkor megvizsgljuk, hogy melyik
llomnylerrl s -mveletrl szl az rtests.
D) Vgrehajtjuk az I/O mveletet nem blokkold zemmdban.
E) jrakezdjk a B) lpstl.
Ez a megolds egy ms jelleg programvezrlst jelent, mint az eddigi progra-
mok. Ahelyett, hogy a program elejtl vgig lefutna nmi vrakozssal, a
programnak lesz olyan rsze, amely esemnyekre vrakozik, s azokra reagl.
61

4.7.1. Multiplexels a select() fggvnnyel
A POSIX rendszerekben a multiplexels legrgebbi megvalstsa a selectO
rendszerhvs. Ebben a megoldsban egyetlen rendszerhvs klnbz
paramtereivel adjuk meg, hogy milyen llomnylerkon milyen mvelet
vgrehajhatsgra vagyunk kvncsiak, maximum mennyi idt szeretnnk
vrakozni, tovbb ugyanez a rendszerhvs vrakozik az eredmnyekre, s
adja vissza ket. A fggvny deklarcija a kvetkez:
4include<sy s/select.h>
intselect(int n, fd_set*readfds,fd_set*writefds,
hmiL
fd_set*exceptfds,structt mev al*timeout);
A kzps hrom paramter (readfds, writefds s exceptfds) egy-egy halmaz,
ezekkel adhatjuk meg, hogy mely llomnylerkra vagyunk kvncsiak, illetve
visszatrs utn ezek a halmazok tartalmazzk azokat az llomnylerkat,
amelyek kszek a rajtuk val mveletvgzsre. Az els llomnyler-lista, a
readfds, azokat az llomnylerkat tartalmazza, amelyeken olvasst vgez-
6,
Ha az egsz program ilyen vezrlsre pl, esemnyvezrelt programnak hvjuk. A 8.3.
A Qt esemnykezels-modellje alfejezetben rszletesen bemutatjuk az ilyen programok
sajrtossgait.
129
4. fejezet: llomny- s I/O kezels
hetnk (olvashat adat ll rendelkezsre). A writefds az rsra ksz llomnyle-
rkra vrakozik. Az exceptfds nagyon ritkn hasznlatos. Egy gyakori esetet
leszmtva
62
hasznlata meglehetsen esetleges, gy a tovbbiakban nem foglal-
kozunk vele. Ha valamilyen hiba trtnik az llomnnyal, akkor az belekerl a
readfds-be is, s az olvasst vgz fggvny adja vissza a hibt, valamint egyttal
tipikusan az errno-t is belltja. Ezekbl a listkbl brmelyik lehet NULL.
63

Mindegyik paramter egy-egy mutat egy fd_set adatstruktrra, amely az llo-
mnylerk egy halmaza. Ezeket a kvetkez makrkkal kezelhetjk:
Fo_zERo(fd_set * set);
Ez a makr kitrli az llomnyler-listt. Az albbi a makr hasznlatos a
lista inicializlsra:
FO_SET(int fd, fd_set * set);
Az albbi makr az fd lert hozzadja a listhoz:
FD_CLR(int fd, fd_set * set);
A kvetkez makr az fd lert kitrli a listbl:
FD_ISSET(int fd, fd_set * set);
Ez a makr igazzal tr vissza, ha az fd benne van a listban.
A select fggvny els paramtereknt a listkban szerepl legnagyobb l-
lomny lerjnl eggyel nagyobb szmot kell megadnunk, gy neknk kell
kkeresni a legnagyobb lert.
A timeout paramter tartalmazza azt a maximlis idt, ameddig a selectO v-
rakozhat. Ha ez letelik, akkor a selectO mindenkppen visszatr. A select() vissza-
trsekor mdostva adja vissza az rtket, jelezve, hogy mennyi id van mg
htra a megadott maximlis vrakozsi idbl, ez azonban nem mindegyik rend-
szeren van gy, ezrt tekintsk ezt az rtket definilatlannak. A fentiek tkr-
ben a select fggvnyt az albbi forgatknyv szerint hasznlhatjuk:
A) Megkrjk a kernelt, hogy rtestsen akkor, ha az llomnyler k-
szen ll valamilyen I/O mveletre.
1. sszerakjuk a megfelel halmazokat (FD_SET). Mivel a select
majd mdostja az tadott lerhalmazt, ezeket clszer lemsol-
ni, azaz eltrolni egy msik vltozban. Mivel a lerhalmazon
nem lehet vgigiterlni, kln eltroljuk az llomnylerkat, ese-
tnkben egy fds tmbben.
62
Socketek esetn soron kvli adat rkezett (lsd a 6.2 . Az sszekttets-alap kommuni-
kci alfejezetet).
63
A select fggvnyt sokszor hasznljk portolhat vrakozsra, ilyenkor az utols kivte-
lvel az sszes argumentumot lenullzzuk.
130
4.7. A multiplexelt I/O mdszerei
2 . Kiszmoljuk a legnagyobb llomnylert.
3. Inicializljuk a timeval struktrt.
B) Vrakozunk az rtestsre. Ilyenkor a processz vrakozik" llapotba
kerl, nem veszi el a processzoridt ms taszkoktl.
1. Meghvjuk a select fggvnyt.
C) Az rtests felbreszti a processzt, ekkor megvizsgljuk, hogy melyik
llomnylerrl s -mveletrl szl az rtests.
1. Megvizsgljuk a select visszatrsi rtkt.
a) Ha kisebb, mint nulla, akkor hiba trtnt. Kirjuk a hibt,
majd kilpnk.
b) Ha nulla, akkor lejrt a maximum-vrakozsiid, de semmi
vltozs nem trtnt a lerkkal. Itt elvgezzk azokat a m-
veleteket, amelyekrt a maximumidt belltottuk, majd E-tl
folytatjuk.
c) Ha nagyobb, mint nulla, akkor ez a hrom halmazban tall-
hat sszes ler szma.
2 . Felhasznlva az Al -ben ksztett fds tmbt, megnzzk, hogy
annak elemei benne vannak-e a halmazban (FD_ISSET).
D) Vgrehajtjuk az I/O mveletet nem blokkold zemmdban.
1. Ha az llomny benne van a readfds-ben, addig olvassuk, amg
van olvasand adat. A nulla rtk tovbbra is az llomny vgt
jelenti, csvezetkeknl (s socketeknl) azt, hogy a kapcsolatot a
msik oldalon lezrtk. Ha lezrtk, s folytatni akarjuk a kom-
munikcit, kivesszk az llomnylert a halmazokbl, s foly-
tatjuk E-tl.
2 . Ha az llomny benne van a writefds-ben, akkor rhatjuk.
E) jrakezdjk a B) lpstl.
1. Az Al-ben kszlt msolat alapjn visszalltjuk a lerhalmazo-
kat, s belltjuk a timeval struktrt.
2 . Folytatjuk B-tl.
Ennek tkrben vizsgljuk meg a kvetkez egyszer pldt.
Feladat Mdostsuk az elz programot gy, hogy a multiplexelst select fggvnnyel oldjuk meg.
131
4.fejezet: llomny- s I/O kezels
/*multipipe3 .c-Apipel-tesapipe2 -tolv assaparhuzamosan,
aselect()metodussal.*/
#include<stdio.h>
#include<unistd.h>
#include<fcntl.h>
#include<sy s/select.h>
intmain(v o d)
{
intfds[2 ];
charbuf[2 048];
nt ,res,maxfd;
fd_setwatchset;/*Afigy elendoleirok .*/
fd_setinset;/*Aselect()metodusaltalfrissitettlista.*/
/*Olv asasramegny itj uk apipele s p petallomany ok at,ha
l eteznek .*/
if((fds[0]=open("pipel",O_RDONLYIO_NONBLOCK))<0)
{
perror("openpipel");
return1;
if((fds[1]=open("pipe2 ",O_RDONLYIO_NONBLOCK))<0)
{
perror("openpipe2 ");
return1;
/*Ak etle rotelhely ezzek alistaban.*/
FD_ZER0(&watchset);
FD_SET(fds[0],&watchset);
FD_SET(fds[1],&watchset);
/*Kiszamolj uk alegnagy obbleiroertek et.*/
maxfd=fds[0]>fds[1]?fds[0]:fds[1];
/*Acik lusaddigtart,am glegalabbegy leirotfigy elunk .
while(FD_IssET(fds[0],&watchset)II
FD_ISSET(fds[1],&watchset))
{
/*Lemasolj uk aleirolistat,mertaselect()metodus
modositj a.*/
inset=watchset;
if(select(maxfd4-1,& nset,NULL,NULL,NULL)<0)
perror("select");
return1;
132
4.7. A multiplexelt I/O mdszerei
/" Ellenorizzuk, mely leiro tartalmaz olvashato adatot."/
for(i=0; i < 2; i++)
{
if(FD_ISSET(fds[i], &inset))
/* Az fds[i] olvashato, ezert olvassuk is.
./
res =read(fds[i], buf, sizeof(buf) - 1);
if(res > 0)
{
buf[res] ='\0';
printf("Pipe%d: %s", 1+1, buf);
else if(res ==0)
{
/* A pipe-ot lezartak. "/
close(fds[1]);
Fo_CLR(fds[1], &watchset);
el se
perror("read");
return 1;
return 0;
Ez a program hasonl eredmnyt ad, mint a nem blokkolt mdszert hasznl,
m jval takarkosabban bnik az erforrsokkal. sszehasonltva a progra-
mot a korbban kifejtett forgatkny D.1. pontjval, lthat, hogy nem olvas-
tuk addig az llomnyt, ameddig csak lehetett (az EAGAIN bekvetkeztig).
Elviekben ktfle esemnyrl kaphatunk rtestst:
az adott llomnyra adat rkezett, gy olvashatv vlt, illetve
olvashat adat ll rendelkezsre az adott llomnyban.
Az els esetben csak a vltozsrl kapunk rtestst, a msik esetben min-
daddig, amg az llomnyler olvashat llapotban van. Az els mdszert
lvezrelt (edge triggered), a msodikat szintvezrelt (level triggered) rte-
stsnek nevezzk. A ksbbiekben trgyalt epoll-t kivve mindegyik mdszer
szintvezrelt. Ezrt, ha az llomnyt addig olvassuk, amg tudjuk, megkml-
jk magunkat nhny felesleges select hvstl, illetve az argumentumok fel-
ptstl, de adatot akkor sem vesztnk, ha egyszerre csak egybuffernyi
adatot olvasunk be.
A select fggvnyt a BSD Unix vezette be, a hvsnak van egy POSIX-
verzija is:
133
4 . fejez et: llom ny - s I /O kez els
#include sy s/select. h>
intpselect(intnfds,fd_set*readfds,fd_set*writefds,
fd_set*exceptfds,
conststructtimespec*ntimeout,
constsigset_t*sigmask );
A legfontosabb klnbsg a kett kztt az, hogy a pselect a vrakozs idejre
kpes letiltani jelzseket a jelzsmaszkot tartalmaz utols paramter alap-
jn. Visszatrskor a kernel visszalltja az eredeti belltsokat. Akad kt
aprbb klnbsg is: a maximum-vrakozsiidt nagyobb felbontssal adhat-
juk meg a timespec struktrval, s a fggvny ezt az rtket nem rja fell.
Br ennek a struktrnak nanoszekundumot is megadhatunk, a gyakorlat-
ban nincsen nagy jelentsge, mert ezek a fggvnyek a mikroszekundum
felbontst sem tudjk garantlni.
A select s a pselect legfontosabb elnye a hordozhatsg. Legnagyobb
htrnya az, hogy els paramterknt a legnagyobb lert kell megadnunk, s
a fggvnyek a sznfalak mgtt az sszes kisebb lert figyelemmel ksrik,
fggetlenl attl, hogy benne van-e valamelyik halmazban. Termszetesen a
vrakozsi idt sem knyelmes minden hvs utn belltani, de ezt a prob-
lmt a pselect kikszbli.
4.7.2. Multiplexels a poll() fggvnnyel
A selectO mellett a Linux rendelkezik egy msik hasonl eszkzzel is: a poll0-
lal. Ez a fggvny a System V Unix vlasza a multiplexelsre, amely erfor-
rs-takarkosabb, mint a selectO.
Ellenttben a select fggvnnyel, a poll szmra minden lerhoz jelzbi-
tekkel megadjuk azokat az esemnyeket, amelyekrl rtestst szeretnnk
kapni. A fggvny ahelyett, hogy ezeket fellrn, egy msik jelzbitsorozat-
tal adja vissza az adott lerhoz tartoz rtestseket. Ezt az adatstruktrt a
pollfd definilja:
structpollfd{
intfd;
shortev ents;
shortrev ents;
1;
/* llom ny le r*/
/*figy eltesem ny ek */
/*v issszaadott(bek v etk ezett)esem ny ek */
Az fd meznek a megnyitott llomnylert adjuk rtkl. Az events mez ad-
ja meg, hogy a pollQ az adott llomny mely esemnyeit figyelje. Ez egy olyan
bitmaszk az adott esemnyekre, amely a 4.7. tblzatban bemutatott jelz'bi-
tek VAGY kapcsolatbl ll ssze:
134
4.7. A multiplexelt I/O mdszerei
4,7. tblzat. A poll jelzbitjei
kdt
Jelents
POLLIN Adat rkezett, amelyet beolvashatunk.
POLLPRI Soron kvli adat rkezett, amelyet beolvashatunk.
POLLOUT rhatunk.
POLLWRBAND Soron kvli adatot rhatunk.
A Linux ezeken kvl tovbbi jelzbiteket is ismer, j nhny kzlk ekvivalens
a fentiek valamelyikvel. A select readfds halmaznak a POLLIN I POLLPRI
bitkombinci felel meg, mg a writefds-nek a POLLOUT POLLWRBAND.
Az revents mez tartalmazza az rtestseket, vagyis az events mezben
megadott esemnyek kzl azokat, amelyek bekvetkeztek. Van hrom ese-
mny, amelyet mindenkppen visszakapunk, ha megtrtntek, ezrt ezeket
nem kell megadnunk figyelend esemnyekknt. Ezeket a 4.8. tblzat foglal-
ja ssze.
4.8. tblzat. A poll ltal figyelhet esemnyek
Jelzbit Jelents
POLLERR Hiba trtnt az llomnylerval.
POLLHUP A kapcsolatot lezrtk.
64

POLLNVAL Rossz llomnylert adtunk meg.
A poll rendszerhvs ezekbl az esemnyekbl ll tmbt, annak mrett s
egy vrakozsi idt vr:
4include <poll.h
int poll(struct pollfd *ufds, unsigned int nfds, int timeout);
A timeout azt a maximlis vrakozsi idt ezredmsodpercben adja meg,
amely utn a fggvny visszatr. A timeout paramter esetben a negatv r-
tk vgtelen vrakozst jelent.
A rendszerhvs visszatrsi rtke tartalmazza azt, hogy hny llomny-
lerra kvetkezett be esemny, vagyis hny nem nulla revents mezt tartal-
maz struktra tallhat a tmbben. Idtllpskor az rtke 0, hiba esetn
pedig 1. Lthat, hogy a rendszer tt mskppen jelzi a msik oldal lezr-
snak esemnyt: kln jelz'bittel, s nincsen sszevonva az olvasssal, mint
a selectO fggvnynl.
Ezek utn tekintsk t a poll hasznlatnak forgatknyvt.
64
A Linux tmogatja a POLLRDHUP esemnyt, amely a msik oldal lezrst jelzi.
135
4. fejezet: llomny- s I/O kezels
A) Megkrjk a kernelt, hogy rtestsen akkor, ha az llomnyler k-
szen ll valamilyen I/O mveletre.
1.
Sorra vesszk az llomnylerkat, felptjk bellk a tmbbe
rendezett pollfd struktrkat, belltjuk a figyelni kvnt esem-
nyeket.
B) Vrakozunk az rtestsre. Ilyenkor a processz vrakozik" llapotba
kerl, nem veszi el a processzoridt ms taszkoktl.
1. Meghvjuk a poll fggvnyt a fenti tmbbel, annak mretvel s a
vrakozsi idvel.
C) Az rtests felbreszti a processzt, ekkor megvizsgljuk, hogy melyik
llomnylerrl s -mveletrl szl az rtests.
1. Ha a fggvny visszatrsi rtke negatv, kezeljk a hibt az
errno kiolvassval, kilpnk, esetleg folytatjuk B1-tl.
2 . Ha a visszatrsi rtk nulla, lejrt a vrakozsi id anlkl, hogy
brmilyen rtests rkezett volna. Itt elvgezzk azokat a mve-
leteket, amelyekrt a maximumidt belltottuk, majd E-tl foly-
tatjuk.
3. Ha a visszatrsi rtk pozitv, bejrjuk a tmbt, s megvizsgl-
juk az egyes struktrk revents mezjt.
D) Vgrehajtjuk az I/O mveletet nem blokkold zemmdban.
1. A POLLERR s a POLLNVAL ellenrzsvel megnzzk, hogy
trtnt-e hiba. Ha igen, kezeljk, kilpnk, vagy folytatjuk E-tl.
2 . Ha nem eszkzket, hanem kommunikcis csatornkat (csveze-
tkek, socketek) kezelnk, a POLLHUP jelzbit vizsglatval el-
lenrizzk, hogy a msik oldal nem zrta-e le a kapcsolatot. Ha
lezrult, s folytatni akarjuk a kommunikcit, kivesszk az l-
lomnylert a pollfd tmbbl, s folytatjuk E-tl.
3. Ha POLLIN jelzbit be van lltva, akkor nem blokkold zem-
mdban olvassuk az llomnylert.
4 . Ha a POLLOUT jelzbit be van lltva, akkor rhatjuk az llo-
mnyt.
E) jrakezdjk a B) lpstl.
Ezek alapjn nzzk meg a pollQ hasznlatt a mr jl ismert pldn keresztl.
Feladat Mdostsuk az elz programot gy, hogy a multiplexelst a poll fggvnnyel oldjuk meg.
136
4.7.Amultiplexelt I/O mdszerei
/*multipipe4.c-Apipel-tesapipe2 -tolv assaparhuzamosan,a
poll()metodussal.*/
#include<stdio.h>
#include<unistd.h>
#include<fcntl.h>
#include<poll.h>
intmain(v oid)
{
intfds[2 ];
1111
111

charbuf[2 048];
inti,res;
structpollfdpollset[2 ];
intnumpoll=2 ;
/*Olv asasramegny tj uk apipelespipe2 allomany ok at,ha
leteznek .*/
if((fds[0]-open("pipel",O_RDONLY1O_NONBLOCK))<0)
{
perror("openpipel");
return1;
}

if((fds[1]=open("pipe2 ",O_RDONLY 1 O_NONBLOCK))<0)


{
perror("openpipe2 ");
return1;
}
/*Ak etleirotelhely ezzuk alistaban.*/
pollset[0].fd=fds[0];
pollset[0].ev ents=P OLLIN;
pollset[1].fd=fds[1];
pollset[1].ev ents=P OLLIN:
while(1)
/*Apollfuggv eny v arak ozik azesemeny re*/
i f(poll(pollset,numpoll,-1)<0)
perror("poll");
return1;
/*Ellenorizzuk mely leirotartalmazolv ashatoadatot.*/
for(i=0;i<numpoll;i++)
//errorcheck
if(pollset[i].rev ents&(P OLLERRIP OLLNVAL))
13 7
4. fejezet: llomny- s I/O kezels
printf("Hibaamuv eletbenv agy erv eny telen
allomany leiro\n");
return1;
if(pollset[i].rev ents& POLLHUP)
{
printf("Apipe%dlezarult\n",1+1);
return0;
if(pollset[i].rev ents&POLLIN)
/"Azfds[i]olv ashato,ezertolv assuk s. */
res=read(fds[i],buf,sizeof(buf)-1);
/*Ittaltalabanreszlegesolv asastalalhato*/
if(res>0)
[
buf[res]='\0';
O M F
printf("P ipe%d:%s",1+1,buf);
else
perror("read");
return 1;
return0;
Hasonlan a select fggvnyhez, a pollnak is van egy ppoll vltozata, amely
viszont nem POSIX-kompatibilis. Ez ugyangy a jelzsek letiltst teszi lehe-
tv, tovbb a vrakozsi id pontosabb megadst.
A po//nak ugyanakkor van egy msik, szintn csak Linux alatt mkd
verzija, az epoll (event poll'). Hasznlata nagyon hasonlt a pollra, a legl-
nyegesebb klnbsg az, hogy az llomnylerkat tartalmaz adatszerkezet
nem halmaz, nem is tmb, hanem egy olyan llomny, amelyet az epoll_create
fggvnnyel hozunk ltre, s az epoll_ca fggvnnyel vltoztathatunk meg.
Az rtestsekre az epoll_wait fggvnnyel vrakozhatunk. Az epoll_ctl fgg-
vnynek azt is megadhatjuk, hogy l- vagy szintvezrelt rtestst szeret-
nnk-e kapni.
13 8
4.8. llomnyok lekpezse a memriba
4.7.3. A multiplexelsi mdszerek sszehasonltsa
Nhny llomnyler esetn gyakorlatilag az sszes mdszer ugyanolyan
gyors. A poll hordozhatsga egyre inkbb megkzelti a selectt, ahogy az
egyre rgebbi rendszereket lecserlik. A pollt valamivel knyelmesebb prog-
ramozni, m a klnbsg annyira nem jelents.
Nagyobb szm llomnylerk esetben az sszes mdszer linerisan
sklzdik: ha ktszer annyi llomnylert figyelnk, nagyjbl ktszer any-
nyi ideig tart, amg a kernel feldolgozza az esemnyt, s visszatr az rtes-
tssel. A select esetben ez a szm inkbb a legnagyobb llomnylerval, a
poll esetn a tmb mretvel, mg az epoll esetn az aktv (tnylegesen rtest-
seket kld) llomnylerk szmval arnyos. Ahogy az aktv llomnylerk
szma kzeledik az sszes ler szmhoz, gy romlik az epoll teljestmnye.
Ezt a szmot mrsekkel rdemes meghatrozni.
Az epoll esetben annyi llomnylert hasznlhatunk, amelyet a / proc/
sys/fs/epoll/max_user_watches llomny megenged, mg a select esetben ez
egy konstans (FD_SETSIZE), illetve RLIMIT NOFILE poll esetn. Ez utbbi
egybknt az sszes megnyithat llomny szma.
4.8. llomnyok lekpezse a memriba
Az eddig megismert llomnykezelsi megoldsok mellett kihasznlhatjuk a
virtulismemria-kezel lehetsgeit: az llomnyokat s az llomnyszeren
megjelen eszkzket a POSIX-kompatibilis mmap() fggvny segtsgvel
lekpezzk a folyamat virtulismemria-terletre.
Hagyomnyos esetben az llomny tartalma ktszer van bent a memri-
ban: a laptrban, valamint az r-olvas fggvnyeknek tadott pointerek ltal
megcmzett adatterleteken. A lekpezssel pontosan ezt a kettssget takart-
juk meg: az adat kzvetlenl a felhasznl cmtartomnyba kpzdik le.
Az mmap alkalmazsakor az llomny tartalma nem msoldik be tnylegesen
a fizikai memriba, csak egy lekpezst hoz ltre. Az llomnyt a virtulis-
memria-kezels mechanizmusa, vagyis az igny szerinti lapozs algoritmusa
tlti be, amikor az adott memrialapra hivatkozunk, s a rendszer szreveszi,
hogy a lap nem tallhat a memriban.
A lapozsos virtulismemria-kezels jellegbl addik, hogy csak egsz
lapokat kezelhetnk. Ezrt, ha az llomny mrete nem egyezik meg a lap-
mrettel vagy annak tbbszrsvel, akkor az llomny vge utni terlet a
laphatrig 0 rtkkel lesz kitltve. Ha erre a terletre ksbb runk, akkor ez
nem mentdik el az llomnyba.
139
4. fejezet: llomny-s I/Okezels
Ha az mmap() fggvnyt egy eszkzllomnyra hasznljuk, akkor egy
megosztott memriaterletet hozhatunk ltre a meghajtprogram s az al-
kalmazs kztt. Az adott fizikaimemria-lapot mind az alkalmazs, mind az
eszkzkezel elri. gy a kt komponens kztt gyors adattvitelt valstha-
tunk meg. m ilyenkor a konkurenciaproblmkat is neknk kell kezelni.
Ezrt a meghajtmodul ksztje valsznleg szinkronizlsi mechanizmu-
sokat is definil az mmap() fggvny hasznlathoz. Ennek az adott meghaj-
tprogram dokumentcijban kell utnanznnk. (A problma okait s
lehetsges megoldsait lsd a 7.12. Az mmap tmogatsa alfejezetben.)
Az mmap() fggvny alakja a kvetkez:
void *mmap(void *addr, size_t length, int prot, int flags, int fd,
off_t offset) ;
Az addr paramterben azt a memriacmet adhatjuk meg, ahova az llo-
mnyt le szeretnnk kpezni. Ha az rtke NULL, akkor a kernel vlaszt c-
met. A lehetsges tkzsek elkerlse rdekben ltalban ez a vlaszts
javasolhat. Ha megadunk egy cmet, s az nem esik laphatrra, akkor a ker-
nel nem pontosan ezt a cmet hasznlja, hanem a legkzelebbi laphatrra
igaztja. A fggvny visszatrsi rtke tartalmazza azt, hogy a lekpezs
tnylegesen milyen cmre trtnt meg.
A fggvny az fd llomnylerval hivatkozott llomny tartalmt az
offset kezdcmtl length byte hosszan kpezi le az elzekben kiszmolt me-
mriacmre. Az offset rtknek nullnak vagy a lapmret
65
tbbszrsnek
kell lennie.
A prot paramter adja meg a memrialapokra vonatkoz vdelmi bellt-
sokat. Ezekkel korltozhatjuk az llomnyon vgezhet mveleteket. Ugya-
nakkor figyelnnk kell arra, hogy ezek a belltsok ne tkzzenek az llomny
megnyitsakor az openO fggvnynl hasznlt belltsokkal. A prot paramter
rtke lehet PROT NONE vagy a 4.9. tblzatban sszefoglalt rtkek biten-
knti VAGY kapcsolata:
4 .9. tblzat. A prot paramter jelzbitjei
rtk Jelents
PROT_EXEC A lap futtathat.
PROT_READ A lap olvashat.
PROT_WRITE A lap rhat.
A flags paramter szablyozza azt, hogy ha ms folyamatok is lekpezik az l-
lomnynak ugyanazt a terlett a memriaterletkre, akkor a vltoztatsokat
lssk-e. A flags paramter lehetsges rtkei a kvetkezk (4.10. tblzat).
65
Az adott rendszeren hasznlt lapmretet a sysconf( SC_PAGESIZE) fggvnyhvssal
krdezhetjk le.
14 0
4.8. llomnyok lekpezse a memriba
4.10. tblzat. A flags paramter rtkei
rtk Jelents
MAP_SHARED A rendszer megosztja az informcikat. Ha a lekpezett memri-
n keresztl mdostjuk az llomny rtkt, akkor az lement-
dik az llomnyba, s ezen keresztl a msik folyamat is ltja.
m addig nem biztos, hogy frissl az llomny, amg az msyne()
vagy az munmapQ fggvnyek valamelyikt meg nem hvjuk.
1VIAP_PRIVATE Egy privt lekpezst hoz ltre a rendszer. A memriban tr-
tnt mdostsok nem lthatk a tbbi, ugyanazt az llomny-
rszt hasznl folyamat szmra. Nincs meghatrozva, hogy a
lekpezs utn az llomnyon vgzett mdostsok, lthatk-e
a lekpezett terleten.
Az eddig felsorolt rtkek POSIX-kompatibilisek, lteznek azonban nem hor-
dozhat belltsok is. Ezekbl nhny fontosabbat a 4.11. tblzat foglal ssze.
4 . 11. t b l za t . A flags tovbbi paramterrtkei
r t k Jelent s
MAP_ANON Lsd MAP ANONYMOUS.
A lekpezs htterben nincs valdi llomny. Az fd pa-
MAP_ANONYMOUS ramter rtkt figyelmen kvl hagyja a rendszer, s a
terletet kezdrtkknt 0-val tlti fel.
MAP_FIXED
Az addr paramtert nemcsak javaslatnak veszi a rend-
szer, hanem pontosan oda vgzi el a lekpezst. Az addr-
paramternek azonban ebben az esetben pontosan lap-
hatrra kell esnie.
MAP_LOCKED
A lekpezett memriaterletet a fizikai memriban
tartja, s nem engedi az eltvoltst.
Ha minden paramtert jl adtunk meg, akkor az mmap() fggvny a lekpe-
zett memriaterlet kezdcmvel tr vissza. Ha valamilyen hibt kvettnk
el, akkor a visszatrsi rtke MAP_FAILED, amely valjban (void*)-1.
Az errno rtke tartalmazza a hiba kdjt.
Az mmap() fggvnnyel ltrehozott lekpezst az munmapQ fggvnnyel
oldhatjuk fel. Az munmapQ fggvny alakja a kvetkez:
11
~01~e~
1~01
Az munmapQ fggvny az addr s a length paramterek ltal megadott cmtar-
tomnyra megsznteti a lekpezst. A lekpezs abban az esetben is auto-
matikusan megsznik, ha a folyamat vget r. Arra azonban figyeljnk, hogy
az llomny bezrsakor nem sznik meg automatikusan. Ezrt a elose() fgg-
vny hvsa eltt az munmapQ-pal meg kell szntetnnk minden lekpezst.
141
4. fejezet: llomny- s I/O kezels
Az addr paramternek ezttal is laphatrra kell esnie. Ez a felttel telje-
sl, ha az mmap() fggvny ltal visszaadott cmet hasznljuk.
A lekpezs feloldsa utn, ha a korbban hasznlt memriaterletre hi-
vatkozunk, akkor memriakezelsi hiba trtnik, s a rendszer egy SIGSEGV
szignllal lelltja a folyamatunkat.
rdemes mg megemlteni az msyncQ fggvnyt, amelynek segtsgvel a
memria s az llomny tartalmt szinkronizlhatjuk. Ha a memriban vl-
toztatunk az adatokon, s nem hasznljuk az msync fggvnyt, akkor nem
tudhatjuk, hogy az munmap hvsa eltt kirdik-e egyltaln valamikor a
mdosts az llomnyba, illetve mikor trtnik meg. Az msync fggvnnyel
ezt garantlhatjuk. A fggvny alakja a kvetkez:
intmsy nc(v o
-
id*addr,size_tlength,intflags);
1111111~MINE
Az addr s a length paramterekkel adhatjuk meg, hogy melyik cmtarto-
mnyra krjk a szinkronizlst. A flags paramter a kvetkez rtkek bi-
tenknti VAGY kapcsolata lehet (4.12. tblzat).
4.12 .tblzat. Az msync jelzbitjei.
rtk Jelents
MS ASYNC
A frisstst krelmezzk, de a fggvny azonnal vissza-
tr mg a szinkronizls befejezse eltt.
MS_SYNC
A fggvny addig vr, amg a frissts be nem fejezdik,
s csak utna tr vissza.
MS_INVALIDATE
Az adott llomny tbbi lekpezsnek frisstst krel-
mezi. gy ezek a lekpezsek is ltjk az j tartalmat.
Az MS ASYNC s az MS SYNC belltsok termszetesen sszefrhetetle-
nek, gy egyszerre nem lehet ket hasznlni.
Az msync0 fggvny sikeres hvskor 0 rtkkel tr vissza, egybknt 1-
gyel, s az errno vltoz tartalmazza a hibakdot.
A kvetkez egyszer pldn bemutatjuk az mmap() fggvny hasznla-
tt. A program megnyitja a paramterknt megadott llomnyt, lekpezi a
memriba, s a memribl kirja a tartalmt. Ezt kveten a program v-
gn automatikusan megsznik a lekpezs, s bezrdik az llomny:
#include<unistd.h>
#include<stdio.h>
#include<sy s/ty pes.h>
#include<sy s/mman.h>
#include<fcntl.h>
nt man(int argc, char* argvlj)
int fd;
char* mem;
1 4l
4.9. llom ny z rol s
i f(argc ! = 2)
printf("Hasznlat: %s llomny\n", argv[0]);
return 1;
if((fd = open(argv[1], O_RDONLY)) < 0)
perror("open");
return 1;
if((mem = mmap(0, 256, PROT_READ, MAP_SHARED, fd, 0)) ==
MAP_FAILED)
{
perror("mmap");
return 1;
write(srpouT_FILEN0, mem, 256);
return 0;
4.9. llomnyzrols
Jllehet ltalnos eset, hogy egyidejleg tbb processz hasznl egy llomnyt,
ehhez megfelel vatossgra van szksg. Sok llomny tartalmaz komplex
adatstruktrkat, amelyek versenyhelyzetben knnyen megsrlhetnek. Ezek-
nek a problmknak a megoldst szolglja az llomnyzrols (file lock).
Kt fajtjt klnbztetjk meg. Az ltalnosabb tjkoztat zrols
(aduisory lock) csak informcit szolgltat, a kernel nem felgyeli a hozzf-
rst; csak egy olyan konvenci, amelyet az llomnyhoz hozzfr processzek
kvetnek. A msik fajta a ktelez zrols (mandatory lock), amelynek be-
tartst a kernel foganatostja. Ha egy processz zrolja az llomnyt azrt,
hogy rhasson bele, akkor a kernel a tbbi rni vagy olvasni prbl processzt
a zrols feloldsig felfggeszti. Br ez utbbi megolds tnik a haszno-
sabbnak, a sok vizsglat azonban minden rs- s olvassmveletnl cskken-
ti a rendszer teljestmnyt.
A Linux kt metdust tmogat az llomnyzrolsra: a zrolllom-
nyokat s a rekordzrolst (record lock).
143
4.fej ezet: llom ny - sI/Ok ezel s
4.9.1. Zrolllomnyok
A zrolllomnyok biztostjk a legegyszerbb lehetsget a hozzfrs vezr-
lsre. Minden vdend llomnyhoz hozzrendelnk egy msik fjlt, az gy-
nevezett zrolllomnyt Amikor a zrolllomny ltezik, akkor az adott
fjl zrolva van, teht ms processzeknek nem szabad hozzfrnik. Ha a
zrolllomny nem ltezik, akkor a processz ltrehozhatja, s hozzfrhet az
llomnyhoz. Amg a zrolllomny ltrehozsa atomi mvelet, addig ez
a mdszer garantlja a klcsns kizrst.
Ebbl kvetkezik, hogy a zrolllomny vizsglatt s ltrehozst egy
rendszerhvson bell kell megejtennk, klnben egyes helyzetekben ez a md-
szer nem mkdik megfelelen. Erre hasznlhat az open0 fggvny O_EXCL
jelzbitje (lsd a 4.1.2. llomnyok megnyitsa alfejezetben). Ha ezt megadjuk, s
az llomny ltezik, akkor az llomny ltrehozsa meghisul. A fggvny ilyen-
kor hibajelzssel tr vissza. gy a megvalsts pldul az albbi lehet:
fd=open("somefile.ick ",O_WRONLY O_CREATIO_EXCL,0644);
if((fd<0)&&(errno==EEXIST)
{
printf("Azallomany blok k olt.\n");
return1;
elseif(fd<0)
{
perror("lock ");
return1;
/*Apidbeleirasaazallornany ba.*/
close(fd);
A zrolllomny megszntetse az unlink(somefile.lek") fggvnyhvssal
lehetsges.
A Linux rendszereknl ltalnos a zrolllomny hasznlata, pldul a
soros portok vagy a jelszllomny kezelsnl. Annak ellenre, hogy sokszor
jl hasznlhatk, rendelkeznek nhny htrnnyal is:
Egyszerre csak egy processz frhet hozz az llomnyhoz, gy kizrja
tbb processz prhuzamos olvassnak a lehetsgt.
Az O_EXCL jelzbit csak a loklis fjlrendszereknl hasznlhat.
Ez a zrols csak tjkoztat, a processzek, ha akarnak, hozzfrhet-
nek az llomnyokhoz a zrolllomny ellenre is.
144
4.9. llom ny z rol s
Ha a zrolllomnyt ltrehoz processz meghibsodik, futsa meg-
szakad, a zrolllomny megmarad. Ha a zrolllomny tartalmaz-
za a processz azonostjt, akkor a tbbi processz megbizonyosodhat a
futsrl, s szksg esetn trlheti a zrolllomnyt. Viszont ez
komplex megolds, s nem is mkdik minden esetben.
A kvetkez fejezetekben bemutatott mdszerek orvosoljk ezeket a probl-
mkat.
4.9.2. Rekordzrols
A zrolllomnyok problmjnak megoldsra a System V rendszerekben
megjelent a rekordzrols, amely a lockf() s a flock0 rendszerhvsokkal
rhet el. A POSIX-szabvny egy harmadik metdust is definil az fenti()
rendszerhvs hasznlatval. A Linux mindhrom metdust alkalmazza, m
a lockf() metdust nem kln rendszerhvsknt, hanem az fenti() rendszer-
hvsnak interfszeknt implementlja. A kvetkezkben az fenti() rendszer-
hvst trgyaljuk.
A rekordzrols elnyei a zrolllomnyokkal szemben az albbiak:
Az llomnyok egyes terleteit kln-kln zrolhatjuk.
A zrolsok nem troldnak a fjlrendszeren, a kernel kezeli ket.
Amikor a processz megsznik, a zrols felszabadul.
A rekordzrols kt zrolstpusbl ll: az olvassi zrols (rend lock) s az
rsi zrols (write lock). Az olvassi zrols megosztott zrols (shared
lock), mivel tbb processz szmra is lehetv teszi egy llomnyterlet pr-
huzamos olvasst.
Amikor a processznek rnia kell egy llomnyt, akkor az rsi zrolssal
kizrlagos jogot kell szereznie az adott terletre. Az rsi zrols kizrla-
gos zrols (exclusive lock). A kizrlagos zrolsra az jellemz, hogy egy-
szerre csak egy processz rhatja a terletet, s ms processzek mg olvassi
zrolst sem hozhatnak ltre rajta.
A POSIX-szabvny szerint a rekordzrols az fenti() rendszerhvsokon
keresztl rhet el. Ennek defincija a kvetkez:
#include<fcntl.h>
intfcntl(intfd,intcmd);
intfcntl(intfd,intcmd,longarg);
ntfcntl(intfd,intcmd,structflock ,lock ); 4111
Esetnkben a zrols hasznlatra az utols alak alkalmazand. Itt az utols
paramterben szerepl pointer egy flock struktrra mutat:
145
4. fejezet: llomny- s I/O kezels
struct flock
{
short l_type;
short l_whence;
off_t l_start;
off_t l_len;
pid_t 1_pid;
} ;
Az l_type paramter a zrols tpusa, a 4.13. tblzat ltal sszefoglalt rt-
kek valamelyike lehet.
4.13. tblzat. A flock struktra l_type mezjnek lehetsges rtkei
Opci Jelents
F_RDLCK olvassi zrols
F_WRLCK rsi zrols
F_UNLCK a zrols eltvoltsa
A kvetkez kt paramter (l_whence s l_start) a rgi kezdett tartalmazza
hasonlkppen, ahogy a seek() fggvnynl lttuk. Az l_len paramter a lefog-
lalt terlet nagysga byte-okban. Ha az rtke 0, akkor az llomny vgig
tart a zrols. Az utols l_pid paramter csak a lekrdezsnl hasznlatos, s
a lekrdezett processz azonostjt tartalmazza.
Az fenti() parancsok (cmd argumentum) kzl a 4.14. tblzatban ssze-
foglalt hrom hasznlatos az llomnyok zrolsra.
4.14. tblzat. Az fenti zrolssal kapcsolatos parancsai
Opci Jelents
Belltja a harmadik argumentumnak megadott zrolst. Ha ez
F_SETLK konfliktusban van ms processz zrolsval, akkor EAGAIN
hibartkkel tr vissza.
F_SETLKW
Hasonl, mint az elz, m blokkolja a processzt, amg a zrols
nem hajthat vgre.
F GETLK Ellenrzi, hogy a zrols vgrehajthat-e.
A rek ordz rol shaszn lat ran zznk egy p ld t:
/*recordlock .c-Egy szerupeldaarecordlock hasznalatara.*/
#include<stdio.h>
#include<unistd.h>
#include<fcntl.h>
#include<errno.h>
146
4.9. llomnyzrols
/*megj elen tiazuzenetet,esv arazenterbillenty u
leny omasara.*/
v oidwaitforuser(char*uzenet)
printf("%s",uzenet);
fflush(stdout);
getchar();
printf("\n");
/*megszerziazadotttipusulock otazallomany ra. At pus
ertek eiazalabbiak lehetnek : F_RDLCK,F_WRLCK, v agy F_UNLCK*/
v oidgetlock (intfd,intty pe)
structflock lock info;
charuzenet[12 8];
/*Azegeszallomany tlock olj uk .*/
lock info.l_whence=SEEK_SET;
lock info.l_start=0;
lock info.l_len=0;
/Addigprobalj uk ,amigsik erul.*/
while(1)
f
lock info.l_ty pe=ty pe;
/*Hasik erultmegszerezni,ak k orv isszaterunk .*/
f(fcntl(fd, F_SETLK, &lock info).=0)return;
/*megnezzuk k itartj amaganal.*/
fcntl(fd, F_GETLK, &lock info);
/*v anraegy k isesely ,hogy azallitasesazolv asas
k ozottalock felszabadul. Ezert lev izsgalj uk eztaz
esetet.*/
if(lock info.l_ty pe!=F_UNLCK)
sprintf(uzenet,"Konflik tusv ana%dprocesszel..."
"Ny omj entert!",lock info.l_pid);
waitforuser(uzenet);
}
intmain(v oid)
intfd;
/*tetrehozunk egy lock olandoallomany t.*/
fd=open("testlock f le", O_RDWRIO_CREAT, 0666);
147
4. fejezet: llomny-s I/Okezels
if(fd<0)
perror("open");
return1;
printf("olv asasralock olj uk .\n");
getlock (fd, F_RDLCK) ;
printf("Alock olassik eres.\n");
waitforuser("\nNy omj entertafoly tatashoz!");
printf("Elengedj uk alock ot.\n");
getlock (fd,F_LiNtck );
printf("irasralock olj uk \n");
getlock (fd,F_WRLCK);
printf("Alock -olassik eres.\n");
waitforuser("\nNy omj entertak ilepeshez!");
/*Azallomany lezarasak oralock isfelszabadul.
close(fd);
return0;
}
4.9.3. Ktelez zrols
Az eddig trgyalt metdusok tjkoztat zrolst valstottak meg. Hasznla-
tukhoz a programjainkban implementlnunk kell a zrols kezelst, az ope-
rcis rendszer ugyanis nem gondoskodik a kezelsrl automatikusan.
Ezzel szemben a ktelez zrols esetben a kernel gondoskodik az l-
lomnyok zrolsnak kezelsrl, gy garantlja azt, hogy a processzek csak
megfelelen szablyozva frhessenek hozz.
Linux alatt a ktelez zrols hasznlathoz kt lpst kell tennnk. El-
szr az adott llomnyrendszer felcsatolsakor a mount parancsnak opcikkal
meg kell adnunk, hogy engedlyezzk (mand opci) vagy tiltjuk (nomand op-
ci) a ktelez zrolst. Alaprtelmezett esetben a rendszer tiltja a zrols
hasznlatt. Ennek az az oka, hogy csak szksg esetn s akkor is inkbb a
loklis llomnyrendszerekre kapcsoljuk be, mert hlzaton megosztott llo-
mnyok kezelsekor teljestmnyproblmkat okozhat.
Msodik lpsknt meg kell jellnnk azokat az llomnyokat, amelyekre
a ktelez zrolst hasznlni szeretnnk. Egy llomnyt gy tehetnk zrol-
hatv, hogy az llomny jogosultsgainak egy specilis, normlis esetben
nem elfordul kombincijt alkalmazzuk: a setgid bitet be kell kapcsol-
148
4.10. Kapcsolat a magas szint llomnykezelssel
nunk, ugyanakkor a csoport futtatsi jogt el kell vennnk (chmod). Ezek
utn ugyangy hasznljuk a zrolst, mint az elz pldban, a klnbsg
annyi, hogy ezttal a kernel ktelezen betartatja a zrolst.
Minderre kln figyeljnk oda, mert ekkor mg a root felhasznl sem
frhet hozz a zrolt llomnyhoz. Az egyetlen megolds ez esetben, hogy t-
rljk a setgid bitet. A knyv rsakor a Linux alatt a ktelez zrols nem
tekinthet stabilnak, versenyhelyzetek alakulhatnak ki. Remlhetleg min-
dez hamarosan megvltozik.
4.10. Kapcsolat a magas szint
llomnykezelssel
A C nyelvet jl ismerknek sszefoglaljuk a magas szint llomnykezelsi
koncepcik s a fejezetben ismertetett megfelelik kztti kapcsolatot (4.15.
tblzat). A magas szint llomnykezels az alacsony szintre pt, vagyis
minden magas szint ler alatt van egy alacsony szint (amelyet a fileno
fggvnnyel le is krdezhetnk). A magas szint llomnykezels rtege buffe-
reli az adatokat, ezt a buffert a da t folya mna k (stream) nevezzk.
4 .15. tblzat. A magas s alacsony szint llomnykezels sszehasonltsa
Koncepci Magas szint Alacsony szint
llomnyler tpusa F1LE* struktramutat int
Szabvnyos stdin, stdout, stderr STDIN_FILENO (0)
llomnylerk STDOUT_FILENO (1)
STDERR_FILENO (2 )
Megnyits fopen open
Lezrs fclose, fcloseall close
rs fwrite, fputs, fputc, fprintf write, writev, pwrite
Olvass fread, fgets, fgetc, fscanf read, readv, pread
tirnyts freopen dup, dup2
llomny llapota terror fggvny errno vltoz
Magas szint lerbl fileno
alacsony szint
Alacsony szint lerbl fdopen
magas szint
Pozicionls fseek, fsetpos, ftell, fgetpos lseek
Zrols flockfile, funlockfile, flock, lockf, fcntl
ftrylockfik
Bufferek rtse fflush fsync
149
4. fejezet: llomny- s I/O kezels
Az adatfolyamokkal kapcsolatos fggvnyeknek (ungetc, clearerr, feof, setvbuff)
nincs alacsony szint megfelelje. St szigoran vve az fflush nem megfelelje
az fsync-nek, hiszen elbbi az adatfolyamot rti ki, a msik pedig az alacsony
szint buffereket s gyorsttrakat. Ezrt, ha azt szeretnnk elrni, hogy az
adat kirdjon a merevlemezre, mindkt fggvnyt meg kell hvnunk az
fflush-t a magas szint, az fsync-et az alacsony szint lerra.
tmutat Lehetleg ne keverjk az alacsony szint s magas szint mveleteket. Ha valami-
rt nem ezt nem tudjuk elkerlni, a magas szint mvelet utn mindig hvjuk meg az fflush
fggvnyt.
4.11. Soros kommunikci
Mivel soros kommunikci a begyazott rendszerek miatt mg ma is nagy je-
lentsg, ezrt ebben a fejezetben rszletezzk a hasznlatt. A korbbiak-
ban mr megismerhettk az ltalnos llomnykezelsi mdszereket. Ezek a
mdszerek, belertve a multiplexelt kommunikcit, ltalnosan hasznlha-
tk minden fjltpusra, gy a soros kommunikcira is. Mindssze arrl van
sz, hogy ennek az eszkznek tovbbi, csak r jellemz belltsai vannak,
amelyeket nem ltalnos llomnykezelsi fggvnyekkel kell kezelnnk.
Ebben a fejezetben ezeket a fggvnyeket ismertetjk.
A /dev/ttyS* eszkzinterfszek elssorban a Unix-gphez kapcsolhat
soros terminlok hasznlatra lettek kifejlesztve. Jllehet a modemes betr-
cszs mr j ideje nem tl gyakori, a programozsi felleten mg mindig
keveredik a kt funkci. Ezrt hasznlatukhoz a POSIX termios interfszen
keresztl be kell lltanunk a paramtereit.
A termios struktra deklarcija az albbi:
struct termios
tcfl ag_t c_i fl ag ;
tc f 1 ag_t c_ofl ag ;
tcfl ag_t c_cfl ag;
tcfl ag_t c_l fl ag;
cc_t c_cc [NCCS] ;
;
/* bemeneti mod beallitasai */
/* kimeneti mod beallitasai */
/* kontrollbeallitasok */
/* lokalis mod beallitasa */
/* kontrollkarakterek */
MM'
A soros portok kezelsre tbb megkzelts is ltezik, az adott alkalmazstl
fggen kell kivlasztani ezek kzl a legmegfelelbbet. A tovbbiakban eze-
ket a megkzeltseket tekintjk t.
150
4.11.Soros kommunikci
4.11.1. Kanonikus feldolgozs
A kanonikus feldolgozs soronknt kezeli a szveget. Ez a terminlok
norml kezelsi metdusa, de hasznos lehet ms soralap kommunikcira
is. A soros kmmunikcival elrhet terminlkezelshez az albbi hrom r-
tegre volt szksg:
magt a soros hardvert kezel rteg;
specilis karaktereket, terminlparancsokat rtelmez rteg;
az llomnyabsztrakcis interfsz megvalstsa.
Ezek a rtegek az eszkzmeghajtban vannak implementlva. Az els rteg a
hardverklnbsgeket rejti el. A terminlnak rtelmeznie is kell a karaktere-
ket, pldul a Ctrl + C rkezst megszaktsknt kell kezelni, a trls ka-
raktereket nem megjelenteni kell, hanem rvnytelenteni a trlt karakte-
reket, illetve a sorvge karaktereket is specilisan kell kezelni. Ezt a msodik
rteg, a vonalrend (line discipline) kezeli, amely a terminl belltott rtel-
mezsei alapjn manipullja az adatfolyamot. A fels rteg szolgltatsait
mr jl ismerjk Amikor terminltl fggetlenl, kanonikus feldolgozssal
szeretnnk soros kommunikcit programozni, az a clunk, hogy a vonalrend
belltsait gy mdostsuk, hogy egyltaln ne vltoztassa az elkldtt ada-
tokat. A fejezetben bemutatott belltsok j rsze ezt a clt szolglja.
Kanonikus feldolgozs esetn a read0 fggvny egsz sorokat olvas be.
A vonalrend szellemben a sorok vgt az ASCII kd LF, EOF vagy EOL ka-
rakter jelenti. A CR karakter nem zrja a sort. A kanonikus hozzfrs kezel
ms terminlkezel specilis karaktereket s: erase, delete, reprint stb.
Nzzk meg a kzismert Serial Programming HOWTO [18] pldjt a
kanonikus soros port kezelsre:
seriall.c - Kanonikus soros port kezelese. * /
#include<sy s/ty pes.h>
finclude<sy s/stat.h>
#include<fcntl.h>
#include<termios.h>
#include<stdio.h>
#include<stdlib.h>
#include<unistd.h>
#include<str ng.h>
#defineBAUDRATE83 8400
/*Azertek etahasznaitsorosporteszk ozallomany arak ell
modositani.*/
#defineMODEMDEVICE"/dev /tty 51"
151
4. fejezet: llomny- s I/O kezels
#defineFALSE0
#defineTRUE1
v olatileintSTOP =FALSE;
main
{
intfd,c,res;
structtermiosoldtio,newtio;
charbuf[2 55];
/*Megny itj uk amodemetolv asasraesirasra.Atty k ontrollt
k ik apcsolj uk ,hogy aCTRL-Ck arak terreneszak adj onmega
programfutasa.*/
fd=open(MODEMDEVICE,O_RDwR1O_NOcIlY);
if(fd<0){ perror(MODEMDEVICE);exit(-1);}
/*Elmentj uk asorosportak tualisbeallitasait.*/
tcgetattr(fd,&oldtio);
/*Inicializalj uk astruk turatazuj beallitasok hoz.*/
bzero(&newtio,sizeof(newtio));
/*
BAUDRATE:asorosportsebessege
CRTSCTS:aporthardv eratv itelszabaly ozasa
CS8 :8n1(8bit,nincsparitas,1stopbit)
CLOCAL:lok alisk apcsolat,nincsenek modemj elek
CREAD :ak arak terek fogadasanak bek apcsolasa
*/
newtio.c_cflag=BAUDRATE1CRTSCTSIC581CLOCALICREAD;
/*
IGNP AR:aparitashibasbaj tok atfigy elmenk iv ulhagy j a
ICRNL :aCRk arak tertNIk arak terrek onv ertalj a
*/
newtio.c_iflag= IGNP AR1ICRNL;
/*Ny ersk imenetbeallitasa.*/
newtio.c_oflag=0;
/*Engedely eziak anonik us bemenetet,k ik apcsolj a ak arak ter-
v isszaj elzest,esletiltj aaj elzesek k uldeset.*/
newtio.c_lflag=ICANON;
/*Av ezerlok arak terek inicializalasa.*/
newtio.c_cc[VINTR] =0;/*Ctrl-c*/
newtio.c_cc[VQUIT] =0;/*Ctr1-\*/
newtio.c_cc[VERASE] =0;/*del*/
newtio.c_cc[VKILL] =0;/*@*/
newtio.c_cc[VEOF] =4;/*Ctrl-d*/
152
4.11. Soros kommunikci
newtio.c_cc[VTIME] = 0;
newtio.c_cc[VMIN] = 1;
newtio.c_cc[VSWTC] =0;
newtio.c_cc[vsTART] =0;
newtio.c_cc{VSTOP] =0;
newtio.c_cc[VSuSP] = 0;
newtio.c_cc[VEOL] =0;
newto.c_cc[VREPRINT] = 0;
newtio.c_cc[VoISCARD] =0;
newtio.c_cc[vwERASE] =0;
newtio.c_cc[VLNEXT] =0;
newto.c_cc[VEOL2]
= 0;
/* karakterek kozti idozto */
/* blokkolja az olvasast, amg
nem erkezik egy karakter */
/* '\0' */
/* Ctrl-q*/
/* ctrl-s */
/* ctrl-z */
/* '\0' */
/* Ctrl-r */
/* Ctrl-u */
/* ctrl-w */
/* Ctrl-v */
/* '\0' */
/* Toroljuk a soros port bufferet, es aktivaljuk
a beallitasokat. "/
tcflush(fd. TCIFLUSH) ;
tcsetattr(fd,TCSANOw,&newtio);
/* A beallitasok megvannak, kezeljuk a bemenetet. */
while(STOP==FALSE) /* Akilepesig tart a ciklus. */
{
res =read(fd,buf,255);
buf[res]=0;
printf(":%s:%d\n", buf, res);
i f(buf[0] =='z') STOP=TRuE;
}
/* Visszaallitjuk a regi portbeallitasokat. */
tcsetattr(fd,TcsANow,&oldto);
return 0;
}
Ahogy lthat, a soros port kezelsnl is a szoksos llomnykezelsi fgg-
vnyeket hasznltuk, mindssze kiegsztettk ket a terminlparamterek
belltsaival.
Ahhoz, hogy a programunk lefutsa utn a soros port belltsai meg-
egyezzenek az indts eltti rtkekkel, els lpsknt el kell trolnunk a rgi
belltsokat. Ezt kveten a termios struktrban sszelltjuk azt a bell-
tst, amelyre szksgnk van. Megadjuk a port sebessgt (baudrate), a
hardvertvitel szablyozst (RTSCTS), a bitek (stopbit, paritsbit) bellt-
sait. Ezek utn a CLOCAL opcival megadjuk azt, hogy csak egy soros kbel-
lel ktttk ssze a kt szmtgpet, ezrt nincs szksg a modemvezrl
jelek hasznlatra.
Ezutn belltjuk, hogy kanonikus tvitelt szeretnnk, tovbb iniciali-
zljuk a vezrlkarakterek kezelsnek a belltsait. Itt a szoksos vezrl-
karakterek mellett szerepel mg a VTIME s a VMIN rtk is (ezeket lsd a
kvetkez fejezetben).
153
4. fejezet: llomny- s I/O kezels
A termios struktra sszelltsa utn trljk a soros port buffereit, s
rvnyestjk az j belltsokat.
Ezutn a program a soros porton rkez csomagokat folyamatosan olvas-
sa s megjelenti, egszen addig, amg egy sor eleji z" karakterrel meg nem
lltjuk. Ezt kveten visszalltja a port rgi belltsait, s vget r.
4.11.2. Nem kanonikus feldolgozs
Nem kanonikus feldolgozskor nem sorokat, hanem egy meghatrozott meny-
nyisg karaktert olvasunk be. Ez az zemmd nem hasznl vonalrendet, gy
a specilis karaktereknek nincs szerepk, s nem trtnik meg a feldolgoz-
suk. Hasznlata akkor javasolt, ha mindig egy fix szm karaktert vrunk a
soros vonalon, vagy nyers byte-alap kommunikcit szeretnnk folytatni. Ez
utbbi esetben a timeoutot is bellthatjuk, hogy felkszljnk arra, ha sok-
ig nem jn adat.
Kt paramter szablyozza a rendszer viselkedst ebben a mdban: a
e_ce[VTIME] a karaktertemezt lltja be, a e_cc[17MINJ a karakterek mini-
mlis szmt.
Ha a MIN > 0 s a TIME = 0, akkor csak a MIN paramtert hasznljuk,
amellyel a beolvasand karakterek szmt definiljuk.
Ha MIN = 0 s a TIME > 0, akkor a TIME meghatrozza a timeout rt-
ket (tizedmsodpercben). Ilyenkor vagy beolvas egy karaktert, vagy a meg-
adott id mlva a readQ karakter nlkl visszatr.
Ha MIN > 0 s a TIME > 0, akkor a read0 visszatr, ha a MIN mennyis-
g karaktert beolvasta, vagy a kt karakterolvass kztt az id tllpte a
megadott rtket.
Ha MIN = 0 s a TIME = 0, akkor a read0 azonnal visszatr.
Az elz plda mdostva a kvetkez:
/*serial2 .c-Nemk anon k ussorosportk ezeles.*/
#include<sy s/ty pes.h>
#include<sy s/stat.h>
#include<fcntl.h>
#include<termios.h>
#include<std o.h>
#include<stdlib.h>
# nclude<unistd.h>
#include<string.h>
#defineBAUDRATE 53 8400
#defineMODEMDEVICE "/dey /tty 51"
#define FALSE 0
#defineTRUE 1
_ sfflinimimmo
154
v olatileintSTOP =FALSE;
main()
intfd,c,res;
structtermiosoldtio,newtio;
charbuf[2 55];
fd =open(MODEMDEVICE,O_RDWR I O_NOCTTY);
if(fd<0){ perror(MODEMDEVICE);exit(-1);}
tcgetattr(fd,&oldtio);
bzero(&newtio,sizeof(newt o));
newtio.c_cflag=BAUDRATE I CRTSCTS 1 C58 1 CLOCAL I CREAD;
newtio.c_iflag=IGNP AR;
newtio.c_oflag=0;
/*Azinputbeallitasnemk anonik us,esav isszej elzestis
k ik apcsolj uk .*/
newtio.c_iflag=0;
/*Ak arak terek k oztiidozitotnemhasznalj uk .*/
newtio.c_cc[v TimE]=0;
/*Azolv asasblok k olodik ,amig5k arak tererk ezik .*/
newtio.c_cc[VMIN]=S;
tcflush(fd,TCIFLUSH);
tcsetattr(fd,TCSANOw,&newtio);
while(STOP FALS)
{
/*5k arak terbeolv asasautanv isszater.*/
res=read(fd,buf,2 55);
buf[res]=0;
printf(":%s:%d\n",buf,res);
if(buf[0]=='z')STOP =TRUE;
tcsetattr(fd,TCsANow.&oldtio);
return0;
4.11. Soros kommunikci
Az elbb emltett kt mdszer a fent bemutatott blokkol metdus mellett
nem blokkold mdon is hasznlhat. A nem blokkold zemmdot a mr
trgyaltaknak megfelelen az open fggvny segtsgvel llthatjuk be.
Az eddig ismertetett multiplexel fggvnyeket itt is ugyangy alkalmazhat-
juk, mint eddig.
155
4, fejezet: llomny- s I/O kezels
A soros kommunikci azonban nem csak a multiplexel fggvnyeken
keresztl tud visszajelezni. Lehetsgnk van egy gynevezett a szinkr on
(asynchronous) zemmd belltsra is, amely azt eredmnyezi, hogy az r-
tests egy SIGIO jelzsen keresztl rkezik. (A jelzseket az 5.6. Jelzsek
alfejezetben trgyaljuk.) Az aszinkron zemmdot az albbiak szerint llt-
hatjuk be (fd a soros port llomnylerja):
for t fd,
F_SETrL. MilgOr04:_
Mivel ez a hvs azt eredmnyezi, hogy a soros porttal kapcsolatos rtestsek
egy jelzst vltanak ki, eltte be kell regisztrlnunk a jelzs kezelfggv-
nyt. Mivel a jelzsben nem olvashatunk llomnyokat, ezrt a jelzs csak t-
llt egy olyan vltozt, amelyre a fprogramban vrakozunk. Ennl brmely
multiplexel megolds hasznlata elegnsabbnak tekinthet.
156
TDIK FEJEZET
Prhuzamos programozs
5.1. Processzek
A prhuzamos vgrehajtst a Linux a Unixtl rklt processzabsztrakcival
oldja meg. A vgrehajts alatt ll programot, annak krnyezett s a hozz-
tartoz erforrsokat processznek vagy folyamatnak nevezzk. A processz
szmra a kernel egy virtulis krnyezetet biztost: a processz gy ltja, hogy
a processzoron egyedl fut, s az sszes memrival rendelkezik. A Linux-
kernel adatstruktrkat biztost ezen virtulis krnyezet szmra, amely t-
rolja a processz sszes jellemzjt. gy a kernel kpes arra, hogy a processzek
llapott elmentve, vltakozva futtassa, vagyis temezze ket.
A processzek nem fggetlenek egymstl, hierarchiba rendezhetk.
Minden processzt (kivve a legelst, az gynevezett intet) egy msik processz
hoz ltre. A ltrehoz folyamatot szlprocessznek (parent process), a ltre-
hozott folyamatot gyermekprocessznek (child process) nevezzk. Az nit
processzt kivve minden folyamatnak van szlje. Ha egy szlfolyamat elbb
sznik meg, mint a gyermekek, a gyermekfolyamatok rvkk (orphan) vl-
nak, s szljk automatkusan az nit processz lesz.
A POSIX opercis rendszerekben az j processz ltrehozsa s a futtat-
hat kd betltse kt kln lps. Az els funkcit a fork fggvny valstja
meg, a msikat az exec fggvnycsald.
itinclude
oieLt fOr K4 104 ,
Lnyegben a fork fggvny lemsolja a fut processzt a memriban. Ekkor
a forkot hv szlfolyamat mellett egy j PID-del rendelkez gyermekfo-
lyamat keletkezik. A msols utn a vezrls a fork visszatrsvel folytat-
dik, az egyik fut pldny, a gyermekprocessz szmra nullval, a msik, a
szlprocessz szmra a gyermek azonostjval tr vissza. A fork a szlfo-
lyamathoz a gyermekprocessz azonostjval (PID), mg a gyermekhez 0 r-
tkkel tr vissza. Hiba esetn a fork() visszatrsi rtke 1 (termszetesen a
szl fel, hiszen a gyermekfolyamat ltre sem jtt), s az errno vltoz tar-
talmazza a hiba okt.
5. fejezet: Prhuzamos programozs
Processz megszntetse a
#include<sy s/ty pes.h>
#include<signal.h>
k ill(processzazonosit,SIGINT);
fggvnnyel lehetsges, amelyet a jelzskezelsnl rszleteznk. Elljrban
annyit, hogy ezt az zenetet a privilegizlt esetektl (pl. root jogosultsgok)
eltekintve csak az egyazon felhasznlhoz tartoz processzek kldhetik egy-
msnak.
Az albbi program szemllteti a fork() hasznlatt:
/*fork l.c- P eldaafork ()hasznalatara.
*/
#include<stdio.h>
40"
410
#include<stdlib.h>
I.
-
-Is.

#include<unistd.h>
41
.
0111__ _
intmain()
~I
{
intpid;
printf("Aprograminditasa...\n\n");
pid=fork ();
if(pid<O)
printf("fork ()hiba.\n\n");
exit(-1);
}
if(pid==0)
.
1
11~ffir ~I.
-4
.
/* A gy ermek processz-pid0*/
printf("Gy ermek processz.P ID:%d"
"fork ()v isszateresiertek :%d\n",getpid(),
pid);
else
/*Aszuloprocessz-apidv altozoagy ermek processz
azonositoj a.*/
printf("Szuloprocessz.P ID:%d"
"fork ()v isszateresiertek :%d\n",getpid(),pid);
return0;
158
atetesi% e rtek: 844
teresi
,
rtak
.O
5.1. Processzek
Ennek a programnak a kimenete a kvetkez:
Lthat, hogy a szl processzazonostja 384 3, a gyermek 384 4 . A szlpro-
cessz a fork() visszatrsi rtkbl rtesl gyermeke azonosti rl. Egy pro-
cessz sajt processzazonostjt az <unistd.h> fjlban deklarlt
pi cLt getpid(
fggvnnyel, a szl azonostjt a
Mt . 000004
fggvnnyel krdezhetjk le. Ezeket a fggvnyeket a fenti programrszlet-
ben is felhasznltuk.
Gyermekprocesszek vgre vrakozni s llapotukat ellenrizni az albbi
kt fggvnnyel tudunk:
# zprlii4te <s/tere
# 1 1 1 40'W.ViY$AYS
"Wt4f i~t
i
t
pi
waltPid(pi int *suttus, fint options);
A wait0 fggvny akkor tr vissza, ha a hvprocessz gyermekprocesszei k-
zl brmelyik befejezte a mkdst. A status paramter 1, ha hiba lpett
fel, egybknt egy bitsorozat, amelyet az 5.1. tblzatban tallhat makrk
segtenek kirtkelni.
5.1. tblzat. A wait fggvny kirtkelshez hasznlhat makrk
rtik
WIFEXITED Ha nem nulla, a processz futsa rendben vget rt.
WEXITSTATUS A visszatrsi rtk (amelyet az exit vagy a legutols return visz-
szaadott) als 8 bitje.
WIFSIGNALED Nem nulla, ha a processz kezeletlen jelzs miatt lpett ki.
WTERMSIG Ha nem nulla, akkor a processz kilpst okoz jelzs szma.
WCOREDUMP Linux-specifikus: nem nulla, ha a processz core dump llomnyt ho-
zott ltre. Csak akkor rvnyes, ha a WIFSIGNALED nem nulla
WIFSTOPPED Nem nulla, ha a processz felfggesztett (STOPPED) llapotban
van.
159
5. fejezet: Prhuzamos programozs
rtk Lers
WSTOPSIG Ha nem nulla, akkor a jelzs szma, amely a processzt felfg-
gesztett llapotba vitte. Csak akkor rvnyes, ha a
WIFSTOPPED nem nulla.
WIFCONTINUED A processz elhagyta a felfggesztett llapotot.
A waitpid fggvny sokkal flexibilisebb: itt a pid paramterrel egy meghat-
rozott processzazonostj gyermek kilpsre vrakozhatunk, az utols pa-
ramterrel megadhat opciktl fggen, amelyek kzl a lnyegesebbeket az
5.2. tblzat foglalja ssze.
5.2. tblzat. A waitpid pid paramternek rtkei
rtk Lers
< Vrakozik brmelyik gyermekprocessz vgre, amelynek cso-
portazonostja megegyezik a pid paramterben adottal.
Ekkor a fggvny hatsa megegyezik a wait fggvnyvel.
0 Vrakozik brmelyik gyermekprocessz vgre, amelynek cso-
portazonostja megegyezik a hvfolyamatval.
> 0 Vrakozik brmelyik gyermekprocessz vgre, amelynek folya-
matazonostja megegyezik a pid paramterben adottal.
5.3. tblzat. A waitpid opcii
rtk Lers
WNOHANG Rgtn (vrakozs nlkl) visszatr, ha mg egy gyermekpro-
cessz sem rt vget. Ezt a konstanst VAGY kapcsolatba kell
hozni a fenti hrom lehetsg alapjn vlasztott rtkkel. gy
lehet idnknt rnzni" a gyermekekre.
WCONTINUED Ha a processz kilp a felfggesztett llapotbl, akkor is vissza-
tr, nemcsak a gyermekprocessz vgnek esetben.
A nem POSIX wait3 s wait4 fggvnyek nagyon hasonltanak a waitpid
fggvnyhez, de sokal tbb hasznlati statisztikt adnak vissza a gyermek-
processzrl.
Ha a vrakozs idpontjban a gyermekprocessz mr kilpett, a wait
fggvnyek mg mindig vissza tudjk adni a gyermekprocessz visszatrsi r-
tkt. Ez gy lehetsges, hogy a gyermekprocessz kilpse utn nem az sszes
hozztartoz erforrs szabadul fel: nhny adatstruktra megmarad.
Az ilyen llapot processzt zombinak (zombie) nevezzk, mert mr nem l,
de mg nem is halott. A zombillapot addig tart, amg a szl nem vrakozik
a processzre. Ha a hvs idpontjban egy gyermekprocessz mr zombilla-
potban van, akkor a wait fggvnyek azonnal visszatrnek. Mivel a zombipro-
cesszek erforrst foglalnak, fontos, hogy a szlprocesszben vrakozzunk
160
5.1. Processzek
rjuk. Ha a szl nem engedheti meg magnak a vrakozst, a SIGCHLD jel-
zst is felhasznlhatja, amely a gyermekfolyamat kilpst jelzi. Ha a szl
elbb hal meg, az nit vlik az j szlv, amely periodikusan vr a gyermek
processzeire, gy rvid szlprocessz esetn nem kell aggdnunk, hogy zombik
foglaljk a rendszer erforrsait. Azt is megakadlyozhatjuk, hogy a processz
zombiv alakuljon: ehhez a SIGCHLD jelzs SA_NOCLDWAIT jelzbitjt bel-
ltjuk, vagy a kezelfggvnyt SIG_IGN-ra lltjuk. Ilyenkor a wait fggv-
nyek vrakoznak ugyan a processz vgre, de hibval trnek vissza (ECHILD),
s a sttusz nem rvnyes.
A kvetkez programrszletben ltalnos smt adunk arra, hogyan hoz-
zunk ltre elgazst:
/* fork2.c - Pelda a fork() hasznalatara. */
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
int child_function();
int parent_function(int child_id);
int child_function()
printf("Gyermek processz. PI D: %d\n",getpid());
printf("szulo PID: %d\n\n",getppid());
exit(0);
int parent_function(int child_id)
printf("szulo processz. PI D: %d\n",getpid());
printf("Gyermek ID: %d\n\n",child_id);
exit(0);
}
int main()
nt pid, status;
printf("A program inditasa...\fl\n");
pid-fork();
i f(pid<O)
printf("fork() hiba.\n\n");
exit(-1);
}
161
A programinditasa...
Szula processz. PID: 3690
Gy ermek processz. PID: 3691
szulo PID: 3690
5. fejezet: Prhuzamos programozs
f(pid==0)
{
/*Agy ermek processz-pid0*/
chi1d_functionC);
else
{
/*Aszuloprocessz-apidv altozoagy ermek processz-
azonositoj a.*/
parent_function(pid);
/*v arak ozasagy ermek processzv egere*/
wait(&status);
return0;
A fenti program egyes fggvnyei (parent junction, child junction) tudnak az
identitsukrl (a szl tudja magrl, hogy szl, a gyermek tudja magrl,
hogy gyermek), illetve egyms processzazonostjt is szmon tartjk. A kil-
pshez az albbi fggvnyt hasznljuk:
. vold eXitOm xtaws
Ennek a fggvnynek a status paramtere a processz kilpsi kdja (exit code).
A konvenci szerint a 0 hibtlan mkdst jelent, minden ms visszatrsi
rtk a hiba kdjt jelenti.
A fenti program kimenete az albbi lehet:
Gy ermek io: 3691
Jl lthat, hogy a processzek tnyleg prhuzamosan, egymst vltva futnak.
Ha azt szeretnnk, hogy a kt prhuzamosan fut kd ugyanabbl a futtatha-
t llomnybl szrmazzon, ezzel kszen is vagyunk. Viszont ha egy msik
programot szeretnnk elindtani, akkor ez mg csak az els lps. A kvetke-
z lps pedig a gyermekfolyamat kdjnak kicserlse az jonnan betlttt
programkddal. Ilyenkor a processz azonostja a rgi marad, de ezt teljesen
fellrja a betlttt program, s annak main fggvnytl folytatdik a futta-
ts. Mindezt a npes exec fggvnycsald valstja meg:
162
5.1.P rocesszek
#include<unistd.h>
intexecv e(constchar*filename,char*constargv [],
char*constenv p[]);
Ez a fggvny a hv processzbe betlti a megadott program kdjt, amely az
els paramterben megadott elrsi tvonalon tallhat. Az argv egy NULL
terminl sztringekre mutat pointertmbje, amelyet egy NULL pointernek
kell zrnia. Ezeket kapja meg az adott program parancssori paramterknt.
Hagyomnyosan ennek 0 index eleme a program elrsi tvonalt tartal-
mazza, teljes vagy relatv formban. Hasonlan az envp a krnyezeti vltoz-
kat trolja a vltoznv=rtk formtumban. Itt is gyeljnk arra, hogy az
utols pointer NULL legyen.
Az execve sikeres vgrehajts esetn nem tr vissza, az j program fut.
A processz bels tulajdonsgai megvltoznak, hiszen ms van a memriban,
ms kd fut, a knyvtrak (kztk a libc is) jratltdtt. Ezrt a libc-ben be-
regisztrlt visszahvhat fggvnyek, belltsok, a szlak belltsai, a jelz-
sek s azok belltsai, klnbz zrolsok mind elvesznek. A processzek
alaptulajdonsgai, amelyek fggetlenek a futtatott kdtl, ilyen pldul a
processzazonost, a jogosultsgok, a priorits, a tulajdonos, ugyanazok ma-
radnak. Az sszes le nem zrt fjl lerja ugyancsak rkldik, kivve, ha
msknt adtuk meg az fenti fggvny az FD_CLOEXEC jelzbitjvel.
Nzzk meg a fggvnycsald tbbi tagjt, ezek deklarcii a kvetkezk:
#include<unistdh>
externchar**env iron;
intexecl(constchar*path,constchar*arg, ..);
intexeclp(constchar*file,constchar*arg,...);
intexecle(constchar*path,constchar*arg,
constchar*env p[]);
intexecv (constchar*path,char*constargv []);
intexecv p(constchar char*constargv []);
A fggvnyek nevben az exec az execute (futtasd") szra utal. A v azt jelenti,
hogy az indtand program argumentumlistjt a fggvnynek vektor formj-
ban kell tadni, mg az 1 azt jelenti, hogy listaknt, vagyis az argumentumlista
rszeknt. Mindkt esetben az utols argumentumknt NULL-t kell tad-
nunk. Ugyangy kell elksztennk a krnyezeti vltozk tmbjt, amelyet az
e rvidt (environment variables"). A p azt jelenti, hogy a fggvny a hv
program PATH krnyezeti vltozjt is felhasznlja az indtand program
megkeresshez. Ilyenkor csak az llomnynevet adjuk meg els paramter-
knt, ha az tartalmaz T' karaktert, akkor a fggvny csak pontos egyezs
esetn futtatja az llomnyt, nem keresi a krnyezeti vltozban. Ha a PATH
res, akkor ezek a fggvnyek elszr az aktulis knyvtrban keresik az l-
lomnyt, majd a confstr ltal visszaadott knyvtrban.
163
5. fejezet: Prhuzamos programozs
Az execop szmra pldul a tmbt vektor formjban kell megadni, s
elg, ha a program benne van a PATH-ban:
const char * const args[] =
{ "kdevelop", "/hom e/tiham er/exec. c", NULL };
int result;
result = execvp("kdevelop", args);
Az execlp listaknt vrja az indtand program argumentumait:
int result;
result = execlp("kdevelop",
"kdevelop", "/hom e/tiham er/exec. c", NULL);
Ha a fork lemsolja a folyamatot az egsz memriatartomnyval egytt,
majd utna fellrjuk valamelyik exec fggvnnyel, akkor a msols felesle-
ges volt. Ezt a Linux a msols rskor (copy-on-write) technikval oldja meg
(lsd a 2.3.4. Processzek ltrehozsa s terminlsa alfejezetben). Ez rviden
sszefoglalva azt jelenti, hogy a kernel nem msolja le a memrit addig,
amg rssal meg nem vltoztatjuk. Mivel az exec fggvnyek lecserlik a me-
mrialapok tartalmt, a msols nem trtnik meg, ha a fork utn a gyer-
mekprocesszben nem vltoztattuk meg ket.
j processzt az opercis rendszer parancsrtelmezjn keresztl is in-
dthatunk. Erre a
fggvny ad lehetsget. Ha pldul ki szeretnnk listzni egy knyvtr tar-
talmt, akkor az albbiak szerint tehetjk meg:
#include<stdlib. h>
int m ain()
sy stem ("ls -a");
return 0;
~ 111111~ 1 . 111Ei1~ 11rC
A processzek indts utn konkurensen hajtdnak vgre, ennek kvetkezt-
ben hol egyszerre, hol fizikailag egyms futst megszaktva futnak. Ez a
megllapts jabb krdseket vet fel:
164
5.2. Processzek kztti kommunikci (IPC)
Hogyan lehet kt vagy tbb processz mkdst egymshoz szinkro-
nizlni?
Hogyan tudnak az egymssal prhuzamosan fut processzek kommu-
niklni?
Ezekre a krdsekre vlaszolnak a kvetkez fejezetek.
5.2. Processzek kztti kommunikci (IPC)
A UNIX opercis rendszer csaldjban a processzek kztti kommunikci
(Interprocess Communication) egyik f alappillre a System V IPC, amelyet
az AT&T fejlesztett ki sajt UNIX-verzijhoz. Ezt a tbbi UNIX is tvette, a
POSIX-szabvny rsze lett, s a Linux is megvalstja. A System V IPC-rl
rszletes tmutatst ad az ipc(5) man oldal.
A processzek kztti kommunikci kt legfontosabb eleme a szinkroni-
zci s az adatmegoszts. A magas szint programozsi nyelveken megrt
program nem tartalmaz idztsi informcit, csak sorrendisget: a program-
vezrls meghatrozott sorrendben futtatja le a program utastsait. Ez all
termszetesen kivtel a prhuzamos futtats. Itt a processzek kdjnak egy-
mshoz viszonytott sorrendje ismeretlen, az temezs teljesen az adott kr-
nyezettl (pldul a processzorok szma, opercis rendszer belltsa, I/O
prerifrik sebessge) fgg. Ha a sorrendisget a prhuzamosan futtathat
kdban rvnyesteni akarjuk, a processzek futst szinkronizlnunk kell. Ez
azt jelenti, hogy valamilyen megosztott adat rtke alapjn engedlyeznk
valamilyen adathozzfrst, illetve vrakozunk annak egy adott rtkre.
Ilyenkor nagyon fontos, hogy a megosztott adat rtknek ellenrzse s az
arra val reagls kztt az adat rtkt egy msik processz ne vltoztassa
meg. Ezrt az ellenrzsnek s a reakcinak oszthatatlan (atomi) mveletnek
kell lennie. Ennek megvalstsra a kernel segtsgt kell krnnk. Ebben a
fejezetben olyan egyszer tpus szinkronizcis objektumot ismertetnk,
amely lnyegben int vltoz, ppen az teszi szinronizcis objektumm, hogy
mindegyik hozzfrs atomi mvelet. A msik fontos tnyez az adatmegosz-
ts. Tudjuk, hogy a processzek virtulis memriatartomnya teljesen elkl-
nl. Ezrt a gyors tjrst egyedl a kernel kpes biztostani. Az albbiakban
ismertetjk a szinkronizci s az adatmegoszts lehetsgeit.
A System V IPC programozsa kzben segtsgnkre lehet kt hasznos
segdprogram. Az ipcs program kirja a kernelben lv olyan IPC-objektumo-
kat, amelyekhez a hv processznek olvassi joga van. Az ipcs paramtereit
az 5.4. tblzat foglalja ssze.
165
Semapor'e
k ey semid owner perms ns
0x53 09dbd2 8198553 6schspy
644 1
5. fejezet: Prhuzamos programozs
5.4 . tblzat. A waitpid opcii
ipcs q Csak az zenetsorokat mutatja.
ipcs s Csak a szemaforokat mutatja.
ipcs m Csak az osztott memrit mutatja.
ipcs h Tovbbi segtsg.
Nzznk erre egy pldt:
Fejleszts kzben az is hasznos lehet, ha el tudjuk tvoltani az egyes IPC-
objektumokat a kernelbl. Erre szolgl az
iperm <msg I sem I shnr
segdprogram. Pldul a fent megjelentett szemafort a
iperm ,sem E3,985536
paranccsal szntethetjk meg.
5.2.1. Szemaforok
Gyakori szinkronizcis lehetsg a szemafor (semaphore) hasznlata. A sze-
mafor unsigned int szmllnak tekinthet, amelynek megvltoztatsa oszt-
hatatlan mvelet, vagyis ms szlak s processzek nem tudjk megszaktani
a szemaforhoz ppen hozzfr processzt.
A szemafort egy meghatrozott kezdeti rtkre lltjuk. Valahnyszor
egy processz megszerzi/lefoglalja a szemafort (acquire), annak rtke egy-
gyel cskken. Ha elri a nullt, tbb processz mr nem foglalhatja le. Ameny-
nyiben egy processznek mr nincs tbb szemafor ltal vdend dolga, nveli
eggyel a szemafor rtkt, vagyis elengedi (release) a szemafort.
A fentiekbl addik, hogy a szemafor kezdeti rtke hatrozza meg, hogy
egyszerre hny processz szerezheti meg a szemafort. Ha ez 1, egyszerre csak
egy processz foglalhatja le a szemafort, amely a klcsns kizrst (mutual
exclusion, mutex) jelenti. A szemafor tipikus felhasznlsi terlete egy adott
erforrshoz hozzfr processzek szmnak a maximalizlsa. Ttelezzk
166
5.2 . Processzek kztti kommunikci (IPC)
fel, hogy egy hardvereszkzt maximum t processz tud hatkonyan hasznlni,
klnben lassv vlik, s gyakori lesz a hibs mkds, illetve adatveszts
is trtnhet. A hardvereszkzhz val hozzfrs eltt minden processz meg-
szerzi a szemafort, vagyis eggyel cskkenti az rtkt. Ha mr nem hasznlja a
hardvereszkzt, akkor elengedi a szemafort. Ha t processz mr foglalja a sze-
mafort, akkor az rtke nulla. A hatodik processz vagy vrakozik arra, hogy le-
galbb egy processz elengedje a szemafort, vagy pedig megprblja lefoglalni,
s ha nem sikerl, nem vrakozik tovbb, hanem megprblja ksbb.
Ez az egyszer plda kt dologra irnytja r a figyelmet. Alaprtelme-
zsben a szinkronizci nkntes dolog, a processz felelssge, hogy megsze-
rezze a szemafort az erforrshoz val hozzfrs eltt, s elengedje annak
hasznlata utn. Ha ezt a megbzhatsgot nem felttelezhetjk, az erfor-
rshoz hozzfr fggvnyeket gy kell megterveznnk, hogy az eszkzhz az
azt felhasznl kd ne is tudjon a szemafor lefoglalsa nlkl hozzfrni, il-
letve mindenkppen elengedje.
66
Ez tudatos tervezi erfesztst ignyel.
A msik fontos szrevtel, hogy a processz nem ellenrzi a szemafor rtkt,
majd lefoglalja, hanem megprblja lefoglalni vrakozs nlkl. Ugyanis az
ellenrzsnek s a lefoglalsnak egytt atomi mveletnek kell lennik, ne-
hogy a kt mvelet kztt egy msik processz lefoglalja a szemafort. Ha ez
nem teljesl, az ellenrzs teljesen felesleges, semmilyen kvetkeztetst nem
enged levonni, hiszen a kiolvasst vgz fggvny visszatrse utn mr fut-
hat egy msik processz, s elavultt teheti a kiolvasott rtket. Ezrt kiolva-
ss helyett mindig vrakozs nlkl prblunk foglalni.
Vizsgljuk meg egy pldn keresztl, miknt hasznlhat a szemafor
szinkronizcis clokra.
Feladat Ksztsnk olyan programot, amely egy repltri bejelentkezst szimull. Hozzunk
ltre egy szemafortmbt, ahol a szemafortmb egy lgitrsasgot, az egyes szemaforok pedig
a lgitrsasg pultjait jelentik. Egy program hozza ltre a szemafortmbt, egy msik program
pedig a kvetkezt: menjen oda" az els res pulthoz, s ha minden pult foglalt, lljon be
abba a sorba, ahol legkevesebben vrakoznak. Az utasok nem felttlenl rkezsi sorrendben
kerlnek sorra, mert a tl ksn rkez utasokat a ksbb indulk elreengedhetik.
Megoldsunkban az utasok processzek lesznek, a pultokat szemaforok testestik
meg. A feladat szvege rvilgt a vrakoz folyamatok egy fontos tulajdonsg-
ra: nem biztos, hogy az temez a vrakozs kezdetnek sorrendjben breszti
fel a vrakoz processzeket. A pult olyan erforrs, amelyet egyszerre csak egy
processz hasznlhat, gy a szemaforok kezdeti rtke egy lesz.
66
Erre pldul a C++ automatikusan meghvd fggvnyeit (konstruktor/destruktor)
hasznlhatjuk fel.
167
5. fejezet: Prhuzamos programozs
A System V IPC szemaforjai lnyegben szemafortmbk. Ltrehozsuk a
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/sem.h>
int semget(key_t key, int nsems, int semflg);
fggvnyhvssal trtnhet, ahol az els paramter egy egyedi azonost, az
nsems a ltrehozand szemaforok szma, a semflg a hozzfrsi jogosultsg
belltsra szolgl. Ha a key paramter egy mr ltez szemaforhoz lett hoz-
zrendelve, akkor a semget fggvny a ltez szemafor azonostjt adja visz-
sza, egybknt ltrehoz egy j szemafort, s annak a lerjval tr vissza. gy
mr egy ltez szemaforhoz egy msik processzbl a key paramter segtsg-
vel kapcsoldhatunk hozz. Ha j szemafort szeretnnk ltrehozni, a kulcs-
generlsban segtsgnkre lehet az
# include <sys/types.h>
# nclude <sys/ipc.h>
key_t ftok(const char *pathname, int proj_id);
fggvny, amely a ktelezen ltez fjlra mutat pathname s egy nem nulla
proj_id paramterekbl ltrehoz egy egyedi kulcsot.
Nzznk egy pldt IPC-szemafortmb ltrehozsra:
/* sm.c - Szemafortomb letrehozasa. */
#include <sys/ipc.h>
#include <sys/sem.h>
#include <stdio.h>
int main()
{
int semd;
/* Egyedi kulcsot generalunk a szemaforok szamara. */
key_t key =ftok(".", 's');
i f((semid =semget(key, 5,IP C_CREATIIP C_EXCLI0666))== -1)
{
fprintf(stderr, "A szemafor mar letezik!\n");
exit(1);
printf("A szemafor sikeresen letrejott "
"#%d azonositoval.\n", semid);
return 0;
168
5.2 .P rocesszek k z ttik ommunik ci(IP C)
A fenti programrszletben az IPC_CREAT I IPC_EXCL jelzbitek szorulnak
magyarzatra. A szemafort, ha mg nem ltezik, az IPC_CREAT paramter
ltrehozza. Az IPC_EXCL bitnek csak az IPC_CREAT-tel egytt van rtelme,
ilyenkor, ha a szemafor mr ltezik, akkor a semget fggvny hibval tr visz-
sza. Fordtsuk, futtassuk a programot, majd ellenrizzk a helyes mkdst,
valamint tvoltsuk el a ltrehozott szemafort a kernelbl:
$gccsem,c-osem
S./sem
Aszemaforsik eresenletrej ott#52 42 88azonositov al.
ipcs
- - - SemaphoreArray s
k ey semid owner perms nsems status
0x73 02 ffc7 52 42 88 tihamer 666 5
...
Sipermsem52 42 88
resource(s)deleted
.....eL__
A szemafor trlst termszetesen programbl is vgrehajthatjuk, ha a prog-
ramunkba beszrjuk a kvetkez sort:
semctl(semid. 0,IP C_RMID,0);
Trjnk vissza a pldhoz, s nzzk meg, hogyan hozhatjuk ltre a pultokat
reprezentl szemafortmbt:
k ey _tk ey =ftok (".",'s');
if((*sid=semget(k ey ,members,IP c_cREAT(IP c_ExcLI0666)).--1)
fprintf(stderr, "A legitarsasagmarletezik !\n");
exit(1);
A ltrehozand pultok szmt a members int vltoz trolja. Ha az adott
kulccsal ltrejtt mr szemafor, akkor hibazenetet adunk. Az utasokat szi-
mull programban ppen ellenkez a helyzet: azt vrjuk, hogy a pultokat
mr ltrehoztk, s a program argumentumaknt a kulcsot is tadtk:
k ey =atol(argv [1]);
/*Kapcsolodasazelso programparameteraltalmegadott
szemaforhoz.*/
if((semid=semopen(k ey ))-1)
{
/*Nanincsily enszemafortomb...*/
fprintf(stderr,"Alegitarsasagnemletezik !\n");
return1;
169
IPC_SET
IPC_RM1D
GETALL
GETNCNT
GETPID
GETVAL
GETZCNT
SETALL
SETVAL
Jogosultsg, felhasznl- s csoportazonostk megvltoztatsa.
Szemafortmb megszntetse, felbresztve a vrakoz
processzeket.
A szemafortmb elemeinek rtkt adja vissza.
Egy szemaforra vrakoz processzek szma.
A szemafortmb utols mdostjnak processzazonostjt kr-
dezi le.
Egy szemafor rtkt adja vissza.
Egy szemafor nulla (foglalt) rtkre vrakoz processzek szma.
A szemafortmb sszes elemnek rtkt lltja be.
Egy szemafor rtkt lltja be.
5. fejezet: Prhuzamos programozs
A semca fggvny tbb szemaforvezrl funkcit lt el:
#include <sy s/ty pes.h>
# nclude<sy s/ipc.h>
#include<sy s/sem.h>
int semctl (int semid,
-
int semmim, int cmd, ...);
Az els argumentum a szemafor azonostja, amellyel a semopen fggvny trt
vissza. A semnum argumentum a szemafortmbbl vlaszt ki egy elemet, ez
egy nulla alap index. A semnum s az sszes utna kvetkez argumentum a
cmd rtktl fgg. A lehetsges mveleteket az 5.5. tblzat foglalja ssze.
5.5. tblzat. Szemaformveletek
Mvelet Lers
IPC_STAT Szemaforinformci lekrdezse: olvassi jogosultsg szksges
hozz.
Ahogy sz volt rla, a pultoknl egyszerre csak egy utas tartzkodhat, a sze-
maforokat 1-re inicializljuk, s egyben ki is rjuk a belltott rtket:
semopts.v al= 1;
/*Azosszestagk ezdetiertek enek beallitasaak ezdetiertek re
for(cntr=0;cntr<members;cntr++)
semctl(*sid,cntr, SETVAL, semopts);
printf("%d.szamlaloertek :%d\n",cntr,semgetv al(*s d,cntr));
}
A semgetval fggvny kdja az albbi (a semid a szemafortmb azonostja, a
member az lekrdezend szemafor nulltl kezdd indexe a tmbben):
170
5.2 .P rocesszek k z ttikommunikci (IPC)
/* Lek erdeziaszemaforak tualisertek et*/
intsemgetv al(intsemid,intmember)
intsemv al;
semv al=semctl(semid,member,GETVAL,0);
returnsemv al;
Az albbi fggvny megnzi, hogy tnyleg ltezik-e a szemafortmben egy
adott index tagja:
/"megallap tj a,hogy asemidszemafortombnek letezik -emember
indexutagj a.Haigen,av isszateresiertek 0.*/
intsemismember(intsemid,intmember)

intmembernum;
unionsemunsemopts;
structsemid_dsmy semds;
semopts.buf=Soy semds;
/*szemaforinformaciolek erdezese*/
semctl(semid,O,IP C_STAT,semopts);
11.
/*Aszemafortombtagj ainak szama*/
membernum=semopts.buf->sem_nsems;
if(member<0IImember>(membernum-1))
{
return0;
}
else
return-1;
Egy adott szemaforra vrakoz processzek szmt az albbiak szerint kr-
dezhetjk le:
/*v isszaadj aav arak ozofoly amatok szamat*/
intsemgetwaitingprocs(intsemid.intmember)
{
intsemncnt=semctl(semid,member,GETNCNT,0);
returnsemncnt;
A szemafor ltrehozsa s tulajdonsgainak belltsa utn vizsgljuk meg, ho-
gyan vrakozhatunk egy szemaforra. Ezt az albbi fggvnnyel tehetjk meg:
171
#include<sy s/ty pes.h>
#include<sy s/ipc.h>
#include<sy s/sem.h>
intsemop(intsemid,structsembuf*sops,unsignednsops);
I
if((semop(semid,&sem_acquire,1))-1)
{
}
fprintf(stderr,"muszak ihibaa%d.pultnal.\n",member);
return-2 ;
5. fejezet: Prhuzamos programozs
Az els paramter a megszokott mdon a szemafortmb azonostsra szolgl.
A msodik paramter a sembuf tpus struktrk egy tmbje, amelyek a vg-
rehajtand mveleteket rjk el. A semop fggvny garantlja, hogy ezek k-
zl a mveletek kzl vagy mind, vagy egyik sem lesz vgrehajtva. A sembuf
struktra felptse a kvetkez:
structsembuf
ushort sem_num; /* aszemaforindexeatombben */
short sem_op; /* szemaforertek enek v altozasa*/
short sem_flg; /* amuv eletj elzobitj e */
} ;
A sem_op tagvltoz rtke eljelesen hozzaddik a szemafor rtkhez. Ha
ez az rtk negatv, gy az erforrs foglalsnak felel meg, ha pozitv, akkor
az erforrs elengedst jelenti. Nulla sem_op esetn a processz azt ellenrzi,
hogy a szemafor rtke nulla-e.
A jelzbitek rtke IPC NOWAIT, SEM UNDO, illetve a kett bitenknti
VAGY kapcsolata lehet. Az IPC_NOWAIT esetben a mveletet megksrli
vgrehajtani, ha azonban ez nem sikerl, a semop azonnal hibval tr vissza.
Ha ez a jelzbit nincs belltva, akkor a semop vrakozik a szemafor kedvez l-
lapotra. Ha a sem_op rtke nulla volt, s az IPC NOWAIT nem volt belltva,
akkor a processz vrakozik addig, amg a szemafor rtke nulla nem lesz, va-
gyis akkor tr vissza, amikor az sszes erforrs le van foglalva. A SEM UNDO
jelzbit bekapcsolsakor a mvelet visszavondik, amikor a hv processz vget
r. Ezt akkor hasznlhatjuk, hogyha a program letciklusa sorn lefoglalja a
szemafort, s a kilpsig tartja. gyeljnk arra, hogy ne engedjk el a szema-
fort, mert ez automatikusan megtrtnik, amikor a program kilp.
A semop fggvny utols argumentumaknt a sops tmbben lv sembuf
tpus struktrk szmt adjuk meg. Vrakozssal az albbi mdon tudjuk
eggyel cskkenteni a szemafor rtkt:
structsembufsem_acquire={ member,-1,0} ;/*v arak ozas*/
172
5.2. Processzek kztti kommunikci (IPC)
else
printf("A%d.pultfelszabadult.Azutastk iszolgalj ak .\n",
member);
Ha a szemafor foglalt, s vrakozs helyett rgtn vissza szeretnnk trni,
akkor a sembuf struktra utols tagjt mskpp kell inicializlnunk
-
steur~bitf ~441g:04
1
00~. irl:~
Ha a szemafor mr foglalt, a semop hibval tr vissza, s az EAGAIN rtkre
lltja az errno-t. Ezt termszetesen el kell klntennk a tbbi hibajelzstl:
if((semop(semid,&sem_acguire,1)) -1)
if(errno==EAGAIN)
printf("A%d.pultnemallrendelk ezesre.\n",member);
return1;
else
{
fprintf(stderr,"Muszak ihibaa%d.pultnal.\n",member);
return-2 ;
else
printf("utasa%d.pultnal.\n",member);
A szemafor elengedse csak az inicializls paramterben klnbzik, hi-
szen csak pozitv szmot kell hozzadni a szemafor rtkhez:
structsembufsem_release={ member,1,IP C_NOWAIT} ;
Ezek utn tekintsk t egyben a feladat megoldst. Elsknt a konstansde-
fincikat vesszk sorra:
#defineSEM_MAX_IN_SET3
#defineSEM_RESOURCE_INIT1
Az els konstans a pultok szma, a msik az egy pultnl egyszerre kiszolglt
utasok:
173
5. fejezet: Prhuzamos programozs
ntmain()
{
intsemid;
/*Generatinguniquek ey numberforsemaphore*/
k ey _tk ey =ftok (".",'s');
createsem(&semid,k ey ,sEM_MAX_IN_SET);
printf("Alegitarsasag#%dletrej ott%d""pulttal.\n",
k ey ,SEM_MAX_IN_SET);
printf("Elindultahej elentek ezesiszolgaltatas...\n");
printf("Ny omj <Enter>-tak lepeshez!\n");
getchar();
semctl(semid,0,IP C_RMIO,0);
printf("Alegitarsasag bezart.\n",k ey );
return0;
Jl lthatan a fprogram ltrehozza a szemafort, majd lelltskor eltvoltja
a kernelbl. A createsem fggvny implementcija az albbi:
/*szemafortombletrehozasa*/
v oidcreatesem(int*s d,k ey _tk ey ,intmembers)
intcntr;
unionsemunsemopts;
if(members>SEM_MAX_IN_SET)
{
printf("Alegitarsasagok max malisszama:%d\n",
SEM_MAX_IN_SET);
exit(1);
I
if((*sid=semget(k ey ,members, IP C_CREATIIP C_EXCLI0666))==-1)
fprintf(stderr, "A legitarsasagmarletezik !\n");
exit(1);
I
semopts.v al=SEM_RESOURCE_INIT;
/*Azosszestagk ezdetiertek enek beallitasaak ezdeti
ertek re*/
for(cntr=0;cntr<members;cntr++)
semctl(*sid,cntr. SETVAL, semopts);
printf("%d.szamlaloertek :%d\n",cntr,semgetv al(*sidecntr));
174
5.2. Processzek kztti kommunikci (IPC)
Nzzk az utasokat megvalst programot:
intmain(intargc,char*argv [])
k ey _tk ey ;
i ntsemid;
inti;
intsemncntmin=mAxINT,semncnt;
intsemminmember=0;
intlock ed=-1;
KeY=atoi(argv [1]);
/*Kapcsolodasazelsoprogramparameteraltalmegadott
szemaforhoz.*/
if((semid=semopen(k ey ))==-1)
{
fprintf(stderr, "Nemtudommegny itniaszemafort.");
return-1;
}
for(i=0;i<SEM_MAX_IN_SET;i++)
intret=semacquire(semid,i);
if(ret==0)
lock ed=i;
printf("Azutasta%d.pultnalszolgalj ak k i.\n",i);
break ;
elseif(ret==-1)/*Hiba:tulfutacik lus*/
{
break ;
elseif(ret==1)/*Nincsszabadpult*/
{
semncnt=semgetwaitingprocs(semid,i);
i f(semncnt<semncntmin)
{
semncntmin=semncnt;
semminmember=i;
}
}
printf("AM.pultra%dutasv arak ozik .\n",i,semncnt);
}
if(lock ed==-1)/*Hanincsszabadpult...*/
/*Beallunk alegrov idebbsorba*/
printf("Alegrov idebbsora%d.pultnalv an%dutassal.\n",
semminmember,semncntmin);
175
semacquirewait(semid,semminmember);
lock ed=semminmember;
}
printf("Ny omj <Enter>-tapultelhagy asahozl\n");
getchar();
semrelease(semid,lock ed);
return0;
}
5. fejezet: Prhuzamos programozs
Termszetesen a legrvidebb sor megkeresse s a sorban lls kztt egy
msik utas bellhat a sorba, hiszen a szemaforok rtknek vgignzse s a
lefoglals nem atomi mvelet. Egy reptren mindennapos, hogy elindulunk
egy sor fel, s valaki bell elnk az utols pillanatban. gy ez a viselkeds
ebben a feladatban elfogadhat.
A semopen fggvny defincija az albbi:
/*k apcsolodasegy ,marletezoszemaforhoz.Hanincsily en,
av sszateresiertek -1.*/
intsemopen(k ey _tk ey )
returnsemget(k ey ,0,0666);
A vrakozs nlkli lefoglals kdja a kvetkez:
/* Amegadottszemafortombamemberargumentumbanmegadottindexu
tagj ateggy elcsok k enti. Nemv arak ozik .*/
i ntsemacquire(intsemid,intmember)
{
structsembufsem_acquire={ member,-1, IP C_NOWAIT} ;
if((semop(semid,ddsem_acquire,1))==-1)
if(errno== EAGAIN)
printf("A%d.pultnemallrendelk ezesre(%d).\n",
member,semgetv al(semid,member));
return1;
else
f
fprintf(stderr,"muszak ihibaa%d.pultnal.\n",member);
return-1;
else
pr ntf("utasa%d. pultnal.\n",member);
return0;
5.2. Processzek kztti k ommunik ci(IP C)
A vrakoz lefoglals kdjnak egy lehetsges implementcija a kvetkez:
/*Amegadottszemafortombamemberargumentumbanmegadottindexu
tagj ateggy elcsok k enti.v arak ozik .*/
intsemacquirewait(intsemid,intmember)
~
1
~
1
q
structsembufsem_acquire={ member,-1,0} ;
/*Aszemaforlefoglalasa*/
printf("Azutasbeal ta%d.pultnalallosorba.\n",member);
if((semop(semid,&sem_acquire,1))==-1)
fprintf(stderr,"muszak ihibaa%d.pultnal.\n",member);
return-2 ;
else
pr ntf("A%d.pultfelszabadult.Azutastk iszolgalj ak .\n",
member);
return0;
A szemafor elengedst az albbi fggvny valstja meg:
/*Aszemafortombmemberargumentumbanmegadottindexuelemenek
ertek etnov eleggy el.*/
v oidsemrelease(intsemid, ntmember)
{
structsembufsem_release={ member,1,IP C_NOWAIT} ;
intsemv al;
/*Foglalj av alak iaszeamafort?*/
semv al=semgetv al(semid,member);
if(semv al==SEM_RESOURCE_INIT)
fprintf(stderr,"Aszemafornincslefoglalv a!\n");
exit(1);
/*Attempttolock thesemaphoreset*/
if((semop(semid,&sem_release,1))==-1)
{
fprintf(stderr,"Azelengedessik ertelen!\n");
exit(1);
else
{
printf("Azutaselhagy taa%d.pultot.\n",member);
}
}
177
5. fejezet: Prhuzamos programozs
5.2.2. zenetsorok
Az zenetsor (message queue) olyan FIFO-jelleg aszinkron kommunikcis
csatorna, amelybe a programoz ltal meghatrozott formtum adatcsoma-
gokat lehet belerakni. Az zenethez hozzrendelhetnk egy pozitv szmmal
jellt tpust, amely alapjn virtulisan egy zenetsoron tbb zenetcsatornt
hasznlhatunk. Fizikailag ez lncolt listaknt jelenik meg a kernel cmter-
ben, amelyet a kvetkez adatstruktra r le:
structmsg
{
structmsg*msg_next;
longmsg_ty pe;
char*msg_spot;
shortmsg_ts;
1;
/*ak ov etk ezouzenetasorban*/
/*azuzenettipusa*/
/*magaazuzenet(ak ernelnemtud
semmitaformatumrol)*/
/*azuzenetmerete */
A fentiekbl jl lthat, hogy a kernel csak az zenet tpust kezeli (msg_type),
a tbbi adatot egy memriaterletre mutat pointer kpviseli (msg_spot).
A kernel tudja a mutatott adatnak (msg_ts) a mrett, az adatot pedig kernel-
szinten nem kell rtelmezni.
Nzzk meg, hogyan adhatjuk meg sajt zenetformtumunkat. Elsknt
vizsgljuk meg azt az alapvet struktrt, amelyet ki kell bvtennk, s a
sys/msg.h llomnyban van definilva:
/*uzenetformatumazuzenetk uldoesuzenetfogadofuggv eny ek nek
(1d.k esobb)*/
structmsgbuf
longmty pe;

/*uzenettipus*/
charmtext[1]

/*adat*/
1;
Vagyis azok a fggvnyek, amelyek zenetet kldenek, illetve fogadnak, a fenti
struktrra mutat pointert vrnak, valamint a tnyleges, a programoz ltal
definilt struktra mrett. Az 5.1. bra szemllteti mindezt.
Tegyk fel, hogy a programoz a kvetkez struktrt definilta:
structstudentinfo
f
char nev [40]; /* Nev */
char cim[80]; /* Cim*/
char igszam[2 0]; /* igazolv any szam*/
charmegj [80]; /* Megj egy zes*/
1;
178
5.2. Processzek kztti kommunikci (IPC)
structstudentinfo_msg
longmty pe;
structstudentinfodata;
} ;
Ha a studentinfo_msg struktrt explicite konvertljuk msgbuf tpus struk-
trra, abbl az IPC-fggvnyek csak a szaggatott vonalig tart rszt ltjk,
s szksgnk van mg arra az informcira, amely megadja az brn jobb
oldalon szerepl, programoz ltal meghatrozott adatstruktra mrett,
mghozz az mtype nlkl. A fenti plda egyben be is mutatta, hogyan kell
sajt zenetformtumot ler struktrt deklarlni.
67

Tpus
mtext[1]
Tpus
5.1. bra. Az msgbuf s a programoz ltal definilt zenetstruktra sszehasonltsa
A System V IPC zenetsorai a kezelsi koncepcit tekintve nagyon hasonlta-
nak a szemaforokra. zenetsort a
#include<sy s/ty pes.h>
#include<sy s/ipc.h>
#include<sy s/msg.h>
int msgget(key_t key, int msgflg); _
fggvnnyel hozhatunk ltre, amelynek az els paramtere egy egyedi kulcs.
Ezt ezttal is ltrehozhatjuk az ftok fggvnnyel. A jelzbitek a jogosultsgokat
lltjk be, illetve megadhatjuk az IPC_CREAT s az IPC_EXCL jelzbiteket,
amelyeket a System V szemaforok lersnl mutattunk be. Ha a megadott
kulcs ltezik, akkor a fggvny a mr ltez szemafor azonostjval tr visz-
sza, egybknt az azonost az jonnan ltrehozott. Hiba esetn a visszat-
rsi rtk 1.
67
A megolds egy trtnetileg is rdekes plda arra, hogy hogyan lehet a tpuskompatibili-
tst rkls nlkl, strukturlt mdszerekkel megoldani. Ez a mdszer termszetesen
kizrja a tpusellenrzs lehetsgt, gy a programoz vdtelenebb sajt figyelmetlens-
gvel szemben.
179
5. fejezet: Prhuzamos programozs
Nzznk egy pldt zenetsor ltrehozsra:
/*Egy edik ulcsletrehozasaftok Oseg tsegev el*/
k ey =ftok ("./",'m');
/*Azuzenetsormegny itasa*/
if((mclid=msgget(k ey , IPC_CREATI0660)) == -1)
{
/* Hiba */
}
Most egy msik processzbl rjk el ugyanezt az zenetsort:
/* Az uzenetsormegny itasa*/
if((mclid=msgget(k ey ,0660)) -1)
{
/*Nincsily enuzenetsor.*/
zenetet kldeni, illetve fogadni az
#include<sy s/ty pes.h>
#include<sy s/ipc.h>
#include<sy s/msg.h>
intmsgsnd(intmsgid,structmsgbuf*msgp,size_tmsgsz,
intmsgflg);
ssize_tmsgrcv (intmsclid,structmsgbuf*msgp,size_tmsgsz,
longmsgty pe,intmsgflg);
fggvnyek segtsgvel tudunk. A klds sorn megadjuk az zenetsor azonos-
tjt, a sajt zenetnk cmt msgbuf struktrra konvertlva, az adatmretet (a
struktra mretbl le kell vonnunk az mtype mrett). Ha az zenetsor tele van,
akkor az msgsnd fggvny hibval tr vissza, vagy vrakozik a kldsre. Els
esetben jelz'bitknt bellthatjuk az IPC_NOWAIT bitet, egybknt nullt
adunk meg. zenet kiolvassnl megadjuk az zenetsor azonostjt, annak a
memriaterletnek a pointert msgbuf tpusra konvertlva, ahova szeretnnk,
hogy az msgrev fggvny lemsolja az zenetet. Kiolvassnl a mret a megadott
memriaterlet mrett jelenti. Ha ennl kisebb az zenet, nem trtnik hiba, ha
nagyobb, akkor igen. Ha azonban belltjuk az MSG_NOERROR jelz'bitet, akkor
az zenet vge le lesz vgva, csak az els msgsz szm byte lesz az msgp ltal
mutatott memriaterletre msolva. Az msgtype argumentumot szrsre hasz-
nlhatjuk az zenet tpusa alapjn.
Ha az msgtype nulla, akkor az msgrcv a soron kvetkez zenetet ol-
vassa ki az zenetsorbl.
Ha pozitv, s
180
5.2 . Processzek kztti kommunikci (IPC)
ha az MSG_EXCEPT jelzbit nincs bekapcsolva, akkor azt a legels
zenetet, melynek tpusa msgtype.
Ha az MSG_EXCEPT jelzbit be van kapcsolva, akkor azt az els
zenetet, amelynek tpusa nem msgtype.
Ha az msgtype negatv, akkor az a legalacsonyabb tpus zenet kiol-
vassa trtnik meg, amelynek tpusa kisebb vagy egyenl, mint az
msgtype abszolt rtke.
Az zenetsor vezrlst a
#i ncl ude <sys/types . h>
# ncl ude <sys/ipc. h>
#i ncl ude <sys/msg h>
int msgctl (int msqid, int cmd, struct msqid_ds * buf);
fggvnnyel vgezhetjk el. Az els paramter az zenetsor azonostja, a
msodik paramtert az 5.6. tblzat foglalja ssze:
5.6. tblzat. zenetsor-mveletek
Parancs Lers
IPC_STAT Informcit msol a buf argumentum ltal mutatott struktrba.
IPC_SET A buf ltal mutatott struktra nmely tagja alapjn tlltja az
zenetsor tulajdonsgait. A figyelembe vett tagok a kvetkezk:
msg_perm.uid
msg_perm.gid
msg_perm.mode (az als 9 bit)
msg qbytes
IPC_RMID Az zenetsor megszntetse.
Az utols paramter tpusa az zenetsor tulajdonsgait rgzt struktra:
struct msqid_ds
{
struct pc_perm msg_perm; /* Hozzaferesi jogosultsagok * /
struct msg "rnsg_f rst ; /* Az el so uzenet a uzenetsor lantolt
1 i stajaban * /
struct msg * msg_last; /* Az utolso uzenet az uzenetsor
lantolt 11 stajaban * /
ti me_t msg_stime; /* A legutolso kuldes ideje * /
ti me_t msg_rtime; /* A legutolso olvasas ideje * /
t me_t msg_ctime; /* A legutolso valtoztatas ideje * /
struct wait_queue wwai t;
struct wait_queue rwai t;
ushort msg_cbytes; /* Az uzenetsorban levo bajtok szarna
(osszes uzenet) * /
181
5. fejezet: Prhuzamos programozs
ushortmsg_inum;
ushortmsg_clby tes;
ushortmsg_lspid;
ushortmsg_lrpid;
/*Azeppenazuzenetsorbanlev o
uzenetek szama*/
/*Azuzenetsorbanlev obaj tok
maximalisszama*/
/*Alegutolsok uldoprocessz
azonositoj a*/
/*Alegutolsoolv asoprocessz
azonositoj a*/
1;
zenetsor eltvoltst a
msgctl(mq d, IP C_RMID,0);
programsorral vgezhetjk.
Vgl rakjuk ssze az eddigieket egy pldban.
Plda Egy egyetemen egy kurzust az azonostjval jellemeznek. Egyszer pldnkban egy
adott kurzusra maximum 5-en jelentkezhetnek. rjunk egy kurzusszerverprogramot, amely
meghirdeti" a kurzust, s ltrehoz egy zenetsort, amelyen keresztl a hallgatregisztrl
kliensprogram elkldi a hallgatk adatait. A szerverprogram egyszeren csak kirja a regisztrlt
hallgatk adatait.
/*k ozos.h-Kozosszerv eresk liensdek laraciok .*/
#ifndefKOZOS_H
#defineKOZOS_H
#defineMSG_TYP E_REGISTER1/*Azuzenettipusa*/
structstudentinfo
{
charnev [40];
charcim[80];
charigszam[2 0];
charmegj [80];
} ;
/*Nev */
/*Cirn*/
/*Igazolv any szam*/
/*Megj egy zes*/
/*saj atformatumuuzenetpuffer.*/
structstudentinfo_msg
longmty pe;
structstudentinfodata;
} ;
#endif/* kozos_H */
/*k urzus_szerv er.c-Ak urzusszerv er,*/
#include<sy s/ty pes.h>
#include<sy s/ipc.h>
#include<sy s/msg.h>
182
5.2. Processzek kztti kommunikci (IPC)
#include<stdio,h>
#include"k ozos.h"
/*Max.enny ihallgatoj elentk ezhetak urzusra.*/
#defineMAX_REGISTRATION5
intmain()
k ey _tk ey ;
int mgid,i;
structstudentinfo_msgmsg;
structstudentinfo_msg*pmsg=&msg;
/*Egy edik ulcsletrehozasaftok ()segitsegev el.*/
k ey =ftok ("./",'m');
/*Azuzenetsormegny itasa.*/
if((mgid=msgget(k ey ,IP C_CREATI0660))==-1)
fprintf(stderr,
"Ak urzusazonositot#%dnemlehetletrehozni.\n",k ey );
return1;
printf("A#%dk urzusfogadj aaregisztrac ok at.\n",k ey );
for(i=0;i<MAX_REGISTRATION;i++)
pmsg->mty pe=MSG_TYP E_REGISTER;
msgrcv (mgid,(structmsgbuf*)pmsg,sizeof(msg)-sizeof(long),
MSG_TYP E_REGISTER,0);
printf("Ak urzusraj elentk ezotanuloadatai:\n");
printf("Nev :%s\n",pmsg->data.nev );
printf("Cim:%s\n",pmsg->data.cim);
printf("Igazolv any szam:%s\n",pmsg->data.igszam);
pr ntf("Megj egy zes:%s\n\n",pmsg->data.megj );
/'uzenetsortorlese.*/
msgctl(mgid,IP C_RMID,0);
printf("Aregisztraciolezarult.\n");
return0;
/*regisztracio.c-Ahallgatok atregisztralok liens."/
/*P arancssoriargumentumak urzusszama.*/
# nclude<sy s/ty pes.h>
#include<sy s/ipc.h>
#include<sy s/msg.h>
#include<stdio.h>
#include<stdlib.h>
#include"k ozos.h"
183
5. fejezet: Prhuzamos programozs
intmain(intargc,Ihar*argv [])
{
k ey _tk ey ;
int mgid;
structstudentinfo_msgmsg;
int msgsize;
if(argc!=2 )
fprintf(stderr,"Hasznalat:"
"regisztracio<k urzusazonosito>\n");
return-1;
k ey =atoi(argv [1]);
/*Azuzenetsormegny itasa.*/
if((mgid=msgget(k ey ,0660))==-1)
fprintf(stderr,"Ak urzusazonosito#%dnemletezik .\n",k ey );
return1;
}
printf("Nev :");
scanf("%s",msg.data.nev );
printf("Cim:");
scanf("%s",msg.data.cim);
printf("Igazolv any szam:");
scanf("%s",msg.data.igszam);
printf("Megj egy zes:");
scanf("%s",msg.data.megj );
/*uzenetk uldes.*/
printf("Diak regisztralasa...\n");
msg.mty pe=mSG_TYP E_REGISTER;
/*Ahosszazmty petagv altozonelk ulertendo.*/
msgsize=sizeof(structstudentinfo_msg)-sizeof(long);
if((msgsnd(mgid,(structmsgbuf*)&msg,msgsize,0))==-1)
{
fprintf(stderr,"Aregisztracioelk uldesesik ertelen.\n");
return-1;
}
printf("Adiak regisztracioj asik eres.\n");
return0;
134
5.2. Processzek kztti kommunikci (IPC)
5.2.3. Megosztott memria
A megosztott memria (shared memory) olyan kzs memriatartomny,
amelyhez tbb processz is hozzfrhet. Ez a leghatkonyabb mdja a pro-
cesszek kzti kommunikcinak, mert a kzs fizikai memriatartomny a
megosztott memrit hasznl processzek virtulis cmterbe lapoldik, s
a kzvetlen memria-hozzfrs gyorsabb, mint brmelyik msik eddig tr-
gyalt System V IPC-mechanizmus. A megosztott memria csak megosztst
biztost, szinkronizcit nem. gy elkpzelhet, hogy az A processz a B pro-
cessz adatmdostsa kzben lesz betemezve, s gy inkonzisztens adatot lt.
Ha ez a veszly fennll, rdemes szemafort hasznlnunk. A memriaterletet
sajt magunknak kell menedzselnnk: a mallocl free fggvnyeket nem ir-
nythatjuk t" a megosztott memrira.
Az exit s az exec rendszerhvsok esetben a rendszer az sszes meg-
osztottmemria-erforrst lecsatolja, fork esetn a gyermekprocessz rkli a
szlhz csatolt sszes megosztott memriatartomnyt.
Az eddigiekkel sszhangban megosztott memrit az
#include <sy s/ipc.h>
#include<sy s/shm.h>
intshmget(k ey _tk ey , int size, int shmflg);
fggvnnyel hozhatunk ltre. A key egyedi azonost, amelyet legtbbszr egy
ftok hvssal generlunk. Ha a key argumentum nem egyedi, a jelzbitek
(shmflag) rtktl fggen hiba trtnik, vagy egy mr ltez megosztott me-
mriatartomny azonostjt kapjuk vissza. A size argumentum a kvnt me-
mria mrete byte-okban, a lefoglalt memria mrete a size rtk felkerektve a
PAGE_SIZE legkisebb tbbszrsre. Az shmflg rtke a mr ismert hozzf-
rsi jogosultsg belltsaibl s az opcionlis IPC_CREAT s IPC_EXCL jel-
zbitekbl ll.
Ha szeretnnk hasznlni egy mr ltrehozott memriatartomnyt az azo-
nost segtsgvel, akkor elbb hozz kell csatolnunk (attach) a processz cm-
tartomnyhoz. Ezt a
#include <sys/types,h>
#include <sys/shm.h>
v oid*shmat(int shmid,constvoid *shmaddr, i nt shmflg);
hvssal tehetjk meg, amely visszaad egy pointert a lefoglalt s a processz
cmtartomnyba lekpezett megosztott memriatartomnyra. Ha az shmaddr
paramterben megadunk egy memriacmet, s belltjuk az SHM_RND jelz-
bitet, akkor a visszaadott cm az shmaddr rtke lesz lekerektve a legkzelebbi
laphatrra. Ha az SHM_RND nincs belltva, akkor az shmaddr argumentum-
185
5. fejezet: Prhuzamos programozs
nak cmhatrra igaztott rtket kell tartalmaznia. A gyakorlat tbbsgben
azonban ez a paramter nulla, s a rendszerre bzza az megfelel cmtarto-
mny kivlasztst. Az shmflg argumentum a mr emltett SHM_RND rt-
ken kvl SHM_RDONLY lehet, amely csak olvassra csatolja a megosztott
memrit a processz cmtartomnyhoz.
Mivel most mr van egy mutatnk, ennek segtsgvel tudjuk rni s ol-
vasni a megosztott memriatartomnyt. Ha mr nincs szksgnk tbb a
megosztottmemria-erforrsra, le kell csatolnunk (detach), ezt a
#include<sy s/ty pes.h>
#include<sy s/shm.h>
intshmdt(constv oid*shmaddr);
fggvny meghvsval kell vgrehajtanunk, amelynek egyetlen paramtere
az shmat fggvny ltal visszaadott mutat.
A vezrlst ezttal a
#include<sy s/ipc.h>
#include<sy s/shm.h>
intshmctl(intshmid,intcmd,structshmid_ds*buf);
fggvnnyel vgezhetjk. Az els paramter a megosztott memria azonost-
ja, a msodik paramtert az 5.7. tblzat foglalja ssze.
5.7. tblzat. Megosztott memria parancsai
Parancs Lers
IPC_STAT Informci a megosztott memrirl.
IPC_SET Hozzfrsi jogosultsgok s azonostk megvltoztatsa.
IPC_RMID A megosztott memria megszntetse.
SHM_LOCK A megosztott memria mindvgig a fizikai memriban marad.
Linux-specifikus.
SHM_UNLOCK Engedlyezi a swappinget.
Az utols paramter felptse a kvetkez:
structshmid_ds
structipc_permshm_perm;
/*Hozzaferesesazonositok beallitasa*/
intshm_segsz; /* A memoriatartomany merete(baj tok ban)*/
time_tshm_atime;/*A legutolsofelcsatolasidej e*/
time_tshm_dtime;/*A legutolsolecsatolasidej e*/
time_tshm_ctime;/*Azutolsov altozasidej e*/
186
5.2. Processzek kztti kommunikci (IPC)
/* - - - - - - - - -
ALobbi tagot a rendszer hasznalja - - - - - - - -
*7491111
unsigned short shm_npages; /* A tartomany merete (lapok szama) */
unsigned long *shm_pages;
struct vm_area_struct *attaches; /* A felcsatolasok leiroja */
} ;
A megosztott memria megszntetse, pldul, a
shmctl(shmd, IPC_RMID, 0);
hvssal trtnhet. Ha nincs olyan processz, amelyik csatolva tartan az er-
forrst, azonnal megsznik, ha van, akkor csak mintegy megjelli megsznte-
tsre a megosztottmemria-erforrst, a tnyleges eltvolts csak az utols
lecsatols utn trtnik meg.
A fentiek alapjn nzznk meg egy egyszer pldt.
Plda rjunk programot, amely ltrehoz egy megosztott memrit, r r valamilyen adatot, majd
ksztsnk egy msik programot, amelyik kiolvassa mindezt. gyeljnk arra, hogy ne maradjon
felszabadtatlan erforrs a kernelben (ellenrzshez hasznljuk az ipcs segdprogramot).
unsgned short shm_cpid; /* A letrehozo processz azonositoja */
unsigned short shm_lpid; /* Az utolso muvelet vegrehajtojanak
azonositoja */
short shm_nattch; /* Az aktualis felcsatolasok szama */
/* kozos.h */
#ifndef KOZOS_H
#define KOZOS_H
#define MEMORY_SIZE 10
#define SHM_ID 1234
#endif /* KOZOS_H */
/* shmem.c - Megosztott memoria letrehozasa. */
#include <sys/ipc.h>
#nclude <sys/shm.h>
#include <stdio.h>
#include "kozos.h"
#define MEMORY_SIZE 9
int main()
int shmid;
char c;
char *shmptr;
/* A megosztott memoria letrehozasa. */
if((shmid =shmget(SHM_ID, MEMORY_SIZE, IPC_CREAT10666)) < 0)
187
5. fejezet: Prhuzamos programozs
fprintf(stderr,"Hibaamegosztottmemorialetrehozasanal.\n");
exit(1);
}
/* Amegosztottmemoriafelcsatolasa.*/
if((shmptr=shmat(shmid.0,0))==(char*)-1)
fprintf(stderr,"Hibaamegosztottmemoria"
"felcsatolasanal.\n");
ex t(1);
}
printf("Adatok irasaamegosztottmemoriaba...\n");
for(c=0;c<MEMORY_SIZE;c++)
{
shmptr[c]='1
.
4-c;/*12 3 456789*/
}
shmptr[c]='\0';
printf("Ny omj <Enter>-tafoly tatashoz!\n");
getchar();
/*Amegosztottmemorialecsatolasa.*/
shmdt(shmptr);
/*Amegosztottmemoriamegszuntetese.*/
shmctl(shmid,IP C_RmIO,0):
return0;
/*shmrd.c-megosztottmemoriak iolv asasa.*/
#include<sy s/ipc.h>
#include<sy s/shm.h>
#include<stdio.h>
#include"k ozos.h"
intmain()
intshmid;
char*shmptr;
/*Amarletezomegosztottmemorialeiroj anak lek erdezese.*/
shmid=shmget(SHM_Io, MEMORY_SIZE, 0666);
i f(shmid<0)
fprintf(stderr,"Hibaamegosztottmemoriahozv alo"
"hozzaferesben.\n");
exit(1);
188
5.3. Processzek a Linux rendszerben
/ A megosztottmemoriafelcsatolasa.*/
shmptr=shmat(shmid,0,0);
if(shmptr==(char*)-1)
fprintf(stderr,"Hibaamegosztottmemor a
"felcsatolasanal.\n");
exit(1);
}
printf("Amegosztottmemoriatartalma:%s\n",shmptr);
/' A megosztottmemorialecsatolasa."/
shmdt(shmptr);
return0;
Ez a plda a megosztott memrit hivatott illusztrlni, ezrt a msodik prog-
ramot akkor indtottuk, amikor az els mr befejezte az rst, de mg nem
csatolta le a megosztott memrit. A gyakorlatban ilyenkor clszer valami-
lyen szinkronizcis objektummal vdeni a hozzfrst, mert ha az els fo-
lyamat nem vgez az rssal, amikor a msodik futni kezd, nem lehet tudni,
hogy az olvasprocesszben a printf hol tall egy lezr nullt.
5.3. Processzek a Linux rendszerben
Ez a fejezet az opercis rendszer kontextusba helyezi a folyamatokrl szerzett
eddigi ismereteket. A rendszerben fut processzeknek tbbfle letciklusmodellje
lehet, szmunkra itt kett klnsen fontos. Az els tpust a felhasznl indtja a
terminlrl vagy az XWindow rendszerbl, a msik tpust a rendszer indtsa
utn automatikusan szerentnk indtani, s addig fut, amg a rendszer. Az els
kategriba az ltalunk futtatott programok, mg az utbbi kategriba a vala-
milyen szolgltatst vgz programok tartoznak, pldul a webszerver, a levele-
zszerver, az idzts, a naplzs, az idztett programfuttats, az USB-port
figyelse. Ez utbbi programokban az a kzs, hogy nincsen felhasznli felle-
tk, nem kapcsoldnak semmilyen terminlhoz vagy grafikus rendszerhez, s
tipikusan a rendszerrel indulnak, s a rendszer lelltsakor fejezik be a ma-
dsket.
68
A tbbi processzel valamilyen IPC-mechanizmuson vagy socketeken
keresztl kommuniklnak. Ezeket a processzeket dmonoknak (daemon) ne-
vezzk, amely sokszor a nevkben is megjelenik.
69

" Termszetesen egy dmont a felhasznl is elindthat, illetve lellthat, de nem ez a tipi-
kus forgatknyv. Ugyanakkor, ha a felhasznl elindt egy dmont, a felhasznl kilp-
svel nem ll le automatikusan, mint a tbbi programtpus.
80
Pldul a TCP/UDP portokat figyel internetdmon neve inetd.
189
5. fejezet: Prhuzamos programozs
Jllehet egy rendszer indtsa a rszletekben ersen klnbzhet az egyes
disztribcikban, s az elmlt vekben is sokat vltozott, lnyegben az albbi-
ak szerint trtnik. Az opercis rendszer indtsakor elindul a kernel az,
amely inicializlja az llomnyrendszert. A kernel ezek utn elindtja az els
felhasznli zemmd processzt,
70
amelynek a processzazonostja 1. Ez a
processz tetszleges program betltsvel keletkezhet, ugyanakkor hagyom-
nyosan initnek hvjk. Ennek a processznek hrom specilis tulajdonsga van:
Ez az egyetlen felhasznli zemmd processz, amelynek elindtst
a kernel kezdemnyezi, ezrt nincs szlprocessze.
Ha ez a processz lell, akkor az a rendszer lellst eredmnyezi.
Azoknak a processzeknek, amelyeknek a szlei lelltak, az nit pro-
cessz lesz a szlje.
Ezek utn az nit processz inicializlja a rendszert. Ezt az inicializcis fo-
lyamatot a Linux nit processze tbb mint szertegaz konfigurcis lehets-
gekkel tmogatja
71
. Ezt kt alapvet mdon teszi: shellszkriptet futtat, illetve
sajt konfigurcis llomnyok alapjn kzvetlenl indt el megadott pro-
cesszeket. Az els esetben az nit processz csak a shellt indtja, csak a shellt
futtat processz lerjrl tud, a shell ltal indtott programokrl nem. Ezrt
nem kap rtestst arrl, ha a a dmon kilpett, s nem tudja szksg esetn
jraindtani (respawn') sem. A konfigurcis llomnyok esetben az nit
kpes szlelni az elindtott processzekkel kapcsolatos esemnyeket, s kpes
reaglni is rjuk. Jelen pillanatban az utbbi megolds fel mozdulnak el a
disztribcik.
A dmonok indtsa utn az nit tipikusan
72
a terminlokat s az XWindow
rendszert indtja el. A terminlok esetn a getty programot vagy annak vala-
melyik vltozatt (pl. agetty) indtja el valamelyik tty eszkzzel s annak be-
lltsaival paramterezve. A getty megnyitja az eszkzt, vr a kapcsoldsra,
majd amikor az megjtt, elindtja a login programot, amely pedig vgl elin-
dtja a shellt." Amikor kilpnk a shellbl, kilpnk a loginbl is.
Ha a shellben elindtunk egy programot, akkor addig nem kapjuk vissza a
parancsrtelmezt, amg be nem fejezte a mkdst, vagyis a processz ki
nem lpett. gy egyszerre csak egy parancsot tudnnk lefuttatni. Ennek elke-
rlsre az & karakter hozzadsval a httrben tudjuk futtatni a progra-
70
A kernelszlak szlje a 2 -es sorszm kthreadd processz.
71
Az nit ltal betlttt programokat tbb knyvtrnyi konfigurcis llomny hatrozza
meg. Ezeket a belltsokat tbbek kztt futtatsi szintet (runlevel) is az ti nit kezeli.
72
Ne feledjk el, hogy az nit processz konfigurcis llomnyok alapjn indt programokat,
amelyeket rendszergazda-jogosultsgokkal brki megvltoztathat.
73
Sajt Linux rendszernk fut programjait knnyen ttekinthetjk, ha kirajzoljuk a pro-
cesszft a ps -e -o pid,args --forest paranccsal. A Linux-kernel sorfolytonosan osztja ki a
processzazonostkat. Ha egy processz kilp, az azonostjt nem rendeli jabb processz-
hez addig, amg ki nem fut az azonost rtktartomnybl. gy a processzazonostkbl
a sorrendre is kvetkeztethetnk A kernelszlak szgletes zrjelben jelennek meg.
190
5.3. Processzek a Linux rendszerben
mot, s a terminlt visszakapjuk. A httrben fut programok nem tudnak
olvasni a terminlrl, az alaprtelmezett bemenetk (0 azonostj llomny-
ler) a /deo /null, amely termszetesen tirnythat. A jelenleg fut prog-
ram megllthat (CTRL + Z). Ekkor visszakapjuk parancsrtelmezt, s a
httrben, valamint eltrben fut programok kztt shellparancsokkal (fg,
bg) vltogathatunk. A kill CONT paranccsal engedhetjk tovbb egy megl-
ltott program futst. A shell ilyenkor a programokat feladatnak (job) te-
kinti, a fenti megoldssal pedig feladatvezrlst (job control) valst meg.
A kvetkez fejezetekben megvizsgljuk, hogy a Linux miknt tmogatja
a fent rszletezett mechanizmusokat.
5.3.1. Feladatvezrls
A Linux rendszerben a folyamatok nemcsak hierarchiba, hanem klnbz
tpus halmazokba is rendezdnek. Ezen csoportostsok alapjn kapcsold-
nak a terminlokhoz s a shellhez.
A shell s a terminl feladatait nagyban legyszersti, ha a processzek
egy halmaznak egyszerre tudunk jelzseket (lsd az 5.6. Jelzsek alfejezet-
ben) kldeni. Ezrt a processzeket processzcsoportokba (process group)
szervezzk, amelyeknek a killpg fggvnnyel kldhetnk jelzst, amelyet a
processzcsoport minden egyes tagja megkap. A kernel lnyegben ezzel tmo-
gatja a feladatvzrlst: kernelszinten a processzcsoport s a feladat ugyanaz.
Minden processzcsoportnak van egy csoportvezetje (process group leader).
A processzcsoport azonostja (PGID) a csoportvezet azonostja. Egy pro-
cesszcsoport addig ltezik, mg legalbb egy tagja van.
Egy processz ltrejttekor automatikusan a szlprocessz csoportj-
nak a tagjv vlik. A processz csoportazonostjt a getpgid(0) hvssal kr-
dezhetjk le, mg egy folyamatot a setpgid fggvnnyel csatlakoztathatunk
egy csoporthoz:
#i nc 1 ude <uni std h>
int setpgid(pid_t pid, pid_t pgid);
Az els argumentum a processz azonostja, a msodik a processzcsoport. Ha
brmelyik 0, akkor a fggvny a hv processz azonostjt hasznlja. Mivel a
csoportazonost megegyezik a csoportvezet azonostjval, ha a kt param-
ter egyenl, az specilis helyzetet teremt: ilyenkor j csoport jn ltre, amely-
nek a vezetje a megadott azonostj processz lesz.
Ezek alapjn setgpid(0,0) hvs az aktulis processz azonostjt teszi
meg csoportazonostv. Mivel csoportvezetk esetben ez eleve gy van, a
fggvnyhvs hatstalan. Ha a hv nem csoportvezet, ilyenkor j pro-
cesszcsoport jn ltre, amelynek a csoportvezetje az adott folyamat lesz.
191
5. fejezet: Prhuzamos programozs
Nzznk meg egy tipikus esetet, amikor a shell processzcsoportokat hasznl:
$cat /etc/security/limits.conf more
Ilyenkor a shell egy kt processzbl ll processzcsoportot hoz ltre. Ha valame-
lyik processz beragad", a shell egyetlen jelzskldssel le tudja ket lltani.
A feladatvezrls tovbbi lehetsge az, hogy a processzcsoportok munka-
menetbe (session) szervezdnek Ennek a koncepcinak XWindow-krnyezet-
ben nincs jelentsge, a shell hasznlja a terminlkezelsre. A munkamenetek
eredetileg az egy terminlon bejelentkezett felhasznl ltal hasznlt pro-
cesszcsoportokat fogtk ssze.
Ezrt a folyamatok a munkameneten keresztl kapcsoldnak a terminl-
hoz. Egy munkamenethez maximum egy vezrlterminl (controlling termi-
nal) tartozhat, amelynek a nevt a ctermid() fggvnnyel krdezhetjk le. Ez
egyben azt is jelenti, hogy vannak olyan munkamenetek, amelyhez nem kap-
csoldik terminl, erre a ksbbiekben mutatunk pldt. Ugyanakkor minden
terminlhoz tartozik pontosan egy munkamenet.
Biztonsgi okokbl clszer meggtolni, hogy a kln terminlon beje-
lentkezett felhasznlk folyamatai keveredjenek. gy egy processz csak egy
munkameneten bell vlthat processzcsoportot, s nem vlthat munkamene-
tet, leszmtva azt az esetet, amikor egy jat hoz ltre. Ez utbbinak fknt
az a clja, hogy a processzt lekapcsoljuk a terminlrl. A processzcsoporthoz
hasonlan a munkamenetnek is van egy vezetje, s a munkamenet azonos-
tja megegyezik a munkamenet vezetjnek a processzazonostjval.
j munkamenetet a processzcsoporthoz nagyon hasonlan lehet ltrehozni:
#include <unistd.h
pid_t setsid (void);
Ez a fggvny ltrehoz egy j munkamenetet vezrlterminl nlkl, azon be-
ll egy j processzcsoportot, amelynek a hv processz az egyedli tagja, s
a hv processzt mindkett vezetjv teszi. A visszatrsi rtk siker esetn
a processzcsoport azonostja (amely termszetesen a processz s a munka-
menet azonostja egyben). A fggvny elfelttele, hogy a hv processz ne
legyen sem munkamenet-, sem processzcsoport-vezet.
Egy munkamenetnek egy kitntetett processzcsoportja van: az eltrbeli
processzcsoport (foreground process group). Egyedl ez a csoport birtokol
teljes hozzfrst a terminlhoz. A tbbi processzcsoportot httrbeli pro-
cesszcsoportnak (background process group) nevezzk. A terminlnak ma-
ximum egy eltrben s tbb httrbeli processzcsoportja lehet.
A feladatvezrlst jelzsekkel s httrbeli processzcsoportok eltrbe ho-
zsval oldjuk meg. Egy fut processz meglltst a SIGSTOP jelzssel v-
gezhetjk, s a SIGCONT jelzssel indthatjuk el jra. A terminl eltrbeli
processzcsoportjt a tcgetpgrp fggvny segtsgvel krdezhetjk le, s a
tcsetpgrp segtsgvel llthatjuk be.
192
5.3. Processzek a Linux rendszerben
Vizsgljuk meg a klnbsget az eltrbeli s a tbbi processzcsoport k-
ztt. Csak az eltrbeli processzek olvashatnak a vezrlterminlrl A ht-
trbeli processzcsoportok SIGTTIN, illetve SIGTTOU jelzst kapnak, ha rni,
illetve olvasni prblnak. Mindkt jelzs alaprtelmezse a processz megllt-
sa. A meglltott processzt a felhasznl az eltrbe tudja hozni, ahol bekrheti
az adatot. Az rs jelzst a shell ltalban fellrja arra, hogy a vezrltermi-
nlra rhat a httrbeli processz is, br olyankor a terminl megjelense nem
tl szp, amikor tbb processz egyszerre r r.
A billentyzetrl jv megszaktsokat (SIGTSTP, SIGQUIT, SIGINT) csak
az eltrben processzcsoportok kapjk meg Amikor a felhasznl kilp, akkor a
minden processzcsoport a terminlhoz tartoz munkamenetben SIGHUP (hang
up", a msik oldal bontotta a kapcsolatot) betrcszs idket felidz elnevez-
s jelzst kap Ennek az alaprtelmezett kezelse a program terminlsa. Ha
ezt a jelzst figyelmen kvl hagyjuk,
74
akkor a programunk folytatja futst a
felhasznl kilpse ellenre. Ilyenkor figyelnnk kell, hogy a programot ne l-
ltsa meg egy terminlra val rs vagy olvass ltal kivltott jelzs.
5.3.2. Dmonok
A fentiek alapjn minden lnyeges ismeret a rendelkezsnkre ll, hogy meg-
rtsk a dmonok mkdst. A dmonoknak az albbi alapelvet kell kvetke-
zetesen betartania: a dmon nem fgghet az t indt terminltl, knyvtrtl
s felhasznltl.
A legfontosabb dolog az, hogy a dmon lekapcsoldjon a terminlrl Ehhez
az szksges, hogy egy j munkamenetet hozzon ltre. A setsid fggvnynek
azonban elfelttele, hogy a hv processz ne legyen mg munkamenet-vezet.
Ezt gy rhetjk el, hogy rgtn ltrehozunk egy gyermekprocesszt a fork
fggvny segtsgvel, s a gyermekprocessz hozza ltre az j munkamenetet.
A szlprocesszre nincs is szksg, rgtn kilphetnk. Az gy elrvult
gyermekprocessznek az nit lesz a szlje. Lezrjuk a szabvnyos be- s ki-
meneteket, mert a terminl lecsatlakoztatsa utn rvnytelen lehetnek a
hozzjuk tartoz lerk.
Ezek utn tlltjuk az aktulis knyvtrat a gykrknyvtrra. Ezzel
megakadlyoztuk azt, hogy a dmon fogva tartsa az aktulis knyvtrat, s
ne lehessen pldul lecsatolni. Az umaskot is lenullzzuk, hogy a dmon ne
fggjn az aktulis felhasznl belltsaitl.
Feladat Ksztsnk egy dmont, amely megadott idkznknt biztonsgi msolatot kszt a
megadott llomnyrl. A dmon parancsolj argmentumknt vegye t az llomnyt, amelyrl
biztonsgi msolatot kell ksztenie, illetve a msolat teljes tvonalt. A dmont a SIGTERM
jelzssel lehessen lelltani, s a rendszernaplba (syslog) rja az zeneteit.
74
Pontosan ezt teszi a nohup segdprogram, amely a bemenetet s a kimenetet is tirnytja.
193
5. fejezet: Prhuzamos programozs
Az eddigiek alapjn sszegezve az ltalnos lpsek az albbiak:
j folyamat ltrehozsa a fork fggvnnyel,
j munkamenet ltrehozsa,
az umask belltsa nullra,
a munkaknyvtr belltsa a gykrknyvtrra,
a szabvnyos llomnylerk bezrsa.
A feladatspecifikus lpsek az albbiak:
naplzs,
a jelzskezel megrsa s regisztrlsa,
az llomny msolsa.
Elszr a fprogramot mutatjuk be:
#defineDAEMON_NAME"back upd"
#defineBACKUP _TIME60
boolstop=false;
intmain(intargc,char*argv [])
{
if(argc<3 )
f
printf("Usage:back upd<file><back upfile>\n\n");
return-1;
}
pid_tpid,sid;
//Lefork olunk aszulotol
pid=fork ();
if(pid<0)
{
fprintf(stderr,"Hibaazuj foly amatletrehozasak ozben.")
exit(EXIT_FAILURE);
//Hasik erultafork ,nincsszuk segaszulore.
if(pid>0)
exit(ExIT_SUCCESS);
signal(SIGTERMsignal_handler);
umask (0);
iva
5.3. Processzek a Linux rendszerben
7/ Logmegny itasa
setlogmask (LOG_UP TO(LOG_INFO));
openlog(DAEmON_NAmE,LOG_CON5,LOG_USER);
sy slog(LOG_INFO,"Back updelindult.");
//Uj ,terminalnelk ulimunk amenetaprocessznek
sid=setsid();
if (sid < 0)
sy slog(LOG_ERR,"Hibaamunk amenetletrehozasak ozben.");
exit(EXIT_FAILURE);
}
//Amunk ak ony v tarbeallitasa
if((chdir("/"))<0)
sy slog(LOG_ERR,"Hibaamunk ak ony v tarbeallitasak ozben.");
exit(EXIT_FAILURE);
}
/7 A szabv any leirok lezarasa
close(STDIN_FILEN0);
close(STDOUT_FILEN0);
close(STDERR_FILENO);
//Ademonfeladatainak elv egzese
while(!stop)
back up(argy [1],argv [2 ]);
sleep(BACKUP _TIME);
sy slog(LOG_INFO,"Back updleal t.");
exit(EXIT_SUCCESS);
}
A fenti programrszletben a naplzst a syslog rendszernaplba vgezzk: az
openlog fggvnnyel nyitjuk meg, s a syslog hvssal runk bele. Mivel a lel-
ltst egy jelzs hozza a tudomsunkra, amely a stop vltozt teszi igazz. Ha
ez megtrtnik, kilpnk a programbl. Mikor SIGTERM jelzs rkezik, az
megszaktja a sleep fggvny vrakozst, a ciklusban ellenrizzk a stop
vltoz rtkt. A jelzskezel fggvny egyszer:
v oid signal_handler(intsig)
switch(sig)
caseSIGTERM:
stop=true;
sy slog(LOG_WARNING,"Receiv edSIGTERMsignal.");
break ;
195
5. fejezet: Prhuzamos programozs
default:
sy slog(t0G_wAP NING,"unhandledsignal(%d)%s",sig,
strsignal(sig));
break ;
}
}
Fontos, hogy a jelzskezel fggvnyt a gyermekproceszben regisztrljuk,
mert ez a bellts nem rkldik a szlprocessztl. Ha letelt a megfelel id,
elvgezzk a msolst:
v oidback up(char*file,char*back up)
{
intfile_fd;
intback up_fd;
structstatstat_buf;
off_toffset=0;
file_fd=open(f le,O_RDONLY);
if(file_fd<0)
{
sy slog(LOG_ERP ,"Hibaabemenetiallomany megny itasak ozben.");
return;
fstat(file_fd,&stat_buf);
if(time(NuLt)-stat_buf.st_mtime< BACKUP_TIME)
close(file_fd);
return;
}
back up_fd=open(back up,O_WRONLY;O_CREAT,stat_buf.st_mode);
i f(back up_fd<0)
{
sy slog(t0G_EP P ,
"Hibaabiztonsagiallomany megny itasak ozben.");
close(file_fd);
return;
sendfile(back up_fd,file_fd,&offset,stat_buf.st_size);
close(file_fd);
close(back up_fd);
196
5.3. Processzek a Linux rendszerben
Elsk nt lek r dezzk a z llom ny st t usz t , a mely t a r t a lma zza a nna k m r e-
t t s a z ut ols mdost s idej t is. Eb b l kisz molha t juk, hogy a z elmlt cik-
lus a la t t hozz f r t ek-e, ha igen, a sendfile fggv nnyel lem soljuk. gyelnk
a r r a , hogy a megnyit ot t llom nyler ka t minden eset b en lez r juk, nehogy a
d mon sa j t ma ga ell fogja le a z llom nyt .
tmutat A dmonok esetben a hibakeress knnyen nehzkess vlhat. Ezrt rdemes az l-
talnos funkcionalitst egy norml programban tesztelni s a letesztelt fggvnyeket tvinni a
dmonba. Az erforrs-szivrgs (pldul memria, llomnyler) a dmon hossz futsi ideje
miatt sokkal kellemetlenebb, mint egy norml programban, ezrt fokozottan figyeljnk erre.
Futtassuk a d mont :
./backupd /home/tihamer/test /home/ti hamer/test. bckp
Ha a d mon siker esen elindult , a kkor a ps seg dpr ogr a mma l megn zhet jk:
ps -A I grep backupd
13587 ? 00:00:00 backupd
A k r djel a zt jelent i, hogy a z a dot t pr ocesszhez nem t a r t ozik vez r lt er mi-
n l. Ha meg a ka r juk llt a ni a d mont , egy SIGTERM jelz st kell kldennk:
-S UGTZRM X3 :587
A fent i pa r a ncs ha t s r a a d mon legr ossza b b eset b en k t m sodper c mlva
kil p. A d mon na plb ejegyz sit a / var/log syslog szveges llom nyb a n k-
vet het jk nyomon.
5.3.3. Programok indtsa shellbl
Amikor a shell fut t a t egy kls pr ogr a mot , a z a l b b i l p seket ha jt ja v gr e:
A fork fggv nnyel l t r ehoz egy m sik shellp ld nyt Gsubsheln.
A csvezet kek ler it b e llt ja .
Az t ir nyt soka t b e llt ja .
A pr ogr a mot megker esi.
A programot elindt ja .
Vegyk sor r a ezeket a l p seket . A megold s a szok sos: elszr l t r e kell
hozni a pr ocessz m sola t t , ma jd a gyer mekpr ocesszb e t lt jk a fut t a t a nd
pr ogr a mot . Ha a z elt r b en indt juk a pr ogr a mot , a shell v r a kozik a gyer -
mekpr ocessz v g r e, ha a h t t r b en indul, a kkor egy list b a n elt r olja a gyer -
197
5. fejezet: Prhuzamos programozs
mekprocessz azonostjt, majd vrakozs nlkl visszaadja a vezrlst a fel-
hasznlnak. Ha egy parancsban tbb programot indtottunk, akkor minden
progam szmra ltrejn egy shell, mindegyikk az eredeti processz gyerme-
ke. Nzzk a kvetkez pldt:
ps -A Igrep daemon I more
Ekkor hrom gyermekprocessz jn ltre, amelyek rendre a ps, a grep s a mo-
re programokat futtatjk.
Ezek utn a shell belltja a csvezetkeket. A nvtelen csvezetkeket
mg a fork hvs eltt ltrehozta, itt csak be kell ktnie" ket. A ps processz
kimenett tirnytja az els csvezetk bemenetre, a grep bemenett annak
kimenetre. Hasonlan az elbbiekhez, a msodik csvezetk bemenett a
grep kimenetre s a more bemenetre ktjk.
A kvetkez lps az tirnytsok elvgzse. (Erre a 4.1.8. llomnyok
tirnytsa alfejezetben mutattunk pldt.) Ezek utn a shell megkeresi a
programot az aktulis knyvtr, illetve a krnyezeti vltozk segtsgvel;
majd meghvja az execve fggvnyt tadva a program elrst, agumentumait
s a krnyezeti vltozkat. Ezzel elkezddik a program betltse (lsd a 3.4.1.
A betlttt program alfejezetben). A program futsa utn a gyermekprocessz
kilp. Ezrt, ha a gyermekprocesszben mdostjuk a krnyezeti vltozkat,
ezt sem az eredeti shellprocessz, sem a tbbi gyermekprocessz nem rzkeli.
5.3.4. Jogosultsgok
Mivel a programkdot processzek futtatjk, ezrt a Linux a hozzfrs-szab-
lyozst is ezen a szinten valstja meg. Ez els megkzeltsben igen egyszer.
A kernel hozzrendeli a processzt futtat felhasznlnak s a csoportjnak az
azonostjt a processzhez. Ezt (valdi) felhasznli azonostnak (freall
user identifier, rviden user ID, uid), illetve (valdi) felhasznli csoport-
azonostnak (freal] user group identifier, rviden group ID, gid) nevezzk.
Amikor a processz hozz akar frni egy erforrshoz, akkor a kerne] ellenrzi
a jogokat. A legegyszerbb az lenne, ha ezen kt azonost alapjn ellenriz-
nnk a jogosultsgokat. Ennl azonban a POSIX opercis rendszerek jval
rugalmasabb megoldst knlnak: a megszemlyests egy formjt teszik le-
hetv. Ez azt jelenti, hogy be tudjuk lltani, hogy a futtathat program ne
az indt processz azonostjval fusson, hanem a tulajdonosval. A kernel ezt
gy kezeli, hogy a jogosultsgok mellett eltrol kt tovbbi jelzbitet: a setuid
(set user identifier upon execution, azaz: lltsd t a felhasznli azonostt fut-
tatskor), illetve a setgid (set group identifier upon execution, azaz: lltsd t a
felhasznli azonostt futtatskor). Ha ezeket belltjuk egy futtathat llo-
mnyra, akkor a kernel ezeket a tulajdonosuk (setuid), illetve a tulajdonos
csoport csoportvezetje (setgid) nevben futtatja.
198
5.3. Processzek a Linux rendszerben
Ugyanakkor az sem clszer, hogy a kernel valban tlltsa az processz
felhasznli azonostjt, hiszen ez fontos informci. Ezrt azt a megoldst
kveti, hogy nyilvntart kt tllthat" azonostt, amelyek a jogosultsg
szempontjbl a tnyleges azonostk. Ennek neve effektv felhasznli
azonost (effective user identifier, euid), illetve effektv csoportazonost
(effective group id, egid). Tulajdonkppen ezek az igazi" azonostk, hiszen a
kernel ket vizsglja, amikor azt ellenrzi, hogy egy folyamat hozzfrhet-e
egy erforrshoz. Ezt az albbiak szerint teszi.
Korbban lertuk a jogok hrmas tagolst: az els a tulajdonos jogait
tartalmazza, a msodik a tulajdonos csoportjnak a jogait foglalja magban, a
harmadik pedig mindenki mst. Ennek szellemben a kernel ellenrzi, hogy
az adott effektv azonostval rendelkez felhasznl a tulajdonos-e, ha igen,
akkor ellenrzi, hogy az els tagot figyelembe vve van-e a processznek jogo-
sultsga az adott mveletre. Ha nem tulajdonos, akkor ellenrzi, hogy a
processz effektv csoportazonostja megegyezik-e az erforrs tulajdonos-
val, ilyenkor a jogosultsgok msodik tagjt veszi figyelembe. Ha egyik eset
sem teljeslt, akkor a harmadik tagot veszi figyelembe.
Termszetesen az egsz biztonsgi mechanizmust kijtszhatv tenn, ha
brki llthatn ezeket az azonostkat. A felhasznli s csoportazonostt
csak a root felhasznl nevben fut program (vagyis amelynek az effektv
azonostja a root felhasznl azonostja, amely konvenci szerint 0) vltoz-
tathatja. A root nevben fut a login program, amely bejelentkezs utn a
shellt mr a bejelentkezett felhasznl nevben futtatja.
Vizsgljuk meg rszletesen, hogy a programindtsnl a kernel hogyan l-
ltja be a jogosultsgokat. A fork hvs lemsolja a vals s az effektv felhasz-
nli s csoportazonostkat. Az exec hvs rtelmezi a setuidlsetgid biteket:
ezeknek megfelelen tlltja az effektv azonostkat. Mieltt azonban ezt
megtenn, eredeti rtkket elmenti kt azonostba: az elmentett felhasz-
nli azonostba (saved user identifier) s az elmentett csoportazonos-
tba (saved group identifier). Ez utbbi kt azonostt a kernel kizrlag erre
hasznlja. A valdi azonostkat az exec nem vltoztatja, s ha a setuidlsetgid
bitek nincsenek belltva, akkor az effektveket sem.
Amikor teht a login processz elindtja a parancsrtelmezt (nem setuid/
setgides program), akkor az a root nevben indul el. Ezutn a login tlltja a
parancsrtelmez jogosultsgait a bejelentkezett felhasznl jogosultsgaira
az albbi fggvnyekkel:
#include unistd.h
int setui d(ui d_t uid);
int setgi d(gi d_t gi d) ;
Ezeket a fggvnyeket csak a root nevben lehet futtatni, amely a login prog-
ram esetn teljesl is. A set szt getre cserlve a fggvnyevekben a megfelel
lekrdezst megvalst fggvny nevt kapjuk. Ez igaz az albbi kt fgg-
vnyre is.
199
int seteuid(uitLt ewid);
nt setagid(gilLt e9j,d);
5. fejezet: Prhuzamos programozs
A effektv azonostk lltst a kvetkez fggvnyekkel vgezhetjk:
A norml felhasznl csak a sajt valdi vagy az effektv felhasznli, illetve
csoportazonostt hasznlhatja rtkknt. A root felhasznlra nincsenek
ilyen megktsek.
tmutat Az albbi szablyok segtenek eligazodni az azonostk vilgban. Az erforrshoz
val hozzfrs eldntsre az effektv azonostk szolglnak. Ha a setuidlsetgid bitek nin-
csenek belltva, az effektv azonostk a valdi azonostk rtkeit veszik fel. Kzhely, hogy a
setuidlsetgid bitek belltsa biztonsgi rseket okozhat a rendszeren, ezrt kivteles esetben
s akkor is nagyon krltekinten alkalmazzuk.
A Linux hasznl egy llomnyrendszer-felhasznli azonostt s -csoportazo-
nostt (file system user identifier, file system group identifier) is. A Linux ezt
hasznlja az llomnyrendszerhez val hozzfrs jogosultsgainak az eldnt-
sre. Mivel a kernel mindig gondoskodik rla, hogy ez megegyezzen az effektv
azonostkkal, ezeknek nincs klnsebb jelentsgk, ltezsnek rg elavult
okai vannak. Elviekben ezeket kln is llthatjuk, de rtelmetlenl okoz-
nnk gondot magunknak s a virtulis krnyezetnknek
5.3.5. Felhasznli nevek s csoportnevek
Amint korbban rszleteztk, a Linux biztonsgi modellje szmokat hasznl
a felhasznlk s a csoportok azonostsra. Pldaknt mr emltettk, hogy
a root felhasznl azonostja O. A felhasznlk szmra azonban tbb infor-
mcit nyjtanak s knnyebben kezelhetk a nevek. A neveket, a szmokat
s szmos fontos informcit kt rendszeradatbzis, az /etc/passwd s az
/etc/group trolja. Ebben a fejezetben megvizsgljuk, hogyan lehet ezeket az
informcikat a programunkban elrni.
Amikor a rendszertl azonostkat krdeznk pldul a statO rendszer-
hvssal az llomny felhasznli s csoportazonostjt , akkor mindig
szmokat kapunk vissza. Ha ezt a felhasznl szmra rtelmezhet formba
szeretnnk hozni, akkor t kell alaktanunk nevekk, ahogy pldul az Is
program is teszi.
Az informcik az /etc/passwd s az /etc/group llomnyokban szere-
pelnek szveges, nis, ldap s szmos egyb formtumban. Ezrt ezeket az l-
lomnyokat fggvnyeken keresztl rdemes feldolgozni.
200
felhasznaloinev */
felhasznaloij elszok odolv a*/
felhasznaloiazonosito*/
csoportazonosito*/
v alodinev */
homek ony v tar*/
she71 program*/
5.3 .P rocesszek aLinuxrendszerben
A felhasznli adatokat az azonostbl az albbi fggvnnyel rhetjk el:
#include<pwd.h>
structpasswd*getpwuid(u d_tuid);
A visszaadott struktra az /etc/passwd llomny tartalmt tkrzi:
structpasswd
{
char*pw_name; /*
char*pw_passwd;/*
uid_tpw_uid;
/*
gid_tpw-gid;
/*
char*pw_gecos;/*
char*pw_dir;
/*
char *pw_she77; /*
A csoportadatokat is hasonlan rhetjk el az albbi fggvnnyel:
#include<grp.h>
structgroup*getgrgid(gid_tgid);
A visszaadott struktrban az /etc/group llomny informcii szerepelnek:
structgroup
{
char*gr_name; /*csoportnev */
char*gr_passwd;/*csoportj elszo*/
gid_tgr_gid; /*csoportazonosito*/
char**gr_mem; /*csoporttagok */
} ;
Pldaknt nzzk az albbi egyszer programot. Ez a whowni (kivagyokn")
Unix-parancs egyszer megvalstsa, amely a felhasznli nevnket adja
vissza:
whoami.c-P eldaafelhasznaloinev -adatbazishasznalatara.*/
#include<stdio.h>
# nclude<unistd.h>
#include<pwd.h>
#include<sy s/ty pes.h>
intmain()
structpasswd*pw;
u d_tid;
201
5. fejezet: Prhuzamos programozs
/*Lek erdezzuk asaj atazonositonk at.*/
id=getuid();
/*Lek erdezzuk afelhasznaloiadatok at.*/
pw=getpwuid(id);
if(pw == NULL)
{
printf("ismeret]en\n");
return 1;
}
printf("%s\n",pw->pw_name);
return0;
A mr emltett login segdprogramnak ppen az ellenkez irnyra van szks-
ge: felhasznli nvbl kell megtudnia a hozztartoz azonostkat. Ezrt a fen-
tiekben rszletezett adatstruktrkat nv alapjn is elrhetjk. Egyfell a
#include<pwd.h>
structpasswd*cletpwnam(constchar*name);
rendszerhvssal, msfell a
#include<grp.h>
struct group*getgrnam(constchar*name);
fggvnnyel.
5.4. Szlak
A szlak prhuzamosan fut, egymstl kln temezhet, processzen belli
utastssorozatok. Mg a processzek kztt ha kln erfesztst nem te-
sznk csak a vgrehajtand kd a kzs, a szlak ugyanabban a cmtarto-
mnyban futnak. A Linux szempontjbl a szlak leginkbb knny sly
processzek (Lightweight Processes, LWP), amelyek a processzekkel szemben
megosztoznak bizonyos erforrsokon. Az egy processzen bell fut szlak k-
ztt ilyenek a kd- s az adatterletek, a megnyitott llomnylerk, a re-
kordzrolsok, a jelzselrendezsek, az idztk. Termszetesen a processzre
jellemz tulajdonsgok, pldul a processsz- s a processzcsoport-azonostk,
a vezrltermnl, a felhasznli jogosultsgok, az erforrs-hasznlati sta-
tisztikk (lsd getrusage) s a felhasznlt CPU-id (lsd times) szintn kz-
sek. A szlak ugyanakkor nem osztoznak a vermen s az utastsvgrehajts
kontextusn (processzor regiszterei).
202
5.4.Sz lak
A szlak legfbb elnye ppen a kzs erforrsokban rejlik: amikor a
kernel j szlat hoz ltre, a kzs rszeket nem kell jra ltrehoznia, vala-
mint amikor vlt a szlak kztt, a kzs erforrsokat vltozatlanul hagyja.
Ez a processzekhez kpest jelents idt takart meg a ltrehozskor, illetve az
temezskor. Mivel a szlak osztoznak a memrin, kzs vltozkat hasz-
nlhatnak, sokkal knnyebb a kommunikci. Ugyanakkor a htrnyuk is
a kzs erforrsokbl fakad: egy hibsan mkd szl az sszes szl mk-
dst befolysolhatja, illetve az egsz processzt magval rnthatja. Radsul
a kzs memria hasznlata knnyen biztonsgi rsekhez vezethet.
A szlkezelshez a legelterjedtebb programknyvtr-specifikci a POSIX
szlknyvtra, a pthread. Ezt a specifikcit Linux alatt jelenleg a Native
POSIX Thread Library (NPTL, kb. kernel ltal tmogatott POSIX-szlknyv-
tr) kveti, gy a fejezet tovbbi rszben ezt a programknyvtrat ismertet-
jk." Minden egyes NPTL-szlat egy kln kernelszl futtat. Ez a megolds
leegyszersti a szlak kernelbeli tmogatst, a jelzskezelst, az I/0 mve-
letekre val vrakozst, az temezst s a szinkronizcit. A Linux kernel-
zemmd szlkezelsnek a kulcsa a clone rendszerhvs. Ez olyan specilis
fork fggvnynek tekinthet, amelynek paramterknt thadhat az, hogy az
j processz milyen erforrsokat hoz.
A megosztott erforrsokon tl a szlak logikai mkdskben is eltrnek
a processzektl. Mg a processzek esetben ltezik szl-gyermek hierarchia,
addig a szlaknl ez nincs meg. Egy tbbszl processzben ltezik egy fszl
(main thread), amelyet az opercis rendszer elsknt indt el. Ennek belp-
si pontja tipikusan a main fggvny. Ha a fszl kilp, a processz s gy az
sszes hozztartoz szl kilp. Termszetesen, ha brmelyik szl terminlja
a processzt tipikusan az exit hvssal , vagy a processz brmilyen ms ok-
bl megsznik, a processzel egytt az sszes hozztartoz szl is kilp. A f-
szl lttl eltekintve a szlak egyenrangak.
5.4.1. Szlak ltrehozsa
Szlakat a pthread_create fggvny segtsgvel hozhatunk ltre s indtha-
tunk el:
#include<pthread.h>
intpthread_create(pthread_t*thread,pthread_*attr_tattr,
v oid*(*start_routine)(v o d*),v oid*arg);
" Az NPTL a LinuxThreads knyvtrat vltotta fel. A glibc a 2 .4 -es verzi ta az NPTL-t
hasznlja.
203
5. fejezet: Prhuzamos programozs
Ezzel a fggvnnyel egy szlat indthatunk el, amelynek belpsi pontja a
harmadik argumentumban megadott start_routine fggvny, amelynek proto-
tpusa
v oid*start_routine(v oid*param);
formban deklarlhat. Ez a fggvny egy paramtert vr, amelyet a pthread_
create fggvny utols paramtereknt adhatunk meg. Az attr paramterre
ksbb mg visszatrnk, NULL esetben az alaprtelmezett belltsokat je-
lenti. A thread argumentumban a szl lerjt kapjuk vissza. Ezt a lert a
szl azonostsra hasznljuk, ennek segtsgvel vgezhetnk tovbbi mve-
leteket s lekrdezseket a szlon. A pointerekkel ellenttben a lernak
nincs megklnbztetett rtke (NULL), amelynek alapjn el lehet dnteni az
rvnyessgt. Akkor rvnyes, ha sikeres pthread_create hvs adta vissza.
Kt lert rvnyesen a pthread_equal fggvnnyel hasonlthatunk ssze.
Nzznk egy egyszer pldt szl indtsra:
/*threadl.c-Szalinditasa.*/
#include<pthread.h>
#include<stdlib.h>
#include<stdio.h>
#include<unistd.h>
4 b
40
111
q 1111
v oid*thread_function(v oid*arg)
{
inti;
printf("Aszalindul...\n");
for(i=1;i<=2 0;i++)
printf("%d.Helloszalv ilag!\n",i);
sleep(1);
}
printf("Aszalk ilep...\n");
returnNULL;
intmain(v oid)
{
pthread_tmy thread;
if(pthread_create(&my thread, NULL, thread_function, NULL) )
{
fprintf(stderr,"Hibaaszalletrehozasaban.\n");
exit(1);
704
5.4. Szlak
sleep(5) ;
pri ntf("A foszal ki 1 ep... \n") ;
return 0;
Fordtsuk le a fenti programot:
gctthreed]..c-0 threedl-lpthread
Amikor az NPTL-t hasznljuk, ezt hozz is kell linkelnnk a programunkhoz
az -lpthread kapcsolval.
Fordts utn indtsuk is el. Ekkor az albbihoz nagyon hasonl ered-
mnyt kapunk:
S ./threadl
A foszal klep,..
AN.
Figyeljk meg, hogy nem jelent meg a terminlon a szlban tallhat printf
hvsok tbbsgnek az eredmnye. Viszont hibt sem kaptunk, a fprogram
sikeresen befejezte a mkdst.
A magyarzat abban rejlik, hogy a fprogram kln szlknt tovbb fut a
kvetkez, a
printf("A foszal kilep... \n");
sorra, majd a main fggvnybl kilp a vezrls. Mivel a fszl kilpett, a
kernel megsznteti a processzt, kilpskor lelltja a szlakat, s felszabadt-
ja a processz futshoz szksges sszes erforrst. Prbakppen helyezznk
el egy ksleltetst a programban, mieltt a main fggvnybl kilpnk:
sleep(5);
printf("A foszal kilep... \n");
return 0;
Ezutn a futsi eredmny mr hasonlt az eredeti elkpzelshez:
./threadl
A szal indul ...
1. Hello szal vilag!
2. Hello szal vilag!
3. Hello szal vilag!
4. Hello szal vilag!
5. Hello szal vilag!
A foszal ki 1 ep...
205
5.fej ezet:P rhuzamosprogramoz s
A ksleltets nem volt elg ahhoz, hogy a msodik szl befejezze a mkdst,
de mr lthat, hogy elindult, s futott egy darabig. Ezutn persze nvelhet-
nnk az idztst, de mivel minden hardveren ms az temezs idbeli lefo-
lysa, nem pthetnk r. Szksgnk van egy olyan fggvnyre, amellyel a
szlat indt fggvnybl (pldnk esetben a main fggvnybl) meg tud-
nnk vrni a szl lefutst. Erre knl megoldst a
#include<pthread.h>
intpthread_j oin(pthread_tthread,v oid**thread_return);
fggvny, amely felfggeszti a hv szl mkdst mindaddig, amg a thread
argumentumban megadott szl be nem fejezi a futst.
76
Ha a thread_return
nem NULL, akkor a szl visszatrsi rtkre mutat a sikeres visszatrs
utn. Ha ugyanarra a szlra ktszer hvjuk meg ezt a fggvnyt, a msodik
futsa mr nem definilt, ezrt ezt kerljk el. Mdostsuk a main fggvnyt
mindezeknek megfelelen:
i ntmain(v oid)
f
pthread_tmy thread;
if(pthread_create(&my thread, NULL. thread_function, NULL) )
fpr ntf(stderr,"Hibaaszalletrehozasaban.\n");
exit(1);
}
f(pthread_j oin(my thread, NULL ) )
fprintf(stderr,"Hibaaszalmegv arasaban.\n");
exit(1);
printf("A foszal k ilep... \n");
return 0;
Ezutn a msodik szl valban 2 0-ig szmol. Jl lthat, hogy melyik szl v-
rakozhat egy msik szl kilpsre, ha tudja annak azonostjt. Ez is a sz-
lak egyenrangsgt ersti: mg egy processz kilpsre kizrlag annak a
szlprocessze vrakozhat, a szlaknl ezt brmelyik ugyanahhoz a pro-
cesszhez tartoz szl megteheti fggetlenl attl, melyik hozta ltre. Ugyan-
akkor szlak esetben nem vrakozhatunk egy processzhez tartoz sszes
tbbi szl valamelyiknek a kilpsre, m egy processz esetben brmelyik
gyermekprocessz befejezdsre vrakozhatunk.
76
A pthread_tryjoin_np Linux-specifikus fggvnnyel rgtn visszatrhetnk, illetve meg-
adott ideig vrakozhatunk a szlra.
206
5.4. Szlak
A szlak s a processzek kilpse viszont nagyon hasonl. Amikor a szl
befejezi a mkdst, akkor nem szabadul fel teljesen: a zombillapothoz ha-
sonlan megmarad nhny adatstruktra, amely tbbek kztt megrzi a szl
vissszatrsi rtkt. Ezek az erforrsok csak akkor szabadulnak fel, ha a
pthreadjoin fggvnnyel egy msik szl vrakozik r. Ezt nem szeretnnk,
gy a pthread_detach fggvny sikeres meghvsa utn a szlhoz tartoz er-
forrsok a szl kilpsekor automatikusan felszabadulnak. Ilyenkor a szl
lecsatolt (detached) llapotba kerl. Ebben az llapotban a pthreadjoin h-
vsa, illetve a pthread_detach tovbbi hvsai hibt eredmnyeznek. A szl
attribtumt ltrehozs eltt kzvetlenl is lecsatolt llapotba llthatjuk
(lsd ksbb rszletesen).
A szl lecsatolt llapota nem jelenti azt, hogy a fszl kilpse utn is fut
a tbbi szl, mindssze annyit eredmnyez, hogy automatikusan felszabadul-
nak a szlhoz tartoz erforrsok.
5.4.2. Szlak ltrehozsa C++ nyelven
Vizsgljuk meg, hogy miknt lehet szlat indtani C++ nyelven. Az alapgondo-
lat a kvetkez. runk egy jra felhasznlhat Thread osztlyt, amely tartal-
maz egy tisztn virtulis ThreadMain nev fggvnyt: ez lesz a szl belpsi
pontja. Ha j szlat szeretnnk ltrehozni, leszrmaztatunk a Thread osz-
tlybl, implementljuk a ThreadMain fggvnyt, pldnyostjuk az osztlyt,
majd meghvjuk a Start fggvnyt.
Nzznk erre egy pldt. Az osztlydefinci az albbi:
#include <pthread.h>
#include <stdlib.h>
#include <stdio.h>
#include <iostream>
using namespace std;
class Thread
pthread_t thread;
bool started;
static void *ThreadStart(void *pThread);
public:
ThreadO:started(false){}
vod start();
virtual void ThreadMain() =0;
vod Join();
207
5. fejezet: Prhuzamos programozs
Mivel a pthread_t tpus vltozkrl nem lehet eldnteni hogy rvnyesek-e,
ezrt a started vltozt hasznljuk erre: sikeres szlltrehozs s -indts utn
igazra lltjuk az rtkt. A Start fggvny elindtja a szlat, a Join fggvny
vrakozik a szl kilpsre. A ThreadMain fggvny lesz a szl belpsi pontja.
A ThreadStart fggvnyt hasznljuk a pthread_create paramtereknt. Egyel-
re annyit rdemes megjegyeznnk, hogy statikusnak deklarltuk.
Az osztly hasznlatt az elz plda C++-beli verzijval szemlltetjk:
classMy Thread:publicThread
{
public:
v o dThreadMain()
{
inti;
cout"Aszalindul..."endl;
for(1=1;i<=2 0;i++)
couti".Helloszalv ilag!"endl;
sleep(1);
}
cout"A szalk lep..."endl;
};
intmain()
{
My Threadt;
t.Start();
cout"v arak ozasatobbiszalra...\n";
sleep(5);
t.Join();
}
printf("A
return0;
foszal k ilep...
\n");

Nzzk meg az osztly implementcijt. Elsknt a szl belpsi pontjt
rszletezzk. Tudjuk, hogy a C++ nyelv impliciten minden tagfggvnynek
tadja a this pointert. Mivel a pthread_ereate fggvny egy meghatrozott ar-
gumentumlistj fggvnyt vr a szl belpsi pontjaknt, a C++ fenti mk-
dse problmt okoz. Ha azonban a tagfggvnyt staticnak deklarljuk, az
pontosan azt jelenti, hogy a this pointer nem addik t. Ennek viszont az
a kvetkezmnye, hogy a statikus tagfggvny nem frhet hozz az osztly
nem statikus vltozihoz, illetve fggvnyeihez. Erre viszont felhasznlhat-
juk a szl belpsi pontjnak void* argumentumt. Mivel ezt a fggvnyt az
osztly csak az alacsony szint C programozsi fellethez val kapcsoldsra
hasznlja, a klvilg szmra nincs jelentsge, ezrt privtt tettk:
2 08
5.4.Sz lak
v oid*Thread::ThreadStart(v oid*pThread)
{
/*Atv esszuk athispointert,k onv ertalj uk azosztaly
t pusara.*/
Thread*pThis=(Thread*)pThread;
pTh s->ThreadMa n();//megh v j uk aszalat
Ezek utn mr csak meg kell hvnunk a pthread_create fggvnyt, s az j
szlnak t kell adnunk a this pointert paramterknt. Mindemellett a started
vltozt is be kell lltanunk:
v oidThread::start()
{
f(started)
{
cerr"A szalmarelindult."endl;
return;
/*Atadj uk ath spointertv oid*alak ban.*/
if(pthread_create(Sithread, NULL. Threadstart,
(v oid*)this))
{
cerr"Hibaaszalletrehozasanal.\n";
exit(1);
started=true;

m
A Join fggvny implementcija meglehetsen egyszer:
v oidThread::Join()
if(!started)
return;
if(pthread_j oin(thread, NULL))
{
cerr "Hibaaszalmegv arasaban.\n";
exit(1);
started=false;
2 09
5.fej ezet:Prhuzamos programozs
gyeljnk arra, hogy C++-programok esetn g++-t hasznljunk, vagy adjuk
hozz a gcc paramtereihez a
-1stdc++
kapcsolt is, amely hozzlinkeli programunkhoz a szabvnyos C++-knyv-
trat.
A fenti osztly clja elssorban az alapgondolat bemutatsa volt. A meg-
oldst tbbflekppen is ki lehet egszteni. Tovbbi pthread C-fggvnyeket
is egysgbe zrhatunk, vagy az osztlyon kvlrl is elrhetv tehetjk a
szl threadtagvltozban trolt lerjt, valamint lekrdezhetjk s trolhat-
juk a szl visszatrsi rtkt.
5.4.3. Szlak attribtumai
Trjnk vissza a szl attribtumainak belltsra s lekrdezsre. A szl
attribtumait a pthread_attr_t tpus trolja. Az ilyen tpus vltoz rtkt
azonban kzvetlenl nem llthatjuk, csak fggvnyekkel.
Elsknt inicializljuk a vltozt az albbi fggvnnyel, amely feltlti azt
alaprtelmezett rtkekkel:
Sinclude<pthread.h>
intpthead_attr_init(P tnrend_nttr_t*attr);
Az attribtumokat a kvetkez fggvnyekkel llthatjuk be, s krdezhetjk
le az rtkeit. A bellthat argumentumok lerst az 5.8. tblzat tartal-
mazza.
#include<pthread.h>
intpthread_attr_setdetachstate(pthread_attr_t*attr,
intdetachstate);
intpthread_attr_getdetachstate(constpthread_attr_t*attr,
int*detachstate);
intpthread_attr_setschedpolicy (pthread_attr_t*attr,
intpolicy );
intpthread_attr_getschedpolicy (constpthread_attr_t*attr,
int*policy );
i ntpthread_attr_setschedparam(pthread_attr_t*attr,
conststructsched_param*param);
2 10
5.4. Szlak
int pthread_attr_oetschedparam(const pthread_attr_t *attr,
struct sched_param *param);
int pthread_attr_setinheritsched(pthread_attr_t *attr,
int i nher t) ;
int pthread_attr_getnheritsched(const pthread_attr_t *attr,
int *inherit);
int pthread_attr_setscope(pthread_attr_t *attr, int scope);
nt pthread_attr_getscope(const pthread_attr_t *attr, int*scope);
Ezutn tadhatjuk az attribtumot pthread_create fggvnynek, amelynek a
meghvsa utn az albbi fggvnnyel szabadthatjuk fel az adatstruktrt:
#include pthread.h
int pthread_attr_destroy(pthread_attr_t *attr); Mei
Ezzel a fggvnnyel megszntethetjk az attribtumot, amelyet csak egy j
pthread attr_init fggvnyhvs utn hasznlhatunk. Ennek a fggvnynek a
Linux alatti implementcija semmit sem csinl, ennek ellenre a POSIX-
kompatibilits miatt rdemes lehet hasznlni.
5.8. tblzat. Szlak attribtumai
Attribtum Attribtum leirsa
detachstate Kt rtke lehet: PTHREAD_CREATE_JOINABLE (alaprtel-
mezs), illetve PTHREAD_CREATE_DETACHED. Az elbbi a
szl csatlakoztathat llapota, a msik a lecsatolt.
schedpolicy Lehet SCHED_OTHER, amely az alaprtelmezett, nem vals
idej temezs, valamint kt vals idej temezs, a
SCHED_RR egy krbeforg (round-robin); a SCHED_FIFO pedig
FIFO-prioritst jelent. A kt utbbihoz a processznek root jogok-
kal kell rendelkeznie.
schedparam Az temezsi priorits a kt vals idej temezsre.
inheritsched Az alaprtelmezs PTHREAD_EXPLICIT_SCHED, ha az j szl
belltsai (shedpolicy, shedparam) a mrvadak,
PTHREAD_INHERIT_SCHED, ha a ltrehoz szl belltsait
veszi t az j szl.
scope Lsd a kziknyvben.
211
5. fejezet: Prhuzamos programozs
A szl temezsi paramtereit ltrehozs utn is vltoztathatjuk, illetve le-
krdezhetjk a
#include <pthread.h>
int pthread_setschedparam(pthread_t target_thread, int policy,
const struct sched_param *param);
int pthread_getschedparam(pthread_t target_thread, int *policy,
struct sched_param *param);
fggvnyek segtsgvel, amelynek argumentumai megegyeznek a fent trgyalt
pthread_attr_t struktra megfelel tagjaival. A szl lemondhat az idszeletnek
maradk rszrl a pthrea,d_yield0 hvssal, ezzel utat engedve a tbbi szl fu-
tsnak. Ilyenkor a hv szl a futtatand szlak sornak a vgre kerl. En-
nek a fggvnynek az indokolt alkalmazsra nagyon ritkn kerl sor.
5.4.4. Szlbiztos fggvnyek
Nzzk tovbb a szlakkal kapcsolatos lehetsgeket. Ha egy olyan fggvnyt
szeretnnk rni, amelytl elvrjuk, hogy emlkezzen az elz hvsokra is
(ilyen tbbek kztt a szabvnyos knyvtrban az strtok0 fggvny), akkor
szksgkppen statikus vltozkban knyveljk az aktulis llapotot. Ha
azonban egy ilyen fggvnyt tbb szlbl hvunk, a statikus vltoz rtkt
knnyen elronthatjuk kt hvs kztt.
Feladat Ksztsnk olyan ksleltet" fggvnyt, amely egy egsz rtket vesz t argumentum-
knt, s az elz hvskor kapott argumentummal tr vissza. A legels hvsra adjon vissza nullt.
Az els naiv megolds a statikus vltozk okozta problmkra vilgt r:
int delay(int value)
{
stati c int prev =0;
int retval =prev;
prev =value;
return retval ;
=11111iiien..".
Ezt a fggvnyt kitnen hasznlhatjuk egyszl programban. Az albbi
esetben viszont kt szlbl hvjuk:
212
5.4.Sz lak
v oid*thread_function(v oid*arg)
inti;
printf("Aszalindul...\n");
for( =1; <=5; ++)
Azi
( r
printf("Mellek szal.Elozo:%d.Ak tualis:%d\n",delay (i),i);
sleep(1);
printf("Aszalk ilep...\n");
returnNULL;
intmain(v o d) {
Ipthread_tmy thread;
inti;
if(pthread_create(8dmy thread,NULL,thread_function,NULL))
t
fpr ntf(stderr,"Hibaaszalletrehozasaban.\n");
11
II
exit(1); }
for(i=10;i<=15;i++)
printf("Foszal.Elozo:%d.Ak tualis:%d\n",delay (i),i);
sleep(1);
if(pthread_j oin(my thread,NULL))
{
fprintf(stderr,"Hibaaszalmegv arasaban.\n");
exit(1);
printf("Afoszalk ilep...\n");
return0;
A fszl 10-tl 15-ig szmol, mg a mellkszl 1-tt 5-ig. A program kimenete
az albbi:
Foszal.Elozo:0.Ak tualis:10
Aszalindul...
Mellek szal.Elozo:10.Ak tualis:1
Foszal.Elozo:1.Ak tualis:11
Mellek szal.Elozo:11.Ak tualis:2
Foszal.Elozo:2 .Ak tualis:12
Mellek szal.Elozo:12 .Ak tualis:3
213
5. fejezet: Prhuzamos programozs
Foszal. Elozo: 3. Aktualis: 13
Mellekszal. Elozo: 13. Aktualis: 4
Foszal. Elozo: 4. Aktualis: 14
mellekszal. Elozo: 14, Aktualis: 5
Foszal. Elozo: 5. Aktualis: 15
A szal kilep...
A foszal kilep.
Jl lthat, hogy a kt szl ltali elz hvsok rtkei sszekeverednek.
tmutat Tbbszl programokbl hvott fggvnyben ne hasznljunk globlis s statikus vl-
tozkat az elz hvs adatainak az elmentsre.
Azokat a fggvnyeket, amelyeket tbb szlbl biztonsgosan hvhatunk,
szlbiztos fggvnyeknek (thread-safe functions) nevezzk. Linux alatt a
pthread kziknyvoldala tartalmazza a nem szlbiztos fggvnyek listjt.
Meg kell jegyezni, hogy tbbszl krnyezetben az errno sem globlis vltoz,
hanem egy makr, amely szlbiztos fggvnyeket hv.
A globlis s statikus vltozk helyettestsre lehetsgnk van az egyes
szlakhoz tartoz memriaterletek, a szlspecifikus adatok (Thread
Specific Data) hasznlatra is, amelyek egy szlon bell globlis adatterle-
tet jelentenek, ms szlak szmra azonban hozzfrhetetlenek. Ez az adat-
terlet lnyegben egy asszociatv tmb, amely kulcs-rtk prokat trol.
Az rtk tpusa void* pointer. Ltrehozs s inicializls utn a kulcs alapjn
kaphatjuk meg a pointer rtkt.
Elszr teht ltre kell hozni egy kulcsot:
int pthread_key_create(pthread_key_t *key,
ffiig11111ffitew
,
- _
void(*destr_function) (void* ));
A fggvnyhvs utn az els paramterben kapjuk vissza a kulcsot. Ezen k-
vl megadhatunk egy, az rtket felszabadt destruktorfggvnyre mutat
pointert is. Ez a fggvny automatikusan meghvdik minden nem NULL r-
tk kulcs adattagjra, ha a szl futsa vget't.Minden olyan szlra megh-
vdik, amelyben hasznltuk ezt a kulcsot. Mivel a fszl kilpse a program
vgt jelenti, gy ott nem hvdik meg. A fggvny a kulcshoz rendelt void*
pointer rtket kapja meg felszabadts cljbl.
A void* pointert az albbi fggvny rendeli a mr ltrehozott kulcshoz:
i nt pthread_setspeci fi c(pthread_key_t key, const voi d*poi nter) ;
amelyet a
void pth read_getspeci fi c(pthread_key_t key) ;
fggvny segtsgvel krdezhetnk le.
214
5.4. Szlak
Kulcsot a
intpthread_k ey _delete(pthread_k ey _tk ey );
hvssal szabadthatunk fel. Ez a fggvny nem szabadtja fel az rtket, csak
a kulcsot. Ha kizrlag programknyvtrban hasznljuk, akkor a knyvtr
tisztogatfggvnyben rdemes meghvnunk. Ha a fprogram brmikor
hasznlhatja a kulcsot, akkor elfordulhat olyan dnts, hogy csak a program
kilpsvel szabaduljon fel a kulcs.
Egy kulcs tbb szlban is hasznlhat, nem kell minden egyes szlnak
kulcsot ltrehozni, elg a legels hvsnl. Ezt az egyszeri inicializlst tmo-
gatja az albbi fggvny:
#include<pthread.h
intpthread_once(pthread_once_t*once_control,v oid(*init)(v oid));
A fggvny tbbszri hvs esetn is csak az els alkalommal hvja meg a m-
sodik argumentum fggvnypointere ltal kijellt fggvnyt, mg akkor is, ha
ezek a hvsok klnbz szlakbl rkeznek. Mivel a pthread_once fggvnyt
tbb klnbz fggvny egyszeri hvsra alkalmazzuk, mindegyik iniciali-
zlst egy kln vltozval jelezzk. Pldul az albbiakban egy kulcs egy-
szeri inicializlst szeretnnk belltani, ezt a key_init vltozval jelljk ki:
staticpthread_once_tk ey _init=P THREAD_ONCE_INIT;
Ezek utn nzzk meg a feladat megoldst szlspecifikus adatok segtsg-
vel. A ksleltetst az albbi fggvnnyel implementljuk:
staticpthread_once_tk ey _init = PTHREAD_ONCE_INIT;
i ntdelay (intv alue)
i nt*ptr,prev ;
pthread_once(&k ey _init,create_k ey _once);
ptr=pthread_getspecific(k ey );
if(ptr==NULL)
ptr=malloc(sizeof(int));
pthread_setspecific(k ey ,ptr);
prev =0;
else
{
prev =*ptr;
*ptr=v alue;
returnprev ;
215
5. fejezet: Prhuzamos programozs
Ezt a fggvny tbb szl hvja, de csak a legels alkalommal kell inicializlni.
Erre nem hasznlhatunk statikus vltozt, mert a vltoz belltsa s az
inicializls nem lenne atomi mvelet. Pontosan ez az a szolgltats, amelyet
a pthread_once nyjt. A kulcs ltrehozsa utn megnzzk, hogy az adott h-
vst futtat szl szlspecifikus adatai kztt szerepel-e mr a kulcsunk. Ha
nem, akkor a delay fggvny ebbl a szlbl most hvdott meg elszr. Ekkor
ltrehozzuk a kulcsot, s nullval trnk majd vissza. Ha a kulcs mr benne
volt az asszociatv tmbben, akkor krnk az rtkre egy pointert, s annak
mutatott rtkvel visszatrnk. Vgl mindkt esetben az adatot a pointe-
ren keresztl az aktulis rtkre lltjuk.
Ezutn a kulcs ltrehozst vgz fggvnyt s az rtkek felszabadtst
mutatjuk be:
static pthread_key_t key;
void destructor (void* value)
free(val ue) ;
}
void create_key_once()
{
pthread_key_create(&key, destructor);
Az ltalnos megolds szemlltetshez a feladatot kiss tlbonyoltottuk. Ha
csak egy int rtk trolsrl van sz, azt oda-vissza konverzi alkalmazsval
eltrolhattuk volna a pthread_setspecific msodik argumentumban szerepl
void* pointerben is. Ekkor nincsenek dinamikus rtkek, ezrt a destruktor-
fggvnyre sincs szksgnk. Ez esetben a pthred_create_key msodik argu-
mentumaknt NULL-t adunk t.
Vgl egy jval egyszerbb, ugyanakkor nem POSIX-szabvny szerinti
megoldst mutatunk be. A megolds neve szlanknti trol (thread-local
storage). Ez lnyegben egy vltozdeklarcit jelent, amelyet a _thread kulcs-
szval adunk meg rgtn a static vagy az extern utn. Az gy deklarlt vltoz-
nak ugyangy adhatunk kezdeti rtket, mint brmelyik msik statikus vagy
globlis vltoznak. A vltoz lehet tmb is, pldnkban elg egy egsz:
~51~~itil, WhalE111~111~11~111~
Ezek utn csak hasznlnunk kell a vltozt a hibs eredeti fggvnynket
nem sokban mdostva:
int delay(int value)
int retval = prev;
prev = value;
return retval;
216
5.4. Szlak
A szlanknti trolkat a Linux a 2 .6-os kernel ta tmogatja, a gcc a
_thread kulcsszt a 3.3-as verzi ta.
Ha a szlbiztonsg problmja nem a fggvnyhvsok kztti informci
megjegyzsben rejlik, mint a pldnkban, hanem kzs adatterletek egy-
szerre trtn konzisztens mdostsban, akkor ms eszkzkhz kell fo-
lyamodnunk (Ezeket az eszkzket az 5.5. POSIX-szinkronizci alfejezetben
mutatjuk be rszletesen.)
5.4.5. Szl lelltsa
A szlbl val kilpst kezdemnyezhetjk a szlon bellrl (a szl befejezte a
futst), illetve egy msik szlbl. Ebben a fejezetben ezt a kt esetet vesszk
sorra.
A szlon bellrl egyszer dolgunk van. Ha visszatrnk a szl belpsi
pontjt implementl fggvnybl (a pthread_create fggvny argumentuma),
akkor a szl automatikusan kilp. Ha ms fggvnybl szeretnnk befejezni a
szl futst, akkor ezt a pthread_exitQ hvssal tehetjk meg.
Ha msik szlbl szeretnnk meglltani a szlat, akkor sokkal bonyolul-
tabb a feladat. A szl gy trtn meglltst a szl trlsnek (thread
cancellation) nevezzk. Mivel a szlak memrit s ms erforrsokat foglal-
nak, ha brhol trlhetjk (kilhetjk") a szlat, akkor elfordulhat, hogy
ezek az erforrsok nem szabadulnak fel. Ha a szl valamilyen szlak kztt
megosztott adatstruktrn vgez mveletet, s a lellts miatt nem fejezi be,
akkor nem engedi el a szinkronizcis objektumokat, valamint a megosztott
adatstruktrt is inkonzisztens llapotban hagyhatja. Mg a processzeknl az
opercis rendszer fel tudja szabadtani a processzekhez tartoz erforrsokat,
a szlaknl a kzs erforrsok miatt ez automatikusan nem oldhat meg.
A POSIX megoldsa az, hogy a szlak expliciten megadnak olyan pontokat
a programvezrlsben, ahol a szl lellthat. Ezeket trlsi pontoknak (can-
cellation point) nevezzk. Ilyen pontokat gy lehet megadni, hogy egy olyan
knyvtri fggvnyt hvunk, amely trlsi pont. Kln kiemeljk az albbi
fggvnyt, amelynek kizrlagos funkcija, hogy trlsi pontot definiljon:
#include<pthread.h>
v oidpthread_testcancel(v oid);

Ezen knyvtri fgvnyek listjt a pthreads(7) kziknyvoldala tartalmazza.


Amikor a szl futsa egy trlsi ponthoz rkezik, s trlsi krelem rkezett a
szlhoz, akkor a szl futsa megszakad, s a szl visszatrsi rtke
PTHREAD CANCELED lesz.
217
5. fejezet: Prhuzamos programozs
tmutat A trtt nem lecsatolt szlra se felejtsk el meghvni a pthreadjoin fggvnyt.
A norml visszatrs sorn ne hasznljuk a PTHREAD_CANCELED rtket, mert a pthreadjoin
fggvny visszatrsi rtkbl nem tudjuk eldnteni, hogyan lpett ki a szl.
Egy szl trlst egy msik szlbl meghvott pthread_cancel fggvnnyel
krhetjk:
#i ncl ude <pthread .h>
i nt pthread_cancel (pth read_t th read) ;
A fggvny rgtn visszatr fggetlenl attl, hogy azonnal sikerlt-e trlnie
a szlat, vagy csak a krst kldte el, s a szl futsa csak a kvetkez trlsi
pont elrsekor szakad meg.
Az eddigiek alapjn egyrtelm: a legfontosabb problma, hogy a trlsi
pontot gy hatrozzuk meg, hogy a kzs erforrsokat megfelel llapotban
hagyjuk, a szlhoz tartoz erforrsokat pedig felszabadtjuk.
Elsknt nzzk meg azt az esetet, amikor a szl mkdse megszakthatat-
lan, mert a vezrls minden pontjn kapcsolatban van valamilyen erforrssal.
Ekkor egyszeren letiltjuk a trlst. Ezt az albbi fggvnnyel tehetjk meg:
int old;
pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &old); l e i m m i i i m i e e r
A msodik paramter az elzleg belltott rtket adja vissza. Linux alatt
lehet NULL, de a POSIX-szabvny szerint nem, gy a fenti a hordozhat meg-
olds. Ha letiltottuk a trlst, a trlsi krelem hatstalan mindaddig, amg
nem engedlyezzk a trlsi krelmeket:
int old;
pthread_setcancel state (PTHREAD_CANC
IIIMMIIII
~ EL_iJRL, &P l
Vegyk azt az esetet, amikor ilyen erforrsok nincsenek. A szl nagyon egy-
szer feladatot hajt vgre, nem foglal erforrsokat, nincs kapcsolatban
szinkronizcis objektumokkal. Ez a mkds brmikor megszakthat. Ezt a
ritka esetet az albbiak szerint engedlyezhetjk:
int old;
pthread_setcanceitype(PTHREAD_CANCEL_ASYNCHRONOUS, &old);
Egybknt ksleltetett trlst lltunk be:
int old;
pthread_setcanceltype(PTHREAD_CANCEL_DEFERRED, &old);
218
5.4.Sz lak
A fggvny a pthread_setcancelstate-hez hasonlan a msodik argumentumban
az elzleg belltott rtket adja vissza. A ksleltetett trls pontosan azt je-
lenti, hogy a szl futsa a legkzelebbi trlsi pont elrsekor szakad meg.
Leggyakrabban azonban a szlnak dolgoznia kell a megosztott adatokkal,
s erforrsokat is foglal. Amikor a megosztott adatok inkonzisztens llapot-
ban lehetnek tipikusan egy szinkronizcis objektum lefoglalsa s elenge-
dse kztt , akkor ott nem definilunk trlsi pontot. Ilyenkor vgig kell
kvetnnk a program futst, hogy nem hasznlunk-e olyan fggvnyt,
amely trlsi pont. Ha valamirt mgis szksgnk van ennek hvsra, ak-
kor a pthread_setcancelstate fggvnnyel letiltjuk, majd engedlyezzk a tr-
lst. A kett kztti trlsi krs nem veszik el.
Erre a problmra egy msik megolds amely megoldja a felszabadtand
erforrsok problmjt is a tisztogat kezelfggvnyek (cleanup hand-
ler) alkalmazsa. Ezek a fggvnyek vgzi az erforrsok felszabadtst.
A kezelfggvnyeket egy verembe rendezzk. Ha a szl futsa sorn egy
jabb erforrst vagy szinkrinizcis objektumot foglalunk le, akkor annak
tisztogat kezelfggvnyt a verem tetejre rakjuk. Ha a futs sorn a szl
elri azt a pontot, ahol elengedjk a szinkronizcis objektumot s az erfor-
rst, akkor a kezelfggvnyt eltvoltjuk a verem tetejrl. Ha a szlat egy
trlsi pontban egy msik szl trli, a veremben tallhat sszes fggvny a
verem tetejrl kezdve automatikusan meghvdik, vagyis a betevs fordtott
sorrendjben. Ugyanez trtnik a pthread_exit hvsakor. Ha viszont a bel-
psi pontot implementl fggvnybl return-urastssal trnk vissza, ak-
kor ez az automatikus felszabadtsi mechanizmus nem hajtdik vgre:
#include<pthread.h>
v o dpthread_cieanup_push(v oid(*routine)(v oid*),o d*arg);
v oidpthread_cleanup_pop(intexecute);
A cleanup push fggvny segtsgvel a verem tetejre helyezhetnk egy
fggvnyt, amelynek az utols argumentumban egy paramtert is tadha-
tunk. A fggvny deklarcija az albbi:
v oidroutine(v oid*param)
A pthread_cleanup_pop kivesz egy fggvnyt a verem tetejrl, s ha az ar-
gumentuma nem nulla, le is futtatja.
Ennek a megoldsnak fontos jellemzje, hogy a lefoglals s a felszabad-
ts sorrendje kttt: a verem kezelst egymsba gyazott push s pop prok
valstjk meg. Ez nem csak a felszabadts sorrendje miatt ktelez: a kt
fggvny makrkkal van megvalstva. A makrk a fggvnyhvson kvl
mg egy blokkot is definilnak: a push egy nyit kapcsos zrjelre vgzdik
2 19
5. fejezet: Prhuzamos programozs
({"), a pop pedig egy bezr zrjellel (}") kezddik, vagyis egy utastsblok-
kot definilnak. Ezrt az utastsblokkok szerint prban kell lennik, nem
lehet egyik mlyebben, mint a msik.
5.4.6. Szlak s a fork/exec hvsok
A fork mkdse viszonylag egyszeren lerhat egyszl processz esetben.
Tbbszl programoknl viszont mr nem az eredeti processz msa kszl el,
hanem csak az a szl jelenik meg az j processzben, amelyik a forkot hvta ez
a szl megrzi a szlazonostjt. A tbbi szlnak semmifle tisztogatmecha-
nizmusa nem hvdik meg: sem a szlspecifikus adatokra, sem a tisztogat ke-
zelfggvnyekre. A szinkrinizcis objektumok s a globlis vltozk llapota
ugyancsak megrzdik. Ez knnyen inkonzisztencihoz s az erforrsok szi-
vrgshoz vezethet.
tmutat Prbljuk elkerlni a fork hvst tbbszl programbl, azt az egy esetet lesz-
mitva, amikor rgtn utna meghvjuk az exec fggvnyt.
Ha valamirt ez mgsem lehetsges, tipikusan azrt, mert egy program-
knyvtrat ksztnk, amely tbb szlat hasznl, s a fprogram nem is tud
arrl, hogy tbb szl is fut a processzen bell. Ennek megoldsra regisztrl-
hatunk hrom fggvnyt: egy a fark hvs eltt hvdik meg a majdani
szlprocesszben, a msodik a fork utn a szlben, a harmadik a fork utn a
gyermekprocesszben. A fggvnyek regisztrlsra a pthread_atfork fgg-
vnyt hasznlhatjuk:
#incl ude <pthread. h>
int pthread_atfork(voi d (*prepare) (voi d) , void (*parent) (voi d)
void (*chi 1d) (voi d)) ;
Ezzel a hvssal egyszerre tbb fggvnyt regisztrlhatunk mindhrom sze-
repre.
Az exec hvs jval egyszerbb, hiszen ilyenor az egsz processzt kicserli
a betlttt kd. A processzhez tartoz szinkronizcis objektumok szintn
megsznnek. Csak a fggvnyt hv szl marad meg, annak azonostja br-
mi lehet, sem a szlspecifikus adatok destruktorfggvnyei, sem a tisztogat
kezelfggvnyek nem hvdnak meg. Ezek a fggvnyek az exit hvs esetn
sem hvdnak meg.
220
5.5. POSIX-szinkronizci
5.5. POSIX-szinkronizci
Az 5.2. Processzek kztti kommunikci (IPC) cm alfejezetben ismertettk
a processzek kztti szinkronizcis eszkzket. Jllehet jelenleg a System V
IPC is a POSIX-szabvny rsze, ez nem volt mindig gy, gy ltezik kt hason-
l funkcionalits prhuzamosan egyms mellett. Ugyanakkor a System V IPC
objektumait a kernel kezeli, szlak kztt erforrs-pazarls lenne ket hasz-
nlni. Ezrt szlak kztt mindig POSIX-szinkronizcit hasznlunk, amelyre
az NPTL gyors, felhasznli cmtrben implementlt szinkronizcis megol-
dsokat nyjt. Ezeknek a szinkronizcis objektumoknak az alapja a futex
(fast, user-space mutex, gyors felhasznli cmtrbeli mutex").
A System V IPC-ben a kzs szinkronizcis objektumokat a klnbz
processzekbl a nevk alapjn azonostottuk. Az egyik processz ltrehozta, a
msik pedig a nevvel hivatkozott r, s gy szerezte meg a lert a mr ltre-
hozott objektumra. A POSIX-szinkronizci esetn csak a megnevezett objek-
tumok (szemafor, zenetsor, megosztott memria) adnak erre lehetsget, a
tbbi esetben a megosztott memriaterleten dinamikusan kell ltrehoznunk
a szinkronizcis objektumokat, ha processzek kzt szeretnnk hasznlni.
5.5.1. Klcsns kizrs (mutex)
A klcsns kizrs (Mutual Exclusion, mutex) a szlak szinkronizcijnak
hasznos eszkze. A mutexnek kt lehetsges llapota van: foglalt (locked),
amikor egy szl lefoglalta a mutexet, illetve szabad (unlocked) llapot, ami-
kor egy szl foglalta le a mutexet. A mutexet egyszerre csak egy tarthatja
foglalt llapotban.
A mutex tpusa (type) azt mondja meg, hogy mi trtnik akkor, ha szl
elengeds nlkl ktszer prbl lefoglalni egy mutexet. Linux alatt a hrom-
fle tpus mutex van:
gyors (fast),
rekurzv (recursive),
s a hibaellenrz (error checking).
Gyors mutex esetn az adott szl arra vrakozik, hogy a sajt maga ltal
mr lefoglalt mutex felszabaduljon. Nyilvnvalan a mutexet csak ez a szl
tudn felszabadtani, vagyis ekkor vgtelen ciklusba kerlnk.
A hibaellenrz mutex esetn a lefoglalst vgz fggvny rgtn hib-
val tr vissza. Rekurzv mutex esetn a szl jra lefoglalja a mutexet, s
ahhoz, hogy a mutex ms szlak ltal jra lefoglalhatv vljon, mindannyi-
szor el kell engednie, ahnyszor lefoglalta.
221
5. fejezet: Prhuzamos programozs
A mutex tpust a vltoz kezdeti rtkeknt is megadhatjuk statikus ini-
cializlkkal:
#include <pthread.h>
pthread_mutex_t fastmutex = P THREAD_MUTEX_INITIALIZER;
pthread_mutex_t recmutex = P THREAD_RECURSIVE_MUTEX_INITIALIZER_NP :
pthread_mutex_t errchkmutex =
P THREAD_ERRoRcHEac_muTEX_INITIAtIzER_NP ;
Az NP uttag a nem hordozhat (non-portable) makrkra utal: ezeket csak
Linux alatt hasznlhatjuk.
Mutexet a fenti statikus inicializci helyett fggvnyhvssal is ltre-
hozhatunk. Ezt fknt akkor szeretnnk, ha nem felel meg a mutex attrib-
tumainak alaprtelmezett belltsa:
#include <pthread.h>
int pthread_mutex_init(pthread_mutex_t *mutex,
11111111
1_
const pthread_mutexattr_t *mutexattr)
A mutex argumentumban kapjuk vissza a mutexobjektumra mutat pointert,
amelyet lerknt adunk t a mutexen mveleteket vgz fggvnyeknek.
Az utols paramterrel llthatjuk be a mutex attribtumait, amelynek tpu-
sa pthread_mutexattr_t. Ezzel tbbek kztt a mutex tpust llthatjuk.
A mutex felszabadtst a
#include <pthread.h>
int pthread_mutex_destroy(pthread_mutex_t *mutex);
JIM
fggvnnyel kell elvgeznnk, amelynek felttele, hogy a hvs pillanatban
a mutex ne legyen foglalt. Ha a mutexet statikus inicializlkkal hoztuk lt-
re, akkor nem szksges meghvni ezt a fggvnyt, ha a pthread_mutex_init
fggvny segtsgvel, akkor igen.
Mutex lefoglalst a
#include <pthread.h>
int pthread_mutex_lock(pthread_mutex_t *mutex);
fggvnnyel vgezhetjk. Ha a mutex ppen szabad, akkor a pthread_mutex loek
lefoglalja, egybknt a hv szl addig felfggesztve vrakozik, amg a mutex
szabadd nem vlik, s akkor kerl a hv szl birtokba.
222
5.5. POSIX-szinkronizci
Ennek a fggvnynek az a htrnya, hogy ha nem szabad a mutex, akkor
a. szl vrakozik. Ha nem szeretnnk, hogy a fggvny vrakozzon, hanem
csak annyit, hogy ha szabad a mutex, akkor lefoglalja, egybknt rgtn visz-
szatr jelezve, hogy a mutex foglalt, akkor a
#include <pthread.h>
int pthread_mutex_trylock(pthread_mutex_t *mutex);
fggvnyt hasznljuk, amely EBUSY rtkkel tr vissza, ha a mutex foglalt,
s nem blokkolja a szlat.
Miutn lefoglaltuk a mutexet, a
#include <pthread.h>
int pthread_mutex_unlock(pthread_mutex_t *mutex);
fggvnnyel engedhetjk el.
Plda rjunk szlbiztos FIFO-osztlyt C++ nyelven, amely POSIX-mutexet hasznl. Teszteljk is
le valamilyen egyszer mdon.
I

Elsknt tekintsk t az osztlydefincit:
template<class Type> class Fifo
protected:
Type* data;
int elements;
pthread_mutex_t critical_section_mutex;
public:
Fifo();
Fifo(Fifo&);
-Fifo();
bool isEmpty();
int push(Type);
int pop(Type&);
void clear();
private:
void lock();
void unlock();
};
/"
7-
/*
/*
/*
1*
masolo konstruktor */
Ha a FIFO ures, akkor igazzal ter vissza
uj elemet helyez el a FIFO-ban "/
Kvesz egy elemet a FiFo-bol */
Kitorli a FIFO tartalmat */
Lefoglalja a mutex-et */
Felszabadtja a mutex-et */

Az adatokat a data pointer ltal mutatott dinamikus tmbben troljuk, az
elements pedig a benne lv elemek szma. Arra kell figyelnnk, hogy ez a
kt vltoz konzisztens legyen: egyik szl se hagyhat flbe olyan mveletet,
amely mindkett megvltoztatja. Ezrt tagvltozknt elhelyeznk egy
mutexet, amelyeket a konstruktorok inicializlnak-
223
5. fejezet: Prhuzamos programozs
/*Alapertelmezettk onstruk tor*/
template<classTy pe>
Fifo<Ty pe>::Fifo()
{
/*Inicializalj uk amutex-etesatarolostruk turak at.*/
pthread_mutex_init(&critical_section_mutexmuLL);
data=NULL;
elements=0;
/*Masolok onstruk tor*/
template<classTy pe>
Fifo<Ty pe>::Fifo(Fifo<Ty pe>&fifo)
{
/*Inicializalj uk amutex-et.*/
pthread_mutex_ nit(&critical_section_mutex,NULL);
/*Lefoglalj uk amasolandoFIFObelsoadatstruk turaj ahoza
hozzaferest.*/
fifo.lock ();
/*Kimasolj uk azadatok at.*/
elements=fifo.elements;
data=newTy pe[elements];
for(inti=0;<elements; +)
f
data[i]=fifo.data[i];
/*Felszabaditj uk amasolandoFIFOmutex-et.*/
fifo.unlock ();
A msolkonstruktorban a FIFO-osztly ekkor jn ltre, kt szl egyszerre
nem hozhatja ltre ugyanazt a FIFO-t, ezrt a msolkonstruktorban a ltre-
hozand objektum mutext nem foglaljuk le. A paramterknt kapott FIFO
ugyanakkor knnyen megosztott lehet, ezrt lefoglaljuk, hogy egy konzisztens
vltozatot msoljunk le.
Lnyegben minden mvelet azzal kezddik, hogy lefoglaljuk a mutexet,
majd a vgn felszabadtjuk:
/*Kitorlia FIFOtartalmat.*/ '
template<classTy pe>
v oidFifo<Ty pe>::clear()
{
/*Lefoglalj uk amutex-et.*/
lock ();

224
/*Felszabaditj aamutex-et. Az el obbi parj a. */
templ ate<cl ass Type>
voi d fo<Ty pe>::unlock ()
pthread_mutex_unlock (&cri ti cal _secti on_mu tex) ;
- - -
5.5. POSIX-szinkronizci
/*rorolj uk ataroltadatok at.*/
if(data!=NuLL)delete[]data;
data-NULL;
elements=0;
/*Felszabad tj uk amutex-et.*/
unlock 0;
Kzben figyelnnk kell arra, hogy hiba esetn visszatrs eltt elengedjk a
mutexet:
template<classTy pe>
int Fi fo<Ty pe>::pop(Ty pe&ret)
/*Lev edj uk ak r tik usmuv eletek et.*/
lock ();
/*Megv izsgalj uk v an-ev arak ozoelemaFIFO-ban.*/
i f(!elements)
t
/*Hibaesetenfelszabad tj uk amutex-etesv isszaterunk .*/
unlock ();
return-1;
Hasonlan vgig kell nznnk minden egyes utastst, nehogy vletlenl
visszatrjnk a mutex elengedse nlkl: ez a megolds rengeteg hibale-
hetsget rejt magban. A lefoglalst s az elengedst most kt fggvny vgzi:
it
template<classTy pe>
v oidFifo<Ty pe>::lock ()
{
pthread_mutex_lock (&critical_section_mutex);
}
Erre biztonsgosabb felhasznlni a C++ konstruktor/destruktor mechaniz-
must: runk egy olyan osztlyt, amelynek a konstruktora lefoglalja a para-
mterknt kapott mutexet, a destruktora pedig felszabadtja:
225
5. fejezet: Prhuzamos programozs
class Lock
{
pthread_mutex_t* mutex;
public:
Lock(pthread_mutex_t* mutex):
mutex(mutex){pthread_mutex_lock(mutex);}
Lock(){pthread_mutex_unlock(mutex);}
};
Fontos, hogy a mutexet pointerknt vesszk t, mert a ler nem msolhat.
Ezek utn az sszes /ock0 hvst kicserljk az albbi sorra:
Lock 1 ock(&cri ti cal_section_mutex) ;
A felszabadtst automatikusan elvgzi a destrukort, amikor a vezrls el-
hagyja azt a blokkot, amelyben a lock vltozt definiltuk. Nem kell figyel-
nnk sem a visszatrsre, sem a kivtelekre.
rdemes tgondolnunk a destruktort is. Ennek implementcija a kvetkez:
template<class Type>
Fi fo<Type>: : Fi fo ()
if(data!=NULL) delete[] data;
pthread_mutex_destroy(&critical_section_mutex);
Amikor a destruktor meghvdik, akkor komoly problma lenne, ha a felsza-
badtskor msik szlbl mg szeretnnk hasznlni a trolt. Ennek biz-
tostsra szmos megolds ltezik, pldnkban a trol felszabadtst az
sszes hasznl szl kilpse utn vgezzk. Ezzel sszhangban a tesztelst
vgz szlakat az albbiak szerint implementltuk:
class FifoThread: public Thread
int start; // Ettol szamolunk
int end; // Eddig
static Fifo<int> sharedFifo;
public:
FifoThread(int start, int end):start(start), end(end){}
void Threadmain()
for(int i=start; i<=end; i++)
sharedFifo.push(i);
cout i " pushed" endl;
226
5.5. POSIX-szinkronizci
sleep(1);
sleep(1);
for(int i=start; i<=end; i++)
{
int a;
if(sharedFifo.pop(a) 0)
{
coutaendl;
sleep(1);
}
}
1;
A FIFO-t statikusan hozzuk ltre, gy a szlak elindtsa eltt ltrejn, s
utna szabadul fel, majd egyszeren elrhet mindkt j szlbl. Ha az inici-
alizlst az egyik szlbl vgeznnk, akkor az 5.4.4. Szlbiztos fggvnyek al-
fejezetben bemutatott egyszeri inicializls stratgijt kellene hasznlnunk,
vagy statikusan kellene inicializlni a mutexet.
Ezek utn a main() fggvnynk egyszeren implementlhat:
Fi fo<int> Fi f0Thread::sharedFifo;
int main()
II
FifoThread t1(0,5), t2(10, 15);
t1. start();
t2 Start();
tl.Join();
t2.loin();
return 0;
5.5.2. Feltteles vltozk
A feltteles vltozk (conditional variable) arra szolglnak, hogy rtestst
kldjnk egy mutexszel vdett megosztott erforrs llapotnak megvltoz-
srl, illetve erre az rtestsre vrakozni tudjunk. Ennek illusztrcjaknt
nzzk meg a kvetkez szitucit.
Feladat Egy egsz tpus szmll llapota arnyos egy vztartly vzszintjvel, amelyet egy
adatgyjt szl folyamatosan frisst a szenzorok alapjn. Ha a szmll elri a 10-es rtket, egy
msik, monitoroz szlbl rjunk ki egy figyelmeztetst a terminlra, ha pedig elri a 15-s szin-
tet, a monitoroz szl szltsa fel az szni nem tudkat, hogy hagyjk el a gyr terlett.
227
5. fejezet: Prhuzamos programozs
A fenti plda implementcijban az adatgyjt szl foglalkozik a tartly l-
lapotval, s frissti a megosztott erforrst: az unsigned int tpus szmllt.
Tegyk fel, hogy a tartllyal foglalkoz szlakat csak adatgyjtsre hasznl-
juk, ezrt nem implementlhatunk benne sszetett logikt. Ezrt a szmll
llapott egy kln monitoroz szlbl ellenrizzk, s ugyaninnen kldjk a
figyelmeztetseket. Mivel a szmllhoz tbb szl is hozzfr, ezrt azt egy
mutex vdi. Amikor a monitoroz szl olvasni szeretn a vltozt, lefoglalja a
mutexet. m ha egyfolytban olvasgatja az rtket, s fogva tartja a mutexet,
akkor a tartly llapott frisst adatgyjt szlak nem tudjk lefoglalni a
mutexet, gy nem tudjk megvltoztatni a szmll rtkt. Vagyis minden szl
a msikra vr, mikzben a gyrat lassan, de annl hatrozottabban elbortja
a vz. J lenne, ha az ellenrz szl nem ellenrizn s foglaln folyamatosan a
mutexet, hanem az adatgyjt szlak rtestenk arrl, hogy megvltozott
a szmll rtke, s ahogy az esemny bekvetkezik, egy atomi mvelettel
felbredne, s vissza tudn szerezni a mutexet. Erre hasznlhatjuk a feltteles
vltozkat. A feltteles vltozkon kt mvelet vgezhet, az egyik a vrakozs
a jelzsre, a msik maga a jelzs.
77
A feltteles vltoznak nincs llapota, csak
ppen a jelzs pillanatban vrakoz szlak kapjk meg a jelzst. Pldnkban
az adatgyjt szlak egy feltteles vltoznak jeleznek, a monitoroz szlak
pedig a feltteles vltoz jelzsre vrakoznak. Ebben az esetben csak a 10-es
s 15-s rtknl jelznk, de ha nem akarjuk az adatgyjt szlat terhelni a
riaszts logikjval, akkor minden egyes alkalommal, amikor egy adatgyjt
szl megvltoztatja a vzszint rtkt, ezt jelezhetjk a feltteles vltoznak.
Rszletesen ez az albbiakat jelenti.
1. A monitoroz szl lefoglalja a mutexet.
2 . Ellenrzi, hogy meghaladta-e a 10-es vagy 15-s rtket, s aszerint
reagl.
3. A monitoroz szl egy atomi mvelettel elengedi a mutexet, s vra-
kozik a feltteles vltozra. Azrt van szksg az atomi mveletre,
nehogy egy vagy tbb adatgyjt szl kzben lefoglalja a mutexet,
megvltoztassa az rtkt, a monitoroz szl pedig lemaradjon a jel-
zsrl. A mutex 1. pontbeli lefoglalsa s az atomi mvelet egytt biz-
tostja azt, hogy ha egy szl elhatrozza, hogy vrakozik egy feltteles
vltozra, akkor a mutex lefoglalstl szmtva nem fgg az idz-
tstl az, hogy lemarad-e egy jelzsrl.
4 . A monitoroz szl a feltteles vltozra vrakozik, a mutexet nem
tartja fogva, ezrt egy adatgyjt szl lefoglalhatja, ez meg is trt-
nik, ha a vzszint indokoltt teszi. A vzszintszmll vltoz 10-es
vagy 15-s rtke esetn az adatgyjt szl jelez a feltteles vltoz-
nak, s elengedi a mutexet. Ezt tehetn fordtott sorrendben is, a
POSIX mindkt megoldst megengedi.
77
A feltteles vltozval kapcsolatban hasznlt jelzseknek nincs kzk a processszek k-
ztti kommunikcira hasznlt jelzsekhez (ezeket lsd az 5.6. Jelzsek alfejezetben).
2 2 8
5.5. POSIX-szinkronizci
5. A feltteles vltoz jelzsre vrakoz monitoroz szl felbred, auto-
matikusan mr birtokban van a mutex, s az 2 . ponttl folytatdik a
forgatknyv.
Nagyon fontos odafigyelnnk arra, hogy bredskor a monitoroz szl ellen-
rizze a feltteleket. Jllehet beleptettk az adatgyjt szlba, hogy csak ak-
kor szljon, ha a szmll rtke meghaladta a 10-es vagy a 15-s rtket,
nem felttelezhetjk, hogy ez gy is van. Ennek tbb oka lehet.
A feltteles vltozra vrakoz szlat az opercis rendszernek joga
van mindenfle jelzs nlkl felbreszteni. Ezt flsleges bresz-
tsnek (spurious wakeup) nevezzk, s ennek oka a feltteles vlto-
zk hatkony implementlsa tbbprocesszoros rendszeren.
Amikor az adatgyjt szl elengedi a mutexet a 3. pontban, egy msik
adatgyjt szl felbredhet, s akr cskkentheti is a vzszintet.
Ha pldnkban ms szl is vrakozna a feltteles vltozra, s az
elbb szerzi meg a mutexet, megvltoztatn a vltoz rtkt, mire a
mutexet msodkknt megszerz monitoroz szl hozzfr.
tmutat A feltteles vltozra val vrakozsbl felbredve a szlak mindig jra teszteljk
le a felttelt a megosztott erforrson, ne bzzanak a jelzsklds felttelben.
Ezek utn vegyk sorra a feltteles vltozhoz tartoz fggvnyeket. A mu-
texekhez hasonlan feltteles vltozkat ltrehozhatunk statikus inicializ-
lssal s inicializlfggvnnyel. A statikus megoldst az albbi kdrszlet
szemllteti:
sincl ude <pthread . h>
pthread_cond_t cond =P THREAD_COND_INITIALIZER;
Egybknt pedig a
#include <pthread.h>
i nt pthread_cond_init(pthread_cond_t *cond,
pthread_condattr_t "cond_attr);
fggvnnyel nicializljuk a feltteles vltozt, ahol ha a cond_attr NULL, ak-
kor a feltteles vltoz az alaprtelmezett attribtumokkal jn ltre. Az attri-
btumot a thread_condattrint fggvnnyel inicializlhatjuk, s a pthread_
condattr_destroy fggvnnyel kell felszabadtanunk. Az attribtumrtkek
kzl azt llthatjuk be, hogy processzek vagy szlak kztt akarjuk-e hasz-
nlni a feltteles vltozt (pthread_condattr_getpshared, pthread_condattr_
setpshared fggvnyek).
229
5. fejezet: Prhuzamos programozs
Inicializlfggvnnyel ltrehozott feltteles vltozt a
#include<pthread.h>
intpthread_cond_destroy (pthread_cond_t*cond);
fggvnnyel szntethetnk meg. Ekkor egy szl sem vrakozhat a feltteles
vltozra.
Jelzst a
#include<pthread.h>
i ntpthread_cond_signal(pthread_cond_t*cond);
fggvnnyel kldhetnk. Ezt akkor rdemes hasznlnunk, ha elg, hogy a
vrakoz szlak kzl egyetlen, tetszleges szl kapjon rtestst.
Ha azt szeretnnk, hogy az olyan sszes szl, amely egy feltteles vltoz-
ra vrakozik, megkezdje futst, akkor a
#include<pthread.h>
intpthread_cond_broadcast(pthread_cond_t*cond);
fggvnyt hasznljuk Ennek a fggvnynek az esetben az sszes, a jelzs pil-
lanatban vrakoz szl felbred, s vrakozni kezd a mutexre. A sorrend nincs
meghatrozva, Ilyenkor is elfordulhat, hogy valamelyik szl megvltoztatja a
megosztott erforrst, s a felttel a msodikknt hozzfr szl esetben mr
nem lesz igaz. Ezrt hangslyozzuk ismt, hogy a feltteleket a felbred sz-
laknak mindig ellenriznik kell.
Ha vrakozni szeretnnk egy feltteles vltozra, akkor a
#include<pthread.h>
intpthread_cond_wait(pthread_cond_t*cond,
pthread_mutex_t*mutex);
fggvnyt hasznljuk. A fggvny meghvsa eltt le kell foglalnunk a mu-
texet, majd a meghvs utn el kell engednnk, ugyanis visszatrs eltt ez a
fggvny visszaszerzi", azaz jra lefoglalja a mutexet.
Ha csak meghatrozott ideig szeretnnk vrakozni, akkor a
#include<pthread.h>
intpthread_cond_timedwait(pthread_cond_t*cond,
pthread_mutex_t*mutex,
conststructtimespec*abstime);
2 3 0
5.5. P051X-szinkronizci
fggvnyt hasznljuk a cond s a mutexargumentum szempontjbl ugyan-
gy, mint a pthread_cond_wait hvst. Az egyetlen klnbsg az, hogy a fgg-
vny az abstime argumentumban megadott idnl tbbet nem vr, hanem jra
lefoglalja a mutexet, s ETIMEDOUT rtkkel tr vissza. Az id 10 msod-
percre val belltst a kvetkez plda szemllteti:
structtimev alnow;
structtimespectimeout;
gettimeofday (&now);
timeout.tv _sec=now.tv _sec+10;
t meout.tv _nsec=now.tv _usec*1000;
A fentiek fnyben a plda egy leegyszerstett megoldsa az albbi lehet. El-
sknt a monitoroz szlat mutatjuk be:
unsignedintcounter=0;
pthread_mutex_tmutex=P THREAD_MUTEX_INITIALIZER;
pthread_cond_tcondv ar=P THREAD_COND_INITIALIZER;
v oid*monitor_thread(v oid*arg)
unsigned ntc;
pr ntf("Amonitorozoszalindul...\n");
pthread_mutex_lock (&mutex);//1.Mutexlefoglal sa
while(1)
{
if(counter==10)//2 .Felt telek ellenrz se
printf("!F gy elem:v zszint!\n");
}
elseif(counter==15)
{
break ;
}
pthread_cond_wait(&condv ar,&mutex);//2 .v rak oz s
}
pthread_mutex_unlock (&mutex);//Kilepesk orelengedni
printf("!!!Katasztrofatortent!!!\n");
returnNULL;
231
5. fejezet: Prhuzamos programozs
Figyeljnk oda, hogy a flsleges bresztsek miatt a vrakozs mindig cik-
lusban trtnik, s mindig ellenrizzk a felttelt. A fprogram az adatgyjt
szlat szimullja:
ntmain()
{
pthread_tmy thread;
inti;
i f(pthread_create(&my thread, NULL, mon tor_thread, NULL))
fprintf(stderr,"Hibaaszalletrehozasanal.\n");
exit(1);
}
/*Szimulalj uk av izszintv altozasat.*/
for(i=0;i<2 0;i++)
sleep(1);
pthread_mutex_lock (&mutex);
//Aszamlalonov elese
counter++;
printf("Aszamlaloallasa:%u\n",counter);
if(counter==10IIcounter-15)
printf("]elzesk uldese...\n");
pthread_cond_broadcast(&condv ar);
printf("v isszak apj uk amutexet...\n");
pthread_mutex_unlock (&mutex);
}
if(pthread_j o n(my thread, NULL))
{
fprintf(stderr,"Hibaaszalmegv arasanal.\n");
exit(1);
return0;
Jelen pldnkban elhelyeztnk egy sleep hvst, amely leth'bb tette a szimu-
lcit, de mg fontosabb, hogy a fszl nem fejezte be a szimulcit a monitroz
szl indulsa eltt. Ha meg szeretnnk vrni a szl indulst, ahhoz ltreho-
zunk egy boolean vltozt, ezt mutexszel vdjk, s feltteles vltozval vra-
kozunk a megvltozsra. Amikor a szl tlltotta a boolean vltozt, jelez a
fszlnak, erre az felbred, ellenrzi, hogy a a vltoz tnyleg t lett-e lltva,
s ha igen, fut tovbb. Tbb szl esetn boolean helyett unsigned int vltozt
hasznlunk, amelyet mindegyik indul szl megnvel.
2 3 2
5.5. POSIX-szinkronizci
A feltteles vltozk esetn a mutex s a feltteles vltoz kztt szoros
kapcsolat van.
tmutat Ugyanarra a feltteles vltozra vrakozva soha ne adjunk meg klnbz mutere-
ket, mert az eredmny nem definilt.
Ugyanakkor egy mutexhez tbb feltteles vltoz is tartozhat, ha tbbfle r-
testst szeretnnk kldeni.
5.5.3. Szemaforok
Szemben a System V IPC szemafortmbjvel a POSIX-szemaforok egyetlen
szinkronizcis objektumot jelentenek, amelyeket mind processzek, mind sz-
lak kpesek hatkonyan hasznlni. Ahogy sz volt mr rla, a System V IPC-
hvsok egy kzs nv alapjn osztottk meg a szinkronizcis objektumokat.
Az eddigi POSIX szinkronizcis objektumok esetben ltrehozskor a pro-
cesszek kzti megosztst engedlyez atttribtumot kell belltanunk, s
megosztott memriaterleten kell ltrehozni ket. POSIX-szemaforok eset-
ben mindkt lehetsg adott. Az els esetben a szemafornak egy / karakterrel
kezdd nevet adunk, ilyenkor megnevezett szemafornak (named sema-
phore) nevezzk. A msodik esetben csak egy memriacmen lv ler azono-
stja a szemafort, ezek a nvtelen szemaforok (unnamed semaphore).
Nvtelen szemafort a kvetkez fggvnnyel hozhatunk ltre:
#include semaphore.h>
int sem_init(sem_t *sem, int pshared, unsigned int value);
Ha a pshared nem 0, akkor a szemaforhoz ms processzek is hozzfrhetnek,
egybknt csak az adott processz szlai. A szemafor rtke a value param-
terben megadott szm lesz.
Megnevezett szemafort az albbi fggvnnyel hozhatunk ltre:
finclude <semaphore.h>
sem_t *sem_open(const char *name, int oflag, ...);
Az els paramter a szemafor neve, a msodik a megnyits jelzbitjei az l-
lomny megnyitsnl megismert O_CREAT s O_EXCL, amelyekhez az
fcntl.h llomnyt is be kell ptennk. Ha az O_CREAT jezl'bitet belltjuk,
akkor egy harmadik s egy negyedik paramtert is meg kell adnunk. Ekkor a
fggvny prototpusa gy nz ki:
233
5. fejezet: Prhuzamos programozs
sem_t*sem_open(constchar*name,intoflag,mode_tmode,
unsignedintv alue);
_ _
A tovbbi paramterek a jogosultsgok s a szemafor kezdeti rtke.
Vegyk sorra a mveleteket. Egy sem szemafor rtkt a
#include <semaphore.h>
intsem_wait(sem_t*sem);
intsem_try wait(sem_t*sem);
"aele ~1~ 11~el
fggvnyekkel cskkenthetjk eggyel. Ha a sem szemafor rtke pozitv,
mindkt fggvny eggyel cskkenti az rtkt, s visszatr 0-val. Ha a sze-
mafor rtke 0, a sem_trywait azonnal visszatr EAGAIN rtkkel, mg a
sem_wait vrakozik a szemafor pozitv rtkre. Ez utbbi vrakozst vagy
a szemafor llapota (az rtke nagyobb lesz, mint nulla), vagy egy jelzs sza-
kthatja meg.
A szemafort rtkt hasznlat utn a
#include<semaphore.h>
intsem_post(sem_t*sem);
fggvnnyel nvelhetjk eggyel. A szemafor aktulis rtkt a
#include<semaphore.h>
intsem_getv alue(sem_t*sem,int*sv al);
fggvnnyel krdezhetjk le. Ha a szemafort lefoglaltk, akkor a visszatrsi
rtk nulla vagy egy negatv szm, amelynek abszolt rtke megadja a sze-
maforra vrakoz processzek szmt. Ha a sval pozitv, ez a szemafor aktu-
lis rtkt jelenti.
Nvtelen szemafort a
#include<semaphore.h>
intsem_destroy (sem_t*sem);
11111111L~211=1 .
--
__
fggvnnyel szntethetnk meg. Megnevezett szemafort a
#include<semaphore.h>
intsem_close(sem_t *sem);
fggvnnyel zrhatunk le.
234
5.5. POSIX-szinkronizci
A megnevezett szemaforok a processz kilpsekor vagy az exec fggvnycsa-
ld hvsakor automatikusan lezrdnak. Mivel a megnevezett szemaforok
perzisztensek, a close fggvny hatsra nem szabadulnak fel, s rtkket is
megrzik. Ha a close utn jra meghvjuk a sem_open fggvnyt a nevvel,
ugyanazt a szemafort kapjuk vissza, ugyanolyan llapotban, ahogy a processzek
hagytk. A megnevezett szemafort a sem_unlink fggvnnyel trlhetjk.
A szemafor az llomnyokhoz hasnonlan nem trldik rgtn, a kernel megvrja
mg az sszes processz lezrja a lert, s utna szabadtja csak fel. Ugyanakkor
az a processz, amely a sem_unlinket hvta, mr nem nyithatja meg jra.
Feladat Ksztsnk olyan programot, amely egy repltri bejelentkezst szimull. Hozzunk
ltre egy POSIX-szemafort, ahol a szemafor a lgitrsasg pultjait jelenti. Ezttal egy nagy k-
zs sor van, s a szemafor kezdeti rtke jelzi a pultok maximlis szmt. Egy szl hozza ltre
a szemafortmbt, egy msik szl pedig a kvetkezt: menjen oda" az els res pulthoz, ha
minden pult foglalt, lljon be abba a sorba, ahol legkevesebben vrakoznak. Az utasok nem
felttlenl rkezsi sorrendben kerlnek sorra, mert a tl ksn rkez utasokat a ksbb in-
dulk elreengedhetik.
Elsknt az utasszlat mutatjuk be:
/* Globalis valtozok *7
sem_t szemafor;
`_
int utas_szamlalo=0;
void* utas_szal (void"arg)
{
nt sorsz am=" (i nt"
-
)arg ;
Free(arg):
printf("A %d. utas sorban all...\n",sorszam);
/* varakozunk a szemaforra: innen csak akkor jutunk */
/* tovabb, ha egy pult szabad lesz */
sem_wait(&szemafor);
printf("A %d. utas sorra kerult...\n",sorszam);
sleep(KISZOLGALASI_IDO) ;
printf("A %d. utas tavozott...\n",sorszam);
/* El engedjuk a szemafort
tr i
sem_post(&szemafor);
return NULL;
}
235
5. fejezet: Prhuzamos programozs
A szl megprblja lefoglalni a szemafort. Ha nem sikerl, vrakozik, vagyis
sorba ll. Ha sikerl, akkor a szemafort, vagyis a szabad pultok szmt csk-
kenti eggyel, vrakozik a kiszolglsi ideig, majd megnveli eggyel a szema-
fort, s kilp (tvozik").
A fprogram egy lehetsges implementcija az albbi:
intmain()
{
intch;
int*p_sorszam;
pthread_tszal_leiro;
/*Beallitj uk aszemaforertek et*/
sem_init(&szemafor,O,P ULTOK_SZAMA);
printf("Ny omj onu-tuj utask uldesehez,k -tak ilepeshez!\n");
do
do
ch=getchar();
} while(ch!='u'&&ch!='k ');
utas_szamlalo++;
p_sorszam=malloc(sizeof(int));
*p_sorszam=utas_szamlalo;
pthread_create(&szal_leiro,NULL,utas_szal,p_sorszam);
while(ch!='k ');
printf("P ultok atbezartak ,sorbanallok hazamennek ...\n");
return0;
}
A fprogram a felhasznli bemenet alapjn hozza ltre a szlakat, vagyis az
utasokat. Kilpskor az sszes szl megsznik, vagyis az sszes utas eltnik,
ez feladatunkban nem okoz problmt, ezrt nem vrakozunk a szlakra, gy
lerikat sem mentjk el.
5.5.4. Spinlock
Amikor egy szl nem tudja lefoglalni a mutexet, rgtn vrakoz llapotba
kerl. Amikor a mutex llapota megvltozik, akkor a szlat fel kell breszte-
ni, amely jra megprblja lefoglalni a mutexet. Ha a mutexet csak nagyon
rvid deig fogjk a szlak, akkor a vrakozs helyett rdemes rgtn jra
2 3 6
5.5. POSIX-szinkronizci
prblkozni. Ha ez sorozatosan nem sikerl, akkor az lland prblkozssal
pazaroljuk a processzoridt. Ha viszont ez rendre sikerl, akkor a vrakozs-
felbreszts idejt megtakartottuk. Pontosan ezt a forgatknyvet valstja
meg a spinlock.
Feladat Ksztsnk szlbiztos FIFO-trolt spinlockkal.
Elsknt deklarlnunk kell a spinlock objektumot, majd gondoskodnunk kell
az inicializlsrl s a felszabadtsrl.
templatecclass Type> cl ass Fi fo
pthread_spinlock_t spin;
};
/* Al apertel mezett konstruktor '/
template<class Type>
Fi fo<Type> : Fi fo()
/* Inicializaljuk a spi nlockot es a tarolo strukturakat.
*1
pthread_spi n_i ni t(&spi n , 0) ;
}
/* Destruktor */
templ a te<cl ass Type>
Fi fo<Type>: :-Fi fo ()
pthread_spi n_destroy(&spi n) ;
A Lock osztly vgzi a lefoglalst s felszabadtst:
cl ass Lock
{
pthread_spi nlock_t* spin;
publ ic:
Lock (pthread_spi n1 ock_t*spi n) :
spin(spin){pthread_spin_lock(spin);}
-Lock {pthread_spin_unlock(spin);} ;
1;
237
5. fejezet: Prhuzamos programozs
Pusztn az osztly alapjn nem tudjuk megmondani, hogy rdemes-e a mu-
texet spinlockra cserlni, hiszen az elemek kivtele s elhelyezse sorn a
hasznlattl fggen gyakori vagy nagyon ritka is lehet.
tmutat ltalban hasznljunk mutexet, hacsak nem vagyunk meggyzdve az tkzs rit-
kasgrl.
5.5.5. Tovbbi lehetsgek: POSIX megosztott
memria s zenetsorok
A POSIX megosztott memrit az shm_open fggvnnyel hozhatjuk ltre, s
az shm_unlink fggvnnyel szntethetjk meg. A megosztott memrit a pro-
cesszek a megnevezett szemaforhoz hasonlan / karakterrel kezdd nvvel
tudjk azonostani. A POSIX-zenetsorok szintn nv alapjn azonosthatk
fggetlen processzekbl, szl-gyermek viszony esetn a ler rklsvel old-
hat meg a kzs zenetsor ltrehozsa. Megnyitskor egy ler jn ltre
(mq_open). A kld- (mq_send) s az olvas- (mq_receive, mq_timedreceive)
fggvnyek a read/write-hoz hasonl buffereket vrnak. Az zenetekhez prio-
ritsokat is rendelhetnk. Az olvasfggvnyek alaprtelmezsben blokko-
ldnak, a nem blokkold zemmdot neknk kell belltani. A szemaforhoz
hasonlan ltezik lezrs (mq_close) s megszntets (mq_unlink).
5.6. Jelzsek
A jelzsek a Linux programozsnak szinte minden terletn elfordulnak,
gy az elz fejezetekben is szmtalanszor utaltunk rjuk. A jelzsek lnyeg-
ben egyidsek a Unix rendszerekkel.
A jelzs (signal) a processzek kztti aszinkron kommunikci egy form-
ja, amelynek segtsgvel egy egsz szmot lehet kldeni, s amelyet a
processz soron kvl kezel. Az aszinkron tulajdonsg azt jelenti, hogy ltal-
nos esetben a jelzst kld processz nem vrakozik a klds utn, hanem rg-
tn folytatja a futst, nem kap rtestst arrl, hogy a jelzs clba rt-e.
Minden jelzshez egy egyedi egsz szmot rendelnk, amely egytl szmoz-
dik. Az ezekhez a szmokhoz rendelt szimbolikus konstansokhoz a signal.h
llomnyon keresztl frhetnk hozz (a signum.h llomny tartalmazza
ket). A konstansok SIG eltaggal kezddnek, pldul a program futsnak
megszaktsra szolgl SIGINT a kettes sorszm szignlt jelli (#define
SIGINT 2). A soron kvli kezels azt jelenti, hogy a processz norml vgre-
hajtsa megszakad, lefut a jelzst kezel kd, majd utna folytatdik az ere-
238
5.6. Jelzsek
deti vgrehajts. E miatt a tulajdonsguk miatt a jelzseket gyakran a meg-
szaktsokhoz hasonltjk. Jllehet a jelzseket elssorban processzek kztti
kommunikcira hasznljuk, egy folyamat kldhet magnak is jelzseket. St
ez a kommunikcis forma szlak kztt is hasznlhat.
Br jelzseket brmelyik processz kldhet, a jelzsek legfbb forrsa ma-
ga a kernel. Az albbi esetekben a kernel nagyon gyakran jelzsekkel kld r-
testst.
Valamilyen hardveresemny trtnt, tipikusan hardveres megszak-
ts rkezett, s a kernel errl rtesteni szeretn a processzeket (pl-
dul idzts, nullval val oszts).
A felhasznl a terminlfelleten valamilyen specilis billentykom-
bincit nyomott le, pldul Ctrl + C SIGINT jelzst generl.
Valamilyen szoftveresemny trtnt: egy llomnyler olvashatv
vlt, soron kvli adat rkezett a hlzaton, gyermekprocessz befejez-
te a futst.
A jelzsek alapkoncepcija nagyon egyszer: egy folyamat vagy a kernel egy
egsz szmot kld a programunknak, ennek hatsra a program normlis futsa
megszakad, s a programon bell automatikusan meghvdik egy kezelfgg-
vny, amely reagl a jelzsre, vagy ha a processz nem regisztrlt kezelfgg-
vnyt, a kernel vagy figyelmen kvl hagyja, vagy egy alaprtelmezett kezel-
fggvnnyel kezeli a jelzst. Az eddigi fejezetekben pontosan gy tekintettnk a
jelzsekre. Ugyanakkor ebben a tmakrben klnsen igaz az, hogy az rdg a
rszletekben rejlik. A Unix rendszereknek meglehetsen sok ksrletezsre volt
szksge ahhoz, hogy a jelzsek megbzhat kommunikcis mdszerr vljanak,
azaz ne vesszenek el a processzek tudta nlkl. Ahhoz, hogy biztonsggal hasz-
nljuk a jelzseket, rszletesen meg kell rtennk a mkdsket s a helyes
hasznlat rszleteit. Ebben segtenek a kvetkez fejezetek.
5.6.1. A jelzsklds s -fogads folyamata
A kld processz szempontjbl meglehetsen egyszer a helyzet. A jelzs
kldsre felhasznli zemmdban a kill, tgkill, valamint a sigqueue rend-
szerhvsok valamelyikvel lehet utastani a kernelt. Jelzst egy adott pro-
cessznek, processzcsoportnak vagy szlnak lehet kldeni. Ha a processznek
nem volt joga a cmzettnek jelzst kldeni, a rendszerhvsok hibval trnek
vissza. Ezt a folyamatot jelzskldsnek (sending a signal) nevezzk.
A cmzett processz reakcijt egy jelzsre a jelzs elrendezsnek (dis-
position) nevezzk. A cmzett processz hromflekppen rendezheti el a kl-
dtt jelzst:
239
5. fejezet: Prhuzamos programozs
Figyelmen kvl hagyja: ilyenkor a processz llapota s futsa ugya-
naz marad, mintha a jelzs meg sem rkezett volna.
Lefuttat egy fggvnyt, az gynevezett jelzskezelt (signal handler).
Ezt a fggvnyt a processznek elre be kell regisztrlnia.
Hagyja, hogy a kernel egy alaprtelmezett funkcit hajtson vgre.
A jelzstl fggen a kernel alaprtelmezett funkcija hromfle lehet:
Figyelmen kvl hagyja a jelzst (F).
Terminlja a processzt Labnormal process termination", T).
A processz memriabeli s regisztereinek aktulis llapott elmenti
egy llomnyba (core dump), majd terminlja (CD).
A processz felfggesztett (STOPPED) llapotba kerl (STOP).
A processz felfggesztett llapotbl a futsra ksz (RUNNING) lla-
potba kerl (FUT).
Az egyes jelzseket s a kernel alaprtelmezett funkcijt az 5.9. tblzat tb-
lzat tartalmazza.
5.9. tblzat. A jelzsek azonostja, lersa s alaprtelmezett elrendezse
Jelzs Lers Funkci
SIGABRT Az abort0 fggvny generlja. CD
SIGALRM Egy alarmQ ltal felhzott idzt lejrt. T
SIGBUS Memria-hozzfrsi problmk. CD
SIGCHLD A gyermekprocesszt terminltk vagy felfggesz- F
tettk.
SIGCONT A processz a lellts utn folytatja a futst. FUT
SIGHUP A processz terminljt becsuktk. T
SIGFPE Lebegpontos szmtsi hiba. CD
SIGILL A processzor illeglis utastst hajtott vgre. CD
SIGINT A felhasznl megszaktskaraktert (^C) kldtt T
a terminlon keresztl.
SIGIO Aszinkron 1/0: olvashat adat rkezett. T
SIGKILL Mindenkppen terminlja a processzt. T
SIGQUIT A felhasznl kilpsi karaktert (^\) kldtt. CD
SIGPIPE A processz olyan csvezetkbe rt, amelynek nin- T
csen olvasja.
SIGPROF A profiler ltal hasznlt idzt lejrt. T
SIGPWR Tpfeszltsghiba. T
2 4 0
5.6. Jelzsek
IJelzs Lers Funkci
SIGSEGV Illeglis memriacmhez val hozzfrs. CD
SIGSTOP Mindenkppen felfggeszti a folyamat futst. STOP
SIGTERM Kezelhet (fellbrlhat) processzmegszntets. T
SIGTRAP Trspont nyomkvetshez. CD
SIGTSTP A felhasznl felfggesztskaraktert (^Z) kldtt. STOP
SIGTTIN A httrben fut alkalmazs megprblta olvasni STOP
a terminlt.
SIGTTOU A httrben fut alkalmazs rni prblt a termi- STOP
nlra.
SIGWINCH A terminl mrete megvltozott.
SIGURG Srgs I/0 esemny. F
SIGUSRI Programoz ltal definilt jelzs. T
SIGUSR2 Programoz ltal definilt jelzs. T
SIGXCPU CPU idszeletnek tllpse. CD
SIGXFSZ Fjlmret hatrnak tlpse. CD
SIGVTALRM A setitimer() ltal felhzott virtuls idzt lejrt. T
A fenti tblzatot ttanulmnyozva lthatjuk, hogy a Linux elg szigor: ha a
tipikus forgatknyv szernt ltalban kezelnnk kellene egy jelzst, akkor
a kerne] alaprtelmezsben terminlja a programot, nehogy rejtve maradjon
a hiba. Ha komoly hardverhiba trtnik, amely utn knnyen elfordulhat,
hogy a hiba feldertse rdekben nyomon szeretnnk kvetni a processzt, ott
a kernel core dump llomnyt is kszt. A processz felfggesztsvel s jra-
indtsval kapcsolatos jelzsek kezelst a terminl feledatvezrlse szerint
alaktottk ki.
A rendszer elvrt mkdse rdekben a kernel fenntartja a lehetsget,
hogy bizonyos jelzsek elrendezst ne lehessen megvltoztatni. Ezeknek a
jelzseknek a nevt vastagon szedtk a tblzatban. Ugyangy a 0 processza-
zonostj processznek nem lehet jelzst kldeni, mg az 1-es processznek
(nit) csak olyanokat tovbbt a kernel, amelyre jelzskezelt definil.
Ha egy processz jelzst kap, megszaktja a futst, s vgrehajtja az adott
jelzshez tartoz elrendezst. Mivel a pontos felttelek implementcifggk,
rdemes azzal a felttelezssel dolgoznunk, hogy brmelyik kt utasts kztt
rkezhet jelzs, s vgrehajtdhat az elrendezse. Ha a jelzskezelbl hasznl-
juk a program vltozit, a fenti felttelezs tkrben oda kell figyelnnk a ver-
senyhelyzetekre. Vegyk pldaknt az albbi pszeudokdot:
241
5. fejezet: Prhuzamos programozs
intidozito;
staticv oididozito_j elzesk ezelo
idozito=1;
I
intmain()
{
// idozito_j elzesk ezeloberegisztr l saa SIGALRM j elz sre
idozito=0;
alarm(150);//150nanoszek undummlv a SIGALRM j elz s
while(!idozito)
{
pause();//A pausefggv ny ak v etk ezj elz sigv rak ozik
I
A fenti programrszlet egy klasszikus hibt tartalmaz. A megolds alapgon-
dolata az, hogy a fprogram gy vrakozik egy meghatrozott ideig, hogy fel-
hz egy rt. Az ra a beltott id leteltvel egy SIGALRM jelzst kld.
A fprogram s a jelzskezel egy globlis vltozn keresztl kommunikl: az
idozito rtke az indulskor nulla, a jelzskezel lltja be egyre. A fprogram
addig vrakozik, amg a vltoz rtke egy nem lesz. A pause fggvny egy
jelzsre vr. A while ciklusra azrt van szksg, hogy ha ms jelzs breszte-
n fel a pause-t, akkor tovbb vrakozzunk A fenti program az esetek nagy
rszben jl mkdik. m ha az temezs ppen gy alakul, elkpzelhet,
hogy a jelzs az idzt vizsglata utn, de mg a pause fggvny meghvsa
eltt kvetkezik be. Addig, ameddig a program ms jelzst nem kap, vrako-
zik ez pedig tetszleges ideig eltarthat.
A megolds az lenne, ha bellthatnnk egy kritikus szekcit, amelynek a
futsa alatt a processz nem fogadhatna jelzseket. Viszont ha ekzben jelzs
rkezk, annak nem szabad elvesznie, ezrt egy vrakozsi sorban kell tarta-
ni. Termszetesen ennek az alapgondolatnak tbbfle varicija ltezhet, pl-
dul a vrakozsi sor feldolgozsnak sorrendje sokfle lehet, vagy egy adott
tpus jelzs tbbszri elfordulsakor csak egyet trolhatunk.
Els megoldsknt ttelezzk fel az albbi lehetsges megoldst. Minden
egyes jelzshez hozzrendelnk egy engedlyezbitet. Ha ez a bit igaz, a pro-
cessz kezeli a jelzst, ha nem igaz, akkor a kernel nem kzbesti a jelzst. Mi-
vel ez utbbi esetben a jelzs nem veszhet el, minden jelzshez fellltunk egy
vrakozsi sort is. Amikor egy nem engedlyezett jelzs rkezik, a kernel be-
leteszi ebbe a sorba Amikor a processz jra engedlyezi a jelzseket, akkor a
kernel az ppen rvnyes elrendezs szerint kzbesti a vrakozsi sorokban
tallhat jelzseket: a legkisebb rtkhz tartoz sort rti ki elszr. Ter-
mszetesen a vrakozsi sorok FIFO-jellege miatt rkezsi sorrendben
dolgozza fel egy adott sor elemeit. Az ezen az elven mkd jelzseket vals
}
242
5.6. Jelzsek
idej jelz seknek (real-time signal) nevezzk. A vals idej jelzseket
a sigqueue fggvny segtsgvel adhatjuk hozz a vrakozsi sorokhoz, a
SIGRTMIN s a SIGRTMAX kztti jelzsekkel a kezd s a vgrtket is be-
lertve. Mivel a jelzs rtke ilyenkor csak a prioritsrl rulkodik, a sig-
queue tovbbi paramterek elkldst is lehetv teszi.
Sokszor a vals idej jelzsek ltal nyjtott lehetsgeknl jval keve-
sebbre van szksgnk. Nzzk meg pldaknt azt az esetet, amikor egy
idztesemnyre szeretnnk valamilyen feladatot periodikusan elvgezni.
Elfordulhat, hogy a processzor leterheltsge miatt az esemnyek egymsra
futnak: egy esemnyre mg nem tudtunk reaglni, de az jabb mr megrke-
zett. Ilyenkor nem problma, ha arra az esemnyre, amelyrl amgy is lema-
radtunk, nem reaglunk. A torlds leegyszerstsvel szemben viszont nem
szeretnnk, ha egy jelzs elveszne. Ezalatt pontosan azt rtjk, hogy ha a jel-
zs feldolgozsnak megkezdse utn mg egy ugyanolyan jelzs rkezik, ar-
rl kln rtestst szeretnnk kapni, nem veszhet el.
Ezt rdemes gy tekintennk, hogy az egyes jelzsekhez tartoz vrako-
zsi sor egyelem, vagyis egyszerre egy adott tpusbl csak egy feldolgozatlan
jelzst tudunk trolni. Az gy mkd jelzseket ha gyom nyos jelz seknek
(traditional signals) nevezzk. A hagyomnyos jelzseket a kill rendszerh-
vssal kldhetnk.
t mut a t Mivel a hagyomnyos jelzsek esetben a torld jelzsekrl a processz nem kap k-
ln rtestst, a jelzseket nem rdemes szmolni, mert egy adott jelzssorozatra a processzor
terhelstl s egyb rendszerjellemzktl fgg eredmnyt kapunk. Mind a hagyomnyos mind
a vals idej jelzsek esetn egy elkldtt jelzsre a cmzett maximum egyszer reaglhat
(consumable resource"). Jelzs egyik modellben sem veszhet el, pusztn az egymsra torl-
dott jelzsekrl csak egy rtestst kap a cmzett. A vals idej jelzseknl a sorrend adott, a
hagyomnyos jelzseknl nincs elrva, de az implementcik a processz adott llapott rint
jelzseket ltalban elbb kzbestk. A kerneltl kapott jelzsek hagyomnyos jelzsek, mnt
ahogy a Linux rendszer s a programok tbbsge is ilyen jelzseket kld.
A fentiekben teht a kritikus szekcinak csak az egyik felt vizsgltuk: a kri-
tikus szekcit gy alaktottuk ki, hogy a jelzseket letiltottuk, valamint egy
szigor s egy megengedbb megoldst ismertettnk arra, hogy a jelzsek
a letilts alatt ne vesszenek el. Viszatrve a pldnkhoz, a kritikus szekcit
az ra felhzsa eltt belltjuk. A SIGALRM hagyomnyos jelzs: ha a kriti-
kus szekciban mr rkezik jelzs, az nem veszik el, ha tbb is rkezik, csak
egyre hvdik meg a jelzskezel:
int idozito;
static void idozito_jelzeskezelo
{
idozito =1;
243
5. fejezet: Prhuzamos programozs
int main()
{
// idozito_jelzeskezelo beregisztrlsa a SIGALRM jelzsre
idozito =0;
// Az SIGALRM letiltsa
sigprocmask(...);
alarm(150); // 150 nanoszekundum mlva SIGALRM jelzs
whi le( ! i dozi to)
// Kritikus szekci vge SIGALRM engedlyezse
sigprocmask(...)
pause(); // A pause fggvny a kvetkez jelzsig vrakozk
A fenti programrszlettel sajnos nem sokkal vagyunk elrbb: ha a jelzs a
kritikus szekci vge (sigprocmask) s a pause fggvny kztt kvetkezik be,
a fprogram ugyangy nem bred fel, mint azeltt. A pause helyett olyan
atomi mveletre van szksgnk, amely osztatlanul engedlyezi a SIGALRM
jelzst, s vrakozik a legkzelebbi jelzsig. Ez a sigsuspend fggvny. Argu-
mentumban megadhatjuk azokat a jelzseket, amelyre vrakoznia kell, eze-
ket engedlyezi. Ha a megadott jelzsek valamelyike rkezik, elszr megvrja
a jelzskezel lefutst, s csak utna tr vissza. Viszont ha sigsuspend a jel-
zskezel lefutsa utn tr vissza, akkor a jelzskezel futsa utn rgtn le
kell tiltania a megadott jelzseket, vagyis vissza kell lltania az egyes jelz-
sek engedlyezettsgt a hvs eltti llapotokba. Ugyanis ha neknk kellene
ezt megtennnk egy soron kvetkez sigprocmask hvssal, akkor jelzseket
veszthetnnk:
int idozito;
static void idozito_jelzeskezelo()
{
idozito =1;
int main()
{
// idozito_jelzeskezelo beregi sztrlsa a SIGALRM jel zsre
idozito =0;
/7 Az SIGALRM letiltsa
sigprocmask(...);
alarm(150); // 150 nanoszekundum mlva SIGALRM jelzs
244
while(!idozito)
//Kritik usszek civ ge- SIGALRMenged ly ez se,v rak oz s
sigsuspend(...);//Az tadottj elz saSIGALRM
//v isszat r sut nah v sel tti llapotot ll tj av issza
Ezzel megoldottuk a jelzsre vrakozs problmjt anlkl, hogy jelzseket
vesztettnk volna.
tmutat A pause fggvny helyett hasznljunk sigsuspendet.
Specilis jelzs a nulla rtk jelzs: ha ezt kldjk, a kernel semmit nem
kzbest, viszont ellenrizhetjk, hogy az adott azonostj processznek jo-
gunk van-e zenetet kldeni, vagy azt, hogy a processz megtallhat-e a
rendszerben. Ez utbbira jobb megolds a wait fggvnyek hasznlata (ha
a szl szeretn tudni, hogy a gyermeke fut-e) vagy kzs szinkronizcis ob-
jektumok, zrolsok, illyetve IPC-mechanizmusok hasznlata, amelyeket a
kilp processz tllt. Ezek a technikk ugyanis nem okoznak problmt ak-
kor sem, ha a nem hasznlt azonostkat a kernel j processzekhez rendeli.
5.6.2. Jelzsek megvalstsa
A kernel szempontjbl ez valamivel sszetettebb folyamat. Tegyk fel, hogy
processz vagy maga a kernel egy jelzskldst kezdemnyez. Ha a kld
folyamatnak volt ehhez joga, a kernel rtesti a cmzett processzt a jelzs r-
kezsrl, vagyis belltja a processz megfelel adatstruktrit. A kernel
szempontjbl ez a jelzsklds folyamatnak az els rsze, amelyet a jelzs
generlsnak (signal generation) neveznk, mg a folyamat msodik rsze
a jelzs kzbestse (signal delivery). A kzbests folyamn a kernel feldol-
goztatja a cmzett processzel a jelzst. Azokat a generlt jelzseket, amelyek
mg nem lettek kzbestve, fggben lv (pending) jelzseknek nevezzk.
Az egyes jelzsek engedlyezett/letiltott llapott a jelzsmaszk (signal
mask) trolja. Minden folyamathoz tartozik egy jelzsmaszk, amelyet a mr
emltett sigprocmask fggvnnyel llthatunk. A SIGSTOP s a SIGKILL jel-
zseket nem lehet letiltani.
A kernel megprblja kiszrni az egyszerbben kezelhet eseteket. Els-
knt megvizsglja, hogy a generland szignlt nem hagyja-e figyelmen kvl
a processz. Ha ez gy van, akkor a jelzs nem is generldik. Ezt csak akkor
lehet megtenni, ha a jelzs engedlyezett, mert letiltott jelzs nem veszhet el,
hiszen a processz engedlyezs eltt megvltoztathatja a jelzs elrendezst.
245
5. fejezet: Prhuzamos programozs
A msodik eset az, amikor a kernel jelzst generl, s megprblja azon-
nal kzbesteni. Ez akkor lehetsges, ha a cmzett processz mr fut. Ez gy
fordulhat el, hogy a kernel hardvermegszakts miatt generlta a jelzst
(pldul nullval val oszts), amelyet az ppen fut processznek kell kzbe-
stenie. A msik lehetsg az, ha a processz sajt magnak kldte a jelzst.
Ezekben az esetekben a generls utn azonnal megtrtnik a kzbests is.
A nem azonnal kzbestett jelzsek esetben a generlskor a kernel v-
rakozsi sorba helyezi el a jelzst, s bellt egy jelzbitet a processzlerban.
A kernel kt vrakozsi sort tart fenn a fggben lv jelzsek szmra: a
privt vrakozsi sort szlanknt hozza ltre, mg a megosztott vrakozsi
sor a processznek szl jelzseket tartalmazza. A vrakozsi sor maximlis
mrett az opercis rendszer konfigurcis paramterei kztt tartjuk nyil-
vn (RLIMIT SIGPENDING).
Ha a generlt jelzs nem vals idej, s van mr ilyen jelzs a vrakozsi
sorban, akkor nincs tovbbi lpsre szksg, a generls vget r. Ellenkez
esetben a kernel hozzadja a jelzst a megfelel sorhoz. Ha a jelzs engedlyez-
ve van, akkor a kernel belltja a processzben a jelzs rkezst jell jelzbitet,
s megprblja felbreszteni a processzt, vagyis vrakozsi llapotbl tviszi
a futsra ksz llapotba, s hozzadja a futsra ksz processzek listjhoz.
A kernel minden egyes alkalommal, amikor kernelzemmdbl felhasznli
zemmdba kapcsol azrt, hogy egy adott processzt futtasson, ellenrzi, hogy
ennek a processznek van-e fggben lv jelzse. Tipikusan ilyen tkapcsols
trtnik a taszkvlts, illetve rendszerhvsokbl val visszatrs esetn. Ha
vannak ilyen jelzsek, akkor a kernel kzbesti ket. gy, amikor processz fut-
tatsa legkzelebb sorra kerl, a kezdett veszi a kzbests folyamata.
Mivel a kernel nem hoz ltre minden jelzsnek kln vrakozsi sort,
csak kettt tart fenn, kzbestskor nem sorrendben dolgozza fel az zenete-
ket, hanem vlogat" a bennk lv jelzsek kztt. A kernel elsknt elkezdi
kirteni elszr a privt, majd utna a megosztott vrakozsi sort. Elszr a
legalacsonyabb szm jelzseket dolgozza fel, az azonos rtkeket pedig r-
kezsi sorrendben.
Ha a jelzs elrendezse a kernel alaprtelmezett mechanizmusa, akkor
meghvdik az alaprtelmezett mecahnizmus. Jl ismert kivtelt jelent az nit
processz, ez esetben ugyanis a kernel figyelmen kvl hagyja a jelzst.
Ha a jelzs elrendezse egy jelzskezel meghvst rja el, akkor ezt a
kernelnek kell meghvnia. Mivel a fggvny a felhasznli cmtrben van,
a kernelnek t kell kapcsolnia. Ez tbb problmt is felvet. A fggvnynek nem
a veremben tallhat cmre kell visszatrnie, hanem a kernelbe. Ezrt a kernel
a jelzskezel hvsa eltt belltja a sigreturn fggvny cmt, amely egy rend-
szerhvson keresztl visszatr a kernelbe. Radsul, mivel a jelzskezelk
rendszerhvsokat is hasznlhatnak, fontos, hogy a kernel helyett ne a meg-
szaktott fprogramba trjen vissza a fggvny. Ezrt a jelzskezel futtats-
hoz a kernel nem hasznlhatja a megszaktott program veremtartalmt.
246
5.6. Jelzsek
A Linux erre azt a megoldst hasznlja, hogy ltrehoz egy vermet a fel-
hasznli cmtartomnyban (ennek helyt mi is megadhatjuk a signaltstack
fggvnnyel), arra tmsolja a kernel kontextust, kztk a jelzs esetleges pa-
ramtereit, ezutn belltja a visszatrsi cmet a sigreturn cmre, majd elug-
rik a jelzskezel kezdcmre. A jelzskezel vgeztvel a sigreturn rendszer-
hvs tkapcsol kernelzemmdba, visszalltja az eredetileg megszaktott
program kontextust, majd tadja neki a vezrlst.
Sokszor nem akarunk visszatrni a jelzskezelbl, knyelmesebb elug-
rani egy program adott pontjra. Ehhez a setjmp -longjmp prost vlaszthat-
juk. Az elbbi elmenti a kontextust a program egy adott pontjn egy bufferba,
a longjmp pedig visszalltja. Ez azrt fog mkdni, mert a longjmp a kernel
ltal belltott vermet fellrja a program setjmp ltal elmentett kontextus-
val, belertve az utastsszmllt is. gy a program a megfelel veremtarta-
lommal s kontextussal folytatja a futst a setjmp ltal kijellt helytl.
Knnyen lehet azonban, hogy a jelzskezelben ms jelzsek vannak letiltva
s engedlyezve, mint a setjmp ltal meghatrozott ponton. Mivel a setjmp
nem menti el a jelzsmaszkot, a jelzskezelben rvnyes maszkkal fut to-
vbb a program. Ha ezt el szeretnnk kerlni, akkor a hasznljuk a sigsetjmp
s a siglongjmp fggvnyeket, amelyek mindssze annyiban klnbznek a
setjmpllongjmp prostl, hogy ezek elmentik, illetve visszalltjk a jelzs-
maszkot is.
A processz ltrehozsval kapcsolatos szablyok az albbiak. Ha a fork
hvssal hozunk ltre j processzt, az rkli a szl ltal belltott elrendez-
seket s a jelzsmaszkot, viszont a fggben lv jelzseket nem. Az exec fgg-
vnycsald a jelzskezelkre belltott elrendezst alaprtelmezettre lltja,
ugyanis az j program betltsvel a jelzskezelk cme rvnytelenn vlik.
Minden egyb jelzsekkel kapcsolatos bellts megmarad.
5.6.3. A jelzskezel s a fprogram egymsra hatsa
Elsknt vizsgljuk meg annak hatst, hogy egy jelzs milyen llapotban ri
a processzt. Azt az esetet mr korbban trgyaltuk, amikor a processz ppen
fut: ilyenkor a kernel a jelzst azonnal kzbesti.
A rendszer vrakoz llapota valjban ktfle llapotot takar: megsza-
kthat (INTERRUPTIBLE) s megszakthatatlan (UNINTERRUPTIBLE).
Ez a megklnbztets pontosan a jelzsek miatt ltezik: megszakthatatlan
llapotban a processz nem fogadhat jelzst. Ilyenkor a generls megtrtnik,
de a kzbests majd csak akkor, ha a processz elhagyja ezt az llapotot.
A processz ltalban meglehetsen kevs idt tlt ebben az llapotban, fknt
merevlemezzel kapcsolatos mveletek esetben, ezrt ez legtbbszr nem
okoz problmt. Nagyon ritkn, de elfordulhat, pldul valamilyen lemezhiba
folytn, hogy a processz beragad ebbe az llapotba. Termszetesen ilyenkor
mg SIGKILL-t sem kpes fogadni, csak a rendszer jraindtsa segt a prob-
247
5. fejezet: Prhuzamos programozs
lmn. Ezt elkerlend, a Linux egy jabb llapotot is bevezet a megszaktha-
tatlan llapoton bell, ez a KILLABLE. Ebben az llapotban csak a SIGKILL
rkezsekor breszti fel (fut llapotba viszi t) a processzt, amelynek a futsa
a jelzs fontossgnak megfelelen rgtn megszakad.
A megszakthat llapotban rkezett jelzsek klnsen fontosak a prog-
ramoz szmra, ugyanis ebben az llapotban szoktak vrakozni a blokkold
rendszerhvsok, pldul a read fggvny. Ilyenkor a jelzs megszaktja a
rendszerhvst, majd a kernel lefuttatja a jelzs elrendezst. Ezutn kt v-
lasztsi lehetsgnk van: a rendszerhvsbl visszatrnk EINTR rtkkel,
vagy jraindtjuk a rendszerhvst. A jl megrt program fel van kszlve az
EINTR visszatrsi rtkre, s szksg szerint jraindtja a rendszerhvst.
Ezt mr bemutattuk a 4.1.5. Rszleges s teljes olvass alfejezetben:
while((len=read(STDIN_FRENo,buf,sizeof(buf)))!=0)
{
if(len==-1)
{
i f(errno==EINTR)
{
continue;//uj ramegprobalj uk
perror("read");
return-1;
if(write(STDOUT_FILENO,buf,len)==-1)
perror("write");
return-1;
}
Erre a megoldsra akr makrt is definilhatunk: ha a visszatrsi rtk hi-
ba, s az errno rtke EINTR, akkor egy while ciklusban mg egyszer meghv-
juk a fggvnyt:
#defineSIGNAL_RESTART(FUNC) while((FuNC)==-1&&errno==EINTR);

SIGNAL_RESTART(len=read(STDIN_FILEN0,buf,sizeof(buf)))
i f(len=-1)
//Tov bbihib k k ezel se
248
5.6. Jelzsek
Minden pontencilisan blokkold hvs mg a fenti makrba csomagolva
sem a legknyelmesebb megolds. A sigaction fggvny SA_RESTART para-
mtervel megadhatjuk, hogy az egyes jelzseknl a rendszer automatikusan
jraindtsa (jra meghvja) a megszaktott rendszerhvst. Ennek hasznlata
elg krlmnyes, mert jelzsenknt kell belltani az jraindtst, valamint
nem minden rendszerhvs indthat jra. Ezt az informcit a kziknyv 7.
fejezetben tallhat signal oldala rja le.
A msik problmt a fggvnyek nem globlis adatai okozhatjk (globlis
vltozk, statikus loklis vltozk). Pldul a printf fggvny globlis buffere-
ket mdost. Ha a printf egy futsa ppen mdostja a globlis buffert, de mg
nem vgzett a mvelettel, ebben az inkonzisztens llapotban meghvdik egy
jelzskezel, amely szintn hv egy printf-et, amely a globlis buffert inkonzisz-
tens llapotban tallja. Ilyenkor nagyon nehz megjsolni, mi lesz a program
mkdse, azt viszont nem nehz, hogy ez nagy valsznsggel nem az elvrt
viselkeds lesz. Hasonl a problma a memriafoglalsnl s -felszabadtsnl
(malloclfree), amelynek szmos implementcija globlis lncolt listban tart-
ja az adatokat. Ezeket a fggvnyeket nem reentrns fggvnyeknek nevez-
zk. Ha a jelzskezelben is s a fprogramban is hasznlunk nem reentrns
fggvnyeket, a program mkdse definilatlan. Ezt ltalban az albbi
szably betartsval szoktk elkerlni.
tmutat Ne hasznljunk a jelzskezelben nem reentrns fggvnyeket.
A reentrns fggvnyek listjt szintn a signal (7) kziknyoldala tartal-
mazza (jelzsbiztos fggvnyeknek nevezve ket). Tipikusan azok a fggv-
nyek nincsenek ezek kztt, amelyek valamilyen I/O mveletet vgeznek,
vagy a malloc/ free fggvnyek valamelyikt hvjk.
A kvetkez egymsra hats abbl ered, hogy egy mveleti hardverese-
mny ltal kivltott jelzs (SIGBUS, SIGILL, SIGSEGV, SIGFPE) feldolgozsa
utn a megszaktott program ugyanonnan folytatja a futst, ahol abbahagy-
ta. Ha pldul nullval val oszts trtnt, a jelzs feldolgozsa s a jelzske-
zel norml visszatrse utn folytaddik a program, amely jra elidzi a
nullval val osztst s vele egytt a jelzst is.
tmutat A hardveresemny ltal kivltott jelzsek esetben trekedjnk a legegyszerbb
megoldsra: hagyjuk rvnyeslni az alaprtelmezett kezels mechanizmust. Ha ez mgsem
oldhat meg, azok jelzskezelit vagy ugrutastssal (siglongjmp, longjmp), vagy az exit
fggvnnyel hagyjuk el.
Ha egy hardveresemny ltal kivltott jelzst figyelmen kvl hagyunk, a ker-
nel ennek ellenre kzbesti. Ha letiltjuk ket, akkor terminlja a programot.
249
5. fejezet: Prhuzamos programozs
5.6.4. Jelzsek s a tbbszl processz
Tbbszl programok esetn a szabvnyok s az implementcik arra tre-
kedtek, hogy megtartsk a jelzsek eredeti viselkedst abban az esetben,
amikor a processznek kldnk jelzseket, ugyanakkor megprbltk ezt ki-
egszteni egy intuitv s hasznlhat szlak kztti jelzskldssel. Egy
tbbszl programban a szlak nem osztoznak az albbiakon:
jelzsmaszk,
a mr emltett privt vrakozsi sor,
a kernel ltalt a jelzskezel'k szmra ltrehozott ideiglenes verem.
Ez azt jelenti, hogy a jelzselrendezsek viszont kzsek a szlakra nzve: ha
egy szl megvltoztat egy elrendezst, az az egsz processzre, gy a tbbi szl-
ra is rvnyes. Az alaprtelmezett elrendezsek kzl a STOP s a terminls
processzszint: a kernel az sszes szlat meglltja, illetve terminlja.
A legfontosabb krds az, hogy ki kapja a tbbszl processznek kldtt jel-
zst. Az egyes szlaknak kln kldtt jelzst (pthread_kill, pthread_sigqueue)
az adott szl kapja. Az azonnal kzbestett jelzseket (harverjelzsek s a
processz nmagnak kldtt jelzsei), valamint a SIGPIPE jelzst szintn.
A tbbit a kernel mind a processz vrakozsi sorban helyezi el. Ha a kernel
a processz vrakozsi sorban lv jelzst dolgoz fel, amelynek elrendezse egy
jelzskezel, akkor kivlaszt egy tetszleges szlat, amely nem tiltja le az adott
jelzst, s ezt megszaktva futtatja le a jelzst. Ha mindegyik blokkolja a jel-
zst, az termszetesen a vrakozsi sorban marad. Sajnos a szlkezel fggv-
nyeket, belertve a szinkronizcit is, nem hasznlhatjuk a jelzskezelben.
tmutat Szlakban ne hasznljunk aszinkron jelzskezelst. Lehetleg egyetlen szlban en-
gedlyezzk a jelzseket, s ott szinkron mdon kezeljk ket.
5.6.5. Jelzsek programozsa
A jelzsek mkdse utn vegyk sorra a programozs rszleteit. A program-
kdban ktflekppen valsthatunk meg jelzskezelst. Az egyik a mr is-
mertetett megolds, amikor jelzskezelt adunk meg. A msik lehetsg
amely nagyon hasonlt a select/poll fggvnyekhez az, hogy letiltjuk az
sszes letilthat jelzst, s egy fggvnnyel vrakozunk arra, hogy a
processz/szl vrakozsi sorba jelzs rkezzen Amikor a fggvny visszatr,
kezeljk a jelzst. Ez utbbi sokszor nagyon praktikus lehet kifejezetten sz-
lak esetn , sem a reentrns fggvnyekkel, sem pedig a jelzsek elveszts-
vel nem kell foglalkoznunk. Az els mdszert aszinkron jelzskezelsnek
(asynchronous signal handling), mg a msodikat szinkron jelzskezels-
250
5.6. Jelzsek
nek (synchronous signal handling) nevezzk. Hangslyozni kell, hogy csak a
jelzskezels szinkron, a kommunikci formja tovbbra is aszinkron, hiszen a
jelzst kld processz/szl nem vrakozik. A jelzskezlsnl viszont nem tet-
szleges helyen szaktja meg a programot, hanem szinkronizltan, a vrakoz-
fggvny belsejben. Nem kezelhetjk szinkron mdon sem a SIGKILL, sem a
SIGSTOP jelzseket, hiszen ezek elrendezst nem vltoztathatjuk meg, nem
tilthatjuk le ket, valamint nem is vrakozhatunk rjuk. A tovbbiakban sor-
ra vesszk azokat a fggvnyeket, amelyekkel mindezt megvalsthatjuk.
5.6.5.1. Jelzsek kldse
Jelzseket a ki//0 rendszerhvssal kldhetnk:
#include<sy s/ty pes.h>
#include<signal.h>
intk ill(pid_tpici,intsig);
Apid argumentum a processz azonostja, a sig pedig a jelzs azonostja.
A pid specilis rtkeivel lehetsgnk van arra, hogy az nit processzen s
sajt magn kvl az sszes processznek (-1) kldjnk jelzst. Ha a sig argu-
mentum nulla, akkor a ki//0 fggvny nem kld jelzst, de a hibaellenrzst
elvgzi. gy megnzhetjk, hogy van-e jogunk s lehetsgnk jelzst kldeni
egy processznek. Ha a pid kisebb, mint nulla, akkor a kernel a vltoz abszo-
lt rtknek megfelel processzcsoportnak kldi a jelzst. Ezt a konverzt
elvgzi helyettnk az albbi fggvny, ahol kzvetlenl megadhatjuk a pro-
cesszcsoport azonostjt:
#include<sy sity pes.h.
# nclude<signal.h>
intk illpg(intpgrp,intsig);
"1111
,
111
~EMIL
A pgrp argumentum a processzcsoport azonostja, nulla esetn a hv pro-
cessz sajt csoportjnak kldi a jelzst. Vals idej jelzseket a sigqueue fgg-
vnnyel kldhetnk:
#include<signal.h.
intsigqueue(pid_tpid,intsig,constunionsigv alv alue); -
Ahogy sz volt rla, a kernel megrzi az ezzel a fggvnnyel kldtt jelzsek
sorrendjt, s ha tbbszr kldnk ugyanolyan jelzst, azt ugyanannyiszor
kzbesti. A fggvny els argumentuma a cmzett processz azonostja, a
msodik a kldend jelzs. A nulla jelzs itt is hasznlhat a jogosultsg ki-
dertsre. Mivel a hagyomnyos jelzsektl eltren a vals idej jelzsek
2 51
5. fejezet: Prhuzamos programozs
nem hordoznak elre definilt jelentst, egy tovbbi, programoz ltal defini-
lt kiegszt adatot is tkldnk. A fggvnyek ezen harmadik argumentu-
mt hasznlhatjuk egsz szmknt vagy pointerknt:
union sigval

{
int sival_int ;
vod *sival_ptr ;
}; - - - - - -
Arra azonban oda kell figyelnnk, hogy ha a cmzett processz nem azonos a
kld processzel, akkor a kld processz cmtartomnynak egy processze
nem lesz rvnyes a cmzett processz cmtartomnyban. Ezrt a fenti lehet-
sgek kzl ezt az argumentumot ltalban egsz rtkknt kezeljk.
Szlak esetn a pthread_kill s a Linux-specifikus pthread_sigqueue fgg-
vnyt hasznlhatjuk. Mindkt esetben csak a sajt processzbeli szlaknak
kldhetjk a jelzst. Mind szlakra, mind processzekre mkdik az albbi fgg-
vny, amellyel sajt magunknak kldhetnk jelzst:
#include <signal .h>
int raise(int sig);

Ha a fggvnyt tbbszl programbl hvjuk, akkor a kernel a hv szlnak,
ellenkez esetben a hv processznek tovbbtja a jelzst.
Jllehet jelenleg a Linux sszes jelzskld fggvnye tmogatja a vals
idej jelzseket, ez a megolds nem hordozhat, s nincs garantlva, hogy
mindig gy lesz a Linux alatt.
tmutat Ne keverjk a jelzskld fggvnyek s a jelzsek tpusait. Vals idej jelzseket
(SIGRTMIN s SIGRTMAX kztt) mindig sigqueuelpthread_sigqueue fggvnyekkel kldjnk, ha-
gyomnyos jelzseket pedig a killIkillpg/raise/ pthread kill fggvnyekkel. Vals idej jelzsek
kezelsekor mindig lltsuk be a SA_SIGINFO jelzbitet a sigaction fggvny belltsai kztt.
A kldshez val jogosultsgot a kernel az albbi szablyok alapjn dnti el.
A CAP KILL jogosultsggal rendelkez processz brmely processznek kldhet
jelzst. Ahogy emltettk, az init processznek csak olyan jelzst kldhetnk,
amelynek elrendezsre jelzskezelt adott meg. Kln jogosultsgokkal nem
rendelkez processzeknl az albbiak szerint trtnik a dnts. A kernelnek
a kld processz valdi s effektv azonostja szmt. A kernel ezt veti ssze
a cmzett processz valdi s elmentett azonostjval. Ez a kvetkezt jelenti.
Ha nem setuiddal fut a program, akkor a valdi azonost s az effektv meg-
egyezik: gy a jogosultsg vizsglatt a valdi azonost alapjn is el lehet v-
gezni. Ha setuid privilgiumokkal fut a program, akkor pedig egy processz
mindig tud a gyermekeinek zenetet kldeni, hiszen az elmentett azonostja
sajt maga lesz. Mivel az effektv azonostt a kernel nem ellenrzi, ezert egy
252
5.6. Jelzsek
A felhasznlhoz tartoz processz nem tud olyan processznek jelzst kldeni,
amelyet B felhasznl indtott, de a setuid miatt A nevben fut. Egy kivtel
akad: SIGCONT jelzst brmelyik, a kldvel egyez munkamenetben lv
processznek el lehet kldeni. Ez lehetv teszi, hogy a shell akkor is jraindt-
hasson processzeket, ha azok megvltoztattk a felhasznli azonostjukat.
5.6.5.2. Jelzsek letiltsa s engedlyezse. Fggben lv
jelzsek
Szmos fggvny egy jelzshalmazon vgez mveletet. Ezt a halmazt a sig-
set_t adattpus reprezentlja, amely a signal.h llomnyban van definilva.
A POSIX-szabvny 5 fggvnyt definil ennek a halmaznak a kezelsre:
intsigempty set(sigset_t*set);
intsigfillset(sigset_t*set);
intsigaddset(sigset_t*set,intsignum);
intsigdelset(sigset_t*set,intsignum);
intsigismember(constsigset_t*set,intsignum);
A sigemptyset fggvny trli az sszes elemet a halmazbl. Ennek ellenkezje
a sigfillset, amely minden jelzst beletesz a halmazba, belertve a vals idej
jelzseket is. Egyetlen signum jelzst a sigaddset fggvnnyel adhatunk hoz-
z a halmazhoz. Ennek ellenkezje a sigdelset, amely a signum ltal megha-
trozott jelzst trli a halmazbl. A sigismember fggvnnyel lekrdezhetjk,
hogy egy adott jelzs eleme-e a halmaznak. Ha a jelzs szerepel a halmazban,
akkor 0-tl eltr rtkkel tr vissza, egybknt 0-val. Ezek a fggvnyek
csak akkor trnek vissza hibval, ha az argumentumknt megadott jelzs
helytelen. Ezeken kvl a tovbbi Linux-specifikus fggvnyek is rendelke-
zsre llnak
.
sigandset (halmazok metszete), sigorset (halmazok unija), sigis-
emptyset (ressg vizsglata).
Ahogy sz volt rla, a processz jelzsmaszkja tartalmazza azt a belltst,
hogy melyik jelzs van letiltva, illetve engedlyezve. Ezt egy sigset_t adat-
struktra valstja meg: a halmaz a letiltott jelzseket tartalmazza. A mr
emltett sigprocmask() fggvny teszi lehetv, hogy a lekrdezzk/bellthas-
suk a processz jelzsmaszkjt:
ncl ude<signal.h>
intsigprocmask (intwhat,constsigset_t*set,sigset_t*oldset);
Az els paramter, a what, azt hatrozza meg, hogy a jelzsmaszkot hogyan
mdostjuk. rtkeit az 5.10. tblzat tartalmazza.
253
5. fejezet: Prhuzamos programozs
5.10. tblzat. A sigprocmask mveletei
Parancs Lers
SIG_BLOCK A setben lev jelzsek hozzaddnak a maszkhoz.
SIG_UNBLOCK A setben lv jelzsek trldnek a maszkbl.
SIG_SETMASK A set tartalma lltdik be mint j maszk.
Ha megadunk egy halmazt utols paramterknt (nem NULL), akkor abban
visszatrskor az elz jelzsmaszkot kapjuk vissza.
Ha a jelzsmaszk aktulis rtkt szeretnnk lekrdezni, set paramter-
knt NULL rtket adunk t Ilyenkor a fggvny az els paramtert nem veszi
figyelembe. Visszatrskor az oldset tartalmazza az aktulis rtket. Ahogy sz
volt rla, a tbbszl programban az egyes szlak nem osztoznak a jelzsmasz-
kon, gy a sigprocmask viselkedse ilyenkor nem specifiklt. Ezrt tbbszl
programban az azonos paramterezs pthread_sigmask fggvnyt hasznljuk.
A fgg'ben lv jelzsek halmazt az albbi fggvnnyel krdezhetjk le:
#include <signal .h>
int sigpending(sigset_t *
set);
A fggvny visszatrsekor a set vltozban adja vissza a fggben lv jelz-
sek halmazt. Tbbszl programban ez a megosztott vrakozsi sorban s a
hv szlhoz rendelt privt vrakozsi sorban tallhat jelzsek unija.
Ha egy fggben lv jelzst szeretnnk eltvoltani a jelzslistrl, akkor
elszr tlltjuk az elrendezst: figyelmen kvl hagyjuk, azutn pedig en-
gedlyezzk. Mivel a letiltott jelzsek az engedlyezs utn az j elrendezs
szerint kezeldnek, ezrt a jelzs minden mellkhats nlkl eltnik a felfg-
gesztett jelzsek vrakozsi sorbl. Erre a technikra azonban ritkn van
szksgnk.
5.6.5.3. A jelzsek kezelse
A POSIX-programok a jelzsek kezelfggvnyt a sigaction() fggvnyhvs-
sal regisztrlhatjk, illetve krdezhetik le:
#include <signal . h>
int sigaction(int signum, struct sigaction * act,
struct sigaction * oact);
Ez a rendszerhvs belltja a signum ltal meghatrozott jelzsre az act
struktra ltal lert lekezel fggvnyt. Ha az oact nem NULL, akkor a ko-
rbbi kezelfggvny-belltsokat tartalmaz struktra rtkt veszi fel. Ha
az act rtke NULL, akkor a fggvny nem llt be semmit, hanem visszaadja
az aktulis belltsokat.
254
e

5.6. Jelzsek
A kezelfggvnyt a sigaction struktra rja le:

#include <signal .h>
struct sigaction
sighandler_t sa_handler;
sigset_t sa_mask;
unsigned long sa_flags;
void (* sa_restorer)(void);
);
Az sa_handler fggvnypointer, amelynek prototpusa a kvetkez:
void handler(int signum);
ahol a signum rtke a jelzs szma, amellyel a kernel a fggvnyt meghvta.
A fggvnypointeren kvl felveheti a SIG_DFL s a SIG_IGN rtkeket is:
az els az alaprtelmezettre lltja, a msodik esetn a jelzst a processz fi-
gyelmen kvl hagyja.
A struktra tartalmaz tovbb egy jelzslistt (sa_mask). Ezeket a jelz-
seket a rendszer hozzadja a a jelzsmaszkhoz a kezelfggvny futsnak az
idejre, majd a jelzskezel visszatrst kveten visszalltja az eredeti r-
tkre. A jelzskezel hvst kivlt jelzst a fggvny automatikusan letiltja,
fggetlenl attl, hogy szerepel-e ebben a listban, vagy sem. (Ha mgsem
akarjuk, hogy blokkoldjon, akkor ezt az saJlags paramterrel befolysolhat-
juk.) Ezzel megelzzk, hogy ugyanannak a jelzsnek az rkezse megszakt-
sa a jelzskezelt annak egy kvetkez hvsval. Ha tbb jelzst kezelnk
ugyanazzal a fggvnnyel, futsnak az idejre a jelzsmaszkkal tiltsuk le az
sszes ltala kezelt jelzst.
Az sailags vltoz rtkei jelzbitek, amelyeket bitenknti VAGY kapcso-
lattal kombinlhatunk. Ezeket a jelzbiteket az 5.11. tblzat foglalja ssze.
5.11. tblzat. A sigacton struktra lehetsges jelzbitjei
Parancs Lers
SA NOCLDSTOP Norml esetben, ha egy processz gyerekprocessze megsznik,
vagy megll, akkor egy SIGCHLD jelzst kld. Ha ezt az opcit
belltjuk a SIGCHLD jelzsre, akkor csak a megszns esetn
kldi el.
SARESTART Automatikusan jraindtja a megszaktott rendszerhvsokat
(lsd az 5.6.3. A jelzskezel s a fprogram egymsra hatsa
alfejezetben).
SANODEFER Amikor a jelzs kezelfggvnye meghvdik, akkor a jelzs nem
tiltdik automatikusan. (Hasznlata nem javasolt, csak specilis
esetekben.)
2 55
S. fejezet: Prhuzamos programozs
Parancs Lers
SA_ONSTACK Megadhatjuk a jelzskezel veremterlett, amelyet a signal-
stack fggvnnyel hozunk ltre.
SA RESETHAND Akkor hasznljuk, ha azt akarjuk, hogy a jelzskezel csak egy-
szer hvdjon meg. Miutn a kezelfggvny meghvdott, a be-
llts alaprtelmezettre lltdik. Ha ezt nem adjuk meg, akkor
a jelzskezel addig rvnyes, amg egy tovbbi sigaction hvs-
sal meg nem vltoztatjuk.
SA_SIGINFO A jelzskezel paramtereket vr.
SA NOCLDWAIT A SIGCHLD jelzsre hasznljuk: ilyenkor a gyermekprocesszek
nem vltoznak zombiv.
Feladat rjunk olyan jelzskezelt, amely tlltja egy globlis vltoz rtkt a SIGALRM jel-
zsre. lltsuk t a SIGALRM elrendezst a jelzskezelre.
A globlis vltoz deklarcijt s a jelzskezelt az albbi kdrszlet mutatja be:
static volatile sig_atomic_t timer;
static void tmer_handler(int sgno)
{
ti mer =1;
Az egsz rtk sig_atomic_t tpussal kapcsolatban a fordtk garantljk,
hogy hozzfrs atomi mvelet. A volatile mdostt azrt rjuk el, hogy
a fordt az optimalizls miatt nehogy regiszterben trolja, mert a jelzs a
kernel ltal a jelzs szmra sszelltott kln kontextusban fut, ahol nem
ltja a fprogram regisztereit s fordtva. A static kulcsszt azrt rjuk ki,
mert nem szeretnnk, ha ms modulok is hozzfrnnek. A jelzskezel a jel-
zs azonostjt kapja meg, gy egyszerre tbbfle jelzst is tudunk ugyanaz-
zal a fggvnnyel kezelni. A fggvny trzse esetnkben nagyon egyszer:
tlltja a globlis vltoz rtkt.
A regisztrlst vgz kdrszlet a kvetkez:
struct sigaction sa;

// timer_handler regisztrlsa a SIGALRM jelzsre
sigemptyset(&sa.sa_mask);
sa.sa_flags=0;
sa.sa_handler =timer_handler;
sigaction(SIGALRM, &sa, NULL);
Az sa_mash mezt res halmazra lltjuk, mert mst jelzst nem tiltunk le, a
SIGALRM pedig automatikusan letiltdik.
256
5.6.Jelz sek
Ha mr nincs szksgnk az idztsre, szeretnnk visszalltani a jelzs
elrendezsnek eredeti llapott:
structsigaction sa, saold;
//timer_handlerregisztr l saaSIGALRMj elz sre
sigempty set(&sa.sa_mask );
sa.sa_flags=0;
sa.sa_handler=timer_handler;
//Be ll t sk orelementj k azelz llapotot
sigaction(5I6AtRm,&sa,&saold);
sigaction(SIGALRm,&saold,0);//Afeladatv gezt v el
//v issza ll tj uk
Termszetesen alaprtelmezettre is llthatjuk az elrendezst:
sigemptyset(&sa.sa_mask);
sa.sa_flags=0;
sa.sa_handler = SIG_DFL;
sigaction(SIGALRM,&sa,NULL);
Ha a SIG_DFL helyett SIG_IGN-t hasznluk, akkor a processz figyelmen k-
vl hagyja a jelzst.
A sigqueue fggvny trgyalsnl emltettk, hogy jelzsekkel param-
tereket is lehet kldeni. Ennek az adatnak a fogadst egy ms prototpus
jelzskezelvel tehetjk meg, de ehhez meg kell adnunk az SA_SIGINFO jel-
zbitet is:
v oidhandler(intsignum,siginfo_t* nfo, void * param)
t

sa.sa_flags = SA_SIGINFO;
Az els paramter a jelzs azonostja, a msodik a jelzssel s kldjvel
kapcsolatos rszletes informcit tartalmaz struktra, s az utols a jelzs
kontextust ler ucontext_t tpus paramter, amelyet nem rszleteznk.
A jelzssel kapcsolatos informci tartalmazza az elkldt adatot is az si_value
mezben. A struktrt rszleteiben nem ismertetjk, a kziknyv sigaction le-
rsban megtallhatjuk a kifejtst.
A sigaction meglehetsen egyszer eldje a signal fggvny, amelynek
implementcii jelentsen eltrhetnek az egyes rendszereken, gy nehezen
hordozhat. Ugyanakkor az alaprtelmezett elrendezs s a jelzs figyelmen
kvl hagysa egyszeren (s hordozhatan) bellthat vele:
2 57
5. fejezet: Prhuzamos programozs
signal(sig, SIG_DFL);
signal(sig, SIG_IGN);
tmutat A fenti kt esettl eltekintve hasznljuk a sigaction fggvnyt a signal fggvny
helyett.
5.6.5.4. Szinkron jelzskezels
Szinkron jelzskezelskor egy fggvnnyel vrakozunk a jelzsre, amelyre a
vrakozfggvny visszatrsekor reaglunk. Ez a megolds klnsen hasz-
nos szlak esetben, ahol sokkal bonyolultabb szablyok rvnyesek a jelzs
kzbestsre. Ebben a rszben ezeket a vrakozfggvnyeket trgyaljuk.
Elsknt kt fggvny mutatunk be, amelyek nem tekinthetk a sz leg-
szorosabb rtelmben vett szinkron jelzskezelnek, hiszen jelzskezelt
hasznlnak. Ugyanakkor itt is azonosthat a program egy pontja, ahol a fu-
ts megll, s vrakozik a jelzsre. A kt fggvny kzl a legegyszerbb a
pause, amelynek alkalmazst mr az elvi megfontolsok alatt elvetettk.
A mr emltett sigsuspend0 fggvny a processz felfggesztsnek egy msik
lehetsgt jelenti:
#include <signal.h
int sigsuspend(const sigset_t * mask);
!!"
10
ffikr
A sigsuspendO meghvsakor a processz jelzsmaszkjt a paramterben meg-
adottra lltja, vagyis a halmazban szerepl jelzseket letiltja, s vrakozni
kezd a jelzsre. Ezt egy atomi mvelet keretben hajtja vgre: a processz nem
kaphat jelzst a jelzsmaszk belltsa s a vrakozs megkezdse kztt.
A fggvny a jelzs elrendezsnek lefutsa utn rgtn visszalltja a maszkot
a meghvs eltti llapotra, majd hibtlan mkds esetn EINTR rtkkel tr
vissza: a legtbb fggvnynl hiba a jelzs ltali megszakts, itt ppen a nor-
ml visszatrs oka.
Feladat rjunk olyan programot, amely felhz egy idztt, s vrakozik az ALRM jelzsre.
A feladat egy lehetsges megoldst az albbi kdrszlet mutatja be:
#nclude <signal.h>
#include <unstd.h>
#include <stdi.h>


static volati le sig_atomic_t timer;
static void timer_handler0
{
timer =1;
258
5.6. Jelzsek
intmain()
sigset_talarmMask ,suspendMask ;
structsigactionsa,saold;
timer=0;
sigempty set(&alarmmask );
sigaddset(&alarmmask ,SIGALRM);
//Atimer_handlerregisztr l saaSIGALRMj elz sre
sigempty set(&sa.sa_mask );
sa.sa_flags=0;
sa.sa_handler=timer_handler;
sigaction(SIGALRM,&sa,&saold);
//ASIGALRMletilt sa
sigprocmask (SIG_BLOCK,&alarmask ,&suspendMask );
//Haezeredetileglev olttiltv a,
//elt v ol tj uk ,hogy asigsuspendv isszat rj enr
sigdelset(&suspendMask ,SIGALRM);
alarm(10);//10masodpercmlv aSIGALRMj elz s
while(!timer)
{
//Kritik usszek civ ge-SIGALRMenged ly ez se,v rak oz s
sigsuspend(&suspendMask );//Az tadottj elz saSIGALRM
//Visszat r sut nah v sel tti llapotot ll tj av issza
printf("Meg rk ezett\n");
//Vissza ll tj uk azeredetielrendez st
sigaction(SIGALRM,&saold,0);
return(alarm(0));//Kik apcsolj uk azidz tt
Az igazi szinkron jelzskezels sorn letiltjuk a jelzskezelket, az sszes jel-
zst blokkoljuk, s a vrakozfggvnyek a processz privt s publkus vra-
kozsi sorbl veszik az adatot. Ezt kt fggvnnyel valsthatjuk meg:
#include<signal.h>
intsigwaitinfo(constsigset_t*set,siginfo_t*Info);
intsigtimedwait(constsigset_t*set,siginfo_t*info,
conststructtimespec*timeout);
A kt fggvny mkdse azonos, leszmtva, hogy a sigtimedwait lehets-
get ad egy ti meout paramter megadsra. Ha a timeout letelt, s nem rke-
zett alkalmas jelzs, visszatr.
2 59
5.fej ezet:Prhuzamos programozs
A fggvnyek els paramtere azon jelzsek halmaza, amelyre vrakozni
szeretnnk. Ha a jelzs megtallhat a szl privt vagy a processz publikus
vrakozsi sorban, rgtn visszatr. Ha nem, akkor addig vrakozik, mg gy
nem trtnik. A jelzseket ugyanolyan sorrendben kapjuk meg, mint a jelzs-
kezelk esetben. Ha az utols paramter nem nulla, a sigactionnl emltett
(de nem rszletezett) jelzsinformcit kapjuk vissza.
FeladatOldjuk meg azelbbifeladatot szinkron jelzskezelssel.
#include<signal.h>
#include<unistd.h>
#include<stdio.h>
intmain()
f
sigset_talarmMask ,fullmask ;
sigempty set(&alarmmask );
sigaddset(&alarmmask ,SIGALRM);
/7 ASIGKILL sSIGSTOP j elz sek enk iv lazsszesj elz s
//letilt sa
sigf llset(&fullmask ):
sigprocmask (5IG_BLOck ,&fuliMask ,NULL);
}
alarm(10);//10masodpercmlv aSIGALRMj elz s
sigwaitinfo(&fullMask ,NULL);
printf("meg rk ezett\n");
return(alarm(0)); /7 Kik apcsolj uk azid zitt
Egy nagyon hasznos Linux-specifikus fggvny a signalfd, amely llomnyle-
rn keresztl is olvashatv teszi a jelzst:
wi
llik int signalfd(int fd, const sigset_t * mask, int flags);
Ha az els paramternek 1-et adunk t, akkor a visszatrsi rtk egy olyan
llomnyler, amelyet, ha szignl tallhat a privt vagy a publikus vrako-
zsi sorban, akkor olvashatunk is ekkor struct signalfd_siginfo tpus adatot
kapunk vissza, amely a jelzshez kapcsold informcit tartalmazza. A m-
sodik paramter azokat a jelzseket foglalja magban, amelyekre kvncsiak
#include<sy s/signalfd.h>
2 60
5.6.Jelzsek
vagyunk, vagyis amelyek adataihoz az llomnylerbl val olvasssal hozz
szeretnnk frni. Az utols paramter az albbi kt jelzbitet vagy azok VAGY
kapcsolatt tartalmazhatja: SFD_NONBLOCK s SFD_CLOEXEC ezek
megfelelnek az llomnyok megnyitsnl megismert O_NONBLOCK s
0 CLOEXEC jelzbiteknek. Ha az els paramter egy rvnyes, a fggvny
elz hvsval ellltott llomnyler, akkor a signalfd a maszk rtkt l-
ltja t a mr ltez lern.
Feladat Vrakozzunk a S/G_ALRM jelzsre s a szabvnyos bemenetre egyszerre.
A feladat egy lehetsges megoldsa az albbi:
#include <signal.h>
#include <unistd.h>
#include <stdio.h>
#include sys/select.h
#include sys/signalfd.h>
#include <fcntl.h>
,nt main()
sigset_t alarmMask, fullmask;
int fd;
struct signalfd_siginfo info;
11 I
I
int ret;
sigemptyset(&alarmmask);
sigaddset(&alarniMask, SIGALRM);
// Az sszes jelzs letiltsa
si gfi 1 1 set(8/ful 1 mask) ;
sigprocmask(5IG_BLOCK, &filllmask, NULL);
/7 Ler ltrehozsa
fd =signalfd(-1, &alarmmask, 5Fp_N0NBL0Ck);
alarm(10); // 10 masodperc mlva SIGALRM jelzs
// A select az stdinnre es a jelzs lerjra figyel
fd_set readfds;
FD_SET(STDIN_FILENO, &readfds);
FD_SET(fd, &readfds);
select(fd+1, &readfds, NULL, NULL, 0);
if(FD_ISSET(fd, &readfds)) // Na benne van az eredmnyhalmazban
{
ret =read(fd, &info, sizeof(struct signalfd_siginfo));
printf("%d processz jelzest kuldott.\n", info.ssi_pid);
}
26]
5. fejezet: Prhuzamos programozs
close(fd); // Le kell zrnunk az llomnylert
printf("megrkezett vagy megnyomtk.\n");
return(alarm(0)); // Kikapcsoljuk az idzitt
}
5.6.6. A SIGCHLD jelzs
A processzek trgyalsnl (lsd az 5.1. Processzek alfejezetben) mr emltet-
tk, hogy a processzek a kilps utn nem sznnek meg teljesen: nhny lekr-
dezhet statisztikt s a kilpsi rtket tartalmaz adatstruktrkat megrzik,
hogy a szlprocessz le tudja krdezni ezeket. Ezt a processzllapotot neveztk
zombinak. A zombiprocesszeket gy szabadthatjuk fel, hogy meghvjuk vala-
melyik wait fggvnyt vagy blokkok, vagy nem blokkolt mdon.
A gyermekprocessz kilpsrl, azaz zombillapotba kerlsrl a szl-
processz SIGCHLD jelzst kap. Mivel a wait fggvnyek jelzsbiztosak, a jel-
zsbl rgtn meg is hvhatjuk 'ket az albbiak szerint:
i nt oldErrno =errno;
while (waitpid(-1, NULL, WNOHANG) >0)
continue;
errno =oldErrno;
A fenti kdrszlet vgigiterl az sszes kilpett (zombi) gyermekfolyamaton. Ha
nincs tbb ilyen gyermekfolyamat, a fggvny nullval tr vissza, s a ciklus
vget r. Akkor is kilpnk, ha hiba trtnt. Mivel az errno vltozt a fprog-
ram is hasznlhatja, ezrt elmentjk, s visszaWtjuk, ha a waitpid esetleg
megvltoztatta volna. A zombik begyjtsre ez a leghordozhatbb megolds.
tmutat A jelzskezelkben mindig gondoskodjunk az errno vltoz elmentsrl s vissza-
lltsrl, ha olyan fggvnyt hvunk, amely tllthatja az errno vltozt.
Ha azt szeretnnk, hogy a szl rtestst kapjon arrl, hogy a gyermekpro-
cessz jelzst kapott, akkor a sigaction fggvnynek meg kell adnunk a
SA_NOCLDSTOP jelzbitet, amikor a SIGCHLD jelzskezeljt belltjuk.
Ha le szeretnnk tiltani azt, hogy egy mr ltez processz zombiv alakul-
jon, tbb mdszer is ltezik. A SIGCHLD jelzs alaprtelmezett belltsa a
figyelmen kvl hagys. Ennl az egy jelzsnl mst jelent, ha meghagyjuk az
alaprtelmezettet, vagy expliciten belltjuk a jelzs figyelmen kvl hagy-
st. Az utbbi esetben a processz gyermekprocesszeibl nem kpzdik zombi,
262
5.6. Jelzsek
kilpskor megsznnek A bellts eltt mr zombiv alakult folyamatok
viszont nem sznnek meg. Nagyon hasonl mkdst rhetnk el, ha a
sigaction hvs SA_NOCLDWAIT kapcsoljval lltjuk be e jelzskezelt.
Ilyenkor szintn nem alakulnak zombiv a gyermekprocesszek, viszont meg-
sznskrl jelzst kapunk. Ekkor termszetesen nem frnk hozz a statisz-
tikkhoz s a visszatrsi rtkekhez. Figyeljnk arra, hogy a jelzskezelt
vagy a figyelmen kvl hagyst mg az els gyermekprocessz ltrehozsa eltt
belltsuk, klnben lemaradhatunk az rtestsrl.
263
HATODIKFEJEZET
Hlzati kommunikci
Mai, szmtgp-hlzatokkal tsztt vilgunkban a Linux rendszerek egyik f
alkalmazsi terlett a hlzati alkalmazsok jelentik. Ebben a fejezetben
ezeknek a kommunikciknak a megvalstsi alapjait ismerjk meg. Nem fog-
lalkozunk az sszes protokollal, jllehet a Linux tbbet is tmogat (TCP/IP,
AppleTalk, IPX stb.). Ezek rszletes ismertetse meghaladn a knyv kereteit.
Vizsgldsunk egyik terlete a Berkeley socket-API, amely tulajdonkp-
pen egy ltalnos kommunikcis interfsz. Mi kt implementcijt trgyal-
juk. A legfontosabb a TCP/IP protokoll hasznlata, amely lnyegben mkd-
teti az internetet. A msik, egyszerbb protokoll a Unix domain socket, amely
tulajdonkppen nem hlzati kommunikci, hanem egy olyan IPC-mechaniz-
mus, amely csak egy gpen bell hasznlhat, m a programozs hasonlsga
miatt itt trgyaljuk.
Tovbb megismerhetjk a TCP/IP-re pl tvoli eljrshvst (Remote
Procedure Calling, RPC). Ez egy magasabb szint, ltalban egyszerbben
hasznlhat kommunikcis metdus.
6.1. A socket
Mint a Linux ms erforrsait, a socketeket is a fjlabsztrakcis interfszen
keresztl implementltk a rendszerbe. A hlzati kapcsolatnak azokat a
vgpontjait, amelyeket a programoz hasznlhat, socketeknek nevezzk, ezek
egyben egy llomnytpust is jelentenek. Ltrehozsuk a socket0 rendszerh-
vssal trtnik, amely egy llomnylerval tr vissza. Miutn a socketet ini-
cializltuk, a read0 s a write() fggvnyekkel kezelhet, mint minden ms
llomnyler, hasznlat utn pedig a close0 fggvnnyel le kell zrnunk.
j socketeket a socket0 rendszerhvssal hozhatunk ltre, amely az inici-
alizlt socket llomnylerjval tr vissza. Ltrehozsakor a sockethez egy
meghatrozott protokollt rendelnk, m ezek utn mg nem kapcsoldik se-
hov. Ebben az llapotban mg nem olvashat vagy rhat:
6. fejezet: Hlzati kommunikci
#include <sys/socket.h>
int .ocket (i nt domain, nt type, int protocol);
Mint az openO, a socket() is 0-nl kisebb rtkkel tr vissza hiba esetn, s ha
sikeres, az llomnylerval, amely 0 vagy annl nagyobb.
Hrom paramter definilja a hasznland protokollt. A domain a proto-
kollcsaldot adja meg, s rtke a 6.1. tblzatban tallhat lista valamelyike:
6.1. tblzat. A protokolcsctldokhoz tartoz rtkek
Protokoll Jelents
PF_UN1X, PF_LOCAL Unix domain socket (gpen belli kommunikci)
PF INET IPv4 protokoll
PF INET6 IPv6 protokoll
PF IPX Novell IPX
PF NETLINK A kernel felhasznli interfsze
PF X25 X.2 5 protokoll
PF AX25 AX.2 5 protokoll, a rdiamatrk hasznljk
PF ATMPVC Nyers ATM-csomagok
PF APPLETALK AppleTalk
PF PACKET Alacsony szint csomaginterfsz
A kvetkez paramter, a type, a protokollcsaldon bell a kommunikci
mdjt definilja a 6.2. tblzatban tallhat rtkek egyikvel.
6.2 . tblzat. A kommunikci lehetsges mdjai
Tpus Jelents
SOCK STREA11
,
1
Sorrendtart, megbzhat, ktirny, kapcsolatalap
byte-folyam-kommunikcit valst meg.
SOCK DGRA111
Datagramalap (kapcsolatmentes, nem megbzhat)
kommunikci.
SOCK SEQPACKET
Sorrendtart, megbzhat, ktirny, kapcsolatalap
kommunikcis vonal, fix mret datagramok szmra.
SOCK RAW Nyers hlzatiprotokoll-hozzfrst tesz lehetv.
SOCK RDM
Megbzhat datagramalap kommunikcis rteg. (Nem
sorrendtart.)
SOCK PACKET Elavult opci.
2 66
6.2 . Az sszekttets-alap kommunikci
Az utols paramter, a protocol, a protokollcsaldon bell konkretizlja a pro-
tokollt az adott kommunikcis mdhoz. A csaldokon bell ltalban csak
egy protokoll ltezik egy tpus kommunikcira, amely egyben az alaprtel-
mezett. gy ennek a paramternek az rtke leggyakrabban O. Pldul a
PF_INET csaldon bell a TCP (Transmission Control Protocol) az alapr-
telmezett folyamprotokoll, s az UDP a datagramalap.
m egy kivtelt is mutathatunk. Ez a SOCK RAW kommunikcis md.
A SOCK RAW md pldul a PF INET csald vlasztsval lehetv teszi
olyan socketek ltrehozst, ahol az IPv4 kommunikcis protokoll implemen-
tlst a felhasznli tartomnyban vgezzk el. m ennl tbbre is kpes.
Az utols, protocol paramterknt megadhatunk a 0 mellett olyan rtkeket
is, mint az IPPROTO_RAW, az IPPROTO_ICMP, az IPPOROTO_IGMP, az
IPPROTO TCP, az IPPROTO_UDP. Ezzel olyan protokollokat is elrhetnk
a csaldbl, amelyet a tbbi paramterrel nem (ICMP, IGMP).
78

A kommunikcis tpusok listjt vgignzve lthatjuk, hogy alapveten
kt rszre oszlanak: a kapcsolat- vagy sszekttets-alap, illetve a kapcsolat
vagy sszekttets nlkli kommunikci. Az sszekttets-alap kommuni-
kci egy kapcsoldsi folyamattal kezddik, amelynek eredmnyekppen egy
folyamatos kapcsolatot hozunk ltre kt fl kztt. Ennek sorn lnyegben
egy ktirny csatorna jn ltre, amelyen a programok oda-vissza kommuni-
klhatnak. A kommunikci vgn pedig le kell bontani a csatornt.
Az sszekttets nlkli kommunikci esetben viszont elmarad a kapcso-
ldsi folyamat. A kikldtt csomagjainkat kln-kln cmezzk s kldjk a
tbbi kommunikcis rsztvevnek. Tovbb brkitl kaphatunk is csomagot.
A kommunikci vgn a kapcsolatot sem kell lebontanunk, csak abbahagy-
juk a kommunikcit.
Analgiaknt nzhetjk a telefonlst s az SMS-kldst. A telefonls a
kapcsolatalap kommunikcira hasonlt. Trcsznunk kell a kommunikci-
s partnernket, neki fogadnia kell a hvst, beszlgetnk, s a vgn bon-
tunk. Az SMS esetn azonban nem kell vgigvinnnk a hvsi folyamatot,
csak megcmezzk az zenetet, s elkldjk. Ugyangy brmikor kaphatunk
msoktl is zeneteket.
6.2. Az sszekttets-alap kommunikci
Els lpsknt az sszekttets-alap kommunikcit tekintjk t. Ennek a
kommunikcis mdnak lnyeges rsze a kapcsolat felptse Amikor ez lt-
rejn, a kommunikci hasonlan trtnik, mint korbban a csvezetkeknl
lttuk. Majd a prbeszd vgn valamelyik fl bontja a kapcsolatot. Nzzk
meg sorban ezeket a mveleteket.
78
A SOCK RAW mdot csak rendszergazdai jogosultsgokkal fut folyamatokban hasznl-
hatjuk.
2 67
6. fejezet: Hlzati kommunikci
6.2.1. A kapcsolat felptse
Ha egy sszekttets-alap kapcsolatotadatfolyam-socketet (stream socket)
hoztunk ltre, akkor hozz kell kapcsoldnunk egy msik gphez. A socket
kapcsoldsa aszimmetrikus mvelet, vagyis a ltrejv kapcsolat kt oldaln
a feladatok eltrnek egymstl. A kapcsolat felptst kveten a kommuni-
kci viszont mr szimetrikus.
A kliensoldalon a socket ltrehozsa utn kapcsoldunk (connect) a szer-
verhez. Ha a kapcsolds sikeres (a szerver elfogadja a kapcsoldsi krel-
met), akkor a socketen mint llomnylern keresztl tudunk adatot kldeni
s fogadni. Ezt a tpus socketet klienssocketnek nevezzk.
A szerver s a kliens kzti lnyeges klnbsg a kapcsolat felptsben s
a kezelend socketek szmban rejlik. Ennek megfelelen a szerveroldalon kt-
fajta socket tallhat. Az egyiket a tovbbiakban szerversocketnek hvjuk.
Funkcija szerint vrakozik (listen) egy cmen, amelyet elre megadtunk (bind),
s arra vr, hogy a kliensoldali socketek kapcsoldjanak (connect) hozz. Ha
egy kapcsoldsi krelem rkezik, a szerver elfogadja (accept), ennek eredm-
nyekppen ltrejn egy klienssocket. Ezen keresztl trtnik az adatcsere.
A kapcsoldsi krelem elfogadsa utn a kommunikci a szerversockettl
fggetlenl zajlik, a szerversocket csak tovbbi kapcsoldsi krelmekre vr.
A szerveroldalon ezrt gyakran tbb klienssockettel kell trdnnk.
6.2.2. A socket cmhez ktse
Ahhoz, hogy a kliens meg tudja cmezni a szervert a kapcsoldskor, a szerver-
nek az adott cmhez kell ktnie a socketjt. Ez egy olyan helyi cm, ahol a szer-
ver a bejv kapcsolatokat vrja. A kliensprogramnl is lehetsg van loklis
cm megadsra, ez azonban nem ktelez, mert nem hivatkozunk a cmre.
Ilyenkor a rendszer automatikusan egy cmet generl a kapcsoldskor.
A cmhozzrendels mvelett ktsnek (binding) nevezzk, s a bind()
rendszerhvssal tehetjk meg:
#include <sys(socket.h>
int b nd(i nt sock , struct sockaddr *my_addr, socklen_t addrlen);
Az els paramter a socket lerja, a msodik a cmet ler struktra, az utol-
s a cmet ler struktra hossza. A cmstruktra alakja itt nincs specifiklva,
mivel protokollonknt eltr a cmbrzols. Mindig az adott protokoll cm-
alakjt hasznljuk. Mivel az egyes cmtpusoknak a mretignye eltr, ezrt
kell megadnunk a cm hosszt.
268
6.2. Az sszekttets-alap kommunikci
6.2.3. Vrakozs a kapcsoldsra
A cmhez kttt socketnk nmagban mg nem alkalmas a kapcsolatok fo-
gadsra, mg nem lesz belle szerversocket. A processz a listen() rendszerh-
vssal lltja be a socketre ahhoz, hogy fogadja a kapcsoldsokat, majd a
kernel kezeli a kapcsoldsi ignyeket. Egy kapcsoldsi igny berkezse
utn azonban mg nem pl fel azonnal a kapcsolat. A vrakoz processznek
az acceptO rendszerhvssal kell elfogadni a kapcsoldst. Azokat a kapcsol-
dsi ignyeket, amelyeket az accept0-tel mg nem fogadott, fggben lv
kapcsolatnak (pending connection) nevezzk.
Norml esetben az accept() fggvny blokkoldik, amg egy kliens kapcso-
ldni nem prbl hozz. Termszetesen tllthatjuk az fenti() rendszerhvs
segtsgvel nem blokkold mdba is. Ilyenkor az accept0 azonnal visszatr,
amikor egyetlen kliens sem prbl kapcsoldni. Mivel a szerversocket is llo-
mny, a selectQ vagy a poll() rendszerhvst is alkalmazhatjuk a kapcsoldsi
ignyek szlelsre. Ezekben az esetekben a szerversocketre rkezett kapcso-
ldsi igny mint olvassi esemny rzkelhet.
A listen() s az accept() fggvnyek formja a kvetkez:
#include <sy s/sock eth>
int listen(int sock, int backlog);
int accept(int sock, struct sockaddr *addr, socklen_t *addrlen);
Els paramterknt mindkt fggvny a socket lerjt vrja. A listen() m-
sodik paramtere, a backlog, amely megadja, hogy hny kapcsoldni kvn
socket krelme utn utastsa vissza az jakat. Vagyis ez a fggben lv kap-
csolatok vrakozsi lista mrete.
Az accept0 fogadja a kapcsoldsokat. Visszatrsi rtke az j kapcsolat
lerja, egy klienssocket. Az addr s az addrlen paramterekben a msik ol-
dal cmt kapjuk meg. Az addr ltal mutatott struktrba a cm, az addrlen
ltal mutatott vltozba pedig a cm mrete kerl.
6.2.4. Kapcsolds a szerverhez
A kliens a ltrehozott socketet a szerverhez hasonlan a bind0 rendszerh-
vssal hozzrendelheti egy helyi cmhez. Ezzel azonban a kliensprogram lta-
lban nem trdik, a kernelre bzza, hogy ezt automatikusan megtegye.
Ezek utn a kliens a connectO rendszerhvssal kapcsoldhat a szerverhez:
#include <sys/socket.h>
int connect(int sock, struct sockaddr *addr, socklen_t addrlen);
269
Kliens

Szerver
socket()
connect()
socket()
bind()
(isten()
accept()
6. fejezet: Hlzati kommunikci
Az els paramter a socket lerja, a tovbbi paramterek a szerversocket c-
mt adjk meg.
A kapcsolat felplst a 6.1. bra mutatja.
Kommunikci
write() read()
read() 4 write()
close() close()
6.1. bra. Az sszekttets-alap kommunikci
6.2.5. A kommunikci
A kapcsolat felptst kveten a szerveroldalon az accept0 ltal visszaadott
klienssocketet, kliensoldalon pedig a kapcsolathoz ltrehozott socketet kt
sszekapcsolt llomnylerknt hasznlhatjuk, mint korbban a csvezet-
keknl. Amit az egyik oldalon a write() fggvnnyel belerunk, azt a msik ol-
dalon a read0 fggvnnyel olvashatjuk. m eltren a csvezetkektl a
kommunikci ktirny, vagyis mindkt oldalon rhatunk s olvashatunk is
6.2.6. A kapcsolat bontsa
A socketkapcsolat lebontsa tipikusan az llomnyoknl megismert close0
rendszerhvssal trtnik Ha a kapcsolat egyik vgt lezrjuk, akkor azt a
msik oldal is rzkeli, amikor legkzelebb olvassa a kapcsolat klienssocket-
jt. Ekkor a socket mr nem hasznlhat tovbbi kommunikcira, ezrt a le-
rt a tloldalon is lezrjuk.
270
6.2. Az sszekttets-alap kommunikci
A shutdown0 rendszerhvs lehetsget ad arra is, hogy a ktirny
kommunikcibl csak az egyik irnyt zrjuk le:
#include sys/socket.h>
int shutdown(int sockfd, int how);
Az els paramter a socket lerja. A msodik a lezrs mdjt adja meg a
6.3. tblzatban tallhat rtkek kzl.
6.3, tblzat. A shutdown mdjai
Tpus Jelents
SHUT RD Csak az olvassi gat zrjuk le. Az olvass llomny vge" jel-
zst (0 visszatrsi rtk) ad vissza. rni tovbbra is tudunk a
socketbe.
SHUT WR Csak az rsi gat zrjuk le. Amikor a tloldal teljesen kiolvasta
a korbban elkldtt tartalmat, egy llomny vge" jelzst kap.
A tovbbi rsi prblkozsra hibt kapunk, olvasni viszont to-
vbbra is tudjuk.
SHUT RDWR Mind az olvassi, mind az rsi gat lezrjuk. Mintha az elz
kt lezrst egyarnt elvgeznnk.
Ha a shutdown0 rendszerhvst a SHUT RDWR opcival hvjuk meg, akkor
a mkds hasonlt a close() rendszerhvsra. Nhny jelents eltrs azon-
ban van a kt megolds kztt.
A close0 az llomnylert zrja le, mg a shutdown0 a kommunikcis
csatornt. Vagyis ha a dup0 rendszerhvssal a socketlerrl msolatot k-
sztnk, akkor a close0 csak egy lert zr le. A kapcsolat csak akkor zrdik
le, ha minden lert lezrtunk. Ezzel szemben, ha a shutdown0-t brmelyik
msolatra meghvjuk, akkor lezrja a kapcsolatot, s a tbbi msolaton ke-
resztl sem folytathatjuk a kommunikcit. Ha a msolat a fark() rendszerh-
vs hatsra szletik, akkor is hasonl a helyzet.
Ugyanakkor a shutdown0 nem zrja le az llomnylert. Ezrt hasznla-
ta utn a close0 meghvsra van szksg.
6.2.7. Tovbbi kapcsolatok kezelse a szerverben
A 6.1. brn lthat kommunikcis folyamat sorn a szerver csak egy kap-
csolatot kpes kiszolglni, hiszen a kapcsolat felplse utn nem hvja meg
ismt az accept() fggvnyt. A szerverek tbbsgnl azonban nem ez a kvnt
mkdsi md. A tipikus elvrs az, hogy egy szerver tbb kapcsolatot is k-
pes fogadni, s prhuzamosan kiszolglja a klienseket. Ennek megvalsts-
hoz a szerverimplementcinkban prhuzamosan kell kommuniklnunk a
271
1. fl 2. fl
socket()
bind()
socket()
bind0
6. fejezet: Hlzati kommunikci
kliensekkel a klienssocketeken keresztl, kzben ismt meg kell hvnunk az
accept() fggvnyt a szerversocketre. (A 6.5.12.2. TCP szerver alkalmazs al-
fejezetben lthatunk majd pldkat a szerverfeladatok prhuzamostsra.)
6.3. Az sszekttets nlkli kommunikci
sszekttets-alap kommunikci esetn a kommunikcit megbzhat adat-
folyamknt foghatjuk fel. Ez egyrszt knyelmes megolds, mert nem kell fog-
lalkoznunk azzal, hogy az adat, amelyet elkldtnk, valban clba rt-e: a
kommunikcit vgrehajt fggvnyek jelzik a hibt vagy a kapcsolat bontst.
Msrszt azonban az adatok szinkronizcija tbb csomagforgalmat s
kernelerforrs-hasznlatot (CPU, memriabufferek, idztk) is jelent. Ezrt olyan
alkalmazsok esetn, ahol nem tl nagy problma", ha elveszik egy-egy"
csomag, ott alkalmazhatunk sszekttets nlkli megoldst, amely egyben
gyorsabb kommunikcit eredmnyez. Ilyenek tipikusan a multimdia-alkal-
mazsok, hiszen ha egy zene hangmintit kldjk el, nem jelent szmottev
minsgromlst egy-egy keret kimaradsa, valamint, ha ksn rkezik, nem
is tudunk mit kezdeni vele, hiszen mr elrbb tartunk a lejtszsban.
Az sszekttets nlkli kommunikci esetn ltrehozunk egy socketet
(socket()), s egy cmhez rendeljk (bind()). Ezen keresztl fogadjuk a hozznk
rkez csomagokat (datagram). Ugyanakkor nemcsak fogadjuk a csomagokat,
de kldnk is a tbbi alkalmazs szmra. m mivel ltrejtt kapcsolat hjn
a rendszer nem tudhatja, kinek sznjuk a csomagokat, ezrt egyesvel meg is
kell cmeznnk ket. gy a korbban ltott read/write fggvnyek itt nem
mkdnek.
Kommunikci
sendto() recvfrom()
recyfrom() sendto()
....... ................................ 4
,

close() close()
6.2. bra. sszekttets nlkli kommunikci
272
6.3. Az sszekttets nlkli kommunikci
A 6.2. bra mutatja az sszekttets nlkli kommunikci ltrehozsnak a
menett. A kt oldal ebben az esetben szimmetrikus, szemben a korbban l-
tott sszekttets-alap kommunikcival. Mindkt oldal mkdik kezdem-
nyezknt s fogadknt is. St valjban nem is csak kt oldal van, hanem
tbb kommunikcis fl is elkpzelhet.
Ahhoz, hogy a hozznk rkez csomagokat fogadni tudjuk, a socketnket
hozz kell ktnnk egy cmhez. Lehetsgnk van azonban arra, hogy a kt
kommunikcis fl esetben csak az egyiknl vgezzk el a cmhez ktst.
Ebben a struktrban a bind() fggvnyt hasznl oldal lesz a szerver, a di-
namikuscm-hozzrendelst hasznl oldal a kliens. Felvetdik a krds,
hogyan derti ki a szerver a kliens cmt, s kld neki csomagot. Ehhez az
szksges, hogy a kliens kezdemnyezze a kommunikcit az els csomag el-
kldsvel. A szerver fogadva a csomagot megtallja benne a kliens cmt.
Ezt kveten a szerver a kapott cmre vlaszcsomagot tud kldeni.
6.3.1. A kommunikci
Lthatan az sszekttets nlkli kommunikci esetben a korbban meg-
ismert readO s write() fggvnyek nem hasznlhatk. Ennek az az oka, hogy
nem adatfolyam-jelleg kommunikcit vgznk, hanem csomagokat keze-
lnk. Ez mg megoldhat is lehetne az absztrakcis interfszen keresztl,
msik nagy hinyossguk azonban az, hogy nem tmogatjk a cmkezelst.
gy helyettk a recufromQ s a sendto() fggvnyeket kell hasznlnunk.
sszekttets nlkli kapcsolat esetn teht az adatfogads az
#include <sys/types.h>
#include <sys/socket.h>
ssize_t recvfrom(int sock fd, void *buf, size_t len, int flags,
struct sock addr*src_addr, socklen_t *addrlen);
fggvnnyel trtnik. Az els hrom paramter a readO fggvnybl mr is-
mers lehet. A sockfd a socket lerja, a buf a buffer mutatja, amelybe az
adatokat vrjuk. A len a buffer mrete. Ha a megadott buffer rvidebb, mint
amekkora hosszsg adat rkezett, akkor a recyfrom() a csomag vgt au-
tomatikusan levgja.
A flags paramter socketspecifikus I/O belltsokra szolgl. Ezeket bveb-
ben a mm() fggvnynl trgyaljuk (lsd a 6.5.12. sszekttets-alap kommu-
nikci alfejezetben). A src_addr paramterben egy cmstruktra mutatjt
vrja a fggvny, ha szeretnnk visszakapni tle a csomag forrscmt. Ezt a
struktrt elre le kell foglalnunk, s az addrlen paramterben adjuk t
a mrett. A visszakapott cm mrett szintn az addrlen paramterben kap-
juk meg. Ha nem vagyunk kvncsiak a csomag forrsra, akkor NULL mu-
tatk megadsval ezt a szolgltatst kikapcsolhatjuk.
273
6. fejezet: Hlzati kommunikci
Ameddig nem rkezik adat, a recyfrom() fggvny vrakozik, majd ezt k-
veten az adatok mennyisgvel vagy hibt jelz mnusz rtkkel tr vissza,
ahogy a read0 fggvnynl trtnik.
Az sszekttets nlkli kapcsolatok esetn kldsre az
#include<sy s/ty pes.h>
#include<sy s/sock et.h>
ssize_tsendto(intsock fd,constv o d*buf,size_tlen,intflags,
conststructsock addr*dest_addr,sock len_taddrlen);
fggvnyt hasznljuk. Mint az elz esetben, az els hrom paramter hasonlt
a writeQ fggvny paramtereire. A sockfd a socket lerja, a buf a buffer muta-
tja, amelyben az adatok tallhatk. A len a bufferben lv adatok mrete.
A flags paramter socketspecifikus I/O belltsokra szolgl. Ezeket b-
vebben a send0 fggvnynl trgyaljuk (lsd a 6.5.12. sszekttets-alap
kommunikci alfejezetben). A dest_addr paramterben egy cmstruktra
mutatjt vrja a fggvny, amely a clcmet tartalmazza. A struktra mre-
tt az addrlen foglalja magban.
A fggvny addig blokkoldik, amg az adatokat a protokollkezel rend-
szer a kimen bufferbe bele nem tudja rni. Ezt kveten visszatr az elkl-
dtt byte-ok szmval.
6.3.2. A connect() hasznlata
Br az sszekttets nlkli kommunikci esetn nem ptnk fel kapcsolatot
a kt fl kztt, a connectO fggvny mgis hasznlhat Ekkor valjban nem
kapcsolatot hoz ltre, hanem csak bejegyzi a megadott clcmet. gy a csomagok
kldsnl nem kell megadnunk mindig a clcmet, mert a connectO-nl meg-
adottakat hasznlja. Ezltal lehetv vlik a readQ s a writeQ fggvnyek
hasznlata is csomagok kldsre s fogadsra.
Az albbi lista sszefoglalja a connectQ fggvny hatsait arra a socketre,
amelyre meghvtuk:
A writeQ fggvnnyel (vagy a ksbb trgyalt send() fggvnnyel) ki-
kldtt csomagok mind a connectO fggvnyben megadott cmre r-
keznek.
A socketen keresztl csak olyan csomagokat kapunk meg, amelyek a
connect0-ben megadott cmrl rkeznek.
A tloldal nem rzkeli, hogy a connect() fggvnyt hasznltuk, mivel
nem pl fel kapcsolat.
274
6.4. Unix domain socket
6.3.3. A socket lezrsa
A socketet mindkt oldalon a closeQ fggvnnyel zrhatjuk le. Kapcsolat hi-
nyban azonban ez nem jelent kapcsolatzrst, s a tloldal nem rzkeli,
hogy lezrtuk a socketet. Csupn annyi trtnik, hogy a tovbbiakban nem
fogadjuk a csomagokat.
6.4. Unix domain socket
A Unix domain socket a legegyszerbb protokollcsald, amely a socket-API-n
keresztl elrhet. Valjban nem hlzati protokoll. Csak egy gpen bell
kpes kapcsolatokat felpteni. Habr ez komoly korltoz tnyez, mgis sok
alkalmazs hasznlja, mivel flexibilis IPC-mechanizmust nyjt. A cmei l-
lomnynevek, amelyek az llomnyrendszerben jnnek ltre. Azok a socket-
llomnyok, amelyeket ltrehoz, a stat() rendszerhvssal vizsglhatk, m
nem lehet megnyitni az open() fggvnnyel ket. Helyette a socket API-t kell
hasznlni.
A Unix domain socket tmogatja mind az adatfolyam- (stream), mind a
csomag- (datagram) kommunikcis interfszt, a datagram interfsz azonban
ritkn hasznlatos. A stream interfsz a megnevezett csvezetkekhez hason-
lt, m nem teljesen azonos velk.
Ha tbb processz megnyit egy megnevezett csvezetket, akkor egyikk ki-
olvashatja belle, amit egy msik belert. Lnyegben olyan, mint egy hirdet-
tbla. M egyik processz elkld egy zenetet r, egy msik pedig elveszi onnan.
Ezzel szemben a Unix domain socket kapcsolatorientlt. Minden kapcso-
lat egy-egy j kommunikcis csatorna. A szerver egyszerre tbb klienskap-
csolatot kezelhet, s mindegyikhez kln ler tartozik. E tulajdonsgok
rvn alkalmasabb az IPC-feladatokra, mint a megnevezett csvezetk, ezrt
sok Linux-szolgltats alkalmazza, tbbek kzt az X Window System s a
naplrendszer s.
6.4.1. Unix domain socket cmek
A Unix domain socket cmek llomnynevek a fjlrendszerben. Ha az llo-
mny nem ltezik, akkor a rendszer, amikor meghvjuk a bind() fggvnyt,
socket tpus llomnyknt ltrehozza. Ha az llomnynv mr hasznlt, ak-
kor a bindQ hibval tr vissza (EADDRINUSE). A bind() a 0666-t lltja be
jogosultsgnak (mdostva az umask rtkvel).
Ahhoz, hogy a connect() rendszerhvssal kapcsoldhassunk a sockethez,
olvassi s rsi joggal kell rendelkeznnk a socketllomnyra.
275
6.fej ezet:H lzatik ommunik ci
A Unix domain socket cmeinek megadshoz a struct sockaddr_un struk-
trt hasznljuk:
#include<sy s/sock et.h>
#include<sy s/un.h>
structsock addr_un
unsignedshortsun_fam ly ; /*AF_UNIX
*/
charsun_path[uNIX_P ATH_MAx];/*eleresi u t * /
;
A sunjamily meznek, AF UNIX-nak kell lennie. Ez jelzi, hogy Unix domain
socket cmet tartalmaz. A sun_path tartalmazza az llomnynevet C-string-
knt, vagyis egy '\0' karakterrel lezrva. A rendszerhvsokban hasznlt cm-
struktramret az llomnynv hossza, plusz a sunjamily elem mrete. Br
hasznlhatjuk a teljes struktramretet is, hiszen az llomnynevet lezrtuk.
6.4.2. Unix domain socket adatfolyam
szerveralkalmazs
Az sszekttets-alap szerveralkalmazs felptse megegyezik a korbban
a 6.2. Az sszekttets-alap kommunikci alfejezetben trgyaltakkal, kieg-
sztve a Unix domain socket kommunikciban hasznlt cmzssel.
Feladat K sz tsnk egy Unixdomainsock etszerv eralk almaz st,amely fogadj aak liensek k ap-
csolatait(egy szerreegy et), satlk k apottadatok atk i rj aazalap rtelmezettk imenetre.
A megolds a kvetkez:
/*uszerv er.c- Egy szeru peldaszerv eraUnixdomainsock et
hasznalatara.*/
#include<stdio.h>
#include<sy s/sock et.h>
#include<sy s/un.h>
#include<unistd.h>
intmain(v oid)
structsock addr_unaddress;
intsock ,conn;
sock len_taddrlen;
charbuf[102 4];
intamount;
276
/*Fogadj uk azadatok at.*/
printf("Adatok erk eznek ...\n");
while((amount=read(conn,buf,sizeof(buf)))>0)
if(write(STDOUT_FILENO,buf,amount)!=amount)
perror("write");
return-1;
}
}
if(amount<0)
perror("read");
return-1;
277
6.4. Unix domain socket
/*Letrehozzuk asock etet.*/
1f((sock =sock et(FF_UNIX,SOCK_STREAM,0))<0)
perror("sock et");
return-1;
/*Letorolj uk ak orabb sock etallomany t.*/
unlink ("./sample-sock et");
memset(&address,0,sizeof(address));
address.sun_family =AF_UNIX;
strncpy (address.sun_path,"./sample-sock et",
sizeof(address.sun_path)-1);
/*Atelj es Cirrl hossztartalmazzaasun_family elemetesaz
eleresiuthosszat.*/
addrlen=sizeof(address.sun_family )+
strnlen(address.sun_path,sizeof(address.sun_path));
/*Asock etethozzak otj uk ac mhez.*/
if(bind(sock ,(structsock addr*)&address,addrlen))
perror("bind");
return-1;
/*Bek apcsolj uk ak apcsolodasrav alov arak ozast.*/
if(listen(sock ,5))
perror("listen");
return-1;
}
/*Fogadj uk ak apcsolodasok at.*/
while((conn=accept(sock ,(structsock addr*)&address,
&addrlen))>=0)
{
6. fejezet: Hlzati kommunikci
prntf("...vege\n");
/* Bontjuk a kapcsolatot.
* /
close(conn);
if(conn < 0)
perror("accept");
return -1;
/* Lezarjuk a szerver socketet. */
close(sock);
return 0;
Ez az elg egyszer pldaprogram bemutatja a szksges rendszerhvsokat,
viszont egyszerre egy kapcsolat lekezelsre alkalmas. (Termszetesen k-
szthetnk ennl bonyolultabb, tbb kapcsolat prhuzamos kezelsre is al-
kalmas megoldsokat.)
Az ltalnos socketkezelshez kpest lthatunk a programban egy unlink0
hvst. Erre azrt van szksg, mert ha mr az llomny ltezik, a bind0 hib-
val trne vissza, akkor is, ha az llomny socketllomny.
6.4.3. Unix domain socket adatfolyam
kliensalkalmazs
A kliensalkalmazs termszetesen ugyancsak kveti a socketeknl mr ismerte-
tett mdszereket, a Unix domain socket kommunikcinl trgyalt cmzssel.
Feladat Ksztsk el az elz fejezetben ltott szerver kliensprjt. A kliens az alaprtelme-
zett bemeneten fogadja az ltalunk bert szveget, s ezt a kapcsolaton keresztl kldje el a
szervernek.
A kvetkez program egy plda a megoldsra:
/* ukliens.c - Egyszeru peldakliens a Unix domain socket
hasznalatara. */
#include <stdio.h>
#include <stdlib.h
#include <sys/socket.h>
#include <sys/un.h>
#include <unstd.h>
278
6.4. Unix domain socket
(
intmainCv oid)
I {
structsock addr_unaddress;
intsock ;
size_taddrlen;
charbuf[102 4];
intamount;
/*Letrehozzuk asock et-et.*/
if((sock =sock et(P F_UNIX,SOCK_STREAM,0))<0)
perror("sock et");
return-1;
memset(&address,0,sizeof(address));
address.sun_family =AF_UNIX;
strncpy (address.sun_path,"./sample-sock et",
sizeof(address.sun_path)-1);
/
4
Atelj escimhossztartalmazzaasun_family elemetesaz
eleresiuthosszat.*/
addrlen=sizeof(address.sun_family )+
strnlen(address.sun_path,sizeof(address.sun_path));
/*Kapcsolodunk aszerv erhez.*/
if(connect(sock ,(structsock addr*)&address,addrlen))
perror("connect");
return-1;
/*Elk uldj uk azadatok at.*/
while((amount=read(STDIN_FILENO,buf,sizeof(buf)))>0)
if(write(sock ,buf,amount)!=amount)
I
{
perror("wTite");
ret urn
.
i

} }
if(amount<0)
{
perror("read");
O
.
i l f i l
return-1;
}
/*Bontj uk ak apcsolatot.*/
close(sock );
return0;
279
6. fejezet: Hlzati kommunikci
6.4.4. Unix domain socket datagram kommunikci
Az elz fejezetekben lthattuk az ltalnos sszekttets-alap kommunik-
cis megoldsok alkalmazst a Unix domain socket protokollra. Ezekkel
analg mdon az sszekttets nlkli datagramkommunikci is az ltal-
nos fggvnyeket alkalmazza kiegsztve a Unix domain socket cmzssel.
Ezrt datagramkommunikcira pldt majd csak az IP-kommunikci tr-
gyalsnl mutatunk
tmutat Br a datagramkommunikci nem megbzhat s nem sorrendtart a specifikcik
rtelmben, ez a Unix domain socket protokoll esetben nem igaz. Mivel a kommunikci csak
loklisan, a kernel mechanizmusain keresztl trtnik, gy garantlt, hogy nem vesznek el
csomagok, s nem cserldik fel a sorrendjk.
6.4.5. Nvtelen Unix domain socket
Mivel a Unix domain socket egy sor elnnyel rendelkezik a csvezetkekkel
szemben (ilyen pldul a ktirny kommunikci), ezrt gyakran alkalmaz-
zk IPC-kommunikcihoz. A hasznlatukat megknnytend ltezik egy
socketpair0 rendszerhvs, amely egy pr sszekapcsolt, nv nlkli socketet
hoz ltre:
include <sys/types.h>
#include <sys/socket.h>
i nt socketpai r(int domain, int type, int prot, int sockfdsl2]);
Az els hrom paramter megegyezik a socket0 rendszerhvsnl trgyaltak-
kal. Az utols paramter, a sockfds, tartalmazza a visszaadott socketlerkat.
Szemben a nvtelen csvezetkekkel a kt ler egyenrtk.
6.4.6. A Linux absztrakt nvtere
A Unix domain socket kommunikci sorn cmknt socketllomnyokat
hasznlva szembeslhetnk nhny problmval:
A socketllomnyokat rendszeresen trlnnk kell, mert ha az llo-
mny ltezik, akkor a bindO hibval tr vissza.
Ha megszakad a program, akkor ott marad az llomnyrendszerben a
socketllomny.
280
6.4. Unix domain socket
Elfordulnak olyan helyzetek, amikor nincs jogosultsgunk llomnyt
ltrehozni.
Hasznlhatunk olyan llomnyrendszert, amely nem tmogatja a soc-
ketllomnyokat.
Ezek a problmk mnd azt mutatjk, hogy az llomnyok hasznlata cm-
knt sokszor gondot jelent. Ugyanakkor a Linux ms rendszerektl eltren
tartalmaz egy plusz szolgltatst, amellyel elkerlhetjk az llomnynevek
hasznlatt. Ez a szolgltats az absztrakt nvtr.
Az absztrakt nvtr hasznlata egyszer. Alapesetben a cmstruktra
sun_path eleme egy C-sztringet tartalmaz, vagyis nem null karakterek soro-
zatt a vgn lezrva egy '\0' karakterrel. Ha absztrakt nevet szeretnnk
megadni, akkor ettl eltren egy '\0' karakterrel kell kezdennk a mezt,
majd az ezt kvet karakterek tartalmazzk az azonostt. m ebben az eset-
ben nem jelezhetjk 0' karakterrel az azonost vgt. gy a megadott sz-
veget teljesen a cmstruktra vgig veszi figyelembe a rendszer. Ezt azonban
befolysolhatjuk, amikor megadjuk a cmstruktra hosszt.
Nzznk erre egy pldt:
struct sockaddr_un address;
size_t addrlen;
memset(&address, 0, sizeof(address));
address.sun_family =AF_UNIX;
address.sun_path[0] =0;
strncpy(address.sun_path + 1, "myaddr",
sizeof(address.sun_path) - 2);
addrlen =sizeof(address.sun_family) +
strnlen(address.sun_path + 1, sizeof(address.sun_path) - 1) + 1;
A sun_path mez els elemnek belltjuk a 0-t. Ezt kveten a msodik byte-
tl bemsoljuk az ltalunk megadott szveget. A mret kiszmolsnl fi-
gyelnnk kell arra, hogy a szveg hosszt csak a msodik karaktertl mrjk,
illetve a kezd '\0' karaktert is hozzadjuk.
Hasonlan sszelltva a cmet mind a szervernl, mind a kliensnl a ko-
rbbi pldk tovbbra is mkdnek, de nem ignylik llomnyok ltrehoz-
st, illetve trlst.
tmutat Br ebben az esetben nem lthatjuk az llomnyrendszerben a cmeket, a netstat
programmal lehetsgnk van kilistzni a Unix domain socket szervereket, illetve kapcsolato-
kat. gy a cmknt hasznlt absztrakt neveket is lthatjuk.
281
6. fejezet: Hlzati kommunikci
6.5. IP
Az elz fejezetben a Unix domain socket protokoll hasznlatval csak egy
gpen bell kommuniklhattak a folyamataink. Ebben a fejezetben bemutat-
juk az Internet protokoll (IP) hasznlatt, amellyel mr lehetsgnk van
szmtgp-hlzaton keresztl kommunikcit felpteni klnbz szmt-
gpeken fut folyamatok kztt.
Az IP-kommunikci sorn is az eddig megismert socketkezel fggv-
nyeket alkalmazzuk. Eltrst nagyrszt csak a cmzsnl ltunk.
A fejezetben prhuzamosan ismertetjk az IP protokoll korbbi 4 -es ver-
zijnak (IPv4 ) s az j 6-os verzijnak (IPv6) hasznlatt. Jelenleg az IPv4
protokoll hasznlatos szles krben, m a programjainkban clszer felk-
szlnnk az IPv6 tmogatsra is, hogy a jvben hasznlhatk legyenek.
6.5.1. Rviden az IP-hlzatokrl
Mieltt ismertetnnk az IP protokollok hasznlatt, illetve az internetes
kommunikcit, rviden bemutatjuk az IP-hlzatok mkdst, hogy a k-
sbb trgyalt fogalmak rtelmet nyerjenek.
Kommunikci a hlzaton
Az internet loklis hlzatokbl pl fel, sok kisebb-nagyobb hlzatbl, ame-
lyeket tvonalvlasztk (routerek) kapcsolnak ssze. Ez azt is jelenti, hogy a
hlzati kommunikci egy loklis hlzaton bell lv szmtgpek kztt
mskppen zajlik, mint az egymstl tvoli, klnbz loklis hlzatokba
tartoz szmtgpek kztt.
Loklis hlzat
Loklis hlzatnak tekintend az a hlzat, amelyen bell kt szmtgp k-
ztt router kzbeiktatsa nlkl, kzvetlenl lehet kommuniklni. Ez tipiku-
san egy switchre,
79
vagy tbb switchbl ll struktrra UTP-kbellel kapcso-
ld szmtgpeket jelent. Szoktk ezt szegmensnek vagy alhlzatnak is
neve zni.
90

79
A switch olyan hlzati eszkz, amely a portjaira (csatlakozira) kapcsolt eszkzk kzt-
ti kommunikcit biztostja. Eldje a HUB, amely az egyik portjra rkez jeleket a tbbi
portjra tovbbtja. A switch ehhez kpest annyi tbbletintelligencival rendelkezik,
hogy a csomagokat megvizsglja, s csak arra a portjra tovbbtja, ahol a cmzett eszkz
tallhat.
8
Msfajta hlzattpusok is lteznek (Token bus, Token ring), m ezekkel a htkznapok
sorn ritkn tallkozunk
282
6.5. IP
Klasszikus esetben egy loklis hlzaton bell, ha az egyik szmtgp
elkld egy csomagot, akkor azt az sszes tbbi szmtgp megkapja, de csak
az hasznlja fel, amelyiknek szl. Hogy kinek szl, azt a cmzett gp hlzati
krtyjnak fizikai cme (MAC-cm, hardvercm stb.) hatrozza meg. Ez a cm
minden hlzati krtyra egyedi, s csak ennek ismeretben lehetsges a kt
szmtgp kztt kommunikcit megvalstani.
Manapsg a mkds csak annyiban tr el, hogy a switcheszkzk is
kpesek rtelmezni a fizikai cmet s megjegyezni, hogy melyik portjukon ta-
llhat az ezt hasznl gp. gy az optimalizci rdekben csak arra kldik
tovbb a csomagot.
Vagyis a kommunikci kt gp kztt a fizikai cmmel trtnik. Mirt
van szksg akkor az IP-cmre, mirt nem hasznlja a protokoll a fizikai c-
meket? Elszr is, mert knyelmetlen, nehezen megjegyezhet. De ami sokkal
fontosabb: elvileg mg megvltoztathatatlan
81
a hlzati krtya legyrtsa
sorn adott egyedi cm. gy garantljk, hogy egy loklis hlzaton vletlenl
se legyen kt egyforma fizikai cmmel rendelkez gp.
Mivel a fizikai cmeket a gyrtskor hatrozzk meg, ezrt semmilyen in-
formcit nem hordoz az alhlzattal kapcsolatban. nmagban a cmbl
nem tudjuk eldnteni, hogy a loklis hlzatunk tagja-e, vagy ha nem, akkor
hol tallhat a vilgban. Elvileg sszellthatnnk egy nyilvntartsi tblza-
tot, de ennek karbantartsa lehetetlen feladat lenne. Ezrt van szksg egy
msik cm hasznlatra is, s ez az IP-cm.
Hogyan dnthet el, hogy egy adott IP-cmmel rendelkez gpnek (cm-
zettnek) mi a fizikai cme? Erre szolgl az ARP (Address Resolution Protocol).
Ha egy gp egy msiknak akar csomagot kldeni, akkor els krben a
cmzett IP-cme s a hlzati maszk alapjn eldnti, hogy a clgp vele egyez
alhlzatnak a tagja-e, vagy sem (a mdszert lsd a 6.5.3. IPv4-es cmzs alfe-
jezetben).
Ha a clgp ugyanannak az alhlzatnak a tagja, akkor elkld egy broad-
cast- (mindenkinek szl) zenetet, amelyben megkrdezi, hogy melyik is az
adott IP-cmmel rendelkez szmtgp, s mi a fizikai cme. Az zenetet
mindenki veszi, de csak az vlaszol r, aki az adott IP-cm tulajdonosa, s el-
kldi a kezdemnyeznek a sajt fizikai cmt (a kezdemnyez a sajtjt ter-
mszetesen feltntette az zenetben). Ezt kveten a kezdemnyez hogy
ne kelljen folyton ARP-zeneteket kldzgetni elhelyezi a cmzettre vonat-
koz informcikat egy gyorsttrba (ARP Cache), s legkzelebb, ha ugya-
nazzal a cmzettel akar kommuniklni, akkor mr ebbl veszi az adatokat.
A fizikai cm kidertse utn mr csak annyi a feladat, hogy ezzel a fizikai
clcmmel kell a gpnek csomagokat kldenie, gy a clgp megkapja ket.
81
Gyakorlatban a gyrtsi folyamat egyszerstse miatt megvltoztathat, illetve szoftve-
resen fell is rhat.
2 83
6. fejezet: Hlzati kommunikci
Globlis hlzat
Mi trtnik akkor, ha olyan cmzettel akar egy szmtgp kommuniklni,
amelyik nincs vele egy szegmensen? Ekkor jut szerephez a router. A router
(tvlaszt) egy kitntetett szmtgp a szegmensen, amely egyszerre tbb
loklis hlzathoz is kapcsoldik, s amelyik ppen ezrt tbb szegmensbe is
tud adatot kldeni, gy lehetv teszi a szegmensek kztti kommunikcit.
Ha egy szmtgp egy msik szegmensben (ezt az alhlzati maszk segts-
gvel llaptja meg) lv gppel akar kommuniklni, akkor nem kzvetlenl a
cmzettel kezdemnyez kapcsolatot, hanem az alaprtelmezett routerrel (ez
minden gp esetben be van lltva). Ehhez persze elszr ARP-vel kiderti a
router fizikai cmt, majd elkldi az adatcsomagot, azzal az utastssal, hogy
a megadott IP-cmre kell eljuttatni.
Ezt kveten, ha a clcm valamelyik, a routerhez kapcsold alhlzathoz
tartozik, akkor a router ARP-vel kiderti ennek a fizikai cmt, s elkldi a
csomagot. Ha a cmzett semelyik, a routerhez kapcsold szegmenshez sem tar-
tozik, akkor a router is egy msik routerrel veszi fel a kapcsolatot, amely tbb
msik alhlzatot kezel routerrel is kapcsolatban ll, s annak kldi tovbb
a csomagot. Ezt a megoldst addig ismtli a rendszer, amg eljut egy olyan
szintre, ahol a router tudja, hogy a clgp alhlzata merre tallhat. Ezt k-
veten a csomag eljut a clalhlzat routerhez, amely tovbbtja a clgpnek.
Fontos megjegyezni, hogy kt szmtgp kztt ebben az esetben is csak
egy szegmensen bell s a fizikai cmek alapjn zajlik a kzvetlen kommuni-
kci. Szegmenseken kvlre kzvetetten (routerek kzbeiktatsval) kerl-
nek a csomagok.
6.5.2. Az IP protokoll rtegzdse
Az IP protokoll csaldot tbb protokollra s tbb rtegre bontjuk. A rtegeket
s a protokollokat a 6.3. bra szemllteti:
Alkalmazsok
TCP UDP
IP
Ethernet
Szlltsi rteg
Hlzati rteg
Adatkapcsolati rteg
6.3. bra. Az IP protokoll csald gyakrabban hasznlt elemei
284
6.5. IP
Az adatkapcsolati rteg biztostja a kommunikcit a hlzat elemei kztt.
A hlzati rteg teszi lehetv a csomagok eljutst a kldtl a cmzettig.
Az IP protokoll is ebben a rtegben tallhat, vagyis a legfbb feladata az,
hogy az interneten tallhat kt gp kztt megoldja a cmzst s az adatok
tovbbtst.
A szlltsi rteg biztostja, hogy az alkalmazsok kztt az adattvitel
transzparensen megvalsulhasson. Az UDP protokoll lnyegben az alkalma-
zsok megcmezhetsgvel (portok kezelse) egszti ki az IP-t. A TCP a por-
tok kezelse mellett mg a kapcsolat megbzhatsgt is garantlja.
6.5.3. IPv4-es cmzs
Az IP-cmek egyedek mnden hoszt esetben, s 32 bitbl (4 byte-bl) llnak.
Szoksos megjelensk a 4 byte pontokkal elvlasztva. Prbljuk meg lekr-
dezni sajt gpnk IP-cmt:
8ipaddr
1: lo:<LOOP BACK,UP ,LOwER_uP >mtu1643 6qdiscnoqueuestateUNKNOWN
link /loopback 00:00:00:00:00:00brd00:00:00:00:00:00
inet12 7.0.0.1/8scopehostlo
inet6::1/12 8scopehost
v alid_lftforev erpreferred_lftforev er
2 : eth0:<BROADCAST,mULTICAST,UP ,LOWER_UP >mtu1500qdisc
pfifo_faststateUP qlen1000
link /ether00:2 2 :3 f:dl:d3 :a7brdff:ff:ff:ff:ff:ff
i net192 .168.1.10/2 4brd192 .168.1.2 55scopeglobaleth0
i net6fe80::2 11:2 fff:fedl:d3 a7/64scopelink
v alid_lftforev erpreferred_lftforev er
Amikor egy szervezet hlzati adminisztrtora ignyel egy cmtartomnyt,
akkor kap egy 32 bites hlzati cmet s egy 32 bites hlzati maszkot. Ez a
kt szm meghatroz egy cmtartomnyt. Ezt a 6.4. bra szemllteti.
Hlzati cm
Hlzati maszk
Helyi cm
Idegen cm
il000000liolol000 ocw0000ll00000000
11111111111111111
4 - Hlzati Hoszt -
11000000 10101000 00000001 0 0 0 0 1010
10 0 110 0 0 01 0 0 0 0 1 0 101 111 01 0 0 0 0 1 0 10
6.4. bra. IPv4-es hlzati cm s maszk
~a
2 85
6. fejezet: Hlzati kommunikci
Egy IP-cmbl azok a bitek, ahol a hlzati maszk 1-est tartalmaz, a hlzati
cmet hatrozzk meg. Azok a bitek, ahol a maszkban 0 szerepel, az adott gp
egyedi hosztcmt adjk meg.
Vagyis egy hlzaton bell a szmtgpek egyedi IP-cmei csak azokban
a bitekben trhetnek el a hlzati cmtl, ahol a maszkban 0 szerepel. Ha az
IP-cm a maszk 1-es rtkeinl is eltr, akkor az mr egy msik alhlzatnak
az eleme.
Egy szmtgpen csak a gp egyedi IP-cmt s a hlzati maszkot szoktuk
megadni, mivel az elz sszefggsek alapjn ebbl a kt rtkbl a hlzati
cm elllthat. A megads sorn mg egy egyszerstssel szoktunk lni.
A hlzati maszkban nem keveredhetnek az 1-es s a 0-s rtkek. A maszk
elejn x darab 1-es, majd ezt kveten (32 x) darab 0 bit kvetkezik. gy a
maszk teljesen lerhat x-szel, amely egy szm 0 s 32 kztt. Ezt a szmot az
IP-cm utn egy 1" jellel elvlasztva rjuk. Pldul:
X.01Atitt ..10, -
A /2 4 " azt jelzi, hogy a maszk 2 4 darab 1-est majd 8 darab 0-t tartalmaz. Va-
gyis az els 2 4 bit a hlzati cmhez, a maradk 8 bit a hosztcmhez tartozik.
Ugyanez a maszk pontozott formtumban gy nz ki:
.Z. 5. 295. a ~: _
Egy tartomny els s utols cmnek specilis jelentse van. Ezeket szm-
tgpeknek nem adjuk ki. Az els cm, amikor a hosztcm bitjei vgig 0-k, a
hlzati cm. Az utols cm, amikor a hosztcm vgig 1-es a broadcastcm.
A broadcastcmre kldtt csomagokat az alhlzat minden gpe megkapja.
6.5.4. IPv4-es cmosztlyok
Manapsg a hlzati cmtartomnyok meghatrozst hlzati cm s hlzati
maszk alapjn vgezzk. Korbban azonban a tartomnyok meghatrozsa
az n. cmosztlyok alapjn trtnt. Ezt jelenleg mr nem hasznljk, m
idnknt mg mindig tallkozunk a cmosztlyok fogalmval.
Az IPv4 32 bites cme ebben az esetben is ktfel oszlik. Az els M bit egy
azonost, amely megmutatja a hlzat tpust, a kvetkez N bit a hlzat
cme, a maradk 32-M-N bit pedig az adott hlzaton bell egy szmtgp
cme. Attl fggen, hogy N rtkt mekkorra vlasztjuk, tbb hlzatot c-
mezhetnk meg (N-et nvelve), illetve tbb gpbl ll hlzatot cmezhetnk
meg (N-et cskkentve).
A cmosztlyokat a 6.4. tblzat foglalja ssze:
286
6.5. IP
6.4. tblzat. Cmosztlyok
Cm Els cm Utols cm Azonost
A osztly 1.0.0.0 12 7.2 55.2 55.2 55 0 7
B osztly 12 8.0.0.0 191.2 55.2 55.2 55 10 14
C osztly 192 .0.0.0 2 2 3.2 55.2 55.2 55 110 2 1
D osztly 2 2 4 .0.0.0 2 39.2 55.2 55.2 55 1110 Tbbes klds
E osztly 2 4 0.0.0.0 2 4 7.2 55.2 55.2 55 11110 Fenntartva
Feladat llaptsuk meg, hogy a www.aut.bme.hu szerver IP-cme milyen osztlyba tartozik.
$ping www.aut.bme.hu
PING www.aut.bme.hu (152.66.188.11) 56(84) bytes of data.


Amint a tblzat alapjn lthat, ez egy B osztly IP-cm, s ez nem megle-
p, hiszen a BME-hez elg sok gp tartozik, gy a hosztok megcmzshez 16
bitre van szksg (az A osztly esetn adott 2 4 sok lenne, a C osztlyban
hasznlt 8 kevs).
6.5.5. IPv4-es specilis cmek
A teljes IPv4 -es cmtartomnyban vannak olyan tartomnyok, amelyeknek
specilis a jelentse.
A 12 7.0.0.1 cm tipikusan a loopbackcm, amely arra hasznlatos, hogy a
folyamatok a sajt gpket megcmezzk, vagyis egy gpen bell folytassanak
IP-kommunikcit. Valjban a 12 7.0.0.0/8 tartomny brmelyik cmt lehet
erre a feladatra hasznlni, de az els cmet szoktk.
A 10.0.0.0/8, a 172 .16.0.0/12 s a 192 .168.0.0/16 privt IP-cmtartom-
nyok. Ez azt jelenti, hogy az interneten nem tallkozunk ilyen cmeket hasz-
nl gpekkel, mivel az tvonalvlasztk (router) nem tovbbtjk ezeket a
csomagokat. A sajt hlzatunkban szabadon hasznlhatjuk a privt cmtar-
tomny cmeit, kzvetlenl ezek a gpek azonban nem kommuniklhatnak az
interneten.
82

A 2 2 4 .0.0.0/4 D osztly cmtartomny cmeit a tbbes kldshez hasz-
nlhatjuk. A tbbes klds sorn egy-egy csomagot nemcsak egy gpnek, ha-
nem hosztok csoportjnak kldjk el. (Hasznlatt bvebben lsd a 6.5.13.2.
Tbbes klds alfejezetben.)
82
Ha privt cmeket hasznl szmtgpekkel el akarjuk rni az internetet, akkor cmfor-
dtst (network address translation, NAT) kell hasznlnunk.
287
6. fejezet: Hlzati kommunikci
6.5.6. IPv6-os cmzs
A 6-os verziszm IP-cmek ltrejttnek elsdleges oka az, hogy az eredeti
(4 -es verzij) IP-cmekbl kifogytunk. A problma megoldsra dolgoztk ki
az IPv6-ot, amely mr 12 8 bites cmeket hasznl.
Az IPv6 a 16 byte-os cmeken kvl szmos tbbletszolgltatst nyjt, gy
pldul:
automatikuscm-konfigurci,
fejlettebb tbbes klds,
az tvonalvlasztk (router) feladata egyszersdtt,
tbb tvonalvlasztsi opci,
mobilits,
hitelests,
adatbiztonsg.
A 16 byte-os IP-cmek lershoz rtelemszeren ms formtumot haszn-
lunk: a szmokat hexadecimlisan 4 -es csoportokra osztjuk kettsponttal el-
vlasztva, ez sszesen 8 csoportot jelent. Pldul:
0000:4200010000:0000}203Z: ~1~0CM.'"'
Vrhat, hogy az IPv6-os cmek kiosztsnl (s valsznleg mg elg sok-
ig) a cm kezdetben sok, nullkkal teli blokkot tartalmaz. Egyszerstskp-
pen bevezettk azt, hogy a kezd nullk minden blokkon bell elhagyhatk,
egy vagy tbb nullbl ll blokk kt kettsponttal helyettesthet:
0000t, t n 546A4: FEEI)4 DEAL
Az ttrs megknnytsre a rgi IP-cmek kt kettsponttal kezdden a
hagyomnyos, pontokkal elvlasztott mdon rhatk le:
A rgi IP-cmek a kvetkez minta alapjn illeszkednek az j cmbe:
000'400.~0004:s00~~,;gxxX_
-
_
-
_ _
Itt az XXXX:XXXX az IPv4 -es cm hexadecimlis formtumban. A lehetsges
rvidtseket alkalmazva az trsi sma a kvetkez:
_
288
6.5.IP
Igya
152 .66.188.11
IPv4 -es cm IPv6- os formtumban az albbi:
::FFFF:9842 :BCOB
6.5.7. Portok
Eddig az IP-rteg cmzst vizsgltuk, amely a szmtgp-hlzaton lv g-
pek azonostsra szolgl. Egy gpen azonban ltalban tbb szolgltats is
fut, amelyeket meg kell klnbztetnnk egymstl. Vagyis az egyes alkal-
mazsokat is meg kell cmeznnk valahogyan.
A TCP- s az UDP-rteg lehetv teszi tbb virtulis csatorna" ltrehozst
kt gp kztt. A szlltsi rteg ezt a kommunikcit a portokkal azonostja.
Egy TCP/UDP kommunikciban mindkt fl kln portszmmal rendelkezik.
Az 102 4 -nl kisebb szm portokat jl ismert portoknak (well-known
ports) nevezzk, amelyek meghatrozott szolgltatsoknak vannak fenntartva.
A felhasznli programok az 102 4 -tl 4 9 151-ig lv tartomnyt hasznlhatjk
(regisztrlt portok registered ports). A dinamikus s a magnportok
(Dynamic and Private Ports) a 4 9 152 65 535 intervallumban helyezkednek
el. Az Internet Assigned Numbers Authority (TANA, az internet szmhozzren-
del hatsga) szervezet ltal definilt portok listja a http:/ /www.iana.org/
assignments/port-numbers oldalon tallhat. A legismertebb szolgltatsok
portjait a 6.5. tblzat foglalja ssze.
6.5. t bl zat.Szolgltatsok portjai
Szolgltats neve Port
ftp-daca 2 0
ftp 2 1
ssh 2 2
telnet 2 3
smtp 2 5
http 80
port map 111
https 4 4 3
Linux alatt a szolgltatsok az /etc/services fjlban vannak felsorolva.
2 89
6. fejezet: Hlzati kommunikci
6.5.8. A hardverfgg klnbsgek feloldsa
A hlzati kommunikci byte-ok sorozatn alapszik. Egyes processzorok azon-
ban klnbz mdon troljk a klnbz adattpusokat. Mivel a klnbz
processzorra! szerelt gpeknek is szt kell rtenik egymssal, ezrt ennek a
nehzsgnek az thidalsra definiltak egy hlzati byte-sorrendet (network
byte order). A hlzati byte-sorrendben az alacsonyabb helyrtk byte jn
elbb (a nagyobb van htul" big endian). Azoknl az architektrknl, ahol
az n. hoszt byte-sorrendje ellenkez (a kisebb van htul" little endian)
ilyenek pldul az Intel 8086-os alap processzorok konverzis fggv-
nyek llnak rendelkezsnkre, amelyeket a 6.6 tblzat foglal ssze.
6.6. tblzat. Byte-sorrend-konverzis fggvnyek
Fggvny Lers
ntohs Egy 16 bites szmot a hlzati byte-sorrendbl a hoszt byte-sorrendbe
(big-endianlittle-endian) vlt t.
ntohl Egy 32 -bites szmot a hlzati byte-sorrendbl a hoszt byte-sorrend-
jbe (big-endianlittle-endian) vlt t.
htons Egy 16-bites szmot a hoszt byte-sorrendjbl hlzati byte-sorrendbe
(little-endianbig-endian) vlt t.
htonl Egy 32 -bites szmot a gp byte-sorrendjbl hlzati byte-sorrendbe
(lttle-endianbig-endian) vlt t.
Azokon az architektrkon, ahol nem szksges ez a konverzi, ezek a fgg-
vnyek a megadott argumentumrtkekkel trnek vissza, vagyis hordozhat
kd esetn mindenkppen alkalmazzuk ezeket a fggvnyeket.
A byte-sorrend problmjval elssorban a cmzsnl tallkozunk. Az t-
vitt adatok rtelmezst mr mi definiljuk az alkalmazsszint protokoll
specifiklsnl, m az implementci sorn rdemes szben tartani ezt a
problmt.
6.5.9. A socketcm megadsa
A 6.2. Az sszekttets-alap kommunikci alfejezetben bevezettk a connectO
fggvnyt, amellyel a szerverhez tudunk kapcsoldni, illetve a bind0 hvst,
amellyel cmet rendelhetnk a socketekhez. Mindkt fggvny egy-egy cmet
vr paramterl. Nzzk meg kzelebbrl a cm megadsnak a mdjt.
IPv4
Az IPv4 -es cmeket a sockaddr_in struktra definilja, amelyet a netinet/ in.h
llomny tartalmaz:
2 90
6.5. IP
structsock add_in
sa_family _t sin_family :
in_port_t sin_port;
structin_addrsin_addr;
unsignedcharsin_zero[8];
/*
/"
/
*
C mcsal d=AF_INET*/
Aportsz ma*/
IP v 4cim*/
structsock addrv ge*/
} ;
Az in_addr struktra felptse a kvetkez:
structin_addr
in_addr_ts_addr;/*elj eln lk li3 2 bitessz m*/
IPv6
Az IPv6-os struktra hasonlt az IPv4 -hez, m ebben az esetben a cm 32 bit
helyett 12 8 bites. A cmet a sockaddr_in6 struktra trolja, amely szintn a
netinetlin.h llomnyban tallhat:
structsock addr_in6
sa_family _t
in_port_t
uint3 2 _t
structin6_addr
uint3 2 _t
} : shememmew
sin6_family ; /*C mcsal d=AF_INET6
sin6_port; /*Aportsz ma*/
s n6_flowinfo;
sin6_addr; /*IP v 6c m*/
sin6_scope_id;
A sin_flowinfo s a sin6 scope_id mezk rtelmezsre jelen keretek kzt
nem trnk ki. 0 rtket hasznlunk az esetkben.
Az in6 addr struktra felptse az albbi:
structin6_addr

a
41"-

MMM

uint8_ts6_addr[16];
N _
;
Mind az IPv4 , mind az IPv6 esetben a rendszer a cmet binris formban, h-
lzati byte-sorrendben vrja. Ezek megadsa azonban a felhasznl szmra
nehzkes lenne. A 6.5.3. IPv4-es cmzs s a 6.5.6. IPv6-os cmzs alfejezetekben
lthattuk az elterjedt cmmegadsi formtumokat. Ezek szveges formtumok,
amelyekbl a binris cm ellltsa fggvnyek segtsgvel lehetsges.
Az IPv4 -es protokoll esetn az inet_aton() s az inet_ntoa() fggvnyeket
hasznlhatjuk arra, hogy a pontozott szveges formtumbl a binris form-
tumot ellltsuk, illetve fordtva. Ezek a fggvnyek azonban csak IPv4 ese-
tben hasznlhatk, ezrt manapsg mr elavultnak szmtanak.
2 91
6. fejezet: Hlzati kommunikci
Az inet_pton0 s az inet_ntop0 fggvnyek hasonltanak az inet_aton0 s
az inet_ntocco fggvnyekre, m mind az IPv4 pontozott szveges formtu-
mt, mind az IPv6 hexadecimlis szveges formtumt tmogatjk. Ezrt
ezeket a fggvnyeket rdemes megvizsglni.
Az inet_pton0 fggvny nevben a p prezentcit (presentation), az n h-
lzatot (network) jelent. Vagyis a fggvny az ember ltal kezelhet szveges
formtum cmbl hlzati byte-sorrendes binris formtumot llt el.
i n c l u d e < a r p a t i n e t . h >
i n t i n e t _ p i t o n e i n t a f , c o n s t c h a r * s r c , v o i d * 4 s t )
-
4
Az af a cmcsald, vagyis esetnkben AF INET vagy AF INET6. Az src pa-
ramter az IP-cm szveges reprezentcijt tartalmazza. A dst paramternek
egy nem tipizlt mutatt kell belltanunk. Ennek valjban egy in_addr
vagy egy in_addr6 tpus struktrra mutat rtknek kell lennie, attl fg-
gen, hogy IPv4 -es vagy IPv6-os cmet alaktunk t.
A fggvny visszatrsi rtke sikeres konverzi esetn 1. Ha 0 rtket
kapunk vissza, akkor az azt jelenti, hogy a szveges reprezentci nem meg-
felel. Hibs af rtk esetn pedig 1 rtket ad vissza a fggvny.
Az inet_ntop0 fggvny az ellenkez irny konverzit vgzi el. A hlza-
ti binris cmbl egy olvashat szveges cmet llt el:
#include<arpa/inet.h>
constchar*inet_ntop(intaf,constv oid*src,char*dst,
sock len_tsize);
Az af rtke ebben az esetben is AF INET s AF INET6 lehet. Az src para-
mternek egy in_addr vagy egy in_addr6 struktrra kell mutatnia, amely a
binris cmet tartalmazza. A dst paramterknt meg kell adnunk egy karak-
tertmb-mutatt, amelybe a fggvny a szveges reprezentcit elhelyezi nul-
lval lezrva. A tmb mrett a size paramterrel kell specifiklnunk. Ha tl
kicsi tmbt adunk meg, akkor a konverzi sikertelen lesz.
Sikeres konverzi esetn a fggvny a szveges reprezentci mutatjval
tr vissza (a dst paramter). Ellenkez esetben NULL rtkkel jelzi a hibt.
A megfelel szvegbuffermret megvlasztshoz a netinet/in.h llomny
tartalmaz kt segddefincit az IPv4 -es s az IPv6-os cmekhez:
#dgfine 4 4 W' 10,
afilite 1~A011~
292
6 . 5. I P
6.5.10. Loklis cm megadsa
A 6.2.2. A socket cmhez ktse alfejezetben megmutattuk a socketek cmhez
ktst. A cmhez kts mvelete egy loklis cm megadst ignyli. Az eddig
ltott fggvnyek segtsgvel ssze tudunk lltani egy olyan struktrt,
ahol a programunkat futtat szmtgp IP-cmt adjuk meg, tovbb egy
portot. Ezt kveten az adott cmhez kthetjk a socketet. Ezzel a mdszerrel
azonban tbb gond is van. Egyrszt ki kellene dertennk a programot futtat
gp cmt. Msrszt egy internetre kttt gpnek legalbb kt IP-cme van:
egy hlzati s egy loopbackcme
A megolds egy specilis cmbellts hasznlata, amely a futtat gp min-
den IP-cmhez hozzkti a socketet. Ez a cm IPv4 esetn az INADDR ANY,
amely ngybyte-os, 0-t tartalmaz rtk.
Megfog INAOD,LANY ttin.A4dr_t) No0000000)
Az IPv6 is rendelkezik egy hasonl defincival, ennek neve IN6ADDR ANY
INIT, s rtke 16 darab 0 byte-ot tartalmaz tmb:
#define IN6ADORANYXNZ1
-
Ot0,0~9404nAMilb04
Br a kt konstans hasonl, a hasznlatukban van egy klnbsg. Az INADDR_
ANY skalrtpus, ezrt brhol hasznlhatjuk rtkadsra. Viszont az
IN6ADDR_ANY _INIT tmbrtk, amelyet a C nyelv szintaktikja szerint egy
egyszer egyenlsgjellel nem msolhatunk le, kivve a tmb ltrehozst:
torsi strUOt InLiddr*100,0 0 .XN6APORANYLXNZ
,

A rendszer tartalmazza az ebben a pldban szerepl rtkadst, gy az
in6addr_any globlis vltoz fel is hasznlhat rtkadsra.
Bizonyos szolgltatsok esetn elfordul, hogy azokat csak loklisan elr-
hetv akarjuk tenni, s nem publikljuk az internet fel. Ilyenkor csak a
loopbackinterfszhez ktjk hozz a socketet. Ennek meghivatkozsra is
tartalmaz konstansokat a rendszer. IPv4 esetn a loopbackinterfsz cme
INADDRLOOBACK:
Iftlefine IkAnDILL001%
,

.ax7fOoGLIII1127 .4.tra.
IPv6 esetn egy tmbkonstansunk van IN6ADDR_LOOPBACK_INIT nven:
4ht!ifil* DtOtikE0OPWIUSTY
*- _ Att4:0.0A41.4.44';04
-
gti;04tUl
.
,11k t,t144
293
6. fejezet: Hlzati kommunikci
A definci mellett in6addr_loopback nven globlis vltoz is rendelkez-
snkre ll:
c o n s t s t r u c t i n 6_ a d d r i n 6a d d r _ l o o p ba c k
tmutat Figyeljnk arra, hogy az IPv4-es konstansok hosztbyte-sorrendben vannak, ezrt
mg konvertlni kell ket hlzati byte-sorrendre a htonI0 fggvnnyel. Ez a 0-t tartalmaz
INADDR_ANY esetn mg nem fontos, de az INADDR_LOOPBACK rtke mr nem O. Az IPv6-os
konstansok viszont hlzati byte-sorrendben vannak.
6.5.11. Nv- s cmfelolds
Az IP-cmek hasznlata a felhasznlk szmra nehzkes, mivel sok szmot
kellene fejben tartaniuk. Emellett, ha a szerver IP-cmt trjuk, akkor a fel-
hasznlk nem talljk meg tbb. Ezrt a gyakorlatban nem is IP-cmeket,
hanem hosztneveket hasznlunk. Ha a hoszt nevbl az IP-cmt szeretnnk
megllaptani, akkor nvfeloldsrl beszlnk.
A nvfelolds trtnhet szmos forrs alapjn:
loklis llomny (/etc/hosts),
kzponti szerverek (DNS, mDNS, Yellow pages stb.),
Szerencsre programozknt nem kell minden lehetsges forrst leimplemen-
tlnunk. Helyette a Linux egysges nvfeloldst vgz fggvnyeket nyjt.
6.5.11.1. A getaddrinfo() fggvny
A getaddrinfo0 fggvny a hosztnevet s a szolgltatsnevet (lsd 6.5.7. Portok
alfejezetben) kpes tkonvertlni IP-cmm s portszmm.
83
A fggvny egya-
rnt kezeli az IPv4 -es s az IPv6-os cmeket. Hasznlata sorn olyan kritriumo-
kat adunk meg, amelyekkel meghatrozzuk a megfelel cmeket. Ennek hatsra
a fggvny egy cmekbl ll listt ad vissza. A fggvny alakja a kvetkez:
#include <sys/socket.h>
#include <netdb.h>
int getaddrinfo(const char *node, const char *service,
const struct addrinfo *hints,
struct addrinfo **res);
void freeaddrinfo(struct addrinfo *res);
const char *gai trerror(int errcode);
83
A getaddrinfo() fggvny eldeinek tekinthet a gethostbynaine(), amely hosztnv felol-
dsra kpes, illetve a getservbyname(), amely a szolgltatsok portjt adja vissza. Ezeket
a fggvnyeket azonban szmos korltjuk miatt manapsg nem hasznljuk.
294
6.5. IP
A lista memriafoglalsnak felszabadtshoz s a hibakezelshez tovbbi
fggvnyek llnak rendelkezsre.
A node paramterben kell megadnunk a hosztnevet, a service paramter-
ben pedig azt a szolgltatst, amelyeknek a cmre kvncsiak vagyunk Mind
a kt esetben szveges formtumot hasznlunk. A hosztnvnl megadhatunk
IP-cmet a szoksos formtumokban ekkor az inet_pton0 fggvnyt helyet-
testheti , illetve a hoszt nevt. A szolgltatsnl is hasznlhatjuk a megne-
vezs mellett a port szmt szveges, decimlis formtumban. Ha a service
paramternek NULL rtket adunk meg, a fggvny a vlaszban a portsz-
mot nem lltja be.
A hints paramterben adhatjuk meg azokat a kritrumokat, amelyek
meg kell, hogy feleljenek a tallatoknak. A res paramterben kapjuk meg
a vlaszt lncoltlista-formban. Ksbb a lncolt lista felszabadtsban a
freeaddrinfo() fggvny segt, amellyel egy lpsben megoldhat a feladat.
A getciddrinfo0 fggvny visszatrsi rtke 0, ha sikeresen vgrehajt-
dott. Hiba esetn a visszatrsi rtk egy olyan hibakd, amelynek szveges
informciv alaktst a gai_strerrorO fggvnnyel vgezhetjk el.
Mind a kritriumok, mind a vlasz tpusa struct addrinfo, ennek felpt-
se a kvetkez:
struct addrinfo
int ai_flags ;
int ai _fami 1 y ;
int ai_socktype;
int ai_protocol ;
si ze_t ai_addrlen;
struct sockaddr *ai_addr;
char *ai_canonname;
struct addrinfo *al_next;
};
Az ai_family mez a cmcsaldot adja meg. rtke lehet AF INET s AF_INET6
is. Kritriumknt AF UNSPEC rtket is bellthatunk. Ekkor a vlaszlistban
IPv4 -es s IPv6-os cmek is szerepelhetnek.
Az ai_socktype mezben a SOCK STREAM s a SOCK DGRAM rt-
keket vagy 0-t adhatunk meg. 0 rtk esetn mind TCP-, mind UDP-bejegyz-
seket tartalmazhat a vlaszlista, ha az adott szolgltats mindkt protokollt
tmogatja.
Az ai_protocol a protokollindexet adja meg. Kritriumknt 0-t megadva
azt jelenti, hogy a protokollrtket nem ktjk meg.
Az eddig felsorolt hrom mez rendre a socketO fggvny paramterei le-
hetnek, amikor felhasznlunk egy vlaszbejegyzst.
Az ai_addrlen mez a cm mrett adja meg byte-okban. A cmet az
ai_addr mez tartalmazza byte-osan sockaddr_in (IPv4 ) vagy sockaddr_in6
(IPv6) formtumban. Ezeket az rtkeket hasznlhatjuk a cm megadsnl.
295
6, fejezet: Hlzati kommunikci
Az ai_canonname mez csak a lista els elemnl van kitltve, s a hoszt
nevt tartalmazza abban az esetben, ha kritriumknt az ai_flags mezben az
AI CANONNAME rtket megadtuk.
Az ai_next mez a lncolt lista kvetkez elemre mutat, illetve a lista
utols elemnl az rtke NULL.
A lista vgre hagytuk az ai_flags mezt, amely egy kicsit hosszabb ma-
gyarzatot ignyel. Ez a mez a kritriumok sszelltsnl kap szerepet.
Egy bitmaszkrl van sz, amely klnbz opcikat kapcsolhat be. A hasznl-
hat rtkeket a 6.7. tblzat foglalja ssze:
6.7. tblzat. A cmmegads s -sz
-
rs opcii
Jelzbit Lers
AI ADDRCONFIG A vlaszlista csak akkor tartalmaz IPv4 -es cmet, ha a loklis
gpnek legalbb egy IPv4 -es cme van, amely nem a
loopbackcm. Illetve IPv6-os cmek esetn hasonlkppen.
AI ALL Csak az AI V4MAPPED rtkkel van jelentse. rtelmezst
lsd ott.
AI CANONNAME Ha a node paramter rtke nem NULL, akkor a vlaszlista el-
s elemnek ai_canonname mezje tartalmazza a hoszt nevt.
AI NUMERICHOST Kikapcsolja a nvfeloldst, s a node paramter rtke csak
numerikus cmreprezentci lehet. Ezzel megtakarthatjuk a
nvfelolds idejt.
AI NUMERICSERV Kikapcsolja a szolgltats nvfeloldst. Szolgltatsnak csak
szmot adhatunk meg (szvegesen).
AI PASSIVE A cmstruktra egy szerversocket cmhez ktshez hasznl-
hat loklis cmet tartalmaz, ha ez az opci be van lltva, s a
node paramter NULL. Vagyis a cm INADDR ANY vagy
IN6ADDR ANY INIT lesz.
Al V4MAPPED Ha ez az opci be van kapcsolva, s mellette a kritrium
aijamily mez rtke AF INET6, s a fggvny ennek ellen-
re csak IPv4 -es cmet tall, akkor az IPv4 -es cmet IPv6-os
formtumban adja vissza. Ha az AI ALL opcival egytt al-
kalmazzuk, akkor IPv6-os s IPv4 -es cmeket is visszaad, de
utbbiakat IPv6-os formtumba alaktva.
Jrjuk krbe az AI PASSIVE opcit egy kicsit jobban. Ha ezt az opcit bel-
ltjuk, s nem adunk meg hosztnevet, akkor a kapott cm tipikusan a bind0
fggvnnyel hasznlhat (INADDR ANY vagy IN6ADD_ANY INI7). Ha nem
lltjuk be ezt az opcit, akkor a kapott cm a connect() s a sendto0 fggv-
nyek szmra hasznlhat. Ez esetben, ha megadunk hosztnevet, akkor an-
nak a cmt vagy cmeit kapjuk vissza. Arra is lehetsgnk van azonban,
hogy nem adunk meg hosztnevet, s akkor a loopbackcmet kapjuk vissza
(INADDR_LOOPBACK vagy IN6ADDR_LOOPBACK INIT).
296
6.5. IP
Br a kritriummegadsra s a vlaszlista ellltsra ugyanazt a
struktrt hasznljuk, valjban a mezk hasznlatban van nmi eltrs.
Kritrium megadsakor csak az aijlags, az aiJamily, az ai_socktype s az
aiprotocol mezknek van szerepe. A tbbi mez rtkt nem hasznljuk, r-
tkknek 0-nak vagy NULL-nak kell lennie. A vlaszban pedig az aijlags
meznek nincsen szerepe.
Ha semmilyen kritriumot nem kvnunk belltani, csak a hoszt nevre
s a szolgltatsra szrni, akkor kritriumknt NULL rtket is belltha-
tunk. Ez azzal egyenrtk, mintha az aijlags meznek (AI V4MAPPED I
Al ADDRCONFIG) rtket, az aijamily meznek AF UNSPEC rtket, mg
a tbbi meznek 0-t lltottunk volna be.
Feladat Alkossunk egy egyszer programot, amely a paramterknt kapott hosztnevet IP-
cmm alaktja s kirja.
/* getpaddr.c - internetes nvfelolds. */
#include <stclio.h>
#include <string.h>
#include <netdb.h>
#include <arpa/inet.h>
int main(int argc, char* argv[])
struct addrinfo hints;
struct addrinfo* res;
struct addrinfo* p;
int err;
char ips[INET6_ADORSTRLEN];
if(argc !=2)
printf("Hasznlat: %s <nv>\n", argv[0]);
return -1;
}
memset(&hints, 0, sizeof(hnts));
hints.ai_family =AF_UNSP EC;
hints.ai_socktype =SOCK_STREAM;
err = getaddrinfo(argv[11, NULL, &hints, &res);
if(err !=0)
{
fprintf(stderr, "getaddrinfo: %s\n", gai_strerror(err));
return -1;
}
for(p =res; p !=NULL;p=p->ai_next)
if(p->ai_family ==AF_INET)
{
297
6.fej ezet:H lzatik ommunik ci
i f(inet_ntop(AF_INET,
&((structsock addr_in*)(p->ai_addr))->
sin_addr, ps,sizeof(ips))!=NULL)
{
printf("IP :%s\n", ps);
}
elseif(p->ai_family ==AF_INET6)
if(inet_ntop(AF_INET6,
&((structsock addr_in6*)(p->ai_addr))->
sin6_addr,ips,sizeof(ips))!=NULL)
printf("IP :Yos\n",ips);
}
}
freeaddrinfo(res);
return0;
Teszteljk is le:
./getipaddrwww.aut.bme.hu
IP :152 .66.188.11
S . /getipaddrwww.google.com
IP :173 .194.3 5.176
IP :173 .194.3 5.177
IP : 173 .194.3 5.178
IP : 173 .194.3 5.179
IP : 173 .194.3 5.180
IP :2 a00:1450:4016:801::1011
S . /getipaddrthat.s.not.funny .com
getaddrinfo:Nameorserv icenotk nown
6. 5 . 1 1 . 2 . A g e t n a n n * ; f i 3 O f ggv n y
A getnameinfo0 fggvny nagyjbl a getaddrinfoo fggvny inverze. Az a fe-
ladata, hogy a socketcmet hoszt- s szolgltatsnvv konvertlja." A fgg-
vny alakja az albbi:
84
Ez a fggvny egyesti a korbban, az IPv4 esetn hasznlatos gethostbyaddr0 s
geiservbyport0 fggvnyek funkcionalitst, m azoknl flexibilisebb.
298
#include <sys/socket.h>
#include <netdb. h>
int getnameinfo(const struct sockaddr *sa, socklen_t salen,
char *host, size_t hostlen,
char *serv, size_t servlen, int flags);
Az sa paramter a socketcmstruktra (sockaddr_in vagy sockaddr_in6) muta-
tja. A struktra mrett a salen paramterben kell megadnunk. A host s a
serv paramterknt egy-egy ltalunk lefoglalt karaktertmbt kell tadnunk,
amelyeknek mrett a hostlen s a servlen paramterekkel tudjuk kzlni. Eb-
ben a kt tmbben kapjuk vissza a hoszt s a szolgltats nevt NULL termi-
nlt sztringknt. Ha valamelyik rtkre nem vagyunk kvncsiak, akkor NULL
rtket s 0 hosszsgot megadva ezt jelezhetjk. Termszetesen legalbb az
egyiket krnnk kell, mert klnben nincs rtelme meghvni a fggvnyt.
A flags paramter mdosthatja a fggvny mkdst a 6.8. tblzat szerint.
6.8. tblzat. A getnameinfo fggvny jelzbitjei
Jelzbit Lers
NI DGRAM Egyes portoknl TCP s UDP protokollok esetben ms-ms
szolgltats fut. Alaprtelmezetten a TCP-szolgltats nevt
kapjuk vissza. Ezzel a paramterrel az UDP-szolgltatst kap-
juk meg.
NI NAMEREQD Alaprtelmezetten, ha a hosztnevet nem tallja a fggvny,
akkor szveges IP-cmet ad vissza. Ha megadjuk ezt az opcit,
akkor ebben az esetben hibval tr vissza a fggvny.
NI NOFQDN Alaprtelmezetten teljes hosztnevet (Fully Qualified Domain
Name) kapunk vissza, ezzel az opcival csak a rvid
hosztnevet.
NI NUMERICHOST Ha megadjuk, akkor nem trtnik nvfelolds, hanem csak
szveges IP-cmet kapunk vissza. Ez trtnik akkor is, ha nem
sikerl a hosztnevet kiderteni.
NI NUMERICSERV Numerikusan, egy decimlis szmot tartalmaz szvegknt
kapjuk vissza a portot.
Sikeres vgrehajts esetn a fggvny 0-val tr vissza. Sikertelensg esetn
hibakdot kapunk visszatrsi rtkknt, amelyet ekkor is a gai_strerror()
fggvnnyel tudunk szvegg alaktani.
A getnameinfo() fggvnyt elssorban az acceptQ vagy a reevfrom() fggv-
nyek ltal visszaadott cmekre alkalmazzuk. Tipikusan a naplzshoz alaktjuk
vissza a socketcmeket a felhasznl szmra is rtelmezhet formtumba.
Feladat Az elz fejezet pldjt alaktsuk gy t, hogy a socketcmet szveges IP-cmm a
getnameinfo0 fggvnnyel alaktjuk vissza.
2 99
6. fejezet: Hlzati kommunikci
/*getipaddr.c-Internetesn v felold s.*/
#include<stdio.h>
#include<string.h>
#include<netdb.h>
intmain(intargc,char*argv [])
{
structaddrinfohints;
structaddrinfo*res;
structaddrinfo*p;
interr;
charip5[INET6_ADDRSTRLEN];
if(argc!=2 )
printf("Haszn lat:%s<n v >\n",argv [0]);
return-1;
}
memset(&hints,0,sizeof(hints));
hints.ai_family =Ar_uNSP EC;
hints.ai_sock ty pe=SOCK_STREAM;
err=getaddrinfo(argv [1],NULL,&hints,&res);
i f(err!=0)
{
fpr ntf(stderr,"getaddrinfo:%s\n",gai_strerror(err));
return-1;
for(p=res;p!=NULL;p=p->ai_next)
{
if(getnameinfo(p->ai_addr,p->ai_addrlen,
ips,sizeof( ps), NULL,0,NI_NUMERICHOST)=0)
printf("IP :%s\n",ips);
}
}
freeaddrinfo(res);
return0;
m nemcsak a cmet hozhatjuk szveges formba ezzel a fggvnnyel, hanem
inverz nvfeloldst is vgezhetnk vele.
Feladat Ksztsnk egy programot, amely a paramterknt megkapott IPv4-es cmet hoszt-
nvv alaktja.
300
6.5.IP
/*gethost.c-IP c mheztartozn v felold sa.*/
# nclude<stdio.h>
#include<string.h>
#include<netdb.h>
#include<arpa/inet.h>
intmain(intargc,char*argv [])
structsock addr_ naddr;
charname[Ni_mAxH0ST];
interr;
if(argc!=2 )
printf("Haszn lat:%s<IP c m>\n",argv [0]);
return-1;
}
memset(&addr,0,sizeof(addr));
addr.sin_family =AF_INET;
i fOnet_ptOn(AF_INET,argv [1],&addr.sin_addr)==0)
perror("inet_pton");
return-1;
err=getnameinfo((structsock addr*)&addr,sizeof(addr),
name,sizeof(name),NULL,0,NI_NAMEREQD);
if(err!=0)
fprintf(stderr,"getnameinfo:%s\n",gai_strerror(err));
return-1;
printf("Ag pnev e:%s\n",name);
return0;
}
A programot letesztelve a kvetkez kimenetet kapjuk:
$./gethost152 .66.188.11
Agepnev e:www.aut.bme.hu
$./gethost152 .66.188.111
qetnameinfo:Nameorserv icenotk nown
emmemer
-
11
301
6. fejezet: Hlzati kommunikci
A pldaprogramban szembesltnk azzal a problmval, hogy foglalnunk kell
egy megfelel mret buffert a gp nevnek. Szeretnnk akkort foglalni,
hogy belefrjen a teljes nv, de nem tudhatjuk, mi elg. Hasonl problmval
a szolgltatsnevek feloldsnl is szembeslhetnk. A programoz dolgt az
albbi kt definci megknnyti:
Ez a kt rtk akkora, hogy a vrhat nevek belefrnek ekkora bufferekbe.
6.5.12. sszekttets-alap kommunikci
A 6.2. Az sszekttets-alap kommunikci alfejezetben mr bemutattuk az
sszekttets-alap kommunikci egyes lpseit. IP-kommunikci esetn is
ezeket a lpseket kvetjk, csak annyi kiegsztssel, hogy IP-socketet hozunk
ltre, s a cmet az elz fejezetekben megismert mdon lltjuk ssze. gy je-
lenlegi ismereteink alapjn mr kpesek vagyunk egy TCP-kommunikci
felptsre s hasznlatra.
A kommunikci sorn hasznlhatjuk a reado s a write() fggvnyeket,
a rendszer tartalmaz azonban kt olyan msik fggvnyt, amely tbb lehet-
sget nyjt.
Az adatok kldshez hasznlhatjuk a send0 fggvnyt:
#include <sys/socket.h>
ssize_t send(int sockfd, const void *buf, , si ze_t len, int flags) ;
Az els argumentum a socket lerja, a msodik az elkldend adat buffernek
a mutatja, a harmadik az elkldend adat mrete. Eddig a paramterezs
megegyezik a write() fggvnyvel. A klnbsget az utols, flags argumen-
tum jelenti, amelyben tovbbi opcikat llthatunk be. A flags argumentum-
ban megadott jelzbitek jelentst a 6.9. tblzat mutatja.
6.9. tblzat. A send jelzbitjei
4 04 0bit _ Lelt4
MSG_DONTROUTE A csomag nem mehet keresztl az tvlasztkon, csak kzvet-
lenl ugyanazon a hlzaton lv gp kaphatja meg.
MSG_DONTWAIT Engedlyezi a nem blokkol I/O-t. EAGAIN hibval tr vissza,
ha vrakozni kellett volna a kirsra, mert tele van a buffer.
MSG_MORE Tovbbi adatot szeretnnk mg kikldeni. Ezrt nem kldi el a
csomagot addig, amg nem kap egy sendO hvst MSG_MORE
opci nlkl.
302
6.5. iP
'
4 8126 b it Ler s
MSG_NOSIGNAL Adatfolyam-alap kapcsolat esetn a program nem kap
SIGPIPE jelzst, amikor a kapcsolat megszakad. Ez azonban
az EPIPE hibajelzst nem rinti.
MSG_OOB Soron kvli srgs adatcsomagot (out-of-band data) kld.
ltalban jelzsek hatsra hasznljk.
A sertd() visszatrsi rtke hasonlt a write() fggvnyhez. Sikeres klds
esetn az elkldtt byte-ok szmt kapjuk vissza, hiba esetn pedig negatv
rtket. Utbbinl az errno globlis vltoz tartalmazza a hibt.
A send0 prja a recv() fggvny, amely a readO fggvnyre hasonlt:
4 include <sys/socket.h>
ssize_t recv(int sockfd, void * buf, size_t len, int flags);
A fggvny els hrom paramtere a read() fggvnynl is megszokott alak.
Sorban a socketler, a fogad buffer s a buffer mrete. Ezt kveti a flags pa-
ramter, amellyel tovbbi opcikat llthatunk be. A flags paramter rtke a
6.1(). tblzatban sszefoglalt jelz'bitekbl llhat ssze:
6.10. tblzat. A recv jelzbitjei
Jelzbit
d
r Ler s
MSG_DONTWAIT Engedlyezi a nem blokkol 1/0-t. EAGAIN hibval tr vissza, ha
vrakozni kellett volna az olvassra, mert nem rkezett adat.
MSG_OOB Soron kvli adat fogadsa.
MSG_PEEK Az adat beolvassa trtnik meg anlkl, hogy a beolvasott
adatot eltvoltan a bufferbl. A kvetkez recv0 hvs ugya-
nazt az adatot mg egyszer kiolvassa.
MSG_WAITALL Addig nem tr vissza, amg a megadott buffer meg nem telik,
vagy egyb rendhagy dolog nem trtnik, pldul jelzs rkezik.
A recv0 fggvny visszatrsi rtke megegyezik a read() fggvnyvel. Sike-
res olvass esetn a bufferbe bert byte-ok szma, hiba esetn mnusz rtk,
valamint 0, ha a tloldal lezrta a kapcsolatot.
Gyakori feladat, hogy a TCP-kapcsolaton keresztl egy llomnyt kell el-
kldennk. Ezt leimplementlhatjuk gy, hogy egy ciklusban a readO fgg-
vnnyel beolvassuk az adatokat egy bufferba, majd a send0 fggvnnyel el-
kldjk a TCP-kapcsolaton. Ez a megolds jl mkdik, m nagyobb mret
llomny esetben sokszor meghvdna a ciklus, s egyre inkbb eljnne a
htrnya, miszerint az adatokat az egyik rendszerhvssal a kernelbl egy
tmbbe msoljuk, majd egy msik rendszerhvssal vissza a kernelbe. Egy-
szerbb s gyorsabb egy lpsben a kernelben elvgezni az egsz mveletet.
Ezt valstja meg a sendfileQ rendszerhvs:
303
6.fej ezet:H lzatik ommunik ci
#include <sys/sendfile.h>
ssize_t sendfile(int out_fd, int in_fd, off_t *offset,
size_t count);
A fggvny az in_fd llomnylerval megadott llomnybl az out_fd llo-
mnylerval lert socketkapcsolatba kldi az adatokat. Ha az offset param-
ter nem NULL, akkor egy olyan vltoz mutatjt kell, hogy tartalmazza,
amely megadja az eltolst az in_fd llomny elejhez kpest. Az olvasst s a
kldst csak ettl a pozcitl kezdi el a fggvny. Amikor a fggvny vissza-
tr, akkor mdostja az eltols rtkt. Az j rtk az utols elkldtt byte + 1
lesz. Ha az offset nem NULL, akkor a fggvny nem mdostja a bemeneti l-
lomny aktulis pozcijt.
Ha az offset rtke NULL, akkor az olvass a bemeneti llomny aktulis
pozcijtl indul, s a fggvny vgn frissl is.
A count paramter a msoland byte-ok szmt adja meg. Ha tbb lenne,
mint amennyi byte-ot az llomny tartalmaz, akkor csak az llomny vgig
tovbbtja a byte-okat.
Sikeres visszatrskor a visszatrsi rtk az elkldtt byte-ok szma. Hiba
esetn mnusz rtk, s az errno globlis vltoz tartalmazza a hibakdot.
A sendfile0 rendszerhvs mellett a Linux tmogat mg tovbbi nem
szabvnyos rendszerhvsokat is hasonl clokra: spliceO, vmspliceO, teeO.
Ezekre jelen keretek kzt nem trnk ki.
6.5.12.1. TCP kliens-szerver plda
Eddigi ismereteink alapjn knnyen meg tudunk valstani egy egyszer
TCP-szervert s a hozzkapcsold klienst.
Feladat Alkossunk egy egyszer TCP-szervert, amely kpes egy kapcsolat fogadsra, majd a
klienstl kapott adatokat kirja az alaprtelmezett kimenetre.
A feladatot az albbi, IPv6-ot tmogat szerverprogram megoldja:
#include<stdio.h>
#include<stdlib.h>
#include<unistdh>
#include<string.h>
#include<sy s/sock et.h>
#include<netinet/in.h>
#include<netdb.h>
#definePO RT "112 2 "
304
I
if(listen(ssock ,5)<0)
perror("listen");
return1;
6.5.IP
intmain()
structaddrinfohints;
structaddrinfo*res;
nterr;
structsock addr_in6addr;
sock len_taddrlen;
charips[Ni_mAXHOST];
charserv s[NI_MAXSERV];
intssock ,csock ;
charbuf[2 56];
intlen;
intreuse;
memset(&hints,0,sizeof(h nts));
h nts.a _flags=AI_P ASSIVE;
hints.ai_family =AF_INE76;
hints.ai_sock ty pe=SOCK_STREAM;
err=getaddrinfo(NULL,P ORT,&hints,&res);
i f(errI--0)
fprintf(stderr,"getaddrinfo:%s\n",gai_strerror(err));
return-1;
if(res==NULL)
{
return-1;
}
ssock =sock et(res->ai_family ,res->ai_sock ty pe,
res->ai_protocol);
if(ssock <0)
perror("sock et");
return1;
reuse=1;
setsock opt(ssock ,SOL_SOCKET,SO_REUSEADDR,&reuse,
sizeof(reuse));
if(bind(ssock ,res->ai_addr,res->ai_addrlen)<0)
{
perror("bind");
return1;
}
3 05
6. fejezet: Hlzati kommunikci
freeaddrinfo(res);
addrlen =sizeof(addr);
while((csock =accept(ssock,
(struct sockaddr*)&addr, &addrlen)) >=0)
{
if(getnameinfo((struct sockaddr*)&addr, addrlen,
i ps, sizeof(ips), servs, sizeof(servs), 0) ==0)
{
printf("Kacsolds: %s:%s\n", ips, servs);
}
while((len =recv(csock, buf, sizeof(buf), 0)) > 0)
write(STDOUT_FILENO, buf, len);
printf("Kapcsolat zrsa.\n");
close(ssock);
close(ssock);
return 0;
A cmhez ktshez ssze kell lltanunk egy loklis cmet. Ezt megtehetjk kz-
vetlenl a sockaddr_in6 struktra kitltsvel, vagy rbzhatjuk a getaddrinfo()
fggvnyre. Pldnkban az utbbit vlasztottuk, hogy bemutassuk a hasznlatt.
A szervercmhez a fggvny kritriumban meg kell adnunk az Al PASSIVE op-
cit. Ugyanakkor a paramterek kzt hosztnvnek NULL rtket adtunk meg.
A kt bellts hatsra a cm rtke 1N6ADDR ANY INIT lesz.
A cm ellltsa utn ltrehozunk egy socketet, majd a setsockoptQ fgg-
vny segtsgvel belltjuk, hogy a programunk lellsa utn a szolgltats
portja azonnal smt hasznlhat legyen. (A setsockopt() fggvnyt bvebben
a 6.6. Socketbellt sok alfejezetben ismertetjk.)
Ezt kveten hozzktjk a socketet a cmhez, s bekapcsoljuk a szerver-
mdot. Majd egy cikluson bell fogadjuk a kapcsoldsokat, kirjuk a kliens
cmt, portjt s a kapott adatokat. Amikor a kliens lezrja a kapcsolatot, ak-
kor a recv() fggvny nullval tr vissza, s megszakad a ciklus. Ezt kveten
a szerver is zrja a socketet, s vrja a kvetkez kapcsolatot.
Feladat Alkossuk meg az elz szerver kliensprjt. A kliens kapcsoldjon a paramterknt
megadott szervergphez, s a socketkapcsolaton kldje el az alaprtelmezett bemenetn ka-
pott szveget.
Az albbi pldaprogram valstja meg a feladatot:
306
6.5.IP
#include<stdio.h>
#include<unistd.h>
#include<string.h>
#include<sy s/sock et.h>
#include<netinet/in.h>
#include<arpa/inet.h>
#include<netdb.h>
#defineP ORT"112 2 "
intmain(intargc,char*argv [])
{
structaddrinfohints;
structaddrinfo*res;
interr;
intcsock ;
charbuf[102 4];
i ntlen;
if(argc!=2 )
{
printf("Haszn lat:%s<szerv er>\n",argv [0]);
return1;
}
memset(&hints,0,sizeof(hints));
hints.ai_family =AF_UNSP EC;
hints.ai_sock ty pe=SOCK_STREAM;
err=getaddrinfo(argv [1], P ORT, &hints,&res);
if(err!=0)
fprintf(stderr,"getaddrinfo:%s\n",gai_strerror(err));
return-1;
}
if(res==NULL)
{
return-1;
}
csock =sock et(res->ai_family ,res->ai_sock ty pe,
res ->ai_protocol);
if(csock <0)
{
perror("sock et");
return-1;
if(connect(csock ,res->ai_addr,res->ai_addrlen)<0)
perror("connect");
return-1;
307
6. fejezet: Hlzati kommunikci
while((len = read(STDIN_FILENO, buf, sizeof(buf))) >0)
{
send(csock, buf, len, 0);
}
close(csock);
freeaddrinfo(res);
return 0;
}

A pldaprogramban a getaddrinfo() fggvny segtsgvel ellltjuk a clgp
megadott portjhoz tartoz cmstruktrt. Ha tbb cmet is visszakapunk, ak-
kor a lista els elemt vlasztjuk a kapcsoldshoz. A kapcsolat ltrejtte utn
a program folyamatosan olvassa az alaprtelmezett bemenetet, s a szveget
elkldi a socket, kapcsolaton keresztl Amikor a bemenetet a CTRL +D gom-
bokkal lezrjuk, akkor a program zrja a socketkapcsolatot, s vget r.
6.5.12.2. TCP szerver alkalmazs
Az elz fejezetbeli szerverplda alkalmazsa tartalmaz egy slyos hinyos-
sgot. Az alkalmazs egyszerre csak egy kapcsolatot kpes fogadni. Addig,
amg ezt kiszolglja, nem hvdik meg az aceept() fggvny, s nem fogad
jabb kapcsolatot. Az ilyen jelleg szervereket iteratv szervernek nevezzk,
s legfeljebb olyan esetekben alkalmazzuk, amikor a kliensek kiszolglsa
nagyon gyors.
ltalban a kliens-szerver kommunikci hosszabb, s a szerverektl azt
vrjuk el, hogy konkurensen egyszerre tbb klienst is kiszolgljanak. Ilyenkor
prhuzamosan kell futnia a kapcsolatok fogadsnak s a kliensek kiszolg-
lsnak. Erre a problmra tbb szerveroldali megkzeltst alkalmazhatunk.
Kapcsolatonknt egy szl (folyamat)
Minden bejv kapcsolatnak j szlat (vagy folyamatot) indtunk, amelynek
tadjuk a kapcsoldott klienssocketet. A klienssocketet ezt kveten mr a
szl (folyamat) kezeli. Ekkor minden kapcsolatot a kd szempontjbl szim-
metrikusan kezelnk, de a szlak (folyamatok) kztti vlts lasst tnyez.
Illetve a sajt stack miatt nem sklzdik jl nagy szervereken.
Processzek esetben a Linux copy-on-write technikja (forkQ hasznlata-
kor csak akkor msolja le a memriaterletet, ha arra a gyermekprocessz r)
jelentsen cskkenti az j processz ltrehozsnak az idejt, jllehet egy j
processz ltrehozsa kln erforrst emszt fel a rendszerbl, s az indthat
processzeknek fels korltja van.
308
6.5. IP
Ugyanakkor processzek esetben az 5.1. Processzek alfejezetben trgyalt
exec() fggvnycsald segtsgvel knnyen indthatunk ms programokat."
Robusztussg szempontjbl viszont, ha j processzt indtunk, annak esetle-
ges sszeomlsa nem rntja magval az sszes tbbi processzt.
Elre elindtott szlak (folyamatok)
A fenti mdszert gyorsthatjuk azzal, hogy a szerverprogram elindtsa utn
rgtn egy meghatrozott szm szlat (folyamatot) indtunk el (process
pool", thread pool"), s ha valamelyik szabad, az kezeli az jonnan bejv
kapcsolatot. A korbbi megoldshoz kpest ekkor egy feladatkioszt algorit-
must is kell ksztennk.
A megolds elnye az, hogy a szlak (folyamatok) szmnak korltozs-
val optimlisan kihasznlhatjuk a gp erforrsait. Emellett egy DoS-tma-
ds
86
csak a szolgltatst rinti, s nem fojtja" meg az egsz gpet.
A mdszer htrnya az, hogy esetleg feleslegesen sok szlat (processzt)
futtat foglalva az erforrsokat. Ennek kezelsre a komolyabb programok
menedzsmentalgoritmust alkalmaznak, amely a terhels figyelembevtelvel
megszntet vagy ltrehoz szlakat (folyamatokat). m egy ilyen algoritmus
implementlsa bonyoltja a programot.
Nzznk egy egyszer pldt az elre alloklt szlak hasznlatra. A pl-
daprogramban egy vletlen szmokat visszaad szervert mutatunk be:
#include <stdo. h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#nclude <sys/socket. h>
#include <netinet/in.h>
#include <pthread. h>
#define PORT 2 2 33
#define THREAD_NUM 3
int ssock;
pthread_mutex_t smutex = PTHREAD_MUTEX_INITIALIZER ;
85
Ha paramterknt vesszk t a futtatand program nevt, mindig gondoljuk t a szerver
tmadhatsgt. Ha egy nem ellenrztt sztringet tadunk az execQ fggvnynek, a tvoli
felhasznl akrmit lefuttathat a gpnkn a fut szerverprogram jogosultsgval.
A lelemnyes betr ilyenkor pldul lefuttatja a sendmail segdprogramot, hogy az kldje
el neki a jelszavakat tartalmaz fjlt, amellyel aztn otthon eljtszadozhat". Alapszably
teht: futtats eltt mindig ellenrizzk a kvlrl kapott paramtereket.
K
6
Az elrasztsos tmads (DoS, denial-of-service attack) vagy elosztott elrasztsos t-
mads (DDoS, distributed denial-of-service attack) sorn olyan sok kapcsoldsi krelem
rkezik a szerverszolgltatshoz, amelyet az nem tud kezelni. A tmad gy teszi elrhe-
tetlenn a szolgltatst, de akr az egsz szervergpet is megbnthatja.
309
sleep(3 );
spr ntf(buf,"%d.sz l:%d\n",ix,rand()%10);
send(csock ,buf,strnlen(buf,sizeof(buf)),0);
close(csock );
returnNULL;
}
intmain()
f
structsock addr_in6addr;
pthread_tth[THRE4o_Num];
inti;
intreuse;
int*pix;
if((ssock =sock et(P F_INET6,SOCK_STREAM,0))<0)
{
perror("sock et");
return1;
}
reuse=1;
setsock opt(ssock ,SOL_SOCKET,SO_REUSEADDR,&reuse,
sizeof(reuse));
memset(&addr,0,s zeof(addr));
addr.sin6_family =AF_INET6;
addr.sin6_addr=in6addr_any ;
addr.sin6_port=htons(P ORT);
6. fejezet: Hlzati kommunikci
v oid*comth(v oid*arg)
f
intix;
intcsock ;
charbuf[64];
ix=*((int*)arg);
free(arg);
while(1)
pthread_mutex_lock (&smutex);
csock =accept(ssock ,NULL,NULL);
pthread_mutex_unlock (&smutex);
310
S.S. IP
if(bind(ssock, (struct sockaddr*)&addr, sizeof(addr)) < 0)
perror("bind");
return 1;
if(listen(ssock, 5)<0)
perror("listen");
return 1;
srand(time(NULL));
for(i =0;i<THREAD_NUM;i++)
pix = malloc(sizeof(int));
*pix = i;
pthread_create(&th[i], NULL, comth, pix);
}
// vgtelen vrakozs
while(1) sleep(1);
return 0;
A program indulskor elvgzi a szerversocket belltsait, majd ltrehoz hrom
szlat. A kapcsolatok sztosztsra a szlak kztt egy arnylag egyszer
trkkt alkalmazunk. Egy mutex segtsgvel elrjk, hogy egyszerre egy szl
hvhassa meg az acceptQ fggvnyt, s fogadhasson kapcsolatot. gy nem kell
tadnunk a klienskapcsolatokat a szlaknak.
A szerver kiprblshoz a telnet program segtsgvel kapcsoldjunk a
tcp 2 2 33-as porthoz. Kis vrakozs utn visszakapunk egy vletlen szmot, s
a szerver bontja a kapcsolatot.
Tbb kliens kezelse egy szlon
Az llomnyok prhuzamos kezelsnl megismert seleet(), pollQ s
epoi/0
fggvnyeket hasznlhatjuk a socketek esetn is. gy egy szlon, esemnyvez-
relten kezeljk az sszes klienssocketet. Emellett a szerversocketet is kezelhet-
jk ezzel a megoldssal, mert a kapcsolds egy olvassi esemnyt generl
ebben az esetben.
Az egyszl megvalsts lehetv teszi, hogy az egyes klienskapcsolatok
kztt adatokat mozgassunk szinkronizls nlkl. gy leginkbb ilyen jelle-
g alkalmazsokban ltszik az elnye.
Ugyanakkor a mdszer htrnya az, hogy a kd bonyolultabb, nem annyi-
ra szimmetrikus, mint a korbbiakban ltottak.
3 11
6.fej ezet:H lzatik ommunik ci
Az albbi program egy csevegszervert valst meg. Egy ilyen szolglta-
tsnl a felhasznlk egymsnak kldik az zeneteiket, vagyis az egyik kli-
enskapcsolaton rkez szveget a tbbi kapcsolatra kell kikldennk.
A kapcsolatok kztti adattvitel miatt a szolgltatst egy szlon rdemes le-
implementlni:
#include<stdio.h>
#include<stdlib.h>
#include<unistd.h>
# nclude<string.h>
#include<sy s/sock et.h>
#include<netinet/in.h>
#include<poll.h>
#defineP ORT3 3 44
#defineMAXCONNS5
, iI 1 1 1
#defineFULLMSG"megtelt!"
intssock ;
intconnect_list[mAxCONNs];
structpollfdpoll_list[mAXcoNNS+1];
intbuild_poll_list()
{
inti,count;
poll_list[0].fd=ssock ;
poll_list[0].ev ents=P OLLIN;
count=1;
for(i=0; <MAXCONNS;i++)
{
if(connect_list[1]>=0)
poll_list[count].fd=connect_list[i];
poll_list[count].ev ents=P OLLIN;
count++;
returncount;
v oidhandle_new_connection()
inti,csock ;
csock =accept(ssock ,NULL,NULL);
if(csock <0)return;
for(i=0;i<MAXCONNS;i++)
{
if(connect_list[i]<0)
3 12
6.5.1p
{
connect_list[i]=csock ;
csock =-1;
break ;
if(csock >=0)
send(csock ,FULLMSG,strlen(FULLMSG),0);
close(csock );
v oidprocess_read(intcsock )
{
charbuf[2 56];
intlen;
inti;
len=recv (csock ,buf,sizeof(buf),0);
if(len>0)
{
for(i=0;i<MAXCONNS;i++)
{
i f((connect_list[i]>=0)&&(connect_list[i]!=csock ))
send(connect_list[i],buf,len,0);
}
intmain()
structsock addr_in6addr;
i ntreuse;
inti;
int i;
if((ssock =sock et(P F_INET6,SOCK_STREAM,0))c0)
{
perror("sock et");
return1;
}
reuse=I;
setsock opt(ssock ,SOL_SOCKET,SO_REUSEADDR,&reuse,
sizeof(reuse));
memset(&addr,0,sizeof(addr));
addr.sinfl_family =AF_INET6;
addr.sin6_addr=in6addr_any ;
addr.sin6_port=htons(P ORT);
313
return0;
6.fej ezet:H lzatik ommunik ci
i f(bind(ssock ,(structsock addr*)&addr,sizeof(addr))<0)
perror("bind");
return1;
}
if(listen(ssock ,5)<0)
{
perror("listen");
return1;
}
for(i=0;i<MAXCONNS;i++)connect_list[i]=-1;
while(1)
i ntcount=build_poll_list();
if(poll(poll_list,count,-1)>0)
{
if(poll_list[0].rev ents&P OLLIN)
{
handle_new_connection();
for(i=1; <count;i++)
if(poll_list[i].rev ents&(P OLLERRIP OLLHUP ))
for(ii=0;ii<MAXCONNS;ii++)
i f(connect_list[ii]=pol1_1 st[iI . fd)
{
connect_list[ii]=-1;
close(pol1_11st[i].fd);
else f(poll_list[i].rev ents&P OLLIN)
process_read(poll_l st[i].fd);
_..
1
11
111

A program bellt egy szerversocketet, majd sszellt egy kapcsolatlistt. Ezt
kveten a poll0 rendszerhvssal vrja, hogy kapcsoldsi krelem rkezzen.
Amikor egy olvassi esemny rkezik a szerversocketre, akkor fogadja a kap-
csolatot, s elhelyezi a listba (vagy visszautastja, ha a szerver megtelt). Ezt
kveten ismt meghvdik a pollQ. Ha valamelyik klienskapcsolatra rkezk
adat, akkor a program beolvassa, s kikldi a tbbi kapcsolatra.
3 14
6.5. IP
A szerverre a telnet program segtsgvel tudunk csatlakozni (tcp 334 4 -es
port). rdemes egyszerre tbb kapcsolatot felpteni. Ezt kveten, amit az
egyik kapcsolaton elkldnk, az a szveg a tbbi kapcsolaton megjelenik.
6.5.12.3. TCP-kliensalkalmazs
A kliensalkalmazs az esetek tbbsgben egyetlen klienssocketet tartalmaz,
amely kapcsolatot kezdemnyez valamilyen szerver fel. Majd a kapcsolat
felvtele utn megindul a kommunikci. Itt az adatfogads jelenthet nmi
problmt, ugyanis alaprtelmezsben a recv0 hvs blokkoldik, s mindaddig
nem tr vissza, amg nem rkezik valamilyen csomag. Radsul kliensoldalon
gyakran grafikus felhasznli fellet tallhat, amely ltszlag lefagy", mert
az alkalmazs blokkolt llapotban nem tudja frissteni a kpernyt s reaglni
a felhasznli interakcikra. Ugyanez a problma lphet fel szveges termi-
nl esetben is, hiszen blokkolt llapotban nem tudunk olvasni a szabvnyos
bemenetrl. Lehetsges megoldsok a kvetkezk.
Szveges mdban tovbbra is hasznlhatjuk a selectO, poll(), epoll() fgg-
vnyt, amellyel nemcsak a socketre, hanem a szabvnyos bemenetre (stdin) is
vrakozunk.
Egy msik megolds a kln szl indtsa. Ilyenkor azonban sokszor meg
kell oldanunk a szlak kommunikcijt s a kzs adathozzfrs szinkroni-
zcijt. Kln folyamatot is indthatunk a socketkommunikcira, de a ne-
hzsgek hasonlak a szlakihoz.
Grafikus felhasznli fellet esetn aszinkron socket kezelsre van szk-
sgnk. A grafikus fejleszti knyvtrak tartalmaznak ennek megvalsts-
hoz mechanizmusokat. Hasznljuk ezeket.
A socketkommunikciban lehetsgnk van a magas szint fjlkezels
hasznlatra is. Erre mutat pldt az albbi kliensprogram, amely a HTTP
0.9-es protokoll segtsgvel lement egy internetoldalt. A kapcsolds utn a
szerveralkalmazsnl mr ltottaknak megfelelen hasznlhatnnk a recv()
s a send() hvsokat a kommunikcira (amelyek, mint kiderlt, sokkal tbb
lehetsget adnak a kommunikci szablyozsra), de a plda egyszers-
gnl fogva knyelmesebb a magas szint megoldst alkalmazni:
#include <stdio.h>
#include <unistd.h>
#include <fcntl.h>
#include <string.h>
#include <sysisocket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <netdb.h>
int main(int argc, char* argv[])
struct addrinfo hints;
struct addrinfo* res;
315
6.fej ezet:H lzatik ommunik ci
struccaddrinfo*p;
nterr;
charips[INET6_ADDRsTRLEN];
intcsock ;
charbuf[102 4];
FILE*fpsock ;
FILE*fpfile;
intlen;
if(argc!=4)
{
printf("Haszn lat:%s<szerv er><oldal><f j l>\n",argv [0]);
return1;
memset(&hints,0,sizeof(hints));
hints.ai_family =AF_UNSP EC;
hints.ai_sock ty pe=SOCK_STREAM;
1105err=getaddrinfo(argv [1],"http",&hints,&res);
if(err!=0)
{
fprintf(stderr,"getaddrinfo:%s\n",gai_strerror(err));
return-1;
}
fpfile=fopen(argv [3 ],"w");
if(fpfile==NULL)
{
perror("fopen");
return-1;
}
for(p=res;p!=NULL;p=p->ai_next)
{
lf(getnameinfo(p->ai_addr,p->ai_addrlen,
ips,sizeof(ips),NULL,0,NI_NUMERICHOST)==0)
{
printf("Kacsold s:%s\n",ips);
}
csock =sock et(p->ai_family ,p->ai_sock ty pe,p->ai_protocol);
i f(csock <0)continue;
if(connect(csock ,p->ai_addr,p->ai_addrlen)==0)
{
printf("Sik eresk apcsold s.\n");
fpsock =fdopen(csock ,"r+");
I
//HTTP 0.9oldallek r s
fpr ntf(fpsock ,"GET%s\r\n",argv [2 ]);
fflush(fpsock );
printf("Adatok ment se.\n");
316
6.5. IP
wh le((len=fread(buf,1,sizeof(buf),fpsock ))>0)
fwrite(buf,1,len,fpfile);
printf("Kapcsolatbont sa.\n");
fclose(fpsock );
break ;
}
else
perror("connect");
close(csock );
fclose(fpfile);
freeaddrinfo(res);
return 0;
Prbljuk ki a programot.:
./httpmentwww.aut.bme.hu/test.html
6.5.13. sszekttets nlkli kommunikci
sszekttets nlkli kapcsolathoz az IP-csald esetben a szlltsi rtegben
UDP-t (User Datagram Protocol, felhasznli datagramprotokoll) haszn-
lunk Az UDP protokoll mkdse egyszerbb, a fejlce kisebb, gy gyors kom-
munikcit tesz lehetv.
m nem garantlt, hogy
a csomag clba r;
az elkldtt adatok ugyanabban a sorrendben rkeznek meg, amely-
ben kldtk ket.
Az UDP-csomagok mrete legfeljebb 64 kB lehet.
6.5.13.1. UDP-kommunikci-plda
A 6.3. Az sszekttets nlkli kommunikci alfejezetben bemutattuk a kapcso-
lat nlkli kommunikci hasznlatt, az elz fejezetekben pedig az IP-cmek
kezelst. gy egy UDP-kommunikcit megvalst programot is sszellt-
hatunk.
3 17
6.fej ezet:H lzatik ommunik ci
A datagram-alap kommunikciknl ltalban nem klnbztetnk
meg szerver- s kliensszerepet, mivel mindkt oldal fogad s kld is adatokat.
A kvetkez pldban azonban a knnyebb rthetsg kedvrt a kt funkcit
sztvlasztottuk. gy lesz egy fogad- s egy kldprogramunk.
A fogadprogram UDP-csomagokat fogad. Kirja a kldt s a csomag tar-
talmt:
#include<stdio.h>
#include<stdl b.h>
#include<unistd.h>
#include<string.h>
#include<sy s/sock et.h>
#include<netinet/in.h>
#include<netdb.h>
#defineP ORT"112 2 "
intmain()
{
structaddrinfohints;
structaddrinfo*res;
interr;
structsock addr_in6addr;
sock len_taddrlen;
charips[NI_MAXHOST];
charserv s[NI_MAXSERV];
intsock ;
charbuf[2 56];
ntlen;
memset(&hints.0,sizeof(hints));
hints.ai_flags=AI_P ASSIVE;
hints.ai_family =AF_INET6;
h nts.ai_sock ty pe=SOCK_DGRAM;
err=getaddrinfo(NULL,P ORT,&hints,&res);
i f(err!=0)
fprintf(stderr,"getaddrinfo:%s\n",gai_strerror(err));
return-1;
}
if(res==NULL)
{
return-1;
sock =sock et(res->ai_family ,res->ai_sock ty pe,
res->ai_protocol);
3 18
b5. IP
if(sock <0)
perror("sock et");
return1;
i f(bind(sock ,res->ai_addr,res->ai_addrlen)<0)
perror("bind");
return1;
}
freeaddr nfo(res):
addrlen=s zeof(addr);
while((len=recv from(sock ,buf,sizeof(buf),0,
(structsock addr*)&addr,&addrlen))>0)
{
if(getnameinfoUstructsock addr*)&addr,addrlen,
ips,sizeof(ips),serv s,sizeof(serv s),0)==0)
fprintf(stdout,"%s:%s:",ips,serv s);
fflush(stdout);
}
write(STDOUT_FILENo,buf,len);
close(sock );
return0;
A kldprogram a szabvnyos bemeneten fogad szveget, s soronknt egy-
egy csomagban elkldi a szervernek. Egszen addig csinlja ezt, amg a
CTRL + D billentykkel lelltjuk a bevitelt:
#include<stdio.h>
#include<stdlib.h>
#include<unistd.h>
#include<string.h>
#include<sy s/sock et.h>
#include<netinet/in.h>
#include<arpa/inet.h>
#include<netdb.h>
#define PO RT "112 2 "
intmain(intargc,Ihar*argv [])
structaddrinfohints;
structaddrinfo*res;
3 19
i nterr;
intsock ;
charbuf[102 4];
intlen;
if(argc!=2 )
f
printf("Haszn lat:%s<szerv er>\n",argv [0]);
return1;
memset(&hints,0,sizeof(hints));
hints.a _family =AF_UNSP EC;
hints.ai_sock ty pe=SOCK_DGRAM;
6.fej ezet:H lzatik ommunik ci
err=getaddr nfo(argv [1], P ORT, &hints,&res);
if(err!=0)
{
fprintf(stderr,"getaddrinfo:%s\n",ga _strerror(err));
return-1;
}
if(res==NULL)
{
return-1;
}
sock =sock et(res->ai_family ,res->ai_sock ty pe,
res->a _protocol);
if(sock <0)
perror("sock et");
return-1;
while((len=read(ST0IN_FILENO,buf,sizeof(buf)))>0)
{
sendto(sock ,buf,len,0,res->ai_addr,res->ai_addrlen);
freeaddr nfo(res);
close(sock );
return0;
6.5.13.2. T bbe s kl d s
Amikor nemcsak egy vgpontnak, hanem egyszerre tbbnek szeretnnk elkl-
deni valamit, elg egyszer dolgunk van: specilis IP-cmre kell kldennk a
csomagot. A tbbes kldst (multicast) az IP-hlzaton az tvlasztk bo-
nyoltjk le.
3 2 0
6.11. tblzat. Elredefinilt IPv4-es multicastcsoportok
Az egy LAN-on lv tvlasztk
Az egy LAN-on lv tvlasztk
6.5. IP
IPv4 esetn valamelyik D osztly (2 2 4 .0.0.0-2 39.2 55.2 55.2 55) cmet kell
hasznlnunk. Minden D osztly cm egy hosztcsoportot jelent Vannak ideig-
lenes hosztcsoportok, amelyhez csatlakozhatunk, vagy amelybl kivlhatunk.
Van azonban nhny lland cm is.
87

Az IPv6 esetn a tbbes klds cmeinek az ff00::/ 8 tartomny van fenntart-
va. Ebben az esetben is szmos elre definlt csoport van.
88

6.12. tblzat. Elredefinilt IPv6-os multicastcsoportok
A tbbes klds fogadsa elre definilt csoportoknl nem ignyel plusz m-
veletet. Ha azonban dinamikusan ltrehozott csoportot szeretnnk hasznlni,
akkor a socketnket hozz kell rendelnnk a kivlasztott csoporthoz. Ezt a
setsockopt0 fggvnnyel (bvebben lsd a 6.6. Socketbelltsok alfejezetben)
vgezhetjk el:
#include<sy s/sock et,h
intsetsock opt(intsock fd,intlev el,int optname,
const void *optval, socklen_t optlen);
A fggvny igen sok funkcit valst meg. Tbbes kldsnl az els paramter
a socketler, a level IPv4 esetn IPPROTOJP, IPv6 esetn IPPROTOJPV6.
Az optname argumentum rtkeit IPv4 esetn a 6.13. tblzat foglalja ssze.
6.13. tblzat. /P1)4-es multicastbelltsok
Opci neve Lers
1P_MULTICAST LOOP Ezzel tilthatjuk/engedlyezhetjk azt, hogy az elkldtt
multicast zeneteket mi is megkapjuk.
" A teljes listt a http:/ /www.iana.org /assignments/ multicast-addresses/multicast-addresses.
txt cmen tallhatjuk meg.
88 A teljes listt a http:/ / www.iana.org / assignments/ipv6-multicast-addresses / ipv6-multi-
cast-addresses.xml cmen rhetjk el.
32 1
6. fejezet: Hlzati kommunikci
Opci neve Leirs
IP MULTICAST TTL Ezzel llthatjuk a time-to-live (TTL) mezt.
IP MULTICAST 1F Itt adhatjuk meg, hogy melyik hlzati interfszrl
kldjk a csomagokat. A rendszer-adminisztrtor alap-
rtelmezsben megad egyet, de fellrhatjuk.
IP ADD_MEMBERSHIP Csatlakozs egy csoporthoz.
IP DROP MEMBERSH1P Kivls egy csoportbl.
IPv6 esetn az albbi opcikat hasznlhatjuk:
6.1 4. tblzat. IPv6-os multicastbelltsok
Opci neve Lers
IPV6 MULTICAST LOOP Ezzel tilthatjuk/engedlyezhetjk azt, hogy az elkldtt
multicast zeneteket mi is megkapjuk.
IPV6 MULTICAST HOPS Ezzel llthatjuk a hop limit mezt.
IPV6 MULTICAST IF Itt adhatjuk meg, hogy melyik hlzati interfszrl
kldjk a csomagokat. A rendszer-adminisztrtor alap-
rtelmezsben megad egyet, de fellrhatjuk.
IPV6_JOIN GROUP Csatlakozs egy csoporthoz.
IPV6 LEAVE GROUP Kivls egy csoportbl.
Nzznk pldt a fontosabb funkcikra. Ha szeretnnk vagy nem szeretnnk
visszakapni az elkldtt csomagokat, akkor a kvetkezkppen engedlyez-
hetjk vagy tilthatjuk le:
i_charloop;
loop=1;/*Tiltas:loop=0; */
"1~
setsock opt(sock et,IP P ROTO_IP ,IP _MULTICAST_LOOP ,&loop,
sizeof(loop));
Az IP-csomag fejlcben elhelyezked TTL- (Time-To-Live, letbenmaradsi
id) rtk minden tvlasztn val thaladskor eggyel cskken, s ha elri a
0 rtket, az tvlaszt eldobja a csomagot. Ez meggtolja, hogy a csomagok
az idk vgtelensgig keringjenek a hlzaton. Tbbes klds esetn ez a
mez egy msik szerepet is betlt: minden egyes tvlaszt-interfszhez egy
kszbszm (threshold) van rendelve, amellyel a tbbeskldtt csomagban
szerepl rtket ssze kell hasonltani, s csak akkor lehet a csomagot to-
vbbengedni, ha a TTL-rtk nagyobb, mint a kszbszm. A 6.15. tblzat-
ban talljuk a gyakorlatban alkalmazott kszbszmokat:
3 2 2
6.5.IP
6.15. tblzat. T7'L- rtkek
TTL-rtk rvnyessg
0 Csak ugyanarra a hosztra mehet el a csomag. Nem lesz tovbbkldve
egyetlen interfszen sem.
1 Csak ugyanazon az alhlzaton kapjk meg. Egy tvlaszt sem
tovbbtja.
< 2 55 Az egsz internet megkapja.
A csomag TTL-rtkt az albbi kdrszlet mintjra llthatjuk be:
u_charttl;/70-2 55-igv ehetfelertek et
ttl-1;
setsock opt(sock et, IPPROTO_IP, IP_MULTICAST_TTL, &ttl,
sizeof(ttl));
Ha nem lltjuk be a TTL-mezt, az alaprtelmezett rtk 1, s ez megakad-
lyozza, hogy a csomag kikerljn az alhlzatbl.
Ha egy csoporthoz csatlakozni akarunk, IPv4 esetn az albbi struktrt
kell kitltennk:
structip_mreq
structin_addrimr_multiaddr; /* A csoportIP cime*/
structin_addrimr_interface; /* A lok alis IP cim */
1;
IPv6 esetn a struktra a kvetkez:
structipv 6_mreq
structin6_addr'ipv 6mr_multiaddr;/*A csoport I P cime*/
unsignedintipv 6mr_ nterface; /* A lok alisinterf sz */
;
A korbbi UDP-fogad pldaprogram kibvtett vltozatn mutatjuk be a cso-
portcmek hasznlatt:
#include<stdio.h>
#include<stdlib.h>
#include<unistd.h>
#include<string.h>
#include<sy s/sock et.h>
#include<netinet/in.h>
#include<netdh.h>
#include<arpa/inet.h>
3 2 3
6. fejezet: Hlzati kommunikci
#define PO RT "112 2 "
intmain()
{
structaddrinfohints;
structaddrinfo*res;
nterr;
structsock addr_in6addr;
sock len_taddrlen;
charips[Ni_mAxHOST]:
charserv s[NI_MAXSERV];
intsock ;
charbuf[2 56];
intlen;
structip_mreqmreq;
structipv 6_mreqmreq6;
memset(&hints,0,sizeof(hints));
hints.ai_flags=AI_P ASSIVE;
hints.ai_family =AF_INET6;
hints.ai_sock ty pe=SOCK_DGRAM;
err=getaddrinfo(NULL,P ORT,&hints,&res);
if(err!=0)
{
fprintf(stderr,"getaddrinfo:%s\n",gai_strerror(err))
return-1;
}
if(res==NULL)
{
return-1;
sock =sock et(res->ai_family ,res->ai_sock ty pe,
res->ai_protocol);
if(sock <0)
{
perror("sock et");
return1;
if(bind(sock ,res->ai_addr,res->ai_addrlen)<0)
{
perror("bind");
return1;
freeaddrinfo(res);
memset(&mreq,0,sizeof(mreq));
inet_pton(AF_INET,"2 2 4.1.1.1",&mreq.imr_multiaddr);
324
6.5. IP
if(setsockopt(sock, IPPROTO_IP, IP_ADD_MEMBERSHIP, &mreq,
sizeof(mreq)) ! = 0 )
perror("IP_ADO_MEMBERSHIP");
return -1;
M
I
memset(&mreq6, 0, sizeof(mreq6));
net_pton(AF_INET6, "ff02 : :13D" , &mreq6, pv6mr_mul ti add r) ;
i f(setsockopt(sock, IPPROTO_IPv6, IPV6_JOIN_GROUP, &mreq6,
sizeof(mreq6)) ! = 0 )
perror("IPV6_JOIN_GROUP");
return -1;
}
addrlen = sizeof(addr);
while((len = recvfrom(sock, buf, sizeof(buf), 0,
(strucc sockaddr*)&addr, &addrlen)) > 0)
i f(getnameinfo((struct sockaddr*)&addr, addrlen,
ips, sizeof(ips), servs, sizeof(servs), 0) == 0)
{
fprintf(stdout, "%s:%s: ", ips, servs);
fflush(stdout);
1
write(STDOUT_FILENO, buf, len);
close(sock);
return 0;
A szolgltatsunkat hozzrendeljk a 2 2 4 .1.1.1 IPv4 -es s az f'f()2 ::13D IPv6-os
csoportcmekhez. Ha lefuttatjuk a mdostott fogadprogramot, akkor a ko-
rbbi kldprogrammal tesztelhetjk.
Feladat Teszteljk a mdostott UDP-fogad programot gy, hogy a kldprogramnl a kvet-
kez cmeket hasznljuk: 224.1.1.1, ff02::13D, ff02::1.
325
6. fejezet: Hlzati kommunikci
6.6. Socketbelltsok
A socketbelltsokkal a socket mkdsnek szmos jellemzjt tudjuk m-
dostani. Egy-egy socketmvelet sorn tbb protokollszintet is hasznlunk
egyszerre. Egy TCP-kommunikci sorn pldul hasznljuk a TCP-, az IP-
s a socketszintet. Az egyes szinteken klnbz opcikat tudunk belltani
s ezzel hangolni a kommunikcit.
A belltsokat a getsockoptQ rendszerhvssal krdezhetjk le, s a set-
sockoptO rendszerhvssal mdosthatjuk:
#include<sy s/sock et.h>
intgetsock opt(intsock fd,intlev el,intoptname,
v oid*optv al,sock len_t*optlen);
intsetsock opt(intsock fd,intlev el,intoptname,
const v oid*optv al, socklen_t optlen);
Az els paramter a socket lerja. Ezzel hivatkozunk arra a socketre, amely-
nek a belltsait mdostani szeretnnk. A level paramterrel adjuk meg,
hogy melyik protokollszinthez tartozik az a bellts, amelyet kezelni szeret-
nnk. A 6.16. tblzatban sszefoglaljuk a tipikusan hasznlt rtkeket.
6.16. tblzat. IP protokoll szintek
rtk Szint man" oldal
SOL_SOCKNT socket s egyben Unix socket(7), unix(7)
1PPROTO_IP IPv4 ip(7)
rPPROTO IP6 IPv6 ipv6(7)
IPPROTO_TCP TCP tcp(7)
1PPROTO_UDP UDP udp(7)
Az optname paramterben adjuk meg a kivlasztott opcit. A lehetsges bel-
ltsok a protokollszinttl fggenek. Az elz tblzat utols oszlopban meg-
adtuk az adott szintet ler man" oldal nevt. Ezek a lersok tartalmazzk a
teljes belltslistt.
Az optval paramter tartalmazza a bellts rtkt, mg az optlen a vl-
toz mrett. Az rtk tpusa fgg a belltstl, s az elbb emltett lersok
tartalmazzk.
Az albbiakban kiemelnk nhny gyakrabban hasznlt belltst. A tb-
bes klds belltsaira nem trnk ki (ezeket lsd a 6.5.13.2. Tbbes klds al-
fejezetben).
326
6.6. Socketbelltsok
SO_KEEPALIVE
A socketszint tartalmazza. Kapcsolatalap socket esetn
.
n. letben tart
(keep-alive) zeneteket kld. Ennek segtsgvel abban az esetben is rzkel-
hetjk a kommunikcis hibt, ha egybknt hosszan nem forgalmazunk
adatot. Az rtk tpusa integer. 0 s 1 rtkkel kapcsolhatjuk ki, illetve be.
SO_REUSEADDR
A socketszint tartalmazza. A bindo rendszerhvs szmra jelzi, hogy a lok-
lis portot jra felhasznlhatja, ha ppen nincs aktv socket az adott porton.
Az rtk tpusa integer. 0 s 1 rtkkel kapcsolhatjuk ki, illetve be.
tmutat Ahogy a korbbi pldinkban is lthat volt, ennek a belltsnak a hasznlata igen
gyakori. Ha nem hasznlnnk, akkor a folyamat lelltst kveten nem lehetne az alkalma-
zst azonnal jraindtani, mert ekkor a bind() mvelet hibval trne vissza. Azt jelezn, hogy
a portot mr msik folyamat hasznlja. Ekkor ki kell vrnunk egy bizonyos idt, amg a port j-
ra hasznlhatv vlik. A SO_REUSEADDR bellts hasznlatval viszont a port azonnal jra-
hasznosthat, ha lezrtuk a szerversocketet.
TCP_CORK, UDP_CORK
A TCP-, illetve az LTDP-rteg tartalmazza ket. Ha belltjuk ezt az opcit,
akkor a sendO, illetve a sendto0 fggvnyek meghvsakor nem kldi el
azonnal a csomagokat, hanem egy vrakozsi sorban gyjtgeti ket. Ezt k-
veten az opci kikapcsolsakor az adatok kikldse egy csomagban trtnik.
Az rtk tpusa integer, s 0/1 rtkekkel kapcsolhatjuk ki s be az opcit.
Ezek a belltsok nem hordozhatk, csak Linux rendszereken mkdnek.
Az albbi pldban a korbbi UDP-kld program mdostsval de-
monstrljuk a bellts mkdst:
#include <stclio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <sys/socket.h>
#include <netinet/in.h>
#nclude <netinet/udp.h>
#include <arpa/inet.h>
#include <netdb.h>


#define PORT "1122"
#define SAYS "Simon mondja: "
int main(int argc, char* argv[])
struct addrinfo hints;
struct addrinfo* res;
nt err;
BEI
327
6. fejezet: Hlzati kommunikci
intsock ;
charbuf[102 4];
intlen;
intstate;
i f(argc!=2 )
printf("Haszn lat:%s<szerv er>\n",argv [0]);
return1;
memset(&hints,0,sizeof(hints));
hints.ai_family =AF_UNSP EC;
h nts.ai_sock ty pe=SOCK_DGRAM;
err=getaddrinfo(argv [1],P ORT,&h nts,&res);

if(err!=0)
{
fprintf(stderr,"getaddrinfo:%s\n",gai_strerror(err));
return-1;
}
if(res==NULL)
{
return-1;
sock =sock et(res->ai_family ,res->ai_sock ty pe,
res->ai_protocol);
i f(sock <0)
{
perror("sock et");
return-1;
}
state=1;
setsock opt(sock ,IP P ROTO_UDP ,UDP _CORK,&state,sizeof(state));
while((len=read(STDIN_FTLENO,buf,sizeof(buf)))>0)
{
sendto(sock ,buf,len,0,res->ai_addr,res->ai_addrlen);
}
freeaddrinfo(res);
state=0;
setsock opt(sock ,IP P ROTO_UDP ,UDP _CORK,&state,sizeof(state));
close(sock ):
return0;
3 2 8
6.6. Socketbelltsok
Fordtsuk le s prbljuk ki a programot. Azt tapasztaljuk, hogy a bert sz-
veget nem soronknt kldi el a fogadnak, hanem egyben, egy csomagban.
A gyakorlatban finomabban tudjuk szablyozni a csomagok sszevonst
a sendO, illetve a sendto() rendszerhvs MSG_MORE opcijval. Ilyenkor az
MSG MORE opcival kldtt adatok belekerlnek a vrakozsi sorba, majd a
soron kvetkez MSG_MORE opci nlkli hvs sorn az adatok kikldse
egyben trtnik meg. Ennek mkdst a kvetkez pldaprogram mutatja be:
#include <stdio.h>
#include <stdlb.h>
#include <unistd.h>
#include <stri ng h>
#include <sys/socket.h>
#include <net net/i n h>
# nclude <arpa/inet.h>
#include <netdb.h>
#define P ORT"1122"
#define SAYS "Simon mondja: "
int main(int argc, char* argv[])
struct addrinfo hints;
struct addrinfo* res;
int err;
int sock;
char buf[1024];
int len;
if(argc !=2)
{
printf("Hasznlat: %s <szerver>\n", argv[0]);
return 1;
}
memset(&hints, 0, sizeof(hints));
hints.ai_famly =AF_UNSP EC;
hints,ai_socktype =SOCK_DGRAM;
err =getaddrinfo(argv[1], PO RT, &hints, &res);
if(err !=0)
{
fprintf(stderr, "getaddrinfo: %s\n", gai_strerror(err));
return -1;
if(res ==NULL)
t
return -1;
sock =socket(res->ai_family, res->a_socktype,
res->ai_protocol);
329
6. fejezet: Hlzati kommunikci
i f(sock < 0)
perror("socket");
return -1;
while((len = read(STDIN_FILENO, buf, sizeof(buf))) > 0)
{
sendto(sock, SAYS, strlen(SAYS), MSG_MORE,
res->ai_addr, res->ai_addrlen);
sendto(sock, buf, len, 0, res->ai_addr, res->ai_addrlen);
freeaddrinfo(res);
cl ose(sock) ;
return 0;
Ha a programot kiprbljuk, akkor azt tapasztalhatjuk, hogy a kt
sendto0
hvs adatai egyben, egy csomagban klddnek ki.
6.7. Segdprogramok
A hlzati kommunikci implementlsakor belefuthatunk hibkba, amikor
a kommunikci valamirt nem tud felplni a programjaink kztt. Ilyenkor
segdprogramok segthetnek kiderteni, hogy meddig jutottunk el a kapcsolat
felptsben.
Az egyik legfontosabb program a netstat, amely szmos informcit kir a
hlzati alrendszerrl. Paramterek nlkl kirja az ppen l hlzati kap-
csolatokat. A -a paramterrel a lista kiegszl a szerver- s az UDP-socketek-
kel. A -t s a -u opcival kiegsztve a listt leszkthetjk a TCP-, illetve
UDP-socketekre. Emellett a -n opcival kikapcsolhatjuk a nvfeloldst, s
mindent numerikusan lthatunk
A netstat a forgalmazott csomagokrl nem ad informcit, m a tcpdump
program igen. Segtsgvel monitorozhatjuk a hlzati csomagforgalmat, s
alacsony szinten megnzhetjk, hogy a programunk tnyleg kld-e vagy kap-
e csomagokat.
A tcpdump program szveges interfsze miatt nagyobb forgalom esetn
nehezen kezelhet. m a feladatra ltezik egy grafikus felhasznli fellettel
rendelkez program, a wireshark.
89
A grafikus fellet nagyban segti a prog-
ram hasznlatt s az adatok rtelmezst.
89
A Wireshark program weboldala: http://www.wireshark.org/.
330
-
-
.11 II
Frame 1, 42 bytes un wtre (336 birs), 42 bytes captured ( 336 blts)
Ethernet II. Src: Hewlett. fS:de:la ( 68:b5:99:f3:de: la), 0st: Broadcast ( ff:ff:ff:ff:ff:ff)
6.8. Tvoli eljrshvs
C4r8.uril8Frer8 wON0(.3
,
p
,
rdr,,,t 147 66 188 111 rWcres'neri: 1671
, Q.7 ,Caoture mkae Tele.$.71lt Jpols Irccm,lls he(:.
'
a a a ZT ITU J i ts "
8488388:0
,

0>sbnac

e
,
Lenath
1 0.000000 Hetimtett-_f3:de:ta Broadcast ARP 42 who has 152.66.188.11?
2 0.000514 tlicrosof_fb. ld: f Hewlett - t3 de la ARP 65 I52.66 188.11 is a1 00:15
6.5. bra. A Wireshark fablaka
A Wireshark program fellett a 6.5. bra mutatja. A program fablaka h-
rom rszre tagoldik. A fels rszben egy listt tallhatunk, amely az elkapott
csomagokat tartalmazza. Ha ebbl a listbl kivlasztunk egy csomagot, ak-
kor az als rszben lthatjuk a binris tartalmt, mg a kzps rsz ezt r-
telmezett formban mutatja. A vizsgldsaink sorn elssorban a kzps
rszt hasznljuk.
A kzps mez a kivlasztott csomag ltal tartalmazott keretek listjt
mutatja. Ahogy a csomag az egyes hlzati rtegeken keresztl haladva fel-
pl, minden rteg egy j keretet alkot belle. Minden keret rendelkezik n-
hny fejlcmezvel s egy adatrsszel. A lista elemeit lenyitva a fejlcmezk
tartalmt tekinthetjk meg.
6.8. Tvoli eljrshvs
A tvoli eljrshvs (Remote Procedure Call, RPC) egy magas szint
kommunikcis paradigma. Lehetv teszi tvoli gpeken lv eljrsok
meghvst, mikzben elrejti a felhasznl ell az alsbb hlzati rtegeket.
Az RPC logikai kliens-szerver modellt valst meg. A kliens szolgltatsi
ignyeket kld a kiszolglnak. A szerver fogadja az ignyeket, vgrehajtja a
krt funkcit, vlaszt kld, majd visszaadja a vezrlst a kliensnek.
331
6. fejezet: Hlzati kommunikci
Az RPC megkmli a felhasznlt az alsbb hlzati rtegek ismerettl s
programozstl. A hvsok transzparensek. A hvnak explicite nincs tudom-
sa az RPC-rl, a tvoli eljrsokat ugyangy hvja, mint egy helyi eljrst.
6.8.1. Az RPC-modell
A tvoli eljrshvs modellje hasonlt a helyi eljrshvs modelljre. A helyi
eljrs hvja a hvs argumentumait egy jl meghatrozott helyre teszi,
majd tadja a vezrlst az eljrsnak. A hvs eredmnyt a hv egy jl
meghatrozott helyrl elveszi, s tovbb fut. Tvoli eljrshvs esetn a vg-
rehajtsi szl kt folyamaton (kliens s szerver) halad keresztl. A hv zene-
tet kld a szervernek, majd vlaszra vr. A hv zenete tartalmazza a hvs
paramtereit, a vlaszzenet pedig az eljrs eredmnyt. A kliens kiveszi a
vlaszzenetbl az eredmnyt, s tovbb fut.
A gp
Kliensprogram
B gp
Szerverdmon
RPC-hvs
Szolgltats
meghvsa
17
Szolgltats
vgrehajtsa
Szolgaltats
ksz
Program
folytatdik
6.6. bra. RPC-kommunikci
A szerveroldalon egy vrakoz alv processz vrja a hvk zeneteit.
Az rkez zenetbl kiveszi az eljrs paramtereit, elvgzi a feladatot, majd
visszakldi a vlaszzenetet. A kt processz kzl egy idben csak az egyik
aktv, a msik vrakoz llapotban van.
6.8.2. Verzik s szmok
Minden RPC-eljrst egyrtelmen meghatroz egy programszm s egy elj-
rsszm. A programszm az eljrsok egy csoportjt jelli. A csoporton bell
minden eljrsnak egyedi eljrsszma van. Ezen kvl minden programnak
van verziszma is. gy a szolgltatsok bvtse vagy vltoztatsa esetn
Vlasz
332
6.8. Tvoli eljrshvs
nem kell j programszmot adni, csak a verziszmot nvelni. A programsz-
mok egy rsze elredefinilt, ms rszk fenntartott. A fejlesztk szmra a
0x2 0000000-0x3fffffff tartomny ll rendelkezsre.
6.8.3. Portmap
Minden hlzati szolgltatshoz dinamikusan vagy statikusan hozz lehet
rendelni portszmot. Ezeket a szmokat regisztrltatni kell a gpen fut
portmap dmonnal. Ha egy hlzati szolgltats portszmra van szksg,
akkor a kliens egy RPC-kr zenetet kld a tvoli gpen fut portmap d-
monnak. A portmap RPC-vlaszzenetben megadja a krt portszmot. Ezu-
tn a kliens mr kzvetlenl kldhet zenetet a megadott portra. A fentiek-
bl kvetkezik, hogy a portmap az egyetlen olyan hlzati szolgltats,
amelynek mindenki ltal ismert, dediklt portszmmal kell rendelkeznie. Je-
len esetben ez a portszm a 111.
6.8.4. Szllts
Az RPC fggetlen a szlltsi protokolltl. Nem foglalkozik azzal, hogy miknt
addik t az zenet az egyik processztl a msiknak. Csak az zenetek specifi-
kcijval s rtelmezsvel foglalkozik. Ugyancsak nem foglalkozik a megbz-
hatsgi kvetelmnyek kielgtsvel. Ez egy megbzhat szlltsi rteg
- pldul az sszekttets-alap TCP - felett kevsb okoz gondot. Egy kevsb
megbzhat szlltsi rteg - pldul UDP - felett fut RPC-alkalmazsnak
magnak kell gondoskodnia azonban az zenetek megbzhat tovbbtsrl.
Linux alatt az RPC tmogatja mind az UDP-, mind a TCP-szlltsi rte-
get. Az egyszersg kedvrt a TCP-t ajnlatos hasznlni.
6.8.5. XDR
Az RPC felttelezi az n. kls adatbrzols (eXternal Data Representation,
XDR) megltt. Az XDR gpfggetlen adatler s kdol nyelv, amely jl
hasznlhat klnbz szmtgp-architektrk kztti adattvitelnl.
Az RPC tetszleges adatstruktrk kezelsre kpes, fggetlenl az egyes
gpek bels adatbrzolstl. Az adatokat elklds eltt XDR-formra ala-
ktja (serializing), a vett adatokat pedig visszaalaktja (deserializing).
333
6. fejezet: Hlzati kommunikci
6.8.6. rpcinfo
Az rpcinfo parancs hasznlatval informcikat krhetnk a portmap d-
monnl bejegyzett programokrl: program neve, szma, verzija, portszma,
a hasznlt szlltsi rteg. Ezen kvl meg lehet vele krdezni, hogy egy prog-
ram adott verzija ltezik-e, illetve vlaszol-e a krsekre.
A loklis gpre az informcik lekrdezse a kvetkez:
6.8.7. rpcgen
A tvoli hvst hasznl alkalmazsok programozsa nehzkes s bonyolult
lehet. Az egyik nehzsget ppen az adatok konverzija jelenti. Szerencsre
ltezik egy rpcgen nev program, amely segti a programozt az RPC-alkal-
mazs elksztsben.
Az rpcgen egy fordt. Az RPC-program interfsznek defincijt az el-
jrsok nevt, az tadott s visszaadott paramterek tpust az gynevezett
RPC nyelven kell lerni. A nyelv hasonlt a C-re. A fordt az interfszdefinci
alapjn nhny C nyelv forrslistt llt el: a kzsen hasznlt defincikat
(headerfjlt), a kliens- s a szerveroldali RPC-programok vzt (skeleton).
A vzak feladata az, hogy elrejtsk az alsbb hlzati rtegeket a program
tbbi rsztl.
A programfejlesztnek mindssze az a feladata, hogy megrja a szerverol-
dali eljrsokat. Az eljrsok tetszleges nyelven megrhatk, figyelembe v-
ve termszetesen az interfszdefincit s a rendszerhvsi konvencikat.
Az eljrsokat sszeszerkesztve a szerveroldali vzzal, megkapjuk a futtatha-
t szerveroldali programot.
A kliensoldalon a fprogramot kell megrni, ebbl hvjuk a tvoli eljrsokat.
Ezt linkelve a kliensoldali vzzal, megkapjuk a futtathat kliensprogramot.
Az rpcgen-nek ltezik egy a kapcsolja is, amely tovbb egyszersti a
feladatunkat Hasznlatval az interfszllomnybl mg a megrand prog-
ramrszekre is kapunk egy C nyelv vzat, amelyet mr csak ki kell egsz-
tennk, hogy hasznlhassuk. (gyeljnk arra, hogy egy ismtelt generlssal
a C-vzak fellrdnak, ezrt clszer tneveznnk ket.)
gy ltalban a kvetkez parancsot hasznljuk:
-rpoOr-41
,
-Irltferfa
~.
ahol az interface.x az interfszllomny.
334
1
6.8. Tvoli eljrshvs
6.8.8. Helyi eljrs talaktsa tvoli eljrss
Tegyk fel, hogy van egy eljrsunk, amely loklisan fut. Ezt az eljrst sze-
retnnk tvoliv tenni. Az talaktst egy egyszer pldn vizsgljuk meg.
A loklis program a hvskor megadott paramtert, mint zenetet, kirja a
kpernyre. A cl az, hogy tvoli gp kpernyjre is tudjunk zenetet kirni.
A program loklis vltozata a kvetkez:
/*printmsg.c-uzenetk iirasaak eperny ore.*/
#include<stdio.h>
intprintmessage(char*msg)

printf("%s\n",msg);
return1;
intmain(intargc,char*argv [])
{
char*message;
i f(argc!=2 )
t
fprintf(stderr,"Hasznalat:%s<uzenet>\n",argv [0]);
return-1;
message=argv [1];
tf(!printmessage(message))
fprintf(stderr,"%s:nemmegj elenithetoazuzenet.\n",
argv [0]);
return-1;
}
printf("Azuzenetelk uldv e!\n");
return0;
A protokoll kialaktshoz szksg vannak annak ismeretre, hogy az elj-
rsnak milyen tpus paramterei s visszatrsi rtkei vannak. Jelen eset-
ben a printmessage0 fggvny szveget vesz t paramterknt, s egy egsz
szmot ad vissza. A protokollt hagyomnyosan egy .x kiterjeszts llomny-
ban rjuk meg:
/*msg.)(-Tav ol uzenetny omtatasprotok ollj a.''/
programMESSAGEP ROG /*programnev */
v ersionMESSAGEVERS{ /*v erzionev */
intP RINTMESSAGE(string)=1; /*1.fuggv eny */
} =1; /*v erzioszam*/
} =0x2 0000099; /*programszam*/
335
6.fej ezet:Hlzati kommunikci
A tvoli program egyetlen eljrst tartalmaz, amelynek szma 1. Az RPC auto-
matikusan generl egy O. eljrst is. Ez a szerver megszltsra (pinging)
hasznlhat A nagybetk hasznlata nem szksges, csak hasznos konvenci.
szrevehet, hogy az argumentum tpusa nem char*, hanem string. Ez
azrt van, mert a klnbz nyelvek msknt rtelmezik a szveges tpust,
st a char* mg a C nyelvben sem egyrtelm. A hasznlhat vltoztpuso-
kat az XDR dokumentcija tartalmazza.
Nzzk a tvoli eljrs implementcijt:
/* msg_proc.c - Tavoli printmessage eljaras. */
#include <stdio.h>
#include <rpc/rpc.h>
#include "msg.h"
int* printmessage_1(char** msg)
f
static int result;
printf("%s\n", *msg);
result =1;
return (&result);
A printmessage_10 tvoli eljrs hrom dologban klnbzik a printmessage()
helyi eljrstl.
Argumentumknt stringre mutat pointert vesz t string helyett. Ez min-
den tvoli eljrsra rvnyes. Ha nincs argumentum, akkor void*-ot kell
megadni.
Vissza egsz szmra mutat pointert ad, egsz helyett. Ez szintn jellemz
a tvoli eljrsokra. A pointer-visszaads miatt kell a result vltozt staticknt
megadni. Ha nincs visszatrsi rtk, akkor void*-ot kell hasznlni.
A tvoli eljrs nevnek a vgre _1" kerlt. ltalban az rpcgen ltal
generlt eljrsok neve a protokolldefinciban szerepl nv kisbetkkel, egy
alhzsi karakter, vgl pedig a verziszm.
Vgl kvetkezzen a kliensprogram, amely a tvoli eljrst meghvja:
/* rprintmsg.c - A printmsg.c tavoli verzioja. */
#include <stdo.h>
#include <rpc/rpc.h>
#include "msg.h"
nt man(int argc, char* argv[])
{
CLIENT* cl;
int* result;
char* server;
char* message;
336
6.8. Tvoli eljrshvs
i f(argc ! = 3)
{
fprintf(stderr,"Hasznalat:%s.szerv er><uzenet>\n",
argv [0]);
return-1;
serv er=argv [1];
message=argv [2 ];
/* A k liensleiroletrehozasa,k apcsolatfelv etelea
szerv errel.
-
V
cl=clnt_create(serv er, MESSAGEPROG, MESSAGEVERS,
"tcp");
if(c1 == NULL)
{
clnt_pereateerror(serv er);
return-1;
}
7* A tav olielj arasmeghiv asa.*/
result=printmessage_1(&message,cl);
if(*result==NULL)
{
clnt_perror(cl,"callfailed");
return-1;
}
if(result==0)
f
fprintf(stderr,"%s:%snemmegj elenithetoazuzenet\n",
argv [0],serv er);
return-1;
printf("Azuzenetelk uldv ea%sszerv ernek !\n",serv er);
return0;
Els lpsknt a kapcsolatot hozzuk ltre a clnecreate0 meghvsval. A vissza-
kapott lert a tvoli eljrs argumentumaknt hasznljuk. A cInt_create0 utol-
s paramtere a szlltsi protokollt adja meg. Jelen esetben ez TCP, de lehet
UDP is.
A printmessage_1O eljrs meghvsa pontosan ugyangy trtnik, ahogy
azt az msg_proc.c llomnyban deklarltuk, de itt utols paramterknt meg
kell adni a kliens-kapcsolatazonostt is.
A tvoli eljrshvs ktfle mdon trhet vissza hibval. Ha maga az
RPC-hvs nem sikerlt, akkor a visszatrsi rtk NULL. Ha a tvoli eljrs
vgrehajtsa kzben kvetkezik be hiba, akkor az alkalmazstl fgg a hiba-
jelzs. Esetnkben a 0 visszatrsi rtk mutatja a hibt.
3 3 7
6. fejezet: Hlzati kommunikci
A kiegsztend kdvzat (skeleton) tartalmaz llomnyokat az
r> 00:1 1 1 ~
x
paranccsal generlhatjuk. Ez a kvetkez llomnyokat hozza ltre:
Egy msg.h headerllomnyt, amelyben definilja a MESSAGEPROG,
MESSAGEVERS s PRINTMESSAGE konstansokat, tovbb a fgg-
vnyeket kliens- s szerveroldali formban is.
A kliensprogram vzt az msg_clnt.c llomnyban. Ebben szerepel a
printmessage_1() eljrs, amelyet a kliensprogram hv.
A kiszolglprogram vzt az msg_suc.c llomnyban. Ez a program
hvja az msgproc.c llomnyban tallhat printmessage_10 eljrst.
Az rpcgen a a kapcsol hasznlatakor ezek mellett a kliens- s a szerver-
program egyszer implementcijt s a makefile-t is ltrehozza. (Vigyzzunk
a make clean hasznlatval, mert itt a szoksos megvalstssal szemben a
generlt kliens- s szerverprogram forrst is letrli.)
338
HETEDIKFEJEZET
Fejleszts a Linux-
kernelben
Az opercis rendszer egyik feladata az, hogy egy egysges, magas szint prog-
ramozsi felletet nyjtva elrejtse a felhasznl ell a rendszer hardverelemei-
nek a kezelst. Az llomnykezels sorn pldul nem kell foglalkoznunk a
konkrt troleszkz kzvetlen vezrlsvel, mivel az opercis rendszer meg-
teszi ezt helyettnk.
Ha a fejlesztk belemerlnek a Linux-kernelbe, annak az az egyik leg-
gyakoribb oka, hogy specilis eszkzeikhez meghajtprogramot szeretnnek k-
szteni. Ilyenkor az a feladat, hogy az eszkz alacsony szint interfszre ptve
megvalstsk az opercis rendszer magas szint interfszt. A Unix vilg-
ban az eszkzket llomnyknt, az gynevezett fjlabsztrakcis interfszen
kezeljk (lsd a 2.1. A Linux-kernel felptse alfejezetben). Ez a Linux-meg-
hajtprogram esetben azt jelenti, hogy az eszkz kezelst llomnymvele-
tekre kell lekpeznnk.
9
A Linuxnl ez a feladat sok esetben nem is olyan
nehz, m komoly odafigyelst ignyel, mivel a kernel a rendszer rzkeny
rsze: egy elrontott kd ezen a helyen a rendszer sszeomlst is eredm-
nyezheti.
Termszetesen az eszkzk sklja, gy az eszkzvezrlk is, elg szles.
Radsul a kernel kapcsold fggvnyeit gyakran vltjk fel j verzik.
Ezrt ebben a fejezetben tfog bevezetst nyjtunk a leggyakrabban hasz-
nlt technikkba, fknt a kevss vltoz alapelvek ismertetsre s azok il-
lusztrlsra szortkozunk, mintegy kiindulsi alapknt azok szmra, akik
ebben a tmban szeretnnek elmlyedni.
Linux alatt az eszkzvezrlket kernelmodulknt valstjuk meg. A ker-
nelmodul a betlts utn hozzkapcsoldik a kernelhez, s annak szerves r-
szt alkotja. gy lnyegben a kernelmodul-fejleszts Linux-kernel-fejlesztst
jelent.
9
A Linuxban nem minden meghajt rendelkezik llomnyinterfsszel, m a tbbsg igen.
7. fejezet: Fejleszts a Linux-kernelben
7.1. Verzifggsg
A kernel a Linux egyik legdinamikusabban fejld rsze. Ebbl kvetkezen a
verzivltsok sorn gyakran kerlnek bele strukturlis s szintaktikai vlto-
zsok. A 2 .4 -es stabil kernel verzirl a 2 .6-os stabil verzira trtn vlts a
modulok jelents trst tette szksgess, mert a kt kernelverzi kztti k-
lnbsgek jelentsek voltak. A 2 .6-os verzitl kezdden a kernel fejlesztsi
ciklusa megvltozott. Megsznt a stabil mellett prhuzamosan megjelen fej-
leszti kernelvltozat, gy a vltozsok kzvetlenl a kernel egyetlen fejlesztsi
vonalba kerltek. Ennek egyik hatsa az, hogy szinte folyamatosan kisebb t-
alaktsokat kell vgeznnk a moduljainkon. Termszetesen, ha kt egymstl
szmozsban tvolabb es 2 .6.X-es kernelverzi kztt vltunk, akkor a kis
mdostsok szma is megnvekszik. Ugyanakkor nem jellemz olyan draszti-
kus nagy talakts, mint a korbban emltett 2 .4 ---> 2 .6 vlts esetben. Ebbl
is kvetkezik, hogy a kernel f verziszmai rgta nem is vltoztak.
9
' A nem-
rg megjelent 3.0-s kernel verziszma is valjban csak szimbolikus, s nem
tartalmaz jelents eltrseket a 2 .6.39-es verzihoz kpest.
A folyamatos fejlds tkrben fontos felhvni a figyelmet arra, hogy az
ebben a fejezetben tallhat forrskdok a knyv rskor aktulis 2 .6.39-es
kernelverzihoz kszltek. Jllehet ksbbi verzik hasznlatakor elfordul-
hat, hogy a szintaktika egyes pontokon eltr, m a kd mgtt ll alapelvek
lassabban vltoznak, gy remnyeink szerint a fejezet a ksbbi kernelverzi-
knl is aktulis marad.
A kisebb szintaktikai mdostsokat ltalban a fordtskor kapott hiba-
jelzsek alapjn rgtn szrevesszk. Ilyenkor a helyes szintaktika knnyen
felderthet az aktulis kernelforrs tanulmnyozsval. Ha keresnk pld-
ul egy olyan eszkzvezrlt, amely a problms rszletben hasonlt a mi esz-
kzvezrlnkre, akkor innen kiderthetjk, hogy az aktulis kernelverzi ese-
tben mi a helyes szintaktika.
Idnknt a kernelforrs mellett tallhat dokumentcik is segthetnek.
Sajnos a kernel nem tartozik a Linux jl dokumentlt rszei kz, ugyanis a
forrskd fejlesztse ltalban gyorsabb, minthogy a dokumentci kvetni
tudn. Szerencsre az utbbi vekben jelents fejlds tapasztalhat ezen a
tren is: a kernelfejleszt'k egyre inkbb dokumentljk a munkjukat.
91
A 2 .6.0-s kernelverzi 2 003. december 17-n jelent meg. A 2 .6.X-es kernelek korszaka
egszen 2 011. jlius 2 1-ig tartott, amikor Linus Torvalds bejelentette a 3.0-s verzit a Li-
nux-kernel 2 0. szletsnapja alkalmbl.
34 0
7.2. A kernel- s az alkalmazsfejleszts eltrsei
7.2. A kernel- s az alkalmazsfejleszts
eltrsei
Elszr rszleteznnk kell a kernel s az alkalmazsok fejlesztse kzti k-
lnbsgeket. A ksbbi fejezetekben elssorban kernelmodulok fejlesztst
trgyaljuk, m nincs klnbsg a modulknt elksztett s a kernelbe kzvet-
lenl belefordtott kdok kztt a megktsek tekintetben.
Elszr is a kernelrszek ksztsnl lehetleg felejtsnk el ms nyelve-
ket, s dolgozzunk C-ben, esetleg assemblyben.
ltalban az alkalmazsok egy feladaton dolgoznak az indtstl a folya-
mat vgig. Ezrt ezeknek egyetlen belpsi pontjuk van, C nyelv programok
esetn tipikusan a main fggvny. A kernelmodulok letciklusa sokkal jobban
hasonlt a nem statikus programknyvtrakhoz: a programknyvtr rendel-
kezsre llst regisztrlssal adjuk a rendszer tudtra, ettl kezdve arra
vr, hogy egy program betltse s meghvja a szolgltatsait. Hasonlkppen a
kernelmodulok elszr csak regisztrldnak, hogy ksbb feladatokat teljest-
hessenek, s ezzel az inicializl fggvnyk mr vget is r. A modul msik
belpsi pontja a tisztogatfggvny, amely a modul eltvoltsakor aktivizl-
dik, pontosabban kzvetlenl eltte. A modul szolgltatsait kttt prototpus
fggvnyek valstjk meg, amelyeket a programok a kernel kzvettsvel
pldul az llomnyabsztrakcis interfszen keresztl hasznlhatnak. Szek-
vencilisan lefut kdot csak gy implementlhatunk, ha kernelszlat ind-
tunk (lsd a 7.17. Vrakozs alfejezetet).
A programok fejlesztsekor gyakran hasznlunk olyan fggvnyeket,
amelyek fejleszti knyvtrakban vannak. Ilyenkor maga a program nem tar-
talmazza a fggvnyt, hanem a fordtsi fzis utn a linker vagy a betlt-
program a linkelsi fzisban oldja fel ezeket a kls hivatkozsokat. Ilyen
pldul a printf() fggvny, amely a libc knyvtrban tallhat. Ezzel szem-
ben a modulok csak a kernellel linkeldnek, ezrt csak olyan fggvnyeket
hasznlhatnak, amelyek a kernelben (belertve ms modulokat) mr ltez-
nek. Termszetesen a modulok fejlesztsben nem hasznlhatunk semmilyen
libc fggvnyt, hiszen az egy jval magasabb szint, felhasznli zemmd-
ban hasznlatos fggvnyknyvtr. A kernel ltal rendelkezsre bocstott
fggvnyeket a / proc /kallsyms virtulisszveg-llomnyban tudjuk megnz-
ni. Ez csak az ppen aktulis fggvnylistt jelenti meg, amely a modulok
betltsvel s eltvoltsval bvlhet, illetve cskkenhet.
Mivel nem hasznlhatunk fejleszti knyvtrakat, gy a hagyomnyos
headerllomnyok sem szerepelhetnek a kdunkban. Helyettk a kernelforrs
include alknyvtrban tallhat llomnyok kerlnek bele, s errl a kernel-
forrs Makefile-ja gondoskodik azzal, hogy a megfelel elrsi utakat adja meg
a fordtnak. Ebben a knyvtrban tallunk egy linux s egy asm knyvtrat,
amelyek az ltalunk hasznlhat headerllomnyokat tartalmazzk.
341
7. fejezet: Fejleszts a Linux-kernelben
A kernelrszek kdjait s adatait ltalban a fizikai memriban trol-
juk, vagyis nem kerlhetnek ki egy lapcsere folytn a merevlemezre. Hogy
megrtsk ennek az okt, nzznk meg egy pldt. Tegyk fel, hogy a kernel
adatait is olyan virtulismemria-terleten tartjuk, mint az alkalmazsokit.
Ebben az esetben elfordulhat, hogy egyes lapok kikerlnek a lapcsere-
partcira, ha kevs a hely a fizikai memriban. Ha ppen a lapcsere algo-
ritmuskdja vagy adatai kerlnnek ki: tbbet nem lehetne visszatlteni sem
ezt a lapot, sem ms lapokat a rendszerbe.
Termszetesen a fizikai memria vges, ezrt ne szabad elpazarolni. Nagy
mennyisg adathoz kernelfejlesztskor is lehetsgnk van arra, hogy virtu-
lis memrit is allokljunk. Ezekre a terletekre csak adatokat helyezhetnk
el, s szmolnunk kell az esetleges lapcsere okozta lassabb hozzfrssel.
Lebegpontos szmtsokat ne hasznljunk. Ha mgis szksges lenne,
akkor neknk kell gondoskodnunk az FPU llapotnak lementsrl s visz-
szalltsrl.
Az utols nagy eltrs a hibk lekezelsnl tapasztalhat. Amg a prog-
ramok fejlesztsekor egy hibs memria, illetve I/O mvelet (segmentation
fault) a rendszer szempontjbl nem veszlyes, s knnyen kiszrhet, a ker-
nelmodulban elkvetett hasonl hiba komoly kvetkezmnyekkel, akr mg a
rendszer sszeomlsval is jrhat. Ugyanakkor a kernel fejldsvel a hiba-
kezel metdusok is fejldtek, gy manapsg az esetek tbbsgben a rendszer
mg mkdkpes marad, s olyan hibajelzst (a jl ismert Oops zenet) k-
pes produklni, amely nagyban segti a fejlesztst. Ugyanakkor egy hiba utn
a rendszer instabil llapotba kerlhet, ezrt clszer jraindtani. Ellenkez
esetben furcsa, nem determinisztikus hibajelensgeket tapasztalhatunk,
amelyek lehetetlenn tehetik a hiba feldertst.
A hibakeress is nehzkesebb: az alkalmazsoknl hasznlt mdszerek
nem eredmnyesek, vagy csak komolyabb elkszletek utn, s akkor is csak
megktsekkel. m ms mdszerek is rendelkezsnkre llnak, br ezek sok-
szor nem nyjtanak olyan segtsget, mint amit az alkalmazsoknl megszok-
hattunk. A tovbbiakban bemutatunk majd nhny jl hasznlhat mdszert.
7.2.1. Felhasznli zemmd kernelzemmd
A felhasznli alkalmazsok sajt virtulis cmteret kapnak indtskor: eb-
ben a cmtrben tudnak dolgozni a futsuk sorn. Ugyanakkor az egyms
mellett fut prhuzamos folyamatok el vannak vlasztva egymstl. Egyms
terleteihez nem frhetnek hozz, csak szablyozott csatornkon rintkez-
hetnek (lsd a korbbi fejezetekben).
A folyamat virtulis cmtartomnya 32 bites rendszerben 2
32
, vagyis 4 GB.
Ezt a Linux rendszer kt rszre osztja. Az als 3 GB a felhasznli cmtarto-
mny, mg a fels 1 GB a kernel szmra fenntartott tartomny. A mretek
fggetlenek attl, hogy a szmtgp valjban mennyi fizikai memrit tar-
talmaz, mert itt csak virtulis cmterletekrl van sz.
342
7.3. Kernelmodulok
A mai processzorok tbb privilgiumszint hasznlatt teszik lehetv.
Ezek azt szablyozzk, hogy a folyamatok mihez frhetnek hozz. Kzlk a
Linux kt szintet hasznl: a felhasznli zemmdot s a kernelzemmdot.
A f klnbsg a kt zemmd kztt az, hogy felhasznli zemmdban a fo-
lyamatok a fels kernelcmtrhez nem frhetnek hozz, nem olvashatjk, r-
hatjk vagy futtathatjk a rajta lv kdot.
Az tjrst a felhasznli zemmd s a kernelzemmd kztt a rend-
szerhvsok nyjtjk. A rendszerhvsok meghvsval tudnak a folyamatok
olyan mveleteket vgrehajtani, amelyek a sajt virtulis birodalmukon kvl
tallhat rszekre hatssal vannak. Ilyenkor a rendszer ellenrzi a jogosult-
sgaikat, s vgrehajtja a mveletet.
Azok a mveletek, amelyek kernelmdban futnak, pldul a rendszerh-
vsok implementcija vagy a ks'bb trgyaland kernelszlak, hozzfrhet-
nek a kernel cmtartomnynak az egszhez. Ez azt jelenti, hogy semmilyen
korltozs nem vonatkozik rjuk, brmilyen mveletet vgrehajthatnak.
Vagyis elmondhatjuk, hogy a hibs vagy a rosszindulat kdot tartalmaz
modulokkal szemben a kernel vdtelen, ezrt a rendszer adminisztrtorra,
illetve a rendszerfejlesztkre hrul az a feladat, hogy ezektl a veszlyektl a
rendszert megvdjk.
7.3. Kernelmodulok
A Linux-kernel eredetileg monolitikus, vagyis egyetlen nagy program, amely
tartalmaz minden olyan funkcit s bels adatstruktrt, amely az opercis
rendszerhez tartozik (lsd a 2.1. A Linux-kernel felptse alfejezetben). Az al-
ternatva a mikrokernel lenne, amely minden funkcionlis elemet kln egys-
gekben tartalmaz, s az egyes rszek kztt jl meghatrozott kommunikci
zajlik. gy minden j komponens vagy funkci hozzadsa a kernelhez na-
gyon idignyes feladat lenne. A korai kernelverziknl, ha egy j eszkzt tet-
tnk a gpbe, a kernelt tnylegesen jra kellett konfigurlni s fordtani.
A Linux gy orvosolta a monolitikus kernel rugalmatlansgt, hogy az
1.2 -es verzi ta mr teljes tmogatst nyjt a futs kzben betlthet ker-
nelmodulok hasznlathoz. A kernelmodulok olyan trgykd binrisok,
amelyeket a rendszer indtsa utn brmikor betlthetnk, s dinamikusan
hozzlinkelhetnk a kernelhez. Majd amikor mr nincs r szksgnk, le-
kapcsoljuk (unlink), s eltvolthatjuk a modult memribl. Ez lehetv te-
szi, hogy az opercis rendszer egyes komponenseit dinamikusan betltsk s
eltvoltsuk, attl fggen, hogy szksgnk van-e rjuk, vagy sem. A legtbb
eszkzvezrlt modulknt valstottk meg, s ez a megolds javasolhat a
sajt eszkzvezrlink elksztsnl is. Ez a megkzelts magt a fejlesztst
is nagyban knnyti s gyorstja.
343
7. fejezet: Fejleszts a Linux-kernelben
Feladat A plda-eszkzvezrl feladata az lesz, hogy olvasskor kirja a Hello!" szveget,
rskor pedig a konzolra kirja a specilis llomnyba foglaltakat.
7.3.1. Hello modul vilg
Kezdsknt nzzk meg, hogyan alkothatjuk meg a legegyszerbb kernelmo-
dult. Ezt tekinthetjk majd vzknt is a ksbbi munknkhoz. Ez a kd a
kernel 2 .6.x-es verzija alatt fordul s mkdik:
/* hellomodule.c -Egyszeru kernel modul. */
#include <linux/module.h>
#include <linux/kernel.h>
int ni t_module(void)
{
printk("Hello modul vilag! \n");
return 0;
void cl eanup_module(void)
printk("viszlat modul vilag! \n");
MODULE_LICENSE("GPL");
A modul a lehet legegyszerbb. Minden modul minimum kt fggvnnyel
rendelkezik. Az egyik a modul betltsekor (init_module()), a msik az eltvo-
ltskor (cleanup_module()) hajtdik vgre. Ezek formja a 2 .6-os kernel ese-
tn a pldban lthat. A gyakorlatban azonban nem a fggvnyek beptett
neveit hasznljuk, hanem a sajt nevekkel ltrehozott fggvnyeket regiszt-
rljuk be, ez ugyanis flexibilisebb megolds. Ezzel a kibvtssel a kvetkez
kdig jutunk:
/* hellomodule.c - Egyszeru kernel modul. */
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/init.h>
static int ini t hello_init(void)
{
printk("Hello modul vi lag! \n");
return 0;
}
344
7.3. Kernelmodulok
static void exit hello_exit(void)
{
printk("viszlat modul vilag!\n");
module_init(hello_init);
module_exit(hello_exit);
mODuLE_DEsCRIPTIoN("Hello module");
MODULE_LICENSE("GPL");
A modul betltsekor s eltvoltsakor meghvand fggvnyeket a modu-
le_init() s a module_exit() makrkkal jelljk ki. Megfigyelhetnk mg egy kis
eltrst a fggvnyek alakjban. Nevezetesen az _init s az _exit makrkat.
Ezeket a makrkat arra hasznljuk, hogy megjelljk a kernel szmra az
inicializcis s az eltvolt fggvnyeket. A kernel a makrk ltal nyjtott
informcit felhasznlhatja a memriafelhasznls optimalizlsra. Jelen-
leg ezek az optimalizcis algoritmusok csak akkor lpnek mkdsbe, ha a
kernelmodult belefordtjuk a kernelbe.
Ha teht a kernelbe ptettk a modult, az _init makr hatsra az ini-
cializcis folyamat utn az init fggvny megsznik, s a hozztartoz me-
mria felszabadul. Az _exit makr hatsra a tisztogatfggvnyt figyelmen
kvl hagyja a rendszer a fordts sorn, hiszen a kernel kitltdsekor nincs
szksg felszabadtsra. Ha a modult nem ptjk a kernelbe, ezek a fggv-
nyek norml inicializl s tisztogatfggvnyekk vlnak, s a makrknak
nincs klnsebb hatsuk. Vagyis az _init s az _exit makrk hasznlata
azrt clszer, hogy egy kdban mindkt esetet kezelhessk.
A pldaprogramban a regisztrlt fggvnyeink kirsokat vgeznek.
Az zenetek kirsra a printk() fggvnyt hasznljuk, amely hasonlt a printf()
fggvnyhez, de a Linux-kernelben van definilva. A modul betltsekor a Li-
nux-kernelhez linkeldik, gy a printk() fggvny is hasznlhatv vlik.
(A printf() pldul nem hasznlhat, hiszen a felhasznli knyvtrban van
definilva.)
A modul vgn makrkkal megadhatjuk a modul ksztjt, lerst s a
licencinformciit. Jllehet ezeket az adatokat nem ktelez megadni, lega-
lbb a licencet clszer belltanunk Ha nem GPL licencet lltunk be, akkor
a modul betltsekor figyelmeztetst kapunk, illetve egyes, a kernelben lv
fggvnyek elrhetetlenek lesznek a modulunk szmra.
345
7. fejezet: Fejleszts a Linux-kernelben
7.3.2. Fordts
Miutn elkszltnk a kernelmodulunk forrskdjval, a kvetkez lps a
fordts. A fordtshoz mindenkppen szksg van a hasznlt kernel forrs-
ra. Ez nemcsak azt jelenti, hogy le kell tltennk egy kernelforrst, amely
ugyanolyan verzij, mint amit ppen hasznlunk, hanem hogy ha vannak
mdostsok (patch) a kernelnkben, akkor azoknak a forrsban is meg kell
lennik, tovbb a konfigurcinak is egyeznie kell.
Szerencsre ez tbbnyire nem jelent komoly problmt, hiszen a disztri-
bcik tbbsge minden kernelverzihoz tartalmazza a forrscsomagot is (ti-
pikusan: linux-source, linux-kernel-source) vagy pedig egy kernelfejleszti
csomagot (tipikusan: linux-devel, linux-kernel-devel, linux-headers). Utbbi
ltalban nem teljes forrscsomag, hanem csak azok a rszei vannak benne,
amelyek a modulok fordtshoz szksgesek. Ez termszetesen lnyegesen
kisebb, m szmunkra teljes rtk.
A modulunk fordtshoz felhasznljuk a kernelforrs Makefile-jait. Ezrt
a telepts utn pontosan tudnunk kell, hogy melyik knyvtrban helyezke-
dik el a f Makefile. Ezt a korbban emltett s felteleptett forrscsomagok
llomnylistjnak a megtekintsvel lehet kiderteni. A forrs gykrknyv-
trra van szksgnk (tipikusan: /usr/src/ alatt egy knyvtr, amely a ne-
vben a kernelverzit is tartalmazza).
A fordtsi metdus a kvetkez:
1. A modul knyvtrban ltre kell hoznunk egy Makefile nev llomnyt.
Ebben az llomnyban a kvetkez sor bersval jelezhetjk, hogy
a hellomodulel.c llomnyt szeretnnk felvenni a fordtsi listba (a
trgykd llomny nevt kell megadni, vagyis a .0" kiterjesztst:
olaj -rt1 bel
-
1 ~91 e .9
2 . Ezt kveten meg kell hvnunk a make parancsot gy, hogy a kernel-
forrs f'knyvtrban lv Makefile llomnyt hasznlja. Ugyanak-
kor t kell adnunk a SUBDIRS paramterrel a modulforrsunk
knyvtrt. Ezt kveten a modules" clt is meg kell adni a fordts-
hoz, amellyel jelezzk, hogy kernelmodulokat szeretnnk fordtani.
Ezzel a parancssor a kvetkez lesz:
mak e-C<k erne'k ny v t r>suBDIRs=<modulforr sk ny v t r>modules
A fordts sorn ltrejn egy trgykd llomny .0" kiterjesztssel. Ezt ki-
egsztve adminisztratv informcikkal ltrejn a .ko" kiterjeszts llo-
mny is, amely mr a ksz kernelmodul.
346
7.3. Kernelmodulok
7.3.3. A modulok betltse s eltvoltsa
Miutn elkszlt a kernelmodulunk, a kvetkez problma: hogyan tltsk
be? ltalnosan elmondhat, hogy kernelmodult csak rendszergazdai jogo-
sultggal tlthetnk be. Mivel a modul a kernel teljes rtk rsze lesz, ezrt
szinte teljhatalommal rendelkezik, korltozni csak nagyon kis mrtkben le-
het. Nyilvnval, hogy ha egy felhasznl a sajt moduljt ilyen mdon be-
tlthetn, akkor az egsz vdelmi rendszer teljesen hatstalan lenne.
A kvetkezkben ttekintjk a betlts folyamatt.
7.3.3.1. insmod/rmmod
A lefordtott modult a legegyszerbben az albbi paranccsal tlthetjk be:
1 nsinod hel 1 omodul e . ko
Az insmod program hozzlinkeli a modult a kernelhez, s vgrehajtdik az
inicializl metdusunk. A metdus kirja az dvzlszveget a konzolra.
92

A betlttt modulokat az lsmod paranccsal ki is listzhatjuk. Ez az aktu-
lisan betlttt modulokrl s a kztk fennll kapcsolatrl is mutat inform-
cikat.
A modul eltvoltsra a kvetkez parancs szolgl:
rniMod bel 1 omodk.il e
Ilyenkor meghvdik a modulunk tisztogatfggvnye, amely kirja a konzolra
a bcsszveget. Majd lekapcsoldik a modul, s eltvoltdik a memribl.
7.3.3.2. modprobe
A msik lehetsg a modulok betltsre a modprobe program hasznlata.
Ehhez azonban elszr el kell helyeznnk a modulllomnyt a modulok hiva-
talos trolknyvtrba:
Ill/modki~kempivert~
Pontosabban az ebben a knyvtrban lv kernel vagy update knyvtrak va-
lamelyikbe kell helyeznnk, egy, a modul fajtjtl fgg alknyvtrba. Ez
utbbi csak ajnls, a mkds szempontjbl nem rdekes.
92
Ha valamilyen terminlprogramot hasznlunk, amely tipikus grafikus fellet esetben,
akkor azon a konzolzenetek nem jelennek meg. Ilyenkor a dmesg paranccsal listzhat-
juk ki a konzolzeneteket.
34 7
7. fejezet: Fejleszts a Linux-kernelben
Ezt kveten le kell futtatni a depmod a parancsot. Ez a parancs rekur-
zvan felderti a knyvtrak tartalmt. sszegyjti a tallt modulok listjt,
tovbb feltrkpezi a modulok kztti fggsgeket.
93
Ezutn a modprobe
mr kpes betlteni s eltvoltani a modulokat.
Mivel a depmod parancs egy fggsgi listt llt el a modulokhoz, gy a
modprobe kpes r, hogy ne csak a megnevezett modult tltse be, hanem azo-
kat is, amelyektl fgg, illetve amelyeknek a szolgltatsaira pt.
A modprobe konfigurcis llomnya, illetve knyvtra a kvetkez:
/etc/modprobe.conf
/etc/modprobe.d/
A konfigurcis llomnyban az albbi parancsokat (7.1. tblzat) hasznl-
hatjuk:
7.1. tblzat. A modprobe belltsai
Parancs Jelents
Alias Bellthatunk egy msk nevet a modulnak, illetve leggyakrabban spe-
cifikus modulokat rendelnk az eszkznevekhez, hogy azok automati-
kusan betltdhessenek.
Options Paramterezst adhatunk meg a modul betltshez.
A modul betltse helyett a megadott komplex parancssort hajtja vgre.
Remove Lsd az installt, csak eltvoltsra hasznljuk.
Include
Egy llomnyt vagy egy egsz knyvtr tartalmt beilleszthetjk a kon-
figurcis llomnyba. Ezltal modulrisan pthetjk fel az llomnyt,
amely egyszersti az automatikus konfigurcimdostst.
Blatklist A megadott modulokba beptett alias belltsokat figyelmen kvl
hagyja a rendszer. (tkzsek, illetve egyes modulok automatikus be-
tltse ellen hasznljuk.)
7.3.4. Egymsra pl modulok
Tallkozhatunk olyan esettel, amikor a modulok egymsra plnek. Ilyenkor
az egyik modul valamilyen olyan szolgltatst valst meg, amelyet ms mo-
dulok hasznlnak. Ehhez a szolgltatst nyjt modulok szimblumokat,
fggvnyeket, esetleg vltozkat exportlnak, amelyek ms modulok ltal
meghvhatk.
93
A fggsgeket a ko" llomny adminisztratv meziben tallhat informcik alapjn
hatrozza meg.
3 48
7.3 .Kernelmodulok
Betltskor termszetesen gondoskodnunk kell a fggsgekrl, vagyis a
szolgltatst nyjt modult kell betltennk elszr, majd az azt felhasznlt.
m a modprobe ezt megoldja helyettnk.
Ha egy modulbl szimblumokat akarunk exportlni, akkor definilnunk
kell benne az EXPORT SYMTAB makrt. Ezt kveten az exportland
fggvnyeket az EXPORT SYMBOLO makr segtsgvel kell megadnunk.
A modul, amely elrhetv teszi a hello() fggvnyt a tbbiek szmra a
kvetkezkppen nz ki:
/*hellomodulea.c-aszolgaltatastny uj tomodul*/
#ifndefEXP ORT_SYMTAB
#defineEXP ORT_SYMTAB
#endif
#include<linux/module.h>
#includelinux/in t.h>
char*hello(v oid)
{
return"Hello!";
}
EXP ORT_SYMBOL(hel1 o) ;
staticint_ nithelloA_ n t(v oid)

printk ("ModuleAstart!\n");
return0;
1
staticv oid exithelloA_exit(v oid)
{
printk ("moduleAend!\n");
}
module_init(helloAj nit);
module_exit(helloA_ex t);
MODULE_OESCRIP TION("HellomoduleA");
MODULE_LICENSE("GP L");
Ahhoz, hogy a tbbi modulban hasznlhassuk a fggvnyt, ltre kell hoznunk
egy header llomnyt:
/*hellomodulea.h-azexportaltfuggv eny */
char*hello(v oid);
3 49
7. fejezet: Fejleszts a Linux-kernelben
A header llomny hasznlatval a fggvnyt felhasznlhatjuk egy msik
modulban:
/*hellomoduleb.c-aszolcialtatasthasznalomodul*/
#include<linux/module.h>
#include<linux/init.h>
#include"hellomodulea.h"
static nt_ i nithelloB_init(v oid)
{
printk("modul e S start! \n");
printk("%s\n", hello());
return 0;
1
1~
staticv oid ex thelloB_exit(v oid)
{
pr ntk ("Module e end!\n");
}
module_init(helloB_in t);
module_exit(helloB_exit);
"1~
MODULE_DESCRIP TION("Hellomodule8");
MODULE_LICENSE("GP I");
Fordtsuk le mindkt modult, ekkor elszr az A modult, utna a B modult
betltve lthatjuk, hogy a B modul tnylegesen hasznlja az A modul expor-
tlt fggvnyt.
A fggvnyek exportlsakor gondolnunk kell arra, hogy mkds kzben
a modulunk a kernel teljes rtk rsze lesz, az exportlt fggvnynk/vlto-
znk pedig egy globlis szimblum. Azt pedig az alkalmazsok fejlesztsbl
tudjuk, hogy nem lehet kt azonos nev globlis fggvnynk vagy vltoznk.
Ezrt neknk is gy kell megvlasztanunk a neveket, hogy ne lehessen tk-
zs a kernellel vagy ms modulokkal.
Az EXPORT SYMBOLO makrnak ltezik mg egy tovbbi varinsa,
amelynek neve EXPORT SYMBOL_GPLO. A mkdse megegyezik az elz-
vel, m csak GPL licenccel rendelkez modulok szmra elrhet a szimblum.
Ezltal a GPL licences munknkat elfedhetjk a zrt lincenccel rendelkez
modulok ell.
350
7.4. Paramtertads a modulok szmra
7.4. Paramtertads a modulok szmra
A modulok leggyakrabban egy-egy eszkzvezrlt implementlnak. Az esz-
kzvezrlk sokszor rendelkeznek klnfle belltsokkal (pldul az eszkz
I/O cmtartomnya). Ezeket a belltsokat kontansknt bele is drtozhat-
juk" a modulba, eszerint ha valamelyik belltson mdostani szeretnnk,
akkor jra kell fordtanunk a modult. Ez termszetesen nagyon krlmnyes.
A megfelel megolds az lenne, ha a modul betltsekor is megadhatnnk be-
lltsokat. Erre szolgl a Linux-kernel paramtertadsi mechanizmusa.
A belltsokat paramterekben adhatjuk t a modulnak. Ennek mdja
nem egyezik meg a felhasznli alkalmazsoknl megszokott parancssori ar-
gumentumokkal. Definilhatunk olyan globlis vltozkat, amelyeket az
insmod parancs az indtskor kitlt. A vltoz ltrehozsakor megadhatjuk
az inicializcis rtkt, amely egyben a paramter alaprtelmezett rtke is
lesz. Ezt kveten a moduleparamO makr valamelyik vltozatval meg kell
adnunk azt, hogy az adott vltoz modulparamternek szmt, illetve tpustl
fggen egyb belltsokra is szksg van:
module_param(n v ,t pus,sy sfs-j ogok );
module_param_names(n v ,v ltozn v ,t pus,sy sfs-j ogok );
module_param_array (n v ,tipus,m retmutat,sy sfsj ogok );
module_param_array _named(n v ,v ltozn v ,t pus,m retmutat,
sysfs-jogok);
module_param_string(n v ,v ltozn v ,m ret,sy sfs-j ogok );
A nv a vltoz neve, a tpus a vltoz tpusa, a sysfs jogok a paramter-
jogosultsg belltsai a sysfs llomnyrendszeren bell. A mret mutat
a tmb esetben opcionlis paramter. Ha megadunk egy vltozt, illetve an-
nak mutatjt, akkor a rendszer a vltozban eltrolja a tmb elemeinek
szmt a paramter tadskor. A mretparamter a string tpus esetn a
szveg maximlis hosszt adja meg belertve a zr karaktert is. (A string t-
pus paramternl a nv ismtldse nem nyomdahiba, hanem implement-
cis furcsasg.) A stringparamter msik megads mdja, ha tpusnak charp
rtket adunk meg, amely karaktermutatt jelent. Ekkor azonban nem kell
megadnunk a mretet:
module_param(n v ,charp,sy sfs-j ogok );1.1.111~1~L
A paramterek lerst is clszer megadnunk a modulban a MODULE_
PARM DESCO makr hasznlatval. Erre azrt van szksg, hogy a felhasz-
nlk a modulbl megtudhassk a paramterek jelentst. A makr formja a
kvetkez:
MODULE_P ARM_DESC(n V,le r s);
351
7.fej ezet:Fej leszt saLinux-k ernelben
Nzznk egy egyszer pldt a paramterek hasznlatra:
/*helloparam.c-Egy szerupeldaabetoltesiparameterek
k ezelesere.*/
#include<linux/module.h>
#include<linux/moduleparam.h>
#include<linux/k ernel.h>
#include<linux/ nit.h>
/"Letrehozzuk aparameterek nek megfeleloglobalisv altozok at.*/
staticcharparaml[16]="hello";
staticintparam2 =5;
staticintparam3 [2 ]={ 1,2 } ;
/*Mak rok k almegadj uk ,hogy parameterk entv arj uk ,eshogy mily en
tipussal.*/
module_param_string(paraml,paraml,16,0644);
MODULE_P ARM_DESC(paraml,"Szov egesparameter");
module_param(param2 ,int,0644);
MODULE_P ARM_DESC(param2 ,"Szamparameter");
module_param_array (param3 ,int,NULL,0644);
moDuLE_P ARm_0EsC(param3 ,"Szamtombparameter");
staticint inithello_init(v oid)
printk ("paraml:%s\n",paraml);
printk ("param2 :%d\n",param2 );
printk ("param3 ;%d,%d\n",param3 [0],param3 [1]);
return0;
}
staticv oid_exithello_exit(v oid)
printk ("paraml:%s\n",paraml);
printk ("param2 :%d\n",param2 );
printk ("param3 :%d,%d\n",param3 [0],param3 [1]);
module_init(hello_init);
module_exit(hello_exit);
MODULE_DESCRIP TION("Helloprof");
MODULE_LICENSE("GP L");
A lefordtott modul paramtereit s a lersokat a modinfo parancs segtsg-
vel nzhetjk meg:
m o d i n f a h o l l o p a r a m , 3 5 0
3 52
7.5. Karakteres eszkzvezrl
A paramtereket az nsmod parancs hasznlatakor llthatjuk be. Nem szk-
sges minden paramtert megadnunk. Amelyiket nem adjuk meg, annak az
rtke az lesz, amellyel a C kdban inicializltuk az adott statikus vltozt:
Ha a modprobe parancsot hasznljuk a modul betltsre, akkor a mod-
probe.conf llomnyban kell megadnunk a paramtereket.
Ha a sysfs jogosultsgok belltsnl adtunk olvassi vagy rsi jogosult-
sgot a paramterekre, akkor utlag is kiolvashatjuk vagy mdosthatjuk az
rtkket. Ehhez a /sys/module/<modul nv>/parameters knyvtrban kell
krlnznnk. Itt minden egyes paramterhez tallhatunk egy virtulis l-
lomnyt. Ezeket olvashatjuk s rhatjuk.
Termszetesen utlagos mdostsok esetn szmolnunk kell az esetleges
konkurenciaproblmkkal Erre pldaknt nzzk meg a kvetkez esetet. Egy
tbbprocesszoros gpen kt alkalmazst futtatunk prhuzamosan. Az egyik al-
kalmazs hasznlja a kernel modulszolgltatst, mg a msik mdostja
a kernel modulparamtert a sysfs llomnyrendszeren keresztl. Ha a para-
mter sszetett (szveg, tmb), akkor tbb gpi mvelettel trtnik az rsa,
illetve az olvassa. Vagyis a kt alkalmazs ltal kivltott paramterkezelsi
folyamatok tlapoldhatnak, gy kritikus versenyhelyzetet eredmnyezhetnek.
7.5. Karakteres eszkzvezrl
Ebben a fejezetben egy karaktertpus eszkzvezrl moduljt ksztjk el.
Azrt ezt a tpust, mert ltalban ez illeszkedik az egyszerbb hardvereszk-
zkhz, illetve ez a legegyszerbben rthet eszkzvezrl-fajta.
A Unix rendszerek az eszkzket a idei) knyvtrban tallhat specilis
llomnyokknt teszik elrhetv a felhasznlk szmra, illetve a felhaszn-
li mdban fut programok is lllomnyokknt hasznljk ket. Ezrt esz-
kzvezrl ltrehozsakor az az els feladatunk, hogy hardvereszkzeink
funkciit llomnykezelsre kpezzk le: megnyits, rs, olvass, bezrs.
Az eszkzvezrl modulnak az llomnykezelssel kapcsolatos funkcik te-
szik ki az egyik rszt. A msik rszk a modulkezelshez tartoz inicializl s
tisztogatfggvnyek, amelyeket az elz fejezetben lttunk. Egy eszkzvezrl
esetben ezekben a fggvnyekben regisztrljuk be a kernel nyilvntartsba
az eszkznket, illetve tvoltjuk el a bejegyzst.
353
7. fejezet: Fejleszts a Linux-kernelben
7.5.1. F- s mellkazonost (major s minor number)
Mint mr sz volt rla, az eszkznk elrshez szksg van specilis llom-
nyokra, amelyeket az mknod paranccsal vagy rendszerhvssal hozhatunk lt-
re. A korbbi fejezetekben lthattuk, hogy a ltrehozsukhoz szksges a tpus,
valamint egy f- s egy mellkazonost (major s minor number) megadsa.
A fazonost azonostja a specilis llomnyhoz tartoz modult. A kernel
ennek alapjn vlasztja ki, hogy melyik eszkzvezrl modulhoz forduljon, ha
egy program ezt az llomnyt nyitja meg.
A mellkazonostt az eszkzvezrl program hasznlhatja, amennyiben
tbb llomnyinterfszt is kezel. Ezt neknk kell kezelnnk a modulon bell, a
kernel nem foglalkozik vele." A soros interfsz fazonostja pldul 4 , azon be-
ll a mellkazonostk hatrozzk meg a konkrt eszkzk interfszeit. Az els
soros port (/dev/ttySO) fazonostja pldul 4 , mellkazonostja 64 .
95

Egy j eszkzvezrl beregisztrlsa lnyegben azt jelenti, hogy hozzren-
deljk egy fazonosthoz a virtulis llomnykezelst megvalst fggvnyeit.
A karakteres eszkzvezrl regisztrlfggvnynek alakja a kvetkez:
ntregister_chrdev (unsignedintmaj or,constchar*name,
structfile_operations*fops);
A visszatrsi rtk negatv szm esetn hibt mutat. A major argumentum
a fazonostt jelenti, a name argumentum annak az eszkznek a neve, amely
a /proc/devices listban jelenik meg. A fops paramter egy olyan struktrra
mutat, amely az egyes llomnykezelsi funkcikat megvalst fggvnyek
mutatit tartalmazza, pldul azt, hogy a specilis llomnyba val rskor
melyik fggvny hvdjon meg.
Lehetsgnk van arra, hogy a regisztrls sorn ne mi vlasszuk meg a
fazonostt kockztatva ezzel az tkzst egy msik meghajtval , hanem
a rendszerre bzzuk ezt a feladatot Ekkor a kernel automatikusan kivlaszt
egy azonostt, s a fggvny visszatrsi rtkben adja vissza.
Miutn az eszkzvezrlnket regisztrltuk a kernel knyvelsbe, minden
olyan mvelet esetn, amelyet az ltalunk regisztrlttal megegyez fazonos-
tj specilis llomnyokkal vgznk, a kernel meghvja a mvelethez meg-
adott fggvnyt.
A modulunk eltvoltsakor termszetesen el kell tvoltanunk ezt a bejegy-
zst, s el kell eresztennk a fazonostt. Erre szolgl a kvetkez fggvny:
~iit~idgrtia~d, int itialr, ~t 4 ~01
94
Hangslyoznunk kell, hogy a kernel kizrlag a fazonostt hasznlja a modul azonost-
sra. A modul neve, megjelense az llomnyrendszerben kizrlag a knnyebb kezelhet-
sget segti el a felhasznlk szmra. A blokkos s karakteres eszkzket teljesen kln
kezeli a kernel, ezrt egy blokkos s egy karakteres eszkz azonostja ugyanaz is lehet.
" Az eddig kiosztott azonostk a The Linux Assigned Names And Numbers Authority
(http: / / www.lanana.org) oldaln tallhatk.
3 54
7.5. Karakteres eszkzvezrl
Az els paramter a fazonost, a msodik az eszkzvezrl neve. Utbbi
csak biztonsgi okokbl szerepel. A kernel sszehasonltja a korbban regiszt-
rlttal, s eltrs esetn nem hajtja vgre a regisztrci eltvoltst.
Ha netn a modult a regisztrls trlse nlkl tvoltannk el, az ksbb
komoly kellemetlensgeket okozhat. Minden olyan mvelet, amely erre az esz-
kzvezrlre hivatkozik a mr emltett Oops hibazenet vltja ki a kernelbl.
7.5.2. Az eszkzllomnyok dinamikus ltrehozsa
Tradicionlisan a /dev knyvtr tele volt statikusan ltrehozott eszkzllo-
mnyokkal. Minden a Linux ltal tmogatott eszkzllomnynak szerepelnie
kellett benne, htha az adott meghajtt hasznlni szeretnnk. Ez jelents s
felesleges helyfoglalst jelentett. Ezrt clszernek ltszott az eszkzllom-
nyok dinamikus ltrehozsa.
Az els prblkozs a devfs llomnyrendszer tmogatsa volt. A kernel
ezen az llomnyrendszeren keresztl virtulis llomnyokkal reprezentlta
az eszkzllomnyokat, amikor erre szksg volt. A modern kernelvltozatok
ezt a mechanizmust manapsg mr nem tmogatjk.
A jelenleg is hasznlatos megolds az udev felhasznli mdban fut al-
kalmazsra pt. A folyamatosan fut udev daemon fogadja a kernel hotplug
zeneteit, s ezek alapjn dinamikusan hoz ltre s trl le eszkzllomnyo-
kat egy virtulis, memriban trolt llomnyrendszeren.
A hotplug zenetek generlshoz az eszkznknek implementlnia kell
a 2 .6-os kernelekkel bemutatkoz eszkzmodellt (device model). A Linux-esz-
kzmodell lnyegben egy olyan komplex adatstruktra, amely tartalmazza
azt, hogy az eszkz milyen tpusosztlyba tartozik, melyik buszra csatlakozik,
s milyen specilis attribtumokkal rendelkezik. Ha az eszkzkezelkben el-
vgezzk ezeket a regisztrcikat, akkor az eszkzvezrlnk, illetve az eszk-
znk megjelenik a sysfs llomnyrendszerben is a hierarchinak megfelel
helyen. Emellett lehetv vlik az udev rendszer hasznlata.
Ha clunk mindssze az eszkzllomnyok automatikus ltrehozsa, ak-
kor elegend a device_create() fggvnyt hasznlnunk, amely az udev szm-
ra kiadja a megfelel jelzst. A fggvny alakja a kvetkez:
structdev ice*dev ice_create(structclass*oszt ly ,
structdev ice*szl,dev _teszk z,constchar*n v ,...);
Az osztly egy mutat arra az osztlyra, amelyhez az eszkzt rendeljk. Lt-
rehozsa a class_create() fggvnnyel lehetsges. A szl egy mutat a szl-
eszkzre, ha ltezik ilyen. Az eszkz a f- s mellkazonostkat tartalmaz
argumentum. Ellltsa az MKDEVQ makrval lehetsges. A nv s az ezt
kvet argumentumok az eszkz llomnynevnek sszelltst teszik lehe-
tv a printf() fggvnyhez hasonl mdon.
355
7. fejezet: Fejleszts a Linux-kernelben
A ltrehozott eszkzt a device_destroy0 fggvnnyel kell megsemmisteni
a modul eltvoltsa eltt. A fggvny alakja a kvetkez:
Void_dev ce_de.stroY(struc.tclass*oszt ly ,dev _teszk z);
A fggvny paramtereinek rtelmezse megegyezik a ltrehozsnl hasznl-
takkal.
Az eszkz ltrehozshoz szksges egy olyan osztly, amelyhez hozzren-
delhetjk. Ezt a class_create0 fggvnnyel hozhatjuk ltre, amelynek alakja a
kvetkez:
struct class* cl ass_create(struct module*modul,constchar*n v );
A modul paramter annak a modulnak a mutatja, amely az eszkzosztlyt
birtokolja. A THIS MODULE makrval adhatjuk meg a modulunkat. A nv
az osztly szveges megnevezse.
Az osztly megszntetst a class_destroy0 fggvnnyel kell elvgeznnk
a tisztogatsnl. A fggvny szintaxisa a kvetkez:
void cl ass_destroy(struct class* osztly);
Nzznk egy pldt az eszkzllomny ltrehozsra:
staticstructclass*hello_class;
hello_class=class_create(THis_MODULE,"hello");
dev ice_create(hello_class,NULL,MKDEV(12 0,0),NULL,"hello");
Az eltvolts:
dev ice_destroy (hello_class,MKDEV(12 0,0));
class_destroy (hello_class);
A kdrszleteket elhelyezve az nit s az exit fggvnyekben az udev automa-
tikusan ltrehozza, illetve letrli a hello" eszkzllomnyt. Ha szeretnnk az
llomny jogosultsgait megadni, akkor ez az udev konfigurcis llomny-
ban lehetsges.
7.5.3. llomnymveletek
Az eszkzvezrlnek az eszkzk elrhetv ttelre, kezelsre az llomnyke-
zelseknl hasznlatos fggvnyeket kell implementlnia. Ezeknek a fggv-
nyeknek a mutatit tartalmazza a file_operations struktra. Olyan mveletekrl
van sz, mint a megnyits, az olvass, az rs, a bezrs stb. A lista tartalmaz-
hat NULL pointereket is, ennek jelentse az, hogy az adott mveletet az eszkz-
vezrl nem tmogatja.
356
7.5. Karakteres eszkzvezrl
A struktra a kernelverzik vltozsakor folyamatosan ntt, s talakult
az jabb elemek felvtelvel. Az ppen aktulis lerst a linux/ fs.h llomny
tartalmazza.
A struktra egyes elemeibl lthat, hogy az adott metdust milyen fgg-
vnnyel lehet lekezelni. Az implementlni kvnt llomnykezel metdusokat a
struktrban megadott paramterekkel s visszatrsi rtkkel kell definilni.
Mivel a struktra az egyes verzikban vltozhat, ezrt az albbi mdon
javasolhat a hasznlata:
96

staticstruct fi 1 e_operations hel 1 o_fops
{
owner
read:
wri te :
open :
rel ease :
1;
THIS_MODULE,
hello_read,
hello_write,
hello_open,
hello_release
Az owner mez megadsval jelezzk, hogy melyik modulhoz ktdik a ler
struktra. A THIS_MODULE makr az aktulis kernel moduller struktr-
jnak mutatjt adja vissza.
7.5.4. Hasznlatszmll
Ha egy alkalmazs hasznlja az eszkzvezrlt, a kernelnek nem szabad addig
eltvoltania a modult, amg az utols alkalmazs is le nem zrja az eszkzvezr-
lhz tartoz llomnyt. Ezt a vdelmet a kernel klasszikus referenciaszmlls-
sal implementlja. Neknk csak annyit kell tennnk, hogy amikor megnyitjk az
eszkznket, akkor nvelnk egy szmllt, amikor pedig lezrjk, akkor csk-
kentjk a szmllt. A kernel nem tvoltja el a modult a memribl, amg en-
nek a szmllnak az rtke nagyobb, mint nulla y'
Ennek a mechanizmusnak a hasznlathoz ksz fggvnyeket nyjt a
rendszer. A szmllt nvelni az albbi fggvnnyel tudjuk:
try _module_get(THIs_mpoutE):
96
Ez a definci egy gcc kiterjesztsre pl, amely lehetv teszi a struktra tagjainak nv
szerinti inicializlst (a nem inicializlt tagokat a gcc nullra inicializlja). A szabv-
nyos megolds a C99-es szabvny gynevezett nv szerinti inicializlsi (designated
initializer) mechanizmust hasznlja. Ilyenkor a pont utn megadjuk az egyes mezk ne-
veit, s expliciten adunk rtket nekik egyenlsgjellel. Azokat a vltozkat, amelyeket
nem sorolunk fel, a fordt nullval inicializlja. Ezt a C-ben is viszonylagosan j szinta-
xist a C++ nem tmogatja. Vagyis ha a tagok nevei el pontot, a kettspont helyett pedig
egyenlsget hasznlunk, akkor hordozhat megoldshoz jutunk.
97
A kernel termszetesen szmon tartja azt is, hogy ha ms modulok is hasznlnak egy
adott modult. Ilyenkor szintn nveli a referenciaszmllt.
357
/*hellodriv er.c- Egy szerudriv eroffsetk ezelessel.
#include<1nux/moduleh>
#include <1 i nux/kernel .h>
#include <linux/fs.h>
#include <asm/uaccess . h>
#include <1 i nux/devi ce .h>
#defineDEVICE_NAME "hello"
staticintmaj or_num=12 0;
#defineCLASS_NAME"helloclass"
staticstructclass*hello_class;
#defineMSG_LEN 7
staticchar*msg="Hello!\n";
7. fejezet: Fejleszts a Linux-kernelben
Ha mr nem hasznljk a modult, akkor cskkentennk kell a szmll rtkt:
module_put(THIS_MODULE);
A rendszer figyeli, s ha a hasznlatszmll rtke nagyobb, mint 0, akkor
nem engedi a modult eltvoltani. Ez ugyanakkor a fejleszts sorn gondot is
jelenthet, mert ha elrontjuk a knyvelst, akkor nem lehet a modult a rend-
szer jraindtsa nlkl eltvoltani. Ezrt a kernelbe belefordthat a kny-
szertett eltvolts lehetsge.
98

7.5.5. Hello vilg" driver
Hogy knnyebben megrtsk, nzzk meg egy pldn az alapmveleteket s
az implementlsuk sorn felmerl problmkat.
A plda-eszkzvezrl feladata az lesz, hogy olvasskor kirja a Hello!"
szveget, rskor pedig a konzolra kirja a specilis llomnyba rtakat:
/*Azirasmuv eletetk ezelorutin.*/
staticssize_thello_write(structfile*pfile,constchar*buf,
size_tcount,loff_t*ppos)
{
/*Akernel memoriabol lefoglaljuk a szukseges teruletet. * /
char*str=k malloc(count+1, GFP _KERNEL);
98
A kernelfordts eltti konfigurls sorn a modulokra vonatkoz belltsoknl kiv-
laszthatjuk a knyszertett modul eltvoltsi lehetsgt. Ksbb a lefordtott kernelt
hasznlva lehetsgnk lesz a modul knyszertett eltvoltsra. Br a rendszer engedi
az eltvoltst, csak szksg esetn hasznljuk.
358
7.5.Karak tereseszk zv ez rl
/*Atmasolj uk afelhasznaloicimteruletrolazadatok atak ernel
cimteruletre.*/
f(!copy _from_user(str,buf,count))
{
/*Lezarj uk egy 0k arak terrel.*/
str[count]=0;
/* Aprintk ()fuggv eny hiv assalk iirj uk .*/
printk (DEVICE_NAME"write:%s\n",str);
/*Felszabaditj uk alefoglaltteruletet.*/
k free(str);
/*v isszaterunk azolv asottbaj tok szamav al.*/
returncount;
/*Azolv asasmuv eletetlek ezelofuggv eny .*/
staticssize_thello_read(structfile*pfile,char*buf,
size_tcount,loff_t*ppos)
{
//haapoz zicioaszov egv egeremutatak k orv isszaterunk
i f(*ppos>=MSG_LEN)return0;
//Maximumanny ibaj totszolgalunk k i,amily enhosszuaszov eg.
if((*ppos+count)>MSG_LEN)count=MSG_LEN - *ppos;
/*Atmasolj uk azadatotak ernelcimteruletrol,azolv aso
fuggv eny altalk apottbufferbe.*/
if(copy _to_user(buf,msg+*ppos,count))
{
return -EFAULT;
*ppos+=count;
/*V sszaterunk av isszaadottadatmenny iseghosszav al.*/
returncount;
/*Amegny itasmuv eletetlek ezelofuggv eny .*/
staticinthello_open(structinode*inode,structfile*pfile)
t
/*Nov elj uk ahasznalatiszamlalot.*/
try _module_get(THIs_mODULE);
printk (DEVICE_NAME"open.\n");
return0;
359
7. fejezet: Fejleszts a Linux-kernelben
/* Alezarasmuv eletetlek ezelofuggv eny .*/
stat cinthello_close(structinode*inode,structfile*pfile)
{
printk (DEv ICE_NAME"close.\n");
/*Csok k entj uk ahasznalatiszamlalot.*/
module_put(THIS_M0DuLE):
return0;
staticstructfile_operationshello_fops=
owner: THIS_MODULE,
read: hello_read,
write: hello_write,
open: hello_open,
release:hello_close
} :
/*Ak ernelmodulinic al zalasatv egzofuggv eny .
staticint inithello_init(v oid)
intres;
structdev icecerr;
/*Regisztralj uk ak arak tertipusueszk ozt.'/
res=register_chrdev (maj or_num,DEVICE_NAME,&hello_fops);
i f(res<O)
{
printk (DEv ICE_NAME"afoazonosito:%dnemelerheto\n",
maj or_num):
returnres;
}
if(maj or_num==0)maj or_num=res;
/*Azudev sz m raj elz s,hogy hozzal treaz
eszk z llom ny t.*/
helloclass=class_create(TNIs_m0DuLE,CLASS_NAME);
err=dev ice_create(hello_class,NULL,MKDEV(maj or_num,0),
NULL,DEVICE_NAME);
printk (DEv ICE_NAmE"betoltv e.Fazonosito:%d\n",maj or_num);
return0;
}
/*Ak ernelmoduleltav olitasaelottafelszabad tasok atv egzi.
staticvoid _exithello_ext(void)
/*Azudev sz m raj elz s,azeszk zelt v olit s rl.*/
dev ice_destroy (hello_class,MKDEV(maj or_num,0));
class_unregister(hello_class);
class_destroy (hello_class);
360
7.5. Karakteres eszkzvezrl
/*Eltav olitj uk az eszkoz regisztrac ot.*/
unreg ster_chrdev (maj or_num,DEv ICE_NAmE);
printk (oEv icE_NAmE"felszabaditv a.\n");
}
module_init(hello_init);
module_exit(hello_exit);
moDuLE_DEscRIP TIoN("Hello driv er");
mODULE_LICENSE("GP L");
A modul inicializl- s tisztogatfggvnye mr ismers. Ennl a modulnl
ezekben a fggvnyekben regisztrljuk, illetve tvoltjuk el a 12 0-as fazono-
sthoz az eszkzvezrl fggvnyeinket.
A file_operations struktrrl szintn esett mr korbban sz. A pldban
lthatjuk, hogyan adhatjuk meg az egyes llomnymveletekhez tartoz
fggvnyeket.
A hello_openo s a hello_elose0 fggvnyeinkben nveljk, illetve csk-
kentjk a hasznlatszmllt. Ezltal megakadlyozhatjuk a modul eltvolt-
st, amg egy vagy tbb processz nyitva tartja az eszkzvezrlnkhz tartoz
llomnyt.
Az eszkzllomny olvasst megvalst fggvnynk a korbban meg-
adott Hello!" szveget, vagy ha az olvas kevesebb byte-ot vr, akkor annak
egy rszt bemsolja a paramterknt kapott bufferbe (bal). A msolsra a
copy_to_user0 fggvnyt hasznljuk. Ennek az a feladata, hogy a kernel me-
mriatartomnyban lv adathalmazunkat a felhasznli memriatarto-
mnyba msolja. gy valsthatjuk meg a tartomnyok kzti adatmozgatst
ebben az irnyban.
Az olvasst megvalst fggvny visszatrsi rtkeknt a visszaadott
byte-ok szmt, az llomny vge" esetn 0-t vagy hiba esetn negatv rt-
ket kell visszaadnunk, annak megfelelen, amit a readO fggvny meghv-
sakor az alkalmazsban vrunk. Eltrs csak a hibajelzsnl mutatkozik,
ahol a hiba kdjt kell visszaadnunk, amelyet az alkalmazs az errno vlto-
zban kap meg. Az rst megvalst fggvny implementcijnl hasonlan
kell eljrnunk, csak ebben az esetben a szmrtk a feldolgozott byte-ok sz-
mt jelenti.
99

A hello_readO fggvny implementcija az adatok visszaadsa mellett
knyveli az aktulis pozcit is. Ennek akkor van szerepe, ha a fogad buffer
mrete kisebb a visszaadand szvegnl. Ilyenkor a ppos vltozban (term-
szetesen msknt is elnevezhetjk a paramtert) trolhatjuk, hol tartunk az
adatokban, s a kvetkez olvassi mveletnl visszaadhatjuk a maradkot.
A ppos vltoz egy llomnykezelsi viszonylatban egyedi. Vagyis ha megnyi-
tunk egy llomnyt, akkor kap egy egyedi pozcit trol vltozt, amely
99
Mindkt esetben a visszatrsi rtk tpusa ssize t, amely eljeles size _t (signed size_t")
tpust jelent. Ez a negatv rtkek visszaadsa miatt szksges.
361
7. fejezet: Fejleszts a Lnux-kernelben
megrzi az rtket. Ha egy msik folyamatban szintn megnyitjuk ugyanazt
az llomnyt, akkor ez a viszonylat egy msik vltozt kap. gy az egyes vi-
szonylatok nem zavarjk egymst.
A read s a write fggvnyek olyan buffereket kapnak paramternek a
felhasznli programoktl, amelyek a felhasznli cmtartomnyban vannak
lefoglalva. Ugyanakkor a kernelmodulok ltal lefoglalt terletek ltalban
a kernel cmtartomnyban vannak, ezrt meg kell oldanunk az adatok moz-
gatst a kt terlet kztt. Erre a linux/ uaccess.h tartalmaz az elz pld-
bl ismers fggvnyeket:
unsigned long copy_from_user(void *to, const void _user *from,
unsigned long n);
unsigned long copy_to_user(void _user *to, const void *from,
unsigned long n);
Az eszkzllomny rst implementl metdusban lthatjuk, hogy a kernel
memriatartomnyban a kmalloc0 fggvnnyel alloklhatunk terletet, s a
kfree0 fggvnnyel szabadthatjuk fel.
Valjban itt nem szksges az allokls s a msols, mert a konzolra
trtn kirs ezek nlkl is mkdne. A vals alkalmazsoknl azonban l-
talban szksg van ezekre a lpsekre, ezrt kerltek bele a pldba.
A fenti pldaprogram fordtsa a korbbi modulnl ismertetett Makefile
segtsgvel trtnhet.
Ezt kveten, ha az insmod utastssal betltttk a modult, akkor mr
hasznlhat is.
7.5.6. Az open s a release fggvnyek
Az open fggvny tipikus feladatai a kvetkezk:
A hasznlatszmll nvelse.
Eszkzspecifikus inicializci az els megnyitsnl.
Ha egyszerre az eszkzt csak egy program vagy egy felhasznl hasz-
nlhatja, akkor a klcsns kizrs megvalstsa.
A mellkazonost alapjn a pfile->f op paramter mdostsa, egy
msik file_operations struktra belltsa.
A pfile->private_data pointerhez alloklhatunk egy trterletet, s
bellthatunk valami eszkzspecifikus informcit.
362
7.5. Karakteres eszkzvezrl
A release fggvny feladatai a kvetkezk:
A hasznlatszmll cskkentse.
Eszkzspecifikus lezrsok az utols bezrsnl.
Ha a pfile->private_data pointerhez allokltunk valamit, akkor ennek
felszabadtsa.
A hasznlatszmllk kezelst mr korbban lthattuk. Az egyszeres meg-
nyitst a mellkletben tallhat pldakdokkal mutatjuk be, a mellkazonos-
t kezelsvel kapcsolatos megoldsokat pedig a kvetkez fejezet trgyalja.
7.5.7. A mellkazonost (minor number) hasznlata
A mellkazonost lehetsget biztost arra, hogy az eszkzmeghajt tbb
azonos tpus eszkzt tegyen lthatv az opercis rendszer szmra. Br a
meghajt szabadon hasznlhat eltr implementcit a klnbz mellkazo-
nostkhoz, az egysges viselkeds ersen javallott.
Vegyk pldnak a soros portokat kezel eszkzvezrlt. Termszetesen
az eszkzvezrl az egyes portokra megegyezik, hiszen pazarls lenne minden
porthoz kln eszkzvezrlt betlteni s regisztrlni. Vagyis az eszkzvezr-
lnk egy pldnyban van jelen, s egy fazonostra regisztrlta az llomny
interfszt. Az sszes soros porton foly kommunikcit azonban egyetlen l-
lomnyon keresztl elrhetv tenni nehz s clszertlen lenne. Jobban j-
runk, ha minden porthoz rendelnk egy llomnyt. Ekkor ezek az llomnyok
egy fazonostval rendelkeznek, s a mellkazonost klnbzteti meg ket.
A mellkazonost kezelse, ahogy korbban mr sz volt rla, a mi fela-
datunk. Kt utat vlaszthatunk. Az egyik megolds szerint az olvasst s
rst kezel fggvnyeinkbe helyeznk elgazsokat, amelyek a mellkazono-
st alapjn ms-ms kdrszletet futtatnak.
Feladat Mdostsuk az elbbi plda eszkzvezrljt gy, hogy ha 0-s mellkazonostj eszkz-
llomnyon keresztl olvassuk, akkor a Szia!", ha az 1-es, akkor a Mizu?" szveget adja vissza.
Nzznk egy rszletet, amely illeszkedik a korbbi pldba:
#defineMSG_LENb
staticchar*msgs[]={ "szia!","mizu?"} ;
staticssize_thello_read(structfile*pfile,char*buf,
size_tcount,loff_t*ppos)
i ntlen;
l en=count;
if(count>mSG_LEN)len=MSG_LEN;
363
7. fejezet: Fejleszts a Linux-kernelben
switch(MINOR (pfile- >f_dentry - >d_inode - >i_rd ev))
{
case0:
i f(copy _to_user(buf,msgs[0],len))return-EFAULT;
break ;
case 1:
if(copy _to_user(buf,msgs[1],len)) return -EFAULT;
break ;
default:
return - EINVAL
return len;
Az llomnyt ler struktra segtsgvel elrjk annak az eszkzllomny-
nak az inode-informciit, amelyen keresztl a fggvny meghvdott. Azon
bell is a f- s a mellkazonostt tartalmaz i_rdev tagjt vizsgljuk. Ebbl
a M/NORO makr hasznlatval kinyerhetjk a mellkazonostt. Ezt kve-
ten a switch-case szerkezet segtsgvel eltr kdot hajtunk vgre az egyes
esetekben.
A msik megolds az, ha az elz fejezetben ltottak szerint az llomny
megnyitsnl lltunk be eltr lekezel fggvnyeket az egyes minor sz-
mok esetben. Nzznk egy pldakdrszletet erre az esetre is:
#defineMSG_LEN 6
stat cchar*msgs[]={ "Szia!","mizu?"} ;
staticssize_thello_write(structfile*pfile,constchar*buf,
size_tcount,loff_t*ppos);
staticssize_thello_readl(structfile char*buf,
size_tcount,loff_t*ppos);
staticssize_thello_read2 (structfile*pfile,char*buf,
size_tcount,loff_t*ppos);
staticinthello_open(structinode*inode,structfile*pf le);
staticinthello_close(structinode*inode,structfile*pfile);
staticstructfile_operationshello_fops=
owner: THIS_MODULE,
read: hello_readl,
write: hello_write,
open: hello_open,
release:hello_close
} ;
staticstructfile_operationshellol_fops=
owner:

THIS_MODULE,
read:

hello_readl,
write:

hello_write,
364
7.5. Karakteres eszkzvezrl
open: hello_open,
release:hello_close
} ;
staticstructfile_operationshello2 _fops=
{
owner: THIS_MODULE,
read: hello_read2 ,
write: hello_write,
open: hello_open,
release:hello_close
} :
structfile_operations*hello_fops_array []=
&hellol_fops,
&hello2 _fops,
} ;
/*Azolv asasmuv eletetlek ezelofuggv eny .*/
staticssize_thello_readl(structfile*pfile,char*buf,
size_tcount,loff_t*ppos)
{ ntlen;
len=count;
if(count>MSG_LEN)len=MSG_LEN;
if(copy _to_user(buf,msgs[0],len))return -EFAULT;
returnlen;
/*Azolv asasmuv eletetlek ezelofuggv eny .*/
staticssize_thello_read2 (structf le*pfile,char*buf,
size_tcount,loff_t*ppos)
{
intlen;
len-count;
if(count>MSG_LEN)len=MSG_LEN;
if(copy _to_user(buf,msgs[1],len))return-EFAulT;
returnlen;
/*Amegny itasmuv eletetlek ezelofuggv eny .*/
staticinthello_open(structinode*inode,structfile*pfile)
{
intnum;
num=MINOR(inode->i_rdev );
if(num>=2 )return-ENODEV;
pfile->f_op=hello_fops_array [num];
7. fejezet: Fejleszts a Linux-kernelben
/*Nov elj uk ahasznalatiszamlalot.*/
try _module_get(THIS_mODuLE);
printk (DEVICE_NAME"open.\n");
return0;
_Y..-. --
A pldban kt eltr fggvnynk van a kt eszkzllomny olvassra. Azt
azonban mr tudjuk, hogy csak egy kezelfggvnyt llthatunk be egy fazo-
nostra, vagyis ez mindegyik mellkazonostnl ugyanaz lesz. Ezt a probl-
mt gy oldhatjuk meg, ha az open fggvnyben az adott helyzetre mdostjuk
a belltott kezelfggvnyeket.
A pldban a mellkazonost kinyerse utn eltr lekezelfggvny-
halmazt lltunk be az egyes viszonylatokra. A mellkazonostt indexknt hasz-
nlva a korbban belltott tmbbl ms-ms fggvnyhalmazt vlasztunk.
7.5.8. Az ioctl() i mplementcija
A Unix fjlabsztrakcis interfsznek elnye az egyszersg. Ugyanakkor az
egyes eszkzk ltal lehetv tett specilis belltsokhoz nem lehet a meg-
nyits, lezrs, rs s olvass mveletein keresztl hozzfrni. Ezt az lta-
lnos ioctl fggvny segtsgvel oldhatjuk meg.
Az ioctl fggvnnyel kzvetlenl parancsokat hajthatunk vgre az eszkz-
kezeln bell. Ezzel feloldhatjuk az ltalnos llomnymveletek korltait.
Ugyanakkor mrskelten ellenrztt, kzvetlen hozzfrst ad az eszkzve-
zrl bels funkciihoz, ezrt a kernelfejleszt'k biztonsgi kockzatot ltnak
benne, s nem igazn kedvelik. Ennek ellenre sok funkcit mg mindig gy
lehet a legjobban megoldani. Ugyanakkor kialakulban vannak jabb mecha-
nizmusok, amelyek rszben kivlthatjk az ioctl fggvnyt. Ilyenek pldul a
sysfs llomnyrendszeren keresztl elrhet eszkzattribtumok.
Az ioctl rendszerhvs kezelfggvnyt hasonlan tudjuk megvalstani,
mint a karakteres eszkzvezrl tbbi llomnykezel fggvnyt. Ltre kell
hoznunk egy fggvnyt, majd a mutatjt be kell lltanunk a file_operations
struktra adott mezjben. A fggvny alakja, amely egybknt a file_operations
struktra defincijbl derl ki, a kvetkez:
lengioctl(structfile*pfile,unsignedintcmd,unsignedlongarg)
m ha alaposabban megnzzk a file_operations struktrt, tbb olyan mezt
is tallhatunk benne, ahol az ioctl fggvny mutatjt bellthatjuk. Vegyk
ezeket sorra.
Az ioctl mez a 2 .6.37-es kernelig volt jelen. Az itt megadott fggvnyt
gy futtatja le a rendszer, hogy eltte lefoglalja a nagy kernelzrolst" (Big
Kernel Lock, lsd a 7.9.5. Olvas/r ciklikus zrols (spinlock) s szemafor
(semaphore) alfejezetban), majd a vgn felszabadtja. Ezzel a rendszer leke-
3 66
7.5. Karakteres eszkzvezrl
zeli a szinkronizcis problmk egy rszt, gy ezzel a fggvny ksztjnek
mr nem kell foglalkoznia. A nagy kernelzrols" megsznsvel azonban az
ioctl fggvny ilyen jelleg implementcija sem maradhatott meg, ezrt a
2 .6.37-es kernel ta nem hasznlhat.
Az unlocked_ioctl a jelenleg leggyakrabban hasznlt mez ioctl fggv-
nyek regisztrlsra. Ahogy a neve is tartalmazza, a rendszer nem vgez
szinkronizcit, gy az esetleges konkurenciaproblmkat neknk kell megol-
dani a fggvny megvalstsban.
A compat_ioctl a harmadik mez, amely mg elfordul. Jelentsge ak-
kor van, ha egy 64 bites rendszerben a 32 bites folyamatoknak szeretnnk
ioctl szolgltatst nyjtani. Ilyenkor a fggvnynk megvalstsakor fel kell
kszlnnk az eltr adatbrzols okozta problmkra.
A szinkronizcis s az adatkezelsi problmkat leszmtva a hromfle
ioctl i mplementci felptse hasonl. A fggvny gyakran egy switch-case
szerkezetet tartalmaz, amely a parancskd alapjn gazik el. Az gak az
egyes parancsok megvalstst kpezik.
Az ioct/O parancskdok sszelltsa az els feladatunk. Egyedi azonostt
kell megadnunk minden parancshoz, de nem clszer, hogy egyesvel elkezdjk
szmozni ket 1-tt kezdden. Ezzel ugyanis az a problma, hogy a felhasznl
tvedsbl az egyik eszkz parancskdjait felhasznlhatja egy msik tpus
eszkznl, amely rtelmezi a parancskdot, s teljesen mst csinl, mint amit
a felhasznli program ksztje szeretne. Mivel itt a kernel cmtartomnyban
garzdlkodunk", ezrt ez akr vgzetes is lehet a rendszer szempontjbl.
Az ilyen jelleg problmk elkerlshez clszer abban gondolkodni, hogy
a parancskdok egyediek legyenek, s az adott eszkzhz tartozzanak, ms
eszkzk pedig lehetleg ne rtelmezzk, s hibt adjanak vissza.
Kzenfekv megoldsnak tnik, amelyet a korai Linux-verzik hasznltak
is, hogy a 16 bites parancskdbl a fels byte legyen egy mgikus szm".loo gy
ez a szm az eszkz szma, az als byte pedig az eszkzn belli egyedi azo-
nost. Termszetesen ez nem garantlja a parancskd tnyleges egyedisgt,
m jelentsen lecskkenti a vletlen balesetek eslyt. A mgikus szmokrl
a Documentation lioca-number.txt llomnyban tallhatunk egy listt.
Egy potencilis hibaforrs azonban tovbbra is fennll. A rendszer nem
tudja ellenrizni, hogy az adott parancskdhoz megfelel argumentumot ad-
tunk-e meg utols paramterknt. Ugyanis a fordt ezt nem teheti meg, hi-
szen ltalnos pointereket hasznlunk, ezrt a feladat a kernelre pontosab-
ban a kernelmodul ksztjre hrul. A megolds az, ha minden argumen-
tumspecifikus informcit is belekdolunk a parancskdba, gy mr olyan l-
talnos ellenrz mechanizmus hasznlatra is lehetsg nylik, amelyet a
kernel is kpes tmogatni.
Nzzk meg vgl, melyek azok a paramterek, amelyeket manapsg a
parancskdok ellltsra hasznlnak (7.2. tblzat).
100
A mgikus szm" egy olyan szm, amelyet a felhasznl igyekszik egyedinek megvlasz-
tani.
367
7. fejezet: Fejleszts a Linux-kernelben
7.2. tblzat. Az IOCTL parancskdok ellltshoz hasznlt paramterek
Informci Jelents
type Egy mgikus szm, amelyet az adott eszkzhz vlasztottunk Mre-
te 1 byte.
number Egy 1 byte-os szm, a parancsnak az eszkzn belli egyedi azonostja.
Dir Az adatramls irnya: nincs adatramls, rs, olvass, mindkett.
Size Az argumentum mrete.
Az adatokbl a parancskdok ellltsban a kvetkez makrk segtenek:
#nclude <asm/ioctl .h>
_IO(ty pe,number)
_IOR(ty pe,number,dataitem)
_IOW(ty pe,number,dataitem)
_IOWR(ty pe,number,dataitem)
A makr nevnek az JO utni rsze adja meg az adatramls irnyt a fel-
hasznli oldal fell:
nincs
R: olvass
W: rs
WR: rs s olvass
A dataitem az argumentum tpusa vagy egy ugyanolyan tpus vltoz. Ebbl
a rendszer meghatrozza az architektra fgg mretet.
A 7.2. tblzatban szerepl egyes informcikat a parancskdbl a kvet-
kez makrkkal lehet visszafejteni:
_IOC_TYP E(cmd)
_IOC_NR(cmd)
_IOC_DIR(cmd)
_IOC_SIZE(cmd)
-9
~1~11111a
Ezek alapjn nzznk meg egy pldaheaderfjlt:
#define HELLO_IOC_MAGIC ' h '
#defineHELLO_IOC_INCREASE_IO(HELLO_IOC_MAGIC,0)
#defineHELIO_IOC_OECREASE_10(HELI0_IOC_MAGIC,1)
#defineHELLO_IOC_GET_IOR(HEILO_IOC_MAGIC,2 ,int)
#defineHELLO_IOC_SET_10W(HELLO_IOC_MAGIC,3 ,int)
368
7.5. Karakteres eszkzvezrl
A kvetkez feladatunk az ioca() fggvny implementcija. Nzznk erre is
egy pldt:
longhello_ioctl(struct file *pfile,unsignedintcmd,

unsignedlongarg)
f
intres=0;
i f(_IOC_TYP E(cmd)!=HELLO_IOC_MAGIC)return-ENoTTY;
if(_IOC_DIR(cmd)&_IOC_READ)
if(!access_ok (VERIFY_READ,(v oid*)arg,
_IOC_SIZE(cmd)))return-EFAULT;
elseif(_IOC_DIR(cmd)&_IOC_WRITE)
i f(!access_ok (v ERIFY_WRITE,(v oid*)arg,
_10C_SIZE(cmd)))return-EFAULT;
}
switch(cmd)
{
caseHELLO_IOC_INCREASE:
/*Muv elet1*/
break ;
caseHELLO_IOC_DECREASE:
/*Muv elet2 */
break ;
caseHELLO_IOC_GET:
/*Muv elet3 */
break ;
caseHELLO_IOC_GET:
/*Muv elet4*/
break ;
default:
return-ENOIOCTLCMD;
returnres;
}
A fggvny elejn megvizsgljuk a parancskdba kdolt informcikat: a m-
gikus szmot, az adatramls irnyt, az argumentum mrett. Majd ellen-
rizzk, hogy a kapott argumentum megfelel-e ezeknek a kritriumoknak.
Az argumentumok ellenrzst az access_ok() fggvnnyel vgeztk. En-
nek alakja a kvetkez:
#include <asm/uaccess.h
intaccess_ok (intty pe,constv oid*addr,unsignedlongsize)
369
7. fejezet: Fejleszts a Linux-kernelben
Az els argumentum (type) lehet VERIFY READ, VERIFY WRITE vagy a
kett bites vagy kombincija is a mvelet tpustl fggen. A msodik pa-
ramter (addr) a vizsglt argumentum cme. Az utols (size) az ltalunk vrt
adatterletmret. A visszatrsi rtk valjban egy logikai rtk. Ha sikeres
az ellenrzs, akkor 1, ha az ellenrzs problmt tallt, akkor O.
Ha az ellenrzs sorn minden rendben van, akkor egy elgazssal ms-
ms mveletet hajtunk vgre az egyes parancsokra. Ha az argumentum hi-
bs, vagy ismeretlen parancskdot kaptunk, akkor hibval trnk vissza.
A kezelfggvny implementcija utn mr csak regisztrlnunk kell a
fggvnyt az eszkzvezrlhz hasonlan, mint korbban a read vagy a write
fggvnyeket, ezttal a file_operations struktra unlockedioctl nev mezjn
keresztl.
7.6. A /proc llomnyrendszer
A Linux rendelkezik egy tovbbi mechanizmussal is, amellyel a kernel vagy a
kernelmodulok informcikat tudnak tadni a felhasznli zemmdban fut
folyamatoknak. Br a karakteres eszkzvezrlknl megismert mdszerrel is
megoldhatjuk a kommunikcit egy folyamat s egy kernelmodul kztt, m a
/proc llomnyrendszer hasznlata ezt leegyszersti. Eredeti feladata az,
hogy knnyen hozzfrhet informcit szolgltasson a processzekhez kapcso-
ld adatokrl (lsd a 2.3.1. A Linux processzekhez kapcsold informcik
alfejezetben). Manapsg a kernel minden olyan rsze hasznlja, amelyik va-
lamilyen hasznos jelentssel vagy statisztikval szolglhat. Tovbb mr
nemcsak olvashatjuk, hanem rhatjuk is egyes rszeit, gy szablyozva a ker-
nel s a modulok mkdst.
A metdus hasonlt az elzekben, az eszkzvezrlben hasznltakhoz. Itt
is egy struktrt kell ltrehoznunk, amely tartalmaz minden informcit,
amely szksges a /proc llomnyunkhoz, belertve a mutatt a kezelfgg-
vnyekre. Ha egy csak olvashat llomnyt szeretnnk ltrehozni, akkor csak
egy fggvnyt kell implementlnunk s belltanunk, amely az llomny ol-
vassakor meghvdik. A modul inicializlsakor regisztrljuk a ler struk-
trnkat, s a tisztogatfggvnyben eltvoltjuk.
A kvetkez pldamodul ltrehoz a /proc llomnyrendszerben egy hello"
llomnyt, amely egy dvzl szveget ad vissza, ha kiolvassuk a tartalmt:
/* helloproc.c -Egy szerukernel modul a /proc allomanyrendszer
hasznalatara. */
#include <1 i nux/modul e .
#include <1 nux/kernel . h>
#include <1 i nux/proc_fs h>
370
7.6. A /proc llomnyrendszer
/*Azallomany olv asasatlek ezelofuggv eny .*1
intprocfile_read(char*buffer,char**buffer_location,
off_toffset,intbuffer_length,int*eof,
v oid*procdata)
{
intlen;
/* Az egy szerusegk edv eertnemengedunk reszlegesolv asast.
Csak azallomany elej erol.*/
i f(offset)
{
*eof=1;
return0;
}
/*Feltoltj uk abuffertesv isszaterunk azadathosszav al.
len=sprintf(buffer,"Helloprocv ilag!\n");
returnlen;
}
/*Ak ernelmodulinicializalasatv egzofuggv eny .
staticint_inithello_in t(v oid)
structproc_dir_entry *hello_proc_ent;
/*Dinamik usanhozzuk letreaprocallomany bej egy zest.*/
hello_proc_ent=create_proc_entry ("hello", S_IFREGIS_IRUGO,
0);
/*Beallitj uk alink szamlalotesak ezelofuggv eny t.*/
if(!hello_proc_ent)
{
remov e_proc_entry ("hello",0);
printk ("Error: A /proc/hellonemletrehozhato.\n");
return -ENOMEM;
}
hello_proc_ent->nlink =1;
hello_proc_ent->read_proc=procfile_read;
printk ("A/proc/helloletrehozv a.\n");
return0;
/*Ak ernelmoduleltav olitasaelottafelszabaditasok atv egzi.*/
staticv oid_exithello_exit(v oid)
/*Megsemmisitj uk aprocallomany bej egy zest.*/
remov e_proc_entry ("hello",0);
printk ("A/proc/helloeltav olitv a.\n");
371
7. fejezet: Fejleszts a Linux-kernelben
module_init(hello_init);
module_exit(hello_exit);
MODULE_DESCRIP TION("Helloproc");
moDuLE_LicEN5E("GP L");
Lthat, hogy itt dinamikusan hoztunk ltre a proc llomnyler struktr-
bl egy elemet, amelynek belltottuk a linkszmlljt s az olvasst kiszol-
gl fggvnyt. A megsemmistst a neve alapjn vgezzk el.
Az olvasfggvny implementlsnl az egyszersg kedvrt csak a 0
eltolst fogadjuk el. Ilyenkor a paramterknt kapott bufferbe berjuk a sz-
veget, s a hosszval visszatrnk. Ha megnzzk a kdot, lthatjuk, hogy
ebben az esetben nem foglalkoztunk a kernel s s a felhasznli cmtarto-
mny kztti mozgatssal. Ennek az a magyarzata, hogy a fggvny megh-
vsakor bufferknt egy memrialapot kapunk. Miutn rrtuk az informcit,
a tartalma tmsoldik a felhasznli cmtartomnyba, gy a folyamatok el-
rik. Ezzel a megoldssal az implementci leegyszersdik, s a hibalehet-
sgek szma is cskken.
rhatv is tehetjk a virtulis llomnyunkat Ehhez szksg van az rs-
kor meghvott fggvny implementcijra. Ez hasonlt a karakteres eszkzve-
zrlknl megismertekre, belertve a kernel- s a felhasznli cmtartomny
kztti adatmozgatst is. A kvetkez pldaprogram megmutatja, hogyan hoz-
hatunk ltre rhat proc llomnyt:
/*helloproc2 .c-Egy szeruk ernelmodula/procallomany rendszer
hasznalatara.*/
#include<linux/module.h>
#include<linux/k ernel.h>
# nclude<linux/proc_fs.h>
#include<asm/uaccess.h>
Whill~~M~
1
~~1
#defineGBUFFERSIZE2 56
staticchargbuffer[GBuFFERsizE];
staticunsignedlonggbufferlen=0;
staticP EFINE_MUTEx(lock );
/*Azallomany olv asasatk ezelofuggv eny .*/
ntprocfile_read(char*buffer,char"buffer_location,
off_toffset, ntbuffer_length,int*eof,
v oid*procdata)
{
intlen;
/*Azegy szerusegk edv eertnemengedunk reszlegesolv asast.
Csak azallomany elej erol.*/
if(offset)
{
*eof=1;
return0;
372
7.6. A /proc llomnyrendszer
/*Feltoltj uk abuffertesv isszaterunk azadathosszav al.*/
if(down_interruptible(&lock ))return -ERESTARTSYS;
memcpy (buffer,gbuffer,gbufferlen);
l en=gbufferlen;
up(&lock );
returnlen;
}
intprocfile_write(structf le*pfile,constIhar*buffer,
unsignedlongcount,v oid*procdata)
{
if(count>GBUFFERSIZE)
count=GBUFFERSIZE;
}
if(down_ nterruptible(&lock ))return -ERESTARTSYS;
if(copy _from_user(gbuffer,buffer,count))
{
gbufferlen=0;
up(&lock );
return -EFAULT;
gbufferlen=count;
up(&lock );
returncount;
}
/* A k ernelmodulinicializalasatv egzofuggv eny .*/
staticint_inithello_init(v oid)
structproc_dir_entry *hello_proc_ent;
/*Dinamik usanhozzuk letreaprocallomany bej egy zest.*/
hello_proc_ent=create_proc_entry ("hello",
S_IFREGIS_IRUGOI S_IWUGO, 0);
/*Beallitj uk alink szamlalotesalek ezelofuggv eny t.
if(!hello_proc_ent)
{
remov e_proc_entry ("hello",0);
printk ("Error: A /proc/hellonemletrehozhato.\n");
return-ENOMEM;
}
hello_proc_ent->nlink =1;
hello_proc_ent->read_proc=procfile_read;
hello_proc_ent->write_proc=procfile_write;
hello_proc_ent - >mode=S_IFREGIS_IRUGOIS_IWUGO;
hello_proc_ent - >uid=0;
373
7. fejezet: Fejleszts a Linux-kernelben
hello_proc_ent->gid=0;
hello_proc_ent->size=2 56;
printk ("A/proc/helloletrehozv a.\n");
return0;
/*Ak ernelmoduleltav ol tasaelottafelszabaditasok atv egzi.
A /
staticv oid exithello_exit(v oid)
/*megsemmisitj uk aprocallomany bej egy zest.*/
remov e_proc_entry ("hello",0);
printk ("A/proc/helloeltav olitv a.\n");
module_init(hello_init);
module_exit(hello_ex t);
MODULE_DESCRIP TION("Hell0proc");
MODULE_LICENSE("GP L");
A pldban egy olyan proc llomnyt hozunk ltre, amely hasonlt a vals l-
lomnyokra. Vagyis amit belerunk, azt utna kiolvashatjuk belle. Ugyan-
akkor tartalmaz egyszerstseket is, gy nem teljes rtk implementci.
A virtulis llomny prhuzamos olvassa s rsa versenyhelyzetet ered-
mnyezhet, ezrt a pldban a globlis troltmbhz val hozzfrst szinkro-
nizcis eszkzzel kell szablyoznunk. A korbbi pldkban nem volt szksg
erre, mert a globlis vltoznkat csak olvastuk, ezzel szemben ebben a pld-
ban olvassuk s rjuk is prhuzamosan. A pldban ezt egy szemaforral tettk.
(A szinkronizcis eszkzket s hasznlati terletket egy ksbbi fejezetben
trgyaljuk, m a helyes implementcihoz szksg volt a hasznlatra.)
Ahhoz, hogy a folyamatok tnylegesen tudjk rni az llomnyt, az rst
kezel fggvny regisztrcija mellett arra is szksg van, hogy az rsjogot
megadjuk a felhasznlknak Az llomny ltrehozsnl lthatjuk, hogy a
pldban mindenkinek joga van rni a virtulis llomnyunkat.
Felmerlhet a krds: hogyan lehetsges az, hogy rhat az llomnyunk,
pedig nem is a /proc/sys knyvtr alatt tallhat. Az igaz, hogy ltalban az r-
hat proc llomnyok az emltett knyvtr alatt tallhatk, de ez csak konvenci.
Valjban a /proc knyvtr alatt tetszleges llomnyt tehetnk rhatv.
374
7.7. A hibakeress mdszerei
7.7. A hiba keress mdszerei
A hibakeressre kernelfejleszts esetben korltozottabbak a lehetsgeink,
mint egy alkalmazsnl. Mivel a kernelmodul a betlts utn a kernel szer-
ves rszt alkotja, ezrt ilyenkor lnyegben abban a programban kell hibt
keresnnk, amely a mkd rendszer kzponti eleme, s ugyanezen program
alatt futnak a hibakeressre hasznlt eszkzeink is. Ezrt a feladat jval bo-
nyolultabb, mint felhasznli cmtartomnyban.
A legegyszerbb s ugyanakkor leggyakrabban hasznlt mdszereket mr
megmutattuk. Mind a printk() fggvny, mind a /proc llomnyrendszer al-
kalmas arra, hogy informcit kzljnk a kernelmodul llapotrl, gy hasz-
nlhatk a hibakeresshez. Ezeken kvl lteznek kifinomultabb mdszerek
is, amelyekre ugyancsak mutatunk pldt ebben a fejezetben.
7.7.1. A prntk() hasznlata
A legegyszerbb s ezrt az egyik leggyakrabban hasznlt mdszer a hibake-
ressre, ha a lnyeges pontokon kirjuk az llapotokat. A kernel esetn ezt a
printkQ fggvnnyel tehetjk meg, majd a kernelnaplbl nzhetjk vissza.'"
A kernelnaplba rt zenetek klnbz fontossgak lehetnek. A hibake-
resshez ltalban minden szba jhet informcit kiratunk, ez pedig nagy
mennyisg naplbejegyzst eredmnyez. Viszont valsznleg kisebb a sz-
ma a fontos, konkrt hibt jelz zeneteinknek. Azrt, hogy ezeket a naplz-
sokat kzben tarthassuk, a Linux szintekbe szervezi a klnbz fontossg
zeneteket, ezt clszer neknk is alkalmaznunk a kirsaink sorn. Az albbi
szinteket klnbztetjk meg (7.3. tblzat):
7.3, tblzat. Kernel zenetek szintjei
Cmke rtk Ler s
KERN_DEBUG <7> A legkevsb fontos zenetek, amelyeket csak teszte-
lsnl hasznlunk.
KERN_INFO <6> Informcik a driver mkdsrl.
KERN_NOTICE
<5>
Nincsen gond, de azrt jelznk valamilyen emltsre
mlt szitucit.
KERN_WARNING <4 > Problms helyzet jelzse.
KERN_ERR <3> Hiba jelzse.
101
A kernelnaplt a dmesg paranccsal vagy a log llomnyokbl nzhetjk vissza. Tipikus
helye a /var/logimessages vagy /var/logisyslog llomny a syslog rendszer belltstl
fggen.
375
7. fejezet: Fejleszts a Linux-kernelben
Cmke rtk Lers
KERN_CRIT <2 > Kritikus hiba jelzse.
KERN_ALERT <1> Vszhelyzet, amely esetleg srgs beavatkozst ignyel.
KERN_EMERG <0> A legfontosabb zenetek. Tbbnyire a rendszer meg-
halsa eltt kapjuk.
A naplzrendszer lehetv teszi, hogy a ksbbiekben a fontossgi szint
alapjn szrjnk. Vagyis nem szksges a szoftveren mdostani, ha pldul
az egyszerbb hibakeressi zeneteket ki akarjuk kapcsolni.
A fontossgi szintek hasznlata a kvetkez:
printk(KERN_DEBUG "uzenet \ n") ;
A szrs belltsa az albbi:
echo 8 > /proc/sys/kernel/printk
A pldban a 8"-as rtk adja meg, hogy a KERN_DEBUG zeneteket is lt-
ni szeretnnk. Ahogy ezt a szmot cskkentjk, gy csak az egyre fontosabb
zeneteket lthatjuk. A 0" rtk azt jelenti, hogy csak a KERN_EMERG
zeneteket kapjuk meg.
Elfordul, hogy szeretnnk egy zenetben kirni, hogy ppen merre j-
runk a kdban. Termszetesen ezt megtehetjk gy, hogy a szvegbe beler-
juk a pozcit, m ltezik ennek automatizlt mdja is.
Pldul a forrskdllomny nevnek s sorszmnak kirsa a kvetkez:
printk(KERN_DERuG "Kod: %s:%
-
i \n", FILE , LINE )
Ha az ppen aktulis programkd pointerre vagyunk kvncsiak, vagyis ar-
ra, hogy a kirst vgz gpi instrukci hol tallhat a virtulis memriban,
a kvetkezt kell tennnk:
printk(KERN_DEBuG "Cim: Yop\n", ptr);
7.7.2. A /proc hasznlata
Az elz fejezetben lthattuk, hogyan valsthatunk meg olyan llapotelle-
nrzst, amikor is a kernelmodul adja a futsa sorn a jelzseket. Nha azon-
ban egy ilyen jelleg megolds olyan mennyisg llapotinformcival raszt
el bennnket, amelynek a kezelse knyelmetlen. Emellett a rendszer futst
is ersen lelassthatja egy ilyen jelleg kirsradat.
376
7.7. A hibakeress mdszerei
Ilyenkor a megolds az lenne, ha bizonyos idpontokban, amikor ppen
szksg van rjuk, megvizsglhatnnk az llapotvltozk aktulis rtkt,
vagyis igny szerinti lekrdezst alkalmaznnk. Ezt teszi lehetv a /proc l-
lomnyrendszer a virtulis llomnyain keresztl. Ennek implementcijt
korbban lthattuk. Az jdonsgot csak az jelenti, hogy a korbban megis-
mert mechanizmust hibakeressre is hasznlhatjuk.
A /proc llomnyrendszer mellett hasonl hatst rhetnk el az ioca0
rendszerhvs implementcijval is, amelyre most nem trnk ki. Az
ioca0
rendszerhvst azonban csak eszkzvezrl'knl alkalmazhatjuk, gy ltalnos
modulok esetben nem jrhat t.
7.7.3. Kernelopcik
A kernel fordtsa eltt, a konfigurlskor szmos hibarzkelsi mechaniz-
must bekapcsolhatunk. Ezeknek az opciknak a hatsra a fordts sorn
plusz hibarzkelsi s kezelsi algoritmusok fordulnak bele a kernelbe. gy
az ltalunk rt kd hibira knnyebben fny derlhet. A kernel hibarzkelsi
algoritmusainak egy j rsze azonban a plusz ellenrzsek miatt lasstja a
kernel mkdst, gy norml rendszerben nem hasznlhatk, ezrt alap-
esetben ki vannak kapcsolva.
A hibarzkelsi/kezelsi opcikat a kernelkonfigurci sorn a Kernel
Hacking" gban tallhatjuk meg. Minden opcihoz kapunk segtsget, amely
lerja az adott bellts ltal nyjtott szolgltatst. A lehetsges hibakeressi
opcik listja hossz, s kernelverzinknt vltozik, bvl, gy nem vllalko-
zunk a lista rszletes lersra s elemzsre. Az albbiakban sszegyjtt-
tnk nhny fontosabb opcit.
CONFIG_DEBUG_KERNEL: Bekapcsolja a hibakeressi opcikat.

CONFIG_MAGIC_SYSRQ: Bekapcsolja a magic SysRq" mechanizmust.


Ez segtsget nyjthat kritikus esetben a sttusz megvizsglsra.
(A magic SysRq" mechanizmusrl a 7.7.5. Magic SysRq alfejezetben
lesz sz rszletesebben.)
CONFIG_DEBUG_SLAB: Tovbbi ellenrzsek bekapcsolsa, ame-
lyekkel memriahasznlati hibk derthet'k fel. Specilis byte-rtkek
belltsval rzkelhetv teszi a memriainicializlsi s -tlrsi hi-
bkat.
CONFIG_DEBUG_SPINLOCK: Ciklikus zrols hasznlati hibk de-
tektlsa a feladata, pldul az inicializls elmulasztsa. (A ciklikus
zrolsi eszkzt a szinkronizls tmakrben trgyaljuk.)
377
7. fejezet: Fejleszts a Linux-kernelben
CONFIG_DEBUG_SPINLOCK_SLEEP: A ciklikus zrolsi eszkz le-
rsnl sz lesz arrl, hogy a ciklikus zrolst nem szabad olyankor
hasznlni, amikor a kritikus szakaszban sleepet hasznl fggvny
van. Ezzel az opcival kiderthetjk, ha mgis elkvettk ezt a hibt.
CONFIG_DEBUG_INFO: A hibakeressi informcik belefordtsa a
kernelbe. Ezt ksbb a gdb-vel hasznlhatjuk.
CONFIG_DEBUG_STACKOVERFLOW: A stacktlcsorduls rzkelse.
CONFIG_DEBUG_STACK_USAGE: A veremhasznlat monitorozsa,
statisztikk.
CONFIG_DEBUG_PAGEALLOC: A felszabadtott lapokat eltvoltja
a kernel memriaterletbl.
CONFIG_DEBUG_DRIVER: Az eszkzvezrlk kdjaiban bekapcsolja
a hibazenetek kirst.
Br nem a kernel hibakeressi szekcijban szerepelnek, m a hibakeress
szempontjbl hasznos opcik lehetnek az albbiak is:
CONFIG_KALLSYSMS: Ezen opci hatsra a szimblumok elrhe-
tek lesznek a /proc/kallsyms llomnyban.
CONFIG_IKCONFIG, CONFIG_IKCONFIG_PROC: Az aktulis ker-
nel konfigurcija elrhetv vlik a proc llomnyrendszeren keresz-
tl. gy ellenrizhetjk a belltsait, illetve az adott belltsokhoz
fordthatjuk a modulokat.
CONFIG_PROFILING: ltalban a rendszer finomhangolsra szol-
gl, de segthet a hibk feldertsben is.
7.7.4. Az Oops zenet
Ha a kernelben, kernelmodulokban slyos hiba trtnik, akkor a kernel ezt egy
Oops" zenettel jelzi. Termszetesen a slyos hiba eredmnyezheti a rendszer
teljes lefagyst, ez pedig odig fajulhat, hogy mg Oops" zenetet sem kapunk,
ez azonban manapsg ritka. Ugyanakkor attl, hogy a rendszer mkdkpes
marad, mg srlhet olyan mrtkben, hogy a tovbbi mkdse kiszmthatat-
lan lesz. Ezt az Oops" zenet jelzi is. Ilyenkor a hibazenet feldolgozsa utn
clszer a rendszert jraindtani. Ha ezt elmulasztannk, akkor furcsa" hib-
kat kaphatunk, amelyek lehetetlenn teszik a tovbbi hibakeresst.
Ahhoz, hogy az Oops" zenet knnyen rtelmezhet legyen, a kernelt a
CONFIG_KALLSYMS s a CONFIG_DEBUG_INFO opcik bekapcsolsval
kell fordtanunk. Szerencsre ezek az opcik tbbnyire a norml hasznlatban
lv kernelekben is be vannak kapcsolva, gy nem kell j kernelt fordtanunk.
378
7.7. A hibakeress mdszerei
Az albbiakban egy Oops" zenetet lthatunk (nhny sor elhagysval):
BUG: unabletohandlek ernel NULL pointerdereferenceat00000000
EIP: 0060:[<c06ae66a>] EFLAGS: 002 102 46CPU: 1
EIP isatiret_exc+0x6aa/0x97e
EAX: 00000000 EBX: 00000005 ECX: 00000005 EDX: 00000003
ESI: b8015000EDI: 00000000 EBP: f3 3 c5f68ESP: f3 3 c5f54
DS:007bES: 007bFS: 00d8 GS: 003 3 SS: 0068
P rocessbash(pid:8148,ti=f3 3 c5000task =f3 1e19a0
task .ti=f3 3 c5000)
Stack :000000050000000500000005f2 4b5600f90d3 047f3 3 c5f74
f90d3 05400000005f3 3 c5f90c0492 f18f3 3 c5f9cb8015000
f2 4b5600fffffff7b8015000f3 3 c5fb0c0493 00cf3 3 c5f9c
0000000000000000000000000000000100000005f3 3 c5000
CallTrace:
[<f90d3 047>]?hello_write+Ox0/0x2 9[buggy _driv er]
[<f90d3 054>]?hello_write+Oxd/0x2 9[buggy _driv er]
[<c0492 f18>]?v fs_write+0x84/0xdf
[<c0493 00c>]?sy s_write+Ox3 b/0x60
[<c0404c8a>]?sy scall_call+0x7/Oxb
A legels sor megmutatja, hogy pontosan milyen hiba is trtnt.
Az EIP rtke elrulja, hogy ppen melyik gpi utastsnl jrt a prog-
ram. Az rtelmezs egyszerstse rdekben nem memriacmet ad meg, ha-
nem a C fggvny nevt s az eltolst a fggvny belpsi pontjhoz kpest.
Esetnkben br a hiba az adott ponton kvetkezett be, a tnylegesen hibs
kd valjban nem ott van. Ebbl is lthat, hogy az EIP rtke nem felttle-
nl a hiba helyre mutat.
A Call Trace" mez tartalmazza az egymsba gyazd fggvnyhvso-
kat. Esetnkben itt talljuk meg azt a sort, amely a kernel egy msik rszn
a hibt okozta. Ez a sor a hello_write fggvnyben tallhat, s a fggvny
elejhez kpest a Oxd eltols krnykn van a problms utasts. Ezt onnan
tudjuk, hogy nem a megszaktskezel visszatrsnl talljuk a hibt, s
nem is a fggvny belpsi pontjnl. gy a hivatkozsi listban ez a kvetke-
z elem, amely jogosan gyans lehet szmunkra.
Mivel az eltols gpi utastsban rtend, ezrt mg meg kell fejtennk,
hogy ez konkrtan hol tallhat a C forrsban.
7.7.4.11. Az Aops" zenet rtelmezse kernel esetben
Ha a hibs kdrszlet a kernelben tallhat, s nem kln kernelmodulban,
akkor az elemzshez szksgnk lesz a vmlinux llomnyra, amely a kernel
fordtsakor keletkezik. Ez az llomny a kernel tmrtetlen, helyfgg
programkdja. gy az Oops" zenet ltal megadott cmeken tallhat utas-
tsok visszakereshetk belle.
A hibakeress a gdb program segtsgvel trtnik:
379
7. fejezet: Fejleszts a Linux-kernelben
Ezt kveten megkereshetjk a memriacmhez tartoz sort:
WftelidbY
De megkereshetjk a fggvny neve alapjn is:
(gdb) info line fuggveny
7.7.4.2. Az Oops" zenet rtelmezse kernelmodul esetben
Ha a problma egy kernelmodulban tallhat, akkor a feladatunk nehezebb.
Az elz esetben hasznlt umlinux llomny ekkor termszetesen nem tar-
talmazza a krdses rszeket. A problms rszek a modul llomnyban ta-
llhatk. Ugyanakkor az Oops" zenetben lv memriacmek pedig attl
fggnek, hogy a kernelmodult az adott helyzetben hova tlttte be a kernel,
amely termszetesen vltozhat. Vagyis van egy cmnk, de nem tudhatjuk,
hogy a binrisban ez melyik helyet jelenti.
gy hivatalos mdszer nincs is jelenleg erre a helyzetre. Szerencsre azrt
nmi gyeskedssel kiderthetjk a hinyz informcit.
Nyissuk meg a kernelmodult:
Mivel az Oops" zenetben mr a kernel visszafejtette az abszolt cmeket C
fggvnynevekre s eltolsokra, ezrt krdezzk le, hogy a kernelmodulban
most hol tallhat az a fggvny, amelyhez kpest az eltolst nzzk:
440.. 1 0:
1
Uniz htlons"
,
.
A kapott pozcihoz adjuk hozz az eltolst, s krdezzk le az gy kapott c-
met, amely a hibs sor:
Ez a parancs megad egy sorszmot a C-forrsban, amely a pldban a 17.
Nzzk meg, mi tallhat ott:
Ezzel eljutottunk a hibs sorig, s mr csak r kell jnniink, mirt addott a
hiba.
Ha esetleg szeretnnk az egsz fggvnyt assemblyben ltni s ellenriz-
ni, hogy mi tallhat az adott eltolsi ponton, akkor az albbi paranccsal fejt-
hetjk vissza a kdot:
380
7.7. A hibakeress mdszerei
7.7.5. Magic SysRq
Az elz fejezetben lttuk, hogy idnknt elfordulhat, hogy a rendszer Oops"
zenet nlkl teljesen lefagy. Ez rtelemszeren nagyban htrltatja a mun-
knkat, mert nincs semmi informcink a hibrl, legfeljebb annyi, amit ad-
dig a kernel a konzolra kirt.
Szerencsre azrt ilyenkor sem vagyunk teljesen elveszve. A Magic SysRq
mechanizmus rvn specilis gombkombincik lenyomsval egyszer pa-
rancsokat hajthatunk vgre. Ezekkel megvizsglhatjuk a rendszer aktulis
llapott. Termszetesen ez nagyon alacsony szint vizsglatot jelent, gy
mlyrehatbb ismereteket ignyel az gy rendelkezsre ll informci felhasz-
nlsa. PC esetn a specilis gombkombinci: ALT + SysRq s a parancs.
Nhny parancsot pldaknt bemutatunk, a teljes listt a kernel forrs-
ban a Documentation/sysrq.txt llomnyban tallhatjuk meg.
7.4 . tblzat. Magic SysRq parancsok
Parancs Lers
b Azonnal jraindtja a rendszert az llomnyrendszerek szinkronizlsa
s lecsatolsa nlkl.
c Rendszersszeomlst okoz a napl (crashdump) generlsa rdekben.
e SIGTERM szignlt kld minden folyamatnak az nit kivtelvel.
g
Elindtja a kgdb-t, ezltal lehetv tve a tvoli hibakeresst.
h Megjelenti a segtsget.
SIGKILL szignlt kld minden folyamatnak az nit kivtelvel.
1 Megmutatja az aktv CPU-stack backtrace informciit.
m Az aktulis memriainformcikat kirja a konzolra.
Az aktulis regiszterrtkeket kirja a konzolra.
s Az llomnyrendszereket szinkronizlja, kirja a buffer tartalmt.
t Az aktulis taszkok listjt s informciit kirja a konzolra.
u Csak olvashat mdban jracsatolja az llomnyrendszereket.
0 9 Belltja a konzol naplzsi szintjt. (Lsd a 7.7.1. A printkQ hasznlata
alfejezetben.)
A mechanizmust a kernelben engedlyezni vagy tiltani a /proc/sys/kernel/
sysrq virtulis llomny rsval lehet.
Ha gondjaink tmadnnak a SysRq gombkombinci hasznlatval, akkor
a parancskaraktert a /proc/sysrq-trigger virtulis llomnyba rva ugyanazt a
hatst rhetjk el:
e cho t > /proc/s y s rq-t ri gg e r
381
7. fejezet: Fejleszts a Linux-kernelben
7.7.6. A gdb program hasznlata
A gdb program hasznlata a kernel esetben jval korltozottabb, mint ahogy
az alkalmazsoknl megismertk. Figyelembe kell vennnk, hogy ebben az
esetben egy olyan alkalmazsban" keressk a hibt, amelyben ppen fut a
hibakeres alkalmazs is. Ezrt nincs lehetsgnk a folyamat meglltsra,
lptetsre, mert az hatssal lenne a hibakeres alkalmazsra is. Ezrt l-
nyegben csak egy pillanatnyi helyzetet rtkelhetnk ki
A mechanizmus a gdb program core llomnykezelst hasznlja. Ehhez
a kernel generl egy virtulis core llomnyt /proc/kcore nven. Igy a pa-
rancssor a kvetkezkppen nz ki:
gdbvmlinux /proc/kcore
Ezt kveten a gdb print utastsnak segtsgvel megnzhetjk a vltozk
aktulis tartalmt. m vegyk figyelembe, hogy az els megtekints utn a
gdb trolja az rtket a gyorsts rdekben. Vagyis ugyanannak a vltoz-
nak egy ksbbi lekrdezsben mr nem bzhatunk meg maradktalanul.
A modulok debugolsa nem megoldott ebben a mechanizmusban.
7.7.7. A kgdb hasznlata
Lehetsg van arra is, hogy egy msik gprl soros porton keresztl debu-
goljuk a kernelt. Az elz megoldshoz kpest gy nagyobb lehet a mozgste-
rnk, mivel interaktvan debugolhatunk.
A mdszer hasznlathoz szksg van egy kernelkiegsztsre (patch),
amelyet a rgebbi kernelverzik esetn r kell hznunk a kernelforrsra, az
jabb verzik esetn azonban mr tartalmazza a forrs. A kgdb elrhetsge
a kvetkez: http://kgdb.sourceforge.net .
A tvoli debugolshoz, meg kell adnunk a kommunikcira hasznlt soros
vonalat s annak belltsait. Ha belefordtottuk a kernelbe a kgdb-t, akkor a
kernel betltsekor, ha modulknt fordtottuk, a modul betltsekor meg kell
adnunk az albbi paramtert:
k gdboc=<tty -eszk z>,[baud]
Pldul:
k gdboc=/dev /tty 50,1152 00
Ha ezt elmulasztottuk volna, akkor utlagos belltsra is van lehetsg a
sysfs llomnyrendszeren keresztl:
echotty 5O>/sy s/module/k gdboc/parameters/k gdboc
382
7.7. A hibakeress mdszerei
Ezt kveten a debugzemmdot tbbflekppen is indthatjuk:
A kernel fordtsakor bellthatjuk, hogy automatikusan induljon el.
A kernel indtsakor egy paramter segtsgvel is elindthatjuk.
Menet kzben az SysRq +g billentykombincival indthatjuk.
Az elindtst kveten egy msik gprl soros porton keresztl a gdb prog-
rammal debugolhatunk. Ehhez termszetesen szksgnk van a mdostott
kernel vmlinux llomnyra is a tvoli gpen. A gdb elindtsa a hagyom-
nyos mdon trtnik:
4db :2ortInioc
Ezt kveten meg kell adnunk a soros kommunikci sebessgt, illetve hogy
melyik porton keresztl csatlakozzon a msik gpre:
setremotebaud1152 00
targetremote/dev itty 50
_ 411111111ffla
Amikor a gdb csatlakozik a msik gphez, akkor hasonlan az alkalmazsok
hibakeresshez megvizsglhatjuk a tesztelt rendszer bels llapott, vagy
elhelyezhetnk trspontokat a kernelben, s folytathatjuk a futtatst a t-
rspontig.
A kernelben trtn hibakeresshez jl hasznlhat mdszer, a modulo-
kat azonban ezzel a mdszerrel is nehzkes nyomkvetni, br nem lehetetlen.
Ha a soros port nyjtotta sebessget zavaran lassnak tallnnk, akkor
vannak hlzaton mkd megvalstsok is (kgdb over ethernet), m ezek
alaprtelmezsben nem rszei a kernelnek.
7.7.8. Tovbbi hibakeressi mdszerek
Az eddigi felsorolssal nem zrult le teljesen az eszkztrunk. A User Mode
Linux (UML, felhasznli mdban fut Linux) virtulis Linux rendszereket
kpes futtatni felhasznli folyamatknt egy valdi Linux rendszerben. Ezl-
tal az UML lehetsget nyjt arra, hogy a virtulis rendszerben teszteljnk
anlkl, hogy a vals rendszert veszlyeztetnnk. m ennl tbbre is kpes:
segtsgvel a Linux-kernelt mint egy felhasznli folyamatot debugolhatjuk.
gy a hibakeress olyan lesz, mint a felhasznli alkalmazsok esetben.
Az UML htrnya az, hogy begyazott rendszerek fejlesztsekor csak ak-
kor hasznlhat, ha a clgp architektrja megegyezik a fejleszti gppel, il-
letve a perifrik is ugyangy elrhetk. ltalban ez nehezen teljesthet
kvetelmny, de ilyenkor jl hasznlhat helyette a kgdb. Az UML msik
htrnya az arnylag munkaignyes rendszer-sszellts.
3 83
7. fejezet: Fejleszts a Linux-kernelben
Tovbbi kernel-zemmdbeli hibakeressi eszkz lehet mg az OHCI-
1394 Firewire port hasznlata, amelyen keresztl direkt hozzfrs nyerhet
a memrihoz, gy nagyon alacsony szint vizsglatokat vgezhetnk egy
msik gp segtsgvel.
7.8. Memriakezels a kernelben
7.8.1. Cmtpusok
A kernelprogramozs sorn tbb cmtpussal is tallkozhatunk. Ezrt clsze-
r megvizsglnunk, milyen cmtpusokat klnbztetnk meg. Ezek kzl
nem mindegyiket hasznljuk a kernelben, mivel a fizikai cm kzvetlen hasz-
nlata sszefrhetetlen a virtulis cmzs elveivel, de a tbbivel tallkozha-
tunk munknk sorn.
Fizikai cm: A processzor a memrihoz val hozzfrshez hasznlja.
Kernel-logikaicm: A kernel ltal hasznlt cmtartomny a norml al-
loklsoknl Fizikai cmknt kezeljk, viszont a legtbb architekt-
rn valjban a fizikai cmtl egy eltolssal tr el.
Kernel-virtuliscm: Valjban a kernel-logikaicm is egy virtulis
cm: lineris lekpezs fizikai cmre. A vmalloc -kal alloklt memri-
nl viszont a cmtartomny folytonossga fontosabb. Ezrt itt valdi
virtulis cmeket hasznlunk, amelyeknl nem garantlt a lineris
lekpezs.
Felhasznli virtulis cm: A felhasznli processzek sajt virtulis
cmtartomnnyal rendelkeznek. A felhasznli virtulis cm ebben a
cmtartomnyban egy hivatkozs.
Buszcm: Az architektrk ltalban a perifrik fizikai cmeit hasz-
nljk az adattvitelre. Ezrt a buszcm fizikai cm.
7.8.2. Memriaallokci
A kernelmodulokban a memriaallokcit leggyakrabban a kmalloc0 fgg-
vnnyel vgezzk. Ennek ltalnos alakja a kvetkez:
void* ktalloc(size-t sizo, flAgs);
384
7.8.Memriakezels akernelben
A flags mez rtke a leggyakrabban GFP KERNEL, m hasznlhatunk to-
vbbi rtkeket is:
GFP_ATOMIC: Norml esetben a kmalloe0 meghvhatja a sleep fgg-
vnyt. Ezzel a paramterrel ez nem trtnhet meg, a memriafoglals
atomi mvelett vlhat, ezrt a megszaktskezel fggvnyekben is
hasznlhat.
GFP_KERNEL: A szoksos allokcis metdus. Az allokci sorn a
kernel hasznlhat sleep fggvnyt.
GFP_USER: A felhasznli cmtartomnybeli lapok alloklsnl
hasznlatos alaprtelmezett bellts. Ettl a foglals mg nem a fel-
hasznli cmtartomnyban trtnik, mindssze ugyanazokkal a bel-
ltsokkal megy vgbe az allokci.
GFP_NOIO: Ugyanaz, mint a GFP_KERNEL, csak kzben nem haj-
tdnak vgre az 1/0 mveletek.
GFP_NOFS: Mint a GFP_KERNEL, csak kzben nem hajtdnak
vgre az llomnyrendszer-mveletek.
A felszabadtst minden esetben a kfree0 fggvny vgzi:
Igfree(voli *afidit'l; ffl~
A kmalloc0 ltal alloklt terlet a kernel logikai cmtartomnyba esik (ker-
nelbeli logikai cm), vagyis lnyegben fizikai cmeket hasznlunk egy elto-
lssal. A fizikai cm hasznlata megnehezti a lapokon tnyl allokcit,
mert megfelel mret sszefgg terletet kell tallni hozz a memriban.
Ezrt az allokci egyszerstsre a kernel indulskor a memrit tbb
klnbz mret rszre osztja. Ezek egy rszt konkrt, a kernelben gyak-
ran hasznlt lerstruktrk trolsra tartja fent, gy ezek allokcija gyors
lesz. A msik rszt ltalnos allokcik rszre, klnbz mret blokkokra
osztva alloklja. Ezt az allokcis stratgit hvjuk slab allokcinak. A Li-
nux-kernel tbb konkrt algoritmust is tartalmaz erre a feladatra, amelyek-
nek a mkdse eltr." Mivel a slab allokci algoritmusa sokfle lehet, a
konkrt jellemzk is eltrnek, hasznlatuk azonban egysges.
A kmalloc0 az ltalnos hasznlat blokkokat alkalmazza, azokbl azt a
legkisebb szabad blokkot osztja ki az allokcis krsre, amelybe mg belefr
az ignyelt terlet. Vagyis a krnalloe0 lnyegben nem is allokl, csak a szabad
blokkok kzl osztogat. Ebbl is lthatjuk, hogy az ltala kiosztott terlet v-
ges, ezrt vatosan kell bnnunk vele, s kerlnnk kell a memriaszivrgst.
102
Az eredeti SLAB algoritmus helyett manapsg a SLUB hasznlata az elterjedt. Emellett
mg a SLOB (SimpleList Of Blocks) algoritmus is vlaszthat, amely a kicsi, begyazott
rendszerek szmra elnys.
385
7.fej ezet:Fej leszt saLinux-k ernelben
A kmalloc0 hasznlata sorn az albbi korltokra figyeljnk:
A blokkok mrete elre rgztett: tipikusan a 2 hatvnyai; az egyre
nagyobb blokkokbl pedig egyre kevesebb van. A minimum s a ma-
ximum mret ltalban 8 byte s 8 kilobyte.
Ha nagyobb memriaterletre van szksg, akkor a vmallocQ-kal al-
loklhatunk a virtulis memribl.
A msik lehetsg nagymret allokcik esetn az, ha teljes lapot
vagy tbb lapbl ll sszefgg rszt krnk.
Ez utbbi kt lehetsgre mutatunk nhny fggvnyt. Mint az elz felsoro-
lsban is szerepelt, ha nagy egybefgg terletre van szksgnk, akkor a
vmalloc() fggvnnyel alloklhatunk a virtulis cmtartomnybl:
v oid*v mal1oc(unsignedlongsize);
Ilyenkor a felszabadts a ufree() fggvnnyel trtnik:
vold vfrea(void* addr);
A vmalloc0-nl nagyobb teljestmnyt rhetnk el, ha egy lapot vagy tbb
lapbl ll folytonos terletet alloklunk az albbi fggvnyekkel:
unsignedlongget_zeroed_page(gfp_tgfp_mask );
unsignedlong__get_free_page(gfp_tgfp_mask );
unsignedlong_get_free_pages(gfp_tgfp_mask ,unsignedintorder);
Az els fggvny egy nullkkal telert lapot ad vissza. A msodik hasonl az
elshz, de nem inicializlja a terletet. A harmadik fggvnnyel kaphatunk
vissza tbb lapbl ll terletet. Mivel azonban a lapok szmnak 2 egsz
szm hatvnynak kell lennie, ezrt a visszaadott lapok szma a kvetkez-
kppen addik: lapszm = 2^order.
A lap(ok) felszabadtst az albbi fggvnyekkel vgezzk:
v oidfree_page(unsignedlongaddr);
v oidfree_pages(unsignedlongaddr,unsignedintorder);
7.9. A prhuzamossg kezelse
A kernelfejleszts sorn is tallkozhatunk olyan helyzetekkel, amikor a pr-
huzamos vgrehajts miatt szinkronizcira van szksg. Ilyen esetek a k-
vetkezk:
3 86
7.9. A prhuzamossg kezelse
Ha megszaktskezelben hasznlunk olyan vltozkat, amelyek ms-
hol is hozzfrhetk a rendszerben.
Ha a kdunk sleep() rendszerhvst tartalmaz. Ez tulajdonkppen azt
jelenti, hogy a fggvnynk futst meglltjuk az adott ponton, s ms
folyamatokra vlt t a kernel. (Van tbb olyan ms rendszerhvs is,
amely hasznlja a sleep() fggvnyt. Lttuk, hogy a kmalloc() is ilyen,
ha nem a GFP ATOMIC kapcsolt hasznljuk, de a copy_from_user() is
idetartozik.)
Ha kernelszlakat hasznlunk.
Ha tbbprocesszoros rendszert hasznlunk. (Ide tartoznak a tbbma-
gos processzorok s a tbbszl processzorok is.)
A prhuzamossg problminak kezelshez olyan szinkronizcis eszkzkre
van szksgnk, amelyek a klcsns kizrst valstanak meg. A Linux-ker-
nelben tbb ilyen eszkzt is tallunk, ezeket tipikus alkalmazsi terletkkel
egytt a kvetkez fejezetekben mutatjuk be.
7.9.1. Atomi mveletek
A legegyszerbb szinkronizci, ha nincs szksgnk szinkronizcis eszkz-
re. Ezt gy rhetjk el, ha a mveletnk atomi, vagyis gpikd-szinten egy
utastsban valsul meg. gy nincs olyan veszly, hogy a mvelet vgrehajt-
sa kzben egy msik processzoron fut msik kd hatssal lesz a mvele-
tnkre, mivel az egy lpsben valsul meg.
Annak eldntshez, hogy a mvelet atomi-e, gpikd-szinten kell megvizs-
glnunk. Ebbl addan platformfgg s C-fordt-fgg, hogy egy mvelet
tnyleg atomi lesz-e. A kernel platformfgg, assembly rszeiben gondoskodha-
tunk arrl, hogy teljesljn a mveleteinkre ez a felttel. m a platform-
fggetlen kernelrszek szmra is lehetv kellett tenni, hogy garantltan
atomi mveleteket hasznlhassanak. Ezt a kernel fejleszti egy atomi tpus s
a rajta rtelmezett fggvnyek definilsval rtk el. Amikor a kernelt egy j
platformra ltetik t a fejlesztk, akkor ezeket a fggvnyeket az adott archi-
tektrnak megfelelen kell megvalstaniuk gy, hogy a vgeredmny valban
atomi legyen, vagy megfelelen szinkronizlt. Elfordulhat, hogy egy adott plat-
formon az implementci a hagyomnyos mveleteknl lassabb. Ezrt az atomi
mveleteket csak ott hasznljuk, ahol tnyleg szksg van rjuk.
Az atomi mveletek egyszerek, klnben nem lehetne egy gpi utasts-
ban elvgezni ket.
103
Ezrt az atomi fggvnyek halmaza csak egsz szmo-
kon rtelmezett rtk nvel/cskkent/tesztel s bitmveleteket tartalmaz.
103
Ez nem jelenti azt, hogy minden atomi mvelet minden processzortpuson egy gpi utas-
tsra fordul le. m a lista sszelltsa sorn egy-egy processzor utastskszletbl in-
dultak ki a fejlesztk.
387
7. fejezet: Fejleszts a Linux-kernelben
Az egsz szmot kezel atomi fggvnyek csak az atomic_t adattpuson
rtelmezettek, amely egy eljeles egsz szmot tartalmaz. Ms, hagyomnyos
tpusokkal nem hasznlhatk. Tovbb az atomi adattpuson nem hasznlha-
tk a hagyomnyos opertorok sem. Az atomic_t tpus vltozt csak az ATO-
MIC_INITO makrval inicializlhatjuk. Pldul:
" :*tiitte 4" 4,atitbil
-
';~t~ilia~
Az albbi atomi egszszm-mveleteket hasznlhatjuk (7.5. tblzat):
7.5. tblzat. Atomi egszszm-mveletek
Fggvny Ler s
atomic_read(atomic_t *u) Az atomi rtk kiolvassa.
atomic_set(atomic_t *v, int i) Az atomi rtk belltsa i-re.
void atomic_add(int i, atomic_t *v) Hozzadja i-t v-hez.
void atomic_sub(int i, atomic_t *u) Kivonja i- t
void atomic_inc(atomic_t *u) Megnveli 1- gyel v rtkt.
void atomic_dec(atomic_t *v) Cskkenti 1- gyel v rtkt.
int atomic_add_return(int i, atomic_t *v) Hozzadja i - t v-hez s visszaadja az
eredmnyt.
int atomic_sub_return(int i, atomic_t *v) Kivonja i-t v-bl, s visszaadja az
eredmnyt.
int atomic_inc_retu.rn(atomic_t *v) Nveli a v rtkt 1-gyel, s vissza-
adja.
int atomic_dec_return(atomic_t *v) Cskkenti a v rtkt 1-gyel, s visz-
szaadja.
int atomic_add_negative(int i, atomic_t *v); Hozzadja i-t v-hez. Ha az eredmny
negatv, akkor igaz, egybknt ha-
mis rtkkel tr vissza.
int atomic_sub_and_test(int i, atomic_t *v); Kivonja i-t v-bl. Ha az eredmny 0,
akkor igaz, egybknt hamis rtk-
kel tr vissza.
int atomic_inc_and_test(atomic_t *0) Megnveli 1-gyel v rtkt. Ha az
eredmny 0, akkor igaz, egybknt
hamis rtkkel tr vissza.
int atomic_dec_and_test(atomic_t *u) Cskkenti 1-gyel v rtkt. Ha az
eredmny 0, akkor igaz, egybknt
hamis rtkkel tr vissza.
int atomic xchg(atomic_t *v, int i); Belltja v-t i-re, s v korbbi rt-
kvel tr vissza.
int atomic_cmpxchg(atomict *v, int u, int i); Ha v rtke megegyezik u-val, akkor
belltja v-nek az i rtkt. A vissza-
trsi rtk a rgi rtke a v-nek.
388
7.9. A prhuzamossg kezelse
Fggvny Lers
int atmnic_add_unless(atontic_t *u, int i, int u); Ha v rtke nem egyenl u-val,
akkor i-t hozzadja v-hez, s igaz
rtkkel tr vissza. Egybknt a
visszatrsi rtke hamis.
Az atomi mveletek msik csoportjt a bitmveletek alkotjk. A bitmveletek
unsigned long tpus rtkeket kezelnek, s egy memriacmmel megadott
memriaterleten vgzik el a mveletet annyi byte-ra rtelmezve, amennyi
az unsigned long tpus mrete az adott architektrn. A byte-sorrend (little-
endian, big-endian) rtelmezse szintn az architektrtl fgg annak a
byte-sorrendjvel egyezik meg. Ez sajnos azt jelenti, hogy a bitmveletek
platformfggk.
A bitrtkeket az albbi fggvnyekkel llthatjuk be:
void set_bit(unsigned long nr, volatile unsigned long * addr)
void clear_bit(unsigned long nr, volatile unsigned long * addr);
void change_bit(unsigned long nr, volatile unsigned long * addr);
A fggvnyek rtelmezse sorrendben az nr bit belltsa, trlse, tlltsa.
Az rtkbelltst kombinlhatjuk ellenrzssel is:
inttest_and_set_bit(unsignedlongnr,
v olatileunsignedlong*addr);
inttest_and_clear_bit(unsignedlongnr,
v olatileunsignedlong*addr);
inttest_and_change_bit(unsignedlongnr,
__ v olatileunsignedlong*addr);_ _
A fggvnynevek is utalnak arra, hogy elszr az adott bit rtknek vizsg-
lata trtnik meg, s ezt kveti az rtk lltsa. Ha a rgi bitrtk 1, akkor
igaz a visszatrsi rtk, egybknt hamis.
7.9.2. Ciklikus zrols (spinlock)
A ciklikus zrols (spinlock) egy olyan szinkronizcis eszkz, amely folyama-
tosan, egy CPU-t terhel ciklusban ksrletezik a zrols megszerzsvel min-
daddig, amg meg nem szerezte. Ezrt csak rvid kritikus szakaszok esetn
hasznljuk, egybknt a vrakoz szlak/folyamatok szmottev mrtkben
pazarolnnk a CPU-t. Ugyanakkor a rvid szakaszok esetben hatkonyabb,
mint az sszetettebb szemafor. Tovbbi elnye az, hogy egyprocesszoros rend-
szernl res szakasszal helyettesti a rendszer, ugyanis ott nincs szksg
ilyen jelleg szinkronizlsra.
389
7. fejezet: Fejleszts a Linux-kernelben
Ugyanakkor figyelnnk kell arra, hogy a ciklikus zrolssal vdett kriti-
kus szakasz ne tartalmazzon sleep0-et hv fggvnyt. Ha ugyanis egy szll
folyamat lefoglalja a zrolst, s sleep0 miatt egy olyan szl/folyamat kapja
meg a vezrlst, amelyik szintn megprblja megszerezni a zrolst, akkor
CPU-pazarlan vr r a vgtelensgig. Szlssges esetben ez holtponthoz s
gy a rendszer lefagyshoz vezet. Az elz pldval analg eset llhat el, ha
megszaktskezel fggvnyben hasznlunk ciklikus zrolst. Ezrt megsza-
ktskezelben ersen ellenjavallt a ciklikus zrols alkalmazsa.
Egy ciklikus zrols ltrehozsa az albbiak szerint trtnhet:
_ _ Oxi
Ezt kveten inicializlnunk kell:
s pi rt.:11;x1L3 ni t U1 pc ;
m a ltrehozst s az inicializlst egy lpsben egy makrval is elvgezhet-
jk, st rdemesebb ezt a megoldst vlasztani:
~4 ~INF-3~1-0(.1W Ock) ;-
Lefoglalsa a kvetkez:
..01111.
-
0tV411ic.) ;
Felszabadtsa pedig az albbi:
stvirt_ mrtydkal:04c):
Elfordulhat, hogy a kritikus szakasznl arrl is gondoskodnunk kell, hogy pr-
huzamosan ne hvdhasson meg egy megszaktskezel. A megszaktskezels
tmeneti letiltst s engedlyezst az albbi fggvnyekkel tehetjk meg:
spi n_ unl ock_ i rgrestore(&lock, flags);
11111
1~1~-.
Tapasztaltabb programozknak gyans lehet, hogy a spin_lockirqsave0 mso-
dik paramtereknt nem a flags vltoz mutatja szerepel. Ez nem nyomdahi-
ba. A bemutatott fggvnyek valjban makrk, ezrt valjban nem rtk
szerinti tadst lthatunk, hanem a vltozt adjuk t.
unsi gned 1 ong fl ags ;
spi n_ 1 ock_ i rqsave (8,1ock , flags);
390
7.9. A prhuzamossg kezelse
7.9.3. Szemafor (semaphore)
A szemafor (senzaphore) a ciklikus zrolsnl sszetettebb mechanizmus,
ezrt tbb erforrst is ignyel. gy a nagyon rvid szakaszok esetn inkbb
a ciklikus zrolst rszestjk elnyben. Ugyanakkor a komolyabb esetekben,
illetve ha a ciklikus zrols a megktsei miatt nem hasznlhat, akkor ez a
helyes vlaszts.
Figyeljnk arra, hogy a semaphore a vrakozshoz sleepQ fggvnyt
hasznl, gy nem alkalmazhatjuk olyan helyen, ahol a sleep()-es fggvnyek
tiltottak.'"
A semaphore ltrehozsa a kvetkez:
Struct sema phor e m m ;
Inicializlsa eszerint trtnik:
rfrtid
siminiltCs:tmct va3.).;
A ltrehozst s az inicializlst kombinl makr az albbi:
static DerINLSOIMORk(sem);
A val paramter a szemafor kezdrtkt adja meg.
A szemafor lefoglalsakor lehet, hogy vrakozsra knyszerl a fggvny.
m attl fggen, hogy ezt a vrakozst mi szakthatja meg, tbb fggvny is
vlaszthat a lefoglalsra.
Egyszer lefoglals az, amikor csak a szemafor felszabadulsa vet vget a
vrakozsnak:
00
.
(5tr4 1:kt..se~tore
Ha egy jelzs megszakthatja a vrakozst (ilyenkor -EINTR a visszatrsi
rtke):
itt* .4 S,WIUMW.1%ii tible(St
-
rilCt. $fflOritgire: '
11
'4 004
Ha kritikus szignl szakthatja csak meg:
ticiWn.*17141~.~tiotk
10
' Nem hasznlhatunk sleep0-es fggvnyeket pldul a megszaktskezel fggvnyekben
(hardver- s szoftver-megszaktskezelk). Emellett ciklikus zrols ltal vdett szaka-
szokban sem.
391
7. fejezet: Fejleszts a Linux-kernelben
Ha nem akarunk vrakozni, hanem csak egy hibajelzst szeretnnk, ameny-
nyiben nem lehet lefoglalni:
500110e *$.210;
Ha idkorltos vrakozst szeretnnk:
intdow niM eout(w uct sem aph re *sem ,long jiffies);
Az idkorlt mrtkegysge jiffy. (Lsd a 2.3.9. Id s idztk alfejezetben.)
A szemafor elengedse a kvetkez:
uraid up(stNct semaph re*sem);
7.9.4. Mutex
A kernelfejlesztk a szemafort tbbnyire 1 kezdrtkkel mutexknt klcs-
ns kizrs megvalstsra hasznljk olyan esetekben, ahol a ciklikus zro-
ls nem alkalmazhat. Ha azonban nem hasznljuk ki teljesen a funkciit,
akkor lehetsges egy egyszerbb megvalsts is, amellyel valamelyest jobb
lesz a rendszer teljestmnye. Ilyen megfontols vezette a fejlesztket, amikor
bevezettk a kernel mutexeszkzt.
A kernelfejlesztsek sorn a mutex azokban az esetekben hasznlhat,
ahol egybknt szemafort hasznlnnk a klcsns kizrsra.
A megktsek nagyrszt a szemafor megktseivel azonosak, ugyanakkor
vannak j elemek is:
Csak a lefoglal szabadthatja fel.
Rekurzv foglals vagy tbbszrs felszabadts nem engedlyezett.
Nem hasznlhat megszakts kontextusban. (Vagyis sem hardver-,
sem szoftvermegszaktst kezel fggvnyben.)
A mutex tpusa az albbi:
,%t
Inutglci
Inicializlsa a kvetkez:
inutex
~ ttm utW). ;
-

A ltrehozs s az inicializls a kvetkez makrval trtnhet:
WINP.iltilliTEXONt) ;
392
7.9. A prhuzamossg kezelse
A mutex lefoglalsa gy nz ki:
v oidmutex_lock (structmutex*lock);
A mutex lefoglalsa, ha a vrakozst jelzssel megszakthatv szeretnnk
tenni, a kvetkez:
1~14
1
1,4 4
.
012 41jtitii;
A mutex lefoglalsa, ha sikertelensg esetn nem vrakozni akarunk, hanem
hibavisszajelzst szeretnnk kapni:
int mutex_try lock (structmutex*lock );
A mutex felszabadtsa az albbi:
11115~11


A mutex foglaltsgnak ellenrzse pedig eszerint trtnik:
-
int mutex_is_locked(struct mutex * lock);
7.9.5. Olvas/r ciklikus zrols (spinlock) s szemafor
(semaphore)
A kritikus szakasznl clszer megklnbztetnnk, hogy a szakaszon bell
a vdett vltozt rjuk vagy olvassuk. Mivel ha csak olvassuk az rtket, ak-
kor azt prhuzamosan tbb szl is problma nlkl megteheti (megosztott z-
rols). Mg ha rjuk, akkor msik szlnak sem rni, sem olvasni nem szabad
(kizr zrols). A kt eltr zrols hasznlatval nvelhetjk a rendszer
teljestmnyt.
Az olvas/r ciklikus zrols ltrehozsa s inicializlsa a kvetkez:
rwlock_t rwlock ;
rwlock_i ni t (&rwlock) ; 1111~1~1~1~"
A ltrehozst s az inicializlst kombinl makr:
stati C DEF/NE_RWLOCK( rwl ock)
- ~~~=.
Olvassi (megosztott) zrols:
read_lock (&rwlock );
read_unlock (&rwlock );
3 93
7. fejezet: Fejleszts a Linux-kernelben
rsi (kizr) zrols:
write_lock (8irwlock );
write_unlock (&rwlock );
Az olvas/r szemafor ltrehozsa:
structrw_semaphorerwsem;
Inicializls:
v oid nit_rwsem(structrw_semaphore*sem);
Lefoglals olvassra:
v oiddown_read(structrw_semaphore*sem);
ntdown_read_try lock (structrw_semaphore*sem);
Felszabadts olvass esetn:
v oidup_read(structrw_semaphore*sem);
Lefoglals rsra:
v oiddown_write(structrw_semaphore*sem);
intdown_write_try lock (structrw_semaphore*sem);
Felszabadts rs esetn:
v oidup_wrte(structrw_semaphore*sem);
Elfordulhat, hogy egy olvassi zrolst felszabadts nlkl rsi zrolsra
szeretnnk talaktani, m erre a Linux-kernel implementcijban nincs le-
hetsg: ilyen jelleg prblkozs holtpontot okoz.
Ugyanakkor az rsi zrolst brmikor visszalptethetjk" olvassi zro-
lsra:
void downgrade_wri te(struct rw_semaphore *sem) ;
7.9.6. A nagy kernelzrols
A nagy kernelzrols (Bg Kernel Lock) egy globlis rekurzv ciklikus zrols.
Hasznlata nem javasolt, mivel rtelemszeren jelentsen korltozza a ker-
nel mkdst, s rontja a rendszer valsidejsgt, ugyanis akadlyozza a
kernel prhuzamos mkdst.
394
7.10.1/0 mveletek blokkolsa
Ez a zrolsfajta a 2 .0-s verzitl volt jelent a kernelben, amikor a tbbpro-
cesszoros rendszerek tmogatsa belekerlt (symmetric multiprocessing, SMP).
A lehetsges konkurenciaproblmkat gy elztk meg a fejlesztk, hogy
kernelzemmdban az egsz kernelt zroltk. Ezzel kivdtk, hogy egy msik
processzor is futtasson prhuzamosan kernelmd kdot. A konkurenciaprobl-
mk kezelsre szles krben alkalmaztk, mert segtsgvel gymond biztos-
ra lehetett menni", s nem kellett vgiggondolni az adott konkurenciahelyzetek
hatsait. Ugyanakkor ez egy tmenetinek sznt megolds volt, amelynek a
helyt ksbb tgondoltabb, kifinomultabb megoldsok vettk t. Az idk fo-
lyamn egyre tbb helyrl sikerlt kiszortani, s vgl a 2 .6.37-es verziban
sikerlt vgleg eltvoltani. Br lehetsg van r, hogy a kernel konfigurci-
ja sorn visszakapcsoljuk, ez rtelemszeren nem javasolt.
A teljessg kedvrt azonban a nagy kernelzrols lefoglal s felszabad-
t fggvnyeit is megemltjk:
1 ock_ ke rnel 0 ;
unl ock_ kernel () ;
_
7.10. I/O mveletek blokkolsa
Az eszkzvezrlknl gyakran felmerl problma, hogy vrakoznunk kell a
hardverre, hogy vgre tudjunk hajtani egy mveletet. Ennek leggyakoribb
formja, hogy a felhasznli alkalmazs mr olvasn az adatokat, de mg
nem kaptunk meg mindent az eszkztl. Nem clszer hibajelzssel vissza-
trnnk, mert akkor ismtelten meg kell hvnia az olvasst/rst vgz fgg-
vnynket Azt az utastst sem adhatjuk, hogy itt az llomny vge, mert
nem igaz. Helyette blokkolnunk kellene a fggvnyt, s csak akkor kellene
visszatrnie, amikor mr van adatunk.
Ez a megolds mr ismers lehet az alkalmazsfejlesztsbl, hiszen szmos
fggvnynl tapasztalhattuk, hogy csak akkor trnek vissza, ha megrkezett az
adat. Most megvizsgljuk, hogyan tudjuk ezt a mkdst kerneloldalon meg-
valstani.
Termszetesen nem clszer a kdunkba egy vrakoz ciklust tenni, mert
ez a vrakozs idejre teljesen lefoglalna egy CPU-t. Ha csak egyetlen CPU van
a gpnkben, akkor ez egyenl a rendszer lefagysval. Helyette egy sleep jel-
leg vrakozst kell vlasztanunk, vagyis a vrakozs idtartamra enged-
jk, hogy ms folyamatok fussanak, mg a minket hv folyamat alszik. Majd
amikor az esemny bekvetkezik, akkor felbresztjk, s folytathatja a m-
kdst. Erre a kernel a kvetkez hatkony megoldst biztostja. A 2.3.2.
A processz llapotai alfejezetben emltettk a processz llapotait. Ha egy pro-
cessz egy adott esemnyre vrakozik, a kernel vrakozsi llapotba lltja a
395
7. fejezet: Fejleszts a Linux-k ennelben
processzt, s elhelyezi egy ktszeresen lncolt listba. Ha egy jelzs felb-
reszti" ezeket a folyamatokat, ezek ellenrzik, hogy az esemny, amelyre v-
rakoznak, bekvetkezett-e. Ha nem, akkor maradnak a vrakozsi sorban, ha
igen, akkor eltvoltjk magukat a vrakozsi sorbl.
A vrakozsi sor programozsa egy ugyanilyen nev, gynevezett vrako-
zsisor- (wait queue) vltozt ignyel a Linuxban.
Ennek ltrehozsa s inicializlsa a kvetkez:
wait_queue_Wead_twait_queue;
init_waitqueue_head(&wait_queue);
-~~~-
Ha statikusan hozzuk ltre, vagyis nem egy fggvny loklis vltozja, illetve
dinamikusan alloklt struktra rsze, akkor a kvetkez makrval fordtsi
idben is elvgezhetjk a ltrehozst s inicializlst:
DECLARE_WAIT_QUEUE_HEAD(wait_queUe);
7.10.1. Elaltats
Miutn ltrehoztuk a vrakozsisor-vltozt, a segtsgvel elaltathatjuk a
processzeket a kvetkez fggvnyek valamelyikvel:
sleep_on(wait_queue_head_t*queue);
1111111~~1111111~11-:
A processzt a sleep fggvny segtsgvel esemnyre vrakoz llapotba kldi,
s behelyezi a vrakozsi sorba. Htrnya ennek a fggvnynek, hogy jelzsek-
kel nem szakthat meg, ezrt a processz beleragadhat az adott mveletbe.
interruptible_sleep_on(wait_queue_head_t*queue);
Mkdse megegyezik a sleep_on() fggvnyvel, de jelzsek megszakthat-
jk. Az eszkzvezrlkben az egyik leggyakrabban hasznlt fggvny a blok-
kolsra:
sleep_on_timeout(wait_queue_head_t*queue,longtimeout);
Ez a sleep_on() timeoutos vltozata. Vagyis a megadott idnl tovbb nem vra-
kozik. Az id jiffyben van megadva. (Lsd a 2.3.9. Id s idztk alfejezetben.)
interruptible_sleep_on_timeout(wait_queue_head_t*queue,
__ _ longtimeout); _
Ez az interruptible_sleep_on() timeoutos vltozata (lsd az elzt):
3 96
7.10. I/O mveletek blokkolsa
wait_ev ent(wait_queue_head_tqueue,intcondition);
wait_ev ent_timeout(wait_queue_head_tqueue,intcondition,
longtimeout);
Ez a makr kombinlja a vrakozst s a felttel tesztelst. Mindezt gy,
hogy a kritikus versenyhelyzeteket kizrja. Hasznlatakor a folyamat csak
akkor bred fel tnylegesen, ha a felttel (condition) igaz rtk:
wait_ev ent_interruptible(wait_queue_head_tqueue,intcondition);
wait_ev ent_interrupt ble_timeout(wait_queue_head_tqueue,
intcondition,longtimeout);
Ez a wait_euent() megszakthat vltozata. Ez a makr a javasolt mdszer az
esemnyekre val vrakozsnl, ugyanis tartalmazza a biztonsgos felttel
kirtkelst s a megszakthatsgot is:
waiLev eot_,Ici1101e(wait_queue_head_tqueue, intconditi on);
Ez a csak fontos szignlokkal megszakthat vltozat.
A sleep_on hasznlata manapsg nem javasolhat. Helyette a wait_eventet
hasznljk. Ennek az a f oka, hogy a sleep_ont a fejlesztk tbbnyire egy while
ciklusban alkalmaztk. Ennl a megoldsnl azonban a wait_event jobb.
7.10.2. Felbreszts
Mutn elaltattuk a folyamatot, fel is kell bresztennk, amikor mr megrke-
zett a vrt adat. Ezt az eszkzvezrl egy msik rszn szoktuk elvgezni, tipi-
kusan egy megszaktskezelben. Erre a kvetkez fggvnyek hasznlhatk:
wak e_up(wait_queue_head_t*queue)
Ez a fggvny felbreszti az sszes olyan folyamatot, amely a vrakozsi lis-
tban szerepel.
wak e_up_interruptible(wait_queue_head_t*queue)
Ez a fggvny azokat a folyamatokat breszti fel, amelyek interruptible sleep
llapotban vannak. A tbbiek tovbb alszanak.
wak e_up_sy nc(wa t_queue_head_t*queue)
wak e_up_interruptible_sy nc(wait_queue_head_t*queue)
Az elz fggvnyek a folyamatok felbresztse mellett azonnal egy temez
hvst is eredmnyeztek, hogy a vrakoz processzek tnylegesen tovbb fut-
hassanak. Ez a kt fggvny csak futsra ksz llapotba teszi 'ket, de jra-
temezst nem vlt ki.
397
7. fejezet: Fejleszts aLinux-k ernelben
Ha interruptible sleep llapotban vagyunk, akkor lnyegben mindegy,
hogy a wake_up0 vagy a wake_up_interruptible0 fggvnyt hasznljuk, a szo-
ks azonban az utbbi alkalmazsa.
7.10.3. Plda
Feladatrjunk egy karakteres eszkzvezrlt, amelyben az olvass addig blokkoldik, amg
nem irunk az eszkzllomnyba. Mivel nincs felttel, amelyre vrakoznnk, ezrt a sleep_on
fggvnyt hasznlhatjuk.
/*Blok k olaspelda1*/
#include<linux/k ernel.h>
#include<linux/module.h>
#include<linux/fs.h>
# nclude<linux/sched.h>
#include<asm/uaccess.h>
#include<linux/dev ice.h>
#defineDEVICE_NAME"hello"
static ntmaj or_num=12 0;
#defineCLASS_NAME"helloclass"
staticstructclass*hello_class;
wait_queue_head_twait_queue;
/*Azirasmuv eletetlek ezelorutin.*/
staticssize_thello_write(structfile*pfile,constchar*buf,
size_tcount,loff_t*ppos)
{
printk ("Ebresztes...\n");
wak e_up_interruptible(&wait_queue);
returncount;
/*Azolv asasmuv eletetk ezelofuggv eny .*/
staticssize_thello_read(structfile*pfile,char*buf,
size_tcount,loff_t*ppos)
{
if(pfile->f_flags&O_NONBLOCK)
{
return-EAGAIN;
printk ("Alv as...\n");
interruptible_sleep_on(&wait_queue);
printk ("Alv asv ege\n");
return0;
398
7.10. I/O mveletek blokkolsa
/*Amegny itasmuv eletetlek ezelofuggv eny .*/
staticinthello_open(struct node*inode.structfile*pfile)
try _module_get(THIS_mODuLE);
printk (DEv ICE_NAmE"megny itas.\n");
return0;
/*Alezarasmuv eletetk ezelofuggv eny .*/
staticinthello_close(structinode*inode,structfile*pfile)
{
printk (DEVICE_NAME"lezaras.\n");
module_put(THIS_mODuLE);
return0;
}
staticstructfile_operationshello_fops=
{
owner: THIS_MODULE,
read: hello_read,
write: hello_write,
open: hello_open,
release:hello_close
1;
/*Ak ernelmodulinicializalasatv egzofuggv eny .*/
staticint inithello_init(v oid)
intres;
structdev ice*err;
init_waitqueue_head(&wait_gueue);
/*Regisztralj uk ak arak tertipusueszk ozt.*/
res=register_chrdev (maj or_num,DEVICE_NAME,&hello_tops);
if(res<O)
{
printk (DEVICE_NAME"afoazonosito:%dnemelerheto\n",
maj or_num);
returnres;
}
if(maj or_num=0)maj or_num-res;
/*AZudev sz m raj elz s,hogy hozzal treaz
eszk z llom ny t.*/
hello_class=class_create(THIS_MODULE,CLASS_NAME);
err=dev ice_create(hello_class,NULL,MKDEV(maj or_num,0),
NULL,DEVICE_NAME);
printk (DEVICE_NAME"betoltv e.Foazonosito:%d\n",maj or_num),
return0;
399
7. fejezet: Fejleszts a Linux-kernelben
/*Ak ernel modul eltav olitasaelottafelszabad tasok atv egz .
staticv oid exithello_exit(v oid)
{
/*Azudev sz m raj elz s,azeszk zelt v ol t s rl.*/
dev ice_destroy (hello_class,mk pEV(maj or_num,0));
class_unregister(hello_class);
class_destroy (hello_class);
/*Eltav olitj uk azeszk ozregisztraciot.*/
unregister_chrdev (maj or_num,DEVICE_NAME);
printk (DEVICE_NAME"felszabad tv a.\n");
module_ n t(hello_init);
module_exit(hello_ex t);
MODULE_DESCRIP TION("Hellodriv er");
mooutE_LicENSE("GP L");
A pldban a read fggvny vrakozst egy write-tal tudjuk megszaktani.
Feladat Mdostsuk az elbbi pldt gy, hogy 10 karakter bersra vrakozzunk.
Ebben az esetben, mivel felttelre vrunk, ezrt clszer a sleep_oninterrupt-
ible0 fggvnyt wait_eventinterruptible0 fggvnyre cserlni:
/*Blok k olaspelda2 */
#include<linux/k ernel.h>
#include<linux/module.h>
#include<linux/fs.h>
#include<linux/sched.h>
#include<asm/uaccess.h>
#include<linux/dev ice.h>
#defineDEVICE_NAME"hello"
stat cintmaj or_num=12 0;
#defineCLASS_NAME"helloclass"
stat cstructclass*hello_class;
DECLARE_WAIT_QUEUE_HEAD(wait_queue);
intcounter=0;
staticnEFINE_SP INtock (lock );
/*Azirasmuv eletetlek ezelorutin.*/
staticssize_thello_write(structfile*pfile,constchar*buf,
size_tcount, loff_t *ppos)
{
intlcounter;
printk ("szamlalonov elese...\n");
spin_lock (Mock );
400
7.10. I/O mveletek blokkolsa
counter+=count;
lcounter=counter;
spin_unlock (&lock );
printk ("Ertek :%d\n",lcounter);
wak e_up_interruptible(&wait_queue);
returncount;
/*Azolv asasmuv eletetlek ezelofuggv eny .*/
stat css ze_thello_read(structfile*pfile,char*buf,
size_tcount,loff_t*ppos)
{
intlcounter;
printk ("Altatasamigelerj uk a 10-et...\n");
wait_ev ent_interruptible(wait_queue,(counter)-=10));
printk ("Altatasv ege\n");
spin_lock (&lock );
counter-=10;
lcounter=counter;
spin_unlock (&lock );
printk ("Ertek :%d\n",lcounter);
return0;
/* A megny itasmuv eletetk ezelofuggv eny .*/
staticinthello_open(structinode*inode,structfile*pf le)
{
try _module_get(THIs_moDuLE);
printk (DEVICE_NAME"megny itas.\n");
return0;
}
/*Alezarasmuv eletetk ezelofuggv eny .*/
staticinthello_close(structinode*inode,structf le*pfile)
printk (DEv ICE_NAME"lezaras.\n");
module_put(THIS_MODULE);
return0;
}
staticstructfile_operationshello_fops=
owner: THIS_MODULE,
read: hello_read,
write: hello_write,
open: hello_open,
release:hello_close
} ;
401
7. fejezet: Fejleszts a Linux-kernelben
/*Ak ernelmodulinicializalasatv egzofuggv eny .*/
staticint inithello_init(v oid)
ntres;
structdev ice*err;
/*Reg sztralj uk ak arak tert pusueszk ozt.*/
res=register_chrdev (maj or_num,DEVICE_NAME,&hello_fops);
if(res<0)
{
printk (oEv Ica_NAmE" afoazonosito:%dnemelerheto\n",
maj or_num);
returnres;
11.1
Pr Azudev sz m raj elz s,hogy hozzal treaz
eszk z llom ny t.*/
'hello_class=class_create(TNIS_MODULE,CLASS_NAME);
err=dev ice_create(hello_class,NULL,MKDEV(maj or_num,0),
NULL,DEVICE_NAME);
printk (DEv ICE_NAmE"betoltv e. Fo azonosito:%d\n",maj or_num);
return0;
}
/*Ak ernelmoduleltav olitasaelottafelszabad tasok atv egzi.*/
staticv oid exithello_ex t(v oid)
{
/*Azudev sz m raj elz s,azeszk zelt v ol t s rl.*/
dev ice_destroy (hello_class,MKDEV(maj or_num, 0));
class_unregister(hello_class);
class_destroy (hello_class);
/*Eltav ol tj uk azeszk ozreg sztraciot.*/
unregister_chrdev (maj or_num,DEVICE_NAME);
printk (DEVICE_NAME"felszabaditv a.\n");
module_init(hello_init);
module_exit(hello_exit);
m0DULE_DESCRIRTION("Hellodriv er");
mODULE_LICENSE("GP L");
A blokkols megvalstsnl figyeljnk arra, hogy ha az llomnyt a pro-
cessz nem blokkos mdon, vagyis az O_NONBLOCK opcival nyitotta meg,
akkor ne blokkoljuk, hanem EAGAIN hibajelzssel jelezzk, hogy jra olva-
ssra van szksg. Ezt gy tehetjk meg, ha a kvetkez sort beillesztjk az
altats el:
if(pfile->f_flags& O_NONBLOCK)return-EAGAIN;NeffliEgiTiw,"ek
if(maj or_num.=0)maj or_num=res;
402
7.11. A select() s a poll() tmogatsa
7.11. A select() s a poll() tmogatsa
A blokkolod I/O eszkzk prhuzamos olvassakor a felhasznli progra-
munkban a selectO vagy a poll0 metdust hasznltuk. Ezzel lehetv vlt,
hogy egyszerre tbb eszkzre is vrakozhassunk. m ahhoz, hogy ezt a sajt
eszkzeinknl is hasznlhassuk, implementlnunk kell a poll() tmogatst,
vagyis a poll kezelfggvnyt. Ez egyben a selectO tmogatst is jelenti.
A poll kezelfggvnynek alakja a kvetkez:
unsigned int ("poll)(struct file * , poll_table * );
Alapveten kt lpst kell ebben a lekezel fggvnyben megtennnk.
A poll_wait0 fggvnnyel meg kell adnunk minden olyan vrakozsi sort,
amelyiknek a vltozsa a poll sttuszban is vltozst eredmnyezhet, s
vissza kell adnunk egy bitmaskot, amellyel jelezzk az adott pillanatban vg-
rehajthat mveleteket.
A msodik paramter a poll_table struktra tartalmazza azt a vrakozsi-
sor-listt, amelynek segtsgvel a select /poll vrakozst meg tudja a kernel
valstani. Ebbe a listba a poll_wait0 fggvnnyel vehetnk fel j elemeket.
void poll_wait(struct fi le * pfi le, wait_queue_head_t * pwait_queue,
poll_table * pwai t) ;
A msik mvelet a maszk belltsa, hogy visszaadjuk az azonnal kivitelez-
het mveleteket. A maszk rtknek sszelltshoz az albbi linux/poll.h-
ban definilt rtkek llnak rendelkezsre (7.6. tblzat).
7.6. tblzat. Poll rtkek
rtk Lers
POLLIN Az eszkz blokkols nlkl olvashat.
POLLRDNORM ,, Normal" adat olvashat. Az elzvel kombinltan hasznlatos.
POLLRDBAND Out-of-band adat olvashat (nem hasznlatos).
POLLPRI High-priority adat (vagyis out-of-band data) olvashat. Ez a
select fggvnynl mint az exceptfds halmazban jelenik meg.
POLLHUP Vge van az llomnynak
POLLERR Hibajelzs.
POLLOUT Az eszkz blokkols nlkl rhat.
POLLWRNORM Lsd az elzt, azzal kombinltan hasznlatos.
POLLWRBAND Out-of-band adat rhat.
403
-
unsigned int hel lo_pol 1 (struct fi le *pfi 1 e , pol l_tabl e *wait)
{
unsigned int mask =0;
pol l_wai t(pfi le , &wa t_queue, wai t);
spin_lock(Mock);
if(counter >=10) mask 1=P OLLIN P OLLRDNORM;
spin_unlock (8A ock)
return mask;
7. fejezet: Fejleszts a Linux-kernelben
Feladat Egsztsk ki az eddigi pldnkat gy, hogy a poll vagy a select fggvnyekkel is tud-
junk vrakozni az olvassra. Vagyis ksztsk el a poll kezelfggvny implementcijt,
amely 10 karakter utn jelzi, hogy az llomny olvashat.
Egy plda a kezelfggvny implementcijra, amely kitnen illeszkedik az
elz fejezet pldakdjba:
A beilleszts mellett a feladatunk csak annyi, hogy a karakteres eszkzvezr-
l regisztrlsnl a poll fggvnyt is belltsuk:
s truct fi le_operati ons hel 1 o_fops =
owner: THIS_MODULE,
poll:
};
hel 1 o_pol 1
7.12. Az mmap tmogatsa
Az mmap0 rendszerhvssal mr tallkoztunk az alkalmazsok fejlesztsnl.
Hasznlatval egy llomnyt kpezhetnk le a folyamat cmterbe. Ez az esz-
kzllomnyoknl is nagy jelentsggel br, mert segtsgvel az eszkzvezrl
bels memrijnak egy rszt is lekpezhetjk, s gy nagyon gyors kommuni-
kcit rhetnk el az alkalmazs s az eszkzvezrl kztt, erre pedig nagy
mennyisg adat tvitelekor szksgnk lehet. Arrl van sz, hogy ugyanazt a
fizikai memrit lekpezzk a kernelmodulunk s a felhasznli zemmdban
fut programunk virtulis cmterbe. gy lnyegben kzvetlen memriamve-
letekkel olvashatunk vagy rhatunk az eszkzvezrl bufferbe.
Ahhoz hogy a lekpezst meg lehessen valstani, az eszkzvezrlnkben
egy- vagy tbblapos terletet kell a buffernek lefoglalnunk. Ennek mdjt
mr lthattuk a memriakezels alfejezetben.
404
7.12. Az mmap tmogatsa
Kvetkez lpsknt le kell implementlnunk az mmap mvelet kezel-
fggvnyt, amelynek alakja a kvetkez:
nt mmap(struct file *pfile, struct vm_area_struct *vma)
MM
A fggvny msodik, struct vm_area_struct* tpus paramtere tartalmazza a
krt terlet mrett, illetve azt a virtulis cmet, ahova a lekpezst el kell v-
geznnk m a kernelcmtartomnyban tallhat terletnk lekpezse a krt
virtulis cmre csak tbb lpsben valsthat meg. Elszr a kernelbeli logikai
cmbl el kell lltanunk a fizikai cmet, majd a fizikai cmbl a lapkeret-
azonostt (Page Frame Number, PFN). Majd a lapkeret-azonostval megad-
hatjuk a rendszernek, hogy melyik lapot kpezze le a krt virtulis cmre.
A logikai cm talaktst fizikai cmre egyni szmtssal vgezhetjk, a
mr emltett eltols kivonsval, de a javasolt mdszer a kvetkez fggvny
hasznlata:
unsigned long vi rt_to_phys (vol ati le void * address);
A fggvny paramtere a virtulis cm, vagyis a kernel logikai cme, a visszatr-
si rtke pedig a fizikai cmet tartalmazza. A fizikai cmet PFN-re alaktani egy-
szer feladat. Le kell osztanunk a cmet a lap mretvel, s megkapjuk a PFN-t.
A leggyorsabb megolds, ha a fizikai cmnket jobbra lptetjk PAGE_SH1F7'
bittel. "
Ha rendelkezsnkre ll a lap PFN-je, a lapot le kell kpeznnk a fel-
hasznli cmtartomnyba. Ennek fggvnye a kvetkez:
int remap_pfn_range(struct vm_area_struct * vma,
unsigned long addr, unsigned long pfn,
unsigned long size, pgprot_t prot);
A vma az mmap fggvny ltal kapott struktra. Az addr a user space cm,
ahova lekpezzk a lapot. Apfn a fizikai lap cme, amelyet az elzekben
szmoltunk ki. A size a lekpezett terlet hossza byte-okban, a prot a vdelmi
belltsokat tartalmazza.
A lekpezst kveten mr csak a kt kezelfggvnyt kell implementl-
nunk s regisztrlnunk, amelyek a lekpezett terlet megnyitst s lezr-
st kezelik.
Feladat Ksztsk el egy karakteres eszkzvezrl mmap kezelfggvnynek implementci-
jt, amely elrhetv teszi a felhasznli alkalmazsnak a kernelmodul data mutat ltal mu-
tatott lapjnak olvasst.
I
" Felttelezve a little endian szmbrzolst.
4 05
7.fej ezet:Fej leszt saLinux-k ernelben
A data mutat egy olyan lapra mutat, amelyet mr korbban lefoglaltunk.
gy a pldnkban ezt kpezzk le az alkalmazs cmterbe:
v oidhello_v m_open(structv m_area_struct*area)
f
printk (0EVICE_NAmE"v m_open.\n");
v oidhello_v m_close(structv m_area_struct*area)
{
printk (0Ev icE_NAmE"v m_close.\n");
}
staticstructv m_operations_structhello_v m_ops=
{
open:hello_v m_open,
close:hello_v m_close
} ;
staticinthello_mmap(structfile*pfile,
structv m_area_struct*v ma)
{
unsignedsongv size=v ma->v m_end-v ma->v m_start;
if(v size!=P AGE_SIZE)
printk (DEVICE_NAME"hibasmeret:%lu\n",v size);
return -EINVAL;
}
if(v ma->v m_flags&VM_WRITE)
return-EP ERM;
if(P AGE_SIZE>(116))
return-ENOSYS;
if(remap_pfn_range(v ma,
v ma->v m_start,
v irt_to_phy s((v oid*)data)>P AGE_SHIFT,
v ma->v m_end-v ma->v m_start,
v ma->v m_page_prot))
return-EAGAIN;
}
v ma->v m_ops=&hello_v m_ops;
hello_v m_open(v ma);
return0;
406
7.13.1/0 portok kezelse
A kezelfggvnynkben ellenrizzk a paramtereket, a mretet s a jogosult-
sgbelltsokat. Ezt kveten elvgezzk a cm talaktst s a lekpezst egy
sorban. Majd a megnyit s a lezr fggvny regisztrcija kvetkezik, s
egyben meg is hvjuk a megnyit fggvnyt.
A ksz kezelfggvnynket be kell lltanunk az eszkzvezrl regisztr-
lsnl, hogy az mmap metdust implementlja, s mris hasznlhatjuk ezt a
gyors kommunikcis mdot az alkalmazsainkban:
structfile_operationshello_fops=
{
owner: THIS_MODULE,
mmap:

hello_mmap
1;
7.13. I/O portok kezelse
Az eddigi fejezetekben bemutattuk, hogy hogyan tudunk az alkalmazsok s
a kernelmodulok kztt kommuniklni. m egy eszkzvezrlnl ez mg csak
a feladat egyik fele, hiszen az eszkzvezrlnek nem elg az alkalmazsokkal
kommuniklnia, az ltala kezelt hardverrel is tartania kell a kapcsolatot.
Ezrt a kvetkez nhny fejezetben azt mutatjuk be, hogyan tudunk kernel-
bl klnfle eszkzket vezrelni.
Az egyszerbb hardvereszkzkkel a kommunikcit leggyakrabban az
I/O portok segtsgvel folytatja a CPU, mgpedig az in s az out parancsok
segtsgvel. A Linux-kernelmodulokban is elrhetjk ezeket a parancsokat,
illetve portokat. m a portok hasznlata eltt illik a tartomnyt lefoglalni.
Az I/O porttartomny lefoglalsnak az a clja, hogy a kernel knyvelje,
hogy melyik tartomnyt melyik eszkzvezrl hasznlja. gy egy lefoglalsi
krelem sorn jelezheti, ha az adott tartomnyt egy msik eszkzvezrl ne-
tn mr hasznlja. Termszetesen az eszkzvezrl eltvoltsakor a tarto-
mnyt is fel kell szabadtanunk, hogy ms eszkzvezrl is hasznlhassa.
Porttartomny lefoglalsa az albbi fggynnyel trtnik:
structresource*request_region(resource_size_tstart,
resource_size_tn,constchar*name);
A start a tartomny eleje, az n a tartomny mrete. A name paramterre
azrt van szksg, hogy ha megnzzk a lefoglalt tartomnyok listjt, akkor
lthassuk, hogy melyik eszkzvezrl hasznlja. Ezrt ez a paramter az esz-
kzvezrl szveges elnevezst tartalmazza.
A lefoglalhatsgot kln is ellenrizhetjk:
intcheck _region(resource_size_tstart,resource_size_tn);
407
7. fejezet: Fejleszts a Linux-kernelben
A hasznlat utn a terlet felszabadtsa a kvetkez:
rvi7fase.re9icrresource.. ~5tarti rpstkume..,size_t ki);
A lefoglalt I/O portok listjt felhasznlknt is elrhetjk a /proc/ioports
virtulis llomny megtekintsvel.
A tartomny lefoglalsa utn a portokat klnbz I/O mveletekkel r-
hetjk el. Az adat mrettl fggen tbb fggvny kzl is vlaszthatunk:
8 bites
unsigned char inb( int port);
vojg1 outb( unsigned char value, int port);
1 6 bites
unsigned short inw( int port) ;
vo d outw( uns gned short value, int port) ;
32 bites
unsigned long inb( int port);
void outl ( unsigned long value, int port) ;
Ugyanakkor mindegyik fggvnynek ltezik egy vrakoz (pause") vltozata,
amely egy kis vrakozst is tartalmaz. Erre a lassabb buszok/krtyk hasz-
nlatakor lehet szksgnk. Ezeknek a fggvnyeknek az alakja megegyezik
az elzekben felsoroltakkal, m a fggvnyek nevnek a vgre egy _p ut-
tagot kell illeszteni.
7.14. 1/0 memria kezelse
Br az egyszer eszkzknl az 1/0 portok hasznlata npszer, a kicsit ko-
molyabb eszkzkkel az I/O memrin keresztl tartjuk a kapcsolatot, mivel
sokkal gyorsabb s sokkal nagyobb mennyisg adat tvitelre alkalmas.
Az I/O memria olyan, mint egy szoksos RAM-terlet. m nem egy me-
mriamodult kell keresnnk az alaplapon, hanem ez valjban az eszkzk-
ben, a bvt'krtykon foglal helyet, s a processzor tbbnyire egy buszon
(ISA, PCI) keresztl ri el. A teljes kphez hozztartozik, hogy a processzor-
gyrtk manapsg gyakran integrlnak eszkzket az alaplapi vezrl chip-
kszletbe vagy ppen a processzorba. Termszetesen ekkor az I/O memria is
integrltan tallhat meg.
408
7.14.I/Omemriak ezel se
Br elmletben egyszer memriamutatkkal is tudnnk kezelni 'ket,
mint egy memriatmbt, m ez a mdszer nem javasolhat. Helyette speci-
lis fggvnyeink vannak erre a feladatra.
Mieltt hozzfrhetnnk az I/O memriaterlethez le kell foglalnunk:
structresource*request_mem_region(resource_size_tstart,
resource_size_tn,constchar*name);
A start paramterrel adhatjuk meg a rgi elejnek fizikai cmt, az n-nel a
mrett, mg a name az eszkzkezelnk szveges elnevezse a ks'bbi admi-
nisztrcihoz.
Mieltt lefoglalnnk a terletet, ellenrizhetjk, hogy ms mr hasznlja-e:
int Chk_metn_region(resource_size_t start, resource_size_t n);
A lefoglalt terletet nem szabad elfelejtennk felszabadtani, amikor mr
nincs r szksgnk:
Ilk~~~fopin~~ ~+._
A foglalsokat felhasznlknt is ellenrizhetjk a /proc/iomem llomny
megnzsvel. Ebben ttelesen szerepelnek a hasznlt memriaterletek s
az eszkzvezrlk megnevezsei.
Sok rendszeren az I/O memria lefoglalsa nmagban nem elg a mem-
riaterlet elrshez, ugyanis nem lehet ket kzvetlenl elrni. Ezeken a
rendszereken a buszmemribl a kernel ltal elrhet virtulis memriate-
rletre kell lekpezni a rgit.
A lekpezs az albbi fggvnyekkel trtnhet:
v oid__iomem*ioremap(resource_size_toffset,unsignedlongsize);
void _iomem *ioremap_nocache(resource_size_toffset,
unsignedlongsize);

t
A mvelet vgn a lekpezs megszntetsrl se feledkezznk meg:
01111~~1~~1~1ffik
Ezen a ponton mr hozzfrhetnk az eszkz memriaterlethez, s adato-
kat mozgathatunk. Nmelyik rendszer esetben kzvetlenl memriakezel
fggvnyekkel is megtehetjk ezt, m ltalban csak az albbi fggvnyek
mkdnek:
unsigned nt oread8(v oid__iomem*);
unsignedintioreadl6(v oid_iomem*);
unsignedintioread3 2 (v oid_iomem*);
v oidiowrite8(u8,v o d__iomem*);
v oidiowritel6(u16,v oid iomem*);
v oidiowrite3 2 (u3 2 ,v oid_iomem*);
1111111W
409
7. fejezet: Fejleszts a Linux-kernelben
A fggvnyek 1, 2 , vagy 4 byte-ot olvasnak be vagy rnak ki a megadott cmre.
Lteznek azonban ismtld (repetitive") megoldsok is a tmbk kezelsre:
v oidioread8_rep(v oid_iomem*port,v oid*buf,
unsignedlongcount);
v oidioreadl6_rep(v oid iomem*port,v oid*buf,
unsignedlongcount);
v o dioread3 2 _rep(v oid_iomem*port,v oid*buf,
unsignedlongcount);
v oidiowrite8_rep(v oid iomem*port,constv oid*buf,
unsignedlongcount);
v oidiowritel6_rep(v o d iomem*port,constv oid*buf,
unsignedlongcount);
v oidiowrite3 2 _rep(v oid iomem*port,constv oid*buf,
unsignedlongcount);
Tovbb a megszokott C-fggvnyeknek is megtallhatjuk az analgiit az
I/O memria kezelsre:
v oidmemset_io(v olatilev oid _i omem*addr,unsignedcharv al,
intcount);
v oidmemcpy _fromio(v oid*dst,constv olatilev oid i omem*src,
intcount);
v oidmemcpy _toio(v olatilev oid iomem*dst,constv oid*src,
intcount);
7.15. Megszaktskezels
Ha az eszkzvezrlnkben megszaktst szeretnnk kezelni, akkor az albbi
mveleteket kell elvgeznnk:
1. Ltre kell hoznunk egy megszaktskezel fggvnyt.
2 . Regisztrlnunk kell a megszaktskezel fggvnyt az adott megsza-
ktshoz.
3. A meghajtprogram eltvoltsakor a megszaktskezel regisztrci-
jt is el kell tvoltanunk.
A megszaktskezel fggvnymutat tpusa a kvetkez:
ty pedefrqreturn_t(*irq_handler_t)(intirq,v oid*dev id);
A fggvny paramterei a megszakts szma (irq), amelynek hatsra a
fggvny meghvdik, illetve egy azonost (devid), amelyet a kezelfggvny
regisztrcijnl adunk meg.
410
7.15. Megszaktskezels
A megszaktskezelnket az albbi fggvnnyel regisztrlhatjuk:
intrequest_irq(unsignedintirq,irq_handler_thandler,
unsignedlongflags,constchar*dev name,
4 11111~.
v oid*dev id);
=Mb
Paramterei a megszakts szma (irq), a megszaktskezel fggvny (hand-
ler), az opcik (flags), az eszkzvezrl neve (devname), megosztott megszak-
ts esetn az egyedi azonost (devid).
A flags mez rtkei az albbiak lehetnek:
IRQF_DISABLED (SA_INTERRUPT): A megszaktskezel futsa
alatt a megszaktsok letiltdnak. Ezrt lehetleg rvidre kell megr-
nunk a megszaktskezelt.
IRQF_SHARED (SA_SHIRQ): Annak jelzse, hogy a megszaktst
megosztjuk ms megszaktskezelkkel. Ilyenkor ltalban tbb hard-
ver hasznlja ugyanazt a megszaktsvonalat.
IRQF_SAMPLE_RANDOM (SA_SAMPLE_RANDOM): A megsza-
kts felhasznlhat a vletlenszm-generlshoz. Ezt olyan meg-
szaktsoknl alkalmazhatjuk, amely vletlenszeren generldik.
Ilyen pldul a billentyzet megszaktsa.
IRQF_TIMER: A megszakts az idzttl (timer) rkezik.
A megszaktskezel fggvny implementcijnl az albbi rtkekkel tr-
hetnk vissza:
IRQ_HANDLED: A megszaktst kezelte a fggvny.
IRQ_NONE: A megszaktst nem kezelte a fggvny.
A sikeres regisztrcit a /proc/interrupts virtulis fjlban ellenrizhetjk,
amely tartalmazza a megszaktsokat s a megszaktskezelket.
A megszaktskezel regisztrcijnak trlse a kvetkez fggvnnyel
trtnik:
void free_irq(unsigned int irq, void * devid);
Ha a megszaktsvonalat megosztottan hasznltuk ms megszaktskezelk-
kel, akkor gyeljnk arra, hogy a felszabadtsnl ugyanazt a devid rtket
adjuk meg, amelyet a regisztrcinl. A rendszer nem akadlyozza meg, hogy
ms eszkzvezrl regisztrcijt trljk, ezrt klnsen oda kell figyel-
nnk r.
411
7. fejezet: Fejleszts a Linux-kernelben
7.15.1. Megszaktsok megosztsa
Mivel a megszaktsvonalak szma tbbnyire vges, ezrt a hardverksztk
gyakran knyszerlnek arra, hogy tbb eszkz kztt osszanak meg egy meg-
szaktsvonalat. Ebben az esetben a megszaktskezel fggvny regisztr-
cijnl jeleznnk kell az IRQF SHARED flaggel a megosztott hasznlatot.
Emellett a devid paramternek meg kell adnunk egy egyedi rtket, amellyel
ksbb a regisztrcinkat azonosthatjuk.
A megszaktskezel fggvny implementcijnl az IRQ_NONE vissza-
trsi rtkkel jelezhetjk, ha a megszakts nem az ltalunk kezelt eszkz-
nek szlt.
Termszetesen ilyenkor vigyznunk kell a megszakts esetleges letilt-
sval s engedlyezsvel, mivel ebben az esetben ms eszkzk kezelsre is
hatssal lehet.
7.15.2. A megszaktskezel fggvnyek megktsei
A megszaktskezel fggvny implementcijakor tbb szablyt is be kell
tartanunk.
Nem hasznlhatunk sleep0-es fggvnyt, mivel belthatatlan kvetkez-
mnyekkel jrna egy taszkvlts a megszaktskezel kontextusban.
A kmalloc0-os allokcit is csak a GFP ATOMIC flaggel vgezhetjk,
mivel egyb esetben sleep0 fggvnyt hasznlhat az allokci sorn.
A kernel s a user space kztt nem mozgathatunk adatokat, mivel az
erre szolgl fggvnyek sleep0-es fggvnyek.
Trekedjnk a gyorsasgra. A nagy szmtsokat lehetleg mshol
vgezzk.
Mivel nem processz hvja meg a fggvnyt, ezrt a processzspecifikus
adatok a megszaktskezelbl nem rhet'k eb
7.15.3. A megszakts tiltsa s engedlyezse
Ha egy megszaktst le szeretnnk tiltani, az albbi kt fggvnnyel tehetjk
meg:
void disablo_irq(unsigned int irq);
-
vola
dhable,_1 ronosync(unsigned int i rO);
412
7.15. Megszaktskezels
A nosync fggvny abban klnbzik a trstl, hogy mg a norml vltozat
az esetleg fut megszaktskezel fggvny vgt megvrja a visszatrs
eltt, a nosync vltozat azonnal visszatr a fggvny meghvsa utn.
A megszakts ismtelt engedlyezse az albbi fggvnnyel trtnik:
void enable_irq(unsigned int rq);
Ha szksgnk van az sszes megszakts letiltsra, illetve engedlyezs-
re, akkor ezt az albbi fggvnyekkel tehetjk meg:
void local_i rg_enable();
void local_i rq_disable();
Tbbnyire szeretnnk a korbbi belltsokat lementeni, illetve az engedlye-
zskor visszalltani. Az albbi fggvnyek erre nyjtanak lehetsget:
1
-
06

void local_i rg_save(unsigned leng flags);
void local_i rg_restore(unsigned long flags);
7.15.4. A szoftvermegszakts
A szoftvermegszaktsok (software interrupt, softirq) lehetv teszik a kernel-
nek egy feladat vgrehajtsnak a ksleltetst. Jellegre s megktsekben
egyeznek a korbban trgyalt hardvermegszaktsokkal, csak nem hardver-
esemny generlja ket, hanem szoftver vltja ki a mechanizmust.'w
Amikor egy fggvnyhvssal szoftvermegszaktst vltunk ki, akkor erre
a kernel nem azonnal reagl, hanem kicsivel ksbb hvja meg a kezelfgg-
vnyt. Egsz pontosan, amikor egy hardvermegszakts kezelfggvnye v-
get r, akkor a kernel lefuttatja a vrakoz szoftvermegszaktsokhoz tartoz
kezelfggvnyeket.
A szoftvermegszakts-kezels kzponti eleme egy 32 bejegyzst tartal-
maz tbla, amely az egyes kezelfggvnyek mutatit, adatait tartalmazza.
A megszakts generlsakor a regisztrlt fggvnyek hvdnak meg.
A 32 -es limit arnylag szknek tnhet, m kzvetlenl nem szoks hasz-
nlni ezt a mechanizmust. Ehelyett az erre pl szolgltatsokat vesszk
ignybe, ilyenek pldul a kisfeladatok (lsd a 7.15.5.1. A kisfeladat (tasklet)
alfejezetben).
16
A megadott fggvnyek valjban makrk, ezrt a paramter nem rtk szerint addik t.
17
A Linux-kernel esetn trgyalt szoftvermegszakts terminolgia nem egyezik meg az
x86-os vilgban hasznlt hasonl nev fogalommal, azaz nem az Intel x86-os processzor
INT x instrukcijnak hasznlatrl van sz.
4 13
7. fejezet: Fejleszts a Linux-kernelben
7.15.5. A BH-mechanizmus
A hardvermegszakts-kezelben sokszor komolyabb adatfeldolgozst is el
kell vgeznnk, ekkor azonban nem lesz gyors az implementci, amely a
megszaktskezel egyik legfontosabb alapkvetelmnye. Erre a problmra
nyjt megoldst az alsrsz- (Bottom half, BH) mechanizmus, amely a meg-
szaktskezelt egy fels rszre (Top half) s egy als rszre (Bottom half) v-
lasztja szt. A fels rsz a tnyleges megszaktskezel rutin. Ennek feladata
csak az adatok gyors letrolsa a ks'bbi feldolgozshoz, illetve a feldolgoz
rutin futtatsnak krvnyezse. Az alsrsz-rutin mr nem megszaktsid-
ben fut, ezrt a futs idejre nem rvnyesek a szigor megktsek.
Az als rsz implementcijra kt mechanizmust hasznlhatunk:
Kisfeladat (Tasklet)
Munkasor (Workqueue)
A kt megoldsnak eltr tulajdonsgai, elnyei s htrnyai vannak, ame-
lyeket a kvetkezkben rszletesen megvizsglunk.
Ltezik mg egy harmadik megolds is, amely kzeli rokonsgban ll a
munkasorral, nevezetesen a kernelszlak hasznlata a feladatok elvgzsre,
ennek ksbb kln fejezetet szentelnk.
7.15.5.1. A kisfeladat (tasklet)
Ha a hardvermegszaktsban elvgeztk a gyors kritikus dolgokat, kzenfek-
v megolds, hogy a feladat maradk rszre meghvunk egy szoftvermegsza-
ktst (lsd a 7.15.4. A szoftvermegszakts alfejezetben). A Linux-kernel erre
kln tmogatst nyjt, ezeket kisfeladatoknak (tasklet) nevezzk. A kisfela-
datok szoftvermegszakts ltal meghvott kdrszletek, amelyeket a prog-
ramoz regisztrlhat, illetve eltvolthat, s amelyeket a kernel temez.
gy a megoldsunk a kvetkez. A megszakts idignyesebb rszt egy
megadott paramterlistj fggvnyben implementljuk, s beregisztrljuk
mint kisfeladatot. A hardvermegszakts vgn krjk a kisfeladat temez-
st. Ha nem hasznljuk tovbb a kisfeladatot, akkor fel kell szabadtanunk.
Kisfeladatot akkor alkalmazunk, ha a feladat tl kevs ahhoz, hogy kln
szlat rendeljnk hozz.
A kisfeladat implementcija sorn figyelembe kell vennnk nhny
megktst:
A kisfeladat futtatst tbbszr is krhetjk, mieltt lefutna. Ilyenkor
azonban csak egyszer fut le.
Ha a kisfeladat fut mr egy CPU-n a krvnyezskor, akkor ksbb
ismt lefut.
A kisfeladat azon a CPU-n fut le, ahol elszr krvnyeztk.
414
7.15. Megszaktskezels
Egyszerre a kisfeladat csak egy pldnyban futhat mg SMP-rend-
szerben is.
Klnbz kisfeladatok viszont futhatnak prhuzamosan SMP-rend-
szerben.
A kisfeladat nem indul el, amg a megszaktskezel be nem fejezdik.
A kisfeladat futsa sorn meghvdhat a megszaktskezel.
Mivel a kisfeladat szoftvermegszakts-kontextusban fut, ezrt a meg-
szakts-kezelk implementcis megktsei r is rvnyesek: sleep0-et
tartalmaz fggvnyt nem hasznlhatunk kisfeladatban sem.
A kisfeladat-mechanizmus hasznlathoz elszr ltre kell hoznunk egy keze-
lfggvnyt Ennek alakja a kvetkez:
vala k^seadat^i(ursignd' lging
j
Feladatot a kvetkez makrval hozhatunk ltre:
DCLARLtA$
1
0,....ET( Ov
,
A nv a kisfeladat neve, amellyel ksbb hivatkozhatunk r. A fggvny a ke-
zelfggvnynk neve. Az adat mezben tallhat szmot kapja meg a keze-
lfggvnynk adatknt egyetlen paramtern keresztl.
Ezt kveten a kisfeladat lefuttatst a tasklet_scheduleQ fggvnnyel
krhetjk:
if: Utsklet' . ~1.1 le
Nzzk meg, hogyan is hasznlhatjuk ezeket a fggvnyeket.
Feladat rjunk kernelmodult, amely szmolja a belltott megszaktst. A szmll rtkt
egy kisfeladat msolja le, hogy aztn a msolatot elrjk egy proc llomnyon keresztl.
/* helloi rq.c - Egyszeru megszaki tas kezel es kisfeladat
haszna] ataval . */
#include <1 i nux/kernel . h>
#include <11 nux/modul e . h>
#include <11 nux/proc_fs h>
#include <linux/interrupt.h>
#include <asm/i rq . h>
unsigned long counter1=0;
unsigned long counter2=0;
unsigned int cirq=1;
static unsigned int devid=33;
415
7. fejezet: Fejleszts a Linux-kernelben
staticDEFINE_SRINLOCK(hello_lock );
v oidhello_task let_proc(unsignedlong);
DECLARE_TASKLET(hello_task let,hello_task let_proc,0);
/*megszak itask ezelofuggv eny .*/
irgreturn_tcounter_irq(intirq,v oid*dev _id)
{
counterl++;
task let_schedule(&hello_task let);
returnIRQ_NONE;
}
/*Task letk ezelofuggv eny .*/
v oidhello_task let_proc(unsignedlongnothing)
{
unsignedlongflags;
spin_lock _irqsav e(&hello_lock ,flags);
counter2 =counterl;
spin_unlock _irgrestore(&hello_lock ,flags);
}
/*Azallomany olv asasatlek ezelofuggv eny .*/
intprocfile_read(char*buffer,char**buffer_location,
off_toffset,intbuffer_length,int*eof,
v oid*procdata)
{
intlen;
spin_lock (&hello_lock );
len=sprintf(buffer,"Szamlalo:%lu\n",counter2 );
spin_unlock (&hello_lock );
returnlen;
/*Ak ernelmodulinicializalasatv egzofuggv eny .*/
staticint_inithello_init(v oid)
{
structproc_dir_entry *hello_proc_ent;
/*Regisztralj uk amegszak itask ezelot.*/
if(request_irq(cirq,counter_irq,IRQF_SHARED,"Helloszamlalo",
&dev id))
{
printk (KERN_WARNING"A%dmegszak itasfoglalt.\n",cirq);
cirq=-1;
}
/*Dinamik usanhozzuk letreaprocallomany bej egy zest.*/
hello_proc_ent=create_proc_entry ("hello",S_IFREGIS_IRUGO,
0);
416
7.15. Megszaktskezels
/*Beall tj uk alink szamlalotesalek ezelofuggv eny t *
if(hello_proc_ent)
{
hello_proc_ent->nlink =1;
hello_proc_ent->read_proc=procfile_read;
return0;
}
/* A k ernelmoduleltav olitasaelottafelszabaditasok atv egzi.
staticv oid_exithello_exit(v oid)
{
/*Megszuntetj uk amegszak itask ezeloregisztracioj at. * /
if(cirg>=0)free_irg(cirg,&dev id);
/*Megsemmisitj uk aprocallomany bej egy zest.*/
remov e_proc_entry ("hello",0);
}
module_init(hello_init);
module_exit(hello_exit);
m000LE_DEscRIP TI0N("Belloproc");
MODULE_LICENSE( "GPL");
A pldban az 1-es megszaktsra regisztrlunk, s megosztottan hasznljuk
az eredeti kezelfggvnnyel. Ez a megszaktsvonal ltalban az idzt,
amelyre rendszeresen rkeznek megszaktsok. Mivel a mi megszaktskezel
fggvnynk csak egy potya"-fggvny, s nem akarjuk megzavarni a rend-
szer mkdst, ezrt visszatrsi rtkknt IRQ_NONE rtket hasznlunk.
Az idzt megszaktsa helyett vlaszthatunk azonban ms megszak-
tsvonalat is, amelyre vagy nincs megszaktskezel regisztrlva, vagy meg-
osztottan hasznlatos.
7.15.5.2. Munkasor
A munkasor (work queue) olyan kdrszlet, amelyet kernelszlak futtatnak a
httrben. A munkasor aktivlsa a 7.10. I/O mveletek blokkolsa alfejezet-
ben trgyalt vrakozsi sorokon keresztl trtnik: a munkasor aktivlst
ugyangy esemnyknt kezeli a futtat szl, amelyre vrakozik. Az esemny
ekkor a futtats krelmezse.
A munkasor tgabb lehetsgeket nyjt, mint a kisfeladat: mivel a fgg-
vny ebben az esetben egy kln kernelszlban hvdik meg, ezrt egyrszt
hasznlhatunk sleep()-es fggvnyeket is, msrszt az implementci hossz-
ra nincs megkts, mivel kzben lehetsges a taszkvlts. Ugyanakkor to-
vbbra sem rhetjk el ms processzek cmtert, m ez nem szokott komoly
problmt jelenteni.
417
7. fejezet: Fejleszts a Linux-kernelben
Hasznlatuk alapkoncepcii nagyon hasonltanak a kisfeladatokhoz: re-
gisztrlunk egy vgrehajt rutint, krjk annak lefuttatst, ez majd valami-
kor egy ksbbi idpontban lefut, s amikor nincs mr szksgnk r, fel kell
szabadtanunk. Az adatstruktrk s a mkds termszetesen ms, mint a
kisfeladatok esetben.
A munkasor hasznlathoz ltre kell hoznunk egy kezelfggvnyt, ame-
lyet a mechanizmus meghv. Ennek alakja a kvetkez:
void (*work_func_t)(struct work_struct *);
Tovbb ltre kell hoznunk magt a munkasort:
struct workqueue_struct * create_workqueue(const char *name);
Ugyanakkor a kernelmodul eltvoltsakor nem szabad elfelejtennk a mun-
kasor megsemmistst:
void destroy_workqueue(struct workqueue_struct *wq);
A ltrehozst kveten a megszaktskezel rutinban a feldolgozfggv-
nynkbl egy work_struct tpus elemet kell ltrehoznunk. Az els alkalom-
mal ezt az albbi makrval tehetjk meg:
INIT_WORK(structwork_struct *work, void (*function)(void *));
A ksbbi meghvsok sorn a mdostshoz elegend a kvetkez makrt
hasznlnunk:
PREPARE_WORK(struct work_struct *work, void (*function)(void *));
Mg szintn a megszaktskezel rutinban el kell helyeznnk a work_struct
elemmel reprezentlt feladatot a munkasorba:
int queue_work(struct workqueue_struct *wq,
struct work_struct *work);
Feladat Valstsuk meg az elz fejezetben ltott pldt kisfeladat helyett munkasorral.
/* hel 1 oi rq2 . c - Egyszeru pel da a munkasor haszna] atara. */
#include <1 nux/kernel . h>
#include <1 i nux/modul e . h>
#include <1 i nux/p roc_fs . h>
#include <1 i nux/i nterrupt h>
#include <asm/i rq. h>
#include <1 nux/workqueue h>
418
7.15. Megszaktskezels
unsignedlongcounter1=0;
unsignedlongcounter2 =0;
unsignedintcirq=1;
staticunsignedintdev id=3 3 ;
staticbEFINE_SP INL0cK(hello_lock );
staticstructwork queue_struct*hello_wq;
v oidhello_wq_proc(structwork _struct*work );
/*Megszak itask ezelofuggv eny .*/
ircireturn_tcounter_irq(intirq,v oid*dev _id)
{
staticintinited=0;
staticstructwork _structtask ;
counterl++;
/*Awork queuetaszk elok eszitese.
if(inited==0)
{
INIT_woRk (&task ,hello_wq_proc);
inited=1;
//else
//{
//P REP ARE_WORK(&task ,hello_wq_proc);
//}
/* A taszk behely ezeseawork queue-ba.
*/
queue_work (hello_wq,&task );
returnIRQ_NONE;
}
/* A feladatotv egrehaj tofuggv eny .*/
v oidhello_wq_proc(structwork _struct*work )
{
unsignedlongflags;
spin_lock _irqsav e(&hello_lock ,flags);
counter2 =counterl;
spin_unlock _irgrestore(&hello_lock ,flags);
/* Az allomany olv asasatlek ezelofuggv eny .*/
intprocfile_read(char*buffer,char**buffer_location,
off_toffset,intbuffer_length,int*eof,
v oid*procdata)
{
intlen;
spin_lock (&hello_lock );
len=sprintf(buffer,"counter:%lu\n",counter2 );
spin_unlock (&hello_lock );
returnlen;
}
419
7.fej ezet:Fej leszt saLinux-k ernelben
/*Ak ernelmodulinicializalasatv egzofuggv eny .*/
staticint inithello_init(v oid)
{
structproc_dir_entry *hello_proc_ent;
/*Letrehozzuk awork queue-t.*/
hello_wq=create_work queue("hellowork queue");
/*Regisztralj uk amegszak itask ezelot.*/
if(request_irq(cirq,counter_irq,IRQF_SHARED,"Hellocounter",
&dev id))
{
printk (KERN_WARNING"A%dmegszak itasfoglalt.\n",cirq);
cirq=-1;
/*Dinamik usanhozzuk letreaprocallomany bej egy zest.*/
hello_proc_ent=create_proc_entry ("hello",S_IFREG S_IRUGO,
0);
/*Beallitj uk alink szamlalotesalek ezelofuggv eny t.*/
if(hello_proc_ent)
hello_proc_ent->nlink =1;
hello_proc_ent->read_proc=procfile_read;
return0;
/*Ak ernelmoduleltav olitasaelottafelszabaditasok atv egzi.*/
staticv oid exithello_exit(v oid)
/*Megszuntetj uk amegszak itask ezeloregisztracioj at.*/
if(cirq>=0)free_irq(cirq,&dev id);
/*Megsemmisitj uk awork queue-t.*/
destroy _work queue(hello_wq);
/*Megsemmisitj uk aprocallomany bej egy zest.*/
remov e_proc_entry ("hello",0);
module_init(hello_init);
module_exit(hello_exit);
MODULE_DESCRIP TION("Helloproc");
MODULE_LICENSE("GP L");
A plda mkdsben megegyezik a kisfeladat tmakrnl ltottakkal, azzal
az eltrssel, hogy itt munkasort hasznltunk a feladat vgrehajtsakor.
42 0
7.16. A kernelszlak
7.16. A kernelszlak
A megszaktskezels als rszeknt kernelszlakat is hasznlhatunk. Ez ha-
sonlt a munkasor esetre, m tbb lehetsgnk nylik, mert mi magunk v-
gezzk a szlkezelst. Pldul a megszakts hatsra akr egy felhasznli
mdban fut programot is elindthatunk, vagy kommuniklhatunk vele.
(Lsd a call_usermodehelper04.)
Termszetesen a megszaktsokon kvl ms esetekben is alkalmazhat-
juk a kernelszlakat, tipikusan akkor, amikor egy hossz adatfeldolgozs
megvalstsra van szksgnk.
A kernelszl (kernek thread) lnyegben egy olyan folyamat, amelynek
nincs virtulis cmterlete a felhasznli cmtartomnyban. Ehelyette a sz-
lak a kernel cmtartomnyn osztoznak. Erre a memriakezelsnl oda kell
figyelnnk.
A kernelszl ltrehozshoz elszr is meg kell rnunk a szlfggvnyt,
amely a szl belpsi pontjaknt szolgl, hasonlan az alkalmazsszint szl-
kezelshez. A szlfggvny alakja az albbi:
int thr
dfh(v oid*data);
Ezt kveten egy alv llapot szlat az albbi fggvnnyel hozhatunk ltre:
A threadfn a szl f fggvnye. A data a fggvnynek tadott paramter.
A namefmt, ... rsz a szl neve printf-es alakban argumentumokkal vagyis
egy formz szveg, majd egy nem meghatrozott szm paramter. Vissza-
trsi rtkknt megkapjuk a szlat ler struktrra mutat pointert. Ezzel
hivatkozhatunk ksbb a szlra.
Mivel jelenleg mg alv llapotban van a szlunk, fel kell bresztennk:
intwak e_up. prcrcess(strct
-
t k t 'sk );
A ltrehozs s az breszts mvelett egyben is elvgezhetjk:
struct task_struct *kthread_run(int (*threadfn)(void *data),
void *data, const char namefmt[], ...);
A fggvny paramterezse megegyezik a szl ltrehozsnl ltottakkal.
Ezeknek a fggvnyeknek a meghvsa utn ltrejtt a kernelszlunk, s
egyms utn hajtja vgre a szlkezel fggvnyben foglalt utastsokat. Ami-
kor a fggvnynek vge, akkor a szl is lell. Fontos, hogy a szlat kvlrl
nem llthatjuk le. Ennek az az oka, hogy egy ilyen vletlenszer idpontban
421
7. fejezet: Fejleszts a Linux-kernelben
elkvetett megszakts nem definilt llapotba hozhatn a rendszert. Helyet-
te a kezelfggvnynkben kell rendszeresen ellenrizni, hogy szlunkat ms
szlak le akarjk-e lltani. Ezt a kvetkez fggvnnyel tehetjk meg:
intk thread_should_stop(v oid);
A 0-tl eltr rtk jelenti, hogy le kellene lltanunk a szlunkat, ezrt a
fggvny kzvetlenl hasznlhat az if paramtereknt.
Ha ezt implementltuk, akkor a szl lelltst egy msik szlbl az
albbi fggvnnyel krhetjk:
intk thread_stop(structtask _struct*k );
Figyeljnk arra, hogy ezt a fggvnyt mr lellt, nem ltez szlakra ne hv-
juk meg, mert hibt eredmnyez.'"
Feladatrjunk egy kernelmodult, amely elindt egy szlat. A szl msodpercenknt nveljen
egy szmllt, amelynek rtkt ki is rja. Emellett figyelnnk kell arra, hogy a modul eltvol-
tsa eltt le kell lltanunk a szlat.
/* hellothread.c - Egyszeru szalkezeles.
* 7
#include <li nux/modul e . h>
#include <1 i nux/kernel . h>
#include <1 i nux/i ni t .h>
#include <11 nux/kth read . h>
struct task_struct* pth;
/* A szal fo fuggvenye. */
int mythread(void* arg)
{
int i =0;
/*Aleallitasi kerelem ellenorzese. */
while(lkthread_should_stop())
{
ssleep(1);
printk("thread: %d\n", 1);
1++;
}
return 0;
108
A kdban elg nehz annak ellenrzse, hogy egy szl l-e mg. Ezrt ha a kthread_stop0
fggvnyt akarjuk hasznlni, akkor a szlat gy implementljuk, hogy csak ennek a
fggvnynek a hatsra lljon le. Ezzel teljestjk az emltett kvetelmnyt.
422
7.17. Vrakozs
staticint inithello_init(v oid)
{
/* A szalletrehozasaeselinditasa.*/
pth=k thread_run(my thread, NULL, "my thread");
return0;
staticv oid_exithello_exit(v oid)
{
/*Aszalleallitasanak k erelmezese.
k thread_stop(pth);
module_init(hello_init);
module_exit(hello_exit);
m00uLE_DEscRIP TION("Hellomodule");
mOpuLE_LICENSE("GP L");
A pldban szerepl ssleep0 fggvnyt a kvetkez fejezetben trgyaljuk.
7.17. Vrakozs
Az eszkzkkel val kommunikci sorn gyakran van szksgnk kisebb
nagyobb vrakozsok implementlsra a kdunkban, hogy az adott protokoll
idztseit tartani tudjuk.
A vrakozs ideje alapjn kt esetet klnbztethetnk meg. A rvid s a
hossz vrakozst attl fggen, hogy a rendszer rajelnl (jiffy) rvidebb
vagy tbb rajelnyi vrakozsrl van sz.
A vrakozs mdja alapjn van olyan fggvny, amely egy ciklus futtats-
val ri el a megfelel idej vrakozst, s van olyan, amelyik ms folyamatra
vlt t, amg eltelik az id.
7.17.1. Rvid vrakozsok
Amikor a vrakozs rvidebb lehet a jiffy idejnl, s nhny nano-, micro-,
vagy millisecundum, akkor az albbi fggvnyek hasznlhatk a vrakozsra:
v oidndelay (unsignedlongnsecs);
v oidudelay (unsignedlongusecs);
v oidmdelay (unsignedlongmsecs);
42 3
7. fejezet: Fejleszts a Linux-kernelben
Ezek a fggvnyek a processzor sebessge alapjn szmtott vrakoz ciklu-
sokat futtatnak, amelyek lefoglaljk az adott processzort. Van egy msik
megolds, amely a sleep fggvnyre pt. Ehhez a kvetkez fggvnyeket
hasznlhatjuk:
v oidmsleep(unsignedintmsecs);
unsignedlongmsleep_interruptible(unsignedintmsecs);
v oidssleep(unsignedintseconds);
Az els kt fggvny a meghatrozott millisecundum idre alv llapotba he-
lyezi a hv processzt. Az utbbi megszakthat, s a visszatrsi rtke jelzi,
hogy mennyi millisecundum van mg htra a meghatrozott id elteltig.
Az ssleepQ nem szakthat meg, s a megadott msodpercig helyezi alv lla-
potba a processzt. Ezeknek a fggvnyeknek a htrnya, hogy a tnyleges v-
rakozs tbb lehet a megadott idnl.
7.17.2. Hossz vrakozs
A tbb jiffy idej vrakozs esetn az egyik lehetsgnk egy ciklus hasznla-
ta, amely az adott jiffy ideig tart:
while(time_after(j time, ji ffi es))
{
//mag
A pldban a jtime az ltalunk megadott ksbbi jiffyben mrt azon idpont,
ameddig a ciklus tart. A ciklus magjnak tbb fggvnyt is hasznlhatunk.
Ha pontos vrakozst szeretnnk, akkor hasznlhat a epurelax() fggvny,
amelynek az implementcija platformonknt eltr lehet. A msik lehetsg,
hogy lemondunk a CPU-rl a schedule() fggvny meghvsval.
A ciklusos megoldsnl knyelmesebb egy timeouttal dolgoz fggvny
alkalmazsa. Lehetnek ilyenek a korbbiakban, a blokkold fggvnyeknl
ismertetett wait_event fggvnyek:
wait_ev ent_timeout(wait_queue_head_tqueue,intcondition,
longtimeout);
wait_ev ent_interruptible_timeout(wait_queue_head_tqueue,
ntcondition,longtimeout);
Ezek a fggvnyek egy vrakozsi sor ltrehozst ignylik. Ltezik ugyan-
akkor egy konkrtan erre a clra kszlt megolds is, amelyet a kvetkez
fggvnyekkel rhetnk el
424
7.18. Idztk
signed long schedule_timeout(signed long timeout);
signed long schedule_timeout_interruptible(signed long timeout);
signed long schedule_timeout_uninterruptible(signed long timeout);
Ezek a fggvnyek a meghvsuk utn belltanak egy idztt, majd vrako-
z llapotba vltjk a folyamatot, hogy addig ms folyamatok futhassanak.
Az idzt lekezel fggvnye ismt felbreszti a folyamatot.
Br a paramter tpusbl arra kvetkeztethetnk, hogy a timeout argu-
mentumnak negatv rtket is megadhatunk, valjban ekkor a fggvny
azonnal visszatr, s hibajelzst r ki a konzolra.
7.18. Idztk
Elfordulhat, hogy ksleltetve, aszinkron mdon kell vgrehajtanunk mvele-
teket. Ilyenkor hasznlhatjuk a kernelben lv idztket. Ehhez ltrehozunk
egy fggvnyt, amelyet megadott idkznknt a rendszer meghv. Erre a
fggvnyre ugyanazok a megszortsok rvnyesek, mint a megszaktskeze-
l fggvnyekre, mert egy megszaktskezel futtatja.
A kezelfggvny alakja a kvetkez:
unc(w rtsi gned
A ler adatstruktra a ti mer fggvny regisztrlshoz az albbi:
struct timer_list {
unsigned long expres;
void ("function)(unsigned long);
unsigned long data;
1;
A struktra bvebb, s a maradk rszek inicializlshoz szksg van az
albbi fggvnyek valamelyiknek a meghvsra:
void init_timer(struct timer_list * timer);
TINIER_INITIALIzER(_function, _expires, _data)
A kt lpst egyben is elvgezhetjk a kvetkez fggvny hasznlatval:
void setup_timer(struct timer_list * timer,
void ("function)(unsigned long), unsigned long data);
4 25
7. fejezet: Fejleszts a Linux-kernelben
A kvetkez fggvnyekkel ebben a sorrendben engedlyezhetjk, tilthatjuk,
vagy mdosthatjuk az idztt:
void add_timer(struct timer_list * timer);
int del_timer(struct timer_list * timer);
int mod_timer(struct timer_list * timer, unsigned long expi res);
SMP-rendszereken az idzt trlsekor elfordulhat, hogy kzben a kezel-
fggvny egy msik processzoron mg fut. Ezrt ltezik a fggvnynek egy
olyan varinsa, amely csak akkor tr vissza, ha a kezelfggvny mr befeje-
zdtt. Ennek alakja gy nz ki:
int del_timer_sync(st uct timer_l t *timer);
Lekrdezhetjk, hogy a timer fggvny el van-e jegyezve futtatsra, vagyis a
megadott id lejrt-e:
int timer_pending(const struct timer_list * timer);
7.19. Eszkzvezrl modell
A szmtgpben tallhat eszkzk tbbnyire klnbz buszokon keresztl
csatlakoznak a rendszerhez. Ezek a buszok eltren mkdnek, a rajtuk foly
kommunikci ms s ms.
A 2 .4 -es s a korbbi kernelekben a klnbz buszokra csatlakoz eszkzk
vezrlkdjaiban eltr struktrk tartottk nyilvn a rendszerbe csatlakoztatott
eszkzket, ltalnos knyvels nem ltezett. gy egy eszkz jelenltrl csak
a kernelzenetek bngszsvel szerezhettnk tudomst Ez a kaotikus helyzet
a 2 .5-s kernelben olddott meg, majd ez a megolds a 2 .6-os kernelnek is rszv
vlt. Egy egysges eszkzvezrl modell alakult ki a buszok s a rajtuk helyet
foglal eszkzk lersra, tovbb a globlis knyvels is megoldott vlt.
Az adatstruktra hozzfrhet s kezelhet, gy mr pontos kpnk van az rend-
szerben tallhat eszkzkrl.
7.19.1. A busz
Br a buszok eltrnek egymstl, rendelkeznek olyan ltalnos jellemz'kkel,
amelyek egysgesen megtallhatk bennk. Ezek adjk az ltalnos buszmo-
dell alapjt. A buszler struktra az ltalnos attribtumokat s az ltalnos
mveletekhez tartoz visszahvand fggvnyek (callback function) mutatit
tartalmazza. Ilyen mvelet pldul az eszkzk feldertse (detection), a busz
lelltsa, a tpellts kezelse.
426
7.19. Eszkzvezrl modell
Egy buszt a kernelben a bus_type adatstruktra r le. Ez a kvetkezkp-
pen nz ki:
struct bus_type {
const char
struct bus_attri bute
struct devi ce_att ri bute
struct dri ver_attri bute
*name;
*bus_attrs;
*clev_attrs ;
*dry_attrs ;
int (*match)(struct device *dev, struct device_driver *drv);
int (*uevent)(struct device *dev, struct kobj_uevent_env *env);
int (*probe)(struct device *dev);
int (*remove)(struct device *dev);
void (*shutdown)(struct device *dev);
int (*suspend)(struct device *dev, pm_message_t state);
int (*resume)(struct device *dev);
const struct dev_pm_ops *pm;
struct subsys_private *p;
};
A mezk rtelmezse a kvetkez (7. 7. tblzat):
7 .7 . tblzat. A busz regisztrcisstruktra-mezi
Nv rtelmezs
name A busz neve.
bus_attrs A busz alaprtelmezett attribtumai.
dev_attrs A buszra csatlakoztatott eszkzk alaprtelmezett attribtumai.
drv_attrs A busz eszkzvezrlinek alaprtelmezett attribtumai.
match Ez a fggvny hvdik meg, amikor j eszkzt vagy eszkzvezrlt adunk
a buszhoz. Nulltl eltr rtkkel kell visszatrnie, ha az eszkzvezrl
kezelni tudja az eszkzt.
uevent Ez a fggvny hvdik meg, ha egy eszkzt hozzadunk vagy eltvoltunk
a rendszerbl.
probe Meghvdik, amikor j eszkzt vagy eszkzvezrlt adunk a buszhoz, s
meghvja az eszkzvezrl probe fggvnyt.
remove Meghvdik, amikor egy eszkzt eltvoltunk a buszrl.
shutdown A rendszer lelltsakor hvdik meg, hogy az eszkzket lelltsa.
suspend Akkor hvdik meg, amikor a buszon tallhat egyik eszkz alv mdba
akar kapcsolni.
resume Akkor hvdik meg, amikor a busz egyik eszkzt fel kell bresztenie.
pm Tpmenedzsment-mveletek.
p A busz eszkzvezrljnek privt adatait trol struktra.
427
7. fejezet: Fejleszts a Linux-kernelben
Egy j busz regisztrcijakor az eszkzvezrlben minimum a nevet s a
match fggvnyt meg kell adnunk. Pldul:
structbus_ty pepci_bus_ty pe={
.name="pci",
. match=pci_bus_match,
;
Ezen kvl a struktrt a headerllomnyban ki kell exportlnunk:
struct b4s.,t0e
A regisztrcit a kvetkez fggvny vgzi el:
itt bus-.l giste uc't'bus-Ay0
A match() fggvny implementcija buszfgg. Ennek az a feladata, hogy
megllaptsa, hogy egy bizonyos eszkzt egy bizonyos eszkzmeghajt kpes-e
kezelni Amikor egy j eszkzmeghajtt tltnk be, akkor a match0 fggvny
meghvdik minden olyan eszkzre, amelyet nem kezelnek mg a korbbi
eszkzmeghajtk, hogy a rendszer kidertse, vajon az j kezeli-e.
7.19.2. Eszkz- s eszkzvezrl lista
Korbban a buszhoz kapcsold eszkzk s eszkzvezrlk listjt a busz
eszkzvezrlje tartotta nyilvn a sajt egyni mdjn. Az ltalnos modell-
ben azonban ez a knyvels is helyet kapott.
A bus_type struktra p mezje tartalmazza a busz privt adatait. Ebben
kapott helyet az eszkzk s az eszkzvezrlk listja.
Az eszkzvezrlk listjn az albbi fggvnnyel tudunk vgigiterlni:
intbus_for_each_drv (structbus_ty pe*bus,
structdev ice_driv er*start,
v oid*data,int(*fn)(structdev ice_driv er*,
v oid*));
Hasonlan az eszkzk listjn iterl fggvny az albbi:
int bus_for_each_dev (structbus_ty pe *bus,structdev ice*start,
v oid*data,int(*fn)(structdev ice*dev ,
v oid*data));
Kereshetnk egy eszkzt nv szerint:
structdev ice*bus_find_dev ice_by _name(structbus_ty pe*bus,
structdev ice*start,constchar*name);
428
7.19.Eszk zv ez rlmodell
Esetleg gy is kereshetnk, hogy egy fggvnnyel teszteljk, hogy megtall-
tuk-e:
structdev ice"bus_find_dev ice(structbus_ty pe*bus,
structdev ice"start,v oid*data,
int("match)(structdev ice"dev ,
v oid*data));
7.19.3. sysfs
A sysfs llomnyrendszerben tallhat egy knyvtr, ahol elrhet'k az eddig
trgyalt informcik:
Ebben a knyvtrban minden regisztrlt busz kap egy, a nevvel megegyez
knyvtrat. A busz knyvtrban megtallhatk a busz attribtumait repre-
zentl virtulis llomnyok, tovbb egy drivers s egy devices alknyvtr.
Ezek tartalmazzk az elz fejezetben emltett eszkzvezrl- s eszkzkny-
velst. Minden eszkz, illetve eszkzvezrl tovbbi alknyvtrakat kap, ame-
lyekben elrhet'k az attribtumaik.
7.19.4. Buszattribtumok exportlsa
A korbbiakban lttuk, hogy a busz eszkzvezrlje rendelkezhet bizonyos
attribtumokkal. Ezeket az attribtumokat kiexportlhatjuk, s elrhetv
tehetjk a sysfs llomnyrendszeren keresztl. Ehhez els krben implemen-
tlnunk kell egy olyan fggvnyt, amely a virtulis llomny olvassakor hv-
dik meg, s egy msik opcionlist, amely rskor. Ezek alakja az attribtum
lerstruktrjban tallhat meg:
structbus_attribute{
structattributeattr;
ssize_t(*show)(structbus_ty pe*bus,char*buf);
ssize_t(*store)(structbus_ty pe*bus,constchar"buf,
size_tcount);
};
Az attribute struktra tartalmazza a nevet s a jogosultsgbelltsokat:
structattribute{
constchar*name;
mode_tmode;
} ;
42 9
7. fejezet: Fejleszts a Linux-kernelben
A show() fggvny az attribtum olvassakor hvdik meg. Az implementci-
jban a buf paramterben kapott bufferbe kell elhelyeznnk a visszaadand
szveget, s a visszatrsi rtkben kell megadnunk a szveg hosszt. Hason-
lt a korbban a proc llomny olvassnl lthat mvelethez.
A store0 fggvny az llomny rsakor hvdik meg. A buf paramterben
kapjuk a szveget tartalmaz buffert s a count paramterben a hosszt.
Visszatrsi rtkknt a kezelt byte-ok szmt adjuk vissza. A szveg rtel-
mezse s esetleg ms adattpusra alaktsa a fggvny feladata.
A fggvnyek implementcija utn a kiexportlst az albbi makrval
vgezzk el:
4
1
,4
4
1 d414
Sorban a nv, a jogosultsg, a show() fggvny, a store() fggvny. Ha csak
olvashat attribtumot szeretnnk kszteni, akkor a store0 fggvny muta-
tja helyett NULL rtket kell megadnunk s megfelelen belltanunk a jo-
gosultsgokat.
A makr meghvsa megegyezik azzal, mintha ltrehoztunk volna egy
bus_attr_pelda vltozt az albbiak szerint, s belltottuk volna a mezk r-
tkeit:
staticbus_attributebus_attr_pelda
A kvetkez lps az, hogy a virtulis llomnyt hozzadjuk a sysfs knyvtr-
struktrhoz:
i nt bus_.c reat_fi le (sttu bus_type bus-a bute *
Itt meg kell adnunk a buszstruktra s az attribtumstruktra mutatjt, s a
fggvny hatsra ltrejn a virtulis llomny a busz knyvtrban. A busz
eszkzvezrl moduljnak eltvoltsakor termszetesen meg kell szntet-
nnk az llomnyt. Ezt a kvetkez fggvnnyel tehetjk meg:
v oidbus_remov e_file(structbus_ty pe*,structbus_attribute;
7.19.5. Az eszkzvezrl
Az eddigiek sorn elksztettk s beregisztrltuk a buszunkat. Ezt kveten
be kell regisztrlnunk azokat az eszkzvezrlket, amelyek a buszra csatlakoz
eszkzket kezelik. Termszetesen nem minden eszkzhz kell ezt elvgezni,
csak eszkztpusokhoz, hiszen az egyforma eszkzk egyformn kezelhetk.
430
7.19. Eszkzvezrl modell
Az eszkzvezrlt az albbi adatstruktra rja le:
structdev ice_driv er{
constchar *name;
structbus_ty pe*bus;
structmodule *owner;
int(*probe)(structdev ice*dev );
int(*remov e)(structdev ice*dev );
v oid(*shutdown)(structdev ice*dev );
int(*suspend)(structdev ice*dev ,pm_message_tstate);
int(*resume)(structdev ice*dev );
conststructattribute_group**groups;
conststructdev _pm_ops*pm;
structdriv er_priv ate*p;
1;
A mez'k rtelmezse a kvetkez (7.8. tblzat):
7.8. tblzat. Az eszkzvezrl regisztrcis struktra mezi
Nv rtelmezs
name Az eszkzvezrl neve.
bus A busz, amelyhez az eszkzvezrl tartozik.
owner A kernelmodul, amelyhez tartozik (THIS_MODULE).
Akkor hvdik meg, ha egy j eszkzt csatlakoztatunk a buszhoz. Tesztel-
probe jk benne, hogy az eszkzt kezeli-e az eszkzvezrl, illetve elvgezzk az
sszerendelst.
remove Az eszkz eltvoltsakor hvdik meg.
shutdown A rendszer lelltsakor hvdik meg.
suspend Az eszkz elaltatsakor hvdik meg.
resume Az eszkz felbresztst implementlja.
groups Alaprtelmezett attribtumok.
pm Tpmenedzsment-mveletek.
p Az eszkzvezrl privt adatai.
Az eszkzvezrlben minimum a name s a bus mezket ki kell tltennk a
regisztrcihoz. Ezt kveten a regisztrcit az albbi fggvnnyel vgezhet-
jk el:
14 1
;driv regi er trgct
<f
eviCe4 iYer
431
7. fejezet: Fejleszts a Linux-kernelben
Ennek a prja az, amely megsznteti a regisztrcit:
void driver_unregister(struct device_driver * drv);
ltalban azonban az ltalnos eszkzvezrl struktra nem elg az sszes in-
formci trolsra. Tipikusan tovbbi adat szokott lenni az eszkzazonostk
tblzata, amelyeket az eszkzvezrl kezel. Ezek buszspecifikus adatok, gy az
ltalnos struktrba nem kerlhettek bele. Ezrt a klnbz busztpusok sa-
jt eszkzvezrl lerstruktrkat definilnak, amely egyrszt tartalmazza
az ltalnos struktrt, msrszt kibvti azt. Pldul a platformbusz
1

9
ese-
tn a kvetkez:
struct platform_driver {
struct device_driver driver;
struct pl atform_devi ce_i d "id_tabl e;
;
Ugyanakkor ezeket a kibvtett eszkzvezrl lerstruktrkat a korbbi
regisztrlfggvnynek nem adhatjuk t. Ezrt tipikusan minden busztpus
eszkzvezrl tartalmaz egy sajt eszkzvezrlt regisztrl s egy regisztr-
lst megszntet fggvnyt, amely a kibvtett struktrkkal dolgozik. Ez a
specilis regisztrlfggvny vgzi el a bus mez belltst is az eszkzve-
zrl lerstruktrjban. Nzzk meg pldaknt a platformbusz esett:
int pl atform_dri ver_regi ster (struct platform_driver * drv)
{
drv->driver.bus = &platform_bus_type;
return dri ver_regi ster(&dry->dri ver) ;
Az eltvolts a kvetkez:
void pl atform_d ri ver_un regi ster(struct platform_driver * drv)
{
driver_unregi ster(&drv->driver) ;
}
sszegezve: ha egy olyan buszhoz szeretnnk regisztrlni egy eszkzvezrlt,
amely nem az ltalnos lerstruktrt hasznlja ilyen a buszok tbbsge ,
akkor a buszspecifikus lerstruktrbl hozunk ltre egy pldnyt, s azt
tltjk ki, tovbb a buszspecifikus regisztrl- s eltvoltfggvnyeket
hasznljuk.
109
A platformbusz nem valdi busz. Ide soroldnak azok a specilis hagyomnyos hardve-
rek, amelyek nem buszra csatlakoznak, ilyen pldul a billentyzetvezrl.
4 32
7.19. Eszkzvezrl modell
7.19.6. Eszkzvezrl attribtumok exportlsa
Hasonlan a busz attribtumaihoz az eszkzvezrlnek is hozhatunk ltre s
exportlhatunk attribtumokat. Az eljrs megegyezik a korbbival, csak az
adattpusok s a fggvnyek neve ms, ezrt a rszletes magyarzatot nem
ismteljk el, az a buszattribtumoknl olvashat (lsd a 7.19.4. Buszattrib-
tumok exportlsa alfejezetben).
Az eszkzvezrl attribtumtpusa a kvetkez:
struct driver_attribute {
struct attribute attr;
ssize_t (*show)(struct device_driver *driver, char *buf);
ssize_t (*store)(struct device_driver *driver, const char *buf,
size_t count);
};
A mezk megegyeznek a bus_attribute tpus mezivel a fggvnyek param-
terezst leszmtva. rtelmezsk ugyanaz.
A ltrehozst s inicializlst vgz makr az albbi:
. DRiVER_ATTR,(h4 j09
0
SUltS g,
ShoWfv,
storefv)
A makrval ltrehozott vltoz neve driver_attr_nv lesz.
Az attribtum virtulis llomnyt ltrehoz, illetve eltvolt fggv-
nyek a kvetkezk:
int driver_create_file(struct device_driver *driver,
const struct driver_attribute *attr);
void driver_remove_file(struct device_driver *driver,
const struct driver_attribute *attr);
7.19.7. Az eszkz
Az eszkzk ltalnos ler struktrja az albbi:
struct device {
struct device *parent;
struct device_private
const char
const struct device_type
struct mutex
struct bus_type
struct device_driver
void
*
P;
*init_name;
*type;
mutex;
*bus;
*driver;
*platform_data;
dev_t devt;
433
7. fejezet: Fejleszts a Linux-kernelben
struct cl ass * cl ass ;
const struct attri bute_group * * groups ;
void (* rel ease) (struct device * dev) ;
};
A mezk rtelmezse a kvetkez (7.9. tblzat):
7.9. tblzat. Az eszkz regisztrcisstruktra -mezi
Nv
parent
init_name
type
mutex
rtelmezs
Az eszkz szlje, vagyis az az eszkz, amelyre r van csatlakoz-
tatva. Ez tbbnyire egy busz vagy egy vezrl.
Az eszkz privt adatai.

Az eszkz neve.
Az eszkz tpusa.
Az eszkzhz rendelt mutex az eszkzvezrl mveleteinek szink-
ronizlshoz.
bus A buszeszkz, amelyre csatlakoztatva van.
driver A driver, amelyik alloklta ezt a struktrt.
platform_data Trolhely, ahova az eszkzvezrl az eszkzhz kapcsold in-
formcikat helyezheti. Ilyenkor ltrehoz egy egyni adatstrukt-
rt, s ide helyezi a mutatjt.
devt
class
groups
release
A sysfs-en bell, illetve udev-vel eszkzllomny gyrtshoz.
Az eszkz osztlya.
Opcionlis csoportattribtumok.
Akkor hvdik meg, amikor az eszkzler struktrt megsemmis-
ti a busz eszkzvezrlje.
A busz eszkzvezrlje rzkeli az eszkz csatlakoztatst. Ennek hatsra
ltrehoz egy pldnyt a device struktrbl, s regisztrlja a kvetkez fgg-
vnnyel:
intdev ice_register(structdev ice*dev );
Az eszkz akkor sznik meg, ha a referencia szmllja elri a 0-t. A referen-
ciaszmllt nvelni s cskkenteni az albbi fggvnyekkel tudjuk:
struct device *get_device(struct device *dev);
void put_device(struct device *dev);
A get_device0 fggvny visszaadja a struktra mutatjt abban az esetben,
ha az mg ltezik. Ha a referenciaszmll mr elrte a 0 rtket, akkor mr
megsznt az eszkz.
434
7.19.Eszk zv ez rlmodell
Emellett az eszkzn vgzett mveletek szinkronizlshoz hasznlhat-
juk az eszkz struktrjban szerepl mutexmezt. Ezt az albbi mveletek-
kel foglalhatjuk le:
v oiddev ice_lock (structdev ice*dev );
intdev ice_try lock (structdev ice*dev );
Felszabadtani pedig a kvetkez fggvnnyel tudjuk:
v oiddev ice_unlock (structdev ice*dev );
7.19.8. Az eszkz attribtumainak exportlsa
Hasonlan a buszhoz s az eszkzvezrlkhz az eszkzknek is megadha-
tunk attribtumokat, s kiexportlhatjuk. Ebben az esetben is hasonl tpu-
saink s fggvnyeink vannak, mint a busz esetben. (Bvebb informcit a
7.19.4. Buszattribtumok exportlsa alfejezet tartalmaz.)
Az eszkz egy attribtumt ler struktra az albbi:
structdev ice_attribute{
structattributeattr;
ssize_t(*show)(structdev ice*dev ,
structdev ice_attribute*attr,char*buf);
ssize_t(*store)(structdev ice*dev ,
structdev ice_attribute*attr,
constchar*buf,size_tcount);
1 ;
A mezk rtelmezse megegyezik a busz attribtumainl trgyalttal, csak a
fggvnyek paramterezse tr el tle.
Az attribtum ltrehozst s inicializlst vgz makr a kvetkez:
DEVICE_ATTR(n V,md, showfv ,storefv )
A makrval ltrehozott vltoz neve dev_attr_nv lesz.
Az attribtum virtulis llomnyt ltrehoz, illetve eltvolt fggv-
nyek az albbiak:
intdev ice_create_fi1e(structdev ice*dev ice,
conststructdev ice_attribute*entry );
v oiddev ice_remov e_fi1e(structdev ice*dev ,
conststructdev ice_attribute*attr);
435
7. fej ezet:Fej leszt saLinux-k ernelben
7.19.9. Plda
Az eszkzvezrlmodell hasznlatra nzznk egy nagyon egyszer pldt.
A pldban egy meglv buszhoz, a platformbuszhoz adunk hozz egy eszkz-
vezrlt. Majd mivel ez a busz rtelem szerint nem tudja rzkelni, hogy a
kpzeletbeli eszkznket csatlakoztattuk hozz, ltrehozunk egy eszkzt is:
/*dev attr.c-Egy szerudev iceextrasy sfsattributumok k al.*/
#include<linux/module.h>
#include<linux/k ernel.h>
#include<linux/platform_dev ice.h>
#defineDRV_NAME"dev attr"
staticinti=0;
/*Azattribtumlek rdezfggv ny e*/
staticssize_tshow_num(structdev ice*dev ,
structdev ice_attribute*attr,char*buf)
{
returnsprintf(buf,"%d\n",i);
/*Azattribtumbe ll tfggv ny e*/
staticssize_tstore_num(structdev ice*dev ,
structdev ice_attribute*attr,
constchar*buf,size_tcount)
sscanf(buf,"%d",&i);
returncount;
}
/*Azattribtum ssze ll t sa*/
DEv ICEATTR(num,S_IRUGO1S_IWUSR,show_num,store_num);
staticint_dev initdev attr_probe(structplatform_dev ice*pdev )
{
dev _info(&pdev ->dev ,"probe");
dev ice_create_file(&pdev ->dev ,&dev _attr_num);
return0;
staticint_dev exitdev attr_remov e(structplatform_dev ice*pdev )
{
dev _info(&pdev ->dev ,"remov e");
dev ice_remov e_file(&pdev ->dev ,&dev _attr_num);
return0;
43 6
7.19.Eszk zv ez rlmodell
staticstructplatform_driv ermy _driv er={
.probe=dev attr_probe,
.remov e= dev exit_p(dev attr_remov e),
.driv er={
.name=DRV_NAME,
.owner=THIS_MODULE,
}
};
staticstructplatform_dev ice*my _dev ;
staticint initmy _init(v oid)
{
interr;
err=platform_driv er_register(&my _driv er);
if(err)
returnerr;
my _dev =platform_dev ice_register_simple(DRv _NAmE,-1,NULL,0);
if(IS_ERR(my _dev ))
{
platform_driv er_unregister(&my _driv er);
returnP TR_ERR(my _dev );
return0;
staticv oid exitmy _exit(v oid)
{
platform_dev ice_unregister(my _dev );
platform_driv er_unregister(&my _driv er);
module_init(my _init);
module_exit(my _exit);
MODULE_DESCRIP TION("Dev iceattr");
MODULE_LICENSE("GP L");
Az eddig trgyalt fggvnyeken kvl a pldakd hasznlja a platformbusz
egy specilis eszkzt ltrehoz s regisztrl fggvnyt:
staticstructplatform_dev ice*platform_dev ice_register_simple(
constchar*name,intid,conststructresource*res,
unsignedintnum);
Erre a fggvnyre azrt van szksg, mert a virtulis platformbusz szmos
olyan eszkzt foglal magba, amelynek az rzkelse specilis, gy a rendszer
nem tudja rzkelni ezek csatlakoztatst. Ezrt a tbbi busztl eltren itt
manulisan is ltrehozhatjuk az eszkzket.
43 7
7. fejezet: Fejleszts a Linux-kernelben
A name paramterekben meg kell adnunk az eszkz nevt. Azonostk hi-
nyban fontos, hogy az eszkzt az eszkzmeghajtval azonos nven hozzuk
ltre, mert ez jelzi a kztk lv kapcsolatot.
Az id paramter tbb eszkz esetben az adott eszkz sorszmt tartal-
mazza. Ha csak egy eszkz szerepelhet a rendszerben, akkor az rtke 1.
A res paramter tartalmazza az eszkzhz allokland erforrsokat, mg
a num ezek szmt.
Ha manulisan hoztuk ltre az eszkzt, akkor az eltvoltsrl is gon-
doskodnunk kell. Ezt a kvetkez fggvnnyel tehetjk meg:
voi d pl atform_devi ce_unregi ster(struct pl atform_devi ce *pdev) ;
7.20. Tovbbi informcik
A clunk ezzel a fejezettel az, hogy az eszkzvezrl kernelmodulok fejleszt-
snl leggyakrabban hasznlt eszkzket, illetve leggyakrabban tapasztalt
problmkat bemutassuk. m szmos olyan tovbbi terlet maradt a kernel-
programozs tmakrben, amelyre nem trtnk ki. Az albbiakban nhny
forrst javasolunk, ahol az rdekld olvas tovbbi informcit tallhat a
munkjhoz. Viszont mg ezek a dokumentumok sem tartalmazzk a kernel
teljes lerst, hiszen a tma kiterjedtsge miatt ez majdnem lehetetlen fela-
dat. Vagyis biztosan maradnak olyan rszek, amelyet csak a kernel forrsbl
fejthetnk vissza.
A legels javasolt forrs nagyon hinyos s egyltaln nem rendszerezett,
m nhny informci csak itt lelhet fel. Ez pedig a kernelforrs Documenta-
tion knyvtra, amelyet korbban is emltettnk.
Olvasmnyosabb, de nmikppen elavult a http: //www.tldp.org/guides.html
cmen tallhat The Linux Kernel Module Programming Guide.
Tapasztalatunk szerint az egyik legjobb knyv a Linux Device Drivers,
Jonathan Corbet, Al essandro Rubini s Greg Kroah-Hartman tollbl.
Emellett kifejezetten rszletes tmutatt a kernel mkdsrl a Profes-
sional Linux Kernel Architecture cm knyvben tallhatunk.
Szmos online webes intormciforrst is tallhatunk. Kezd s kevsb
kezd kernelfejleszt'k szmra is kihagyhatatlan a http: / /kernelnewbies.org/
oldal.
Amikor a kernelforrst bngsszk, gyakran nehzkes tud lenni a hivatkoz-
sok kikeresse, lekvetse. Ebben nyjt nagy segtsget a http: / /lxr.linux.no/ ol-
dal, amely feldolgozza s linkek formjban egyszeren kezelhetv teszi a ke-
reszthivatkozsokat.
438
NYOLCADIKFEJEZET
A Qt keretrendszer
programozsa
8.1. Az X Window rendszer
Manapsg, ha egy opercis rendszer versenykpes szeretne lenni a piacon,
akkor ktsgkvl szksge van grafikus felhasznli felletre (Graphical
User Interface, GUI). A GUI egyrtelmen bartsgosabb s knnyebben kezel-
het, mint a szveges terminl. A Unix rendszerek s a Linux grafikus fellete
az X Window rendszer (vagy egyszeren X), amely hasonlan sok ms unixos
fejlesztshez egy akadmiai projekt eredmnye: az MIT-n fejlesztettk ki.
A Unix kezdetek ta rendelkezik a tbbfelhasznls (multiuser), a
tbbfeladatos (multitask) kpessgekkel, illetve a hlzatok elterjedse ta
tmogatja a tvoli bejelentkezst is. Az X architektrjt is gy alaktottk
ki, hogy illeszkedjen ebbe az elkpzelsbe.
Az X az Athena projekt keretben, 1984 -ben jtt ltre. 1988-tl az X kon-
zorcium felgyeli a fejlesztst s a terjesztst. Az X specifikcija szabadon
hozzfrhet, ezzel utat nyitottak az olyan ingyenes implementcik ltrejt-
tnek, amilyen pldul az XFree86 vagy az X.Org. Linux alatt is az utbbi
felletet hasznljuk, elterjedtsge azonban nem korltozdik kizrlag a Li-
nuxra, ms opercis rendszereken is (BSD, OS/2 ) hasznljk, st nevvel el-
lenttben ms CPU-architektrkon is.
8.1.1. Az X Window rendszer felptse
Az X-et kliens-szerver architektrjra alaktottk ki. Az alkalmazsok a kli-
ensek, amelyek kommuniklnak a szerverrel. Krseket kldenek, s infor-
mcikat kapnak. Az X szerver kezeli a kpernyt s a bemeneti eszkzket
(billentyzet, egr), a programok ezekhez nem frnek hozz, csak az X szer-
vert krik meg az egyes mveletek vgrehajtsra.
8. fejezet: A Qt keretrendszer programozsa
Ennek a megoldsnak az elnye egyrtelm: a kliensnek nem kell az
adott eszkz jellemzivel foglalkoznia, csak a szerverkommunikcit kell imp-
lementlnia. Ez pedig nem klnbzik attl, mintha csak egy grafikus knyv-
trat hasznlnnk.
m az X architektra ennl tovbb is megy. Nincs szksg arra, hogy a
kliens- s a szerveralkalmazs egy gpen fusson. A kliens-szerver kommuni-
kci hlzaton keresztl is megvalsthat brmilyen IPC-mechanizmussal,
amely megbzhat, adatfolyam-jelleg kommunikcit biztost.
Az X csomag tartalmaz egy fejleszti knyvtrat, az Xlib-et, amely az ala-
csony szint kliens-szerver kommunikcit implementlja. A programjaink-
ban csak ezeket a fggvnyeket kell hasznlnunk, hogy alkalmasak legyenek
arra, hogy X krnyezetben fussanak.
Amikor ablakos, grafikus felletet hasznlunk, akkor termszetes ig-
nynk, hogy a kliensablakokat kezelhessk: mozgathassuk, tmretezhessk,
minimalizlhassuk, maximalizlhassuk stb. Az X nem kezeli ezeket a mvele-
teket, ez a feladat az ablakkezelkre (Window Manager) vr. Az ablakkezel
dszti az ablakokat, illetve felletet biztost a felhasznlknak az ablakmve-
letekhez, de magukat az ablakmveleteket mr az X szerver implementlja.
Mivel az ablakkezel is csak egy kliensprogram, nem rsze az X szervernek,
gy kvnsg szerint cserlgethetjk, s szles vlasztkbl vlaszthatunk az
zlsnknek megfelelt.
Br az ablakkezel f feladata nevbl eredenden a kliensek ablakainak
a kezelse, emellett klnbz egyb funkcikkal is rendelkezhet. Az egyik
ilyen ltalnos funkci pldul a kliensprogramok indtsa.
8.1.2. X Windows kliensalkalmazsok
Ha az eddigi informciink alapjn vgunk neki az X-es alkalmazsunk fej-
lesztsnek az Xlib segtsgvel, hamar kiderl, hogy ez nem egyszer fela-
dat. Az Xlib csak a szksges alapokkal szolgl, s egy nyomgomb kiraksa,
szveg vagy egyb vezrlelem elhelyezse elg sszetett mvelet lehet.
110

Szerencsre a vezrlelemek nehzkes kezelse miatt ltrehoztak olyan
Xlib-re pl programozi knyvtrakat, amelyek egyszerbb teszik a fe-
ladatunkat. Ezeket a knyvtrakat widgetknyvtrnak (Widget Library)
nevezzk. Termszetesen hasznlatukkor nem ajnlatos az Xlib knyvtr
fggvnyeit kzvetlenl hvni, mert konfliktusba kerlhetnek egymssal.
Mivel ettl kezdve a widgetknyvtr felels minden elem megrajzolsrt
s kezelsrt, ezrt programunk kezeli felletnek jellemzi s viselkedse
nagyban fgg attl a knyvtrtl, amelyet vlasztottunk.
110
Az MS Windows alatti programozsban jratosakat leginkbb a Windows API absztrak-
cis szintjre emlkeztetheti.
4 4 0
8.1. Az X Window rendszer
Az els widgetknyvtr az Athena projekt keretben kifejlesztett Athena
knyvtr volt. Csak a legalapvetbb elemeket tartalmazza, s a vezrlele-
mek kezelse eltr a manapsg hasznlatosaktl. Az ezt kvet legismertebb
knyvtr az Open Software Foundation (OSF) Motif csomagja, amely 1980-tl
a korai 1990-es vekig volt elterjedt. A legkomolyabb hibja az, hogy slyos
sszegekbe kerl a fejleszti licenc. Manapsg mr vannak jobb alternatvk
rban, sebessgben, illetve szolgltatsokban. Ilyen pldul a Gtk, amely a
GIMP projekthez kszlt. Arnylag kicsi, sok szolgltatssal, bvthet, s
teljesen ingyenes. Vagy egy msik npszer eszkzkszlet, a Qt, amely a KDE
projekt ta ismert igazn, hiszen a KDE alapjt szolgltatja. A Qt keretrend-
szer s egy hozztartoz fejlesztkrnyezet ingyenesen hasznlhat, de lte-
zik fizets vltozata is, amely tovbbi szolgltatsokat s tmogatst biztost.
Tovbbi alternatva a LessTif, amely egy ingyenes API-kompatibilis helyette-
stje a Motifnak.
8.1.3. Asztali krnyezet
Kiderl teht, hogy felhasznlknt vlaszthatunk ablakkezelt kedvnk sze-
rint, s a programok ri is vlaszthatnak widgetknyvtrakat. Ennek a nagy
szabadsgnak azonban megvannak a htrnyai. A kliensprogram rja hat-
rozza meg, hogy milyen widgetknyvtrat hasznl. m mivel e knyvtrak
vezrlelemei nagyban klnbzhetnek, elfordulhat, hogy ahny programot
hasznlunk, annyiflekppen kell kezelni ket.
Ezek a widgetknyvtrak ltalban dinamikus programknyvtrakban
helyezkednek el, m ha a kliensprogramjaink klnbzket hasznlnak, ak-
kor ez tovbbi memrit ignyel.
Az ablakkezelk is sokflk, klnbz kezelsi koncepcikkal. Az egsz
fellet ennek kvetkeztben nem ll ssze egysges egssz. Nem lehet egy-
ben konfigurlni a kinzett, a kezelst.
Azrt trtnt ez gy, mert az X kialaktsa sorn a flexibilitsra s a fel-
hasznlk szabadsgra helyeztk a hangslyt, ellenttben egyb opercis
rendszerek (pldul a Windows s a MacOS) megktttsgeivel, zrtsgval.
m ez a fenti helyzethez vezetett, ezrt a szabadsggal szemben eltrbe ke-
rlt a komplex fellet ltrehozsa, s ez magval hozta az asztali krnyeze-
tek (Desktop Environment) kialakulst.
Az asztali krnyezet tartalmaz szolgltatsokat s mdszertanokat is,
amelyekkel a fellet egysgesthet, s a problmk lekzdhetk. Ugyanakkor
tbb fajtja is ltezik, s a vlaszts szabadsga gy megmarad. Az ismertebbek
a Motifra pl CDE (Common Desktop Environment), a Qt-alap KDE
(K Desktop Environment) s a Gtk-t hasznl GNOME. A tovbbiakban ezek
kzl a Qt programozst mutatjuk be, amely szles kr hordozhatsga s
hatkony felhasznlhatsga miatt az egyik legelterjedtebb krnyezet.
441
8. fejezet: A Qt keretrendszer programozsa
8.2. Fejleszts Qt alatt
A Qt (hivatalos kiejtse megegyezik az angol cute sz ejtsvel) egy C++ nyelv
keretrendszer platformfggetlen alkalmazsok programozsra. A keretrend-
szer rszt egy osztlyknyvtr s egy fejlesztkrnyezet kpezi. Az osztly-
knyvtr tmogatst nyjt tbbek kztt grafikus felhasznli felletek, a
tbbszl fejleszts, az I/O kezels, az erforrs-llomnyok, a hlzati kom-
munikci, az adatbzis-elrs programozsra. A Qt az opercis rendszerek
szles skljt tmogatja, tbbek kztt a Windows s Linux rendszereket, a
Mac OS platformot, a Symbian- s a Meego-alap mobileszkzket. Br a Qt
C++ nyelven kszlt, tbb nyelvhez ltezik mr programozsi fellete, gy a
Qt szolgltatsai elrhetk tbbek kztt Python, Java s PHP nyelveken is.
A 8.1. brn lthat, hogy a Linux-alap fejleszts esetn hogyan nz ki a
Qt keretrendszer segtsgvel fejlesztett alkalmazsok architektrja.
8.1. bra. Qt -architektra Linux platformon
Az opercis rendszerre pl a korbban bemutatott X Window (X11) ablakoz
rendszer, amely a grafikus megjelentst biztostja. Ezutn kvetkeznek a Qt
egyes komponensei, amelyeket moduloknak neveznk. A QtCore tartalmazza
a tbbi ltal is hasznlt alaposztlyokat, a QtGui pedig a grafikus felhaszn-
li fellethez szksges osztlyknyvtrat jelenti. A kt nagy alapkomponen-
sen kvl a tovbbi modulok kzl az adatbzis-elrst biztost QtSql s a
hlzatkezelst tmogat QtNetwork modulokat ebben a knyvben rszlete-
sebben is bemutatjuk.
442
8.2. Fejleszts Qt alatt
A Qt keretrendszer segtsggvel teht platformfggetlenl tudunk alkal-
mazsokat kszteni, a keretrendszer elfedi a klnbz opercis rendszereken
klnbsgeit. A Linux opercis rendszeren elrhet a KDE ablakoz rendszer,
amely maga is a Qt keretrendszeren alapul, s egy egysges krnyezet biztost-
sra az eszkzkszlett bvti. Ebben a knyvben a Qt alapszolgltatsait s fel-
ptst trgyaljuk, m ha valaki kifejezetten KDE-krnyezetben hasznlhat
alkalmazst fejleszt, akkor rdemes ennek a knyvtrnak a funkciit hasznlnia.
Ebben az esetben a Qt ltal biztostott hordozhatsgot valamilyen szinten elve-
sztjk, mert az alkalmazsok csak KDE knyvtraival egytt futnak.
8.2.1. Hello Vilg!
Bevezetsknt a kvetkez programban egy pldn keresztl bemutatjuk a
Qt kertrendszer hasznlatt s alapvet mkdst. Egy egyszer grafikus
felhasznli fellettel rendelkez alkalmazst hozunk ltre, amelynek a fel-
letn elhelyeznk egy Szveg:" feliratot, alatta egy szveg bevitelre alkal-
mas dobozt, illetve legalul egy Kilp" gombot. A felletrl egy kpernykpet
a 8.2. brn lthatunk.
8.2. bra. Hell Vilg" alkalmazsfellete
/* main.cpp */
#include <QAppl i cati on>
#include <Qmai nwi ndow>
#include <QVBoxLayout>
#include <Qt.abel >
#include <QTextEdi t>
#include <QPushButton>
443
8. fejezet: A Qt keretrendszer programozsa
int main(int argc, char * argv[])
f
QApplication app(argc, argv);
QWi dget*window=new QWi dget();
wi ndow->setWi ndowTitle("HellVil g");
QLabel*label=newQLabel("Sz v eg:");
QTextEdit*txtEdit=newQTextEdit();
QP ushButton*btn=newQP ushButton("Kil p");
QVBoxLay out*lay out=newQVBoxLay out();
window->setLay out(1 ay out);
1ay out->addWidget(1abel);
1ay out->addWidget(txtEdit);
lay out->addwidget(btn);
QObj ect::connect(btn,SIGNAL(click ed()),&app, sLoT(guit()));
window->show();
returnapp.exec();
}
A programunk egyetlen forrsllomnybl ll (main.cpp), ezen bell pedig a
main, fggvnyben hozzuk ltre a felletet. Az els ngy sorban az include
utastsok segtsgvel beptjk a Qt keretrendszerbl hasznlt osztlyok
definciit. Minden Qt-osztlyhoz egy kln headerfjl tartozik, amelynek neve
megegyezik az osztly nevvel. A keretrendszer sszes osztlynak neve ha-
gyomnyosan Q" betvel kezddik.
A main fggvnyben elszr egy QApplication objektumot hozunk ltre.
Ez az osztly felels az alkalmazs esemnykezel ciklusnak az elindts-
rt. Az esemnykezel ciklus fogadja tbbek kztt az ablakoz rendszertl
rkez esemnyeket, gy a felhasznli interakcikat is, amelyeket a megfelel
vezrl'khz tovbbt. Az esemnykezel ciklus addig fut, amg az alkalmazs
utols ablakt be nem zrjuk. (Az esemnykezelsre a ksbbiekben mg visz-
szatrnk.)
A Qt keretrendszerben az X Window rendszerhez hasonlan a grafi-
kus vezrlket widgeteknek nevezik. Minden grafikus elem a QWidget s-
osztlybl szrmazik. Egy alkalmazsban hasznlt vezrlket a keretrend-
szer automatikusan fastruktrba rendezi, vagyis minden elemnek pontosan
egy szlje s tetszleges szm gyereke lehet. Ezt a fastruktrt futs kz-
ben programozottan is be lehet jrni, benne a vezrlket tpus s nv alapjn
meg tudjuk keresni. A gyermekvezrlk mindig a szl terletn bell jelennek
meg. Az a vezrl, amelynek nincsen szlje, mindig egy nll alkalmazs-
ablakknt (top-level window) jelenik meg, ltalban ez azt jelenti, hogy sajt
fejlce (cmsora) s kerete van. A fenti kdban ltrehozott QWidget pldny
lesz az alkalmazs fablaka, mivel ennek nem adtunk meg szlt. A vezrl
setWindowTitle fggvnyvel adjuk meg az ablak cmt.
444
8.2. Fejleszts Qt alatt
A felleten a kvetkez tpus vezrlket helyezzk el:
QLabel (egyszer szveg kirsra),
QTextEdit (tbbsoros szvegbeviteli doboz) s
QPushButton (nyomgomb).
A vezrlk kialaktsa utn egy elrendezskezel (layout manager) objek-
tumot hozunk ltre, amelynek segtsgvel automatikusan elrendezzk a fe-
lletre elhelyezett elemeket. Az elrendezskezel felels a benne elhelyezett
vezrlk mretnek s pozcijnak automatikus lltsrt. Ez biztostja,
hogy pldul az ablak tmretezse utn is megfelelen legyenek elhelyezve
az elemek. A pldban hasznlt QVBoxLayout osztly fgglegesen egyms
al helyezi el azokat a vezrlket, amelyeknek az elrendezsrt felels. Egy
elrendezskezel objektumhoz az addWidget metdussal adhatjuk hozz az
elrendezend elemeket. A hozzads sorrendje termszetesen szmt, pldul
a QVBoxLayout ilyen sorrendben helyezi el a widgeteket egyms al.
A keretrendszerben az objektumok kztti kommunikcit az gynevezett
szignl-szlot mechanizmuson alapul esemnykezels teszi lehetv. Ennek
lnyege, hogy tetszleges, a QObject sosztlybl szrmaz osztly specilis
esemnytpusokat publiklhat, amelyeket szignloknak (signal) neveznk.
Egy adott esemnytpusbeli esemny bekvetkezst a szignl kibocstsval
(emit) jelezzk. Az esemnyekre specilis deklarcij fggvnyekkel, gyne-
vezett szlotokkal (s/ot) reaglhatunk. A szlotokat szintn a QObject sosz-
tlybl leszrmaz osztlyokban definilhatjuk. Ha egy szignlt sszektnk
egy szlottal, akkor valahnyszor kibocstjk a szignlt (jelzik a szignl ltal
reprezentlt esemnytpus egy konkrt elfordulst), a szlotfggvny meg-
hvdik. A fejleszts sorn a szignlfggvnyekhez nem ksztnk fggvny-
trzset, mert azt a Qt generlja helyettnk. A generlt fggvny biztostja,
hogy a szignllal sszekttt szlotfggvnyek meghvdjanak. A szlotfgg-
vny trzst termszetesen neknk kell definilni. Egy szignllal akr tbb
szlotfggvny is sszekthet, s egy szlotfggvnyt akr tbb szignllal is
sszekthetnk, az egyetlen megkts, hogy a szignlfggvny s a szlot pa-
ramterlistja megegyezzen. Amikor egy szignlt kibocstunk, a keretrend-
szer biztostja, hogy az sszes olyan szlotfggvny meghvdjon, amellyel a
szignlt sszektttk, s paramterknt megkapja a szignl kibocstsakor
megadott rtkeket. (A szignlok s a szlotok mkdst, valamint a keret-
rendszer esemnykezelsi modelljt lsd ksbb.)
Egy szignl s egy szlot sszektse a QObject osztly connect metdus-
val trtnik. A connect meghvsakor a SIGNALO s a SLOT() makrkat kell
hasznlni, hogy megadjuk a szignl- s a szlotfggvnyeket. A fenti pldban
a btn objektum clicked szignljt ktjk ssze a QApplication objektum quit
szlotjval az albbi fggvnyhvs segtsgvel:
QObj ect::connect(btn,SIGNAL(click ed()),&app,SLOT(quit()));
445
8. fejezet: A Qt keretrendszer programozsa
A QPushButton osztly ltal publiklt clicked szignl akkor kvetkezik be,
amikor a nyomgombot a felhasznl megnyomja. A Qt keretrendszer bizto-
stja, hogy ha a felhasznl az egrrel egy nyomgomb hatrain bell kattint,
akkor a nyomgomb megkapja ezt az zenetet. Ha a nyomgomb engedlyez-
ve van, kibocst egy clicked szignlt. Ezzel a szignllal kell sszektnnk
azokat a fggvnyeket, amelyek meghvst ki szeretnnk vltani a kattin-
tst jelz esemnnyel. Vagyis a kattintsesemny kezelshez a programoz-
nak csak egy szlotfggvnyt kell ltrehoznia s azt sszektnie a szignllal.
Brmilyen felhasznli beavatkozs esetn a Qt keretrendszer feldolgozza az
opercis rendszertl jv rtestst, ezek bekvetkezst pedig a vezrlk
szignlokkal jelzik.
A quit fggvny kilp az alkalmazsbl. Ezt a fggvnyt a QApplication
osztly szlotknt publiklja A szignl s a szlot sszektse biztostja, hogy
amint rkattintunk a gombra, az alkalmazs azonnal bezruljon.
Minden vezrl lthatatlan a ltrehozs pillanatban, amg meg nem hv-
juk rajta a show metdust. A pldban a fablakot jelentjk meg, amely gon-
doskodik arrl, hogy az sszes tartalmazott vezrl ugyancsak megjelenjen.
A main fggvny utols sorban elindtjuk az alkalmazsobjektum esemny-
kezel ciklust az exec fggvny segtsgvel. Ez akkor r vget, amikor meg-
hvdik az alkalmazs quit fggvnye, a ciklus mindaddig fogadja s tovbbtja
a felhasznli esemnyeket
Az egyetlen main.cpp forrsllomny megrsa utn a kvetkez lps a
program lefordtsa. A Qt keretrendszerben minden programhoz egy platform-
fggetlen projektllomny tartozik, amelynek kiterjesztse .pro. Ez az llo-
mny tartalmazza tbbek kztt a programhoz kapcsold forrsfjlok listjt.
A projektllomnyt a qmake programmal hozhatjuk ltre:
Az llomny neve a forrskdot tartalmaz knyvtr neve lesz.
A projektllomnyokbl szintn a qmake segtsvel tudunk platformspe-
cifikus make llomnyokat generlni:
A generlt make llomnyok segtsgvel az adott platformon elrhet ford-
tval mr a hagyomnyos mdon generlhatjuk a vgrehajthat programot:
make
446
8.2 .Fej leszt sQtalatt
8.2.2. Projektllomnyok
Az elz pldban elksztettnk egy egyszer Qt-alap grafikus alkalma-
zst, az albbiakban a program fordtst vizsgljuk meg rszletesebben.
A lert fordtsi folyamatnak kt Qt keretrendszer specifikus pontja van:
a .pro kiterjeszts projektllomny megrsa s
a platformspecifikus make llomnyok generlsa a qmake programmal.
Ezeket a feladatokat az integrlt fejleszti krnyezetek automatikusan el tudjk
vgezni, de azrt rdemes megismerkedni a projektllomnyok szerkezetvel.
A projektllomnyt megrhatjuk mi magunk is, de a qmake segtsgvel
generlhatjuk is a project kapcsol hasznlatval (lsd az elz pldban).
A korbbi, egyetlen main.cpp llomnyt tartalmaz programhoz a qmake
a kvetkez projektfjlt generlja:
##################################################################
# Automatically generatedby qmak e(2 .01a)P j l.113 :07:412 011
##################################################################
TEMP LATE=app
TARGET=
DEP ENDP ATH+=
INCLUDEP ATH+=.
# Input
SOURCES+=main.cpp
A projektllomnyok legfontosabb rszei a kvetkezk:
A # jellel kezdd sorok megjegyzsek, ezeket a feldolgozsnl a
qmake nem veszi figyelembe.
A megjegyzsek utni els sorban a TEMPLATE vltoznak adunk
rtket, ez ltalban app vagy lib lehet. Az app jelzi, hogy egy nll
futtathat alkalmazst akarunk generlni a projektbl, a lib pedig,
hogy egy programknyvtrat.
A TARGET vltozban megadhatjuk a generland file nevt (kiter-
jeszts s verziszm nlkl), res rtk esetn az alaprtelmezett
nv a projektllomnyt tartalmaz knyvtr neve.
A DEPENDPATH s az INCLUDEPATH vltozk rtkei troljk
azoknak a knyvtraknak a neveit, ahol a nem a projekthez tartoz,
de hivatkozott headerfjlokat s programknyvtrakat kell keresnie a
fordtnak.
447
8. fejezet: A Qt keretrendszer programozsa
A SOURCES vltoznl soroljuk fel a fordtand forrsllomnyokat.
Amennyiben klnll headerfjljaink is lennnek, azokat a HEADERS
utn kellene felsorolni.
A fenti vltozk esetben gyakran nemcsak egy, hanem tbb nevet is fel kell
sorolni, ilyenkor ezeket szkzzel elvlasztva rjuk le. Ha egy sor tl hossz,
akkor a \ jellel trhetjk, s j sorban folytathatjuk. Egy tovbbi lehetsg
az, hogy a += opertor segtsgvel lehet egy vltozhoz hozzfzni jabb r-
tket, ezt tbbszr is meg lehet tenni egyms utn. Az albbi pldban mind-
hrom lehetsget megmutatjuk:
SOURCES =sourcel.cppsource2 .cpp\
source3 .cpp
SOURCES +=source4.cpp
SOURCES +=source5.cpp
Egy projektllomny teht egy Qt-projektet r le, ahol a projekt tartalmazza a
generland alkalmazs vagy programknyvtr nevt, az sszes fordtand
forrsllomnyt s azokat a knyvtrakat, ahol a fordtshoz szksges hi-
vatkozott programknyvtrak megtallhatk. A projektllomny mindezeket
az informcikat platformfggetlen formban trolja.
A projektllomny megrsa utn, a qmake parancs kiadsval (a pro-
jektllomnyt tartalmaz knyvtrban) a projektllomnybl generlunk egy
platformspecifikus make llomnyt, amelyet mr hagyomnyosan tudunk
fordtani.
8.2.3. A QObject szolgltatsai
A Qt keretrendszer olyan specilis konstrukcikat biztost, amelyek lehetv
teszik az objektumok kztti hatkony kommunikcit (szignl-szlot mecha-
nizmus) s a metaadatokhoz val hozzfrst. A keretrendszer alaposztlya a
QObject. Ennek pldnyait a keretrendszer fastruktrba rendezve trolja,
amely programozottan bejrhat futs kzben, gy az objektumok kereshetv
vlnak. A Qt lehetv teszi olyan tulajdonsgok (property) definilst, ame-
lyek futsi idben lekrdezhetk.
A fenti szolgltatsok egy rszt hagyomnyos C++-technikkkal vals-
tottk meg, de bizonyos kiterjesztsek (pldul a szignl-szlot mechanizmus)
szksgess teszik egy specilis elfordt, a moc (Meta-Object Compiler)
hasznlatt. (A moc mkdsre a Qt esemnykezels-modelljnek trgyal-
snl visszatrnk.)
448
8.2. Fejleszts Qt alatt
8.2.4. A QtCore modul
A Qt keretrendszer nem csak grafikus felletek fejlesztshez szksges ve-
zrlket tartalmaz osztlyknyvtrat knl. Sok olyan osztly tallhat ben-
ne, amely a felhasznli fellettl fggetlen programozi interfszt biztost,
tbbek kztt pldul adatbzisok elrsre, hlzati kommunikci rsra
vagy tbbszl programozsra.
Amikor egy forrsfjlban a keretrendszer egyik osztlyra hivatkozunk,
akkor ehhez az include utastssal be kell pteni a megfelel osztlyt. A be-
ptend llomny neve megegyezik az osztly nevvel. A kvetkez sor szk-
sges ahhoz pldul, hogy a QApplication osztlyt tudjuk hasznlni a k-
dunkban:
<t Lica
A Qt keretrendszer knyvtra modulokra van osztva, ezek kzl az egyik a
grafikus komponenseket tartalmaz modul, a neve QtGui. Ha nem szeretnnk
egyenknt az sszes osztlyra gy hivatkozni, lehetsg van modulonknt be-
pteni a keretrendszer osztlyait, ekkor ltalban az adott modul nevt kell
kirni, pldul a grafikus modul esetben a kvetkezkppen:
#inclucte QtGui
Az gynevezett alapmodul a QtCore nevet viseli, ebben azokat az osztlyokat
definiltk, amelyeket az sszes tbbi modul hasznl. Ebben tbbek kztt ta-
llunk:
bonyolultabb adattpusok lersra szolgl osztlyokat (szveg
QString, dtum, idpont QDate, QDateTime, QTime, tglalap
QRectangle),
sablonalap gyjtemnyeket (lista QList, halmaz QSet, asszociatv
tmbk QHash, QMap),
szinkronizcis objektumokat (szemafor QSemaphore, mutex
QMutex),
tbbszl programozshoz szksges osztlyokat (QThread, QThread-
Pool, QTimer),
I/O kezelshez szksges osztlyokat (knyvtr QDir, fjl QFile,
QFilelnfo).
Az egyik fontos osztly, amelyet ebben a fejezetben nagyon gyakran haszn-
lunk, a QString, amellyel 16 bites unicode karaktersorozatokat trolunk.
Egy-egy karaktert a QChar osztllyal runk le, ezek gyjtemnye alkot egy
QStringet. Egy QString inicializlshoz tbb mdszert is vlaszthatunk.
449
8. fejezet: A Qt keretrendszer programozsa
Ltrehozhatjuk valamilyen szvegkonstans- (const char * tpus) kezdetir-
tkkel, de a karaktereket megadhatjuk egyenknt is. A szoksos indexelssel
lekrdezhetjk s mdosthatjuk az egyes karaktereket, illetve tovbbi fggv-
nyek is rendelkezsre llnak a szvegek mdostsra (append hozzfzs,
prepend elfzs, replace helyettests). Lehetsg van tovbb ms ka-
rakterkdols (Latin-1, ASCII, UTF8) szvegekkel val egyttmkdsre is:
A QString osztly hasznlatban fontos megemlteni a QStringBuilder osz-
tlyt, amellyel hatkonyan lehet szvegkonstansokat sszefzni. Ezt az osztlyt
explicit mdon nem kell pldnyostani, elg, ha beptjk a programunkba a
kvetkez utastssal:
r;01,00,
Ezutn a szvegek sszefzsre a % opertort hasznlhatjuk a szoksos +
opertor helyett. Ez a mdszer optimalizlja a szvegek msolsval jr
tbbszrs memriafoglalst:
#include <Q5tri ngsuilder>
QStringmessage = "hello " %"v il g"; //hatkony sszefzs
8.3. A Qt esemnykezels-modellje
A grafikus felhasznli fellet programozshoz egy j szemlletet kell k-
vetnnk, ennek a neve esemnyvezrelt programozs (event driven prog-
ramming). Mr az elz fejezetekben is tallkoztunk azzal a problmval,
amikor a program bemenetre vrva blokkoldik egy adott ponton. Pldul a
socketek esetben a recv fggvny addig blokkolt llapotban marad, amg
adat nem rkezik. Ez utbbi azrt okoz problmt, mert a programunk nem
tud ms feladatot elltni, amg a recv fggvny vissza nem tr. Ennek kezel-
sre tbb technikt is bemutattunk. Az sszes hatkony megolds abbl llt,
hogy megadtuk, milyen esemnyekre szeretnnk reaglni, majd a program
vrakoz llapotba kerlt, ahonnan valamelyik esemny bekvetkezse bil-
lentette ki. Erre a logikra ptve az egsz alkalmazst eljutunk az esemny-
vezrelt programozshoz.
450
8.3. A Qt esemnykezels-modellje
A recv blokkoldsnak egyik megoldsa volt pldul a select fggvny
hasznlata. A select fggvnynek meg kellett adni olyan lerkat, amelyekkel
megmondtuk, hogy milyen eszkzk (hlzat, szabvnyos beviteli eszkz stb.)
milyen jelleg esemnyeirl (pldul rs, olvass) szeretnnk rteslst kap-
ni Amikor a select visszatrt, megvizsgltuk, hogy milyen esemny trtnt,
majd ennek megfelelen reagltunk. Ez a megolds az esemnyvezrelt prog-
ramozsnak egyfajta megvalstsa:
megadjuk, hogy milyen esemnyekrl szeretnnk tudomst szerezni,
ha valamilyen esemny rkezik, arra reaglunk.
A modern GUI-krnyezetek ltalban nyjtanak valamilyen tmogatst az
esemnyvezrelt szemllet programozsra (ilyen pldul a Qt szignl-szlot
modellje), gy a select utni esetsztvlasztst maga a krnyezet biztostja.
Neknk csak azt kell megmondani, hogy milyen esemnyt szeretnnk leke-
zelni, s melyik kdrszlettel.
Az esemnyvezrelt programozssal teht egyszerre tbb beviteli eszkzt
is kezelhetnk, ugyanakkor az zenetkezelkben sztszrt kdokkal a prog-
ram megszokott szekvencilis futst elvesztettk, s ez egyttal bonyolul-
tabb is teszi az esemnyvezrelt programot a hagyomnyos, eljrsvez-
relt (procedure driven) szemllettel szemben.
Az esemnyvezrelt programozs megvalstsakor egy esemnykezel
ciklus indul el, amelyben a keretrendszer fogadja a klnbz tpus zene-
teket. Ezek az zenetek lehetnek az opercis rendszertl jv rtestsek
pldul valamilyen hardveresemnyrl, de lehetnek a sajt programunkban
definilt esemnyek (szignlok), amelyeket mi magunk kldnk. Az gy rke-
zett esemnyek egy vrakozsi sorba kerlnek. Az esemnykezel ciklus
folyamatosan fut, s sorban olvassa be az rkezett zeneteket, majd azok tar-
talmtl fggen hvja meg pldul az ltalunk megadott fggvnyeket.
A program befejezshez a ciklust kell lelltani, erre a keretrendszerek lta-
lban biztostanak valamilyen fggvnyt.
A Qt keretrendszer biztostja az esemnykezel ciklust, tovbb egy ese-
mnyvezrelt programozsi modellt, a szignl-szlot mechanizmust (lsd az els
pldnl). A QPushButton osztlynl lttuk, hogy a szignl-szlot mechanizmu-
son alapul a felhasznli fellet programozsa is. Az egyes vezrlelemeket
megvalst osztlyok szignlokat definilnak, ezekre rkapcsoldva tetszle-
ges felhasznli esemnyrl rteslhetnk. A rkapcsolds azt jelenti, hogy
megadunk egy fggvnyt (szlot), amely az esemny bekvetkeztekor megh-
vdik. A ksbbiekben bemutatjuk, hogyan lehet olyan osztlyt definilni,
amely maga is publikl szignlokat, illetve szlotokat.
Az esemnyeket a szignlok reprezentljk, az esemnyek kezelse pedig
a szlotokkal trtnik. Neknk kell kivlasztani, hogy mely szlotokkal mely
szignlokra akarunk feliratkozni, ezt nevezzk egy szignl s egy szlot ssze-
kapcsolsnak: erre a QObject osztly connect fggvnyt hasznljuk.
451
8. fejezet: A Qt keretrendszer programozsa
A szignlt publikl objektum felels a szignl kibocstsrt Amikor a
jelzs megtrtnik, az sszes olyan szlot meghvdik, amelyet korbban sz-
szekapcsoltunk a szignllal. A szignl kibocstsa utn ltalban azonnal
vgrehajtdik a szlotfggvny, s a vezrls a fggvny vgeztvel tr csak
vissza a kibocsts utni kdra. Ha tbb szlotfggvnyt ktttnk be, akkor
azok szekvencilisan egyms utn futnak le. Ez a mkds teht teljesen
fggetlen az esemnyfeldolgoz ciklustl, nem zenetek segtsgvel jelezzk,
hogy a szlotfggvnyeknek meg kell hvdniuk, hanem a szignl kibocstsa-
kor kzvetlenl hvdnak meg.
Lehetsg van azonban gynevezett vrakozsisor-alap sszektte-
tst definilni (queued connection), ilyenkor a szignl kibocstst egy esemny
jelzi, amely bekerl az esemnyfeldolgoz ciklusba. A szignl kibocstsa utn
azonnal visszatr a vezrls a kibocsts utni sorra, a szlotfggvnyeket pe-
dig az esemnykezel ciklus hvja meg az adott esemny feldolgozsakor.
A ktfle megolds kzl a connect fggvny paramtereivel lehet vlasztani
(ezeket lsd ks'bb rszletesen). Fontos azonban, hogy tbbszl alkalmaz-
soknl, amikor a kibocst szl klnbzik attl a szltl, amelyben a szlotot
publikl objektumot hoztuk ltre, automatikusan vrakozsisor-alap sz-
szekttetst hasznl a rendszer. A Qt ugyanis lehetv teszi, hogy minden
szl sajt esemnykezel ciklussal rendelkezzen.
A szignl-szlot mechanizmus bizonyos rtelemben fggetlen a szignlt, il-
letve a szlotot tartalmaz objektumtl. A szlotfggvny, amely egy bizonyos
szignlt kezel, a program brmelyik objektumban elhelyezkedhet. A szignlt
kld objektumnak semmit nem kell tudnia a szlotfggvnyrl vagy arrl, hogy
melyik objektumban van, st a kt objektum klnbz szlakban is futhat.
Tovbb a jelzs kibocstsakor azzal sem kell foglalkozni, hogy egyltaln
iratkozott-e fel egyetlen szlotfggvny is.
Br a szignl-szlot modell elsdleges funkcija az esemnykezels, hasznl-
hat objektumok kztti kommunikcira is, pldul, amikor egy alkalmazson
bell kt ablaknak kell kommuniklnia egymssal. Ez a mdszer egyszerbb,
mint pointerekkel elrni a msik objektumot s gy hvni publikus tagfggv-
nyeket. A httrben hosszabb mveleteket vgz szlak tipikusan szignlokon
keresztl kommuniklnak a felhasznli fellettel.
8.3.1. Szignlok ltrehozsa
Ha egy osztlyban szignlokat vagy szlotokat szeretnnk definilni, akkor
ennek a QObject osztlybl kell kzvetve vagy kzvetetten leszrmaznia.
Ezen kvl az osztly defincijban el kell helyeznnk a Q_OBJECT makrt.
452
8.3. AQt esemnykezels-modellje
/*textcontent.h*/
#ifndefTEXTCONTENT_H
#defineTEXTCONTENT_H
#include<Q0bj ect>
#include<QString>
classTextContent:publicQObj ect
{
Q_OBJECT7/ k telezQ_OBJECTmak r
public:
v oidsetText(constchar*newText);
signals:
v oidtextChanged(constchar*newText);
priv ate:
QString*text;
};
#endif//TEXTCONTENT_H
A fenti headerfjlban deklarlt TextContent nev osztly egy tetszleges sz-
veg trolsra szolgl. A szveget egy QString tpus tagvltozban (text) t-
roljuk. Egy szignlt is definiltunk, ennek a neve textChanged, ezzel jelezzk,
ha a tartalmazott szveg megvltozott. Az adott fggvny attl lesz szignl,
hogy a signals:" kulcssz utn szerepel a deklarciban. A szignlok mindig
publikusak, a lthatsgukat nem befolysolhatjuk.
A szignl kibocstsakor azt is tudatni szeretnnk, hogy mi az j szveg,
ezrt a textChanged fggvny egy char * tpus paramterrel rendelkezik.
A szignl-szlot mechanizmus ersen tpusos, azaz egy szignlra csak azzal
azonos paramterlistj szlotfggvnyekkel lehet feliratkozni Amikor a szig-
nl kibocstsval jelezzk, hogy a szveg megvltozott, akkor az sszes hoz-
zkapcsolt szlotfggvny meghvdik, mindegyik megkapja paramterknt a
kibocstskor megadott rtket. A szlotfgvnyek, azon kvl, hogy sszekt-
hetk szignlokkal, hagyomnyos fggvnyekknt is felhasznlhatk, ezrt
a szlotoknak lehet visszatrsi rtke is. m a szlotok visszatrsi rtkhez
a szignl kibocstsa utn nem frnk hozz, csak akkor, ha hagyomnyos
fggvnyknt hvtuk meg ket. Mivel a szlotok egyszer fggvnyek, gy vir-
tuliss tehet'k, s a leszrmazott osztlyokban felldefinilhatk.
A TextContent osztlynak csak a setText metdust kell implementl-
nunk. A szignlokhoz nem tartozik kln implementci pontosabban ezt
nem mi ksztjk el , hiszen a szignlok segtsgvel csak jelezzk, hogy az
adott esemny bekvetkezett, a bekttt szlotok meghvsrl a keretrend-
szer automatikusan gondoskodik:
453
8.fej ezet:AQtk eretrendszerprogramoz sa
/*textcontent.cpp*/
#include"textcontent.h"
v oidTextContent::setText(constchar*newText){
text=newQString(newText);
emittextChanged(text->data());
A setText metdusban kell frissteni a trolt szveget s a textChanged jelzst
leadni, vagyis a textChanged szignlt kibocstani. Ennek a szintaktikja a
kvetkez:
emit<szign l_fggv ny >(argumentumok >);
vagyis az emit kulcssz utn a szignlfggvnyt hvjuk meg a megfelel pa-
ramterrtkek tadsval.
8.3.2. Szlotfggvnyek ltrehozsa
A programunkban szksg lesz egy msik osztlyra is, amelynek a szlotjt sz-
szekthetjk a textChanged szignllal. A ContentWatcher osztly segtsgvel
egy TextContent tpus objektumot figyelhetnk meg, gy, hogy feliratkozunk
arra a szignlra, amely az adott objektum szvegnek a megvltozst jelzi:
/*contentwatcher.h*/
#ifndefFILEWATCHER_H
#defineFILEWATCHER_H
#include<Q0bj ect>
#include<textcontent.h>
classContentWatcher:publicQObj ect
{
Q_OBJECT
publicslots:
v oidcontentChanged(constchar*newText);
1;
#endif//FILEWATCHER_H
454
8.3 .AOtesem ny k ezel s-modellj e
/*contentwatcher.cpp*/
#include"contentwatcher.h"
#include<iostream>
v oidContentwatcher::contentChanged(constchar"newText){
std::cout"Contenthaschanged:"newText;
}
A ContentWatcher osztly definil egy contentChanged szlotfggvnyt. A szlo-
tokat mindig a slots:" utn soroljuk fel. A szlotok mindig publikusak, akr-
csak a szignlok, ennek ellenre mgis adhatunk meg lthatsgot, ennek
azonban csak akkor van jelentsge, ha a szlotot mint hagyomnyos fggvnyt
hasznljuk. A contentChanged paramterlistja megegyezik a Text Content osz-
tlyban definilt textChanged szignl paramterezsvel. A szlotfggvny
i mplementcijban egyszeren kirjuk a konzolra a megvltozott szveget.
8.3.3. Szignlok s szlotok sszekapcsolsa
Egy szignlt s egy szlotot a mr korbban ltott connect fggvnnyel kap-
csolhatunk ssze:
#incl ude<Q0bj ect>
boolQObj ect::connect(
constQObj ect* sender,
constchar* signal,
constQObj ect* receiver,
constchar*method,
Qt::ConnectionTy pe type = Qt::AutoConnection)
Paramterei a kvetkezk:
sender: Arra az objektumra mutat pointer, amelytl a szignl szr-
mazik.
signal: A kezelend szignl. A sender objektumnak kell kldenie.
receiver: Arra az objektumra mutat pointer, amelynek fogadnia kell
a szignlt.
method: A receiver szlotfggvnye, amely lekezeli a szignlt.
type: Az utols paramterrel a kapcsolds tpust lehet belltani.
Lehetsges rtkeit a 8.1. tblzatban soroljuk fel.
455
8. fejezet: A Qt keretrendszer programozsa
8.1. tblzat. A szignlok s a szlotok sszekapcsolsnak tpusai
(a Qt::ConnectionType rtkei)
Tpus Lers
Qt:.AutoConnection Ez az alaprtelmezett tpus. Ilyenkor a rendszer au-
tomatikusan vlaszt aszerint, hogy a szignlt publi-
kl s a szlotot definil objektumok egy szlban
vannak-e Ha igen, akkor a DirectConnection tpus
szerint a szignl kibocstsakor a szlot kzvetlenl
hvdik meg, ha nem, akkor a QueuedConnection
tpus szerint a szignl bekerl a msik szl ese-
mnykezel ciklusnak vrakozsi sorba.
Qt::DirectConnection
A szlotot azonnal meghvjuk, amikor a szignlt ki-
bocstjuk.
Qt::QueuedConnection
A szignlt akkor hvja meg a keretrendszer, amikor
a szlotfggvnyt tartalmaz objektum szlnak az
esemnykezel ciklusa feldolgozza a szignl hat-
sra kldtt zenetet.
Qt::BlockingQueuedConnection Ugyangy mkdik, mint a QueuedConnection,
csak a szignl kibocstsakor a kld szl blokko-
ldik, amg a szlot fggvny le nem fut. (Csak k-
lnbz szlak esetn hasznlhat.)
Qt:: UniqueConnection Ugyangy mkdik, mint az AutoConnection, de
csak akkor trtnik meg az sszekapcsols, ha az
korbban mg nem ltezett. Teht a rendszer biz-
tostja, hogy egy objektum egy szignljt egy msik
objektum egy szlotjval csak egyszer lehessen sz-
szekapcsolni.
Amikor egy szignl hatsra meghvdik egy szlotfggvny, ezen bell fontos
lehet tudni, hogy melyik objektum kldte a jelzst. A megolds a QObject osz-
tly sender fggvnye:
;cn*,-,
Ez a fggvny egy szignl hatsra meghvott szlotfggvnyben a szignlt
kld objektummal tr vissza, egybknt pedig 0-val.
Ahhoz, hogy az elbbi kt osztlyban definilt szignlt s szlotot hasznl-
ni tudjuk, a QObject osztly connect fggvnynek segtsgvel a kt osztly
egy-egy pldnyn ssze kell ktni a fggvnyeket, ezt a pldnkban az al-
kalmazs main fggvnyben tesszk meg. Az alkalmazsunk harmadik for-
rsllomnya a main fggvnyt tartalmaz main.cpp. Ebben felhasznljuk a
TextContent s a ContentWatcher osztlyainkat, mindkettt pldnyostjuk,
majd sszektjk a megfelel szignlt s szlotot:
4 56
8.3 .AQtesem ny k ezel s-modellj e
/*main.cpp*/
#include<iostream>
#include<textcontent.h>
#include<contentwatcher.h>
intmain(intargc,char*argv [])
{
TextContent*content=newTextContent();
ContentWatcher*watcher=newContentWatcher();
QObj ect::connect(content,SIGNAL(textChanged(constchar*)),
watcher,SLOT(contentChanged(constchar*)));
content->setText("Hellszign l-szlot!");
return0;
}
A program lefordtshoz szksg van egy .pro kiterjeszts projektllo-
mnyra, amelyet ismt automatikusan generlhatunk a qmake-kel, vagy
megrhatjuk manulisan is:
#watchDog.pro
TEMP LATE=app
SOURCES+=main.cpp\
textcontent.cpp\
contentwatcher.cpp
HEADERS+=\
textcontent.h
contentwatcher.h
Ezutn mr csak a make llomny ellltsa s a make program meghvsa
hinyzik a projekt lefordtshoz:
qmak eWatchDog.pro
mak e
8.3.4. Szlot az tmeneti objektumokban
Ha egy szlotfggvny olyan objektumban helyezkedik el, amelyet csak tme-
netileg hasznlunk, akkor szksg lehet a ltrehozott szignl-szlot kapcsola-
tok megsemmistsre. A szignl-szlot sszekttetseket a QObject osztly
disconnect fggvnyvel kapcsolhatjuk szt:
boolQObj ect::di sconnect
constQObj ect* sender,
const char * signal,
const QObj ect receiver,
const char* method )
457
8.fej ezet:A Qt k eretrendszerprogramoz sa
A sender paramter ltal tartalmazott egyik szignlrl (signal) lecsatlakoztat-
juk a receiver egyik szlotjt (s/ot). Ha a signal vagy a slot paramternek 0 rt-
ket adunk meg, akkor ez az sszes szignl vagy sz/ot lecsatlakoztatst jelenti.
A szignlt kibocst objektum nem tud arrl, hogy a szignlhoz milyen
szlotfggvnyek csatlakoztak, illetve csatlakoztak-e egyltaln, ezzel teht nem
kell foglalkozni a szignl kibocstsakor. Elfordulhat, hogy egy korbban sz-
szekapcsolt szlotfggvnyt tartalmaz objektumot idkzben mr trltnk a
memribl. A Qt keretrendszer gondoskodik rla, hogy a trlt objektum
destruktorban sztkapcsolja az objektum szlotjaihoz tartoz kapcsolatokat,
gy ez nem okoz hibt a futs sorn.
8.3.5. A Meta Object Compiler
A szignl-szlot mechanizmus trgyalsakor szmos olyan j nyelvi elemmel
tallkoztunk a forrsllomnyokban (pldul slots, signals, emit), amelyek
nem felelnek meg a C++ nyelv szintaxisnak. Tovbb a szignlokat a fgg-
vnyekhez hasonl szintaktikval deklarltuk, implementcit mgsem r-
tunk hozzjuk.
A Qt keretrendszer egyrszt makrkat biztost a fenti kulcsszavak helyettes-
tsre, gy a C++-fordt szmra rtelmezhet lesz kd, msrszt egy elfordtt
hasznl, amellyel az osztlyhoz kiegszt kdot generl. Ez az elfordt a ko-
rbban mr bemutatott moc, amely feldolgoz minden olyan headerllomnyt,
amelyben a Q_OBJECT makr szerepel. A feldolgozs sorn ezekhez a header-
llomnyokhoz egy moc_<headerllomnynv>.cpp nev llomnyt kszt. Ez
tartalmazza az osztlyokhoz tartoz metainformcikat s a szignlok imple-
mentcijt. A linkelskor az ltalunk rt forrskdok mellett ezeket az llo-
mnyokat is fel kell hasznlni. A moc hasznlata a qmake programmal teljesen
ttekintheten trtnik, gy a fenti fordtsi lpsekkel kzvetlenl nem kell
foglalkoznunk
A fentiek illusztrlsra nzzk meg, hogy milyen lpsekbl ll az elz
WatchDog elnevezs programunk fordtsa. (Az itt bemutatott kimenet nem
teljes, a knnyebb olvashatsg kedvrt a fordt hvsakor megadott kap-
csolk kzl csak az llomnyok nevre vonatkozkat hagytuk benne, gy hi-
nyoznak pldul a belinkelt programknyvtrak.)
g++-c-omain.omain.cpp
g++-c-otextcontent.otextcontent.cpp
g++-c-ocontentwatcher.ocontentwatcher.cpp
/usr/bin/moc-qt4textcontent.h-omoc_textcontent.cpp
g++-c-omoc_textcontent.omoc_textcontent.cpp
/usr/bin/moc-qt4contentwatcher.h-omoc_contentwatcher.cpp
g++-c-omoc_contentwatcher.omoc_contentwatcher.cpp
g++-owatchDogmain.otextcontent.ocontentwatcher.o
moc_textcontent.omoc_contentwatcher.o
458
8.4. Ablakok s vezrlk
A cpp llomnyokat a fordt hagyomnyosan fordtja le. A moc segtsgvel
minden headerllomnybl ellltunk egy msik cpp forrsllomnyt, ezeket
ugyancsak lefordtjuk, majd a linkelskor felhasznljuk, s beptjk a vgle-
ges programba.
8.4. Ablakok s vezrlk
Az albbiakban a grafikus felhasznli fellet programozst vizsgljuk meg
rszletesebben. A Qt keretrendszerben a felhasznli felleten megjelen ve-
zrlk mindegyike a QWidget sosztlybl szrmazik. Ez az osztly kezeli az
ablakoz rendszert) rkez felhasznli esemnyeket, tovbb az ltalnos
ablakjellemzket, s nyilvntartja a szl-gyermek viszonyokat. Az ablak
esemnyei lehetnek mretvltozssal vagy thelyezssel kapcsolatosak, va-
lamint a felhasznl beavatkozsnak az eredmnyei. Az esemnykezels a
szignl-szlot mechanizmuson alapul. A vezrlket az els pldban ismerte-
tett elrendezskezel objektumok segtsgvel ltalban automatikusan
rendezzk el egy szln bell, gy a felletek knnyen tudnak alkalmazkodni
az ablak tmretezshez.
A vezrlket szigor fastruktrba rendezzk, az a vezrl, amelynek
nincsen szlje, nll ablakknt jelenik meg. A gyermek mindig a szl fel-
letn helyezkedik el, a szlwidget ltal behatrolva.
Az ablakoknak alapveten ktfle tpusa van: a dialgusablakok s a ha-
gyomnyos alkalmazsablakok. Egy grafikus fellettel rendelkez alkalma-
zsnak tipikusan van egy fablaka, ahol eszkzsorokat s menket helyeznk
el itt tudjuk szerkeszteni a megnyitott dokumentumokat , s tbb dial-
gusablaka, amelyek kiegsztik a fablak funkciit.
A dialgusablakok a QDialog osztlybl szrmaznak. A dialgusablakokat az
egyszerbb felletek megjelentsre hasznljuk, van gynevezett visszatrsi
rtkk. A visszatrsi rtket a dialgusablak bezrsakor llthatjuk be, ez
utlag lekrdezhet, illetve van olyan blokkol fggvny (exec), amellyel megjele-
nthetjk a dialgusablakot, s ennek valban ez lesz a visszatrsi rtke.
A fablakot reprezentl osztlyok a QMainWindow-bl szrmaznak. Ez az
osztly sajt alaprtelmezett elrendezssel rendelkezik, menket, sttuszsort,
eszkzsorokat lehet benne elhelyezni. Rendelkezik tovbb olyan terletekkel,
ahov lebeg ablakokat lehet dokkolni, s egy olyan kzponti terlettel, amely-
be tetszleges vezrlt lehet elhelyezni. Ha nincsen szksgnk a Qt ltal biz-
tostott ablakfunkcikra (pldul eszkzsvok, mensv), akkor brmelyik
vezrlt hasznlhatjuk fablaknak (lsd az els pldban is, ahol a QWidget
egy pldnyt jelentettnk meg).
459
8. fejezet: A Qt keretrendszer programozsa
8.4.1. Dialgusablakok ksztse
A dialgusablakokat ktflekppen hasznlhatjuk. Az egyik, amg lthat,
blokkol minden hozzfrst a szlablakhoz, a msik esetben nem korltozza
semmiben a felhasznlt, a szlablakot is hasznlhatjuk. Az els vltozat a
modlis dialgusablak (modal dialog), a msodik a nem modlis dial-
gusablak (modeless dialog). A vlaszts, hogy modlis vagy nem modlis dia-
lgusablakot hasznljunk-e, fknt a dialgusablak funkcijtl fgg. Ha a
programban semmi hasznosat nem tehetnk, amg valamilyen adatot meg
nem kapunk, vagy a felhasznl nem nyugtz valamilyen informcit, akkor
clszer modlis dialgusablakot hasznlni. Pldul egy llomnynv kiv-
lasztsra is modlis dialgusablakot szoktunk megjelenteni. Ezzel szemben
a keress funkcijt ltalban nem modlis dialgusablakknt valstjuk
meg, hiszen kzben szerkeszthetjk a dokumentumot.
Egy modlis dialgusablakot a QDialog osztly exec fggvnyvel jelen-
tnk meg. Ilyenkor az alkalmazs eredeti esemnykezel ciklusa blokkoldik,
s a dialgusablak j ciklust indt. Ez a ciklus blokkolja a ms ablakokhoz r-
kez felhasznli esemnyeket, de tovbbtja pldul az jrarajzolst kr
zenetet. Amikor a felhasznl bezrja a dialgusablakot, akkor lell az
jonnan indtott esemnykezel ciklus, visszatr az exec fggvny, s gy az
eredeti ciklus folytatja a mkdst.
A modlis dialgusablakokat tipikusan loklis vltozknt hozzuk ltre,
ltalban valamilyen esemny kezelsre rt szlotfggvnyben, gy amikor a
vezrls elhagyja az adott fggvnyt, a dialgusablak felszabadul.
A nem modlis dialgusablakok osztoznak az esemnykezel cikluson a
tbbi ablakkal, gy a ltrehozs utn nem blokkoldhat a ltrehoz szl egy
olyan esemnykezel szlotban, amelyben ltrehoztk, s nem is szabad trlni
az objektumot, mert a fggvnybl val visszatrs utn is elrhet kell, hogy
maradjon. Ezrt a nem modlis dialgusablakokat tipikusan az alkalmazs
fablaknak tagvltozjaknt definiljuk, a konstruktorban hozzuk ltre, s
valamilyen esemny hatsra szlotbl jelentjk meg vagy rejtjk el. A meg-
jelentshez az exec helyett a show fggvnyt hasznljuk. Ez az exec-kel
szemben a dialgusablak megjelentse utn azonnal visszatr, s nem vr
az ablak bezrsra. A show tovbb nem indt kln esemnykezel ciklust
az j ablak szmra, az ide rkez zeneteket az alkalmazs fablaknak az
esemnykezelje kapja, s tovbbtja a dialgusablakhoz. Ezrt, ha nem mo-
dlis dialgusablakot jelentnk meg a show fggvnnyel, akkor mindenkp-
pen kell mr futnia esemnykezel ciklusnak, ezt a QApplication osztly exec
fggvnyvel indthatjuk el.
Feladat rjunk egyetlen dialgusablakbl ll alkalmazst, amelyben egy nevet s egy e-mail
cmet tudunk megadni. A dialgusablakbl a Rendben" s a Mgsem" nyomgombokkal
te-
hessen kilpni, a bezrszenetben mutassuk meg a dialgusablakba begpelt adatokat, s r-
juk ki, hogy melyik gombbal lptnk ki.
460
Uj bejegyzes
8.4. Ablakok s vezrlk
A kvetkez plda dialgusablakban (8.3. plda) teht egy ismersnk nevt
s e-mail cmt adhatjuk meg. Ezen a pldn bemutatjuk, hogyan kell sajt
dialgusablak-osztlyt rni, s hogyan kell az elrendezskezel objektumok
segtsgvel elhelyezni a vezrlket.
8.3. bra. QDialog-alap fellet nv s e-mail cm bersra
Sajt dialgusablak ksztsekor leszrmaztatunk a QDialog sosztlybl,
azoknak a tovbbi ltrehozott vezrlknek, amelyeket meg akarunk jelente-
ni, mindig a this mutatval elrt aktulis pldnyt adjuk meg szl'knt, gy
ezek a dialgusablakon bell jelennek meg.
/*contactdialog.h*/
#ifndefCONTACTDIALOG_H
#defineCONTACTDIALOG_H
#include<QtGui>
classContactDialog:publicQDialog
{
Q_OBJECT
public:
ContactDialog(QWidget*parent= 0);
QStringgetName();
QStringgetEmail();
priv ate:
QGroupBox*group;
QLabel*lblName;
QLabel*lblEmail;
QLineEdit*txtName;
QLineEdit*txtEmail;
QP ushButton*btn0k ;
QP ushButton*btnCancel;
QGridLay out*grid;
QVBoxLay out*mainLay out;
QHBoxLay out*buttonLay out;
};
#endif//CONTACTDIALOG_H
461
QGridLayout
tmretezhet res
terletek
QHBoxLayout
8. fejezet: A Qt keretrendszer programozsa
A ContactDialog osztly deklarcijban tagvltozknt troljuk a dialguson
megjelen sszes vezrlt. A group nev tagvltoz egy QGroupBox tpus
mutat. Ez megjelent cmmel egy keretet, a kereten bellre pedig tetszleges
tovbbi tartalmazott vezrl'ket helyezhetnk. A QLabel osztly segtsgvel
egy szveget vagy egy kpet tudunk megjelenteni, a fenti pldban a Nv"
s E-mail" cmkk megjelentsre hasznljuk. A QLineEdit osztllyal egy
egysoros szvegdobozt jelenthetnk meg, amelybe a felhasznl tetszleges
szveget gpelhet. Az egyszer nyomgombok ltrehozsra a Qt keretrend-
szerben a QPushButton osztly hasznlhat: kt ilyen tpus tagvltozt de-
finilunk a kt nyomgomb szmra. A tovbbi hrom tagvltoz a vezrlk
elrendezst segt objektumokat reprezentljk. A QGridLayout ngyzetrcs
alakban helyezi el az elemeket, ezek hasznlatakor minden vezrlhz meg
kell adni, hogy a ngyzetrcs melyik celljba tartozik. A QVBoxLayout a
hozztartoz vezrl'ket fgglegesen egyms al helyezi, mg a QHBoxLayout
vzszintesen egyms mell. A fenti objektumok segtsgvel a kvetkezkp-
pen helyezzk el az elemeket:
a QGridBoxLayout ngyzetrcsba rendezi a QGroupBoxon belli ngy
darab vezrlt, nevezetesen a kt feliratot s a kt szvegdobozt;
a QHBoxLayout csak a kt gombot rendezi el vzszintesen egyms
mell;
vgl a QVBoxLayout objektum segtsgvel a QGroupBoxot, illetve a
gombokat tartalmaz vzszintes svot helyezzk el egyms alatt.
Az automatikus elrendezsek hasznlatakor definilhatunk res te-
rleteket is, amelyek tmretezdnek, amikor az ablak mrete meg-
vltozik. Az elrendezskezel objektumok szerept s mkdst a
8.4. bra mutatja.
8.4. bra. A dialgusablak vezrlinek elrendezse
462
8.4.Ablak ok sv ez rlk
A dialgusablaknak van kt tovbbi fggvnye is: lekrdezhet a bert nv s
az e-mail cm. Erre szolglnak a publikus getName s getEmail fggvnyek:
contactdialog.cpp*/
#include"contactdialog.h"
ContactDialog::ContactDialog(Qwidget*parent):
QDialog(parent)
{
this->setWindowTitle("j bej egy z s");
group=newOGroupBox("Adatok ");
lblName=newQLabel("N v :");
lblEmail=newQLabel("E-mait:");
txtName=newQLineEdit();
txtEmail=newQLineEdit();
grid=newQGridLay out;
grid->addWidget(lblName,
grid->addwidget(txtName,
grid->addWidget(lblEmail,
grid->addwidget(txtEmail,
group->setLay out(grid);
0,
0,
1,
1,
0);
1);
0);
1);
btnok =newOP ushButton("Rendben");
btnCancel=newQP ushButton("M gsem");
buttonLay out=newQHBoxLay out;
buttonLay out->addstretch();
buttonLay out->addwidget(btn0k );
buttonLay out->addWidget(btnCancel);
mainLay out=newQHBoxLay out;
this->setLay out(mainLay out);
mainLay out->addWidget(group);
mainLay out->addStretch();
mainLay out->addLay out(buttonLay out);
connect(btnOk ,SIGNAL(click ed()),this,SLOT(accept()));
connect(btnCancel,SIGNAL(click ed()),this,SLOT(rej ect()));
QStringContactDialog::getName(){
returntxtName->text();
QStringContactDialog::getEmail(){
returntxtEmail->text();
463
8. fejezet: A Qt keretrendszer programozsa
Az osztly konstruktorban elszr a QGroupBoxot, illetve az abban tallhat
ngy vezrlt hozzuk ltre.
Az elrendezskezel objektumokhoz az addWidget fggvnnyel adhatjuk
hozz azokat a vezrlket, amelyeknek az elrendezsrt felelsek. Ha nem
egy vezrlt akarunk hozzadni az elrendezshez, hanem egy msik elrende-
zskezel objektumot, akkor az addLayout fggvnyt kell hasznlni, mivel
ezek az objektumok nem a QWidget osztlybl szrmaznak. Az elemek term-
szetesen a hozzads sorrendjben helyezkednek el.
A QGridLayout hasznlatakor az addWidget fggvny meghvsakor meg
kell adni, hogy melyik sorba, illetve oszlopba kerljn a vezrl (a sorok s
oszlopok indexelse 0-val kezddik). Termszetesen arra is van lehetsg,
hogy egy vezrl tbb egyms melletti cellt foglaljon el, gy a cellkat ssze-
vonjuk, ezeket a tovbbi opcionlis paramterekben lehet specifiklni.
A QGroupBox gyermekvezrljbl lesz a ngyzetrcsban elhelyezett ngy
msik vezrl. Ezt a ngy vezrlt pedig a QGridLayout objektum segtsgvel
rendezzk el, ezrt a QGroupBox objektumnak meg kell hvnia a setLayout
fggvnyt, paramterknt pedig az QGridLayout pldnyt kell tadni. Elren-
dezskezel objektumok hasznlatakor a gyermekvezrlket nem kzvetlenl a
szlhz adjuk, hanem a szlnek a setLayout fggvnyvel megadjuk elszr
az elrendezskezelt, majd ahhoz tesszk hozz a gyermekvezrlket a fentiek
szerint. A fenti kdban nem adtuk meg expliciten azt, hogy a kt cmke s sz-
vegdoboz a group gyermekvezrlje legyen. Ezt megtehettk volna gy, hogy a
vezrlk konstruktorainak tadjuk paramterknt a group szlt. Erre azon-
ban nincsen szksg, mert az elrendezskezel objektumok hasznlatakor a
setLayout fggvny meghvsval a keretrendszer automatikusan inicializlja
a szl-gyermek viszonyokat ez nagyban egyszersti a kdrst.
A kvetkez lpsben a kt nyomgombot s az azokat vzszintesen elren-
dez objektumot hozzuk ltre. A Qt keretrendszerben a vezrlk elrendezs-
nek egyik fontos eleme az res terek kezelse. A fenti pldban azt szeretnnk,
hogy ha az ablakot vzszintesen tmretezzk, akkor a kt nyomgomb mrete
ne vltozzon, hanem mindig az adott sor jobb oldalt foglaljk el, a bal olda-
lon pedig az res terlet szlessge vltozzon. Az addStretch fggvny ppen
egy ilyen, automatikusan vltoz mret res terletet (spacer) helyez el,
mgpedig a kt nyomgomb el, ugyanis ezek hozzadsa eltt hvtuk meg
ezt a fggvnyt.
A kvetkez sorokban az elzkhz hasonlan inicializljuk a fggleges
elrendezst biztost objektumot, a fenti ngyzetrcs s az als gombsor kz
pedig ismt egy res terletet helyeznk el
A QDialog osztlynak van kt szlotja: accept s reject. Ha brmelyik fgg-
vnyt meghvjuk, az ablak automatikusan bezrdik, s a dialgusablak
eredmnye" vagy visszatrsi rtke" a megfelel konstans QDialog::Accepted
vagy QDialog::Rejected lesz. Ezt az rtket a result fggvnnyel tudjuk lekr-
dezni. A kt ltrehozott gombnak a clicked szignljt elg sszektni a megfe-
lel szlottal (accept s reject), gy ezek automatikusan meghvdnak a gomb
megnyomsakor. Termszetesen sajt esemnykezel szlotfggvnyt is rhat-
464
8.4. Ablakok s vezrlk
nnk a gombnyoms lekezelsre, s ezen bell mi is bezrhatnnk az abla,
kot, illetve bellthatnk a visszatrsi rtket. Elbbit a close, utbbit a set-
Result fggvnnyel tehetjk meg.
A Qt keretrendszer nagyban egyszersti a memriakezelssel kapcsola-
tos feladatokat. A szigor fastruktrba rendezett felhasznlifellet-elemek
felszabadtsrl nem kell kln gondoskodni. Ha egy ablakot bezrunk, ak-
kor automatikusan felszabadtja az sszes benne lv vezrl szmra lefog-
lalt memriaterletet. Ezrt, habr a ContactDialog konstruktorban a new
kulcsszval terletet foglaltunk a tartalmazott vezrlknek s az elrendezs-
kezel objektumoknak, ezeket a hivatkozsokat a destruktorban nem kell k-
ln felszabadtani:
/*main.cpp*/
#include<QtGui>
#include"contactdialog.h"
intmain(intargc,char*argv [])
QApplicationapp(argc,argv );
ContactDialog*dlg=newcontactpialog();
dlg->exec();
QMessageBoxmsg;
msg.setwindowTitle("Eredm ny ");
QStringmessage=
"N v :"%dlg->getName()%
email:"%dlg->getEmail()%
(dlg->result()==QDialog::Accepted
?"(j v hagy v a)"
"(nincsj v hagy v a)");
msg.setText(message);
msg.show();
returnapp.exec();
}
Ahhoz, hogy a dialgusablakot ki tudjuk prblni, szksg van egy main
fggvnyre. A fenti forrsllomny els sorban a QApplication pldnyt ini-
cializljuk, majd ltrehozunk egy pldnyt a korbban definilt dialgusab-
lakbl. A dialgusablakot az exec fggvnnyel jelentjk meg modlisan.
Az exec nem tr vissza, amg a dialgusablak esemnykezel ciklusa fut, va-
gyis amg az ablakot be nem zrjuk.
Ha az ablakot nem modlisan szeretnnk megjelenteni, akkor a show
fggvnyt kellene hasznlni. Erre a ksbbiekben mutatunk mg pldt.
A dialgusablak bezrsa utn ltrehozunk egy szvegdobozt (QMessageBox
osztly), amelybe a dialgusablak visszatrsi rtktl fgg zenetet jelen-
tnk meg. A QMessageBox szintn egy beptett dialgusablak-tpus.
465
8. fejezet: A Qt keretrendszer programozsa
A main fggvny utols sorban az app.exec() hvsra azrt van minden-
kppen szksg, mert nem modlis dialgusablakot is hasznlunk (msg),
amely nem rendelkezik sajt esemnykezel ciklussal.
Ebben a pldban teht bemutattuk, hogyan tudunk olyan alkalmazst
rni, amelynek a fablaka egy dialgusablak. Sokszor a clunknak ennyi is
megfelel. A sajt alkalmazsablakokat bemutat fejezetekben rszletesen
megvizsgljuk azt, hogyan rdemes egy fablakkal rendelkez alkalmazsban
a modlis s a nem modlis dialgusablakokat hasznlni.
8.4.2. A Qt vezrlkszlete
A Qt keretrendszer egyik erssge a nagyszm testre szabhat vezrlt tar-
talmaz osztlyknyvtr. A szoksos egyszerbb vezrlk mellett tallhatk
sszetettebb vezrlk, s rendelkezsre llnak a szoksos dialgusablakok is.
A 8.2. tblzatban csak nhnyat sorolunk fel a legfontosabb vezrlk kzl.
8.2 . tblzat. A Qt keretrendszer legfontosabb vezrli
Vezrlk neve Ler s
Egyszerbb vezrlk
QLineEdit,
QTextEdit,
QDateEdit,
QDateTimeEdit,
QTimeEdit
Beviteli mez'k szvegekhez, dtumokhoz s idpontokhoz
QCheckBox, Jellngyzet- s vlasztngyzet-osztlyok
QRadioButton
QComboBox Legrdl lista
QFontComboBox Bettpus- vlaszt lista
QLabel
QMenu
Egyszer szveg vagy kp megjelentse
Menk megjelentse
sszetettebb vezrlk
QCalendarWidget Naptrat megjelent vezrl
QListWidget Elemeket listanzetben megjelent vezrl
QTableWidget Elemeket tblzatnzetben megjelent vezrl
QTreeWidget Elemeket fastruktrban megjelent vezrl
QWebView Webes dokumentumok megjelentsre s szerkesztsre
hasznlhat vezrl
4 66
8.4 . Ablakok s vezrlk
Vez r lk neve Ler s
Dialgusablakok
QColorDialog Sznvlaszt dialgusablak
QFileDialog llomnyok s knyvtrak kivlasztsra hasznlhat
dialgusablak
QFontDialog Dialgusablak bettpus belltsainak szerkesztsre
QlnputDialog Egy darab egyszer tpus adat beolvassa a felhaszn-
ltl (a beolvasand tpus lehet szveg, szm vagy egy
elre megadott lista egyik eleme)
QMessageBox zenet megjelentse a felhasznl szmra
A fenti tblzatban felsorolt vezrlk mindegyike hasonlan hasznlhat.
Mindegyik a QWidgetbl szrmazik, gy pldnyosts utn brmilyen sz-
lwidgeten elhelyezhetk, vagy nll ablakknt is megjelenthetk. Minde-
gyik vezrl szignlokat publikl, amelyekkel jelzi, hogy valamilyen vltozs
trtnt az llapotban. A szignlok termszetesen az adott vezrl tpusnak
megfelel esemnyeket jelzik, a QCheckBox pldul a kijellsi llapot meg-
vltoztatsnak jelzsre tartalmaz szignlt, a QListWidet pedig arra, hogy
megvltozott az ppen kijellt elem a listban. Termszetesen minden vezrl
a tpusnak megfelel tulajdonsgokkal rendelkezik, amelyek a megjelent-
st befolysoljk. Ezeknek a tulajdonsgoknak a lekrdezsre s mdost-
sra a megfelel fggvnyek rendelkezsre llnak. Ha egy konkrt vezrlt
hasznlunk a programozs sorn, rdemes hasznlat eltt tnzni a doku-
mentciban azt, hogy milyen fggvnyekkel szabhatjuk testre a kinzett, s
milyen esemnyekrl kld szignlokat a vezrl.
8.4.3. Sajt alkalmazsablakok
A QMainWindow osztly segtsvel definilhatjuk egy alkalmazs szoksos
felhasznli fellett, amelyen menk, eszkztrak s sttuszinformci je-
lennek meg, tallhatk tovbb lebeg s dokkolhat ablakok.
A QMainWindow osztly fellete elre meghatrozott terletekre van fel-
osztva, mindegyik terletre meghatrozott tpus vezrlket tudunk elhe-
lyezni. A feloszts a 8.5. brn lthat:
mensor (menu bar) s sttuszsor (status bar) az ablak tetejn s
aljn,
eszkztrak (tool bar) helye krben az ablak szlein,
leb ega b la kok (floating window) dokkolsra hasznlhat terlet
az eszkztrak mellett, illetve
a kzponti vezrl terlete, amely az ablak kzept, a legnagyobb te-
rletet tlti ki.
4 67
lebeg ablakok dokkolsnak helye
kzponti vezrl
mensor
eszkztrak
sttuszsor
8. fejezet: A Qt keretrendszer programozsa
8.5. bra. A QMainWindow terletnek felosztsa
A lebegablakok ltalban az alkalmazs fablaka fltt klnll ablakok-
knt helyezkednek el, de lehetsg van ezeket statikusan is elhelyezni, dok-
kolni" az ablak valamelyik oldaln. Mind a mensorbl, mind a sttuszsorbl
csak eggyel rendelkezik az ablak. A QMainWindow hasznlatnak elnye,
hogy beptetten tmogatja a fenti vezrlk elhelyezst. Termszetesen ezek
kzl egyiket sem kell tnylegesen fel is hasznlnunk az alkalmazsunkban.
m ha egyikre sincsen szksgnk, akkor nem rdemes a QMainWindow-bl
leszrmaztatni a fablakot.
A QMainWindow hasznlatakor vlaszthatunk az SDI (single document
interface) s az MDI (multiple document interface) felletek kzl, a keret-
rendszer mindegyik tmogatsra klnbz vezrl'ket biztost. Az SDI fel-
leten a kzponti vezrl terletn egyszerre egy dokumentumablak jelenik
meg. Ha egy msik dokumentummal akarunk dolgozni, akkor az elst be kell
zrni, s ezutn tudunk csak jabb ablakot megnyitni. Az MDI esetben vi-
szont egyszerre tbb dokumentumablakon is dolgozhatunk, vagyis a kzponti
terleten egyszerre tbb sajt fejlccel, kerettel rendelkez, tmretezhet
ablak is lehet megnyitva. Ezeknek az tmretezhetsgt, mozgatst a
QMainWindow biztostja. Az SDI esetben a kzponti terletre brmilyen ve-
zrlt elhelyezhetnk, ez tlti ki a rendelkezsre ll teljes terletet. Az MDI
esetben a kzponti vezrl helyre egy QMdiArea tpust kell elhelyezni,
amelyhez az addSubWindow fggvnnyel mr tetszleges vezrlt hozzad-
hatunk. Minden egyes ilyen vezrl kln ablakknt jelenik meg.
Lthat, hogy az SDI fellet programozshoz semmilyen specilis vezr-
lt nem kell hasznlni, egy MDI fellet megvalstsa azonban bonyolultabb,
erre a dokumentum-nzet architektra trgyalsakor mutatunk pldt.
468
8.4.Ablak ok sv ez rlk
8.4.4. A fablak programozsa
A tovbbiakban megvizsgljuk, hogy milyen fggvnyekkel tudunk hozzfr-
ni a fablak men-, eszkz- s sttuszsoraihoz, s hogyan tudjuk ket az akci-
kkal sszekapcsolni.
Egy alkalmazsban ltalban vannak olyan funkcik, amelyek a fellet tbb
pontjrl is elrhetk, pldul a mensor vagy az eszkztr egyik elemrl, illet-
ve valamilyen billentykombinci segtsgvel. ltalban ilyen pldul az j
dokumentum" funkci. A felhasznl szemszgbl csak az adott funkcinak van
jelentsge, s rdektelen, hogy ppen melyik mdon hvta meg. Egy ilyen funk-
cit az gynevezett akciobjektummal runk le, ez a QAction osztly egyik pld-
nya. Az akci (action) fogja ssze az ugyanannak a funkcinak a meghvshoz
szksges klnbz esemnyeket s a funkcit kezel szlotfggvnyt, valamint
a funkci lerst szvegekkel s kpekkel. Egy mr ltrehozott akcit hozz-
adhatunk egy mensorhoz vagy egy eszkztrhoz, avagy egyszeren maghoz
az ablakhoz, ha csak billentykombincival szeretnnk elrni. Mindegyik
esetben az adott vezrl (mensor, eszkztr, QMainWindow) addAction fgg-
vnyt hasznljuk az akci megjelentshez. Egy QAction ltrehozsakor meg-
adhat ikon, menszveg, gyorsbillenty, sttuszszveg, sgszveg (tooltip).
A QAction publikl egy triggered szignlt, ezzel kapunk rtestst, ha a fel-
hasznl az adott funkcit meghvta fggetlenl attl, hogy a felhasznli fel-
let melyik elemn keresztl aktivldott.
Amikor szeretnnk egy ment ltrehozni, a menuBar fggvnnyel lekr-
dezzk az ablaktl a mensort. A mensor valjban a legels lekrdezskor
inicializldik, ksbbi hvsokkor ugyanazt az objektumot adja vissza, gy ha
nem akarunk ment ltrehozni, s nem prblunk meg hozzfrni, akkor
nem is jn ltre. Hasonlan mkdnek az eszkztrak s a sttuszsor is.
A QMainWindow osztly menuBar metdusnak visszatrsi rtke egy
QMenuBar objektum, amely az ablak mensort rja le. A mensorhoz az
addMenu fggvnnyel adhatunk hozz jabb menelemeket. Ezek a men-
pontok a QMenu osztly pldnyai. Az j pldnyt magval az addMenu
fggvnnyel is ltrehozhatjuk, ekkor csak egy szveget kell tadni a men-
pont ltrehozshoz:
#include<QtGui>
QMenu*QMenu::addMenu(constQString&title)
QMenu*QMenu::addMenu(constQlcon&icon,constQString&title)
A QMenu addAction fggvnyvel egy akcinak megfelel QAction objektumot
adhatunk hozz a menhz. Ennek a szvege pedig egy tovbbi menpontknt
jelenik meg az eredeti menn bell. Lehetsg van arra, hogy a QAction pl-
dnyt az addAction fggvnyhvssal egytt hozzuk ltre, ekkor csak a megje-
lentend menpont cmt kell tadni.
469
8. fejezet: A Qt keretrendszer programozsa
QAction * QMenu::addAction ( const QString & text )
QAction * QMenu::addAction ( const Qicon & icon,
const QString & text )
Az albbi kdrszlet elszr ltrehoz egy Fjl" ment a mensoron, majd ini-
cializl egy QAction pldnyt, ennek szvege a Kilp" lesz. Ezutn a men-
ben megjelenti az akcit:
QMenu * fi leMenu = thi s->menuBar()->addmenu ("Faji ") ;
exitAction = new QAction("Ki lp", thi s);
filemenu->addAction(exi tActi on);
A mensorhoz hasonlan mkdnek az eszkztrak is, de azokbl a men-
sorral ellenttben tbb is lehet. Az ablak addToolBar fggvnyvel hozha-
tunk ltre egy QToolBar tpus eszkztrat, amelyre szintn az addAction
fggvnnyel tudjuk az akciknak megfelel elemeket elhelyezni.
Sttuszsorbl is csak egy van az alkalmazson bell, ezt a statusBar fgg-
vnnyel rjk el. A sttuszsoron hromfle informcit tudunk megjelenteni:
ideiglenes szveget (temporary), ltalnos (normal) s lland (permanent) in-
formcit. Az ltalnos s az lland informci nem csak szveg lehet, ezek
megj elentshez sajt QLabel objektumokat kell ltrehozni, s ezeket az add-
Widget fggvnnyel kell a sttuszsorhoz adni. Lehetsg van tbb QLabel hoz-
zadsra is. Az lland szveg egszen addig lthat, amg a removeWidget
fggvnnyel a megfelel QLabel vezrlt el nem tvoltjuk. Az ideiglenes szve-
get tipikusan valamilyen zenet rvid idej megjelentsre alkalmazzuk, erre
a showMessage fggvnyt hasznljuk, amelynek a megjelentend szveg mel-
lett megadhatjuk, hogy mennyi ideig legyen lthat. Az ideiglenes szveg, elta-
karhatja a norml informcit, de az lland informci mindig lthat marad,
amg programozottan el nem tntetjk.
Feladat rjunk egy olyan alkalmazst, amelyben ismerseink cmlistjt (nv s e-mail cm)
trolhatjuk. A fablakban jelentsk meg a lista adatait tblzatos formban. Ksztsnk dial-
gusablakokat, amelyekkel j bejegyzst vehetnk fel, illetve kereshetnk nv szerint a list-
ban. Az elst modlisan, a msodikat nem modlisan jelentsk meg.
j bejegyzs ltrehozsra az elz pldban bemutatott ContactDialog dia-
lgusablakot hasznljuk. runk tovbb egy SearchDialog osztlyt is, amely
ugyancsak egy dialgusablak, s a keresst teszi lehetv. Az ablakban meg-
jelentnk egy Fjl" ment, amelyben hrom menpont lesz: keress", j
bejegyzs" s Kilp". Ezen kvl hasznljuk a sttuszsort is a felhasznlnak
sznt zenetek megjelentsre. Az alkalmazs fellete a 8.6. brn lthat.
470
8.4. Ablakok s vezrlk
8.6. bra. Cmlista-alkalmazs kpernykpe
/*contactswindow.h*/
#ifndefCONTACTSWINDOW_H
#defineCONTACTSWINDOW_H
#includeQtGui>
#include"contactdialog.h"
#include"searchdialog.h"
classContactswindow:publicQmainwindow
{
Q_OBJECT
public:
explicitContactsWindow(QWidget*parent = 0)
;
signals:
publicslots:
v oidaddNewContact();
v oidupdateStatusText();
v oidsearch(Qstringexpression);
v oidshowSearch();
protected:
v oidcloseEv ent(QCloseEv ent*ev ent);
priv ate:
QAction*exitAction;
QAction*newContactAction;
QAction*showSearchAction;
471
8. fejezet: A Qt keretrendszer programozsa
QMenu *fi 1 emenu ;
QTableWi dget * table;
SearchDialog * searchDi al og ; // Nemodl i s , ezrt tagvltoz
},
#endif // CONTACTSWINDOW_H
A ContactsWindow osztly a QMainWindow-bl szrmazik, s a Q_OBJECT
makrval kezddik, hiszen sajt szlotokat definilunk.
A closeEvent az sosztlyban definilt virtulis fggvny, amely azeltt
hvdik meg, mieltt az ablakot bezrjuk. Ezt a fggvnyt felldefiniljuk, gy
kapunk rtestst az ablak bezrsrl. A fggvnyen bell r tudunk kr-
dezni arra, hogy a felhasznl valban ki akar-e lpni. A felldefinilst biz-
tost fggvnyen bell lehetsgnk van a bezrs megszaktsra is.
Az osztly tagvltozi kzl az els hrom akcikat r le. Az exitAction segt-
sgvel az ablakot lehet bezrni. Ezt a funkcit a menbl is el lehet rni, illetve
egy billentykombincit is rendelnk hozz. A msodik akci a newContact-
Action. Ezzel jelzi a felhasznl, hogy egy j bejegyzst szeretne ltrehozni, ilyen-
kor modlisan megjelentnk egy ContactDialog tpus dialgusablakot. Ez az
akci szintn a mensorbl, illetve egy billentykombincival rhet el.
A harmadik a showSearchAction, amellyel a keres dialgusablakot jelentjk
meg. Ezt nem modlisan tesszk, mivel folyamatosan elrhet lesz, mikzben az
alkalmazs fablakban is dolgozunk.
Tbb szlotfggvnyt is definilunk. Az addNewContacttal a newContact-
Action akci bekvetkezstl kezdve kapunk rtestst, az updateStatusText-
tel pedig arrl, ha a tblzatban j elemet jellnk ki. A showSearch szlottal
a keres ablakot jelentjk majd meg (ezt a showSearchAction akcin keresz-
tl rjk el). Vgezetl a search szlotfggvnnyel kapunk rtestst arrl,
hogy egy bizonyos szvegre kell rkeresni a megjelentett adatok kztt.
A fileMenu vltozval rjk el a Fjl" ment ler objektumot. Arra a
mensorra, amelyben a sajt mennk is megjelenik, nem trolunk kln re-
ferencit, mert azt mindig le tudjuk krdezni a menuBar fggvnnyel.
A table vltoz egy QTableWidget tpusra mutat, amellyel egyszer ele-
mekbl ll tblzatot tudunk megjelenteni. A tblzat celliban QTable-
Widgetltem tpus elemek vannak, egy-egy elemben tbbfle informcit is
trolhatunk, de ebben a pldban mi egyszer szveget jelentnk meg.
Vgezetl a searchDialog tagvltoz egy SearchDialog tpus dialgusab-
lakra mutat. Ezt a dialgusablakot nem modlisan jelentjk meg, gy fontos,
hogy az alkalmazsablakban mindig elrhet legyen. ContactDialog objek-
tumra viszont nem trolunk referencit loklis vltozknt hozzuk majd ltre,
amikor meg akarjuk jelenteni. A modlis dialgusablakot mindig a megjele-
nts eltt hozzuk ltre, majd bezrsa s az bekrt adatok feldolgozsa utn
rgtn trljk, mert ksbb mr nem lesz r szksg.
472
8.4.Ablak ok sv ez rlk
/*contactswindow.cpp*/
#include"contactswindow.h"
#include"contactdialog.h"
#include<QtGui>
#include<QStringBuilder>
contactswindow::contactswindow(Qwidget*parent):
Qmainwindow(parent)
{
this->setwindowTitle(tr("C mlista"));
fileMenu=this->menuBar()->addmenu(tr("&F j l"));
exitAction=newQAction(tr("&Kil p"),this);
exitAction->setShortcut(tr("Ctrl+Q"));
exitAction->setStatusTip(tr("Alk almaz sbez r sa"));
connect(exitAction,SIGNAL(triggered()),this,SLOT(close()));
fileMenu->addAction(exitAction);
newContactAction= newQAction(tr("&j bej egy z s"),this);
newContactAction->setShortcut(OKey Sequence::New);
newContactAction->setStatusTip(tr("j bej egy z sfelv tele"));
connect(newContactAction,siGNAL(triggered()),this,
SLOT(addNewContact()));
filemenu->addAction(newContactAction);
showsearchAction=newQAction(tr("Keres &s"),this);
showSearchAction->setShortcut(OKey sequence::Find);
showSearchAction->setStatusTip(tr("Keres sn v alapj n"));
filemenu->addAction(showsearchAction);
connect(showsearchAction,SIGNAL(triggered()),this,
SLOT(showsearch()));
this->table=newQTablewidget;
table->setSelectionmode(QAbstractItemv iew::SingleSelection);
table->setColumnCount(2 );
this->setcentralwidget(table);
QStringListheaderLabels;
headerLabels"N v ""E-mail";
table->setHorizontalHeaderLabels(headerLabels);
connect(table,SIGNAL(itemSelectionChanged()),this,
SLOT(updateStatusText()));
searchDialog=newSearchoialog;
connect(searchDialog,SIGNAL(searchinv ok ed(QString)),this,
SLOT(search(Qstring)));
}
v oidContactsWindow::showSearch(){
if(!searchoialog->isVisible())
this->searchDialog->show();
473
8. fejezet: A Qt keretrendszer programozsa
v oidContactsWindow::search(QStringexpression){
intcurrently SelectedRowNbr=-1;
QList<QTablewidgetitem*>selecteditems=
table->selecteditems();
i f(selecteditems.length()>0)
currently SelectedRowNbr=selectedItems.first()->row();
inti;
boolfound=false;
for(i=currently SelectedRowNbr+1;
i<table->rowCount();i++){
if(table->item(i,0)->text().contains(expression)){
table->clearSelection();
table->item(i,0)->setSelected(true);
found=true;
break ;
}
}
if(!found){
table->clearSelection();
}
}
v oidContactswindow::closeEv ent(QCloseEv ent*ev ent)
{
QMessageBoxmsg(this);
msg.setwindowTitle(tr("Kil p s"));
msg.setText(tr("T ny legk il p?"));
msg.setStandardButtons(QMessageBox::Yes1QMessageBox::Cancel);
i f(msg.exec()==QmessageBox::Yes)
ev ent->accept();
else
ev ent->ignore();
}
v oidcontactswindow::addNewContact(){
ContactDialog*newContactDialog=newContactDialog(this);
i f(newContactDialog->exec()==Wialog::Accepted)
{
intcurrentRowsNbr=table->rowCount();
table->insertRow(currentRowsNbr);
QTablewidgetItem*newNameitem=
newQTablewidgetItem(newContactDialog->getName());
table->setitem(currentRowsNbr,0,newNameItem);
QTablewidgetItem*newEmailitem=
newQTableWidgetItem(newContactDialog->getEmail());
table->setItem(currentRowsNbr,1,newEmailitem);
}
deletenewContactDialog;
}
474
8.4. Ablakok s vezrlk
v oidcontactswindow::updatestatusText()
{
Qtist<QTablewidgetitem*>selecteditems=
table->selecteditems();
if(selecteditems.length()>0)
this->statusBar()->showmessage(
"Name:"%
table->item(selecteditems.first()->row(),0)->text()
) ;
}
Az osztly implementcis llomnyban elszr a konstruktort rtuk meg.
A setWindowTitle fggvnnyel lltjuk be az ablak fejlcben megjelen cmet.
Ezutn kvetkezik a Fjl" men inicializlsa A menuBar fggvnnyel krjk
el a referencit az alkalmazsablak mensorra, s mivel ez az els hvsa a
fggvnynek, itt jn ltre maga a mensorobjektum. Nem kell kln ltrehozni
QMenu objektumot s azt hozzadni a mensorhoz, ez megtehet egy lpsben
az addMenu fggvnnyel, ezrt csak a menpont cmt adjuk t. A pldban
a &Fjl" szvegkonstans egy tr fggvnyhvson bell tallhat. A tr fggvny
a QObject osztly egy metdusa, s a fellet lokalizlhatv ttelhez hasznl-
juk. Ha egy kln llomnyban lefordtottuk az adott szveget egy msik
nyelvre, akkor a tr fggvny a fellet nyelve alapjn ezt a fordtst adja
vissza az eredeti szvegkonstans helyett. Arra, hogy miknt lehet egy adott
nyelv fordtst megadni, a kvetkez fejezetben trnk vissza, itt csak az a
fontos, hogy a tr fggvnybe gyazva jelezni kell, hogy az adott szveget lokali-
zlhatv akarjuk tenni. Termszetesen, ha biztosan tudjuk, hogy ksbb nem
akarjuk lokalizlhatv tenni az alkalmazsunkat, akkor a tr fggvnyhvs
elhagyhat, s a szveg nmagban is llhat Az addMenu fggvny visszatr-
si rtke az j menpontra mutat referencia. A menpont cmben az F' bet
eltti &" jel az adott menponthoz tartoz gyorsbillentyt jelzi, ebben az eset-
ben teht a Fjl" mennek az F' bet lesz a gyorsbillentyje.
Az els akci, amelyet ltrehozunk, az exitAction. A konstruktornak t-
adott szveg lesz a menpont cme, amikor hozzadjuk egy menhz. Ezenk-
vl egy gyorsbillentyt is megadunk a setShortcut fggvnnyel. A setStatusTip
fggvnynek tadunk egy szveget, amely ideiglenes szvegknt megjelenik a
sttuszsoron, amikor az adott menpont fl visszk az egeret. Az akcihoz
lehetne mg ikonkpet is megadni (seticon), amelyet az eszkztron helyez-
hetnnk el. Az akci hasznlathoz mg kt lps szksges. Elszr egy
megfelel szlotot ssze kell ktni az akci triggered szignljval, gy rtestst
kapunk arrl, ha az adott funkcit a felhasznl el akarta rni. Itt az alkal-
mazsablak close szlotjt hasznljuk, amelynek a meghvsakor bezrul az
ablak. Mivel a close szlotot az sosztly tartalmazza, itt ennek a megrsval
nem kell foglalkozni. Msodszor, az akcit el kell helyezni a mensoron, mert
amg nincsen egy vezrlhz sem hozzrendelve, nem lehet elrni. A QMenu
osztly addAction fggvnyvel a paramterknt tadott akciobjektum me-
npontknt jelenik meg az eredeti menpontot bell. Ilyenkor a billenty-
kombinci is automatikusan mkdik.
475
8. fejezet: A Qt keretrendszer programozsa
A newContactAction funkcival jelentnk meg egy ContactDialog dial-
gusablakot. Az exitAction inicializlsnak lpseihez kpest ennek a ltre-
hozsnl kt klnbsget lthatunk. Az els az, hogy a gyorsbillentyt nem
szvegknt adjuk t, hanem a QKeySequence osztly StandardKey felsorols-
tpusnak egy rtkeknt: QKeySequence::New. A QKeySequence osztlyban
vannak definilva azok az ltalnos billentykombincik, amelyeket gyak-
ran hasznlunk az alkalmazsokban, ilyen pldul az j dokumentum", a
Nyomtats", a Megnyits" vagy a Bezrs". Az adott funkcihoz tartoz
alaprtelmezett billentykombincik az opercis rendszertl fggen vl-
tozhatnak. Ha nem szvegknt definiljuk az akcihoz tartoz gyorsbillen-
tyt, mint az exitAction esetben, hanem a fenti konstansok hasznlatval,
akkor a keretrendszer az aktulis platformnak megfelel alaprtelmezett bil-
lentyparancsot hasznlja. Ezzel nagyban nveljk az alkalmazsunk hor-
dozhatsgt. A msodik klnbsg az exitActionhz kpest, hogy itt egy sajt
szlotot hasznlunk az akci esemnynek a kezelsre, nevezetesen az add-
NewContact fggvnyt, hiszen itt sajt alkalmazsspecifikus logikt szeret-
nnk rni: megjelenteni egy dialgusablakot.
A konstruktor vgn ltrehozzuk az alkalmazs fablaknak kzponti ve-
zrljt (central widget), ez tlti ki az ablak kzps rszt, amelyet ppen
nem foglalnak el az eszkzsorok, a mensor, a sttuszsor, illetve az esetlege-
sen dokkolt lebegablakok. A kzponti vezrl tetszleges QWidget lehet, itt a
QTableWidget tpust hasznljuk. A ltrehozs utn az ablak setCentralWidget
fggvnyvel meg kell adni, hogy ez legyen a kzponti vezrl. A QTable-
Widget konstruktorban most sem kellett megadni a szlvezrlt, mert a set-
CentralWidget automatikusan belltja. A tblzatnak nhny tulajdonsgt
is testre szabjuk: megadjuk, hogy 2 oszlopbl lljon (setColumnCount), hogy
egyszerre csak egy cellt lehessen kijellni (setSelectionMode), s specifikl-
juk az oszlopok fejlceinek a cmt (setHorizontalHeaderLabels). Ez utbbi
belltshoz szksg van egy QStringList tpus objektumra, ebben szveg-
konstansok listjt lehet hatkonyan trolni. A QStringList osztly felldefini-
lja a opertort is, ennek a segtsgvel knyelmesen tudunk j elemeket
hozzadni a listhoz (lsd a fenti kdrszletben).
Az alkalmazs gy mkdik, hogy ha kivlasztunk egy cellt a tblzat-
ban, akkor egy rvid ideig a sttuszsoron is kirjuk az adott sorhoz tartoz ne-
vet. Ehhez egy rtestsre van szksgnk arrl, ha a kijellt cella megvltozik,
ezrt sszekapcsoljuk a tbla itemSelectionChanged szignljt az update-
StatusText szlottal, amelyet mi ksztnk el
A konstruktor vgn ltrehozzuk a SearchDialog osztly egy pldnyt, de
nem hvunk rajta show metdust, ezrt ez nem jelenik meg. Termszetesen le-
hetsg lenne ezt az objektumot magt a dialgusablak els megjelentse
eltt is ltrehozni, nem pedig itt a konstruktorban. A SearchDialog definci-
jt ks'bb mutatjuk be, m elzetesen megllapthat, hogy publikl egy
searchInvoked nev szignlt, amellyel jelezni tudja, hogy valamilyen szvegre
akar keresni a felhasznl. A searchInvoked szignl paramterlistja egy
476
8.4. Ablakok s vezrlk
QStringbl n, ez lesz az a szveg, amelyre keresnk. A search szlotfggvnyt
ktjk ssze a szignllal. A connect fggvnyben a SIGNAL s a SLOT mak-
rk hasznlatakor a paramterlistt is jellni kell.
A konstruktor utn jnnek a tagfggvnyek implementcii. A show-
Search ellenrzi, hogy lthat-e a keresablak, ha nem, akkor a show hvssal
megjelenti.
A search szlotfggvny felels a keress elvgzsrt. Pldnkban csak a
nevekben keresnk, az e-mail cmekben nem. Szeretnnk, ha a keress gy
mkdne, hogy a dialgusablak ltal kibocstott szignlnl az ppen kijellt
cella sora utni sorokban trtnjen csak a keress. Ha a keress sorn tal-
lunk egy olyan nevet, amelyben szerepel a kifejezs, akkor jelljk ki az adott
cellt. Ha az utols sorban sem tallunk tallatot, akkor egyszeren megszn-
tetjk a kijellst a tblzatban. gy teht folytonosan tudunk keresni a tbl-
zatban, s minden elfordulst megtallunk. A fenti logika implementcijhoz
a QTableWidget nhny metdust is meg kell ismernnk. A selectedltems
visszaadja azoknak a cellaelemeknek a listjt, amelyeket ki lettek jellve.
A tblzat inicializlsakor megadtuk, hogy egyszerre maximum egy cella lehet
kijellve, gy felttelezhetjk, hogy a visszaadott listnak 0 vagy 1 eleme lehet.
A QList egy olyan sablonosztly, amellyel adott tpus elemek listjt tudjuk
kezelni, ebben az esetben QTableWidgetltem pldnyok mutatit. A listn a
szoksos mveletek hajthatk vgre, pldul beszrs, trls, keress. A tovb-
biakban csak a lista mrett visszaad size fggvnyre s az els elemmel vissza-
tr first fggvnyre lesz szksgnk. A QTableWidget rowCount fggvnnyel
a sorok szma, az itemmel pedig egy adott sor- s oszlopindex cellaelem kr-
dezhet le. A clearSelection fggvny, ahogyan a neve is mutatja, megsznteti a
kijellst a tblzatban. Vgezetl a QTableWidgetltem setSelection fggvnyt
emltjk meg, amellyel egy adott cellt tudunk kijellni.
A closeEvent fggvny virtulis, azeltt hvdik meg, mieltt az ablak be-
zrdik. A fggvny egyetlen paramternek tpusa QCloseEvent tpus. Eb-
ben a fggvnyben egy felugr ablakban megkrdezzk a felhasznlt, hogy
valban ki akar-e lpni az alkalmazsbl. Az ablaknak cmet adunk (set-
WindowTitle), s megadjuk a kirand szveget (setText), majd belltjuk,
hogy milyen gombokat jelentsen meg Ehhez a QMessageBox osztlyban de-
finilt StandardButton felsorolstpus elemeit hasznljuk fel, jelen esetben a
QMessageBox::Yes s a QMessageBox::Cancel konstansokra van szksgnk,
hogy a felhasznl az Igen" vagy Mgsem" gombok kzl tudjon vlasztani.
Az ablakot modlisan jelentjk meg, ezrt az exec fggvnyt hasznljuk,
amelynek visszatrsi rtke annak a gombnak a kdja lesz, amellyel bezr-
tuk a szvegdobozt. Ha a felhasznl vlasza QMessageBox::Cancel, vagyis
meg 'akarja szaktani a kilpst az alkalmazsbl, akkor a paramterknt
megkapott event vltozn meghvjuk az ignore fggvnyt, ezzel megszaktjuk
az ablak bezrst. Ha ezt nem hvjuk meg, akkor a closeEvent visszatrse
utn valban megtrtnik az ablak bezrsa.
477
8.fej ezet:AQtk eretrendszerprogramoz sa
Az addNewContact szlotfggvny implementcijban elszr ltreho-
zunk egy ContactDialog pldnyt, ezutn megjelentjk a dialgusablakot.
A dialgusablaknak a visszatrsi eredmnyt a korbbi pldban a result
fggvnnyel krdeztk le, de ugyanez lesz az exec fggvny visszatrsi rt-
ke is. Ha a dialgusablakot jvhagytuk, akkor lekrdezzk a bert nevet s
e-mail cmet, majd ezeknek megfelelen ltrehozunk kt j cellt. A tblzat-
ba az insertRow fggvnnyel beszrunk egy j sort, ennek a sornak a cellit
mr tudjuk vltoztatni a setltem fggvny segtsgvel.
A msik szlotfggvny az updateStatusText, ezzel kapunk rtestst arrl,
ha a tblzatban j elemet vlasztottunk ki. Ismt a tblzat selectedltems
fggvnyt hasznljuk annak lekrdezsre, hogy van-e kijellt cella, s ismt
kihasznljuk, hogy maximum egy darab cella lehet egyszerre kijellve. A kije-
llt cellhoz tartoz sor els oszlopbl kiolvassuk az aktulis nevet, majd ezt
2 msodpercig megjelentjk a sttuszsoron. Ehhez a QStatusBar osztly
showMessage fggvnyt hasznljuk, amelynek els paramtere a megjelen-
tend szveg, msodik pedig a megjelents idtartama milliszekundumban.
Ezzel az alkalmazsablak elkszlt, mr csak a dialgusablakok defin-
cija hinyzik. A ContactDialog kdjt a korbbiakban mr trgyaltuk, az
albbiakban a SearchDialogot mutatjuk be:
/*searchdialog.h*/
#ifndefSEARCHDIALOG_H
#define SEARCHDIALOG_H
#include<QtGui>
classsearchDialog:public QDialog
{
Q_OBJECT
public:
explicitSearchQialog(Qwidget*parent=0);
signals:
v oidsearchinv ok ed(Qstringexpresssion);
publicslots:
v oidsearch();
protected:
QH8oxLay out*lay out;
Qi_ineEdit *txtExpression;
QP ushButton*btnsearch;
}
;
#endif//SEARCHDIALOG_H
478
8.4. Ablakok s vezrlk
/*searchdialog.cpp*/
#include"searchdialog.h"
SearchDialog::Searchpialog(QWidget*parent):
Wialog(parent)
{
lay out=newQHBoxLay out;
this->setLay out(lay out);
txtExpression=newQLineEdit;
lay out->addwidget(txtExpression);
btnSearch=newQP ushButton(tr("Keress"));
lay out->addwidget(btnSearch);
connect(btnSearch,SIGNAL(click ed()),this,SLOT(search()));
}
v oidSearchoialog::search(){
emitsearchInv ok ed(txtExpression->text());
A dialgusablak kdja a Qt keretrendszer eddig trgyalt elemeinek ismeret-
ben nem szorul rszletes magyarzatra. A dialgusablakon egy egysoros sz-
vegbeviteli mezt (QLineEdit) s egy nyomgombot (QPushButton) helyeznk
el vzszintesen egyms mellett. A keressgomb megnyomsakor bocstja ki a
dialgusablak a searchlnvoked szignlt.
Ezutn mr csak a main fggvnyre van szksg, amelyben inicializljuk
az alkalmazst, s megjelentjk a fablakot:
/*main.cpp*/
#include"contactswindow.h"
#include<QtGui>
intmain(intargc,char*argv [])
{
QApplicationapp(argc,argv );
ContactsWindow*w=newContactsWindow;
w->show();
returnapp.exec();
8.4.5. Lokalizci
Azokat az alkalmazsokat, amelyekben lehetv akarjuk tenni, hogy a fellet
tbb klnbz nyelven is elrhet legyen, rdemes gy megtervezni, hogy a
klnbz nyelv fordtsokat lehetleg minl kevesebb tovbbi programozs
nlkl, minl egyszerbben tudjuk megadni. Az ilyen jelleg tervezst nemzet-
kziestsnek (internationalization) nevezzk. Lokalizcinak (localization)
hvjuk azt, amikor az alkalmazsunkat egy adott nyelvre lefordtjuk.
479
8. fejezet: A Qt keretrendszer programozsa
A Qt keretrendszerben ez a folyamat gy mkdik, hogy a megjelentett
szvegkonstansokat klnll erforrs-llomnyokban troljuk, amelyeket
egyenknt lefordthatunk klnll nyelvekre, ezeket a fordtsokat pedig
mellkeljk a programunkhoz. A lokalizci teht abbl ll, hogy az erfor-
rs-llomnyoknak elksztjk a klnbz nyelv fordtst (ehhez semmi-
lyen programozi tuds nem kell), illetve gondoskodunk a betltskrl a
programon bell.
Az elz pldban emltettk, hogy azokat a szvegkonstansokat, melye-
ket lokalizlni szeretnnk, kln meg kell jellni a forrskdban. Erre a
QObject osztlyban definilt tr fggvnyt hasznljuk:
QSt ri ng QObject: : t r (
const char sourceText,
const char * disambiguation = 0,
int n = -1 )
A tr fggvny els paramtere az alaprtelmezett szveg, a tovbbi paramte-
rek opcionlisak. Elfordulhat, hogy ugyanazt a szveget az alkalmazs kt
klnbz helyn mshogyan akarjuk lefordtani, ilyenkor a kt kontextust
meg akarjuk klnbztetni, erre szolgl a msodik paramter. Ha a szveg s
a kontextus is megegyezik, akkor ugyanaz lesz a fordts is. A harmadik, int
tpus paramternek a tbbes szm kpzsben van szerepe. Ha az eredeti
szvegkonstans tartalmazza a %n" szveget, akkor ezt a vgleges szvegben
a harmadik paramter (n) rtkvel helyettestjk. A fordtsnl megadhat
az adott kifejezs tbbes szm s egyes szm vltozata is, az n rtktl
fggen a megfelelt hasznlja fel a keretrendszer.
A lokalizland szvegek megjellse utn a kvetkez lps a lehetsges
fordtsok elksztse. A klnbz nyelv fordtsokat klnll fjlokbl ol-
vassa be a rendszer. Minden nyelvhez ltre kell hozni egy .ts kiterjeszts
xml llomnyt. Az llomny minden egyes szveg-kontextus proshoz tartal-
maz egy fordtst.
Az xml llomny vzt automatikusan generlhatjuk a Qt fordtprog-
ramjval, ennek neve lupdate. Ha ltre szeretnnk hozni egy ilyen llomnyt,
a projektllomnyban ezt jeleznnk kell:
TRANSLATIONS+=ContactsApplication_en_US.ts
A fenti sor jelzi, hogy egy ContactsApplication_en_US.ts nev llomnyban
szeretnnk fordtst kszteni az alkalmazsunkhoz. A fjl nevnek a vgz-
dse konvenci szerint a fordts nyelvt jelzi, de ez nem ktelez, tetszleges
fjlnevet is hasznlhatunk. Termszetesen tbb klnbz fordtst is kszt-
hetnk, ekkor tbb nevet kell megadni. Ezutn kell a projekt llomnynev-
vel meghvni az lupdate programot, pldul:
lupdate ContactsApplication.pro
480
8.4.Ablak ok sv ez rlk
A program legenerlja a megfelel xml llomny vzt. Az lupdate bejrja a
teljes forrskdot, s megkeresi a tr fggvnnyel megjellt hvsokat, majd
resen hagyja az adott szveg fordtst. Ezeket a rszeket kell neknk a for-
dtssal kiegsztennk. Fontos tulajdonsga az lupdate programnak, hogy
amennyiben a generland llomny mr ltezik, akkor nem trli annak a
tartalmt, csak az idkzben a forrskdba bert jabb fordtand szvegek
alapjn kiegszti. gy inkrementlisan hasznlhat az alkalmazs rsnak
klnbz fzisaiban a fordtsok elksztsre. Ennek az xml llomnynak a
vzt teht nem kell manulisan sszelltani, ez jelents munktl s az xml
sma ismerettl kmli meg a programozt. Az albbi kd a Contacts-
Application alkalmazs angol nyelv fordtsnak egy rszt mutatja be.
Lthat benne az eredeti szveg, a fordts, illetve az eredeti szveg helye:
<?xmlv ersion="1.0"encoding="utf-8"?>
<!DOCTYP ETS>
<TSv ersion="2 .0"language="en_US"sourcelanguage="hu_Np"
<context>
<name>ContactDialog</name>
<message>
<locationfilename="contactdialog.cpp"line="6"/>
<source>j bej egy z s</source>
<translation>Newcontact</translation>
</message>
</context>
</TS>
A .ts llomnyok teht xml formtumban troljk az adatokat, a program fut-
tatsa sorn mgsem ezeket hasznljuk, hanem egy tmrtett vltozatukat,
amelynek kiterjesztse .qm. Minden .ts llomnybl kell egy ilyet generlni,
erre az lrelease program hasznland:
1 rel ese ContactsAppli cation. pro
A fejezet ksbbi rszben rszletesen is bemutatjuk, hogy milyen alkalmaz-
sok s technolgik segtik a gyors alkalmazsfejlesztst a Qt-krnyezetben,
m mr itt megjegyezzk, hogy mind az lupdate s az lrelease programok
automatikus futtatsra, mind az xml llomnyok szerkesztsre hatkony
grafikus alkalmazsok llnak rendelkezsre egy integrlt fejleszti krnye-
zetben: ezek a szoftverek a fejleszts teljes munkafolyamatt nagymrtkben
egyszerstik.
A Qt keretrendszerben ksztett alkalmazsok lokalizcijra a QTrans-
lator osztlyt hasznljuk. Ha nem az alkalmazs forrskdjba bert alapr-
telmezett szveget, hanem annak valamilyen nyelv fordtst szeretnnk
hasznlni, akkor ltre kell hozni egy QTranslator objektumot, majd a load
fggvnyvel be kell tlteni a megfelel .qm llomnyt. Ezutn az alkalma-
zsobjektum installTranslator fggvnyvel jelezni kell, hogy ezentl ezt a
481
8.fej ezet:AQtk eretrendszerprogramoz sa
fordtst szeretnnk hasznlni. Termszetesen elfordulhat, hogy a fordtsok
tbb llomnyban vannak, ilyenkor minden ilyen llomnyhoz kln QTrans-
lator pldnyt kell ltrehozni:
/*mdos tottmain.cpp*/
#include"contactswindow.h"
#include<QtGui>
intmain(intargc,char*argv [])
{
QApplicationapp(argc,argv );
QTranslatortranslator;
translator.load(QString("ContactsApplication_en_US"));
app.installTranslator(&translator);
QTranslatorqtTranslator;
qtTranslator.load(QString("qt_en"));
app.installTranslator(&qtTranslator);
Contactsw ndow*w=newcontactswindow;
w->show();
returnapp.exec();
}
A fenti kdrszlet alapjn lthat, hogyan kell mdostani az alkalmazsunk
main fggvnyt, hogy a ContactsApplication _en_US llomnyban megadott
angol fordtst tudja hasznlni A .qm llomnynak ebben az esetben a futta-
tott llomnnyal egy knyvtrban kell lennie, vagy a load fggvnyben az el-
rsi tvonalat is meg kell adni az llomny neve eltt.
Az elz pldban a lefordtott kdrszleten kvl egy qt_en nev fordtst
is betltnk. Erre azrt van szksg, mert az alkalmazsunk nemcsak ltalunk
rt vezrlket tartalmaz, hanem a Qt keretrendszer rszt kpez beptett fel-
hasznli felleti elemeket is, ilyenek pldul a felugr ablakokon megjelentett
Jvhagys" s Mgsem" nyomgombok. Az ezeken megjelen szvegek ford-
tsrl is neknk kell gondoskodnunk. A keretrendszer teleptsekor meg-
adott mappban megtallhatk ezeknek a beptett szvegeknek a fordtsai, a
qt_en ahogyan a neve is mutatja ppen az angol nyelv fordtsokat tartal-
mazza, de a magyarral egytt sok ms nyelvhez is megtallhat itt a fordts.
A fenti kdrszletben azt felttelezzk, hogy ezt az llomnyt az alkalmazsun-
kat tartalmaz knyvtrba msoltuk, ezrt nem adunk meg elrsi tvonalat
Termszetesen az gy felhasznlt llomnyt is tetszs szerint mdosthatjuk, ha
jobban testre akarnnk szabni a lefordtott szvegeket.
482
8.4. Ablakok s vezrlk
8.4.6. Sajt vezrlk ksztse
Sajt vezrlnek (custom widget) nevezzk azokat az jrafelhasznlhat
vezrlket, amelyeket magunk definiltunk. Sajt vezrlk ksztsre tbb
lehetsgnk is van a Qt keretrendszerben. Az els lehetsg, hogy egy ltez
vezrlosztlybl leszrmaztatunk, ekkor ennek csak azokat a tulajdonsgait
vltoztatjuk meg, amelyek szmunkra fontosak. A msik mdszer az, hogy
a QWidget sosztlybl leszrmaztatva mi magunk rjuk meg a teljes vezr-
lt. Mivel minden QWidgetnek lehetnek tartalmazott vezrli, elfordulhat,
hogy a sajt vezrlnket egyszeren ms ltez vezrl'k komponlsval sz-
szellthatjuk. Ilyenkor az j vezrlnek csak a tartalmazott komponensek
elhelyezsrt kell felelnie. A legbonyolultabb eset az, amikor sajt megjelen-
tst szeretnnk definilni, a kvetkez rszben ezt az esetet vizsgljuk meg
rszletesen.
Sajt vezrl ksztshez az albbi feladatokat kell megoldanunk:
Hogyan kapja a vezrl az esemnyeket a felhasznltl?
Hogyan kommunikl a vezrl a szljvel?
Hogyan rheti el a sajt terlett a vezrl, s hogyan rajzolhat r?
A rendszer ltal tovbbtott esemnyek mondjk meg azt a vezrlnek, hogy
jra kell rajzolnia a fellett, mert a felhasznl tmretezte, elmozgatta, az
egrrel a felletre kattintott, vagy billentyket ttt le. Termszetesen en-
nek kezelse Qt alatt a szignl-szlot mechanizmussal trtnik. Ugyanakkor
sajt vezrlk ksztsekor mindig ugyanazokat a szlotokat kell megadnunk,
hiszen pldul a rajzolsi esemnyt mindig kezelnnk kell. Sokszor jobb len-
ne, ha valamilyen alaprtelmezett mkdst felttelezhetnnk, s csak akkor
kellene kezelni az adott szignlt, ha ettl a mkdstl el szeretnnk trni.
A QWidget tmogatst nyjt ebben: a szlotok olyan virtulis fggvnyek,
amelyneknek a mkdst tetszs szerint fellrhatjuk vagy megtarthatjuk.
gy az els krdsre a vlasz az, hogy a QWidget virtulis fggvnyek
meghvsval ad lehetsget az esemnyek kezelsre. Mindegyik me-
tdus rendelkezik egy, az esemny jellemzit ler paramterrel. A szrmazta-
tott osztlyok ezeket a fggvnyeket tetszs szerint felldefiniljk. Az egyes
fggvnyek implementcijtl fgg, hogy az adott elem milyen szerepet va-
lst meg, hogyan reagl egy adott esemnyre. A QWidget osztlyban tbb tz
ilyen virtulis fggvnyt tallunk, ezek neve ltalban az Event" szveggel
vgzdik. A leggyakrabban hasznltak a paintEvent s a resizeEvent. Az els-
vel a vezrl jrarajzolst jelzi a rendszer, a msodikkal azt, hogy a vezrlt
tmreteztk. Kln fggvnyeket tallunk a billentyzet (keyPressEuent, key-
ReleaseEvent) s az egr (mousePressEvent, mouseDoubleClickEvent, mouse-
MoveEvent, mouseReleaseEvent) fell rkez esemnyek kezelsre. A tovbbi
fggvnyek megtallhatak a QWidget osztly dokumentcijban.
483
8. fejezet: A Qt keretrendszer programozsa
A vezrl a szlablakkal kzvetlenl szignl-szlot alapon kom-
munikl. A QWidget a QObject osztlybl szrmazik, ezrt implementlja a
szignl-szlot metdust. A vezrl szignlokat hasznl, hogy jelezze a felhasz-
nl beavatkozsait vagy az llapotnak a megvltozst.
A rajzolst a QPainter osztllyal vgezzk. A QPainter osztly ala-
csony szint rajzfunkcikat biztost, amelyekkel az adott vezrlnk terletre
rajzolhatunk. gy nagyon sokfle rajzfunkci rhet el az egyszer vonalh-
zstl a bonyolultabb alakzatok megjelentsig. Lehetsg van tovbb sz-
veg s kpek kezelsre is.
Feladat Ksztsnk egy vezrlt, amely kezdetben megjelent egy tglalapot, amelynek a ke-
rete s a kt tlja 4 pixel szles kk szn vonal, a belseje pedig piros szn. Amikor a fel-
hasznl rkattint a vezrlre, akkor a kitlts megvltozik, ekkor egy ellipszist rajzolunk ki,
amelynek stlusa megegyezik a tglalapval.
Sajt vezrl
8. 7. b r a . Sajt vezrl llapotai
Ebben a pldban megmutatjuk, hogyan kapunk rtestst arrl, hogy a ki-
rajzolsnak meg kell trtnnie, s hogyan lehet tetszleges tartalmat rajzolni
a vezrl felletre. Az elksztett alkalmazs felhasznli fellete a 8.7. b-
rn lthat.
/* customwidget.h */
#ifndef CUSTOMWIDGET_H
#define CUSTOMWIDGET_H
#1 ncl ude <QtGui >
class customwidget : public Qwidget
{
Q_OB JECT
public:
explicit customwidget(Qwidget *parent =0);
enum Shape { Rectangle, Ellipse };
QSize sizeHint0 const;
484
8.4. Ablakok s vezrlk
signals:
v oidshapechanged(intnewshape);
protected:
v oidmousePressEvent(QMouseEvent *ev ent);
v oidpaintEvent(QPaintEvent *event) ;
priv ate:
intcurrentShape;
} ;
#endif//CUSTOMWIDGET_H
A CustomWidget osztly minden vezrl sosztlybl, a QWidgetbl szrma-
zik. Mivel szeretnnk sajt szignlt is definilni, ezrt a deklarcija a
Q_OBJECT makrval kezddik. Szksgnk lesz kt konstansra (Rectangle
s Ellipse), ezek segtsgvel jelezzk, hogy ppen melyik llapotban van a
vezrl. Az aktulis llapotot a currentShape tagvltozban troljuk.
Minden vezrlnek lekrdezhet az alaprtelmezett mrete, ezt adja visz-
sza a sizeHint fggvny, amely a QWidget osztly egy virtulis fggvnye.
A CustomWidget osztly definil egy szignlt is (shapeChanged), ezzel je-
lezzk, amikor az aktulis llapot megvltozik. A fggvny int tpus param-
tere az j llapotot tartalmazza. Az osztlyban felldefinilunk kt tovbbi vir-
tulis fggvnyt is, ezek a mousePressEvent s a paintEvent. Az els fggvny-
nyel kapunk jelzst arrl, hogy egrkattints-esemny trtnt a vezrlnkn,
a msodik fggvny pedig azt az esemnyt jelzi, hogy a vezrlnk egszt
vagy egy rszt jra ki kell rajzolni. Erre pldul akkor van szksg, ha a ve-
zrl egy rszt eddig egy msik ablak takarta, m most jra lthatv vlik.
Egy msik oka lehet az jrarajzolsi esemnynek, ha a programunkbl meg-
hvtuk a vezrln az update vagy a repaint tagfggvnyeket. Ezekkel a fgg-
vnyekkel jelezhetjk, hogy jra akarjuk rajzolni a vezrlt, mert pldul a
megjelentett adatok megvltoztak, s gy frissteni kell a megjelentst.
Magt a paintEvent fggvnyt kzvetlenl sosem szabad meghvni, csak az
elz fggvnyek egyikvel kzvetetten. Az update s a repaint kztt az a
klnbsg, hogy az utbbinl az jrarajzols azonnal megtrtnik, mg az els
hvsakor az jrarajzolsi krs zenetknt bekerl az ablak zenetsorba,
s csak akkor trtnik meg a kiszolglsa, amikor az eltte lv zeneteket
feldolgoztuk. ltalban csak akkor haszljunk repaintet, ha a szlotban mr
szksgk van a kirajzols megjelentsre.
485
8. fejezet: AQt keretrendszer programozsa
/*customwidget.cpp*/
#include"customwidget.h"
CustomWidget::Customwidget(Qwidget*parent):
Qwidget(parent)
{
currentshape=Rectangle;
setSizeP olicy (QSizeP olicy ::minimum,QSizeP olicy ::Minimum);
}
v oidcustomwidget::mouseP ressEv ent(QMouseEv ent*ev ent){
currentShape=currentShape==Rectangle?Ellipse:Rectangle;
update();
emitshapeChanged(currentShape);
}
v oidCustomwidget::paintEv ent(QP aintEv ent*ev ent){
QP ainterpainter(this);
QP enpen;
pen.setColor(Qt::blue);
pen.setWidth(4);
painter.setP en(pen);
QBrushbrush;
brush.setColor(Qt::red);
brush.setSty le(Qt::SolidP attern);
painter.setBrush(brush);
switch(currentshape){
caseRectangle:
painter.drawRect(0,0,this->size().width(),
this->size().height());
painter.drawLine(0,0,this->size().width(),
this->size().height());
painter.drawLine(0,this->size().height(),
this->size().width(),0);
break ;
caseEllipse:
painter.drawEllipse(0,0,this->size().width(),
this->size().height());
break ;
QSizeCustomWidget::sizeHint()const
{
returnQSize(2 00,2 00);
}
486
8.4 . Ablakok s vezrlk
A konstruktor implementcijban elszr belltjuk a kezdllapotot, ez a
Rectangle konstans lesz. A kvetkez lps a setSizePolicy fggvny meghv-
sa. Minden vezrl esetben meg lehet hatrozni, hogy milyen szablyok sze-
rint lehet tmretezni Amikor az adott tpus vezrl elrendezsrt egy
elrendezskezel objektum a felels, akkor ennek figyelembe kell venni eze-
ket a szablyokat:
void setSizePolicy (
QSi zePol cy : :Policy horizontal,
QSizePolicy: :Policy vertica7 )
A setSizePolicy fggvny els paramtere a vzszintes tmretezs szablyt,
a msodik a fgglegest definilja. A lehetsges belltsokat a 8.3. tblzat
tartalmazza.
8.3. tblzat. A vezrlk tmretezsi szablyainak lehetsges tpusai
A szably kdja Lers
QSizePolicy::Fixed A vezrl mrett nem lehet megvltoztatni, az
mindig az alaprtelmezett rtk lesz.
QSizePolicy::Minimum A vezrl alaprtelmezett mrete a minimumr-
tk, teht annl kisebbre nem lehet tmretezni.
QSizePolicy::Maximum A vezrl alaprtelmezett mrete a maximumr-
tk, teht annl nagyobbra nem lehet tmretezni.
QSizePolicy::Preferred A vezrl alaprtelmezett mrete az optimlis
mret, de ha szksges, kisebbre s nagyobbra is
lehet lltani.
QSizePolicy::Expanding Ha van elg hely, a vezrlt rdemes minl na-
gyobb mretre tmretezni, de szksg esetn a
mretet cskkenteni is lehet.
QSizePolicy::MinimumExpanding

A vezrlt kisebbre nem lehet venni, mint az
alaprtelmezett rtk, de ha lehetsges, rdemes
minl nagyobbra venni.
QSizePolicy::Ignored A vezrl alaprtelmezett rtkt figyelmen k-
vl kell hagyni, akkora helyet tltsn ki, ameny-
nyit csak lehet.
A konstruktorban hasznlt argumentumok mellett teht megmondjuk, hogy
a vezrlnek a sizeHint fggvny ltal visszaadott szlessge s magassga a
minimumrtk, ezeknl kisebbre nem lehet tmretezni egyik irnyban sem.
Az alaprtelmezettnl nagyobbra azonban t lehet mretezni.
Az egrkattintsi esemny bekvetkezsekor a mousePressEvent fggvny
hvdik meg. Ekkor megvltoztatjuk a vezrl eddigi llapott, majd a meg-
vltozott llapot miatt jrarajzoltatjuk az update fggvnyhvssal. Vgl ki-
bocstjuk a shapeChanged szignlt, jelezve, hogy a vezrl aktulis llapota
megvltozott.
4 87
8. fejezet: A Qt keretrendszer programozsa
Utolsknt a paintEvent fggvnyt implementljuk. Ez akkor hvdik
meg, amikor a vezrl tartalmt frissteni kell, a rajzolst a fggvnyen bell
vgezhetjk el. A rajzols megkezdshez szksg van egy olyan QPainter
pldnyra, amellyel az aktulis vezrl terletre tudunk rajzolni, ezt pedig
gy kaphatjuk meg, hogy a konstruktorban tadjuk az aktulis vezrlt.
Minden alakzat rajzolsakor meg kell hatrozni, hogy az alakzat krvonala
(toll pen) s a kitltse (ecset brush) milyen stlus legyen. Az elst egy
QPen tpus, a msodikat egy QBrush tpus objektummal rjuk le. A toll ese-
tn tbbek kztt meghatrozhatjuk a sznt, a vonalvastagsgot, a kitltst, az
ecset esetn ugyancsak a sznt s a kitltst. A pldban egy kk szn, 4 pixel
szles tollat s egy egyenletes piros kitltst inicializlunk. A QPen, illetve a
QBrush objektumok ltrehozsa utn a QPainter objektum setPen, illetve set-
Brush fggvnyeivel be is kell ezeket lltani a rajzolshoz. A QPainter osz-
tly drawRect s drawEllipse fggvnyeinek a felhasznlsval rajzolunk egy
tglalapot vagy egy ellipszist a vezrl aktulis llapottl fggen. Mindkt
fggvny esetben az adott alakzatot befoglal tglalap bal fels sarknak
koordintit, illetve szlessgt s magassgt kell tadni. A rajzols sorn
ktdimenzis koordinta-rendszerrel dolgozunk, amelynek bal fels sarknak
koordinti a (0,0), szlessge s magassga pedig a vezrl aktulis mrete,
amelyet a size fggvnnyel krdezhetnk le
A QPainter segtsgvel teht knnyen megvalsthatunk alacsony szint
rajzfunkcikat, m a kpessgei nem csak erre korltozdnak. Bonyolultabb
alakzatokat, sszetett szntmeneteket, koordintatranszformcit s sok
egyb szolgltatst biztost ez az osztly. A QPainter segtsgvel nemcsak
egy QWidgetre tudunk rajzolni, hanem brmilyen QPaintDevice tpus objek-
tumra, ez az objektum az alaposztlya azoknak az objektumoknak, amelyek
valamilyen rajzolhat felletet tartalmaznak Valjban a QWidget is ebbl
szrmazik. Tovbbi kt gyakran elfordul leszrmazott osztly a QPrinter s
a QPixmap. Az els segtsgvel kinyomtathat felletet rnk el, a msodik-
kal pedig a memriban trolt bittrkpet. A QPainterben a felhasznlstl,
teht a konkrt QpaintDevice-tl fggetlenl trtnik a rajzols ugyanazok-
kal a fggvnyekkel, vagyis az a kdrszlet, amely egy memriban trolt k-
pet rajzol ki, egy az egyben felhasznlhat arra, hogy egy vezrl felletre
vagy egy nyomtathat terletre rajzoljunk.
Vgezetl megmutatjuk a main.cpp llomnyt, amelyben az elksztett
vezrl hasznlathoz ltrehozunk egy alkalmazsablakot, amelyben a kz-
ponti vezrljnek belltjuk a CustomWidget egy pldnyt:
/* main.cpp */
#include <QtGui >
#include "customwidget.h"
int mai n(i nt argc, char * argv[])
{
QAppl cati on app (argc , a rgv) ;
Qmai nwi ndow " w =new Qmai nwi ndow;
488
8.5. A dokumentum/nzet architektra
w->setwindowTitle("saj tv ez rl");
Customwidget*c=newCustomWidget;
w->setCentralWidget(c);
w->show();
returnapp.exec();
8.5. A dokumentum/nzet architektra
Ebben a fejezetben megvizsgljuk, hogyan lehet sszetettebb alkalmazsokat
fejleszteni gy, hogy a program struktrja mindvgig ttekinthet, bonyo-
lultsga pedig kezelhet legyen.
A felhasznli fellettel rendelkez (GUI) alkalmazsok fejlesztsekor
nagyon sok esetben adott valamilyen adathalmazunk, amelyet tbbflekp-
pen, tbb nzetbl szeretnnk megjelenteni. Miutn megjelentettk az ada-
tokat, a felhasznl mdostani szeretne rajtuk valamelyik esetleg egyms
utn tbb klnbz nzetben. A felhasznl termszetes elvrsa az, hogy
ha egy adott nzetben megvltoztatott valamit, mind az adathalmaz, mind a
tbbi nzet a vltoztatsnak megfelelen frissljn.
Erre knl egyfajta ltalnos megoldst a dokumentum/nzet (docu-
ment / view) architektra. Az adatok egyes megj elentsi formjt nzetnek
(view) nevezzk. Az adatokat a dokumentum (document) trolja. Ha egy nze-
ten keresztl megvltoztatunk valamit, a nzet frissti a megfelel adatokat a
dokumentumban is. A dokumentum feladata az, hogy ha az llapotban vl-
tozs trtnt, akkor az sszes hozzkapcsold nzetet azonnal rtestse, s
ezzel biztostsa, hogy a nzetek mindig a legfrissebb adatokat mutatjk. Ha
teht egy nzeten keresztl mdostottuk a dokumentum adatait, akkor az
sszes tbbi nzet is automatikusan rtestst kap errl. Az rtestett nzetek
lekrdezik a dokumentumtl az j adatokat, s gondoskodnak sajt jrarajzo-
lsukrl. Egy dokumentum llapott termszetesen nem csak a nzeteken
keresztl lehet mdostani, m brmi okozza is a vltozst, a nzeteket min-
dig rtesteni kell rla.
ltalban ltezik egy a lka lma z s (application) szerepl is, amely inicializl-
ja magt a programot, feldolgozza a parancssori argumentumokat, felpti a do-
kumentumot, ltrehozza a nzeteket, s hozzkapcsolja ket a dokumentumhoz.
A fentiekbl kvetkezik, hogy a dokumentumnak tudnia kell azokrl a
nzetekrl, amelyeket rtestenie kell egy esetleges vltozs esetn. Ez imp-
lementcis szinten, C++ nyelven legtbbszr gy jelenik meg, hogy a doku-
mentum tartalmaz egy olyan listt, amelyben az rtestend nzetekre mutat
pointereket trol. gy egy nzet feliratkozhat" erre a listra, vagy lekapcso-
ldhat rla, a dokumentum pedig bejrhatja ezt a listt, s rtestst kldhet
a nzettpus listaelemek egy megadott tagfggvnynek a meghvsval.
489
8. fejezet: A Qt keretrendszer programozsa
Termszetesen a nzeteknek is tudnia kell az ltaluk megjelentett doku-
mentumrl A dokumentumot egy, a dokumentumnzet-architektrn kvli
osztlyban pldul az alkalmazsban trolhatjuk, s a nzet kzvetlenl az
alkalmazstl krdezi le a dokumentumot. Ha azonban tbb dokumentum is
ltezik egy programon bell, akkor ez nem megfelel megolds, ilyenkor a
legclszerbb az, ha a nzet kln eltrol egy referencit a hozztartoz do-
kumentumra.
Az alkalmazsablakok trgyalsakor mr sz volt arrl, hogy a Qt keret-
rendszer tmogatja az SDI- s az MDI-alkalmazsok ksztst, az SDI rvid-
ts az egy dokumentumablakos, az MDI a tbb dokumentumablakos felletre
utal. Fontos hangslyozni, hogy a Qt terminolgijban a dokumentumablak
a fablakon bell megjelentett olyan tovbbi ablakot jelent, amelyben az ak-
tulisan szerkesztett adatokhoz tartoz funkcikat elrhetjk. Az SDI s az
MDI kifejezsek teht csak arra utalnak, hogy ilyen ablakokbl hny darab
lehet egyszerre megnyitva, vagyis pusztn a felhasznli fellet szempontj-
bl osztlyozzk az alkalmazsokat. A dokumentumablak s a dokumen-
tum/nzet architektra dokumentumkomponense kt klnbz tnyez, csak
a nevk hasonl. Knnyen elkpzelhet pldul, hogy a dokumentum/nzet
architektra szerint egyszerre csak egy dokumentum tallhat egy alkalma-
zsban, de ehhez tbb nzetet jelenthetnk meg klnll ablakokban. gy a
Qt terminolgija szerint MDI-alkalmazsfelletrl beszlnk.
Ebben a fejezetben egy MDI-alkalmazsfelleten keresztl bemutatjuk,
hogyan tudunk tbb dokumentumablakkal egyszerre dolgozni a Qt keret-
rendszerben. A tbb dokumentum kezelsre alkalmas pldaalkalmazs kom-
ponenseit a dokumentum/nzet architektrra ptve kezeljk, gy mutatjuk
be, hogy ezzel a mdszerrel hogyan lehet kzben tartani nagyobb mret
programok bonyolultsgt.
Feladat Ksztsnk programot mrsi eredmnyek (0 s 10 kztti szmok) listjnak a keze-
lshez. Ezeket az eredmnyeket egy listban szeretnnk kirni a felhasznlnak (ez az egyik
nzet), illetve egy hisztogram formjban is meg akarjuk jelenteni ket (ez a msodik nzet).
A mrsi adatokat egy-egy llomnybl olvassuk be. Nemcsak megjelentjk az adatokat ktf-
le nzetben, hanem azt is felttelezzk, hogy a mrsi eredmnyeket szolgltat eszkztl
jabb adatok rkezhetnek folyamatosan, gy ezekkel is frissteni kell a dokumentumot.
A feladat megoldst az albbiakban rszletesen bemutatjuk, az alkalmazs
felletnek egy kpernykpe a 8.8. brn lthat. A pldban az adatforrs
megvalstsra a fellet biztost majd egy gombot, ezt megnyomva az aktu-
lis dokumentum fogadni tudja az adatokat. Egy dokumentumhoz tartoz kt
nzetet mindig egyazon dokumentumablakon bell jelentjk meg, s minden
dokumentumhoz kln ablak tartozik. Termszetesen ugyanolyan knnyen
megvalsthat lenne az is, hogy a kt nzet kt klnbz ablakban jelenjen
meg, m kiderl, hogy a dokumentum/nzet architektra mkdse szempont-
jbl ennek nincs jelentsge. Azrt vlasztottuk az els megoldst, mert gy
minden nzetrl egyrtelm, hogy ppen melyik dokumentumhoz tartozik.
490
)(4
/home/mark/Documents/1.data - K x Diume s63.clata'
8.2
9.6
2.3
1/
0
6.3
9.1
12
6.6
0.7
8.2
9.6
23
1.9
9.1
92
6.6
0.7
6.9
8.5.Adok umentum/n zetarchitek tra
KonyvMOI
Elle
8.8. bra. MDI-alkalmazs kpernykpe
8.5.1. Az alkalmazs szerepe
Az alkalmazskomponens ltalban az alkalmazs fablakt zrja egysgbe.
A fablak feladata, hogy a felhasznli fellet egyes elemeit (men, llapot-
sor, eszkzsv, ablakok) sszefogja:
#ifndefMDIMAINWINDOW_H
#defineMDIMAINWINDOW_H
#include<QtGui>
#include"document.h"
classmoimainwindow: public Qmainwindow
{
Q_OBJECT
public:
explicitmoimainwindow(Qwidget*parent= 0) ;
signals:
public sl ots:
v oidopen();
v oidsav e();
v oidattach5ource();
491
8. fejezet: A Qt keretrendszer programozsa
priv ate:
QMdiArea*mdiArea;
QToolBar*fileToolbar;
QMenu*fileMenu;
QAction*exitAction;
QAction*openDocumentAction;
QAction*sav eDocumentAction;
QAction*attachDataSourceAction;
QList<Document*>*documents;
;
#endif//mDIMAINWINDOW_H
Az MDIMainWindow osztly a QMainWindowbl szrmazik. QAction tpus
tagvltozkat deklarltunk a kilpsre, j dokumentum megnyitsra, az aktv
dokumentum mentsre, illetve arra, hogy az aktv dokumentumhoz hozzcsa-
toljunk egy adatforrst. Az alkalmazs fablakban lthat dokumentumabla-
kok kzl az ppen a fkuszt birtoklt nevezzk aktv dokumentumablaknak,
s az ehhez tartoz dokumentumot nevezzk aktv dokumentumnak.
A dokumentumok tpust a document.h llomnyban deklarljuk (lsd
ksbb) Az alkalmazsunkban lv dokumentumokat egy listban troljuk,
ehhez a QList osztlyt hasznljuk.
A fablaknak hrom fontos vezrlje van, amelyekhez kln tagvltozt is
rendelnk. A mensvon egy Fjl" felirat ment helyeznk el, ezt a QMenu
tpussal rjuk le. Megjelentnk tovbb egy eszkzsvot is (fileToolBar),
amelyben ugyanazok a funkcik lesznek elrhetk, mint a menben. Vgeze-
tl az alkalmazs kzponti vezrlje egy QMdiArea pldny lesz, amely bizto-
stja a tbb dokumentumablakos krnyezet hasznlatt:
moimainwindow::mDIMainWindow(OWidget*parent):
QMainWindow(parent)
{
mdiArea=newQMdiArea;
this->setCentralWidget(mdiArea);
documents=newOList<Document*>;
fileMenu = this->menusar0->addmenu(tr("&Fjl"));
fileToolbar = this->addToolBar(tr("Fi1 e"));
openDocumentAction=newQAction(tr("&Megny it s"),this);
openDocumentAction->setIcon(QIcon::fromTheme("document-open"));
openDocumentAction->setShortcut(OKey Seguence::Open);
fileMenu->addAction(openDocumentAction);
fileToolbar->addAction(openDocumentAction);
connect(openDocumentAction,SIGNAL(triggered()),this,
SLOT(open()));
492
8.5.Adok umentum/n zetarchitek tra
sav eDocumentAction=newQAction(tr("Ment &s"),this);
sav eDocumentAction->setIcon(QIcon::fromTheme("document-sav e"));
sav eDocumentAction->setShortcut(QKey Seguence::Close);
fileMenu->addAction(sav eDocumentAction);
fileToolbar->addAction(sav eDocumentAction);
connect(sav eDocumentAction,SIGNAL(triggered()),this,
SLOT(sav e()));
attachDataSourceAction=
newQAction(tr("Forr scs&atol sa"),this);
attachDataSourceAction->setIcon(QIcon::fromTheme(
"sy stem-run"));
fileToolbar->addAction(attachDataSourceAction);
connect(attachDataSourceAction,SIGNAL(triggered()),this,
SLOT(attachSource()));
exitAction=newQAction(tr("&k il p s"),this);
exitAction->setIcon(QIcon;:fromTheme("application-exit"));
exitAction->setShortcut(QKey Sequence::Quit);
fileMenu->addAction(exitAction);
connect(exitAction,SIGNAL(triggered()),this,SLOT(close()));
}
A konstruktorban lthat, hogy az sszes tagvltozt inicializljuk, s elhe-
lyezzk a menben s az eszkzsvon a megfelel funkcikat. A kilpshez
tartoz funkci csak a menben, az adatforrs csatlakoztatshoz tartoz
funkci csak az eszkzsvon jelenik meg.
A tovbbi fggvnyek implementcijt a dokumentum- s a nzetoszt-
lyok trgyalsa utn mutatjuk be.
8.5.2. A dokumentumosztly
A dokumentumnak (a pldban Document osztly) a kvetkez feladatai vannak:
trolnia kell az adatokat;
interfszt kell biztostania az adatok mdostsra;
trolnia kell a hozz tartoz nzeteket, s lehetv kell tennie jabb
nzetek hozzadst, egy mr trolt nzet eltvoltst;
gondoskodnia kell arrl, hogy ha a trolt adatok vltoznak, akkor az
sszes nzet frissljn;
interfszt kell biztostania az adatok lekrdezsre, ugyanis a nzetek
a frissts sorn lekrdezik a dokumentumtl, hogy milyen adatokat
is kell pontosan megjelenteni:
493
8. fejezet: A Qt keretrendszer programozsa
#ifndef DOCUMENT_H
#defineDOCUMENT_H
#i ncl ude <QtCore>
#i ncl ude <QtGui>
#i nclude "vi ew. h"
cl ass view;
cl ass Document : public QObject
{
Q_OBJECT
public:
explicit Document(QObject *parent = 0);
void addvi ew(Vi ew view);
void removevi ew(vi ew " view);
QList<double> * getState() ;
si gnal s :
public slots:
void appendoata(doubl e val ue) ;
bool openFi 1 e (QStri ng fi 1 eName) ;
bool saveFi 1 e() ;
protected:
void updateAllvi ews() ;
pri vate:
QLi st<double> " state ;
QLi st<View"> "vi ews ;
QString fi 1 ename ;
};
#endif //DOCUMENT_H
A dokumentumosztlyban hivatkozunk a View s a DocumentWindow oszt-
lyokra. A DocumentWindow osztly nem a dokumentum/nzet architektra
rszt kpezi, egyszeren arra szolgl, hogy minden dokumentumhoz megje-
lentsen egy vezrlt (ezek lesznek az adott dokumentumhoz tartoz doku-
mentumablakok), amelyen egyms mell helyezzk az adott dokumentumhoz
tartoz nzeteket egy elrendezskezel objektummal.
A View a nzet az osztlyok kzs se. Felttelezzk, hogy minden olyan
nzet ebbl szrmazik, amelyet a dokumentumhoz nzetknt szeretnnk ren-
delni. Hogy mirt van szksgnk arra, hogy a nzeteknek kzs sosztlya
legyen, a ksbbiekben mg visszatrnk. A nzetek listjnak kezelshez
szksg van mg a views tagvltozra, az addView s a removeView fggv-
nyekre. Az updateAllViews fggvny feladata pedig az, hogy az dokumen-
tumban trolt adatok vltozsakor a listban trolt sszes nzetet rtestse.
494
8.5. Adok umentum/n zetarchitek tra
A dokumentumok kezdeti adatait llomnyokbl olvassuk be, ezrt elt-
rolunk egy llomnynevet (filename tagvltoz) is, illetve openFile s saveFile
fggvnyeket deklarlunk az adatok beolvassra s elmentsre.
A vals adatokat egy QList tpus listban troljuk, ezekre a state tagvl-
tozval hivatkozunk, lekrdezni 'ket pedig a getState fggvnnyel tudjuk.
Pldnkban az adatforrs bizonyos idnknt egy jabb szmot kld, ezt a
dokumentum hozzfzi a korbbi adatlista vgre. Erre szolgl az appendData
fggvny, amelyet szlotknt definilunk, hogy lehetsg legyen aszinkron m-
don msik szlbl kldeni az jabb adatokat, ahogyan azt vals krnyezetben
egy kls eszkztl vrnnk. Ha pldul a listanzeten keresztl is lehetsg
lenne jabb elemek beszrsra, akkor az a nzet is ugyanezt a fggvnyt
hasznlhatn az jonnan beszrt adat jelzsre.
A fentiek alapjn nzzk meg a dokumentumosztly fggvnyeinek imp-
lementcij t:
Document::Document(Q0bj ect*parent):
QObj ect(parent)
{
state=newQList<double>();
v iews=newQList<View*>;
}
v oidDocument::addView(View*v iew){
this->v iews->append(v iew);
}
v oidDocument::remov ev iew(v iew*v iew)
{
this->v iews->remov eAll(v iew);
}
QList<double>*Document::getState(){
returnthis->state;
v oidDocument::appendData(doublev alue){
this->state->append(v alue);
updateAllViews();
boolDocument::openFile(QStringfileName){
this->filename=fileName;
QFilefile(fileName);
i f(!file.open(QI0Dev ice::ReadOnly I QI0Dev ice::Text))
returnfalse;
QTextStreamin(&file);
495
8. fejezet: A Qt keretrendszer programozsa
while (! in.atEnd()) {
QString valueStr = in.readLine();
double value = valueStr.toDouble();
this->state->append(value);
updateAllviews();
return true;
}
bool Document: :saveFi 1 e(){
QFile fi 1 e(fi 1 ename) ;
f ( ! fi 1 e . open(Qi0Devi ce :writeOnly QI0Devi ce: :Text))
return fal se;
QTextStream out (&fi le) ;
QL
-
i stiterator<doubl e> iterator(*state);
while (i terator .hasNext()){
out i terator. next() " \ n" ;
return true;
}
void Document::updateAllviews() {
QListIterator<View*> iterator(*views);
whi le (i terator . hasNext())
{
iterator.next()->updateView();
}
Az updateAllViews defincijban a QListlterator segtsgvel vgigiterlunk
a nzetek listjn. A QListhez hasonlan a QListIterator is egy sablonosztly,
inicializlskor t kell adni a konstruktornak azt a listt, amelyet be szeret-
nnk jrni. Ezutn az itertorobjektum hasNext fggvnyvel krdezhetjk
le, hogy van-e mg elem a listban, s ha igen, akkor azt a next fggvnnyel
krhetjk el. (Termszetesen for ciklussal is bejrhatjuk a listt, a size fgg-
vnnyel lekrdezhet a mrete s a hagyomnyos indexels [ ] opertor is
hasznlhat.) A ciklus belsejben minden egyes nzetnek meghvjuk az update-
View fggvnyt, amely egy, a View osztlyban deklarlt virtulis fggvny, gy
minden leszrmazott nzetosztly rendelkezik ilyen metdussal.
rdemes rviden beszlni az openFile fggvnyrl, amely egy adott nev
llomnyt nyit meg. Ehhez a QFile osztlyt hasznljuk. Az open metdussal
lehet hozzfrni egy llomnyhoz. A fggvny argumentumban jelezni kell,
hogy milyen mveletet szeretnnk az llomnyon vgrehajtani. A QText-
Stream osztly biztost egy olyan szvegfolyamot, amellyel olvasni tudjuk az
llomny tartalmt. Felttelezzk, hogy a beolvasott llomny minden egyes
sora egy darab double tpus szmot tartalmaz, betlts utn ezek lesznek a
dokumentum kezdeti adatai.
496
8.5. A dokumentum/nzet architektra
8.5.3. A nzetosztlyok
A nzetosztlyok egy kzs sbl szrmaznak, amelyet a View osztly defini-
l. A kzs s biztostja azt az interfszt, amelyen keresztl a dokumentum
rtesteni tudja a nzeteket:
#ifndefVIEW_H
#defineVIEW_H
#include"document.h"
#include<QtGui>
#include<QtCore>
classDocument;
classView: public QWidget
{
Q_OBJECT
public:
explicitv iew(Qwidget*parent=0);
v irtualv oidupdateView();
v oidsetDocument(Document*doc);
signals:
public slots:
protected:
Document*document;
} ;
#endif//VIEW_H
A nzet teht egy referencit tartalmaz a dokumentumra, s egy updateView
fggvnyt definil, amely virtulis, gy a leszrmazott konkrt nzetek fell-
definilhatjk:
View::View(QWidget*parent):
QWidget(parent){ }
v oidView::setDocument(Document*doc){
this->document=doc;
updateView();
v oidView::updatev iew(){ }
497
8.fej ezet:AQtk eretrendszerprogramoz sa
A nzet implementcijban egyedl a setDocument fggvnyt emeljk ki: ezzel
tudjuk belltani a nzethez tartoz dokumentumot Amint a bellts megtr-
tnt, meghvjuk az updateView fggvnyt is, hogy az jonnan hivatkozott
dokumentum alapjn a nzet mris frissljn. Az adott nzethez tartoz doku-
mentumot, akr a konstruktorban is tadhatnnk, mivel minden egyes nzet-
hez biztosan tartozik pontosan egy olyan dokumentum, amelyet megjelent.
Ktfle nzetre van szksgnk, ezrt kt osztlyt szrmaztatunk le a
View-bl. Az els egy tblzatban, pontosabban egy listban rja ki az adatokat,
ez a TableView, a msik hisztogram formjban rajzolja ki, ez a DiagramView.
A lists megjelents valamivel egyszerbb, mert itt a Qt beptett vezr-
ljt a QListWidgetet hasznljuk a megjelentshez:
#ifndefTABLEVIEW_H
#defineTABLEVIEW_H
#include<QtGui>
#include"v iew.h"
classTableView:publicvi ew
{
Q_OBJECT
public:
explicitTablev iew(0widget*parent=0);
v oidupdatev iew();
signals:
publicslots:
protected:
QListwidget*list;
QVBoxLay out*lay out;
};
#endif//TABLEVIEW_H
Az osztly tartalmaz egy referencit egy QListWidget tpus vezrlre, amely
az adatok megjelentsre szolgl. Tovbb felldefiniljuk az updateView
fggvnyt, amelyet a View sosztlyban definiltunk virtulis fggvnyknt:
Tablev iew::Tablev iew(0widget*parent):
vi ew(parent)
{
lay out=newQVBoxLay out;
this->setLay out(lay out);
list=new stwidget;
1ay out->addwidget(1st);
}
498
8.5.A dokumentum/nzet architektra
v oidTablev iew:updateView(){
1ist->clear();
Q^ist<double>*state=document->getStateO;
QListIterator<double>terator(*state);
whi1e(iterator.hasNext())
{
doublev alue=iterator.next();
1st->additem(Qstring:number(v alue));
}
A konstruktorban egy elrendezskezel objektum segtsgvel elhelyezzk a
listavezrlt. Az updateView fggvnyt akkor hvjuk meg, amikor a dokumen-
tum tartalma a korbban megjelentetthez kpest frisslt, ezrt ilyenkor jra
kell rajzolni a nzetet. Jelen esetben ez azt jelenti, hogy ki kell trlni a list-
bl az eddig trolt elemeket, lekrdezni a dokumentumtl az aktulis adato-
kat s hozzadni ket a listhoz.
Knnyen tudnnk mdostani a nzetet gy, hogy a felhasznl j rtket
is hozz tudjon adni ezen keresztl a dokumentumban trolt adatokhoz: ehhez
egyszeren arra lenne szksg, hogy pldul elhelyezznk egy QPushButton
tpus gombot, s megnyomsval feliratkozzunk egy szlotfggvnnyel. Ebben
meghvhatjuk a dokumentum appendData fggvnyt, amelynek tadunk
egy vletlen, 0 s 10 kztti double rtket, vagy beolvashatjuk ezt az rtket
a felhasznltl egy dialgusablakon keresztl. Ezutn a dokumentumban
mr automatikusan meghvjuk mindegyik nzeten az updateView fggvnyt,
gy a tbbivel egytt az aktulis nzet amelyen keresztl a mdosts tr-
tnt ugyancsak frissl.
Valamivel bonyolultabb a hisztogramos nzetet megvalst DiagramView
osztly, ezt egy custom widgetknt definiljuk. Ebben a nzetben a doku-
mentumban trolt adatokat egyms alatt, 10 pixel magas tglalapokkal br-
zoljuk, a tglalapok szlessge az egyes adatok rtkvel arnyos. 10-es rtk
esetn a tglalap a vezrl teljes szlessgt kitlti, 0-nl pedig 0 pixel a sz-
lessge. Elfordulhat, hogy tbb adat van, mint amennyivel egy 10 pixel ma-
gas tglalapot ki tudunk rajzolni egyms al a vezrl terletre, ilyenkor
csak a lista vgn lv (legfrissebb) adatokat jelentjk meg.
Ebben a vezrlben a QPainter osztly segtsgvel rajzolunk a vezrl fel-
letre, ezrt felldefiniljuk a paintEvent virtulis metdust (lsd korbban is).
A nzet implementcijnl alkalmazunk egy fontos mdszert, amelyet
gyakran hasznlunk sajt vezrlk ksztsekor Amikor maga a rajzols tbb
lpsbl ll, vagy gyakran kell frissteni a nzetet, a megjelents kzben azt
tapasztalhatja a felhasznl, hogy a vezrl villog. Erre a problmra egy sz-
les krben alkalmazott s tmogatott megolds a kettsbuffer-technika vagy
msknt a virtulis ablakok mdszere. A technika lnyege az, hogy ltreho-
zunk egy, a kpernyvel kompatibilis felpts memriaterletet amelyet a
Qt keretrendszerben a QPixmap osztllyal runk le , s arra rajzolunk, majd
a megjelentskor a memriaterletet egy mvelettel a kpernyre msoljuk.
4 99
8.fej ezet:AQtk eretrendszerprogramoz sa
A rajzols ugyangy trtnik, mintha a sajt vezrlnk terletre rajzol-
nm,(lsd a QPainterrel kapcsolatban is). A villogsnak kt oka is lehet: az
egyik az, hogy maga a rajzols tbb lpsbl ll, a msik pedig az, hogy a raj-
zols mvelete hossz, s gyakran kell ismtelni. A Qt keretrendszer 4 -es
verzija ta a vezrlk az els problmt automatikusan kezelik, vagyis ez
nmagban nem vezet villogshoz. Ms keretrendszerek hasznlatakor ez
nincs felttlenl biztostva, ezrt rdemes lehet megfontolni a kettsbuffer-
technika alkalmazst A msodik problma esetben viszont mindenkppen
rdemes hasznlni ezt a mdszert. Tegyk fel ugyanis, hogy a teljes kirajzo-
lst a paintEvent fggvnyen bell valstjuk meg, vagyis itt lekrdezzk a
dokumentumtl az adatokat, s a megfelel logikval kirajzoljuk ket.
A paintEvent nemcsak akkor fut le, amikor a dokumentum tartalma frissl,
hanem amikor pldul a takarsban lv nzetnk eltrbe kerl. Ha nzet
frisstse sorn a kirajzoland kpet a memriban troljuk, akkor elg egy-
szer ezt tmsolni, ahelyett, hogy a bonyolult s hosszadalmas logikval j-
bl ellltannk:
#ifndefDIAGRAMVIEW_H
#defineDIAGRAMVIEW_H
#include<0tGui>
#include"v iew.h"
classDiagramView: publicv iew
{
Q_OBJECT
public:
explicitDiagramView(QWidget*parent= 0);
v oidupdatev iew();
signals:
publicslots:
v oidpaintEv ent(0P aintEv ent*);
v oid resizeEv ent(QReszeEv ent*);
protected:
v oidupdate8uffer();
QP ixmap*buffer;
};
#endif//DIAGRAMVIEW_H
Nzzk meg teht, hogy a DiagramView osztlyban hogyan valstjuk meg a
kettsbuffer-technikt Szksg van egy QPixmap tpus bufferre (buffer),
amelyre majd rajzolni tudunk, s szksg lesz egy fggvnyre (updateBuffer),
500
8.5. A dokumentum/nzet architektra
amely majd a dokumentum aktulis llapota alapjn frissti a buffert. Ami-
kor a nzetet frisstjk, akkor a buffert is jra kell rajzolni, a paintEvent
fggvnyen bell pedig csak a buffer tartalmt kell tmsolni. A kirajzoland
tartalom azonban nemcsak a dokumentum llapottl fgghet, hanem a ve-
zrlnk mrettl. is. Ezrt szksg van a resizeEvent felldefinilsra is,
amely a vezrl tmretezsekor hvdik meg, ebben ugyanis szintn frisste-
ni kell a buffer tartalmt.
A fenti megfontolsok alapjn nzzk meg a nzet fggvnyeinek imple-
mentcijt:
Di agramVi ew: :Di agramVi ew(QWi dget *parent) :
View(parent)
{
thi s->setmi nimum5i ze(200 , 100) ;
buffer = NuLL;
}
void Di agramview: :pal ntEvent(QPai ntEvent * pai nEvent){
QPai nter pai nter(thi s) ;
if (buffer ! = NULL)
pai nter . drawPi xmap(rect () , *buffer) ;
void Di agramVi ew: : updatevi ew(){
updateBuffer ;
update() ;
void Di agramVi ew: updateBuffer
if (buffer ! = NULL)
del ete buffer;
buffer = new QPi xmap(rect si ze()) ;
QPai nter pai nter(buffer) ;
pai nter. setBrush(Qt: :whi te) ;
pai nter . fi 11Rect(rect() , Qt : :whi te) ;
pai nter. setPen(Qt: : bl ue) ;
QList<double> * data =this->document->getstate();
0/11'
int barHeight = 10;
int maxitems = rect().height() / barHeight;
int index;
int offset = 0;
for (index = data->size() - maxitems < 0 ? 0 :
data->size() - maxitems; index<data->size(); index++)
double value = data->at(index);
painter.drawRect(0, offset*barHeight,
(value/10)*rect().width(), barHeight);
offset ++;
501
8. fejezet: A Qt keretrendszer programozsa
v oidDiagramv iew;:resizeEv ent(QResizeEv ent*resizeEv ent){
updateBuffer();
update();
A paintEvent tmsolja a buffer tartalmt a vezrlre, ehhez a QPainter osz-
tly drawPixmap fggvnyt hasznljuk. Fontos ellenrizni eltte, hogy a
buffer valban megfelelen lett-e inicializlva, mert amg mg nem rendeltnk
dokumentumot a nzethez, addig nem trtnik meg a bufferbe rajzols sem.
Az updateView fggvnnyel rtesl a nzet a dokumentum vltozsrl,
ezrt ebben frissteni kell a buffert, majd hogy a vltozs meg is jelenjen
meg kell hvni az update fggvnyt, amely egy jrarajzolsi jelzst kld az
adott vezrlnek. Lehetsg van az update helyett a repaint fggvny haszn-
latra is.
A resizeEvent fggvnyben, a vezrl mretnek megvltozsakor ugya-
nezt a logikt kell megrni, frissteni a buffert, majd az update hvssal meg-
jelenteni a friss tartalmat.
A tartalom ellltst az UpdateBuffer fggvny vgzi. Ebben a rajzols
ugyangy, egy QPainter objektummal trtnik, mintha magra a vezrlre
rajzolnnk kzvetlenl, csak itt a memriabeli kp mutatjt kell tadni a
konstruktorban. A QPixmap pldnyokat az inicializls utn nem lehet t-
mretezni, ezrt a fggvny minden egyes futtatsakor j QPixmap pldnyt
hozunk ltre. A tovbbi kdrszlet a korbban lert megjelentst vgzi el, va-
gyis kiszmtja, hogy hny tglalap fr el a vezrl terletn, s ettl fggen
kirajzolja az utols nhny adatnak megfelel tglalapot. A barHeight loklis
vltoz rgzti, hogy a megjelentett tglalapok magassga 10 pixel, a max-
Items loklis vltozban troljuk azt, hogy ekkora tglalapokbl legfeljebb hny
darab fr el a vezrl aktulis terletn. A for ciklusban a data gyjtemnyben
trolt utols maxltems darab elem indexn iterlunk vgig. Termszetesen, ha
a data elemeinek a szma kisebb, mint a maximlisan megjelenthet elemek
szma, akkor az sszeset kirajzolja a program. A QList generikus gyjtemny
elemeinek a szmt a size fggvnnyel, mg egy adott indexhez tartoz elemet
az at fggvnnyel krdezhetnk le. Az offset loklis vltozt hasznljuk arra,
hogy megadjuk, hnyadik tglalapot razoljuk ki, ez azrt fontos, mert a kiraj-
zolt tglalapok szmtl fgg, hogy a tglalap bal fels sarknak mi legyen a
fggleges koordintja. Azrt nem a for ciklus index nev fut vltozjt
hasznljuk erre, mert nem biztos, hogy a gyjtemny minden elemt megje-
lentjk. Kiemelend mg a QPainter osztly drawRect fggvnye, amely az
aktulis tollal s ecsettel kirajzol egy tglalapot. A drawRect fggvnynek
tbbfle paramterezse is ltezik, a fenti pldban elszr a bal fels sarok
vzszintes s fggleges koordintit, majd a tglalap szlessgt s magas-
sgt kell tadni.
502
8.5.Adok umentum/n zetarchitek tra
8.5.4. Tovbbi osztlyok
A teljessg kedvrt bemutatjuk a DataSource osztly defincijt is, amelynek
segtsgvel egy adatforrst tudunk a dokumentumokhoz kapcsolni. Egy vals
alkalmazsban ennek a komponensnek a segtsgvel fogadnnk a kls eszkz-
rl rkez adatokat. Ebben a pldban egyszeren egy vletlenszm-genertor
kld msodpercenknt jabb mrsi eredmnyeket" a dokumentumosztly-
nak.m A dokumentum appendData fggvnye egy szlot, gy a msik szlban fut
adatforrs a szignl-szlot mechanizmusra ptve kldhet rtestst:
#ifndefDATASOURCE_H
#defineDATASOURCE_H
#include<QtGui>
#include"document.h"
classDocument;
classDataSource:publicQObj ect
{
Q_013 7ECT
public:
explicitDataSource(Qobj ect*parent=0);
v oidsetDocument(Document*doc);
signals:
v oiddataReceiv ed(doubledata);
publicslots
v oidtimerTimedOut();
v oidstopTimer();
priv ate
Document*document;
QTimer*timer;
;
#endif//DATASOURCE_H
A DataSource osztly deklarcija a kvetkez fontosabb tagokat tartalmazza:
idzt (timer), timerTimedOut s stopTimer szlotfggvnyek, illetve a data-
Received szignl.
11
Jelen trgyalsban a hangsly az adatforrs s a dokumentumosztly kztti kommuni-
kcin van, a mrsi adatok rkezst csak szimulljuk. A gyakorlatban az adat rkezhet
egy eszkzvezrltl, hlzatrl, msik szltl s szmos egyb mdon.
503
8.fej ezet:AQtk eretrendszerprogramoz sa
Az idztshez a Qt beptett idztosztlyt, a QTimert hasznljuk.
A QTimer objektumok a timeout szignllal jelzik, hogy eltelt az elre bell-
tott id, erre a timerTimedOut szlottal iratkozunk fel. A dataReceived szignl-
lal jelez az adatforrs a dokumentumnak, hogy j adat rkezett. A stopTimer
fggvnyben lltjuk le az idztt, amikor mr nincsen r szksg, mert
amikor egy dokumentumot bezrunk, akkor a hozzkapcsold adatforrsban
mkd idztt is felszabadthatjuk:
DataSource::DataSource(Q0bj ect*parent):
QObj ect(parent){ }
v oidQataSource::setDocument(Document*doc){
this->document=doc;
timer=newQTimer(this);
connect(timer,SIGNAL(timeout())this,SLOT(timerTimedOut0)) ;
connect(this,SIGNAL(dataReceiv ed(double)),doc,
SLOT(appendData(double)),Qt::QueuedConnection);
timer->start(1000);
v oidDataSource::merTimedOut(){
emitdataReceiv ed((double)(qrand()%100)/10.0);
}
v oidDataSource::stopTimer(){
this->timer->stop();
}
A DataSource osztly setDocument fggvnyvel tudjuk az adatforrst egy
dokumentumhoz csatolni, ilyenkor indtjuk el az idztt, amelynek a jelzs-
rl a timerTimedOut szlottal kapunk rtestst. Az idztt a QTimer osztly
start metdusval indtjuk el. Szintn a setDocument fggvnyben ktjk sz-
sze a dataReceived szignlt s a dokumentum appendData szlotfggvnyt.
A timerTimedOut szlotban a qrand fggvnnyel generlunk egy vletlen
szmot, majd ezt normalizlva egy 0 s 10 kztti vletlen rtkk generl-
juk, kibocstjuk a dataReceived szignlt, jelezve, hogy j adat rkezett. Vge-
zetl pedig a stopTimer szlot az idzt lelltsrt felels.
A DocumentWindow osztly sszefogja s megjelenti az egy dokumen-
tumhoz tartoz nzeteket. Ismt hangslyozni kell, hogy ez az osztly nem
kpezi a dokumentum/nzet architektra rszt.
A DocumentWindow egy olyan QWidgetbl szrmaz vezrl, amely egy
vzszintes elrendezskezel objektum segtsgvel kirajzolja az ablakhoz az
addView fggvnnyel hozzadott nzeteket. A DocumentWindow egy referen-
cit trol a dokumentumra, s ha ltezik, akkor a dokumentumhoz kapcsolt
adatforrsra is:
504
8.5.Adok umentum/n zetarchitek tra
#ifndefDOCUMENTWINDOW_H
#defineDOCUMENTWINDOW_H
#include<QtGui>
#include"document.h"
#include"datasource.h"
classDocument;
classv iew;
class DataSource;
classDocumentwindow: public Qwidget
{
Q_OBJECT
public:
explicitDocumentwindow(Qwidget*parent =0);
v oidsetDocument(Document*doc);
v oidsetDataSource(DataSource*source);
DataSource*getDataSource();
v oidaddv iew(v iew*v iew);
Document*getDocument();
signals:
public slots:
priv ate:
Document*document;
priv ate:
QHBoxLay out*lay out;
DataSource*source;
};
#endif /7 DOCUMENTWINDOW_H
Az implementciban csak a setDataSource fggvny rdemel kln emltst.
Ezzel lltjuk be az adatforrs-referencit egy j adatforrsra. A bellts
utn az adott vezrl destroyed szignljt sszektjk az adatforrs stop-
Timer szlotjval, gy az adott ablak bezrsakor az adatforrs is befejezi az
adatok kldst:
Documentwindow::Documentwindow(Qwidget*parent):
Qwidget(parent)
this->lay out=newQHBoxLay out;
this->setLay out(lay out);
this->source=NULL;
}
505
8.fej ezet:AQtk eretrendszerprogramoz sa
v oidDocumentwindow::setDOCUment(DoCUment*doc){
this->document=doc;
}
v oidDocumentWindow::addView(v iew*v iew){
this->lay out->addwidget(v iew);
this->update();
}
Document*Documentwindow::getDocument(){
returnthis->document;
v oidDocumentWindow::setDataSource(DataSource*source){
this->source=source;
connect(this,SIGNAL(destroy ed()),source,SLOT(stopTimer()));
}
DataSource*Documentwindow::getDataSource(){
returnthis->source;
}
Vgezetl bemutatjuk az alkalmazsosztly implementcijt:
mDimainWindow::MDIMainwindow(Qwidget*parent):
QMainwindow(parent)
{
mdiArea=newQMdiArea;
this->setCentralwidget(mdiArea);
documents=newQList<Document*>;
fileMenu=this->menuBar()->addmenu(tr("&File"));
fileToolbar=this->addToolBar(tr("File"));
openDocumentAction=newQAction(tr("&Open"),this);
openDocumentAction->setIcon(QIcon::fromTheme("document-open"));
openDocumentAction->setShortcut(QKey Seguence::Open);
fileMenu->addAction(openDocumentAction);
fileToolbar->addAction(openDocumentAction);
connect(openDocumentAction,SIGNAL(triggered()),this,
SLOT(open()));
sav eDocumentAction=newQAction(tr("&Sav e"),this);
sav eDocumentAction->seticon(QIcon::fromTheme("document-sav e"));
sav eDocumentAction->setShortcut(QKey Seguence::Close);
fileMenu->addAction(sav eDocumentAction);
fileToolbar->addAction(sav eDocumentAction);
connect(sav eDocumentAction,SIGNAL(triggered()),this,
SLOT(sav e()));
506
8.5.A dokumentum/nzet architektra
attachDataSourceAction=newQAction(tr("&Attach"),this);
attachDataSourceAction->
setIcon(QIcon::fromTheme("sy stem-run"));
fileToolbar->addAction(attachDataSourceAction);
connect(attachDataSourceAction,SIGNAL(triggered()),this,
SLOT(attachSource()));
exitAction=newQAction(tr("E&xit"),this);
exitAction->setIcon(Qicon::fromTheme("application-exit"));
exitAction->setShortcut(Qxey Sequence::Quit);
filemenu->addAction(exitAction);
connect(exitAction,SIGNAL(triggered()),this,sLOT(close()));
}
v oidmDimainwindow::open(){
QStringfileName=QFileDialog::getOpenFileName(this,
tr("Opendocument"),"/Documents",
tr("Documentfiles(*.data)"));
if(fileName=="")
return;
Document*doc=newDocument;
this->documents->append(doc);
doc->openFile(fileName);
Documentwindow*w=newDocumentwindow;
w->setObj ectName("Documentwindow");
QMdiSubwindow*wContainer=this->mdiArea->addSubwindow(w);
w->setDocument(doc);
wContainer->setwindowTitle(fileName);
Tablev iew*table=newTablev iew;
table->setDocument(doc);
w->addv iew(table);
doc->addv iew(table);
Diagramv iew*diagram=newDiagramv iew;
diagram->setDocument(doc);
w->addv iew(diagram);
doc->addv iew(diagram);
w->show();
v oidmDIMainwindow::sav e(){
QMdisubwindow*subwindow=this->mdiArea->activ esubwindow();
if(subwindow==NULL)
return;
Documentwindow*w=
subwindow->findChild<Documentwindow*>("Documentwindow");
w->getDocument()->sav eFile();
}
507
8. fejezet: A Qt keretrendszer programozsa
v oidmDimainwindow::attachSource(){
Qmdisubwindow*subwindow=this->mdiArea->activ eSubwindow();
if(subwindow== NULL)
return;
Documentwindow*w=subwindow->
findchild<Documentwindow*>("Documentwindow");
if(w==NULL)
return;
if(w->getDatasource()!=NULL)
return;
DataSource*source=newDataSource;
source->setDocument(w->getDocument());
w->setDataSource(source);
A konstruktorban felptjk a felhasznli felletet, ltrehozzuk a QAction
objektumokat, s elhelyezzk ket a menben s az eszkztrban. Az MDI
esetben az alkalmazs fablaknak kzponti vezrlje egy QMdiArea pl-
dny kell, hogy legyen.
Dokumentumot megnyitni az openDocumentAction segtsgvel tudunk,
ennek meghvsakor az open szlot fut le. A QFileDialog osztly statikus
getOpenFileName fggvnyvel megjelentnk egy dialgusablakot, amellyel
a .data kiterjeszts llomnyokat tudjuk kivlasztani. Ezutn ltrehozzuk a
dokumentumot s a hozztartoz kt nzetet. A kt nzetet nem kln abla-
kokban, hanem egy DocumentWindow pldnyban helyezzk el. A pldnynak
a setObjectName fggvnnyel adunk egy nevet, ez segt majd azonostani, ha
az adott elemet a vezrlk fastruktrjban akarjuk programozottan keresni
(lsd ksbb). A ltrehozott DocumentWindow pldnyt a QMdiArea osztly
addSubWindow fggvnyvel jelentjk meg egy jabb ablakknt a fablakon
bell. Ilyenkor a QMdiAren bell ltrejn egy QMdiSubWindow tpus ve-
zrl ez az addSubWindow visszatrsi rtke , amely felels a kirajzolt
ablak fejlcnek s keretnek a megjelentsrt. Ezen bell a kzponti vezr-
l lesz az addSubWindow fggvnynek tadott DocumentWindow pldny.
Az ablakot vgl a show fggvnnyel meg kell jelenteni.
Egy dokumentum aktulis llapott a save szlotfggvny menti el Amikor
a mentsi funkcit kivlasztjuk, az aktv ablak dokumentumt szeretnnk
menteni. Az aktv ablakot a QMdiArea osztly activeSubWindow fggvnyvel
krdezzk le, amely a korbbiakban elmondottak rtelmben egy QMdiSub-
Window pldnnyal tr vissza. Ennek a pldnynak a gyermekvezrlje az
adott dokumentumhoz tartoz DocumentWindow, amelyet legegyszerbben
a findChild sablonfggvnnyel krdezhetnk le. Ennek meg kell adni az
adott vezrl tpust s az objektum nevt, amelyet korbban belltottunk
a setObjectName fggvnnyel. gy megszereztk a referencit az aktv Docu-
mentWindow pldnyra, ettl mr lekrdezhet a dokumentum. Ezt a doku-
mentumot kell elmenteni a saveFile fggvnnyel.
508
8.6. Tovbbi technolgik
Az attachSource fggvny hasonlkppen mkdik. Miutn elrtk az ak-
tv ablakhoz tartoz DocumentWindow pldnyt s azon keresztl a doku-
mentumot, ltrehozunk egy DataSource objektumot, s a dokumentumhoz
kapcsoljuk.
sszefoglalva elmondhatjuk, hogy az alkalmazs az, amely inicializlja s
mozgsba hozza" a dokumentum/nzet architektrt. Az MDIMainWindow
s a DocumentWindow kzsen ltjk el az alkalmazskomponens feladatait,
vagyis a dokumentumok s nzetek ltrehozst s kezelst, de ez nem rin-
ti a dokumentum- s a nzetosztlyok hasznlatt.
8.6. Tovbbi technolgik
A Qt keretrendszer nem csak egy grafikus vezrlket tartalmaz osztly-
knyvtr. Tbb modulja van, amely a felhasznli fellet mgtti alkalmazs-
logika platformfggetlen programozst segti. A Qt-t gyakran hasznljk
csak konzolos alkalmazsok fejlesztsekor is.
A kvetkezkben ttekintjk a Qt keretrendszer nhny fontos technolgi-
jt s az azokhoz kapcsold osztlyokat. Az els a QtCore alapmodul rsze, s
a tbbszl programozst teszi lehetv. A msodik az adatbziskezels elr-
st tmogat knyvtr, amely egy kln modulban, a QtSqlben tallhat. Vgl
bemutatjuk a hlzati kommunikci programozshoz hasznlhat osztly-
knyvtrat, a QtNetwork modult.
8.6.1. Tbbszl alkalmazsfejleszts
A Qt keretrendszer QtCore moduljnak rsze a tbbszl programozst lehe-
tv tv osztlyknyvtr. Ez tmogatja j szlak indtst s a szlak kzt-
ti szinkronizcit.
Tbbszl alkalmazs rsakor figyelni kell arra, hogy az objektumokat
melyik szlban hoztuk ltre. Egy QObject tpus objektumot csak abban
a szlban szabad ltrehozni, amelyben a szlobjektumot hoztuk ltre, s
gondoskodni kell a ltrehozott objektumok trlsrl, mieltt magt a szlat
trlnnk.
A szlak kztti szinkronizcit s kommunikcit tbbfle segdosztly
teszi lehetv. Korbban mr bemutattuk, hogy a Qt keretrendszer fontos tu-
lajdonsga az, hogy a szignl-szlot mechanizmus alkalmas arra, hogy tbb-
szl krnyezetben hasznljuk, azaz lehetsg van bizonyos szignlokat ms
szlakban fut szlotokkal sszektni. A keretrendszer lehetv teszi, hogy
minden szlnak legyen kln esemnykezel ciklusa, s ez teszi lehetv a
vrakozsisor-alap sszekttetsek hasznlatt.
509
8. fejezet: A Qt keretrendszer programozsa
Az j szlak programozsnak bemutatsa eltt tekintsk t rviden, ho-
gyan indul el egy alkalmazs fszla a Qt keretrendszerben. Minden alkal-
mazs a main fggvny futtatsval kezddik, ebben a korbbi pldknl
ltalban ltrehoztunk egy QApplication tpus objektumot, itt a main fgg-
vny vgn meghvtuk az exec metdust. Ez az objektum felels az alkalma-
zs fszlnak, a grafikus szlnak a futtatsrt. Az exec hvsakor valjban
a fszlhoz tartoz esemnykezel ciklus indul el. Erre az esemnykezel cik-
lusra azrt van szksg, hogy az opercis rendszertl rkez zeneteket,
illetve a QObject pldnyok kztti zeneteket kezelni tudjuk. Ezrt egy ilyen
alkalmazsobjektumbl csak egy lehet a programunkban. Ha nem grafikus
fellettel rendelkez, hanem ms Qt-funkcikat hasznl konzolos alkalma-
zst runk, akkor a QApplication helyett a QCoreApplicationt kell pldnyos-
tani. Ez az osztly a QApplication se, s ugyancsak elindt egy zenetkezel
ciklust, de nem a grafikus fellet szmra.
A felhasznli felletet alkot vezrl'k mindig az alkalmazs fszlban
futnak, ezrt ezekhez az objektumokhoz csak a fszlban szabad hozzfrni.
Tegyk fel, hogy egy grafikus fellettel rendelkez alkalmazsban egy gomb
megnyomsnak hatsra idignyes szmtsi mveletet vgznk el. Ezzel
az a problma, hogy ha a mveletnek nem indtunk j szlat, akkor az az al-
kalmazs fszlban fut, amely egyben a megjelentsrt is felels. A mvelet
hosszabb ideig blokkolja a szl mkdst, gy a grafikus fellet a felhasznl
szmra elrhetetlen lesz, mert a felhasznli esemnyeket a mvelet befeje-
zsig nem tudja feldolgozni. rdemes teht ekkor j szlat indtani Ilyenkor
meg kell oldani a kt szl kztti kommunikcit. Ha pldul a szmts
eredmnyt egy szvegdobozban akarjuk megjelenteni, akkor a msik szlbl
egy zenetet kell kldennk a fszlnak a mvelet vgn, ugyanis a msik
szlbl nem mdosthatjuk a fszlban lv objektumok, pldul a vezrl'k
llapott. Erre a problmra a legknyelmesebb megolds a szignl-szlot
mechanizmus hasznlata, ez ugyanis a programoz szmra tltszan kezeli
azt, hogy a szignlt publikl s a szlotot definil objektumok ugyanabban
vagy msik szlban futnak-e.
Egy szl indtshoz szksg van egy olyan objektumra, amely a QThread
osztlybl szrmazik A szlak a main fggvny helyett a QThread osztly run
metdusnak meghvsval indulnak el. Sajt szl definilshoz a QThreadbl
kell leszrmaztatni s fellrni a virtulis run metdust. A szl vgrehajtsa ak-
kor fejezdik be, amikor a run fggvny visszatr, pontosan gy, ahogyan az al-
kalmazs futsa is vget r, amikor a main fggvny befejezdik:
v oid QT;ktr
dmr14 .'0..4 .
A run lthatsga protected, ezrt a szl elindtshoz nem kzvetlenl ezt a
fggvnyt hvjuk meg, hanem a QThread start metdust. Egy adott szl l-
lapott az isRunning, illetve az isFinished metdusokkal lehet lekrdezni a
QThread objektumtl, tovbb hrom szignl is rendelkezsnkre ll, ame-
lyek jelzik, amikor a szl elindult (started), befejezte a futst (finished), il-
letve a szlat lelltottk mg annak befejezse eltt (terminated):
510
8.6. Tovbbi technolgik
bool QThread::isFinished O const
bool QThread::isRunning O const
void QThread::started
void QThread::finished
void QThread: :terminated
// signal
// signal
// signal
j szl indtsakor szksg lehet sajt esemnykezel ciklusra, ha pldul a
szignl-szlot mechanizmust szeretnnk hasznlni. Ennek elindtsra az exec
fggvnyt hasznljuk, ezt a run fggvnyen bell kell meghvni:
QT
bre4d
-
-'
Ilyenkor a szl folyamatosan fut, amg az esemnykezel ciklust le nem llt-
juk. A lelltshoz a szl quit vagy exit fggvnyt kell meghvni. A quit meg-
egyezik az exit(0) hvsval. Az exit paramtere a szl visszatrsi rtke lesz,
s a szl elindtshoz hasznlt exec fggvny ezzel tr vissza. Mindkt fgg-
vnyt szlotknt definiltk, gy szignlok segtsgvel is knnyen lelltha-
tunk egy szlat:
voi Qrh read : qui t ()
void QTh red : : exi t ( i nt returncode = 0 )
Feladat Ksztsnk egy grafikus fellettel rendelkez alkalmazst, amely a felleten tallha-
t nyomgomb megnyomsra indt egy j szlat, amelyben elvgez egy szmtsi mveletet,
majd annak az eredmnyt megjelenti.
Ezen a pldn megmutatjuk, hogyan tudunk j szlat indtani, hogyan defi-
niljuk azt, hogy az indtott szl milyen mveletet hajtson vgre, s hogyan
tudunk a szignl-szlot mechanizmus segtsgvel kommunikcit megvals-
tani klnbz szlak kztt.
A 8.9. brn lthat az alkalmazs kpernykpe. A mvelet, amelyet el-
vgznk a 12 s a 13 szmok sszegnek kiszmtsa, ezt a 12 + 13 = ?" sz-
veg kirsval jelezzk, amelyre egy QLabelt hasznlunk. Alatta helyezkedik
el egy QPushButton tpus nyomgomb, amellyel elindthatjuk a szmtst
vgz szlat. Legalul egy msik QLabelt helyeznk el, ez kezdetben nem tar-
talmaz semmilyen szveget, az eredmnyt jelenti meg, amikor megtrtnt a
szmts.
8.9. bra. Tbbszl alkalmazs fablaka
511
8. fejezet: A Qt keretrendszer programozsa
Kezdjk a szmtst a vgz szl megrsval:
/* calculatorthread.h */
#i fndef CALCULATORTHREAD_H
#defineCALCULATORTHREAD_H
#include <QThread>
cl ass CalculatorThread : public QThread
{
Q_OBJECT
public:
explicit cal cul atorThread(Q0bject *parent =0) ;
void run() ;
si gnal s :
void resultcomputed(i nt resul t) ;
public slots:
void startcomputi ng(int a, int b) ;
}
;
#endif /7 CALCULATORTHREAD_H
A CalculatorThread osztly a QThreadbl szrmazik. Felldefiniljuk a run
metdust, amelyben a szl elindtsakor lefut logikt rjuk meg. A szl elin-
dtsa utn vrakozunk, amg a startComputing szlot meg nem hvdik. Te-
ht a run fggvnyben egyszeren csak elindtjuk az esemnykezel ciklust
az exec meghvsval. A startComputing fggvny kt int tpus argumentu-
ma adja meg, hogy milyen szmokon kell az sszeadst elvgezni. A szmts
vgeztvel a szl egy szignlt bocst ki, amely tartalmazza a mvelet ered-
mnyt. Ez a resultComputed szignl. A startComputing maga is egy szlot-
fggvny, gy egy szignl segtsgvel meg tudjuk hvni.
A connect fggvny bemutatsakor mr sz volt a vrakozsisor-alap sz-
szekttetsekrl. Ha a szignlt publikl s a szlotot definil objektumokat
kln szlban hoztuk ltre, akkor ez az alaprtelmezett sszekttets-tpus.
Ilyenkor a szignl kibocstsa utn a vezrls nem blokkoldik, aszinkron m-
don elkldjk a szignlrl az zenetet a msik szlban fut objektumnak.
sszefoglalva teht a szlosztly mkdst: elindtsa utn vrakozik az
esemnykezel ciklus, amg az osztly startComputing szlotjnak meghvs-
val nem indtunk el egy szmtst. A mvelet elvgzst a resultComputed
esemny kibocstsval jelezzk:
512
8.6. Tovbbi technolgik
/*calculatorthread.cpp*/
#include"calculatorthread.h"
CalculatorThread::CalculatorThread(Q0bj ect*parent):
QThread(parent){ }
v oidCalculatorThread::run(){
exec();
}
v oidCalculatorThread::startComputing(inta,intb)
intresult=a+b;
sleep(3 );//gy m rt ny leghosszmv elet
emitresultComputed(result);
}
Maga a szmts amelyet a startComputing fggvny valst meg a kt
paramterknt kapott szm sszeadst jelenti, ezutn az eredmnyt a
resultComputed szignlon keresztl kldjk el. Azrt, hogy a szmts val-
ban idignyes legyen, a QThread sleep fggvnyvel elaltatjuk 3 msodperc-
re a szlat, mieltt az eredmnyt visszakldennk. Erre a sleep fggvnyt
hasznljuk:
Az szlosztlyunk hasznlathoz ezt pldnyostani kell, bektni a megfelel
szignlokat s szlotokat, majd elindtani a start fggvnnyel, ezeket a fel-
hasznli fellet kdjnak trgyalsa utn vesszk sorra:
/*resultwindow.h*/
#ifndefRESULTWINDOw_H
#defineRESULTWINDOW_H
#include<QtGui>
classResultWindow:publicQWidget
{
Q_OBJECT
public:
explicitResultWindow(QWidget*parent=0);
signals:
v oidstartComputing(inta,intb);
publicslots:
v oidresultComputed(intresult);
priv ateslots:
v oidbuttonClick ed();
513
8.fej ezet:Atk eretrendszerprogramoz sa
priv ate:
QLabel*1blTask ;
QP ushwitton*btnCompute;
QLabel*1blResult;
QVBoxLay out*lay out;
} ;
#endif//RESULTWINDOW_H
A felhasznli felletet a ResultWindow osztly tartalmazza. Az osztly tag-
vltozi az a hrom vezrl, amelyet elhelyeznk a felleten, s egy QVBox-
Layout tpus elrendezskezel, amely fgglegesen egyms al igaztja ket.
A startComputing szignllal jelezzk majd, hogy szeretnnk, ha kt int
tpus szmon elvgeznnk a szmtsi mveletet. Ezt ktjk ssze a szlob-
jektum azonos nev szlotjval. Deklarlunk tovbb egy buttonClicked
szlotot is, ezzel kapunk rtestst majd a gomb megnyomsrl:
/*resultwindow.cpp*/
#include"resultwindow.h"
ResultWindow::Resultwindow(Qwidget*parent):
QWidget(parent)
{
lay out=newQv 8oxLay out;
1blTask =newQLabel("12 +13 =?");
lay out->addwidget(1b1Task );
btnCompute=newQP ushButton("Sz m t s");
lay out->addwidget(btnCompute);
1blResult=new ;
lay out->addwidget(lblResult);
this->setLay out(lay out);
connect(btnCompute,siGNAL(click ed()),
this,SLOT(buttonClick ed()));
v oidResultwindow::buttonclick ed()
emitstartcomputing(12 ,13 );
v oidResultwindow::resultComputed(intresult){
lblResult->setText(Qstring::number(result));
514
8.6. Tovbbi technolgik
A konstruktorban ltrehozzuk a vezrlket s az elrendezskezel objektu-
mot, majd a connect fggvnnyel sszekapcsoljuk a nyomgomb clicked szig-
nljt az osztlyban definilt buttonClicked szlottal.
A fellet megjelentse utn teht addig nem trtnik semmi, amg a
gombot meg nem nyomjuk, ekkor meghvdik a buttonClicked szlot, amelyben
kivltjuk a startComputing szignlt. Az argumentumai a felleten is kirt 12
s 13 szmok lesznek. Ezutn vrakozunk, amg a szmts elvgzse utn
meghvdik a resultComputed szlot, amelynek a paramtere tartalmazza az
eredmnyt. Ezt a QLabel osztly setText fggvnyvel rjuk ki a felletre. Mi-
vel a szmtst kln szlban vgeztk, gy a felhasznli fellet tovbbra is
mkdkpes marad, s reagl a felhasznli esemnyekre:
/*main.cpp*/
#include"calculatorthread.h"
#include"resultwindow.h"
#include<QtCore>
#include<QtGui>
intmain(intargc,char*argv [])
{
QApplicationapp(argc,argv );
Resultwindow*window=newResultWindow;
CalculatorThread*thread=newCalculatorThread;
QObj ect::connect(window,SIGNAL(startComputing(int,int)),
thread,SLOT(startComputing(int,int)));
QObj ect::connect(thread,sIGNAL(resultComputed(int)),window,
SLOT(resultComputed(int))):
thread->start();
window->show();
returnapp.exec();
}
A programunk main fggvnyben inicializlunk egy ResultWindow s egy
CalculatorThread pldnyt. A felhasznli fellet miatt ltrehozzuk a QAppli-
cation objektumot is, amely a fszl elindtsrt felels. Ezutn trtnik a
szignlok s a szlotok sszekapcsolsa. Vgl a szlat a start fggvnnyel in-
dtjuk el, az ablakot pedig a show metdussal jelentjk meg.
A Qt keretrendszer a szlak indtsn s a szignl-szlot mechanizmuson
tl is biztost szolgltatsokat tbbszl programok tmogatsra. A 8.4. tb-
lzatban lthat nhny fontosabb osztly, amelyek a szlak kztti szinkro-
nizcit segtik.
515
8. fejezet: A Qt keretrendszer programozsa
8.4. tblzat. Szlak kztti szinkronizcit tmogat osztlyok
QMutex Klcsns kizrst (mutex) megvalst zr.
QReadWriteLock Hasonl a mutexhez, de az objektumokhoz val hozz-
frs sorn megklnbzteti az rsi s az olvassi
szndkot.
QSemaphore Szemafort megvalst osztly.
QWaitCondition Lehetv teszi, egy felttel ltrehozst, ennek a be-
kvetkeztig egy szl vrakozik. A felttelt teljesl-
st ms szlakbl tudjuk engedlyezni.
Ezek a szinkronizcis osztlyok a QT-szint reprezentcii az 5. Prhuza-
mos programozs fejezetben trgyalt megoldsoknak.
8.6.2. Adatbziskezels
sszetettebb informcihalmazzal dolgoz alkalmazsokban az adatokat lta-
lban nem egyszer llomnyokba mentjk, hanem valamilyen adatbziskezel
rendszert hasznlunk a trolsukra. Az adatbzisok SQL nyelv programoz-
shoz szksges felletet a QtSql modul biztostja.
A modul lehetsget teremt a klnbz adatbziskezel rendszerek egy-
sges s platformfggetlen elrsre. A modulban definilt osztlyok kt cso-
portba oszthatk: az adatbziskezel-fgg vezrl- (driver) rteg osztlyai
biztostjk a kommunikcit a klnbz platformokhoz, mg az SQL prog-
ramozi interfsz (SQL API) osztlyai biztostjk az platformfggetlen
SQL-alap alkalmazsfejlesztst.
A modul elrshez a forrsfjljainkban be kell pteni a megfelel oszt-
lyokat, vagy a kvetkez sor segtsgvel egyszerre tudjuk bepteni a teljes
modult:
# ncl < QtSgl>
>

A modul hasznlatt tovbb a projektllomnyban is jelezni kell. Az albbi
sorral adhatjuk meg azt, hogy a fordts sorn a linker a QtSql knyvtrat is
vegye figyelembe:
QT += 541
Feladat rjunk alkalmazst, amely csatlakozik egy adatbzishoz, amelyben knyvek cmeit s
szerzit troljuk egy tblban. A csatlakozs utn rjuk ki az adatbzis tartalmt a konzolra.
516
8.6. Tovbbi technolgik
Ennek a pldnak az elksztsben bemutatjuk, hogyan kell kapcsoldni egy
adatbzishoz, hogyan tudunk SQL nyelv parancsokat kldeni a programun-
kon keresztl, s hogyan tudjuk egy lekrdezs eredmnyt programozottan
feldolgozni. A tovbbiakban egy MySQl-tpus adatbziskezelt hasznlunk,
amelyben azt felttelezzk, hogy egy qtDatabase nev adatbzisban troljuk
az adatokat. Az adatbzisban egyetlen tblt definiltunk, ebben knyveknek
az adatait (egyedi azonost, cm s szerz) troljuk. A tbla neve Book, az
oszlopai pedig a 8.5. tblzatban lthatk.
8.5. tblzat. qtDatabase adatbzis Book tbljnak oszlopai
Oszlop neve Tpusa Lersa
I d Int(11)
varchar(255)
A knyv azonostja (elsdleges kulcs)
Title A knyv cme
Author varchar(255) A knyv szerzje
A programunk egyetlen main fggvnybl ll, itt ptjk fel a kapcsolatot,
kldjk el a lekrdezst, s rjuk ki az eredmnyt a hibakeres konzolra:
/*main.cpp*/
#include<QtCore>
#include<iostream>
#include<QDebug>
#include<QtSql>
intmain()
{
QSq1Databasedb=QSq1Database::addDatabase("QMYSQL");
db.setHostName("localhost");
db.setpatabaseName("qtQatabase");
db.setuserName("dbUser");
db.setP assword("passw");
if(!db.open())
{
quebug()"Cannotconnecttodatabase...";
quebug()db.lastError();
return1;
QsqlQuery selectQuery ;
if(!selectQuery .exec("select

fromBook "))
{
cpebug()"Errorwithexecutingquery ";
517
8. fejezet: A Qt keretrendszer programozsa
whi le (sel ectQuery. next())
{
gtring title = selectQuery.val ue(1) toString();
QString author = selectQuery.val ue(2) .toString();
cpebug() author ": " title;
}
db. cl ose() ;
return 0;
}
Az adatbzis-elrshez hasznlt osztlyok bemutatsa eltt rdemes felhvni a
figyelmet arra, hogy a fenti main fggvnyben nem hoztunk ltre QApplication
objektumot, mivel itt nincsen szksgnk esemnykezel ciklusra: nem hasznl-
juk a szignl-szlot mechanizmust, s nem hasznlunk olyan osztlyokat, amelyek
ilyen ciklus megltt kvetelik.
Az adatbzishoz val hozzfrs lpsei minden alkalmazs esetben a
kvetkezk:
1. Felptjk a kapcsolatot: ehhez szksg van az adatbzis cmre s a
belpsi adatokra.
2 . Elkldnk az adatbzisnak egy SQL nyelv utastst.
3. Feldolgozzuk az utasts eredmnyt. Ha az utasts egy lekrdezs,
akkor annak visszatrsi eredmnyt soronknt tudjuk bejrni s fel-
dolgozni. Egyb esetben a visszatrsi rtk egy skalr.
4 . Lezrjuk az adatbziskapcsolatot.
Az adatbzishoz val hozzfrs mindig a kapcsolat felptsvel kezddik,
ezt egy QSq1Database pldnnyal rjuk le. Egy program fejlesztse sorn tbb
klnbz adatbziskapcsolatra is szksg lehet, gy tbb pldnyt is ltre-
hozhatunk, mindegyiket egyedi nvvel azonostjuk. Lehetsg van egy alapr-
telmezett kapcsolatot is ltrehozni az alkalmazson bell, ennek nem adunk
meg nevet, ez trtnik a pldaalkalmazsban is. A tovbbiakban hasznlt
fggvnyek nagy rszre igaz, hogy opcionlis paramterknt vrjk az adat-
bziskapcsolat nevt, ha ezt nem adjuk meg, akkor az alaprtelmezett kap-
csolatot hasznljk.
Minden kapcsolat ltrehozsnl meg kell adni az adatbzis tpust, ez
alapjn a Qt keretrendszer a tovbbiakban a megfelel vezrlt hasznlja
a kommunikcira. A fenti pldban a db vltoz lesz az alaprtelmezett kap-
csolat, amelyet a QSq1Database osztly statikus addDatabase fggvnyvel
hozhatunk ltre. Ez a fggvny egyben el is trolja a ltrehozott adatbzis-
kapcsolatokat egy bels listban:
518
8.6. Tovbbi technolgik
QSg1DatabaseQSg1Database::addDatabase(
constQString& t y p e ,
constQString& conne ct i onName =
QLatin1String(defaultConnection))
A fggvny msodik, opcionlis paramtere az adatbzis-kapcsolat neve.
A QMYSQL" szveg azt jelzi, hogy egy MySQL-tpus adatbzishoz akarunk
csatlakozni. Az 8.6. tblzatban olvashat nhny olyan vezrlnv, amellyel
tovbbi adatbziskezel rendszerekhez frhetnk hozz.
8.6. tblzat. A Qt keretrendszer adatbziskezel vezrlinek azonosti
Vezrlnv Adatbziskezel rendszer
QDB2 IBM DB2
QSQLITE SQLite (3-as verzi)
QSQLITE2 SQLite (2-es verzi)
QOCI Oracle Call Interface Driver
QPSQL PostgreSQL
QODBC ODBC-(Open Database Connectivity) kompatibilis adatbzis-
kezelk, pldul Microsoft SQL Server
Az adatbzis-kapcsolat pldnynak inicializlsa utn meg kell adnunk a
kapcsolds paramtereit, ezek az adatbzisszerver cme, az adatbzis neve,
illetve a felhasznl neve s jelszava. A fenti pldban az adatbzisszerver az
alkalmazssal egy gpen fut, ezrt a cme localhost.
Ahhoz, hogy a kapcsolat valban fel is pljn, meg kell hvni a kapcsolat
open fggvnyt, amelynek bool tpus visszatrsi rtke jelzi, hogy sikeres
volt-e a kapcsolds. Ha hiba trtnt, akkor arrl tovbbi informcit a QSql-
Database statikus lastError fggvnyvel krhetnk le:
QSglErrorQSg1Database::lastError()const
A QtSql modul tbbi osztlynl is ltalban ilyen mdszerrel lehet megtudni
az elfordul hibk pontos adatait. A fggvnyek tbbnyire csak azt jelzik,
hogy hiba trtnt, amelyet a lastError fggvnnyel lekrdezhetnk.
Ha a program sorn egy adatbzis-kapcsolatra mr nincsen szksgnk,
akkor eltvolthatjuk a listbl a QSqlDatabase statikus removeDatabase
fggvnyvel. Eltte azonban be kell zrni a kapcsolatot a close fggvnnyel.
A fenti pldban a felhasznl szmra megjelentend adatokat a hiba-
keres konzolra rjuk, amelyet a QDebug osztllyal rnk el. Ez az osztly
egy kimeneti adatfolyamot (output stream) biztost, amelyre a C++-ban meg-
szokott opertor segtsgvel tudunk adatokat kldeni. ltalban ezt az osz-
tlyt nem kell explicit mdon pldnyostani, elg, ha meghvjuk a qDebug()
fggvnyt, amely egy alaprtelmezett pldnnyal tr vissza.
519
8. fejezet: A Qt keretrendszer programozsa
A kapcsolat sikeres felptse utn lehetsgnk van SQL nyelv utast-
sokat kldeni az adatbzisnak. Egy SQL-parancsot a QSqlQuery osztllyal
rhatunk le, amelynek meg kell adni a parancs szvegt. A korbbiaknak
megfelelen, opcionlisan megadhat az adatbzis-kapcsolat is. Az utasts
tpustl fggetlenl az exec fggvnnyel tudjuk ezt lefuttatni:
bool QSql Query : : exec ( const QString & query )
bool QSql Query : :exec ()
Mind a konstruktornak, mind az exec fggvnynek tbbfle paramterezse
ltezik, az SQL-parancsot megadhatjuk a konstruktorban vagy az exec fgg-
vny argumentumn keresztl is. Az open fggvnyhez hasonlan ennek is a
bool tpus visszatrsi rtke jelzi, hogy trtnt-e hiba, ha igen, akkor annak
rszleteit a korbban ismertetett mdszerrel tudhatjuk meg.
Ha olyan utastst adunk ki, amelynek az eredmnye nem lekrdezs
(pldul insert utasts), akkor ezutn tbb feladatunk nincsen. A pldnk-
ban szerepl parancs azonban egy lekrdezs, eredmnye a Book tblban t-
rolt sszes sor. A QSqlQuery osztly segtsgvel a lekrdezs eredmnyt
soronknt tudjuk feldolgozni. Az eredmnyhez gy frnk hozz, mintha egy
virtulis kurzorunk (itertorunk) lenne, amellyel szekvencilisan haladha-
tunk az eredmny sorain. A kurzort tovbblptethetjk a next fggvnnyel,
illetve a kurzor ltal mutatott sornak lekrdezhetjk az adatait. A next fgg-
vny visszatrsi rtke bool tpus, minden lptets utn jelzi, hogy volt-e
tovbbi sor az eredmnyben. A kurzor kezdetben nem az els sorra mutat,
ahhoz, hogy a lekrdezs els sorhoz hozzfrjnk, eltte ugyangy meg kell
hvni a next fggvnyt, mint a ksbbiekben egy jabb sorhoz val ugrsnl.
Ha a lekrdezs eredmnye egyetlen sort sem tartalmaz, akkor mr az els
hvsnl false lesz a visszatrsi rtk. Annak a sornak az adatait, amelyre
ppen a kurzor mutat, a value fggvnnyel krdezhetjk le:
QVariant QSqlQuery: :val ue ( int index ) const
A fggvny egyetlen paramtere a sor egy oszlopnak indexe, visszatrsi rt-
ke pedig egy QVariant tpus objektum. A QVariant segtsgvel egysgesen
tudjuk trolni egy cella tartalmt annak tpustl fggetlenl. A QVariant tag-
fggvnyeivel a trolt adatot a megfelel Qt tpusra lehet konvertlni.
Az aktulis adat tpust a type fggvnnyel le is krdezhetjk:
Type QVari ant: :type () const
A visszatrsi rtk QVariant::Type felsorols tpus, ebben a lehetsges
adatbzistbla-tpusok vannak felsorolva. A konvertlshoz toT formj
fggvnyeket kell hasznlni, ahol T helyre a megfelel tpus azonostjt
kell behelyettesteni. Erre plda a fenti kdban lthat toString fggvny,
amely az adott rtket QString tpusv alaktva adja vissza. Ha olyan tpus-
520
8.6. Tovbbi technolgik
ra prblnnk talaktani a cella tartalmt, amilyenre nem lehet, akkor az
adott tpustl fgg, hogy mi lesz a fggvnyhvs eredmnye. Termszetesen
lehetsg van ellenrizni is mg az talakts eltt, hogy talakthat-e az
adat a megfelel tpusra, ehhez hasznlhatjuk a canConvert fggvnyt:
bool QVariant::canConv ert(Ty pet)const
A 8.7. tblzatban nhnyat sorolunk fel a tpusok lehetsges rtkei kzl,
s jelezzk, hogy milyen Qt-osztlytpusra lehet az adott rtket talaktani.
8.7. tblzat. A QVariant osztlyban trolhat legfontosabb adattpusok
Konstans Adattpus Lers
QVariant::Inoalid hibs adat nincs tpus
QVariant::Bitmap QBitmap kp
QVariant::Bool bool logikai igaz/hamis rtk
QVariant::Date QDate dtum
QVariant::Daterime QDateTime dtum s idpont
QVariant::Time QTime idpont
QVariant::String QString szveg
QVariant::Int int egsz szm
A pldban az 1-es s a 2 -es index, azaz a msodik s a harmadik oszlop tar-
talmt alaktjuk t QString tpusra minden egyes sorban, s ezeket rjuk ki
a felhasznlnak. Az els oszlop az azonostt tartalmazza, erre itt nincsen
szksg.
A program vgn lezrjuk az adatbzis-kapcsolatot a close metdussal. Ter-
mszetesen a kapcsolat ltrehozsa utn tbb SQL-utastst is vgrehajthattunk
volna, nem kell minden egyes parancshoz jabb kapcsolatot inicializlni.
8.6.3. Hlzati kommunikci
Hlzati kommunikci programozsra is sajt osztlyknyvtrat biztost a
Qt keretrendszer, ezeket a QtNetwork modulban tallhatjuk sszegyjtve.
Segtsgkkel TCP/IP alap kliens-, illetve szerveralkalmazsokat kszthe-
tnk. A modul biztost nhny alacsony szint kommunikcit megvalst
osztlyt (pldul QTcpSocket, QUdpSocket, QTcpServer), illetve nhny ezek-
re pl alkalmazsrtegbeli protokollt egysgbe zr osztlyt (pldul http
s ftp kommunikci hasznlatra) is. A magasabb szint kommunikci is
termszetesen az alacsonyabb szint programozi interfszre pl, ezrt az
albbiakban ez utbbinak a hasznlatt trgyaljuk rszletesen.
521
8. fejezet: A Qt keretrendszer programozsa
A Qt keretrendszerben a hlzati programozs koncepcija alapveten
megegyezik a korbban bemutatott mdszerekvel. Az alaposztlyok a QTcp-
Socket, illetve a QUdpSocket, amelyek ahogyan a nevk is mutatja socke-
teket rnak le. Mind a szerver-, mind a kliensoldalon egy-egy socketosztlyon
keresztl trtnik az adatok rsa s olvassa. A knnyebbsg a Qt keretrend-
szer hasznlatban a korbbi megoldssal szemben elszr is a TCP-kapcsolat
szerveroldali programozsban rezhet: a QTcpServer osztly nagyban egy-
szersti a szerveroldali kapcsolat kiptst. Ez rja a le azt a szerverszolglta-
tst, amely egy adott cmen s porton vrja a berkez kapcsolatokat. Amikor
egy j kapcsoldsi krelem rkezik, akkor felpt egy QTcpSocketet. A mso-
dik knnyebbsg az, hogy a mr megszokott mdon, a szignl-szlot mecha-
nizmus segtsgvel kapunk rtestst minden olyan esemnyrl, amely a
socketeken trtnik. gy a hlzati programozs sorn valjban ltre kell
hozni a megfelel objektumokat, ezekban belltani a megfelel hlzati c-
meket, majd azokra az esemnyekre, amelyeket az alkalmazsunkban kezel-
ni szeretnnk, szlotfggvnyekkel kell feliratkoznunk.
A hlzatkezel modul hasznlathoz a projektllomnyt ki kell egszte-
nnk az albbi sorral. Ezzel jelezzk, hogy a linker a hlzati modul osztly-
knyvtrt is hasznlja:
QT += network
Ebben a fejezetben a TCP-csomagokkal trtn kommunikcit trgyaljuk
rszletesen, az UDP-alap kommunikci ehhez hasonl mdon trtnik.
Feladat rjunk egy egyszer csevegalkalmazst. A szerveroldali program tudjon klienseket
fogadni, s amennyiben egy kliens zenetet kld, azt tovbbtsa az sszes tbbi csatlakozott
kliensnek. A kliensalkalmazsnak legyen grafikus felhasznli fellete, s jelentse meg az sz-
szes berkezett s elkldtt zenetet.
Elszr a szerveralkalmazst rjuk meg. Mivel a QTcpSocketnek a szignljai-
ra kell feliratkozni, ehhez szksg lesz egy szlotokat definil osztlyra. Erre
szolgl a ChatServer osztly, amely a teljes alkalmazslogikt trolja, s a
szignl-szlot mechanizmus miatt a QObjectbl szrmazik:
/* chatserver.h */
#ifndef CHATSERVER_H
#define CHATSERVER_H
#include <QtCore>
#include <QtNetwork/QTcpServer>
class chatserver : public Q0bject
{
Q_OBJECT
522
8.6.Tov bbitechnolgi k
public:
explicitChatServ er(Q0bj ect*parent 0);
publicslots:
v oidnewConnection();
v oidtextReceiv ed();
priv ate:
QTcpServ er*tcpServ er;
QList<QTcpsock et*>*clientsock ets;
} ;
#endif//CHATSERVER_H
Az osztlynak kt privt tagvltozja van, egy QTcpServer s egy lista, amely
a QTcpSocketek mutatjt trolja. A QTcpServer felels a TCP-szerver ltre-
hozsrt, a listban pedig a csatlakozott kliensekkel kiptett socketeket
troljuk. Minden, a szerverre rkezett zenet esetben kirjuk a kliens sor-
szmt s magt az zenetet. A szerveralkalmazs nem grafikus, a konzolra
rja ki az zeneteket.
Az osztly kt szlotfggvnyt is tartalmaz. A newConnection segtsgvel
kapunk rtestst arrl, hogy egy kliens megprblt csatlakozni, a textReceived
szlottal pedig arrl, hogy egy klienstl adat rkezett:
/*chatserv er.cpp*/
#include"chatserv er.h"
#include<QtNetwork /QTcpServ er>
#include<QtNetwork /QTcpSock et>
#include<QDebug>
#include<QtCore>
ChatServ er::ChatServ er(Q0bj ect*parent):
QObj ect(parent)
{
tcpServ er=newQTcpServ er();
this->clientSock ets=newQList<QTcpSock et*>();
connect(tcpserv er,SIGNAL(newConnection()),this,
SLOT(newConnection()));
if(tcpServ er->listen(QHostAddress::Any ,993 5)){
dDebug()"Aszerv eralk almaz selindult...";
}
}
v oidChatServ er::newConnection(){
QTcpSock et*sock et=tcpServ er->nextP endingConnection();
clientSock ets->append(sock et);
connect(sock et,SIGNAL(ready Read()),this,
SLOT(textReceiv ed()));
cffiebug()"k liens["this->clientSock ets->size()-1"]
csatlak ozott";
}
523
8. fejezet: AQt keretrendszer programozsa
v oidChatServ er::textReceiv ed(){
QTcpSock et*sock et=(QTcpSock et*)sender();
intindex=this->clientsock ets->index0f(sock et);
QStringmessage=
"["%QString::number(index)%"]:"%sock et->readAll();
qDebug()message;
QListIterator<QTcpsock et*>iterator(*clientsock ets);
while(iterator.hasNext())
{
QTcpSock et*client=iterator.next();
if(client!=sock et)
{
client->write(message.toLatinl());
A szerverosztly implementcija a konstruktort s a kt szlotfggvnyt tar-
talmazza. A konstruktorban inicializljuk a szervert, s feliratkozunk ennek
newConnection szignljra, ez jelzi, ha csatlakozsi krs rkezett.
A listen fggvnnyel megadjuk, hogy a szerver egy adott cmen s portsz-
mon figyelje a berkez krseket. A fggvny nem blokkoldik, rgtn visz-
szatr. Ha valamilyen esemny trtnik, arrl a megfelel szignllal kapunk
rtestst:
bool QTcpServer : :1 i sten (
constQHostAddress&ad d re s s = QHostAddress::Any ,
quintl6p ort = 0)
A cmet a QHostAddress osztllyal rhatjuk le. A QHostAddress::Any egy
olyan konstans, amely jelzi, hogy a szerver az sszes hlzati interfszen fi-
gyel. A fenti pldban a portszmot is megadjuk, de tadhatunk 0-t is a m-
sodik paramternek, ilyenkor a szerverhez egy vletlen portszmot rendel
a rendszer. A listen fggvny visszatrsi rtke jelzi, hogy sikeres volt-e a
szerver indtsa.
A ChatServer osztly pldnyostsa utn teht elindul a szerver, s vrja
a berkez csatlakozsi krelmeket Amikor a kliens megprbl csatlakozni,
akkor a QTcpServer pldny kibocstja a newConnection szignlt, amelyre az
azonos nev szlotfggvnnyel iratkoztunk fel. Ebben a fggvnyben elszr
lekrdezzk az j kapcsolathoz tartoz QTcpSocket pldnyt a nextPending-
Connection fggvny segtsgvel, ezt a pldnyt pedig eltroljuk a client-
Sockets listban. Mivel a QTcpSocket most jtt ltre, ezrt itt kell feliratkozni
a readyRead szignljra, hogy rtestst kapjunk, amikor j olvashat adat
rkezik. Erre a textReceived szlotfggvnyt hasznljuk. Teht, amikor a kli-
ens adatot kld a szervernek, akkor a textReceived fggvny hvdik meg, eb-
ben egyszeren kirjuk a konzolra az rkezett adatot.
524
8.6.Tov bbitechnolgi k
Az els nehzsg, amely el'kerl a textReceived implementlsakor, az az,
hogy hogyan tudjuk meg, hogy melyik klienstl rkezett az adat, ugyanis az
sszes klienshez tartoz QTcpSocketnek a readyRead szignljra ugyanazzal
a fggvnnyel iratkozunk fel. A megolds a mr korbban bemutatott sender
fggvny. Ennek a segtsgvel kapunk pointert az adott klienshez tartoz
QTcpSocketre. A pldnkban a kliens sorszma a hozztartoz socketnek a
clientSockets listban eltrolt sorszma lesz.
A QTcpSocket osztlytl a kvetkez fggvnnyel tudjuk lekrdezni a kli-
enstl rkezett adatot:
QBy teArray QI0Dev ice::readAll()
Az aktulis zenet kiolvassa utn az adott szveget elkldjk az sszes csat-
lakozott kliensnek, kivve termszetesen az zenet kldjt. Erre szolgl a
fggvny vgn tallhat ciklus. A QTcpSocket readAll metdusval olvastuk
ki az adatokat, a write metdussal pedig el tudunk kldeni egy szveget. En-
nek a fggvnynek tbbfle paramterezse ltezik, a pldban a const char *
paramtert hasznljuk, amely a paramterknt tadott szvegkonstansot
kldi el a hlzaton keresztl:
qint64QI0Dev ice::write(constchar*data)
Vgezetl megmutatjuk a main.cpp forrsllomnyt, amelyben a Qt keretrend-
szer inicializlsn kvl mindssze a ChatServer osztlyt pldnyostjuk,
ugyanis ennek a konstruktorban a szerver is ltrejn. Mivel az alkalmazs
nem rendelkezik grafikus fellettel, viszont esemnykezelsre szksgnk
van, a QApplication helyett a QCoreApplication osztlyt pldnyostjuk:
/*main.cpp*/
#include<QtCore>
#include<QtNetwork /QTcpServ er>
#include<chatserv er.h>
intmain(intargc,char*argv [])
{
QCoreApplicationa(argc,argv );
ChatServ er*serv er=newChatServ er();
returna.exec();
}
A kvetkez feladat a kliensalkalmazs elksztse. Ebben nem kell QTcp-
Server objektumot inicializlni, mindssze egy QTcpSocket pldnyt kell lt-
rehozni, amelyet a megfelel cm megadsval a csatlakoztatunk szerverhez.
A kliensalkalmazs mr grafikus felhasznli fellettel rendelkezik, ez a
8.10. brn lthat. A fels csak olvashat szvegdoboz tartalmazza az ed-
dig elkldtt szvegeket, illetve a legels sorban van egy zenetet, amely azt
52 5
8.fej ezet:AQtk eretrendszerprogramoz sa
jelzi, hogy sikerlt-e felpteni a kapcsolatot a szerverrel, tovbb kirja az ed-
dig elkldtt zeneteket is. Alul lthat egy msik szvegdoboz, amelybe az el-
kldend zenetet lehet begpelni, mellette pedig egy gomb, amellyel el is lehet
kldeni. Amg a kapcsolds nem jrt sikerrel, a szvegdobozba nem lehet rni.
Uzenet: Klds
8.10. bra. Cseveg kliensalkalmazsnak kpernykpe
/*chatclientwindow.h*/
#ifndefCHATCLIENTWINDOW_H
#defineCHATCLIENTWINDOW_H
#include<Qwidget>
#include<QtGui>
#include<QtNetwork >
classChatC1ientWindow:publicQwidget
{
Q_OBJECT
public:
explicitChatClientwindow(Qwidget*parent=0);
publicslots:
v oidsendText();
v oidhostConnected();
v oidsock etReady Read();
priv ate:
Qv BoxLay out*v Lay out;
QHBoxLay out hLay out;
QTextEdit*txtChatHistory ;
QLineEdit*txtInput;
QLabel * 1b1Text;
QP ushButton*btnSend;
wrcpsocket * sock et;
#endif//CHATCLIENTWINDOW_H
526
8.6. Tovbbi technolgik
A chatclientwindow.h llomny tartalmazza a ChatClientWindow osztly
deklarcijt. A QWidgetbl szrmaz osztlynak a korbban bemutatott ve-
zrlknek megfelel tagvltozi vannak. Lthat tovbb, hogy kt elrende-
zssegt osztlypldny is szerepel: a QHBoxLayout segtsgvel a Szveg"
szveget, a szvegbeviteli dobozt s a nyomgombot helyezzk el egyms mel-
l, a QVBoxLayout pedig a korbbi zeneteket tartalmaz dobozt igaztja az
elbbi vzszintes tartalom fl. Szintn tagvltozknt definilunk egy QTcp-
Socketet (ennek a funkcijt lsd korbban).
A konstruktoron kvl hrom szlotfggvnyt definilunk. A hostConnected
fggvnnyel kapunk majd rtestst arrl, hogy sikerlt-e a csatlakozs a
szerverhez. A sendText szlotot a nyomgomb megnyomsakor kibocstott
szignl aktivlja, jelezve ezzel, hogy a begpelt adatot kldjk el a szerver-
nek. Vgl a socketReadyRead szlottal iratkozunk fel arra a szignlra, amely
j zenet rkezsekor jelez:
/*chatclientwindow.cpp*/
#include"chatclientwindow.h"
ChatClientwindow::ChatclientWindow(QWidget*parent):
Qwidget(parent)
{
v Lay out=newQVBoxLay out;
this->setLay out(v Lay out);
txtChatHistory =newQTextEdit;
txtChatHistory ->setReadOnly (true);
v Lay out->addwidget(txtChatHistory );
hLay out=newQHBoxLay out;
lblText=newQLabel;
lblText->setText("zenet:");
hLay out->addWidget(lblText);
txtlnput=newQLineEdit;
hLay out->addwidget(txtlnput);
btnSend=newQP ushButton;
btnSend->setText("Rld s");
connect(btnSend,SIGNAL(click ed()),this,SLOT(sendText()));
hLay out->addWidget(btnSend);
v Lay out->addLay out(hLay out);
txtChatHistory ->append("Szerv erk apcsolatm gnem pltfel.");
txtInput->setoisabled(true);
527
8. fejezet: A Qt keretrendszer programozsa
sock et=newQTcpSock et();
connect(sock et,SIGNAL(connected()),this,
SLOT(hostConnected()))
connect(sock et,SIGNAL(ready Read()),this,
SLOT(sock etReady Read()));
sock et->connectToHost("localhost",993 5);
v oidChatClientWindow:sendText()
QStringtext=txtInput->text();
txtinput->clear();
txtChatHistory ->append(
QTimecurrentTime()toString %" n:
sock et->write(text.toLatinl());
sock et->flush();
1 1
%text);
v o dChatClientwindow::hostConnected(){
txtChatHistory ->clear();
txtChatHistory ->append("Szerv erk apcsolatfel p tv e");
txtInput->setEnabled(true);
v oidChatClientWindow::sock etReady Read(){
QStringmessage(sock et->readAll());
txtchatHistory ->append(
QTime::currentTime().toString()%""%message);
Az implementcis llomny a konstruktorral kezddik. Elszr a felleten
elhelyezett vezrlket s az elrendezskezel objektumokat inicializljuk a
korbban mr ismertetett mdon. Mivel a fenti szvegdoboz tbbsoros, ezrt
azt a QTextEdit vezrlvel hozzuk ltre, mg a lentebbi, egysoros szvegdoboz
a QLineEdit osztly pldnya. A ltrehozott vezrlknek nhny tulajdons-
gt mdostjuk. A QTextEdit osztly setReadOnly metdusval csak olvasha-
tv tesszk a fels szvegdobozt, illetve az append fggvnnyel egy jabb
szveget adunk hozz a doboz eddigi tartalmhoz. A QLineEdit setDisabled
fggvnyvel nem engedlyezett llapotba helyezzk a lenti szvegdobozt, ezzel
jelezve, hogy nem lehet bele rni, amg a kapcsolat ltre nem jtt. A QPush-
Button tpus gomb szvegt a setText fggvnnyel lltjuk be, ugyanitt be-
ktjk a sendText szlotot a gomb clicked szignljhoz.
A konstruktor msodik fele a hlzati kapcsolat felptst vgzi el.
A QTcpSocket ltrehozsa utn sszektjk ennek a connected szignljt a sa-
jt osztlyunk hostConnected szlotfggvnyvel, majd a connectToHost fgg-
vnnyel megprblunk csatlakozni a szerverhez. Az utbbi fggvny els
paramtere a szerver cme, a msodik pedig a portszma. Mg a csatlakozs
eltt feliratkozunk a szerversocket egy msik szignljra, a readyReadre is.
Ez a szignl jelzi, hogy j adat rkezett (lsd a szerveralkalmazsnl).
528
8.6. Tovbbi technolgik
Amikor teht a fenti ablakot inicializljuk, s lefut a konstruktor, akkor el-
helyezzk a vezrlket, s a fenti szvegdobozban megjelenik egy szveg, amely
szerint a hlzati kapcsolatot mg nem sikerlt felpteni, majd megprblunk
csatlakozni a szerverhez. Ha sikerlt, akkor automatikusan meghvdik
a hostConnected szlot. Ebben a fggvnyben mdostjuk a felhasznli felle-
tet, a fels szvegdobozba kirjuk, hogy a kapcsolat most mr ltrejtt, illetve
a lenti szvegdobozt is engedlyezzk a setEnabled fggvnnyel.
A tovbbi teendk a felhasznlra vrnak. Miutn bert egy szveget az al-
s szvegdobozba, meg kell nyomnia a kldsgombot, ennek hatsra a send-
Text szlot hvdik meg. Ebben elszr kiolvassuk a szvegdoboz tartalmt, majd
ezt az aktulis idponttal egytt kirjuk a fels szvegdobozba, tovbb a mr
korbban emltett write fggvnnyel elkldjk a hlzaton keresztl a szve-
get. A flush fggvny meghvsval biztostjuk, hogy a QTcp Socket buffer-
nek a tartalmt azonnal elkldjk.
Amikor j zenet rkezik a szervertl, a socketReadyRead szlotfggvny
hvdik meg, ebben kiolvassuk az j zenetet, majd kirjuk a szvegdobozba.
A teljessg kedvrt a kliensalkalmazs main fggvnyt is bemutatjuk:
/*main.cpp*/
#include<QtGui>
#include"chatclientwindow.h"
intmain(intargc,char*argv [])
{
QApplicationapp(argc,argv );
ChatClientWindow*client=newChatClientWindow;
client->show();
returnapp.exec();
}
A main.cpp llomnyban inicializljuk az alkalmazsobjektumot s a Chat-
ClientWindow osztlyunkat, majd megjelentjk az utbbit. Innen maga a
widget felels a hlzati kommunikcirt.
52 9
8. fejezet: A Qt keretrendszer programozsa
8.7. sszefogla l s
Ebben a fejezetben bemutattuk a Qt keretrendszer legfontosabb technolgi-
it, s ismertettk nhny fontos osztlyt. A Qt keretrendszer grafikus felle-
tek programozsa mellett nagyban tmogatja a legklnbzbb konzolos
alkalmazsok fejlesztst, tovbb knnyen megvalsthat az alacsony s
magasabb szint alkalmazsok kztti kommunikci.
Bemutattuk a Qt szignl-szlot mechanizmust, dialgusablakok, sszetett
alkalmazsablakok s sajt vezrl'k ksztsnek a mdszereit. A dokumen-
tum/nzet architektrban lthattuk, hogyan lehet sszetett alkalmazsok-
nl is kzben tartani a program mkdsnek tlthatsgt a klnbz
komponensek szerepeinek sztvlasztsval. Vgl a Qt keretrendszer rszt
kpez nhny fontos technolgit, a tbbszl programozst, az adatbzis-
elrst s a hlzatkezelst trgyaltuk.
A Qt keretrendszer azonban nemcsak egy alkalmazsprogramozi knyv-
trbl ll, hanem egy teljes szoftvercsomagbl, amely nagyban egyszersti
nemcsak a grafikus felhasznl fellettel rendelkez, de a konzolos vagy be-
gyazott alkalmazsok fejlesztst egyarnt.
A knyv rsnak idpontjban a Qt keretrendszerhez ajnlott els szm
fejleszteszkz a QtCreator, amely egy ingyenes, platformfggetlen integrlt
fejleszti krnyezet s a Qt keretrendszer rsze. A QtCreator tbbek kztt a
kvetkez eszkzket biztostja a fejlesztshez:
Forrskdszerkeszt funkcik tbbek kztt C++ s Javascript nyel-
vekhez automatikus kdkiegsztssel.
Teljes projektmenedzsment rendszer, amely automatikusan kezeli a
.pro projektfjlokat, gy ezeket nem szksges kzzel szerkeszteni.
A projekteket automatikusan fordtja s futtatja.
Szoros integrci verzikezel rendszerekkel.
A krnyezet rsze a Qt Designer, amely egy grafikus felhasznli fel-
lettervez alkalmazs. A felleten keresztl megtervezhetjk az
alkalmazsunk kinzett, elhelyezhetjk a vezrlket, elrendezs-
objektumokat hozhatunk ltre. Tovbb lehetsg van szintn a fel-
leten keresztl az egyes vezrl'k ltal definilt szignlok s szlotok
sszekapacsolsra. gy egyetlen programsor rsa nlkl is megal-
kothatjuk a felhasznli fellet s az esemnykezels vzt. A kiala-
ktott fellet lerst egy .ui kiterjeszts xml llomnyban trolja a
rendszer, amelybl automatikusan generlja egy annak megfelel osz-
tly kdjt, gy ezt utna felhasznlhatjuk az alkalmazsunkban
A QtLinguist program segtsgvel egy grafikus felleten tudjuk szer-
keszteni a .ts kiterjeszts xml llomnyainkat, amelyek az alkalma-
zsaink lokalizlt szvegeit troljk.
530
8.7. sszefoglals
A QtCreator rsze egy QML szerkeszt is. A QML (Qt Markup Language)
egy jauctscipt alap nyelv, amelynek a segtsgvel deklaratvan lehet
lerni a felhasznli felleteket. A QML rsze a QtQuick keretrend-
szernek, amely kpes az gy lert felletet futtatni. A QML nyelv bemu-
tatsa meghaladja ennek a knyvnek a kereteit, de fontos megemlteni,
mert egyre elterjedtebb mdszer a Qt-alap fejlesztsekben.
A fent felsorolt funkcik, a platformfggetlen fejleszt'krnyezet s a keret-
rendszer azon kpessge, hogy a mobileszkzktl a begyazott rendszereken
t az asztali szmtgpekig nagyon sok opercis rendszeren mkdik, a Qt-t
az egyik legsokoldalbb alkalmazsplatformm teszik.
531
A FGGELK
Fejleszteszkzk
Linux alatt a fejleszteszkzk szles vlasztka ll rendelkezsnkre. Ezek-
bl kivlaszthatjuk a neknk megfelelt, m nhny fontos eszkzt minden-
kinek ismernie kell.
A Linux-disztribcik szmtalan megbzhat fejleszteszkzt tartalmaznak,
amelyek fknt a Unix rendszerekben korbban elterjedt eszkzknek felelnek
meg. Ezek az eszkzk nem rendelkeznek bartsgos fellettel, a legtbbjk pa-
rancssoros, felhasznli fellet nlkl. m sok ven keresztl bizonytottk
megbzhatsgukat, hasznlhatsgukat. Szmos j felhasznlbart program a
httrben tovbbra is ezeket a parancssoros eszkzket hasznlja.
A.1. Szvegszerkesztk
A Linuxhoz is tallhatunk tbb integrlt fejleszti krnyezetet (Integrated De-
velopment Environment, IDE), m tovbbra is gyakran hasznlunk egyszer
szvegszerkesztket. Sok Unix-fejleszt tovbbra is ragaszkodik ezekhez a ke-
vsb bartsgos, de a feladathoz sokszor tkletesen elegend eszkzkhz.
A Linux trtnete sorn az albbi eszkzk terjedtek el.
A.1 .1 . Emacs
Az eredeti Emacs programot Richard Stallman (az FSF alaptja) ksztette.
vekig a GNU Emacs volt a legnpszerbb vltozat. Ksbb elterjedt a grafi-
kus krnyezethez ksztett XEmacs.
A felhasznli fellete nem olyan feltn, mint sok ms rendszernl, m
szmos, a fejlesztk szmra jl hasznlhat funkcival rendelkezik. Ilyen
pldul a szintaxis-ellenrzs. Ha a fordtt hozzillesztjk, kpes annak hi-
bazeneteit rtelmezni s a hibkat megmutatni. Lehetv teszi tovbb a
hibajavt program krnyezetbe val integrlst is.
A fggelk: Fejleszteszkzk
A.1.2. vi (vim)
A vi egy egyszer szvegszerkeszt. Kezelst leginkbb a gpelni tudk ig-
nyeihez alaktottk. A parancskszlett gy lltottk ssze, hogy a lehet
legkevesebb kzmozgssal lehessen hasznlni. Tapasztalatlan felhasznl
szmra azonban a kezelse meglehetsen bonyolult lehet, ezrt npszers-
ge ersen megcsappant. Elsznt Linux/Unix felhasznlk szoktk alkalmazni.
A.1.3. nano (pico)
A nano s az eldje a pico egyszer kperny-orientlt szvegszerkeszt. lta-
lban minden Linux rendszeren megtallhat. Elterjedten hasznljk a ki-
sebb szvegek gyors mdostsra a terminlbl. Komolyabb feladatokra nem
ajnlhat. Ezekben az esetekben alkalmasabb a kvetkez rszben trgyalt
joe
vagy egy, a feladatnak megfelelen specializlt szerkeszt.
A program parancsai folyamatosan lthatk a kperny aljn. A ^ jel azt
jelenti, hogy a billentyt a Ctrl gomb nyomva tartsa mellett kell hasznlni.
Ha ez esetleg a terminl tpusa miatt nem mkdne, akkor az ESC gomb kt-
szeri megnyomst is alkalmazhatjuk helyette.
A.1.4. joe
A joe a nannl fejlettebb s nagyobb, szintn szveges terminlban hasznl-
hat szvegszerkeszt. Komolyabb feladatokra is alkalmas a magasabb szint
szolgltatsai rvn. Egyszerre tbb llomnyt is megnyithatunk vele kln-
bz opcikkal. Az llomnyokat a kiterjesztsk alapjn felismeri, s auto-
matikusan szintaxiskiemelssel segti a munkt.
Komolysgt a parancsok szmbl is lthatjuk, amelyet a <ctrl>-k-h
gombokkal hozhatunk el s tntethetnk el A jellsekben a ^" jel azt je-
lenti, hogy a billentyket a Ctrl gomb nyomva tartsa mellett kell hasznlni
A.1.5. mc
A Midnight Commander, rviden mc elterjedt alternatvja a Norton Comman-
der nev MS DOS/Windows alkalmazsnak. Szveges, kvzigrafikus fellettel
rendelkezik. Gyakran hasznljk olyan felhasznlk, akik nem szeretnek foly-
ton parancsokat berni, a grafikus fellethez kpest azonban alacsonyabb szin-
t megoldsra vgynak.
534
A.2. Fordtk
A Midnight Commander rendelkezik egy beptett szvegszerkesztvel,
amelyet mceditnek hvnak. Elrhet az F4 gombbal vagy nll programknt
indtva. Sokan hasznljk rvidebb forrskdok szerkesztsre. Ezt elsegti,
hogy ugyancsak rendelkezik szintaxiskiemel szolgltatssal.
A.1.6. Grafikus szvegszerkesztk
A grafikus krnyezetek (Desktop Environment) rendelkeznek sajt fejlett sz-
vegszerkesztkkel, amelyek tmogatjk forrskdok szerkesztst is. A KDE-
krnyezetben a kate j vlaszts, de a kwrite is jl hasznlhat. A GNOME-kr-
nyezet pedig a gedit nev programot nyjtja. Egyszer forrskdok megrsra
ezek jl hasznlhat eszkzk.
A.2. Fordtk
Linux alatt, a programozsi nyelvektl fggen, az albbi kiterjesztsekkel
tallkozhatunk:
.a Statikus fejleszti knyvtr
.c C nyelv forrs
.0 .cc .cpp .cxx .c++ C++ nyelv forrs
.class Java-byte-kd
.F .f .for Fortran nyelv forrs
.h C/C++ nyelv headerfjl
.hxx C++ nyelv headerfjl
java Java nyelv forrs
. m Objective-C forrs
.o Trgykd (object) fjl
.p Pascal-forrs
.patch Klnbsgllomny
.perl Perl-forrs
.ph Perl-headerfjl
.pl Perl-szkript
.pm Perl-modulszkript
.py Python-forrs
535
A fggelk: Fejleszteszkzk
llomnyuttag Jelents
.pyc
Lefordtott Python-kd
.S .s Assembly kd
.S0
Megosztott knyvtr
.tel .tk Tcl-szkript
Termszetesen a lista nem teljes, s nem is lehet az, hiszen mindig szletnek
jabb jellsek. Az uttagokhoz tartoz nyelvekhez kapcsoldan a tovbbi-
akban rviden ttekintjk a GNU Compiler Collection fordtcsomagot.
A.2.1. GNU Compiler Collection
A GNU Compiler Collection (http: //gcc.gnu.org/) a C (gcc), C++ (g++),
Objective-C, Fortran, Java (GCJ), Ada (GNAT) s a Go nyelvek fordtit fog-
lalja egy csomagba. Ezltal az elbb felsorolt nyelveken rt programokat mind
lefordthatjuk a GCC-vel.
Tovbbi nyelvekhez (Mercury, Pascal) is lteznek elttfelletek (front-
end), m ezeknek egy rszt mg nem integrltk a GCC hivatalos csomagj-
ba. Mi a tovbbiakban a C/C++ nyelvekre hagyatkozunk.
A.11. gcc
A gcc-nek nincs felhasznli fellete. Parancssorbl kell a megfelel paramte-
rekkel meghvnunk. Hasznlata szmos paramtere ellenre egyszer, ugya-
nis ltalnos esetben ezeknek a paramtereknek csak egy kis rszre van
szksgnk.
Hasznlat eltt rdemes ellenrizni, hogy az adott gpen a gcc melyik
verzijt teleptettk. Ezt az albbi paranccsal tehetjk meg:
gcc -v
Ebbl megtudhatjuk a gcc verzijt, tovbb azt a platformot, amelyre lefor-
dtottk.
A program gyakran hasznlt paramtereit az A.1. tblzat tartalmazza.
A.1 . tblzat. A gcc leggyakrabban hasznlt paramterei
Paramter Jelents
-o fjlnv
A kimeneti llomnynv megadsa. Ha nem adjuk meg, akkor
az alaprtelmezett fjlnv a.out lesz.
536
A.2. Fordtk
Paramter Jelents
-c Fordts, linkels nlkl. A paramterknt megadott forrsllo-
mnybl trgykd (object) fjlt kszt.
-Ddefinci=x Definilja a defincimakrt x rtkkel.
-Iknyvtrnv Hozzadja a knyvtrnv paramterben meghatrozott knyvt-
rat ahhoz a listhoz, amelyben a .h kiterjeszts (header) llo-
mnyokat keresi.
-Lknyvtrnu Hozzadja a knyvtrnv paramterben meghatrozott knyvt-
rat ahhoz a listhoz, amelyben a fejleszti knyvtr- (library) l-
lomnyokat keresi.
-llibrary A programhoz hozzkapcsolja a library nev programknyvtr
metdusait.
-static Az alaprtelmezett dinamikus linkels helyett a fordt a stati-
kus programknyvtrakat linkeli a programba, ha azok rendel-
kezsre llnak.
-g, -gN,
-ggdb, -ggdbN
A lefordtott llomnyt elltja a hibakeresshez (debug) szks-
ges informcikkal A -g opci megadsval a fordt a szabv-
nyos hibainformcikat helyezi el. A -ggdb opci arra utastja a
fordtt, hogy olyan tovbbi informcikat is elhelyezzen a prog-
ramban, amelyeket csak a gdb hibakeres rtelmez.
A paramter vgn megadhatunk egy szintet (N) 0 s 3 kztt. 0:
nincs hibakeressi informci, 3: extrainformcik is belekerl-
nek. Az alaprtelmezett a 2 -es szint.
-0, -ON Optimalizlja a programot az N optimalizcis szintnek megfele-
len. Az optimalizci sorn kisebb/gyorsabb kd ellltsra
trekszik a fordt.
A szint 0-tl 3-ig vlaszthat meg. 0 esetn nincs optimalizci.
Az alaprtelmezett 1-es szint esetn csak nhny optimalizcit
vgez a gcc. A leggyakrabban hasznlt optimalizcis szint a 2 -es.
-Wall Az sszes gyakran hasznlt figyelmeztetst (warning) bekapcsol-
ja. A csak specilis esetben hasznos figyelmeztetseket kln
kell bekapcsolni.
Pldaknt nzznk vgig nhny esetet a gcc program hasznlatra.
Egy tetszleges szvegszerkesztben elksztettk a mr jl megszokott
kdot:
/* hello.c */
#include <stdio.h>
int main()
{
printf("Hello vilag!\n");
return 0;
}
537
A fggelk: Fejleszteszkzk
Ezutn kiprbljuk a programunkat Ehhez az albbi paranccsal fordthatjuk le:
-o hllO h
Ha nem rontottuk el a kdot, akkor a fordt hibazenet nlkl lefordtja a for-
rst, s a programra a futtatsi jogot is belltja. Hibtlan kd esetn a fordt
nem r ki semmilyen zenetet. Innen tudhatjuk, hogy sikeresen dolgoztunk.
Ezutn mr csak futtatnunk kell a programot:
"Vh;04
,

A programunk fut, s a konzolon megjelenik a kvetkez felirat:
H ell o vilag!
Vagyis meghvtuk a gcc programot, amely lefordtotta (compile) a kdot, majd
meghvta az ld nev linkerprogramot, amely a lefordtott kdunkhoz hozz-
fzte a fejleszti knyvtrakbl a felhasznlt fggvnyeket, s ltrehozta a
futtathat binris llomnyt
Ha csak trgykd llomnyt (object file) akarunk ltrehozni (amelynek
kiterjesztse .o), vagyis ki szeretnnk hagyni a linkels folyamatt, akkor a -c
kapcsolt hasznljuk a gcc program paramterezsekor:
gcc.-c hello.c
Ennek eredmnyekppen egy hello.o nev trgykd fjl jtt ltre. Ez az llo-
mny gpi kdban tartalmazza az ltalunk rt programot. Ezt termszetesen
linkelnnk kell mg, hogy egy ksz futtathat binrist kapjunk:
gcc -o hello
A o kapcsol segtsgvel tudjuk megadni a linkels eredmnyeknt ltrejv
futtathat fjl nevt. Ha ezt elhagyjuk, alaprtelmezsben egy a.out nev l-
lomny jn ltre.
A kvetkezkben megvizsgljuk azt az esetet, amikor a programunk tbb
(esetnkben kt) forrsllomnybl ll. Az egyik tartalmazza a fprogramot:
/* si ncprg .c */
#i ncl ude <stdi o h>
double si nc (doubl e) ;
int mai n()
{
double x;
538
A.2 .Ford tk
printf("Kerem az x-et: ");
scanf("%lf", &x);
printf("sinc(x) = %6.4 f\n", sinc(x));
return 0;
}
A msik implementlja a sinx/x fggvnyt:
/* sinc.c * I
#i ncl ude <math h>
double sinc(double x)
{
return sin(x)/x;
}
A teljes program lefordtsa a kvetkez:
gcc -o sincprg sincprg.c sinc.c -1m
gy a sincprg futtathat fjlhoz jutunk. Ugyanezt megoldhattuk volna tbb
lpsben is:
gcc -c sincprg.c
gcc -c sinc.c
gcc -o sincprg sincprg.o sinc.o -1m
Az /m kapcsolra azrt van szksgnk, hogy a sin() fggvnyt tartalmaz
matematikai programknyvtrat hozzfzzk a programunkhoz. Ha ezt elmu-
lasztjuk, akkor egy hibazenetet kapunk a fordttl arrl, hogy nem tallja a
sin() fggvny referencijt. Az 1 kapcsol ltalban arra szolgl, hogy egy
programknyvtrat hozzfordtsunk a programunkhoz. A Linux rendszerhez
szmos szabvnyostott programknyvtr tartozik, amelyek a /lib, illetve
a /usr/lib knyvtrakban tallhatk. Ha a felhasznlt programknyvtr
mshol tallhat, az elrsi tvonalat meg kell adnunk az L kapcsolval:
gccprog.c-L/home/my name/my libsmy lib.a
Hasonl problmnk lehet a .h-kiterjeszts llomnyokkal (header file).
A rendszerhez tartoz headerllomnyok alaprtelmezetten az /usr/include
knyvtrban (illetve az innen kiindul knyvtrstruktrban) tallhatk. gy
ha ettl eltrnk, az I kapcsolt kell hasznlnunk sajt headertvonalak
megadshoz:
gccprog.c-I/home/my name/my headers
53 9
#ifdef DEBUG
ri ntf CAsz l el I riddl t "
A fggelk: Fejleszteszkzk
Ez azonban ritkn fordul el, ugyanis a C-programokbl ltalban az aktulis
knyvtrhoz viszonytva adjuk meg a sajt .h-llomnyainkat, vagyis relatv
tvonalmegadst hasznlunk:
gcc prog. c
. . inly heeder
A C-elfeldolgoz (preprocessor) msik gyakran hasznlt funkcija a #define
direktva. Ezt is megadhatjuk kzvetlenl parancssorbl. A
gcc DMAX_ARRAY_SZ=80priig. c o
Prdg
hatsa teljes mrtkben megegyezik a prog.c programban elhelyezett
M~R, ZE
preprocesszordirektvval. Ennek a funkcinak gyakori felhasznlsa a
paramterezs. Ilyenkor a programban feltteles fordtsi direktvkat he-
lyezhetnk el a hibakeress megknnytsre:
A fenti esetben ltjuk az j szlak indulst debug zemmdban, amikor a
DEBUG makrt definiljuk. Viszont ez az informci szksgtelen a felhasz-
nl szmra egy mr letesztelt program esetben, gy ekkor jrafordtjuk a
programot a DEFINE nlkl.
A.2.3. LLVM
A GNU Compiler Collection mellett egyre nagyobb npszersgre tesz szert
az LLVM (Low Level Virtual Machine, http://llvm.org/), amely a GCC-hez
hasonlan szmos nyelvet tmogat. Az LLVM egy olyan hatkony fordt-
program-fejleszt krnyezet, amely ksz megoldsokat ad szmos fordtsnl
hasznlatos funkcira, kztk (nyelvfggetlen) optimalizlsra, kztes bels
nyelvre, valamint kdgenerlsra. A clang (C nyelv") projekt az LLVM natv
C-fordtja, amely gcc kompatibilis, de figyelemremltan gyorsabb annl, to-
vbb lteznek olyan eszkzk, amelyek integrljk a gcc fellett a c/anggal.
A C, C++, Objective-C nyelvekhez hasznlhatjuk az LLVM GCC s a Clang
fellett is. Knnyen lehet, hogy az eszkz valamilyen formban tveszi a gcc
szerept.
540
A.3. Make
A.3. Make
A unixos fejlesztsek egyik oszlopa a make program. A Linux rendszereken a
GNU make terjedt el (http:/ /www.gnu.org/software/make/) . Ez az eszkz
lehetv teszi, hogy a programunk fordtsi menett knnyen lerjuk s auto-
matizljuk. Nemcsak nagy programok esetben, hanem akr egy forrsllo-
mnybl ll programnl is egyszerbb a fordts, ha csak egy make parancsot
kell kiadnunk az aktulis knyvtrban a fordt paramterezse helyett.
Tovbbi szolgltatsa a make programnak, hogy egy sok forrsllomny-
bl ll program fordtsakor csak a mdostott llomnyokat fordtja jra, il-
letve azokat, amelyekre ezek hatssal lehetnek.
Ahhoz, hogy mindezeket a funkcikat megvalsthassa a make egy gy-
nevezett Makefile
112
-ban le kell rnunk a programunk fordtsnak menett a
forrsllomnyok megadsval. Nzznk erre egy pldt:
1: # Makefile
2 :
3: objs = sincprg.o sinc.o
4 : libs = -1m
5:
6: sincprg: $(objs)
7: gcc -o sincprg $(objs) $(libs)
8:
9: install: sincprg
10: install -m 64 4 sincprg /usr/local/bin
11:
12 : . PHONY : i nstal 1
Az 1 . sorban egy megjegyzst (comment) lthatunk. A unixos tradcik alap-
jn a megjegyzst # karakterrel jelljk.
A 3. sorban definiljuk az objs vltozt, amelynek rtke: sincprg.o
sinc.o.
A 4 . sorban ugyanezt tesszk a libs vltozval. A ksbbiekben ezt
hasznljuk fel a linkelsi paramterek belltsra.
A 6. sorban egy szably (rule) megadst lthatjuk. Ebben a sincprg l-
lomny az objs vltoz rtkeitl fgg. A sincprg llomnyt hvjuk a szably
cljnak (target), s az $(objs) adja a fggsgi listt (dependency list).
Megfigyelhetjk a vltoz hasznlatnak mdjt is.
A 7. sorban egy parancssor tallhat, m ez tbbsoros is lehet. Azt mutatja
meg, hogy hogyan kszthetjk el a clobjektumot a fggsgi lista elemei-
bl. Itt llhat tbb parancssor is szksg szerint, m minden sort TAB karak-
terrel kell kezdeni.
112
Ha alkalmazzuk a make -f fjlnv szintaxist, akkor a make a megadott fjlt dolgozza fel
az alaprtelmezett Makefile llomnynv helyett.
54 1
A fggelk: Fejleszteszkzk
A 9. sor specilis. Ebben a szablyban valjban nem llomny ltrehoz-
sa a clunk, hanem az installcis mvelet megadsa.
A 10. sorban vgezzk el a programunk teleptst: az install program
meghvsval bemsoljuk az /usr/ local/bin knyvtrba.
A 12 . sor egy problma megoldst rejti. A 9. sorban a cl nem llomny
volt, hanem parancs. m, ha mgis ltezik egy install nev llomny, s az
frissebb, mint a fggsgi listban szerepl sincprg llomny, akkor nem fut
le a szablyunk. Ezt kszbljk ki a . PHONY kulcsszval, amely mdostja a
make mkdst. Ebben az esetben megadhatjuk vele, hogy az install cl ese-
tn ne figyelje az llomny ltt, hanem minden esetben hajtsa vgre a sza-
blyt, ha krjk.
ltalnosan megfogalmazva a Makefile-ok tfle dolgot tartalmazhatnak.
Ezek a kvetkezk:
megjegyzsek,
explicit szablyok,
i mplicit szablyok,
vltozdefincik,
direktvk.
A.3.1. Megjegyzsek
A megjegyzsek magyarzatul szolglnak, a make program gyakorlatilag fi-
gyelmen kvl hagyja ket. A # karakterrel kell kezddnik.
A.3.2. Explicit szablyok
A szably (rule) azt hatrozza meg, hogy mikor s hogyan kell jrafordtani
egy vagy tbb llomnyt. Az gy keletkez llomnyokat a szably cljnak
vagy trgynak (target) nevezzk." Hogy egy llomny ltrejjjn, ltal-
ban ms llomnyokra is szksg van. Ezek listjt nevezzk fggsgi lis-
tnak, feltteleknek vagy elkvetelmnynek. Pldul:
fcm
-
slefsh
gc -c g fk'.c
H3
m mint lthattuk, a cl nem minden esetben llomny ltrehozsa.
542
A.3. make
A fenti pldban a szably trgya a foo.o fjl, az el'kvetelmny a foo.c, illet-
ve a foo.h llomny. Mindez azt jelenti, hogy szksg van a foo.c s a defs.h
llomnyokra, tovbb a foo.o fjlt akkor kell jrafordtani, ha
a foo.o fjl nem ltezik,
a foo.c id'blyege ksbbi, mint a foo.o idblyege,
a defs.h idblyege ksbbi, mint a foo.o idblyege.
Azt, hogy a foo.o fjlt, hogyan kell ltrehozni, a msodik sor adja meg.
A defs.h nincs a gcc paramterei kztt: a fggsget egy - a foo.c fjlban ta-
llhat - #include defs.h"C nyelv preprocesszordirektva jelenti.
A szably ltalnos formja a kvetkez:
A TARGY egy llomnynv. Az ELOKOVETELMENYEK fjlnevek szkzzel
vannak elvlasztva. A fjlnevek tartalmazhatnak specilis jelents, gyneve-
zett helyettest karaktereket (wildcard characters), mint pldul a ." (aktulis
knyvtr), * " vagy %" (tetszleges karaktersorozat), -" (home knyvtr).
A RECEPT szerepelhet vagy az ELOKOVETELMENYEK-kel egy sorban pon-
tosvesszvel elvlasztva, vagy a kvetkez sorokban, amelyek mindegyikt
egy TAB ka r a kt er r el kell kezdeni. A parancssorozat vgt egy olyan sor
jelzi a make-nek, amelynek az elejn nincs TAB karakter.
tmutat gyeljnk arra, hogy sok szvegszerkeszt hajlamos a TAB gomb lenyomsra
space-karaktereket elhelyezni a szvegllomnyba, s ez ksbb hibt eredmnyez. jabban
azonban sok szvegszerkeszt az llomny nevbl detektlja, hogy Makefile-t ksztnk. Eb-
ben az esetben viszont az llomnynv megadsval clszer kezdennk.
Mivel a $ jel mr foglalt a vltozkhoz, ezrt ha a parancsban $ jel szerepelne,
akkor helyette $$-t kell rnunk.
Ha egy sor vgre \" jelet tesznk, a kvetkez sor az elz folytatsa
lesz, teljesen gy, mintha a msodik sort folytatlagosan rtuk volna. Erre
azrt van szksg, mert a make minden parancssort kln shellben futtat le.
Ezltal pldul a cd parancs hatsa is csak abban a sorban rvnyesl, aho-
va rjuk. Pldul:
cd konyvt a r ; \
gcc -c -g foo. c
Ha a make programnak paramterknt megadjuk egy trgy nevt, akkor az a
szably hajtdik vgre, amely a trgy ellltshoz kell. A make felpt egy
fggsgi ft, amelyet bejrva ellenrzi, hogy melyik rszeket kell jraford-
tani. Majd elvgzi a szksges lpseket, hogy ellltsa az aktulis clt.
54 3
A fggelk: Fejleszteszkzk
Ha a make programot paramterek nlkl futtatjuk, akkor automatiku-
san az els szably hajtdik vgre, valamint azok, amelyektl valamilyen m-
don fgg.
tmutat A make program hasznlatnl gyeljnk arra, hogy mivel a lpsek szksgessgt
a trgy- s a fggsgllomnyok idblyege alapjn vizsglja, ezrt ha az idbelltsok meg-
kavarodnak, akkor nem lesz j a mkds. Ilyen helyzet leggyakrabban akkor fordul el, ha a
fejleszts sorn gpet vltunk, s a kt szmtgp rja nem jr szinkronban. Termszetesen
az id visszalltsa is okozhat ilyen problmt. Ilyenkor clszer az idblyeget aktualizlni a
touch paranccsal, s a kztes llomnyok letrlsvel jrafordtani az egsz projektet.
A.3.3. Hamis trgy
Gyakran elfordul, hogy valamilyen mveletre egy szablyt ksztnk, amely-
nek a receptrsze tartalmazza a vgrehajtand parancsokat. A szably clja
ilyenkor nem egy ellltand llomny, hanem pusztn nvknt funkcionl az,
amellyel a szablyra hivatkozunk. Az ilyen trgyakat hvjuk hamis trgynak.
Ha azonban valamelyik mvelet tnyleg ltrehozn a trgyknt megadott
llomnyt, s az frissebb lenne a feltteleknl, akkor a szablyhoz tartoz re-
cept parancsai egyltaln nem hajtdnak vgre. Gyakori, hogy nincs megadva
felttel a hamis szablyhoz. Ilyenkor egyltaln nem hajtdik vgre a sza-
bly, ha a trgyllomny ltezik.
Azrt, hogy elkerljk a korbban vzolt problmkat, a .PHONY kulcs-
szval egyrtelmen deklarlnunk kell a hamis clokat. Pldul:
.P HONY:clean
cl ean:
rm * .o prg
Ha egy knyvtrban tbb program forrsa is szerepel, akkor gyakran ksz-
tnk egy hamis szablyt all" nven, amely mindent lefordt s elllt. s
hogy ez az alaprtelmezett szably is legyen egyben, ezrt els szablyknt r-
juk meg. Pldul:
alt: prgl prg2
.P HONY: all
prgl:prgl.o
gcc-oprglprgl.o
prg2 :prg2 .o
gcc-oprg2 prg2 .o
544
A.3. Make
A.3.4. Vltozdefincik
Mint az els pldban is lthattuk, gyakran elfordul, hogy egyes llomny-
neveknek tbb helyen is szerepelnik kell. Ilyenkor, hogy megknnytsk
a dolgunkat, vltozkat hasznlunk. Ekkor elegend egyszer megadnunk a
listt, a tbbi helyre mr csak a vltozt helyezzk. A vltozk hasznlatnak
msik clja, hogy a Makefile-unkat rendezettebb tegyk, megknnytve ezzel
a ksbbi mdostsokat.
A Makefile-ban a vltozk tpusa mindig szveg. A vltozk megadsnak
szintaxisa a kvetkez:
Erre a vltozra ksbb a
'.414
vagy a
szintaxissal hivatkozhatunk.
A vltoz neve nem tartalmazhat :", #", =" s semmilyen resmez-
karaktert. A gyakorlatban mg szkebb halmazt hasznlunk: betket, sz-
mokat s a : karaktert. A vltozk nevnl a rendszer figyeli a kis- s nagy-
betket. A tradci az, hogy a vltoz nevt csupa nagybetkkel rjuk. Jelen-
leg azonban gyakrabban kisbets neveket hasznlunk a Makefile-ban, s a
nagybets nevek inkbb rendszerfunkcikra vannak fenntartva. Egyes nagy-
bets vltozk felldefinilsval mdosthatjuk a rendszer mkdst.
Emellett nhny karakterkombincinak specilis jelentse van. (Ezeket lsd
az automatikus vltozkrl szl fejezetben.)
Lehetsgnk van arra, hogy a vltozk rtknek megadsakor ms vl-
tozk rtkeit is felhasznljuk. Pldul:
Prgs' = $ (Prgl) . . g. PrO W
Van azonban egy olyan tulajdonsga a rendszernek, amelyre figyelnnk kell.
A vltozk kirtkelse a felhasznls helyn trtnik. Azokat az rt-
keket veszi figyelembe a rendszer, amelyeket addig definiltunk, s szksg
szerint rekurzvan kifejti. Pldul:
objs = $(objl) $ (obj2 )
objl = el so.o
obj 2 = masodi k.o
prg : $ (obj s)
545
A fggelk: Fejleszteszkzk
Amikor a prg" szablyt meghvjuk, akkor a feltteleknl kirtkeli a prog-
ram az objs" vltozt. Ennek rtke $(objl) $(obj2 )". A program kirtkeli
mindkt vltozt, gy megkapjuk az elso.o masodik.o" szveget, amelyet be-
helyettest.
Ennek a megoldsnak van azonban egy msik oldala is. A vltozk hasz-
nlatakor kerlnnk kell a kvetkez megoldst:
objs = elso.o
objs = S(objs) masodik.o
Azonnal arra szmtannk, hogy szekvencilisan hajtdnak vgre a mvele-
tek, s a vgeredmnyknt az elso.o masodik.o" szveg helyettestdik majd
be a $(objs)" helyre. Ezzel szemben egy vgtelen ciklust idznk el, s a
behelyettests helyn vgtelen masodik.o" szveg lesz, mivel ez az utoljra
belltott rtk.
A.3.5. A vltoz rtkadsnak specilis esetei
Lthatan a felhasznls helyn elvgzett rekurzv kirtkels csapdkat rejt
magban. Erre megolds az egyszer kirtkels, amelyet a definils he-
lyn vgez el a rendszer. Ennek jele a :=" karakterkombinci. A mkdst a
kvetkez plda szemllteti:
a := egy
b := $(a) ketto
a := harom
Ez egyenl azzal, mintha a kvetkezket rtuk volna:
b:=egy k etto
a:=harom
Az elzekben emltett hibs pldra is van helyes megolds. Vagyis megoldha-
t, hogy a vltoz rtkhez hozzadjunk tovbbi szvegeket. Ezt a +=" jel-
lel tehetjk meg. A korbban ltott plda helyesen a kvetkez:
objs = elso.o
objs += masodik.o
gy az objs" vltoz hasznlatakor az eredmny nem vgtelen ciklus lesz,
hanem az elso.o masodik.o" szveg.
Az eddig ltottak mellett van lehetsgnk feltteles rtkadsra is.
Ebben az esetben a vltoznak csak akkor adunk rtket, ha mg nincs defi-
nilva. Ennek jele a ?=". Az albbi pldn nzzk meg a mkdst:
546
A.3. Make
=egy
7= . ketto
Ez egyenl a kvetkezvel:
egy
Br ebben a pldban nem ltszik kzvetlenl az eszkz haszna, m egy sz-
szetett, elgazsokat vagy tovbbi llomnyokat tartalmaz Makefile esetn
nagyon hasznos tud lenni.
A.3.6. Tbbsoros vltozk definilsa
A define direktva hasznlatval is adhatunk a vltozknak rtket. Szintaxisa
lehetv teszi, hogy az rtk jsor-karaktereket is tartalmazzon:
definek et-sor=
echo$(a)
echok etto
endef
A define szt a vltoz neve kveti. Ezt kveti a mvelet. Alaprtelmezett a
=" jel, amelyet el is hagyhatunk. m hasznlhat a +=" jel is, ezltal bvt-
hetjk a vltoz korbbi rtkt. A mveleti jel utn mst mr nem rhatunk
az els sorba. Az rtkek a kvetkez sorokban kvetkeznek, s a blokkot az
endef sz zrja. Az endef eltt szerepl jsor-karakter mr nem szmt bele az
rtkadsba.
Lthatan az rtkadsnl hivatkozhatunk ms vltozkra is, ahogy a
korbbi esetekben is. Szksg esetn meg is szntethetjk a definilt vltozt
az undefine kulcsszval:
undefinek et-sor `
A.3.7. A vltoz hivatkozsnak specilis esetei
A helyettest hivatkozs rvn lehetsgnk van arra is, hogy a vltozra
val hivatkozs sorn az rtkt mdostva helyettestsk be. Ilyenkor egy
konverzis szablyt definilhatunk. A konverzi sorn az rtket szavanknt
kezeljk, s a szavak vgn tallhat szvegrszleteket cserljk le ms ka-
raktersorozatokra. Nzznk egy pldt:
s
547
A fggelk: Fejleszteszkzk
Ebben a pldban az objs" vltoz rtke elso.o masodik.o" lesz. Vagyis egy
szlistbl knnyen elllthatunk mdostott listkat is. A helyettest hi-
vatkozs hivatalos formtuma a kvetkez:
$(v altozo:a=b)
vagy
${ v altozo:a=b}
Itt a valtozo" egy vltoz, amely szavakbl ll listt tartalmaz. A mvelet
minden sz vgn lecserli az a" szvegrszletet b" szvegre.
Egy msik specilis vltoz-hivatkozsfajta a szmtott vltoznevek
hasznlata. Ebben az esetben a hivatkozott vltoz nevt egy msik vltoz
tartalmazza. Egy pldn demonstrlva:
a = b
b = c
eredm := $($(a))
A $(a)" rtke b". Ezt behelyettestve a $($(a))" kifejezsbe $(b)"-t kapunk.
Ennek rtke c". Vagyis az eredm" vltoz rtke c" lesz.
A szmtott vltozneveket a helyettest hivatkozsokkal is kombinl-
hatjuk:
src_1 := elso.c
src_2 := masodik.c
objs := $(src_S(a): .c=.o)
Az a" vltoz rtktl fggen vagy az src_1" vagy az src_2 " rtkbl l-
ltjuk el az objs" rtkt, s ennek sorn a .c" kiterjesztst .o"-ra cserljk.
A.3.8. Automatikus vltozk
A receptek ksztsnl gyakran sokat segt, ha a forrs- s a clllomnyok
nevt nem kell minden esetben bernunk, hanem a szably cljbl s felt-
teleibl generlhatjuk. Ez az eddig trgyalt esetekben knnyebbsget jelent,
m tbb ksbb trgyalt esetben nlklzhetetlen eszkz. ltalnos szablyo-
kat nem tudunk gy definilni, hogy az llomnyneveket ne generlnnk, hi-
szen ezekben az esetekben nem tudunk konkrt llomnyokat megadni.
Az llomnynevek ellltst az automatikus vltozkkal vgezzk.
Az A.2. tblzat foglalja ssze az automatikus vltozkat a jelentskkel.
548
A.3. Make
A.2. tblzat. Automatikus vltozk
Automatikus vltoz Jelents
$ @ > A clllomny neve.
$< A fggsgi lista els elemnek a neve.
$? Az sszes olyan felttelfjl neve (sorban, szkzzel elv-
lasztva), amely frissebb a clllomnynl.
Az sszes felttelfjl neve szkzzel elvlasztva.
$+
Jelentse nagyrszt egyezik az elzvel, m ha a feltte-
lek kzt tbbszr szerepel a fjl, akkor azt ugyangy tbb
pldnyban tartalmazza.
$* A clfjl nevnek uttag nlkli rsze.
A kvetkez fejezetekben tallkozunk az alkalmazsi terletekkel is.
A.3.9. Tbbszrs cl
Egy szably megadsakor nemcsak egy trgyat, hanem trgyak listjt is meg-
adhatjuk szkzkkel elvlasztva Ekkor minden trgyra kln-kln vgre-
hajtdik a szably. Ez teht olyan, mintha ugyanazt a szablyt lemsoltuk
volna annyiszor, ahny clllomnyunk van, s mindegyik szably trgyhoz
bernnk egy-egy clllomnyt. Termszetesen ennek csak gy van rtelme,
hogyha nem pontosan ugyanazt a parancsot hajtjuk vgre minden esetben.
Azt az ellenttet, hogy a recept egyforma, de a vgrehajtott parancsok mgis
klnbzek legyenek, az automatikus vltozkkal tudjuk feloldani.
Nzznk egy pldt, ahol egy forrsllomnybl kt klnbz programot
fordtunk eltr paramterezssel:
debug_flags :=-g3 -00
rel ease_fl ags :=-g0 -03
prgs :=debug release
alt: $(prgs)
. PH0NY: all
$(prgs): hello.c
gcc $($(@)_flags) -o $@$<
A make parancs kiadsa utn kt fordts trtnik. Ltrejn egy debug" s
egy release" nev llomny:
gcc -g3 -00 -o debug hello.c
gcc -g0 -03 -o release hello.c
549
A fggelk: Fejleszteszkzk
A kt fordts eltr paramterezssel jn ltre. A $($(@)_flags)" kifejezsben
lthatunk egy automatikus vltozt: $(@)", amely az aktulis trgy rtkt
veszi fel. Ezt a flags" szveggel kiegsztve egy msik vltoz nevt adja ki,
amelyet felhasznlva beillesztjk annak rtkt. A ltrehozott llomny neve
a trgy ($@"), mg a forrs a felttellista els eleme ($<").
A.3.10. Mintaszablyok
Az elz fejezet pldjban lthattuk, hogyan tudunk tbb llomnyt is ell-
ltani ugyanannak a receptnek az alapjn. m ha megfigyeltk, a mdszer-
nek van egy kellemetlen megktse. Az elkvetelmny-lista kzs. Vagyis
csak olyan esetekben mkdik, amikor minden clllomny ellltshoz
ugyanazokra a forrsllomnyokra van szksg.
A problmnkat a statikusminta-szablyok oldjk meg, amelyek lehe-
tv teszik, hogy a clllomnyok nevbl generljuk a feltteleket. Ennek l-
talnos alakja a kvetkez:
T RGYAK:T RGY-MINTA:ELKVETELMNYEK-MINT JA;RECEP T
RECEP T
Hasonlan az egyszer szablymegadshoz a trgyak listjnl hasznlhatunk
helyettest karaktereket. A TRGY-MINTA s az ELKVETELMNYEK-
MINTJA megadja, hogyan szmthat ki egy trgy nevbl a hozztartoz
el'kvetelmnyek neve. A mintk egy helyen tartalmazzk a %" karaktert.
A trgy nevre illesztve a trgy mintjt a %" helyre es szveget a rend-
szer az el'kvetelmny mintjnak %" karakterrel jellt helyre illeszti, s
gy elllt egy j felttelt.
A knnyebb rthetsg kedvrt egy pldn reprezentljuk a statikus-
minta-szablyok hasznlatt:
objs := elso.o masodik.o
all : $(objs)
$(objs): %.o: %.c
gcc -c -o $@ $<
Ez a szably az albbi parancsok vgrehajtst eredmnyezi:
gcc-c-oelso.oelso.c
gcc-c-omasodik .omasodik .c
550
A.3. Make
Vagyis a szably meghvdik elszr az elso.o" cllal. A mintk alapjn eb-
ben az esetben az el'kvetelmny az elso.c" llomny lesz. A fordts sorn a
parancssorba behelyettestdik a clllomny neve s az el'kvetelmny-lista
els eleme mint forrs. Ez eredmnyezi az els parancssort. Majd ezt kvet-
en a masodik.o" clra is vgrehajtdnak ezek a mveletek. Ez eredmnyezi a
msodik parancssort.
A statikusminta-szablynak ltezik egy ltalnostott formja, amelyet
egyszeren mintaszablyoknak neveznk. Mg a statikusminta-szablyok-
nl megadtunk egy trgylistt, s a szably csak azokra az esetekre rvnyes,
addig az ltalnos mintaszablyoknl ezt elhagyjuk, s amolyan alaprtelme-
zett szablyt alkotunk. Ez a szably azonban csak akkor lesz rvnyes, ha a
rendszer nem tall egy specifikus szablyt az adott clllomny ellltsra.
Az ltalnos mintaszably szintaxisa a kvetkez:
Az elz pldnl maradva:
obj s:=elso.omasodik .o
all:$(obj s)
%.o:%.c
gcc-c-o$@$<
A hats ltszlag ugyanaz, mint a statikusminta-szably esetben. m ebben
az esetben egy ltalnos szablyt fogalmaztunk meg, amely lerja, hogy a .0"
vg llomnyok ellltshoz szksg van egy .c" vg llomnyra, illetve
lerja az elllts metdust. Vagyis minden tovbbi .0" vg llomny el-
lltsra is mkdik ez a szably.
A.3.11. Klasszikus ragozsi szablyok
A mintaszablyok eldei a ma mr httrbe szorult ragozsi szablyok.
A make programnak megadhat az uttagok listja, illetve az, hogy az egyik
uttaggal rendelkez llomnybl hogyan llthat el egy msik uttaggal
rendelkez llomny. Hasonlan a mintaszablyokhoz ezek a szablyok is
csak akkor jutnak rvnyre, ha az adott clllomny ellltsra nincs speci-
fikus szably.
Pldaknt nzzk egy ragozsi szably megadst:
551
A fggelk: Fejleszteszkzk
. C.0:
$(CC) C $(CFLAGS) $(CPPFLAGS) o $@$<
. SUFFIXES: . 0 . o
Ez a plda a .c" kiterjeszts forrsllomnyokbl a hozzjuk tartoz .0" ki-
terjeszts llomnyok ellltsra fogalmaz meg ltalnos szablyt. A pl-
dbl lthat, hogy az uttagokat a .SUFFIXES: specilis trgy utn fel kell
sorolnunk, majd pronknt adhatjuk meg, hogy hogyan ll el az egyik utta-
g llomnybl a msik, jelen esetben a .c kiterjeszts C-forrsfjlbl a .0"
kiterjeszts trgykd llomny. A ragozsi szablyok ltalnos alakja a
kvetkez:
Az Fs a forrsuttag, a Cs a cluttag. A forrsbl a cl ellltshoz a make
a RECEPT sorokban megadott utastsokat hajtja vgre. A ragozsi szab-
lyoknak nem lehetnek tovbbi el'kvetelmnyei, csak az az egy, amely gene-
rldik.
Lthatan a ragozsi szablyok ktttebbek, mint a mintaszablyok,
ezrt mostanban az utbbiakat hasznljuk.
A.3.12. Implicit szablyok
A C, C++, Pascal s ms nyelvek forrsllomnyainak lefordtsra megvan-
nak a kialakult fordtprogramok, illetve tipikus parancsok. Ezrt nagyban
egyszersten a fejleszt'k munkjt, ha ezeket a szablyokat nem kellene
mindig gpiesen belerni a Makefile-ba. Ezt a make kszti is felismertk,
ezrt a tipikus mveletek szablyait beleptettk a programba.
Ha a make programnak el kell lltania egy llomnyt, mert arra utast-
juk, vagy szerepel egy feldolgozand szably felttelei kztt, akkor megpr-
blja megkeresni a r vonatkoz szablyt. m ha nem szerepel az llomny
egyetlen szably trgyaknt sem, akkor megprbl egy alaprtelmezett sza-
blyt tallni r, s ha ez sikerl, akkor vgre is hajtja. Ezeket az alaprtel-
mezett szablyokat implicit szablyoknak nevezzk.
Az implicit szablyok nagy rsze elre adott, de mi is rhatunk ilyeneket.
Az elre adott implicit szablyokat a
Make-P
paranccsal nzhetjk meg. Ez a parancs azonban valjban a beptett szab-
lyok s az ltalunk rt Makefile unijt adja vissza. Vagyis ha csak a beptett
szablyokat akarjuk ltni, akkor nem lehet a knyvtrban Makefile.
552
A.3. Make
Az implicit szablyok nagy rsze ragozsi, illetve mintaszably. Hiszen
ezek olyan ltalnos szablyok, amelyek mindenki szmra hasznlhatk.
A recepteket azonban gy fogalmaztk meg, hogy egyes vltozk rtkvel befo-
lysolhatjuk a mkdsket. Pldul a C-llomnyok fordtsakor ez gy nz ki:
%.o: %.c
S(CC)$(CFLAGS)$(CP P FLAGS)S(TARGET_ARCH) -c $(0UTP UT_OP TION)$<
Lthatan pldul a CFLAGS vltoz rtkvel befolysolhatjuk, milyen opci-
kkal trtnjen a C-fordt meghvsa. Vagyis elg a Makefi/e-unkban ennek a
vltoznak ms rtket adni, ha az alaprtelmezett rtkek nem megfelelek,
s nem szksges a szablyt jra megalkotni. Az ilyen jelleg vltzk nev-
nl a konvenci a nagybetk hasznlata, ahogy a pldban is szerepel.
A.3.13. Specilis trgyak
Az eddigi fejezetek sorn lthattunk mr kt specilis clt is. Ilyen volt a
.PHONY s a .SUFFIXES. Az A.3. tblzatban sszegezzk a legfontosabbakat.
A.3. tblzat. Specilis clok
.PHONY Ennek a clnak az elfelttelei hamis cloknak minslnek. Va-
gyis a clhoz tartoz szablyt idblyeg-ellenrzs nlkl min-
denkppen lefuttatja a make.
.SUFFIXES A cl elfelttelei llomnynv-kiterjesztsek, amelyeket a make
a ragozsi szablyok keressnl hasznl.
. DEFAULT Ehhez a clhoz megadott recept fut le azokban az esetekben, ha
egy adott clhoz sem explicit, sem implicit szablyt nem tall a
rendszer.
.SILENT Ha megadunk elfelttelt ehhez a szablyhoz, akkor az ezek el-
lltsnl vgrehajtott parancsokat nem rja ki a make. Ha nem
adunk meg elfelttelt, akkor minden recept vgrehajtsa csen-
des" lesz.
. ONESHELL Korbban lthattuk, hogy a recept vgrehajtsakor minden sor
kln shellpldnyban hvdik meg. Ennek a specilis clnak a
hasznlatval ezt mdosthatjuk. Ebben az esetben a teljes re-
cept egy shellpldnyban hajtdik vgre.
553
Afggelk: Fejleszteszkzk
A.3.14. Direktvk
A direktvk nagyon hasonltanak a C nyelvben hasznlt preprocesszordirek-
tvkhoz Arra utastjk a make programot, hogy a Makefile olvassa kzben
valamilyen specilis mveletet vgezzen el. Ezek a mveletek a kvetkezk
lehetnek:
ms Makefile-ok beolvassa;
felttelek alapjn a Makefile egyes rszeinek hasznlata vagy figyel-
men kvl hagysa;
vltozk definilsa.
Elsknt nzzk meg ms llomnyok hozzadst a Makefile-unkhoz
include FAJL_NEVEK...
A pldban a FAJL_NEVEK egy olyan kifejezs, amely szkzzel elvlasztott
fjlnevekbl, specilis karakterekbl s vltozkbl llhat. A make betlti a
megadott llomnyokat, s beilleszti a Makefile-ba.
Felttelek alapjn a Makefile egyes rszeit kihagyhatjuk, vagy benne
hagyhatjuk a vgrehajtott mveletek kztt:
ifeq($(cC),gcc)
libs :=$(gcc_libs)
el se
libs :=$(normal_libs)
endif
A fenti pldban, ha a CC vltoz rtke gcc, akkor a msodik sor hajtdik
vgre, egybknt a negyedik.
Vltozkat a define direktvval definilhatunk. Erre lthattunk pldt a
tbbsoros vltozk ltrehozsnl. (Lsd az A.3.6. Tbbsoros vltozk defini-
lsa alfejezetben.)
A.4. Make alternatvk
Br a make hatkony eszkz, amely ms platformokon is jl hasznlhat, m
nagyobb projekteknl, amikor a clok szma megn, akkor a megrsa ssze-
tett, nehz feladat lehet. Emellett nehezen tud adaptldni a klnbz rend-
szerek eltr konfigurciihoz. Fordtplatformok vltsa esetn szksg lehet
a Makefile mdostsra.
554
A.4. Make alternatvk
A.4.1. Autotools
A GNU Autotools kiegszti a GNU make funkcionalitst kibvtett szably-
listval s rszletes fggsg-ellenrzssel. F clja a forrskdok hordozha-
tsgnak megteremtse a Unix rendszerek kztt. Szmos nylt forrskd
szoftvercsomag hasznlja.
A GNU Autotools tbb klnll programot tartalmaz, mint az Autoconf,
az Automake s a Libtool. m a programok a mkdsk sorn tovbbi esz-
kzkre is ptenek, pldul a pkg-configre s a gettextre.
Az Autoconf ltrehoz egy configure nev szkriptllomnyt a configure.ac
llomny alapjn. A configure llomnyt lefuttatva felderti a szksges fg-
gsgeket, vagyis a fordtshoz hasznlt programok s fejleszti knyvtrak
megltt s elrsi tjt. Ha minden szksges elemet megtallt, akkor az
eredmnyek s a Makefile.in llomny alapjn legenerlja azokat a Makefile-
okat, amelyekkel a fordtsokat elvgezhetjk.
Az Automake a Makefile.in llomnyok ellltsban segt. Bemenetknt
egy Makefile.am nev llomnyt hasznl, amelybl hordozhat Makefile l-
lomnyok ellltshoz hasznlhat Makefile.in llomnyt llt el.
A Libtool a fejleszti knyvtrak ellltsban segdkezik.
A felhasznlknak a fordtshoz nincs szksgk a teljes Autotools cso-
magra. A forrscsomagban lv configure szkript kpes az Autotools eszkzk
nlkl is elltni a feladatt.
A.4.2. CMake
A CMake (h,ttp:/ /www.cmake.org/) hasonlan a GNU Autotoolshoz Makefile-
okat hoz ltre, amelyekkel elvgezhetjk a tnyleges fordtst. Belltstl
fggen azonban akr Visual Studio-projektllomny ellltsra is alkal-
mas. Vagyis fordt- s platformfggetlen mdon gondoskodik a forrskd le-
fordtshoz szksges llomnyok legenerlsrl.
A.4.3. qmake
A qmake a Qt-csomag rsze. F feladata Qt-programok fordtsnak tmoga-
tsa. Automatikusan kezeli a moc s a uic segdprogramok hvst. Egyszer
konfigurcis llomny, s nagy mennyisg beptett tuds jellemzi. Mk-
dse hasonlt az elz kt eszkzhz. Eredmnyknt egy Makefile-t llt el,
amellyel elvgezhetjk a fordtst.
555
A fggelk: Fejleszteszkzk
A.4.4. SCons
Az SCons (http://www.scons.org/) egy szoftver-konstrukcis" eszkz. Automa-
tikusan vizsglja a forrskdokban a fggsgeket, elvgzi a platformadapt-
cis lpseket. Eredmnyknt ksz binris programokat llt el.
Az SCons Python-alap eszkz, gy a konfigurcis llomnyok s a ford-
tsi mveletek lersai Python-szkriptek.
A.5. IDE
Manapsg a fejlesztk a munkjukhoz olyan knyelmes krnyezetet szeret-
nnek, amely tveszi tlk a gyakran ismtld egyszer mveletek egy r-
szt. A Unix vilg hagyomnyos, fapados" fejleszti eszkzei nem elgtik ki
ezt az ignyt, ezrt szlettek meg az integrlt fejleszti krnyezetek (Integ-
rated Development Environment, IDE).
Az IDE ltalban tartalmaz:
szvegszerkesztt a forrskdok szerkesztshez,
fordtt,
fordtsautomatizlsi eszkzket,
hibakerest.
A Linuxos IDE-megoldsok ltalban ms eszkzkre ptenek. Fordtshoz
GNU-fordtt, automatizlshoz GNU Autottoolst vagy CMake-et s hibake-
resshez a GNU debuggert hasznljk. Ezeket az eszkzket vonjk ssze egy
jl kezelhet egysgbe.
Szmos IDE-eszkzt tallhatunk a Linuxra. Ebbl jelenleg taln az egyik
legelterjedtebb az Eclipse (http://www.eclipse.org/), amely multiplatformos,
tbb programozsi nyelvet tmogat eszkz.
A KDE, de ms C/C++-fejlesztsekhez is jl hasznlhat a KDevelop
(http:/ Ikdevelop.org/).
Hasonlan a GNOME projekt is rendelkezik IDE-eszkzzel, amely ltal-
nosan hasznlhat. Ez az Anjuta (http:/ /www.anjuta.org/).
A Qt-fejlesztsekhez a legclszerbb eszkz a Qt Creator (h,ttp:/ /
qt.nokia.com / products / developer-tools), amely szintn hasznlhat ms
C/C++-fejlesztsekhez is.
556
B FGGELK
Hibakeress
A C az egyik legelterjedtebb programozsi nyelv, s egyrtelmen a Linux-rend-
szerek ltalnos nyelvnek tekinthet. Van azonban j pr olyan jellemzje, ame-
lyek hasznlata knnyen vezethet nehezen felderthet programhibkhoz. Ilyen
gyakori s nehezen felderthet hibafajta pldul a memriaszivrgs (memory
leak), amikor a lefoglalt memria felszabadtsa elmarad, vagy a tlrs (buffer
overrun), amikor a program a lefoglalt terleten kvlre r. Ebben a fejezetben
ezeknek s ms hasonl problmknak a megoldsra is ltunk pldkat.
B.1. gdb
A hibakeresknek, mint pldul a gdb-nek, az a rendeltetse, hogy belelssunk
egy program mkdsbe, kvethessk a futs sorn lezajl processzeket, to-
vbb hogy megtudjuk, mi trtnt a program sszeomlsakor, mi vezetett a
hibhoz.
A gdb-nek a funkciit alapveten ngy csoportba oszthatjuk:
a program elindtsa,
a program meglltsa meghatrozott felttelek esetn,
a program megllskori llapotnak vizsglata,
a program egyes rszeinek megvltoztatsa s a mdostsok hats-
nak vizsglata.
A gdb a C-ben s C++-ban rt programok vizsglatra hasznlhat elssorban.
m ms nyelvek rszleges tmogatsa is megtallhat benne (D, Modula-2 ,
OpenCL C).
B fggelk: Hibakeress
B.1.1. Plda a gdb hasznlatra
A gdb nagyon sok olyan paranccsal s lehetsggel rendelkezik, amelyek meg-
tallhatk a dokumentcijban. Egy tlagos hibakeresshez azonban a pa-
rancsok tredkt elg ismerni. Ebben a fejezetben bemutatunk egy ilyen
plda-hibakeresst ltalban a parancsokkal.
Az albbi hibs pldaprogramot vizsgljuk meg:
/* hibas.c - Hi bas program */
#i ncl ude <stdio. h>
#i ncl ude <string .h>
voi d hi basfv()
{
char* str =NULL;
strcpy (str, ,"Hello");
pri ntf("%s \n" , str) ;
}
{
hi basfv() ;
return 0;
A hibakeresshez az adott programnak tartalmaznia kell a hibakeressi infor-
mcikat, vagyis az adott programot a -g kapcsolval kell fordtani. m ha a
gdb-t hasznljuk, akkor clszer a programot a -ggdb kapcsolval fordtani:
114

$gcc-Wall -ggdb-ohibashibas.c
Elszr indtsuk el a gdb programot, s tltsk be a programunk kdjt:
$ gdb hibas
GNUgdb (ubuntu/Li naro 7.2-lubuntull) 7.2
Copyright (C) 2010 Free Software Foundation , Inc.
Li cense GPLv3+: GNU GP Lversion 3 or 1 ater
<http://gnu.org/li censes/gpl . html>
This is free software: you are free to change and redi stri bute i t.
There isNOWARRANTY,tothe extent permitted by law.
Type "show copying" and "show warranty" for details.
ThisGDBwas configured as "i686-linux-gnu".
For bug reporting instructions, please see:
<http://www.gnu.org/software/gdb/bugs/...
Reading symbols from /tmp/hibas...done.
(gdb)
114
A
-ggdb kapcsol hasznlatakor az informci formtuma a gdb-re lesz optimalizlva.
Ms hibakeres programokat ez sszezavarhat. Ezrt csak a gdb esetn hasznlatos.
558
B.1. gdb
Helyezznk el egy trspontot (breakpoint) a hibasfu" nev fggvnynl:
(gdb) break hibasfv
Breakpoi nt 1 at 0x80483fa: fi 1 e hi bas . c , 1 i ne 7.
(gdb)
A programunk elindtshoz adjuk ki a run parancsot:
(gdb) run
starting program: /tmp/hibas
Ezt kveten a terminlban a programunk kimenett ltjuk, ha van ilyen, il-
letve amit berunk, az a program bemenete lesz. Esetnkben a pldaprogram
nem tartalmaz sem kirst, sem beolvasst a trspont eltt.
A program addig fut, amg elri a trspontot, amelyet a hibasfu" nev
fggvnyre lltottunk be Amikor ez az esemny bekvetkezik, akkor felfg-
gesztdik a program futsa, s visszakapjuk a gdb parancs promptjt:
Breakpoi nt 1, hibasfv () at hi bas . c :7
7 char* str = NULL;
(gdb)
Tovbblphetnk egy sorral a next parancs segtsgvel:
(gdb) next
8 strcpy(str, "Hello");
(gdb)
Lehetsgnk van arra, hogy a kvetkez sorra lpve belelpjnk a soron k-
vetkez fggvny rutinjba. Ezt a step paranccsal tehetjk meg.
A backtrace parancs segtsgvel megnzhetjk, melyik szubrutinban j-
runk ppen:
(gdb) backtrace
#0 hibasfv () at hibas.c:8
#1 0x08048435 in main (argc=1, argv=Oxbffff7e4) at hibas.c:14
(gdb)
Sorban minden aktv fggvny stackkerett megmutatja. gy lthatjuk azt is,
hogy az aktulis fggvny melyik msikbl hvdott meg. Ha szeretnnk b-
vebb informcikat ltni a loklis vltozkrl, akkor kiegszthetjk a full pa-
ramterrel:
(gdb) backtrace full
#0 hibasfv () at hibas.c:8
str = Ox0
#1 0x08048435 in main (argc=1, argv=Oxbffff7e4) at hibas.c:14
Nolocals.
(gdb)
559
B fggelk: Hibakeress
Ha egy vltoz aktulis rtkt akarjuk megvizsglni, akkor a print parancs
segt:
(gdb) print str
$1 = Ox0
(gdb)
Ha a forrskdnak azt a rszt szeretnnk ltni, ahol ppen jrunk, akkor a
list paranccsal kilistzhatjuk:
(gdb) list
3 #i nclude <stri ng .h>
4
5 void hi basfv()
6
7 char* str = NULL;
8 strcpy(str, "Hello");
9 printf("%s\n", str);
10
11
12 int mai n(i nt argc, char* argv )
(gdb)
Elre gyanakodhatunk, hogy hiba volt a karaktertmb allokcijnak az el-
mulasztsa, illetve az strcpy0 fggvnynl hiba trtnik, amikor a 0-s cmre
megprblunk majd szveget msolni.
Engedjk tovbb a program futst a continue paranccsal, s megltjuk a
hiba hatst:
(gdb) continue
Conti nui ng .
Program received signalSIGSEGV,Segmentation fault.
0x001a45c6 i n ?? () from /1 i b/i 386-1 i nux-gnu/1 i bc. so. 6
(gdb)
Ha a programunkban nem lenne hiba, akkor szablyosan lefutna. m ese-
tnkben fatlis hiba trtnt, s a rendszer a SIGSEGV jelzssel terminlja a
folyamatunkat. Mivel a gdb-vel futtatjuk a programunkat, ezrt a folyamat
nem r azonnal vget. Lehetsgnk van a korbban megismert parancsokkal
megvizsglni a folyamat llapott a jelzs rkezsnek pillanatban.
s vgl a quit paranccsal kilphetnk. Ha a folyamatunk mg ltezik,
mert csak felfggesztettk a futst, akkor kilps eltt rkrdez a gdb, hogy
akkor is ki akarunk-e lpni, ha ez a folyamat megszntetst jelenti:
560
B.1 . gdb
(gdb) quit
Adebugging session is active.
Inferior 1 [process 2 052 1] will be killed.
Quitanyway? (y or n)
B.1.2. A gdb leggyakrabban hasznlt parancsai
Foglaljuk ssze az elz pldban ltott gdb parancsokat. Minden parancsnak
ltezik rvidtett formja is, gy a B.1. tblzatban ezeket is feltntetjk.
B.1 . tblzat. A gdb parancsok
Parancs Rvid. Magyarzat
run r A folyamat elindtsa
next n A kvetkez sorra (next line) ugrs
step s Belps egy fggvnybe (step into)
print p Kirja (print) a megadott vltoz aktulis rtkt
backtrace bt A verem megjelentse
list l A forrskd kilistzsa az aktulis pozci krnykn
continue c A program futsnak folytatsa
Ctrl + D A program lelltsa (az EOF jel)
quit q Kilps a gdb programbl
Ha elfelejtennk valamelyik parancs szintaxist, akkor a help paranccsal
krhetnk segtsget.
B.1.3. A gdb indtsa
A gdb-t tbbfle argumentummal s opcival indthatjuk, s ezzel befolysol-
hatjuk a hibakeressi krnyezetet.
A leggyakrabban egy argumentummal hasznljuk, ez a vizsgland prog-
ram neve:
561
B fggelk: Hibakeress
m a program mellett megadhatjuk msodik paramterknt a core llo-
mnyt:
115
g 1,b .. :wogram><coref j l>
A core fjl helyett azonban megadhatunk egy folyamatazonostt (pid) is, ha
egy ppen fut processzt szeretnnk megvizsglni:
<pid>
Ilyenkor a gdb a megadott pid-szm folyamathoz kapcsoldik. Meglltja a
folyamatot (stop), hogy lehetsgnk legyen trspontokat belltani. Ezt k-
veten folytathatjuk a processz futtatst a continue paranccsal.
Az elzekben felsorolt funkcikat a gdb elindtsa utn parancsokkal is
elrhetjk, ha szksg van r.
Az eddig emltett funkcik mellett a gdb-t hasznlhatjuk tvoli hibakere-
ssre is, amikor egy msik gpen fut alkalmazs llapott kvetjk figyelem-
mel. Ezt olyankor alkalmazzuk, amikor az adott gpen nem vgezhetjk el a
hibakeresst. Pldul kernel vizsglatnl vagy korltozott erforrsokkal
rendelkez eszkz esetben. Ilyenkor a kt gpet soros nullmodem-kbellel
vagy Etherneten kell sszektnnk. Utbbi esetben egy TCP/IP kapcsolaton
keresztl folyik a kommunikci. Ha a kernel mkdst akarjuk tvolrl k-
vetni, akkor a kernelbe bele kell fordtanunk, majd be kell kapcsolnunk a
megfelel funkcikat. Alkalmazsok esetn tipikusan egy gdbserver nev al-
kalmazst futtatunk a tvoli gpen, amellyel a gdb kommuniklni tud.
B.1.4. Trspontok: breakpoint, watchpoint,
catchpoint
A trspont meglltja a program futst, amikor az elr egy meghatrozott
pontra. Minden trsponthoz megadhatunk plusz feltteleket is. Belltsuk
ltalban a break paranccsal s paramtereivel trtnik.
Trspontknt megadhatjuk a program egy sort, egy fggvnynevet
vagy egy egzakt cmet a programon bell:
break FUGGVENY
break FAJLNEV:FUGGVNY
115
Amikor a processz egy programhiba kvetkeztben lell, gyakran egy core nev llomny
jn ltre a processz munkaknyvtrban. (Ltrehozst az adott shell limitbelltsai sza-
blyozzk. A bash shell esetn ulimit -c. Emellett a kernel belltsai befolysolhatjk a
pontos llomnynevet s a ments helyt.) Ez az llomny a processz memria-pillanatfel-
vtelt tartalmazza a hiba pillanatban. A gdb program kpes ezt az llapotfelvtelt rtel-
mezni, s a fejleszt szmra rthet formban megmutatni a processz pillanatnyi llapott
a hiba bekvetkeztekor.
562
B.1. gdb
A forrsllomny a FUGGVENY fggvny meghvsnl helyezi el a trs-
pontot (lekezeli a C++-fggvny felldefinilst is):
break +OFFSET
break -CFFSET
Az aktulis pozcitl megadott szm sorral vissza vagy elrbb helyezi el a
trspontot:
break SORSZAM
Az aktulis forrsllomny SORSZAM sorban helyezi el a trspontot:
break FA31-N V: SORSZAM
A FAJLNEV forrsllomny SORSZAM sorban helyezi el a trspontot:
break m.
A CIM cmen helyezi el a trspontot:
break
Argumentum nlkl az aktulis verem kvetkez utastsra helyezi el a t-
rspontot:
break if COND
A trsponthoz feltteleket is megadhatunk. A COND kifejezs minden alka-
lommal kirtkeldik, amikor a trspontot elri a processz, s csak akkor ll
meg, ha az rtke nem nulla, vagyis igaz.
A watchpoint olyan specilis trspont, amely akkor lltja meg a prog-
ram futst, ha a megadott kifejezs rtke vltozik. Viszont nem kell megadni
azt a helyet, ahol ez megtrtnhet. A watchpointokat klnbz parancsokkal
llthatjuk be:
watch KIFEJEZES
A gdb meglltja a folyamatot, amikor a program mdostja, rja a KIFEJEZES
kifejezs rtkt. A kifejezs ltalban egy vltoz neve. Ebben az esetben, ha a
vltoz rtke valahol mdosul, akkor ott a program futsa megll. A felttelt
korltozhatjuk, hogy csak akkor lltsa meg a folyamatot, ha egy bizonyos
szl mdostja az rtket.
Az rtk olvasst is figyelhetjk:
rwatch KIFEJEZES
563
B fggelk: Hibakeress
Ebben az esetben a watchpoint akkor lltja meg a futst, amikor a program
kiolvassa (read) a KIFEJEZES kifejezs rtkt.
A kettt kombinlhatjuk is:
awatchKIFEJEZES
Ebben az esetben a watchpoint mind az olvasskor, mind az rskor megllt-
ja a program futst.
A belltsok utn a watchpointokat ugyangy kezelhetjk, mint a norml
trspontokat. Ugyanazokkal a parancsokkal engedlyezhetjk, tilthatjuk, t-
rlhetjk ket.
A catchpoint egy msik specilis trspont, amely akkor lltja meg a
program futst, ha egy specilis esemny kvetkezik be. Ilyen esemny lehet
pldul egy C++-programban bekvetkez kivtel (exception) vagy egy knyvtr
betltse. Ugyangy, mint a watchpointoknl, itt is tbb lehetsgnk van a t-
rspont belltsra. A catchpoint ltalnos belltsi formja a kvetkez:
Itt az ESEMENY kifejezs a B.2. tblzat elemei kzl valamelyik:
B.2. tblzat. Esemnyek s lersuk
jE
throw Egy C++-kivtel keletkezsekor
catch Egy C++-kivtel lekezelsekor
exec Az exec fggvny meghvsakor
fork
vfork
load [KONYVTARNEW
Az fork fggvny meghvsakor
Az vfork fggvny meghvsakor
A KONYVTARNEV knyvtr betltsekor
unload [KONYVTARNEW A KONYVTARNEV knyvtr eltvoltsakor
A catchpointokat ugyangy kezelhetjk a bellts utn, mint a korbbi t-
rspontokat.
Ha tbb trspontot is elhelyeznk a projektnkben, akkor nehz minde-
gyiket fejben tartani. m erre nincs is szksg, mert knnyen kilistzhatjuk
ket:
infobreak points
A lista tartalmazza a trspontok indext is, amellyel knnyen hivatkozha-
tunk rjuk tiltsnl, engedlyezsnl vagy trlsnl.
564
B.1. gdb
Ha a futtats sorn egy trspont elvgezte a feladatt, gyakran trlni
akarjuk. Ez nem felttlenl szksges, hiszen trls nlkl is tudjuk folytatni
a futtatst, m a ksbbiekben zavar lehet a trspont jelenlte. A trspon-
tok trlst fggetlenl a tpusuktl a delete vagy a clear paranccsal vgez-
hetjk el.
Ha a meglls utn a megllst okoz trspontot szeretnnk trlni, ak-
kor ezt a clear parancs egyszer meghvsval tehetjk meg:
cl gr
A msik lehetsgnk, hogy a trspontot a helyzete alapjn azonostjuk, ha-
sonlan, mint a break parancsnl:
Ahogy korbban sz volt rla, a trspont trlst az indexe alapjn is elv-
gezhetjk. Erre a delete parancs szolgl:
del e
te Wreakpoi nt
TO:
v} ,
r
A TARTOMANY paramterben hivatkozhatunk egy trspontra, de megad-
hatunk tbb indexet is, st akr egy tartomnyt is a trspontok listjban.
Ha elhagyjuk a paramtert, akkor az sszes trspontot kitrljk.
Nemcsak trlhetjk a trspontokat, hanem le is tilthatjuk 'ket. A tilts
sorn ugyangy nem lesz hatsuk, mint trls esetn. m ha a ks'bbiek so-
rn ismt szksgnk lesz az inaktivlt trspontokra, akkor knnyedn jra
engedlyezhetk.
Tiltskor s engedlyezskor a trspontoknak tbb llapotuk is lehet:
Engedlyezett trspont, amely meglltja a program futst.
Letiltott trspont, amelynek nincs hatsa a folyamatra.
Egyszer engedlyezett trspont, amely meglltja egyszer a program
futst, m automatikusan letiltott llapotba kerl.
A tbbszr engedlyezett trspont meghatrozott alkalommal megl-
ltja a folyamatot, mieltt letiltott llapotba kerl.
Egyszer engedlyezett trspont, amely a folyamat meglltsa utn
automatikusan trldik. A tbreak paranccsal llthat be a break pa-
rancsnl ltottak szerint.
565
B fggelk: Hibakeress
A trspontot tiltani a disable paranccsal lehet a delete parancsnl megismer-
teknek megfelelen:
d s b le [b i-ea kpoint s] ETARTOMANYj
Engedlyezsre tbb lehetsg is adott az engedlyezs fajtjtl fggen, vi-
szont minden esetben az enable parancsot hasznljuk. Az egyszer enged-
lyezs a kvetkez:
a b le [b r eRkPOns]
Egyszeri engedlyezs az albbiak szerint trtnik:
ena b le [b r e kpoint s] once TARTOMANY
Tbbszri engedlyezs pedig eszerint:
ena b le [b r ea kpoint s] SZAMTARTOMNY
A SZM paramter a szmll kezdrtkt tartalmazza. Minden alkalom-
mal, amikor a trspont meglltja a futst, a szmll eggyel cskken. Ami-
kor a szmll elri a 0 rtket, akkor a trspont automatikusan letiltdik.
Egyszeri engedlyezs automatikus trlssel az albbi:
ena b le [b r ea kpoint s] delet e TARTOMANY
B.1.5. Data Display Debugger (DDD)
A DDD (Data Display Debugger) olyan GNU-projekt, amelynek az a clja,
hogy gr a fikus elt t (front-end) segtsgvel megknnytse a parancssoros
hibakeresk, pldul a GDB, a DBX, a WDB, a Ladebug, a JDB, az XDB, a
Perl debugger vagy a Python debugger hasznlatt.
A DDD rgi, m manapsg is gyakran hasznlt program. A szoksos el-
ttfunkcik mellett (pldul a forrsllomnyok megtekintse) tbb jelents
szolgltatssal is rendelkezik. Ilyenek az interaktv grafikus adatbrzol-
sok, ahol az adatstruktrk grfknt vannak megjelentve. De kpes akr
grafikonokat is kszteni az adatainkbl.
A DDD fellett mutatja a B.1. bra.
Ennek rszletei a kvetkezk:
Az Ada t ablak az aktulis megfigyelt program adatait mutatja.
A For r skd ablak a program forrskdjt mutatja.
566
Mensv
Eszkzsv
Adatablak
b$:-*-me


F1L
0121111111M111111
MEll=

- Y.
II lin
,
t
114 1



tc, t.aori altat 11111C111
Itg_ttetttat thrt)
t
Ott .14
Ittt M. L'St
Itat-' t S
-
ot
lOtt ...t no. L st
Ittt-Artt- It- 111
atm. t tit- tttts tt
*ot, t 11 t:
4.140. I tt;
Forrskdabtak-
litt tett11 10.1t
Gpikd-abtak
tL/W1,p).1191-U.IW11.. .1 *4 Wlf< :
,
10 3 tl l :[.+
Ma .11,4_1nl,j0 .1% o. 4.1 141:a)..bs.
orwro
Hibakeres konzol
llapotsor
B.1. bra. A DDD fellete
.11t1
100 44410/ *(11 ..0 ~Ment
vol. IisAg *00~ I
FI* MA*, ot itst-mot->lert-Heel fia m ca , 4
B.1. gdb
A Hibakeres konzol fogadja a hibakeres (debugger) parancsokat,
s megmutatja ezek zeneteit.
A Parancsok a leggyakrabban hasznlt parancsok gombjait tartal-
mazza.
A Gpi kd ablak az aktulis gpi kd programot mutatja.
Ft!
Parancsok
Grdtsv
tmretez
-rtkjelzs
Fogtaltsgjetz
B.1.6. Az IDE-k beptett hibakeresje
Az integrlt fejleszti krnyezetek (IDE) gyakran tartalmaznak hibakerest.
Ezek valjban grafikus gdb-elttek. Gyakran a gdb funkcionalitsnak sz-
les skljt teszik elrhetv. Ugyanakkor mindezt a fejleszti krnyezeten
bell vgezhetjk el, ezrt hasznlatuk nagyon knyelmes.
Ha begyazott fejlesztseken dolgozunk, a fejleszti krnyezet gyakran
mg a tvoli hibakeresst is biztostja. Ilyenkor az alkalmazst tviszi a
teszteszkzre, majd a gdbserver programmal indtja el. A fejleszti gpen el-
indtva a gdb programot, az kapcsoldik a begyazott eszkzhz, s mris v-
gezhetjk a hibakeresst a fejleszti krnyezeten bell. Ilyen szolgltatst
pldul az elterjedt Eclipse IDE is tartalmaz.
567
B fggelk: Hibakeress
B.2. Memriakezelsi hibk
Korbban mr emltettk, hogy a C s a C++ nyelv hasznlatakor klnbz
memriakezelsi hibkat ejthetnk, amelyeknek feldertse nehz feladat.
Ennek megoldsra szmos eszkz szletett. Az albbiakban ezekbl ismerte-
tnk nhnyat.
Vizsglataink eltt lltsunk el egy hibs programot, amely az llator-
vosi l" szerept tlti be. A memriakezelsi hibktl hemzseg kdunk le-
gyen a kvetkez:
1 /"
2 "Hi bas kod
3 */
4
5 #include <stdlib.h>
6 #include <stdio. h>
7 #i nclude <string .h>
8
9 char gl obal i s [5] ;
10
11 int mai n(voi d)
12 {
13 char 1 okal i s [5] ;
14 char* dinamikus;
15
16 // 1. tuliras (kicsit)
17 dinami kus=mal loc(5);
18 strcpy(dinamikus, "12345") ;
19 printf("1: %s \ n" , dinamikus);
20 free(dinami kus);
21
22 // 2. fel szabadi tott terulet hasznalata
23 strcpy(dinamikus, "12345") ;
24 printf("2: %s \n" dinamikus);
25
26 // 3. tuliras (nagyon)
27 dinami kus=mal 1 oc(5) ;
28 strcpy(dinamikus, "12345678") ;
29 printf("3: %s \ n" , dinamikus);
30
31 // 4. el e i ras
32 "(dinamikus-1)i \ 0 ;
33 printf("4: %s \n" , dinamikus);
34
35 // memoriaszivargas! ! !
36
37 // 5. lokalis valtozo tuli rasa
38 strcpy(lokal i s , "12345") ;
39 printf("5: %s \n" , 1 okal i s) ;
40
568
B.2. Memriakezelsi hibk
41 // 6. lokalis valtozo eleirasa
42 lokalis[-1]=' \O' ;
43 printf("6: %s\n", lokalis);
44
45 // 7. globalis valtozo tul rasa
46 strcpy(globalis, "12345");
47 printf("7: %s\n", globalis);
48
49 // 8. globalis valtozo eleirasa
50 globalis[-1]-=' \O' ;
51 printf("8: %s\n", globlis);
52
53 return 0;
Ez a kd hromfle memrit allokl, s ezekkel kvet el hibkat. Az els tpus
a dinamikusan, malloc-kal alloklt memria, a msodik loklis vltoz, amely a
program vermben helyezkedik el, a harmadik pedig globlis vltoz, amely egy
kln rszen tallhat. Mindhrom esetben tlrjuk (buffer overrun) a lefoglalt
tartomnyt, illetve egy-egy byte-ot elrunk Ezek mellett a kd tartalmaz egy
mr felszabadtott memriarszhez val hozzfrst s egy fel nem szabadtott
memriarszt, az gynevezett memriaszivrgst (memory leak) is.
Elsre a kdot lefordtva s lefuttatva az albbit ltjuk:
$ gcc -ggdb -Wall -o bugos bugos.c
. /bugos
1: 12345
2: 12345
3: 12345678
4: 12345678
5: 12345
6: 12345
7: 12345
8: 12345
tmutat Habr a fenti programot bven ellttuk hibkkal, mgis ltalban problma nlkl
lefut. Ez azonban nem jelenti azt, hogy ezek a hibk lnyegtelenek. A tlrsok idvel a prog-
ram vratlan s elsre megmagyarzhatatlannak tn sszeomlshoz vezethetnek. A mem-
riaszivrgsok pedig idvel felemsztik a szmtgp memrijt.
A kvetkezkben megismerhetnk nhny eszkzt, amely ennl tbbet mutat
szmunkra.
B.2.1. Malloc hibakeresk
A malloc hibakeresk csaldjba olyan hibakeresst segt eszkzk tartoz-
nak, amelyek a malloc() s a free() fggvnyek felldefinilsval rik el a cl-
jukat, s segtik a memriakezelsi hibk megtallst. Lnyegben fejleszti
knyvtrak, amelyeket felhasznlunk a programunkban.
569
B fggelk: Hibakeress
A memriakezelsi hibk f problmja az, hogy nehezen detektlhatk,
mivel a folyamat a sajt adatterletn vgez illeglis mveleteket. Ezt sem az
opercis rendszer, sem a hibakeres nem rzkeli. Ezrt a f clunk az ilyen
jelleg a hibk rzkelse, lthatv ttele.
A malloc hibakeresk az opercis rendszer virtulismemria-kezel
rendszert hasznljk arra, hogy lthatv tegyk a memriakezelsi hibin-
kat. A szoksos allokcis mechanizmust lecserlik egy mdostott algorit-
musra, amely elri, hogy memriakezelsi hiba sorn a folyamat tiltott lapra
rjon. Ezt rzkelve az opercis rendszer az adott ponton segmentation fault
hibval lelltja a folyamatot. Ezltal a hiba lthatv vlik, s a gdb prog-
rammal knnyen elkaphatjuk".
A klnbz hibk feldertshez ms-ms stratgit hasznl a rendszer.
Ezek a megoldsok egyes esetekben tik is egymst, ezrt meg kell adnunk,
hogy ppen melyik hibkat vizsgljuk.
Vegyk sorra a hibkat s a feldertskre alkalmazott stratgikat.
B.2.1.1. Memriaterlet tlrsa
A tlrs hibjt akkor kvetjk el, ha a lefoglalt terlet utn runk. Vagyis
azt kell elrnnk, hogy a foglals utni terlet rsvdett legyen. m csak
memrialapokat tehetnk rsvdett. Ezrt a clunk elrshez a memria-
allokci sorn 2 lapot kell alloklnunk, s az egyes terleteket az albbiak
szerint kell elrendeznnk (B.2. bra):
Foglals
1. lap 2. lap
B.2. bra. Tlrs figyelse
A lefoglalt terletet az els lap vgre helyezzk el. gy ha tlrnnk, akkor bele-
runk a msodik, vdett lap terletbe. Ez azonnal egy kivtelt okoz, amelynek
hatsra az opercis rendszer megszaktja a folyamatot. gy pontosan rzkel-
hetjk a hiba helyt. Ugyanakkor lthat, hogy ha tlrst figyelnk, akkor az
elrst nem tudjuk rzkelni, ezt a rszt teht nem tudjuk levdeni.
m ebben az esetben is bevethetnk egy msodlagos vizsglatot. Ha a fogla-
ls sorn az els lap nem hasznlt rszt feltltjk egy meghatrozott byte-r-
tkkel (mgikus szm), akkor a felszabadts sorn ellenrizhetjk, hogy nem
rzkeljk-e mdosts nyomt. Ha valahol mdosult az rtk, akkor figyelmez-
tetni tudjuk a fejlesztt, hogy vizsglja meg a programot elrsi hibra.
A mgikusszm-mdszer nem olyan hatkony, mint a lapok hasznlata.
Egyrszt nem rzkeli, ha ppen a mgikus szmrtket rjuk a tiltott terlet-
re, msrszt a hibt csak a felszabadtsnl rzkeljk, gy igazbl nem tud-
hatjuk, hogy hol kvetkezett be. Figyelmeztet rendszernek azonban megfelel.
570
B.2. Memriakezelsi hibk
B.2.1.2. Elrs
A tlrsnl hasznlt mdszerek alkalmasak az elrs vizsglatra is. Mivel
most azt ellenrizzk, hogy trtnt-e a lefoglalt terlet el rs, ezrt csak
meg kell fordtanunk az elrendezst (B.3. bra):
Foglals
1. lap 2. lap
B.3. bra. Elrs figyelse
Ebben az esetben akkor okozunk laphibt, ha a lefoglalt terlet eltti lapra
runk. A tlrs ellen azonban vdtelenek vagyunk, ezrt a msodlagos md-
szerrel figyelnnk kell az elfordulst.
B.2.1.3. Felszabadtott terlet hasznlata
Elfordulhat, hogy a felszabadtott terletet a program tovbbra is hasznlja.
Ennek kidertse egy egyszer mdszerrel trtnhet. A foglalsokat a free()
fggvny hvsakor valjban nem szabadtjuk fel, csak vdett tesszk a lapot
a tovbbi hasznlattal szemben. Ha mgis hasznln mg a folyamat, akkor
az automatikusan laphibt okoz, s a vdelmi belltsok megsrtse miatt az
opercis rendszer meglltja a futst. Termszetesen ez a mdszer rendkvl
memriapazarl.
B.2.1.4. Memriaszivrgs
A memriaszivrgst a malloc hibakeresk knyvelses mdszerrel tudjk
felfedni. Knyvelnek minden memriafoglalst s felszabadtst Amikor a fo-
lyamat befejezdik, akkor a hibakeres eszkz sszeveti a foglalsokat a fel-
szabadtsokkal, s ha nem tall meg minden prt, akkor kilistzza, hogy
mely foglalsok nem lettek felszabadtva. Termszetesen azt nem tudhatja az
eszkz, hogy hol kellett volna elvgeznnk a felszabadtst. gy a fejleszt fe-
ladata megtallni az allokcihoz tartoz felszabadts helyt.
Nem minden malloc hibakeres tmogatja a memriaszivrgs feldert-
st, de tallhatunk olyan eszkzt, amely implementlja ezt a mdszert.
B.2.1.5. A malloc hibakeresk korltai
tmutat Mivel a malloc hibakeresk a malloc() s a free0 fggvnyek felldefinilsval
rik el hatsukat, ezrt csak dinamikus allokcik vizsglatra hasznlhatk. Csak itt hvdnak
meg ezek a fggvnyek.
571
B fggelk: Hibakeress
Ugyancsak korltot jelent a jelents memriaigny. A fejleszti gpet el kell
ltnunk memrival, hiszen minden egyes allokci minimum ktlapnyi ter-
letet foglal le a valsgban. (4 kB-os lapokkal szmolva ez 8 kB.) Ha a felszaba-
dtott terleteket is vdjk, akkor a foglalsok eltartanak a program futsnak
a vgig.
B.2.2. Electric Fence
Az Electric Fence egy elterjedten hasznlt malloc hibakeres implementci.
Br ez az eszkz a memriaszivrgs vizsglatra nem hasznlhat, a korb-
ban emltett msik hrom mdszert tartalmazza. Emellett sok ms malloc
hibakeresvel ellenttben az Electric Fence a hibs olvassokat is detektlja.
De legnagyobb elnyeknt taln azt lehet megemlteni, hogy szinte minden
Linux-disztribci tartalmazza.
Hasznlatakor azonban vegyk figyelembe, hogy csak C-programok ese-
tn alkalmazhat, mivel nem tartalmazza a C++ new s delete opertorainak
felldefinilst.
B.2.2.1. Az Electric Fence hasznlata
Az Electric Fence a C knyvtr norml malloc() fggvnyt cserli le a sajt
specilis allokcis rutinjra. gy egyetlen feladatunk, hogy a libefence.a vagy
a libefence.so knyvtrllomnyt hozzkapcsoljuk a programunkhoz. Ezt kt-
flekppen tehetjk meg.
A -lefence argumentummal fordtskor hozzlinkelhetjk a knyvtrllo-
mnyt a programunkhoz. Ez a pldaprogramunknl a kvetkez:
7`4feric"
A msik lehetsg dinamikus linkels esetn az LD_PRELOAD krnyezeti
vltoz hasznlata. Ezzel megadhatjuk, hogy a knyvtrllomny a program
futsa eltt betltdjn:
kOkl
vagy
A kt megolds kzl az utbbit javasoljuk, mert az els esetben a parancs
kiadsa utn a shellben indtott sszes program az Electric Fence hasznlat-
val fut le, ezzel is pazarolva az erforrsokat.
572
B.2. Memriakezelsi hibk
Ha ezek utn lefuttatjuk a programunkat, akkor mr nem garzdlkod-
hat" szabadon. Az Electric Fence vdelmi algoritmusai felfedik a hibt:
$./bugos
ElectricFence2 .2 .0Copy right(C)1987-1999BruceP erens
1:12 3 45
Segmentationfault
Mint lthat, az Electric Fence nem mondja meg, hol a hiba, viszont sokkal
rzkelhetbb teszi, s gy egy hibakeresvel, pldul a gdb-vel, megvizsgl-
hatjuk. (Ehhez termszetesen a programnak rendelkeznie kell a hibakeressi
informcikkal is.)
Esetnkben ez az albbiak szerint alakul:
$gdb./bugos
GNUgdbRedHatLinux(5.2 -2 )
Copy right2 002 F ree SoftwareFoundation,Inc.
GDBisfreesoftware,cov eredby theGNUGeneralP ublicLicense,
andy ouarewelcometochangeitand/ordistributecopiesofit
undercertainconditions.
ThisGDBwasconfiguredas"i3 86-redhat-Linux"...
(gdb)
Ha dinamikusan szeretnnk hozzadni a knyvtrllomnyt, akkor az alb-
biakra is szksgnk van:
(gdb)setenv LD_P RELOAD=libefence.so.0.0
Ezek utn megkezdhetjk a program vizsglatt:
(gdb)r
Startingprogram:/home/tomcat/bugos
[NewThread102 4(LWP 2 672 7)]
ElectricFence2 .2 .0Copy right(C)1987-1999BruceP erens
1:12 3 45
P rogramreceiv edsignalSIGSEGV,Segmentationfault.
[SwitchingtoThread102 4 (LWP 2 672 7)]
0x42 0807a6instrcpy ()from/lib/i686/libc.so.6
(gdb)where
#0 0x42 0807a6in strcpy () from/lib/i686/libc.so.6
#1 0x080484fcin main () atbugos.c:2 3
#2 0x42 017589in libc_start_main ()from/lib/i686/libc.so.6
(gdb)
Mint lthat, a 2 3. sorban mris elkapott egy hibt a rendszer:
2 3 strcpy (dinamik us,"12 3 45");
573
Bfggelk: Hibakeress
Ez az a hely, ahol a felszabadtott memriaterletre prbltunk rni. Ha ezt a
sort megjegyzss alaktjuk, akkor a 2 4 . sorban, a rendszer a felszabadtott
terlet olvassnl rzkeli a hibt. gy tovbbhaladva a kvetkez hiba a 2 8.
sorban tallhat, ahol jelentsen tlrjuk a lefoglalt memrit. Ezt is eltvo-
ltva tovbbi hibt nem rzkel, pedig mint lthat bven maradt mg.
B.2.2.2. A Memory Alignment kapcsol
Lthattuk, hogy az Electric Fence tszaladt az els tlrson, ahol a tarto-
mnyt csak egy byte-tal rtuk tl. A problma forrsa a memriailleszts.
A modern processzorok a memrit tbb-byte-os rszekre osztjk. Ez 32 bites
processzorok esetn 4 byte. A malloc0 ltalnos implementcija is ennek
megfelelen kerektve foglalja le a memrit. Alaprtelmezett belltsok
mellett az Electric Fence is ezt a mdszert alkalmazza, ezrt nem vette szre
az 1 byte-os differencit.
Ahhoz, hogy ezt a hibt megtalljuk, az Electric Fence-nek meg kell ad-
nunk, hogy 1 byte-os illesztst hasznljon. Ezt az EF ALIGNMENT krnye-
zeti vltoz 1-re lltsval tehetjk meg:
(gdb)set env EF_ALIGNMENT=1
(gdb)r
startingprogram:/home/tomcat/bugos
[NewThread102 4(LwP 2 6810)]
ElectricFence2 .2 .0copy right(C)1987-1999 Bruce Perens
P rogramreceiv edsignal SIGSEGV, Segmentationfault.
[switchingtoThread102 4(LWP 2 6810)]
0x42 0807a6instrcpy ()from/lib/i686/libcso.6
(gdb)where
#00x42 0807a6instrcpy ()from/lib/i686/libc.so.6
#10x080485f8inmain()atbugos.c:18
#2 0x42 017589in libc_start_main()from/lib/i686/libc.so.6
(gdb)
gy mr megtallta a 18. sorban tallhat kis tlrsunkat is.
B.2.2.3. Az elrs
Ahogy kiderlt, ez idig nem sikerlt detektlnunk a elrs esett, vagyis
amikor a lefoglalt terlet el rtunk egy byte-ot. Az EF PROTECT BELOW
vltoz 1-re lltsval azt krhetjk az Electric Fence-tt, hogy kapcsoljon t
az elrs vizsglatra. Termszetesen ilyenkor a tlrst nem tudja rzkel-
ni, mert a memrialapok adott mrete miatt nem vdhetjk mindkt oldalrl
a lefoglalt terletet:
574
B.2 .Memriak ezel sihib k
(gdb)setenv EF_P ROTECT_BELOW=1
(gdb)r
Startingprogram:/home/tomcat/bugos
[NewThread102 4(LWP 2 6868)]
ElectricFence2 .2 .0Copy right(C)1987-1999BruceP erens
1:12 3 45
3 :12 3 45678
P rogramreceiv edsignalSIGSEGV,Segmentation fault.
[SwitchingtoThread102 4(LwP 2 6868)]
0x08048658inmain()atbugos.c:3 2
3 2 (dinamik us-1)='\0';
(gdb)
B.2.2.4. Az Electric Fence tovbbi lehetsgei
Az eszkz hasznlatakor a B.3. tblzatban lthat kapcsolkkal tallkozha-
tunk mg:
B.3. tblzat. Az Electric Fence tovbbi kapcsoli
Vltoz Jelents
EF_PROTECT_FREE Ha rtke 1, akkor a felszabadtott memriaterletek
kiosztsa nem trtnik meg jra, hanem a rendszer
letiltja 'ket.
EF ALLOW MALLOC 0 Ha rtke 1, akkor engedlyezi a 0 mret terletek
alloklst.
EF FILL Amikor 0 s 2 55 kztt van az rtke, akkor a lefoglalt
terlet minden byte-jt feltlti a rendszer ezzel az rtk-
kel, gy segti az inicializcis problmk kiszrst.
B.2.2.5. Erforrsignyek
Az Electric Fence rendelkezik a malloc hibakeresk ltalnos problmjval, a
jelents memriaignnyel. Ha a tesztelt kdban sok kismret memriaallok-
ci van, akkor az Electric Fence hasznlatval tbb nagysgrenddel megnhet
a memriafelhasznls. Termszetesen a helyzet tovbb romlik, ha a felszaba-
dtott terleteket vdjk, mert ilyenkor valjban nem szabadul fel memria.
Ezrt, ha azt tapasztaljuk, hogy hasznlatakor a rendszernek nagyon meg-
fogyatkozik a szabadmemria-kapacitsa, akkor ajnlatos a lapcsere- (swap)
terletet megnvelni.
575
B fggelk: Hibakeress
B.2.3. DUMA
A DUMA malloc hibakeres az Electric Fence tovbbfejlesztse. C- s C++-
programok esetben egyarnt hasznlhat. Emellett nhny tovbbi funkci-
val egszti ki az eldjt:
Minden memriaallokcis fggvny implementcijt tartalmazza,
gymint malloc(), calloc(), memalign(), strdupQ, operator new, opera-
tor new[1, free(), operator delete s operator deletelj. Ezrt hasznlhat
C++-programokhoz is.
rzkeli, ha nem megfelel felszabadtfggvnyt hasznlunk az
adott foglalshoz.
Tartalmazza a memriaszivrgs rzkelst is.
B.3. Valgrind
A Valgrindn
6
egy keretrendszer-hibakeres analizleszkzk ksztshez.
A Valgrind eszkzei kzt tallunk olyanokat, amelyek lehetv teszik a memria-
vagy szlkezelsi hibk feldertst, illetve teljestmnyanalzisek futtatst.
A Valgrind eredetileg az eddig ltott memriakezelsi hibk kiszrshez
kszlt. Idvel azonban odig fejldtt, hogy egy ltalnos keretrendszer lett
belle. m a memriakezels ellenrzst vgz memcheck modul tovbbra is
a rsze s egyben az alaprtelmezett eszkze.
A Valgrind maga egy virtulis gp, amely futsidej (just-in-time, JII) for-
dtsi technikkat hasznl a programok ellenrzshez. A rendszer elszr
tfordtja a programot egy kztes kdra, amely az eredeti kd egy processzor-
fggetlen formja. Az eredeti kdbl semmi sem fut a hosztprocesszoron. A kz-
tes kdot a Valgrind mr igny szerint szabadon mdosthatja. A hasznlt
Valgrind modul kiegszti a kdot az ellenrzsekkel. Vgl az elkszlt kztes
kdot visszafordtja a rendszer a hosztprocesszor ltal futtathat formtumra.
A transzformcik s a beszrt ellenrzst vgz kdrszletek termsze-
tesen jelents teljestmnyromlst okoznak. A lassuls mrtke nagyban fgg
a hasznlt modul ltal beszrt kdoktl is. Pldul a memcheck modul eset-
ben egy memria-hozzfrs akr 10-50-szer lassabban fut, mint natv futta-
tskor. Ebbl lthatjuk, hogy ebben az esetben a fejleszti gpnek jelentsen
ersebb CPU-ra van szksge.
116
A Valgrind weboldaln: http:/ /valgrind.org/ tovbbi rszletes lersokat tallhatunk az
eszkzrl.
576
B.3. Valgrind
A Valgrind felptse modulris s knnyen bvthet. Akr sajt modu-
lokat is kszthetnk hozz. Tovbb a csomaggal szmos jl hasznlhat
modul is rkezik:
Memcheck: A C- s C++-programokban elkvetett memriakezelsi
hibkat derti fel.
Cachegrind: A gyorsttr-hasznlatot s az elgazsokat analizl
eszkz. A processzor Il, Dl s a L2 gyorsttrt szimullja. A prog-
ram analizlsakor meghatrozza a sikeres s a sikertelen gyorst-
tr-hozzfrseket s a feltteles elgazsok jslsnak a tvedseit.
A rszletes statisztikk alapjn optimalizlhatjuk a kdunkat
Callgrind: A fggvnyhivatkozsi grf segtsgvel analizlja a gyor-
sttr-hasznlatot. Funkcii tfedik a Cachegrindt, m tbbet is
nyjtanak annl.
Helgrind: A szlkezelsi hibk feldertst segt eszkz. A tbbszl
alkalmazsainkat ellenrizhetjk vele, hogy helyesen vgeztk-e el a
szinkronizlsokat.
DRD: Szintn szlkezelsi hibk feldertsre szolgl eszkz. Funk-
cionalitsban hasonlt a Helgrindre, m eltr technikkat hasznl.
Massif: Rszletes heapprofilt kpes kialaktani a rendszeres llapot-
mentseknek ksznheten. Segt cskkenteni a programunk mem-
riaignyt.
DHAT: Egy msik heaphasznlatot analizl eszkz.
A tovbbiakban a memcheck s a helgrind modulokat trgyaljuk rszletesebben.
B.3.1. Memcheck
Ahogy korbban emltettk, a memcheck a Valgrind els s az egyik legfonto-
sabb eszkze. Ha nem adjuk meg, melyik eszkzt vlasztjuk, akkor ez az alap-
rtelmezett.
A memcheck feladata a memriakezelsi hibk kiszrse. A hibk szle-
sebb skljt kpes kimutatni, mint egy malloc hibakeres, s a CPU haszn-
lata is intenzvebb. A kvetkez hibkat vizsglhatjuk vele:
A malloc hibakeresknl ltott heapallokci tlrsa, elrs, felsza-
badtott terlet rsa. Veremterlet tlrsa.
Inicializlatlan vltozk rtkeinek a hasznlata.
Hibs felszabadtsok. Dupla felszabadts vagy a nem megfelel fog-
lal-felszabadt fggvnyprok hasznlata.
577
B fggelk: Hibakeress
A memcpy0 fggvny hasznlata sorn a forrs- s a clbufferek tla-
poldsa.
Memriaszivrgs.
tmutat Arra figyeljnk, hogy a memcheck eszkz sem kpes kimutatni a tlrsokat/elrso-
kat statikusan vagy a veremben alloklt vltozk esetben. A problmra megoldst az SGCheck
modul prbl nyjtani, m ez az eszkz jelenleg csak ksrleti llapotban van.
Az eszkzt a kvetkezkppen hasznlhatjuk:
gcc -ggdb -wall bugos bugos.
valgrind ,-tool~antebeck bugos
A Valgrind parancs --tool=memcheck kapcsoljval vlaszthatjuk ki a hasz-
nlni kvnt memcheck eszkzt. Ezutn mr csak a binris nevt kell megad-
nunk, s a Valgrind elkezdi az ellenrzst.
A standard kimenetre kldtt jelents tartalmazza a felfedezett hibkat.
A vgn tallhat sszegzsben pedig a lthatjuk a knyvelsbl kimutatott
memriaszivrgsokat.
Szmos opcival befolysolhatjuk a modul mkdst, a vizsglatok s a ri-
port rszletessgt. Clszer ezeket tanulmnyozni, hogy a kvnt eredmnyt
rjk el.
B.3.1.1. A memcheck modul mkdse
A memcheck modul mkdst gy a legegyszerbb elkpzelnnk, mintha az
egy virtulis processzor lenne, amely br mindazt vgrehajtja, amit a vals
processzor, de emellett tovbbi memriakezelssel kapcsolatos informcikat
knyvel s ellenriz. Ezekbl a plusz informcikbl mondja meg, hogy hibz-
tunk-e valahol. Nzzk, hogyan trtnik mindez.
Az adatterlet minden egyes bitjhez, belertve a processzorregisztereket
is, egy V bit (valid-Value) trsul, amely jelzi, hogy az adott adatbit rvnyes
vagy rvnytelen rtket tartalmaz-e. Ez a V bit egytt mozog az adatbittel.
Amikor a virtulis processzor az adatbyte-ot beolvassa a regiszterbe, akkor a
V biteket trol byte is az adattal tart. Ha a processzor mveleteket vgez az
adattal, akkor a V bitek rtknek kiszmtsa is megtrtnik. s vgl a
memriba rsnl a V bitek is visszardnak. Vagyis ezek a bitek mindig tar-
talmazzk azt, hogy a hozzjuk tartoz adatbit rvnyes adatot tartalmaz-e,
vagy sem.
gy vlhetnnk, hogy ettl kezdve a memcheck modulnak mr csak az a
feladata, hogy mindig ellenrizze ezt a V bitet, s ha rvnytelen adatot olva-
sunk be a virtulis processzorunkba, akkor mindig rjon ki figyelmeztetseket.
Ezzel csak az a baj, hogy idnknt a C-programok teljesen jogosan msolgat-
nak inicializlatlan adatokat. Nzzk meg a kvetkez pldt:
578
B.3 .Valgrind
structs
{
charel;
chare2 ;
} ;
struct s sl ={'
struct s s2 ;
s2 =sl;
' b'} ;
Ltrehozzuk az s nev struktrnkat, amely 2 byte helyigny. Ebbl a
struktrbl ltrehozzuk az s/ s az s2 vltozkat, s sl-et inicializljuk. Azt
gondolnnk, hogy ezek kt byte mret adatblokkok, de tvednk. A C-ford-
tk gy optimalizljk a kdunkat, hogy valjban a processzor sz mretre
kerektik fel, hogy gyorsabban fut kdot kapjunk. Ezrt 4 byte-os szmret-
tel szmolva az s/ kt inicializlatlan byte-ot is tartalmaz. Amikor az s/ rt-
kt tmsoljuk s2 -be, akkor az inicializlatlan rtkeket is msoljuk. s ez
egy teljesen szablyos mvelet, amelyrl nem szeretnnk hibajelentst kapni.
A megoldst az jelenti, hogy nem minden mveletnl valsul meg a V bit
ellenrzse, csak a kvetkez esetekben:
ha az adatbl memriacmet szmolunk ki, amelyre hivatkozunk;
ha az adatot elgazshoz hasznljuk fel;
rendszerhvsoknl.
Ha az ellenrzsek sorn kiderl, hogy olyan adatot hasznlunk fel, amely
rvnytelen biteket is tartalmaz, akkor ez egy hibajelentst eredmnyez.
Mr csak az a problma, hogy az rvnytelen adatot vagy az abbl szr-
maztatott adatokat mshol is hasznlhatjuk, s ez ugyanarrl a hibrl egy
hibajelentsi lavint indthat el. Ezrt a hibajelents utn az adott biteket
rvnyesnek jelli a rendszer.
A V bitek mellett minden egyes adatbyte-hoz tartozik egy A bit (valid-
Address) is, amely a cm rvnessgt jelzi. Az A bit jelzi, hogy az adott byte-
hoz jogosultak vagyunk-e hozzfrni. Minden alkalommal, amikor egy memria
cmet olvas, vagy r a program, akkor a memcheck modul leellenrzi a hozz-
tartoz A bitet, hogy jogosultak vagyunk-e a mveletre. Ha azt tallja, hogy
nem, akkor hibajelzst ad ki. Ezzel prhuzamosan a V bitet rvnyesadat-
llapotba lltja. Ez a lps furcsa lehet, de ha nem lenne gy, akkor az illeglis
memria-hozzfrsek kapcsn rengeteg inicializlatlan adatrl szl hibajel-
zst is kapnnk.
Az A bitek llapotai a kvetkez esetekben mdosulnak:
A program indulsakor a globlis adatterlet engedlyezett vlik.
Amikor terleteket alloklunk, akkor a lefoglalt byte-ok engedlyezet-
tek lesznek. (Csak a lefoglalt byte-ok, teht a szillesztsnek erre
nincs hatsa.)
579
B fggelk: Hibakeress
Amikor a veremmutatt lltja a rendszer, akkor gy mdostja a
memcheck az A bit rtkt, hogy a veremmutat feletti rsz enged-
lyezett lesz, az alatta lv rsz pedig tiltott.
Bizonyos rendszerhvsok, pldul az mmap(), mdosthatjk a me-
mriaterletek elrhetsgt. A memcheck az A biteket is ennek meg-
felelen lltja be ilyenkor.
A felsoroltakon kvl a program explicit mdon is krheti egyes adatterletek
hozzfrsi engedlynek a mdostst, de erre ritkn van szksg.
sszegezve: minden adatbyte-hoz tartozik 8 V bit s 1 A bit.
117
Amikor
egy memriacmhez hozzfrnk, akkor az A bit rtkt ellenrzi a rendszer.
Az adatmveletek sorn a V bitek rtke frissl. Egyes mveleteknl a V bit
rtkt is leellenrzi a rendszer, s szksg esetn hibt jelez. A hibajelzsek
sorn a ksbbi felesleges jelzsek elkerlse rdekben a V bit rtkt mdo-
stja a rendszer.
A memcheck a memriakezel fggvnyeket kiegszti az ellenrz bitek
kezelsvel az albbiak szerint (B.4. tblzat):
B.4. tblzat. Az ellenrz bitek kezelse
malloc, new rvnyes rvnytelen
calloc rvnyes rvnyes
realloc Ha az j foglals kisebb, akkor Ha az j foglals nagyobb, akkor
a klnbsg rvnytelen lesz. a klnbsg rvnytelen lesz.
free, delete rvnytelen rvnytelen
B.3.2. Helgrind
A Helgrind a Valgrind rendszer szlhibk detektlshoz kifejlesztett eszkze.
Azon tbbszl programoknl hasznlhat, amelyek a POSIX pthread fejleszti
knyvtrral kszltek. A modul a kvetkez hibatpusokat kpes rzkelni:
a POSIX pthread API hibs hasznlata;
a zrolsi sorrend problmibl add holtpontveszlyes helyzetek;
versenyhelyzet, amikor kzs adatterletekhez a megfelel zrolsok,
szinkronizlsok nlkl frnk hozz.
117
Valjban a kisebb helyhasznlat rdekben a memcheck modul tmrti a V bitek tro-
lst, gy nem lesz duplja a memriaigny.
580
B.3. Valgrind
A felsorolt hibatpusok gyakran eredmnyeznek vletlenszeren jelentkez
szinte reproduklhatatlan problmkat. Ezrt a fejlesztknek trekednie kell
ezeknek a hibknak a kikszblsre.
A helgrind modult a memcheck modulhoz hasonlan hasznlhatjuk:
valgrind --tool=helgrind fajlnev
A program futsa sorn folyamatosan produklja a jelentseket a tallt hi-
bkrl.
tmutat A szlkezelsi hibk detektlsa mg a memriakezelsi hibknl is nehezebb.
Ebbl fakadan a helgrind modul sok tves riasztst is ad. Ha a fejlesztend programunkat
tesztelni akarjuk vele, clszer mr a fejlesztsi fzisban bizonyos irnyelveket kvetnnk,
hogy minimalizljuk a tvedseket.
Ahhoz, hogy a helgrind modult eredmnyesen hasznlhassuk, az albbi sza-
blyokat kell kvetnnk:
Szlkezelsre csak a POSIX-fggvnyeket hasznljuk. Ha sajt mecha-
nizmusokat implementlunk a pthread fggvnyek megkerlsvel,
akkor a helgrind nem ltja megfelelen az esemnyeket. Sajnos a Qt
4 .x verzija sajt szlkezelst alkalmaz, m a KDE-programok miatt a
helgrind tartalmaz egy ksrleti llapot tmogatst erre az esetre.
Kerljk a lefoglalt terletek jrahasznostst. Ha pldul egy vl-
tozt az egyik szlbl hasznltunk, majd egy ponttl mr egy msik
szl kezeli, akkor lehet, hogy nem kell szinkronizlnunk a vltoz
hasznlatt, de a helgrind ezt nem tudhatja.
Lehetleg kerljk a feltteles vltozk hasznlatt. A helgrind csak
akkor kezeli helyesen, ha a vrakozs megelzi a jelzs kldst.
A helgrind a glibc 2 .3-as vagy jabb verzijnak hasznlatt ignyli a
helyes mkdshez.
Minden szl befejezdst vrjuk meg a pthreadjoin0 fggvnnyel,
s kerljk a lekapcsolt (detached) szlak hasznlatt, mert a hel-
grind csak gy tudja rzkelni a szl vgt.
A helgrind hasznlata eltt memcheckkel ellenrizzk a programot,
mert a memriakezelsi hibk rossz hatssal lehetnek a helgrind-re.
A printf(), az fprintf(), az fwrite(), az freadO fggvnyek tves verseny-
helyzet-jelzseket eredmnyezhetnek.
581
B fggelk: Hibakeress
B.4. Rendszerhvsok monitorozsa: strace
Az strace hasznos diagnosztikai, hibakeres eszkz. ltalnossgban az strace
lefuttatja a paramterknt megadott programot, s monitorozza a folyamat
rendszerhvsait s azokat a jelzseket, amelyeket kap. Az sszes rendszerh-
vst a paramtereivel egytt a szabvnyos hibakimenetre vagy a megadott
kimeneti llomnyba rja. A fejleszti knyvtrak, hibakeres knyvtrak
mkdsnek vizsglathoz, megismershez is hasznlhat.
B.5. Knyvtrfggvnyhvsok
monitorozsa: ltrace
Az ltrace program az strace programhoz hasonl feladatot lt el azzal a klnb-
sggel, hogy a megosztott knyvtrak fggvnyeinek hasznlatt monitorozza.
Emellett kirja a rendszerhvsokat s a folyamat ltal kapott jelzseket is.
Az ltrace program is paramterknt vrja a futtatand program nevt, s
a futs ideje alatt kirja az rzkelt hvsokat a szabvnyos hibakimenetre.
B.6. Tovbbi hasznos segdeszkzk
A splint segdprogram a hibakeressben lehet segtsgnkre. Megkeresi a
veszlyes, nem ajnlott megoldsokat a program forrskdjban. A program
rsa kzben gyakran kvetnk el olyan szinte szrevehetetlen kis hibkat,
amelyek ksbb a hibakeress sorn slyos fejtrst okozhatnak. Ilyen a nem
inicializlt vltozk hasznlata, a tmbk tlindexelse, rtkads az egyen-
lsg vizsglata helyett stb.
Az splint az ilyen hibk elkerlsben segt. A C/C++-forrsllomnyokat
dolgozza fel s rtelmezi gy, mint egy fordt. Tbb szempontbl vizsglja
azonban a kd helyessgt, s keresi a tipikus programozi hibkat, a gyans
rszeket.
Hasznlata a kvetkez:
splintprogram.c
Az splint szolgltatsai kztt megemltjk a tpusellenrzst, a paramter-
tadst, a lehetsges memriahibk feldertst.
582
B.6. Tovbbi hasznos segdeszkzk
Az indent segdprogram olvashatv teszi a C-forrskdot szkz, tabu-
ltor s hasonl jelleg karakterek beiktatsval. Segtsgvel tkonvertl-
hatjuk a forrskdot az egyik programozsi stlusbl egy msikba is.
Hasznlata a kvetkez:
ndent fa j 1 c
A fejleszti krnyezetek gyakran beptve is tartalmazzk az indent funkciona-
litst, gy mr szerkeszts kzben is rendezik a kdunkat.
Binris fjlok analzisnl jl jhet, ha hexadecimlisan is meg tudunk jelen-
teni egy fjlt. Ezt a hexdump segdprogrammal tehetjk meg. A paramterknt
megadott llomnyt a kvnt formtumban jelenti meg. Oktlis, decimlis, he-
xadecimlis, karakteres rtk kirsa kzl vlaszthatunk, de tovbbi paramte-
rekkel ennl pontosabban is megadhatjuk a kvnt kimenetet.
Leggyakrabban azonban paramterek nlkl a kvetkezkppen hasznljuk:
fa0
583
T rgymutat
A,
ablakkezel, 4 4 0, 4 4 1
acceptO, 2 69, 2 70, 2 71, 2 99, 308, 311,
4 63, 4 74
access_ok0, 369
adatfolyam, 104 , 14 9, 151, 2 72 , 2 78, 4 4 0,
519
adatmegoszts, 165
Address Resolution Protocol, 2 83
AF_INET, 2 91, 2 92 , 2 95-2 98, 301, 305,
310, 313, 318, 32 4 , 32 5
AF_INET6, 2 91, 2 92 , 2 95-2 98, 305, 310,
313, 318, 32 4 , 32 5
AF_UNIX, 2 76, 2 77, 2 79, 2 81
AF_UNSPEC, 2 95, 2 97, 300, 307, 316,
32 0, 32 8, 32 9
AI_ADDRCONFIG, 2 96, 2 97
AI_ALL, 2 96
AI_CANONNAME, 2 96
AINUMERICHOST, 2 96
AI_NUMERICSERV, 2 96
Al_PASSIVE, 2 96, 305, 306, 318, 32 4
ALV4 MAPPED, 2 96, 2 97
akci, 4 69, 4 72 , 4 75, 4 76
alacsony szint llomnykezels, 95, 14 9
alkalmazs, 37, 14 0, 2 4 1, 2 72 , 2 75, 308,
315, 334 , 353, 357, 361, 382 , 395,
4 04 , 4 06, 4 4 4 , 4 4 6, 4 4 8, 4 56, 4 60,
4 67-4 72 , 4 76, 4 80, 4 81, 4 84 , 4 89-4 92 ,
508, 509, 510, 511, 518, 52 3, 52 5,
530, 562
alkalmazskomponens, 4 91, 509
llomnyler, 4 4 , 96, 106, 107, 12 9, 130,
133, 134 , 136, 139, 191, 197, 2 39,
2 60, 2 65, 372
llomnyzrols, 14 3
ARP Cache, 2 83
aszinkron 1/0, 37
aszinkron jelzskezels, 2 50
asztali krnyezetek, 4 4 1
thelyezsnek, 81
atomi mveletek, 387, 389
ATOMIC_INITO, 388
atomict, 2 56, 2 58, 388, 389
automatikus vltozk, 54 5, 54 8, 54 9
azonostk, 19, 110, 186, 199, 2 00, 2 02 ,
354
B
bash, 2 0, 93, 379, 562
batch, 2 4
bepl modulok, 4 7, 64 , 68
big endian, 2 90
bindO, 2 68, 2 69, 2 72 , 2 73, 2 75, 2 78, 2 80,
2 90, 2 96, 32 7
binding, 2 68
block device file, 38
blokkolt 1/0, 12 6, 12 7, 12 8
Bottom half, 2 6, 4 14
breakpoint, 559, 562
bss, 81, 82 , 86
buffer overrun, 557, 569
C
call_usermodehelperO, 4 2 1
catchpoint, 562 , 564
CDE, 4 4 1
character device file, 38
ciklikus zrols, 366, 377, 378, 389-394
cmtartomny kezelse, 83
cmtartomny-randomizls, 92
class_createO, 355, 356
class_destroyO, 356
cleanup_moduleO, 34 4
closeO, 99, 14 1, 2 65, 2 70, 2 71, 2 75, 361,
4 73, 4 93, 507, 518
CMake, 555, 556
compat_ioctl, 367
compile, 538
Completely Fair Scheduler, 2 4
CONFIG_DEBUG_DRIVER, 378
Trgymutat
CONFIG_DEBUG_INFO, 378
CONFIG_DEBUG_KERNEL, 377
CONFIG_DEBUG_PAGEALLOC, 378
CONFIG_DEBUG_SLAB, 377
CONFIG_DEBUG_SPINLOCK, 377, 378
CONFIG_DEBUG_SPINLOCK_SLEEP,
378
CONFIG_DEBUG_STACK_USAGE, 378
CONFIG_DEBUG_STACKOVERFLOW,
378
CONFIG_IKCONFIG, 378
CONFIG_IKCONFIG_PROC, 378
CONFIG_KALLSYMS, 378
CONFIG_KALLSYSMS, 378
CONFIG_MAGIC_SYSRQ, 377
CONFIG_PROFILING, 378
configure, 555
configure.ac, 555
connectO, 2 69, 2 74 , 2 75, 2 90, 2 96
copy on write, 34
copy_from_user(), 387
copy_to_user(), 361
core, 4 3, 159, 2 4 0, 2 4 1, 382 , 562
counter, 2 3, 2 31, 2 32 , 4 00, 4 01, 4 04 , 4 16,
4 19, 4 2 0
cpu_relax(), 4 2 4
crashdump, 381
ctors, 82
Cs
csoportazonost, 15, 18, 109, 160, 199,
2 01
csoportvezet, 191
csvezetk, 36, 4 0, 4 3, 97, 114 , 12 0-12 5,
12 7, 12 8, 198, 2 75
D
data, 4 1, 81, 179, 182 -184 , 2 2 3, 2 2 4 , 2 2 5,
2 2 6, 2 87, 2 89, 362 , 363, 4 05, 4 06,
4 2 1, 4 2 5, 4 2 8, 4 2 9, 4 33, 4 34 , 4 54 ,
501-503, 507, 508, 52 5
datagram, 2 66, 2 72 , 2 75, 2 80, 318
DDD, 566, 567
debug, 2 1, 537, 54 0, 54 9
demand paging, 32
dmonok, 189, 193, 197
depmod, 34 8
deserializing, 333
Desktop Environment, 4 4 1, 535
devfs, 355
device drivers, 39
device file, 38
device_create(), 355
device_destroy(), 356
dinamikus linker, 61, 66, 67, 83-91, 93
dinamikus programbetlt, 68
dinamikus szimblumtblzat, 86, 87
dinamikusan betlttt programknyvtr,
67, 68, 72
dinamikusan linkelt megosztott prog-
ramknyvtr, 68
dirty page, 32
dokumentum/nzet, 4 89, 4 90, 4 94 , 504 ,
509, 530
dtors, 82
dup(), 2 71
E,
EADDRINUSE, 2 75
EAGAIN, 12 7, 12 8, 133, 14 6, 173, 176,
2 34 , 302 , 303, 398, 4 02 , 4 06
Eclipse, 556, 567
effektv csoportazonost, 199
effektv felhasznli azonost, 199
egyszer kirtkels, 54 6
Electric Fence, 572 -576
eljrslinkelsi tblzat, 85
eljrsvezrelt, 4 51
eltrbeli processzcsoport, 192 , 193
elrendezsnek, 2 39, 2 57, 2 58, 4 64
elrendezskezel, 4 4 5, 4 59, 4 61, 4 62 , 4 64 ,
4 65, 4 87, 4 94 , 4 99, 504 , 514 , 515, 52 8
eltols, 2 8, 2 9, 31, 304 , 379, 4 05
lvezrelt, 133
Emacs, 533
EPIPE, 303
epoch, 2 3
epollO, 311, 315
errno, 96, 97, 99, 102 , 103, 119, 12 0, 12 3,
12 4 , 12 7, 12 8, 130, 136, 14 1, 14 2 ,
14 4 , 14 6, 14 9, 157, 173, 176, 2 14 ,
2 4 8, 2 62 , 303, 304 , 361
esemnyvezrelt programozs, 4 50, 4 51
everything is a file, 36
execO, 309, 4 4 4 , 4 65, 4 66, 4 74 , 4 79, 4 82 ,
4 89, 511, 513, 515, 52 5, 52 9
EXPORT_SYMBOLO, 34 9, 350
EXPORT_SYMBOL_GPLO, 350
EXPORT_SYMTAB, 34 9
eXternal Data Representation, 333
586
Trgymutat
F
fjlrendszer, 19, 99, 109
fenti, 14 5, 14 6, 2 69
feladatnak, 191, 534
feladatok, 15, 104 , 2 68, 4 14
feladatvezrls, 191, 192
felhasznli azonost, 198-2 00, 2 53
felhasznli azonostba, 199
felhasznli cmtartomny, 11, 2 4 7, 34 2 ,
362 , 372 , 375, 385, 4 05, 4 2 1
felhasznli csoportazonostnak, 198
feltteles rtkads, 54 6
feltteles vltozkat, 2 2 8, 2 2 9
file_operations, 354 , 356, 357, 360, 361,
362 , 364 , 365, 366, 370, 399, 4 01,
4 04 , 4 07
fini, 82
first in, first out, 4 0
fizikai cm, 2 8, 2 9, 31, 35, 36, 2 83, 2 84 ,
384 , 385, 4 05, 4 09
fizikai nv, 57
flockO, 14 5
folyamatkezel, 13
forkO, 12 1, 157, 158, 159, 161, 194 , 2 71,
308
fazonost, 114 , 354 , 355
freeaddrinfoO, 2 95
FSF, 2 , 3, 4 , 533
Fully Qualified Domain Name, 2 99
futsidej dinamikus linker, 83
futex, 2 2 1
fggben lv, 2 4 5, 2 4 6, 2 4 7, 2 54 , 2 69
G
g++, 70, 71, 2 10, 4 58, 536
gai_strerrorO, 2 95, 2 99
gcc, 4 5, 4 8, 4 9, 51, 54 , 55, 58, 59, 60, 62 ,
63, 67, 82 , 89, 91, 169, 2 05, 2 10, 2 17,
357, 536-54 4 , 54 9-551, 554 , 558, 569,
572 , 578
gdb, 79, 378, 379, 380, 382 , 383, 537,
557-563, 567, 570, 573-575
gdbserver, 562 , 567
getaddrinfoO, 2 94 , 2 95, 2 98, 306, 308
getnameinfoO, 2 98, 2 99
getsockoptO, 32 6
getty, 14 , 190
GFP_ATOMIC, 385, 387, 4 12
GFP_KERNEL, 358, 385
GFP_NOFS, 385
GFP_NOIO, 385
GFP_USER, 385
globlis eltolstblzat, 84
GNAT, 536
GNOME, 4 4 1, 535, 556
GNU, 3, 4 , 6, 8, 9, 533, 536, 54 0, 54 1,
555, 556, 558, 566, 573
GNU Autotools, 555
GNU Compiler Collection, 4 , 536, 54 0
GNU debugger, 556
GNU make, 54 1, 555
GPL, 3, 4 , 5, 34 4 , 34 5, 34 9, 350, 352 , 361,
372 , 374 , 4 00, 4 02 , 4 17, 4 2 0, 4 2 3,
4 37, 558
grafikus felhasznli fellet, 2 , 315, 330,
4 39, 4 4 2 , 4 4 3, 4 50, 4 59, 52 2 , 52 5, 530
Gy
gyermekfolyamat, 157, 161, 162 , 2 62
gyermekprocessz, 108, 12 2 , 157-160, 193,
198, 2 63, 308
H
hagyomnyos jelzseknek, 2 4 3
hard link, 4 2 , 114
httrbeli processzcsoport, 192 , 193
Helgrind, 577, 580
helyettest hivatkozs, 54 7, 54 8
hibaellenrz mutex, 2 2 1
hotplug, 355
htonlO, 2 94
I/O buffer, 103
I/O multiplexels, 12 8
I/O temez, 104
igny szerinti lapozs, 31, 32 , 139
in_addr, 2 91, 2 92 , 2 93, 32 3
in6_addr, 2 91, 2 93, 2 94 , 32 3
IN6ADD_ANY _INIT, 2 96
in6addr_any, 2 93, 310, 313
IN6ADDR_ANY _INIT, 2 93, 2 96, 306
in6addr_loopback, 2 94
IN6ADDR_LOOPBACK_INIT, 2 93, 2 96
INADDR_ANY, 2 93, 2 94 , 2 96
INADDR_LOOBACK, 2 93
INADDR_LOOPBACK, 2 93, 2 94 , 2 96
in-core inode, 4 3
indent, 583
inet_atonO, 2 91, 2 92
587
Trgymutat
inet_ntoa(), 2 91, 2 92
inet_ntopO, 2 92
inet_ptonO, 2 92 , 2 95
information node, 4 1
Mit, 14 , 15, 2 0, 82 , 157, 161, 190, 193,
2 10, 2 11, 2 15, 2 2 2 , 2 2 4 , 2 2 9, 2 33,
2 36, 2 37, 2 4 1, 2 4 6, 2 51, 2 52 , 34 4 ,
34 5, 34 9, 350, 352 , 356, 360, 361,
371-374 , 381, 390-396, 399, 4 00, 4 02 ,
4 16, 4 17, 4 2 0-4 2 5, 4 33, 4 34 , 4 37
init_module(), 34 4
inode, 4 1, 4 2 , 4 3, 104 , 105, 108-112 , 114 -
117, 119, 359, 360, 364 , 365, 399,
4 01
insmod, 34 7, 351, 353, 362
Integrated Development Environment,
533, 556
Interprocess Communication, 13, 165
interruptible_sleep_onO, 396
ioctl, 37, 366, 367, 368, 369, 377
IP_ADD_MEMBERSHIP, 32 2 , 32 5
IP_DROP_MEMBERSHIP, 32 2
IP_MULTICAST_IF, 32 2
IP_MULTICAST_LOOP, 32 1, 32 2
IP_MULTICAST_TTL, 32 2 , 32 3
ipcs, 165, 166, 169, 187
IPPOROTO _IGMP, 2 67
IPPROTO _ICMP, 2 67
IPPROTO _IP, 32 1, 32 2 , 32 3, 32 5, 32 6
IPPROTO JP6, 32 6
IPPROTO_IPV6, 32 1, 32 5
IPPROTO_RAW, 2 67
IPPROTO_TCP, 2 67, 32 6
IPPROTO_UDP, 2 67, 32 6, 32 8
IPv4 , 12 , 2 66, 2 67, 2 82 , 2 83, 2 85-2 96,
2 98, 300, 32 1, 32 3, 32 5, 32 6
IPv6, 12 , 2 66, 2 82 , 2 88-2 96, 304 , 32 1,
32 2 , 32 3, 32 5, 32 6
IPV6_JOIN_GROUP, 32 2 , 32 5
IPV6_LEAVE_GROUP, 32 2
IPV6_MULTICAST_HOPS, 32 2
IPV6_MULTICAST_IF, 32 2
IPV6_MULTICAST_LOOP, 32 2
rsi zrols, 14 5, 14 6, 394
IRQ_HANDLED, 4 11
IRQ_NONE, 4 11, 4 12 , 4 16, 4 17, 4 19
IRQF_DISABLED, 4 11
IRQF_SAMPLE_RANDOM, 4 11
IRQF_SHARED, 4 11, 4 12 , 4 16, 4 2 0
IRQF_TIMER, 4 11
J
jelzs, 16, 17, 18, 103, 156, 159-161, 193,
195, 2 2 8-2 30, 2 34 , 2 38-2 51, 2 53-2 62 ,
303, 360, 391, 396, 399, 4 00, 4 02 ,
4 52 , 560, 581
jelzs generlsnak, 2 4 5
jelzs kzbestse, 2 4 5
jelzsklds, 192 , 2 39, 2 4 5, 2 50
jelzsmaszk, 134 , 2 4 5, 2 50, 2 54 , 2 55, 2 58
jiffy, 2 6, 392 , 4 2 3, 4 2 4
joe, 534
K
kanonikus feldolgozs, 151, 154
karaktertpus eszkzvezrl, 353
KDE, 4 4 1, 4 4 3, 535, 556, 581
KDevelop, 556
KERN_ALERT, 376
KERN_CRIT, 376
KERN_DEBUG, 375, 376
KERN_EMERG, 376
KERN_ERR, 375
KERN_INFO, 375
KERN_NOTICE, 375
KERN_WARNING, 375, 4 16, 4 2 0
kernel cmtartomny, 34 3, 362 , 367, 4 2 1
Kernel Hacking, 377
kfree0, 362 , 385
kisfeladat, 2 6, 4 13, 4 14 , 4 15, 4 17, 4 18,
4 2 0
kizrlagos zrols, 14 5
kmallocO, 362 , 384 , 385, 386, 387, 4 12
klcsns kizrs, 14 4 , 166, 2 2 1, 362 ,
387, 392
knny sly processzek, 2 02
ktelez zrols, 14 3, 14 8, 14 9
kts, 2 68, 2 93
kzps lapknyvtr, 31
L
lapazonost, 2 8, 2 9
lapcserellomny, 33, 35
laphiba, 78
lapknyvtr, 2 9, 30, 31
laptr, 103, 104 , 139
Latency tracer, 2 6
ld, 59, 62 , 63, 68, 74 , 87, 178, 538
Least Recently Used, 33
lecsatolt, 2 07, 2 11, 2 18
588
Trgymutat
lefoglalhat, 79
Libtool, 555
link count, 4 3
linkernv, 62
listenO, 2 69
little endian, 2 90, 4 05
llseek, 37
login, 14 , 190, 199, 2 02
loklis hlzat, 2 82 , 2 83, 2 84
lokalizci, 4 79, 4 80, 4 81
loopback, 2 85
lsmod, 34 7
ltrace, 582
Ly
lyukak, 101, 110
M
magas szint llomnykezels, 95, 14 9
Magic SysRq, 377, 381
make, 338, 34 6, 4 4 6, 4 4 7, 4 4 8, 4 57, 54 1,
54 2 , 54 3, 54 4 , 54 9, 551, 552 , 553, 554
Makefile, 34 1, 34 6, 362 , 54 1, 54 2 , 54 3,
54 5, 54 7, 552 , 553, 554 , 555
Makefile.am, 555
Makefile.in, 555
msols rskor, 34 , 78, 79, 83, 164
Massif, 577
mc, 534
megnevezett csvezetkek, 4 0, 103, 113,
12 3, 2 75
megnevezett szemafor, 2 33, 2 35, 2 38
megosztott memria, 16, 34 , 37, 14 0, 185,
186, 187, 2 2 1, 2 33, 2 38
megosztott programknyvtr, 56, 59, 61,
62 , 64 , 68, 70, 72 , 83, 84 , 86, 90
megosztott zrols, 14 5, 393
mellkazonost, 114 , 354 , 362 , 363, 366
Memcheck, 577
Memriainformcik, 16, 381
memory leak, 557, 569
Memory Management Unit, 2 8
merev hivatkozs, 4 2 , 4 3, 111, 114 , 115,
116
minimum granularity, 2 4
minor number, 354 , 363
MINORO, 364
MKDEVO, 355
mknod, 113, 114 , 12 3, 354
mmapO, 139, 14 0, 14 1, 14 2 , 4 04 , 580
moc, 4 4 8, 4 58, 4 59, 555
modlis dialgusablak, 4 60, 4 72
modinfo, 352
modprobe, 34 7, 34 8, 34 9, 353
modprobe.conf, 34 8, 353
mdszertanok, 4 4 1
module_exitO, 34 5
module_initO, 34 5
module_paramO, 351
modulok, 2 56, 34 0, 34 1, 34 6, 34 7, 34 8,
350, 351, 357, 370, 377, 382 , 4 4 2
MSG_DONTROUTE, 302
MSG_DONTWAIT, 302 , 303
MSG_MORE, 302 , 32 9, 330
MSG_NOSIGNAL, 303
MSG_OOB, 303
MSG_PEEK, 303
MSG_WAITALL, 303
munkamenet, 192 , 193, 194 , 195
munkasor, 2 6, 4 17, 4 18, 4 2 1
309,
516
N
nano, 4 2 3, 534
nem blokkold, 12 7-12 9, 131, 136, 155,
2 38, 2 69
nem lefoglalhat, 79
nem modlis dialgusablak, 4 60, 4 66
netstat, 2 81, 330
network byte order, 2 90
nvtelen csvezetk, 4 0, 4 3, 12 1, 12 2 ,
198, 2 80
nvtelen szemafor, 2 33, 2 34
NI_DGRAM, 2 99
NI_NAMEREQD, 2 99, 301
NI_NOFQDN, 2 99
NI_NUMERICHOST, 2 99, 300, 316
NI_NUMERICSERV, 2 99
nice, 2 2 , 2 4
o,
olvassi zrols, 14 5, 14 6, 394
on-disk inode, 4 3, 109, 117
Oops, 34 2 , 355, 378, 379, 380, 381
openO, 97, 98, 113, 14 0, 14 4 , 2 66, 2 75,
361, 4 91, 4 92 , 506, 507, 517
out-of-band data, 303, 4 03
mutex, 166, 2 2 1-2 2 6,
310, 311, 392 , 393,
2 2 8-2 33, 2 36,
4 33, 4 34 , 4 4 9,
589
Trgymutat
P
page, 9, 2 8, 2 9, 31, 32 , 103, 386, 4 06
page directory, 2 9
page fault, 32
Page Frame Number, 2 8, 4 05
page middle directory, 31
PAGE_SHIFT, 4 05, 4 06
pending connection, 2 69
perifriakezel, 13
PF_APPLETALK, 2 66
PF_ATMPVC, 2 66
PF_AX2 5, 2 66
PF_INET, 2 66, 2 67, 310, 313
PF_INET6, 2 66, 310, 313
PF_IPX, 2 66
PF_NETLINK, 2 66
PF_PACKET, 2 66
PF_UNIX, PF_LOCAL, 2 66
PF_X2 5, 2 66
pgid, 18, 191
pid, 18, 2 0, 12 1, 12 2 , 14 4 , 14 6, 14 7, 157-
162 , 190, 191, 192 , 194 , 2 51, 2 61,
379, 562
pipe, 4 0, 113, 12 0, 12 1, 12 5, 12 6, 12 8,
133, 138
pkg-config, 555
po110, 134 , 136, 137, 2 69, 311, 314 , 315,
4 03
poll_table, 4 03, 4 04
poll_waitO, 4 03
POLLERR, 135-137, 314 , 4 03
POLLHUP, 135, 136, 138, 314 , 4 03
POLLIN, 135-138, 312 , 314 , 4 03, 4 04
POLLOUT, 135, 136, 4 03
POLLPRI, 135, 4 03
POLLRDBAND, 4 03
POLLRDNORM, 4 03, 4 04
POLLWRBAND, 135, 4 03
POLLWRNORM, 4 03
portmap, 2 89, 333, 334
pozcifggetlen futtathat llomny, 84
pozcifggetlen kd, 58, 84 , 85, 86
pozicionlhat llomnyok, 100
ppid, 2 0
preprocessor, 54 0
printkO, 34 5, 359, 375, 381
privt lekpezsnek, 79, 14 1
process group ID, 18
process ID, 18
process pool, 309
processzcsoport, 18, 191, 192 , 193, 2 51
processzek kztti kommunikci, 13,
165, 2 39
programbetlt, 59, 79, 80, 82
pstree, 15
pthread, 2 03, 2 04 , 2 06-2 2 0, 2 2 2 -2 2 6, 2 2 9-
2 32 , 2 36, 2 37, 2 50, 2 52 , 2 54 , 309,
310, 311, 580, 581
Q
qmake, 4 4 6, 4 4 7, 4 4 8, 4 57, 4 58, 555
Qt Creator, 556
R
ragozsi szably, 551-553
readO, 2 2 , 99, 12 7, 12 8, 151, 154 , 2 65,
2 70, 2 73, 2 74 , 302 , 303, 361
readdirO, 119, 12 0
real time priority, 2 2
real-time, 2 2 , 2 4 3
recv0, 2 73, 303, 306, 315
recvfromO, 2 73, 2 74 , 2 99
rekordzrols, 14 3, 14 5, 14 6, 2 02
Remote Procedure Call, 2 65, 331
rszleges olvass, 102
round-robin, 2 3, 2 11
router, 2 , 2 82 , 2 84 , 2 87, 2 88
rpcgen, 334 , 336, 338
rpcinfo, 334
s
sajt vezrl, 4 83, 4 99, 530
schedule(), 2 2 , 4 2 4
scheduler, 18, 104
SCons, 556
segmentation fault, 78, 34 2 , 570
selectO, 12 9, 130, 132 , 134 , 135, 2 69, 311,
315, 4 03
semaphore, 166, 174 , 177, 2 33, 2 34 , 366,
391, 392 , 393, 394
sendO, 2 74 , 302 , 303, 315, 32 7, 32 9
sendfile0, 303, 304
sendto(), 2 73, 2 96, 32 7, 32 9, 330
session, 18, 192 , 561
sessionid, 18
setgid, 111, 14 8, 14 9, 198, 199, 2 00
setsockoptO, 306, 32 1, 32 6
setuid, 111, 198, 199, 2 00, 2 52
SGCheck, 578
sh, 2 0
590
Trgymutat
shell, 2 0, 4 4 , 108, 12 2 , 12 3, 190-193, 197,
198, 2 01, 2 53, 562
SHUT_RD, 2 71
SHUT_RDWR, 2 71
SHUT_WR, 2 71
shutdownO, 2 71
SIGPIPE, 12 3, 2 4 0, 2 50, 303
sin6_flowinfo, 2 91
sin6_scope_id, 2 91
slab, 385
sleep(), 387, 390, 391, 4 12 , 4 15, 4 17
sleep_onO, 396
sleep_on_interruptible(), 4 00
SO_KEEPALIVE, 32 7
SO_REUSEADDR, 305, 310, 313, 32 7
SOCK_DGRAM, 2 66, 2 95, 318, 32 0, 32 4 ,
32 8, 32 9
SOCK_PACKET, 2 66
SOCK_RAW, 2 66, 2 67
SOCK_RDM, 2 66
SOCK_SEQPACKET, 2 66
SOCK_STREAM, 2 66, 2 77, 2 79, 2 95, 2 97,
300, 305, 307, 310, 313, 316
sockaddr_in, 2 90, 2 91, 2 95, 2 98, 2 99, 301,
305,306, 310, 313, 318, 32 4
sockaddr_in6, 2 91, 2 95, 2 98, 2 99, 305,
306,310, 313, 318, 32 4
socket, 2 65-2 80, 2 93-2 95, 2 99, 302 -305,
307-32 4 , 32 6-330, 52 3, 52 4 , 52 6, 52 8
socket(), 2 65, 2 66, 2 72 , 2 80, 2 95
socketpairO, 2 80
software interrupt, 4 13
SOL_SOCKET, 305, 310, 313, 32 6
so-nv, 57, 58, 59, 60, 61, 64 , 87
spin_lock_irqsave0, 390
spinlock, 2 37, 366, 389, 390, 393
splice0, 304
splint, 582
SQL programozi interfsz, 516
ssh, 2 89
ssleepO, 4 2 3, 4 2 4
start_kerne10, 14
statO, 109, 2 00, 2 75
statikus programknyvtr, 50, 51, 55, 56,
63, 89, 34 1, 537
statikus szimblumtblzat, 81, 90
statikusan linkelt megosztott program-
knyvtr, 62
stdin, 14 9, 315
strace, 61, 582
stream, 14 9, 2 68, 2 75, 519
stream socket, 2 68
struct addrinfo, 2 94 , 2 95, 2 97, 300, 305,
307,315, 316, 318, 319, 32 4 , 32 7, 32 9
swap file, 33
symbolic link, symlink, soft link, 4 0
sync, 37, 104 , 105, 397, 4 2 6
sysfs, 351, 353, 355, 366, 382 , 4 2 9, 4 30,
4 34 , 4 36
sysfs jogok, 351
$z
szlanknti trol, 2 16, 2 17
szlbiztos fggvnyek, 2 14
szlspecifikus adatok, 2 14 , 2 15, 2 2 0
szmtott vltoznevek, 54 8
szekcik, 79, 81, 82
szekvencilis llomnyok, 100
szemafor, 16, 166-173, 177, 179, 2 2 1,
2 33-2 36, 366, 389, 391-394 , 4 4 9
szignl, 2 60, 391, 4 4 5, 4 4 6, 4 4 8, 4 51-4 59,
4 76, 4 83, 4 84 , 503, 509, 510, 511,
512 , 515, 518, 52 2 , 52 7, 52 8, 530
szimbolikus hivatkozs, 4 0, 4 2 , 98, 109,
110, 113, 115, 116, 118
szimblumfelolds, 56, 66, 83, 86, 89
szinkron jelzskezelsnek, 2 51
Szinkronizcis osztly, 516
szinkronizlt I/O, 105
szintvezrelt, 133, 138
szlot, 4 4 5, 4 4 6, 4 4 8, 4 51-4 53, 4 56-4 59,
4 83, 4 84 , 503, 504 , 508-512 , 515,
518, 52 2 , 52 9
szolgltatsokat, 3, 11, 12 , 4 13, 4 4 1, 515
szlfolyamat, 18, 19, 34 , 157
szlprocessz, 15, 19, 12 2 , 157, 2 62
T
tjkoztat zrols, 14 3, 14 8
trgykd llomny, 50, 51, 54 , 55, 57,
70, 81-83, 86, 87, 89, 34 6, 538, 552
task, 15, 379, 4 19, 4 2 1, 4 2 2
tasklet, 4 13, 4 14 , 4 15, 4 16
tasklet_schedule(), 4 15
tvoli eljrshvs, 2 65, 331, 332 , 337
TCP_CORK, 32 7
tcpdump, 330
tcsh, 2 0
tee0, 304
teljes olvass, 101, 102 , 2 4 8
telnet, 2 89, 311, 315
text, 54 , 74 , 81, 82 , 83, 84 , 92 , 4 53, 4 54 ,
4 63, 4 70, 4 74 , 4 75, 4 79, 52 8
591
Trgymutat
tgid, 18
THIS_MODULE, 356-360, 364 , 365, 366,
399, 4 01, 4 02 , 4 04 , 4 07, 4 31, 4 37
thread pool, 309
threshold, 32 2
timeout, 12 9, 130, 135, 154 , 2 31, 2 59,
392 , 396, 397, 4 2 4 , 4 2 5, 504
tiszttszlak, 104
tisztogat kezelfggvny, 2 19, 2 2 0
Top half, 2 5, 4 14
tbbfeladatos, 13, 15, 4 39
tbbfelhasznls, 1, 4 39
trlsi pontok, 2 17
Translation Look-aside Buffer, 35
Transmission Control Protocol, 2 67
U
H
U
udev, 355, 356, 360, 399, 4 00, 4 02 , 4 34
UDP_CORK, 32 7, 32 8
uic, 555
uid, gid, 18
umask, 98, 114 , 118, 194 , 2 75
Unix domain socket, 4 1, 2 65, 2 66, 2 75,
2 76, 2 78, 2 80, 2 81, 2 82
unlinkO, 115, 116, 2 78
unlocked_ioctl, 367, 370
user space, 4 05, 4 12
U
H
U
temez, 13, 18, 2 1-2 6, 167, 397
zenetsor, 16, 178, 180, 181, 2 2 1, 2 38
V
Valgrind, 576, 577, 578, 580
vals idej jelzsek, 2 4 3, 2 52 , 2 53
vrakozsi sor, 2 4 2 , 2 4 3, 2 4 6, 2 50, 2 54 ,
2 59, 2 60, 32 7, 32 9, 396, 4 03, 4 17,
4 2 4 , 4 51, 4 56
vrakozsisor-alap sszekttets, 4 52 ,
509, 512
VERIFY_READ, 369, 370
VERIFY_WRITE, 369, 370
vezrlterminl, 192 , 193, 197, 2 02
vfree0, 386
vi, 380, 534
vim, 534
virtulismemria-kezels, 2 7, 2 8, 34 , 78,
139
vmalloc(), 386
vmlinux, 379, 380, 382 , 383
vmsplice(), 304
vonalrend, 151, 154
w
wait queue, 396
wait_eventO, 397
wait_event_interruptible(), 4 00
wake_up(), 398
wake_up_interruptible0, 398
widgetknyvtr, 4 4 0, 4 4 1
wireshark, 330, 331
work_struct, 4 18, 4 19
working set, 33
workqueue, 4 14 , 4 18, 4 19, 4 2 0
write, 99, 2 65, 2 70, 2 73, 2 74 , 302 , 303
X
X szerver, 4 39, 4 4 0
X Window, 5, 2 75, 4 39, 4 4 0, 4 4 2 , 4 4 4
X.Org, 4 39
XFree86, 4 39
z
zrolllomny, 14 3, 14 4 , 14 5
zombie, 17, 160
592
Irodalomjegyzk
[1] Kerninghan, Brian W. Ritchie, Dennis M.: A C programozsi nyelv.
Mszaki Knyvkiad, 1994 .
[2 ] Benedek Zoltn Levendovszky Tihamr: Szoftverfejleszts C++ nyel-
ven. SZAK Kiad, 2 007.
[3] Stroustrup, Bjarne: A C++ programozsi nyelv. Kiskapu Kft., 2 001.
[4 ] Wheeler, David A.: Program Library HOWTO. Linux Documentation
Project, October 2 000.
[5] Barlow, Daniel: GCC-HOWTO. Linux Documentation Project, 1999.
[6] Rusling, David A.: The Linux Kernel. Linux Documentation Project,
1996-1999.
[7] Volkerding, Patrick Foster-Johnson, Eric Reichard, Kevin: Linux
Programming. MIS:Press, 1997.
[8] Tannenbaum, Andrew S. et al.: Opercis rendszerek. Panem Knyvki-
ad Kft., 1999.
[9] Fitzpatrick, Richard: Introduction to Computational Physics.
http:// farside.ph.utexas.edu/teaching/32 9/lectures/lectures.html, 2 002 .
[10] Sweet, David et. al.: KDE 2.0 Development. Macmillan/SAMS,
http:// www.andamooka.org/reader.pl?section=kde2 0devel, 2 000.
[11] Tannenbaum, Andrew S.: Szmtgp Hlzatok. 3. kiads, Panem
Knyvkiad Kft. 1999.
[12 ] Marshall, A. D.: Programming in C UNIX System Calls and Subrou-
tines using C. http://www.cs.cf.ac.uk/Dave/C/CE.html, 1994 -1999.
[13] Goldt, Sven et al.: The Linux Programmer's Guide. http://oopweb.com/
OS/Documents/LinuxProgrammersGuide/VolumeFrames.html, 1995.
[17] de Goyeneche, Juan-Mariano: Multicast over TCP/ IP HOWTO.
http://jungla.dit.upm.esk-jmseyas/linux/mcast.howto/multic.html, 1998.
[18] Frerking, Gary Baumann, Peter: Serial Programming HOWTO.
Linux Documentation Project, 1998-2 001.
Iroda lomjegyzk
[19] Johnson, Michael K. Troan, Erik W.: Linux Application Development.
Addison-Wesley, 1998.
[2 0] Szebernyi Imre: Bevezets a UNIX opercis rendszerbe. BME Irny-
tstechnika s Informatika Tanszk, Oktatsi segdlet, 1998.
[2 2 ] Rubini, Alessandro: Linux Device Drivers. O'Reilly. 1998.
[2 3] Manrique, Daniel: X Window System Architecture Overview HOWTO.
Linux Documentation Project, 2 001.
[2 5] Sarwar, Badrul et al.: Linux & Unix Programming Tools: A Primer for
Software Developers. Addison-Wesley, 2 003.
[2 6] Hollabaugh, Craig: Embedded Linux: Hardware, Software, and Inter-
facing. Addison-Wesley, 2 002 .
[2 7] Kerrisk, Michael: The Linux Programming Interface: A Linux and
UNIX System Programming Handbook. October 2 010, No Starch Press.
[2 8] Stevens, W. Richard Rago, Stephen A.: Advanced Programming in the
UNIX Environment. 2 nd edition, Addison-Wesley Professional, 2 005.
[2 9] Love, Robert: Linux System Programming: Talking Directly to the Ker-
nel and C Library. lst edition, O'Reilly Media, 2 007.
[30] Mauerer, Wolfgang: Professional Linux Kernel Architecture.
Wrox, 2 008.
[31] Jelnek, Jakub: Prelink. Red Hat, Inc., 2 004 .
[32] GCC Manual. http://gcc.gnu.org/onlinedocs/, 2 010.
[33] GNU Make Manual. http://www.gnu.org/software/make/manual/, 2 010.
[34] GDB Manual. http://sourceware.org/gdb/current/onlinedocs/gdb/, 2 012 .
[35] Valgrind User Manual.
http://valgrind.org/docs/manual/manual.html, 2 012 .
[36] Linux Kernel forrs. http.//www.kernel.org/,
[37] Bovet, Daniel P. Cesati, Marco: Understanding the Linux Kernel. 3rd
Edition, O'Reilly Media, 2 005.
594
Ekler Peter
Fehr Marcell
Forstner Bertalan
Kelenyi Imre
N L) R. C3 I FIALAP
SZOFTVEFEJLESZ FS
Az Android rendszer programozsanak bemutatsa
Ekler Pter, Fehr Marcell,
Forstner Bertalan, Kelnyi
Imre
Android-alap
szoftver-
fejleszts
Kartonlt, B5
ISBN 978-963-9863-2 7-9
4 00 oldal, 6 000 Ft fval
A Budapesti Mszaki s
Gazdasgtudomnyi Egyetem
Automatizlsi s Alkalmazott
Informatikai Tanszkn mkd
Alkalmazott Mobil Kutatcso-
port (Amorg) kiemelt figyelmet
fordt a hazai mobiltechnolgia-
oktats folyamatos fejlesztsre. Munkjuknak ksznheten lehetv
vlt, hogy szlesebb rtegek ismerkedjenek meg a legnpszerbb mobil-
platformokkal, s napraksz tudsuk legyen a legjabb technolgikat il-
leten. vente csak az egyetemrl tbb mint 500 hallgat vesz rszt a
kurzusaikon. Az Amorg tagjai a tanszk npszer Alkalmazott informati-
ka sorozatnak keretben ezttal egy hinyptl mvel lepik meg az
okostelefonok fejlesztse irnt rdekldket. Btran llthatjuk, hogy
Android platform vilgszinten az egyik legnpszerbb s legelterjedtebb
mobilplatformm ntte ki magt, ppen ezrt a knyv elolvassval meg-
szerezhet ismeretek hossz tv tudst jelentenek a felhasznlk sz-
mra. A knyv szerzi az Android platformmal mr a legels SDK megje-
lense ta foglalkoznak, szaktudsukat llandan szinten tartjk, s fo-
lyamatos rsztvevi a hazai s nemzetkzi ipari kutatsoknak s fejlesz-
tseknek, gy szles kr tapasztalattal rendelkeznek. A knyv gondosan
vlogatott tmakrei, szakszer szerkesztse s a vlogatott pldk lehe-
tv teszik, hogy a mindennapi munka sorn is alkalmazhassuk, s a
rszletes magyarzatok segtsgvel a technolgia mkdst is knnyen
megrthessk. A szerzk trekedtek arra, hogy a knyvben szerepl kd-
rszek hasznlatt lehetsg szerint nll alkalmazsokon keresztl is
bemutassk, ezek a pldk az elszban tallhat hivatkozson keresztl
rhetk el.
Az Alkalmazott informatika sorozat
kaphat ktetei
Charaf Hassan, Cscs Gergely, Forstner Bertalan, Marossy Klmn:
Symbian alap szoftverfejleszts
2 4 0 oldal + CD, 4 .500 Ft fval, ISBN 978-963-9131-66-0, 2 004 .
Benedek Zoltn, Levendovszky Tihamr: Szoftverfejleszts C++
nyelven
52 8 oldal + CD, 6.800 Ft fval, ISBN 978-963-9131-94 -1, 2 007.
Imre Gbor, Balogh Pter, Bernyi Zsolt, Dvai Istvn, Imre Gbor,
Sos Istvn, Tthfalussy Balzs: Szoftverfejleszts Java EE plat-
formon
4 60 oldal, 6 500 Ft fval, ISBN 978-963-9131-97-2 , 2 007.
Gl Tibor: Interfsztechnikk
4 4 0 oldal, 6 800 Ft fval, ISBN 978-963-9863-13-2 , 2 010.
Forstner Bertalan, Ekler Pter, Kelnyi Imre: Bevezets a mobil-
programozsba. Gyors prototpus-fejleszts Python s Java nyelven
2 88 oldal, 4 800 Ft fval, ISBN 978-963-9863-01-9, 2 011.
Ekler Pter, Fehr Marcell, Forstner Bertalan, Kelnyi Imre:
Android-alap szoftverfejleszts
4 00 oldal, 6 000 Ft fval, ISBN 978-963-9863-2 7-9, 2 012 .
Asztalos Mrk, Bnysz Gbor, Levendovszky Tihamr: Linux
programozs, msodik, tdolgozott kiads
616 oldal, 7800 Ft fval, ISBN 978-963-9863-2 9-3, 2 012 .
Felels kiad: a SZAK Kiad Kft. gyvezetje
Felels szerkeszt: Kis dm
Olvasszerkeszt: Laczk Krisztina
Trdel: Mamira Gyrgy
Bortterv: Szilvsi Sndor
Grafikai munka kivitelezje: Flrin Gbor (Typozis Kft.)
Terjedelem 38,5 (B5) v.
Kszlt az OOK Press Nyomdban (Veszprm)
Felels vezet: Szathmry Attila
Ara: 7800 Ft fval
ISBN 978-963-9863-29-3
9 789639 863293
A SZAK Kiad a weben
http://www.szak.hu
LINUX
Msodik, tdolgozott kiads
A Linux a kzelmltban volt hszves. Ez a hsz v egyben sikertrtnet is: a
Linux-alap szerverek npszersge tretlen, nagyon sok begyazott eszkz fut-
tat Linuxot, kztk a legnpszerbb okostelefonok. A Linux-disztribcik egyre
kzelebb kerlnek a felhasznlkhoz, hasznlatuk egyre egyszerbb vlik.
Jllehet szmos magas szint programozsi nyelv s krnyezet ll rendelkezsre,
sok olyan feladat ltezik, amelyet az opercis rendszer programozsi felletn
elrhet funkcikkal lehet csak megoldani. Ilyenkor szksg van az opercis
rendszer mkdsnek mlyebb ismeretre, ez begyazott krnyezetben egye-
nesen elengedhetetlenn vlik. Ezekhez a feladatokhoz kvn segtsget nyjtani
a knyv. Az opercis rendszer C/C++-ban elrhet programozsi felletnek
ismertetse sorn rszletesen bemutatjuk a megvalstsi alapelveket, ennek
tkrben rthetv vlik az egyes funkcik hasznlata is. Egy sokkal teljesebb
kp birtokban a magas szint krnyezetek felhasznli is hatkonyabban tudjk
kihasznlni krnyezetk lehetsgeit. Mivel a Linux a Unix opercis rendszerek
csaldjnak tagja, ezrt a Linuxrl elmondottak nagy rsze igaz a Unixra is. Mind-
ezek alapjn ajnljuk a knyvet mindenkinek, aki Linux/Unix krnyezetben ter-
vezi, illetve programozi munkt vgez, valamint azoknak, akik el szeretnl<
sajttani az ehhez szksges ismereteket.
A szerzk knyvket annak els kiadsa ta szinte teljesen tdolgoztk, s sz-
mos j fejezettel bvtettk. A fbb tmakrk a kvetkezk:
Bevezets a Linux-kernel mkdsbe
Programknyvtrak fejlesztse
Prhuzamos programozs
llomnykezels
Hlzati alkalmazsok
Programozs Qt-krnyezetben
Adatbzis-kezels Qt-alapokon
Fejleszteszkzk, hibakeress

You might also like