home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Amiga MA Magazine 1998 #7
/
amigamamagazinepolishissue1998.iso
/
magazyn_amiga
/
0896
/
028_porty
< prev
next >
Wrap
Text File
|
1998-03-26
|
11KB
|
251 lines
exec.library
------------
PORTY
<lead>Moûe to pojëcie obiîo Ci sië juû o uszy. Moûe nawet wiesz,
czym sâ porty i jak z nich korzystaê? Jeôli tak, to nie musisz
czytaê tego artykuîu. Jednakûe jeôli port kojarzy Ci sië
wyîâcznie z zacumowanymi do nadgniîych sîupów i obijajâcymi sië o
burty kutrami, gdzie powietrze jest wypeînione sîonym zapachem
morza i bardziej juû przykrym odorem nadgniîych ryb, to gorâco Ci
polecam lekturë poniûszego tekstu.
<a>Cromax/Alchemy
<txt>Port -- ten zwykîy, gdzie moûna znaleúê snujâcych sië
marynarzy i gotowe na wszystko kobiety, istnieje, ûeby mogîy do
niego zawijaê i odpîywaê z niego statki. Identycznie rzecz sië ma
z portami z Execa. Jedynâ róûnicâ jest brak zepsutego powietrza i
sîonej wody, statki zaô sâ zastâpione wpîywajâcymi (lub
wychodzâcymi) wiadomoôciami (a gdzie te kobiety? -- red.).
Port -- teraz juû ten execowy -- to po prostu kawaîek pamiëci, a
precyzujâc, pewna struktura. Jeôli teraz znamy adres poczâtku tej
struktury w pamiëci, czyli innymi sîowy adres tego portu, moûemy
wysîaê do niego wiadomoôê (dalej bëdë uûywaî angielskiego
okreôlenia message). Moûemy teû zatrzymaê nasz program i
poczekaê, aû wpîynie do niego jakiô komunikat (czyli po angielsku
message). Kiedy taki message przybëdzie, naleûy go odebraê,
odczytaê, odpowiednio zinterpretowaê, ewentualnie wykonaê jakieô
dziaîanie i odpowiedzieê (czësto koniecznie!) nadawcy, ûe juû
uporaliômy sië z komunikatem. Na ogóî mechanizm czekania na
wiadomoôê, jej odbierania, przetwarzania itd. jest standardowy.
Tak jak wyûej wspomniaîem -- najpierw korzystamy z procedury,
która zatrzymuje nasz program i czeka na wiadomoôê. Kiedy
komunikat dotrze do portu, procedura zwróci adres pierwszego
dostëpnego komunikatu (patrz poniûej opis struktury Message).
Wtedy my odczytujemy wiadomoôê i na podstawie zawartych w niej
danych wykonujemy odpowiednie dziaîanie. Kiedy skoïczymy,
odpowiadamy nadawcy, który wysîaî nam wiadomoôê (w strukturze
Message na ogóî znajduje sië adres portu nadajâcego komunikat).
Czasami moûna zmieniê kolejnoôê tych dziaîaï, tzn. najpierw
odpowiedzieê nadawcy, a dopiero potem zabraê sië do odczytywania
wiadomoôci. W tym wypadku jednak musimy byê caîkowicie pewni, ûe
taka zamiana jest dozwolona (wyjaônienie póúniej). Nie zawsze
moûna jej dokonaê. Natomiast jeûeli zamierzamy wysîaê komunikat,
musimy znaê adres portu, do którego message ma dotrzeê;
powinniômy takûe umieôciê w naszej wiadomoôci adres naszego portu
(choê to nie zawsze jest konieczne), ûeby odbiorca wiedziaî, komu
odpowiedzieê. Na dobrâ sprawë, to mniej wiëcej wîaônie tak
wyglâdajâ porty i komunikacja miëdzy nimi -- oczekiwanie na
wiadomoôci oraz ich wysyîanie.
Poprzedni akapit byî bardzo ogólnym wprowadzeniem. W tym
znajdziesz wiëcej szczegóîów. Do obsîugi portów oraz systemu
komunikacji przewidzianych jest zaledwie kilka procedur (plus
dwie nowe w systemach +2.0) z biblioteki exec.library. Sâ to:
<l> _LVOWait Equ -318
_LVOAllocSignal Equ -330
_LVOFreeSignal Eqi -336
_LVOAddPort Equ -354
_LVORemPort Equ -360
_LVOPutMsg Equ -366
_LVOGetMsg Equ -372
_LVOReplyMsg Equ -378
_LVOWaitPort Equ -384
_LVOFindPort Equ -390
_LVOCreateMsgPort Equ -666 ; V36 (2.0)
_LVODeleteMsgPort Equ -672 ; V36 (2.0)
<txt>Z pewnych powodów trzy pierwsze funkcje opiszë na samym
koïcu. Zanim jednak zacznë opisywaê dwie nastëpne procedury,
muszë wspomnieê o dwóch rodzajach portów, a mianowicie o portach
publicznych (public ports) i prywatnych. Port publiczny to taki,
którego adres zostaje umieszczony na systemowej liôcie (nawiasem
mówiâc, dwukierunkowej, czyli tzw. double-linked) portów
publicznych. Mogâ mieê do niego zatem dostëp takûe inne niû nasz
programy, czyli mogâ do niego wysyîaê komunikaty i czekaê (czego
nie powinny robiê), aû do portu wpîynie jakiô komunikat; czyniâc
port publicznym, trzeba mieê naprawdë do tego powód, bo wtedy
naleûy byê przygotowanym wîaôciwie na wszystko. No i -- jak juû
sië domyôlasz -- port prywatny to taki, którego adres jest znany
tylko nam.
Skoro zaô o tym wspomniaîem przed opisaniem tych dwóch procedur,
îatwo jest sië domyôliê, ûe sâ one wîaônie z typami tych portów
zwiâzane. Struktura portu publicznego absolutnie niczym sië nie
róûni od struktury portu prywatnego -- w kaûdej chwili port
prywatny moûesz wpisaê na listë portów publicznych -- do tego
wîaônie sîuûy procedura _LVOAddPort(). _LVORemPort() uûywasz
natomiast wtedy, gdy chcesz jakiô port z tej listy usunâê. Dziëki
_LVOPutMsg() moûesz wysîaê wiadomoôê do jakiegoô portu, za pomocâ
zaô _LVOGetMsg() odebraê jâ, gdy do naszego portu przybëdzie.
_LVOWaitPort() zatrzymuje dziaîanie naszego programu do momentu,
kiedy do portu podanego jako argument dla powyûszej procedury
wpîynie wiadomoôê. _LVOFindPort() znajdzie nam adres portu o
podanej nazwie z listy portów publicznych (oczywiôcie, jeôli taki
istnieje). Dwie ostatnie procedury -- obecne w ROM-ie od
systemów 2.0 w górë zakîadajâ (_LVOCreateMsgPort()) nowy port i
kasujâ go (_LVODeleteMsgPort()) z pamiëci, czyli alokujâ
(rezerwujâ) pamiëê potrzebnâ na strukturë naszego portu i
wypeîniajâ pewnymi danymi, bez których port nie bëdzie dziaîaî
oraz dealokujâ të pamiëê (zwalniajâ). Poniewaû -- jak juû
wspomniaîem -- procedury te dostëpne sâ jedynie od systemu 2.0,
na niûszych systemach musimy sië sami zatroszczyê o poprawne
zbudowanie struktury portu. Jak taka struktura wyglâda? Ano tak:
<l>
NT_MSGPORT Equ 4
MsgPort: dc.l 0 ; mp_MsgNode....ln_Succ
dc.l 0 ; ln_Pred
dc.b NT_MSGPORT ; ln_Type
dc.b 0 ; ln_Pri
dc.l PortName ; ln_Name
dc.b 0 ; mp_Flags
dc.b 0 ; mp_SigBit
dc.l 0 ; mp_SigTask/mp_SoftInt
dc.l 0 ; mp_MsgList lh_Head
dc.l 0 ; lh_Tail
dc.l 0 ; lh_TailPred
dc.b 0 ; lh_Type
dc.b 0 ; lh_pad
PortName: dc.b "Amsterdam",0
<txt>Jak widaê, nasz port skîada sië z trzech pomniejszych
struktur: ze struktury Node, z pól charakterystycznych dla
naszego portu i ze struktury List. Struktura Node (piëê
pierwszych pól) ma swoje zasîuûone miejsce w systemie Amigi. Jest
ona doîâczana do wielu innych struktur, co wskazuje na jej
uniwersalnoôê. I rzeczywiôcie. Dwa pierwsze pola moûemy spokojnie
wyzerowaê. Sâ one uûywane przez system, jeôli dopisaê nasz
MsgPort do listy portów publicznych (w pierwszym bëdzie adres
nastëpnego portu -- lub zero, jeôli nasz port jest ostatni na
liôcie, w drugim poprzedniego lub zero, jeôli nasz port jest
pierwszy na liôcie; nie powinno sië tych pól ani modyfikowaê, ani
odczytywaê -- sâ one do uûytku przez system). Trzecie pole --
ln_Type -- mówi nam o tym, do czego struktura Node jest
doczepiona. Poniewaû jest to port, ustawiamy wartoôê tego pola na
NT_MSGPORT (czyli 4). Nastëpny bajt -- ln_Pri -- to priorytet
naszego portu. Jeôli nasz program (port) bëdzie czësto
wyszukiwany z listy systemowej, warto ustawiê të wartoôê na
wiëkszâ od zera -- ulokuje to nasz port bliûej poczâtku listy
(lub moûe nawet na samym jej poczâtku), przez co zostanie
szybciej znaleziony. Jeôli mamy ôwiadomoôê, ûe port bëdzie
odszukany raz na tysiâc lat, moûna ustawiê priorytet na mniejszy
od zera -- wtedy port zostanie dodany bliûej koïca listy.
Najczëôciej jednak ustawia sië to pole na zero.
Ostatnie pole struktury Node to wskaúnik na nazwë naszego portu.
Jest ona dowolna i musi byê zakoïczona zerem. Wszystkie te pola
mogâ byê wyzerowane, jeôli nie bëdziemy dodawaê naszego portu do
listy (uwaga: mogâ byê one wyzerowane nawet, jeôli dodamy MsgPort
do listy, ale w wypadku, gdy ln_Name bëdzie równe zero, nie licz
na to, ûe znajdziesz adres tego portu, uûywajâc
_LVOFindPort()...). A co, jeôli port o nazwie, jakâ nadaliômy
naszemu portowi, juû istnieje? Tu jest maîy problem. Procedura
_LVOAddPort() nie zwraca nam ûadnej informacji o tym, czy port,
który chcemy dodaê, nie nazywa sië przypadkiem tak samo, jak
jeden z listy. Ona po prostu dodaje nam nasz port do listy i nie
przewiduje ûadnych kîopotów. Moûe wiëc wystâpiê sytuacja, gdy na
liôcie bëdzie kilka portów o takiej samej nazwie (uûywajâc
_LVOFindPort() dostaniesz adres portu znajdujâcego sië najwyûej
na liôcie o danej nazwie). Dlatego, aby uniknâê tej sytuacji,
warto uûyê _LVOFindPort() przed dodaniem naszej struktury MsgPort
do listy publicznej, aby przekonaê sië, czy port o takiej nazwie
juû istnieje. Jeôli tak, to moûemy wyjôê z programu, wysîaê do
portu jakiô komunikat (np. o tym, ûe uruchomiono drugi taki sam
program) i/albo zmieniê nazwë naszego portu (i oczywiôcie jeszcze
raz uûyê _LVOFindPort(), aû do skutku...).
Trzy kolejne pola -- mp_Flags, mp_SigBit i mp_SigTask (lub
mp_SoftInt; wyjaônienie dalej) wystëpujâ tylko w strukturze
MsgPort. Najpierw jednak opiszë mp_SigTask. W polu tym
najczëôciej znajduje sië adres naszego tasku (zadania), czyli
mówiâc proôciej adres struktury opisujâcej nasz program. Tak
naprawdë to uruchomienie kaûdego programu w systemie îâczy sië ze
stworzeniem przez system dodatkowej struktury -- wîaônie Task
(lub czasem Process), w której zawarte sâ pewne informacje
dotyczâce naszego programu i otoczenia, w jakim zostaî on
uruchomiony, np. tzw. current dir, nazwa naszego programu etc.
Poniewaû z pustego i "Salamon" nie naleje, zatem adres naszego
tasku musimy sami znaleúê i w tym polu umieôciê. Uûywamy do tego
procedury _LVOFindTask() (takûe z exec.library; zauwaû, ûe
funkcja ta dziaîa identycznie jak _LVOFindPort(), tyle ûe
wyszukuje taski, a nie porty), jako parametr zaô (wskaúnik na
nazwë zadania) podajemy zero -- oznacza to, ûe mamy znaleúê adres
struktury bieûâcego tasku, a nie jakiegoô tam z systemowej listy
tasków. Po zwróceniu adresu w d0, kopiujemy go wîaônie do pola
mp_SigTask.
Ale i wtedy nasz port nie bëdzie jeszcze gotowy do dziaîania (o
tym póúniej). Po co tam adres naszego tasku? Otóû multitasking
jest zrealizowany -- najproôciej mówiâc -- wîaônie dziëki
istnieniu listy z taskami, które sâ co chwila "po kawaîku"
wykonywane (tzn. struktura Task zawiera informacje o ostatnio
wykonanym rozkazie programu, który opisuje, i to ten program, a
nie task, jest wykonywany). Kiedy czekamy na komunikat, nasz
program nie robi nic, po co wiëc marnowaê czas procesora na
niepotrzebne pëtle? Istnieje wiëc druga lista -- lista tasków
czekajâcych, gdzie znajdujâ sië taski przeniesione z pierwszej
listy dziëki uûyciu procedury _LVOWaitPort(). Skoro wiëc
przenosimy task do innej listy, musimy znaê jego adres, stâd
zatem wynika potrzeba wpisania do struktury MsgPort adresu
naszego tasku. Po drugie zaô, kiedy port otrzyma komunikat, w
ogólnoôci nasz task przenoszony jest z powrotem na listë tasków
gotowych do wykonania, czyli znowu potrzebny jest jego adres.
Chyba wiëc jasne, ûe jeôli to pole bëdzie wyzerowane, to nie ma
co liczyê na poprawne dziaîanie, a w zasadzie na jakiekolwiek
dziaîanie funkcji _LVOWaitPort()?
Jeôli tak, to jedziemy dalej. Pole mp_SigTask nazwa sië teû
mp_SoftInt. Dlaczego? Wynika to z tego, ûe w zaleûnoôci od
ustawienia flag w polu mp_Flags, nasz program moûe sië róûnie
zachowywaê. Jeôli wiëc ustawimy odpowiedniâ flagë, nasz port moûe
po otrzymaniu komunikatu spowodowaê wywoîanie przez system
przerwania (_LVOCause()), którego adres struktury znajduje sië
wîaônie w polu mp_SoftInt. Dlatego pole to ma dwie nazwy.
To tyle w tym odcinku, za miesiâc zajmë sië polem mp_Flags.