PORTY (2) Kontynuujemy wycieczkë po portach. Bynajmniej nie ûaglowce i fale morza nam w gîowie, ale wnëtrznoôci systemu operacyjnego Amigi. Cromax/Alchemy W polu mp_Flags ustawiamy flagi (bity) maskowane *) przez PF_ACTION, które mówiâ nam, jak ma sië zachowaê nasz program po dotarciu do portu komunikatu. Flagi te to: PF_ACTION Equ 3 ; Maska PA_SIGNAL Equ 0 ; Zasygnalizuj Task (zadanie) w polu mp_SigTask (najczëôciej uûywane) PA_SOFTINT Equ 1 ; Zasygnalizuj SoftInt (przerwanie) w polu mp_SoftInt PA_IGNORE Equ 2 ; Zignoruj przybycie wiadomoôci Flaga PA_SIGNAL jest uûywana -- jak mi sië zdaje -- najczëôciej i taka teû jest uûyta w doîâczonym przykîadzie. PA_SOFTINT to wîaônie ta flaga, która powoduje wywoîanie przez system przerwania, której wskaúnik do struktury jest umieszczony w mp_SoftInt (czyli mp_SigTask). Trzecia, ostatnia flaga -- PA_IGNORE -- powoduje wprawdzie zatrzymanie w porcie wiadomoôci, która do niego przybywa, ale oprócz tego nic sië nie dzieje -- Task nie jest sygnalizowany, zresztâ tak samo jak ewentualne przerwanie. Zostaîo jeszcze pole mp_SigBit, jednak tak jak procedury _LVOWait(), _LVOAllocSignal() oraz _LVOFreeSignal() zostanâ one opisane na koïcu, gdyû do najprostszej komunikacji miëdzy portami nie sâ potrzebne, chociaû dziëki nim moûna efektywniej programowaê. Pamiëtaj jednak o wpisaniu do mp_SigTask/mp_SoftInt adresu Tasku/struktury SoftInt. Zostaîo jeszcze piëê pól, a w zasadzie cztery, które tworzâ strukturë List. W tym miejscu bëdâ umieszczane wskaúniki do napîywajâcych komunikatów. Poniewaû struktura Message (opisana poniûej) takûe -- jak MsgPort -- zawiera w sobie strukturë Node, moûe byê wiëc elementem listy dwukierunkowej. Tak teû sië dzieje. W strukturze mp_MsgList moûna znaleúê wskaúnik do pierwszego komunikatu, jaki przybyî, w pierwszym komunikacie adres do nastëpnego itd. Ûeby sië zbytnio nie mëczyê, do odczytywania komunikatów uûywamy procedury _LVOGetMsg(), która zwróci nam w d0 adres pierwszego dostëpnego komunikatu i dodatkowo usunie go z listy komunikatów oczekujâcych w porcie. Aby jednak naszego MsgPortu moûna byîo w koïcu uûyê, musimy jeszcze wypeîniê owâ strukturë List (jeôli nasz port stanie sië publicznym, procedura _LVOAddPort() zrobi to juû za nas). Moûna do tego celu uûyê -- jeôli korzystasz z include'ów -- macra NEWLIST, jeôli zaô masz awersjë do tego rodzaju "uîatwieï", moûesz skorzystaê z przykîadu (który zresztâ zostaî ûywcem przepisany z w/w macra... 8). Pierwsze trzy pola to nagîówek listy -- w polu lh_Head musi sië znaleúê adres pola lh_Tail, lh_Tail musi zostaê wyzerowane (to pole zawsze bëdzie równe zero), do lh_TailPred zaô naleûy wpisaê adres pola lh_Head. Przeôledúcie zresztâ przykîad, a dojdziecie sami, w czym rzecz. Pole lh_Type zerujë -- okreôla ono zapewne typ nagîówka, ale nigdzie w materiaîach nie spotkaîem sië z wpîywem wartoôci tego pola na dziaîanie portu. Po prostu wyzeruj. No i ostatnie quasi-pole to wyrównanie do parzystego adresu -- nie sâ tam zapisywane ûadne informacje, istnieje ono tylko po to, ûeby ewentualna kolejna struktura czy kod, znajdujâce sië po strukturze MsgPort, zaczynaîa sië od parzystego adresu. Tak wyglâda struktura MsgPort, ale co z Message? Otóû struktura ta skîada sië ze swego rodzaju nagîówka i... absolutnie wszystkiego, czego sobie zaûyczysz. Od nas bëdzie zaleûaîo, jakie komunikaty (i jakiej treôci) bëdziemy wysyîaê. Nagîówek zawiera -- jak wiele struktur w systemie -- Node oraz informacje na temat portu, skâd wiadomoôê przyszîa oraz jaka jest jej dîugoôê: NT_MESSAGE Equ 5 Message: dc.l 0 ; mn_Node.......ln_Succ dc.l 0 ; ln_Pred dc.b NT_MESSAGE ; ln_Type dc.b 0 ; ln_Pri dc.l 0 ; ln_Name dc.l MsgPort ; mn_ReplyPort dc.w 20+n ; mn_Length ;-------------------------------------- blk.b n ; nasze dane, czyli tzw. "message body" W tym wypadku musimy sië zatroszczyê o wartoôê pola ln_Type (NT_MESSAGE), o mn_ReplyPort (jest to adres struktury MsgPort, np. tej zdefiniowanej powyûej) oraz o mn_Length, gdzie wpisujemy dîugoôê struktury Message (20 bajtów) plus dîugoôê bloku naszych danych. Naleûy pamiëtaê, ûe ze wzglëdu na to, iû pole mn_Length jest sîowem, maksymalna dîugoôê Message nie moûe przekroczyê 64 KB (oczywiôcie moûna to zignorowaê i wysyîaê dîuûsze komunikaty, tyle ûe sami gdzieô w treôci Message powinniômy okreôliê jego dîugoôê -- jeôli nam na tym zaleûy...). Przykîadowa struktura Message moûe wyglâdaê nastëpujâco: MyAge: Equ 21 ; juû tyle?! Weight: Equ 77 ; schudîem!!! 8) Height: Equ 179 ; niestety juû nie rosnë... Message: dc.l 0 dc.l 0 dc.b NT_MESSAGE dc.b 0 dc.l 0 dc.l MsgPort dc.w 20+11 ; dîugoôê struktury Message + Message Body ;---------------------------- tu zaczynajâ sië nasze dane... dc.l Nick ; 4 bajty dc.l Group ; 8 bajtów dc.b MyAge ; 9 bajtów dc.b Weight ; 10 bajtów dc.b Height ; 11 bajtów (dîugoôê naszego "message body") ;---------------------------- a tu sië koïczâ. even ; na wszelki wypadek... Nick: dc.b "Cromax",0 MyGirl: dc.b "Agatka",0 Jak widaê, nasza wiadomoôê zawiera takûe wskaúniki do nazw, co jest jednak dozwolone -- w ten sposób moûna ominâê "limit" 64 KB. Uwaga: jeûeli wysyîamy do jakiegoô portu Message, zawierajâcy wskaúniki (jak w powyûszym przykîadzie), to dopóki tamten Task nie odpowie, nie moûemy zmieniaê/dealokowaê pamiëci, których adresy wysîaliômy; w przeciwnym wypadku trzeba sië liczyê z niepoprawnym dziaîaniem programu. Kiedy juû wyjaôniliômy sobie budowë struktur i znaczenie pól, moûemy przejôê do szczegóîowego omówienia procedur. Sâ to wîasnorëcznie (ta taa!) opracowane opisy procedur na podstawie tzw. AutoDoców: exec.library/AddPort ZARYS AddPort (port)/(A1) -- dodaj publiczny port komunikacyjny do systemu FUNKCJA Funkcja ta dodaje strukturë MsgPort do systemowej listy portów publicznych, gdzie moûe ona zostaê póúniej znaleziona dziëki funkcji FindPort(). Zanim jednak omawiana funkcja zostanie wywoîana, naleûy zainicjalizowaê pola mp_Name i mp_Pri (nazwa i priorytet) struktury portu. Jeôli uûytkownik nie wymaga szczególnego priorytetu, to wartoôê pola priorytetu powinna byê wyzerowana. Jedynie te porty, które bëdâ wyszukiwane dziëki funkcji FindPort(), wymagajâ dodania ich do systemowej listy. Jeôli port bëdzie w ogóle wyszukiwany, to pole priorytetu powinno byê równe co najmniej 1 (aby uniknâê z reguîy duûej liczby nieaktywnych portów o priorytecie zero). Jeûeli natomiast port bëdzie czësto wyszukiwany, warto ustawiê priorytet w zakresie od 50 do 100 (wtedy znajdzie sië przed innymi, rzadziej uûywanymi portami). Kiedy juû port zostanie dodany do listy, musisz uwaûaê, aby usunâê go stamtâd (przez funkcjë RemPort), zanim zwolnisz zaalokowanâ dla niego pamiëê. UWAGI Naleûy pamiëtaê, ûe wypeînienie struktury MsgPort samymi zerami nie jest wystarczajâce, aby byîa ona zdatna do uûycia. Tak jak zostaîo wspomniane w rozdziale "Exec", w ROM Kernel Manual, naleûy zainicjalizowaê najpierw strukturë List, bëdâcâ skîadowâ struktury MsgPort. Operacja ta jest automatycznie przeprowadzana przez funkcje AddPort() oraz amiga.lib/CreatePort (a takûe exec.library/CreateMsgPort dla systemów +2.0 -- przyp. tîum.). Inicjalizacja moûe zostaê teû przeprowadzona wîasnorëcznie przy uûyciu funkcji amiga.lib/NewList lub asemblerowego macra NEWLIST. Nie wykonuj funkcji AddPort() na aktywnym porcie (tzn. po wykonaniu na nim funkcji _LVOWait() czy _LVOWaitPort() -- przyp. tîum.) WEJÔCIE port -- Wskaúnik do portu komunikacyjnego. exec.library/RemPort ZARYS RemPort (port)/(A1) -- usuï port komunikacyjny z systemu FUNKCJA Ta funkcja usuwa strukturë portu komunikacyjnego z systemowej listy publicznych portów komunikacyjnych. Poúniejsza próba znalezienia tego portu po jego nazwie zakoïczy sië niepowodzeniem. WEJÔCIE port -- Wskaúnik do portu komunikacyjnego. exec.library/PutMsg ZARYS PutMsg (port, message)/(A0,A1) -- umieôê wiadomoôê w porcie komunikacyjnym FUNKCJA Funkcja ta dodaje wiadomoôê do koïca danego portu komunikacyjnego. Wykorzystuje ona szybki, "nie-kopiujâcy" mechanizm wysyîania komunikatów. Komunikaty mogâ byê doîâczane tylko do jednego portu naraz. Rozmiar czy forma wiadomoôci moûe byê zupeînie dowolna. Poniewaû komunikat nie jest kopiowany, wspóîdziaîajâce zadania dzielâ të samâ pamiëê zajmowanâ przez wiadomoôê. Zadanie, które wysîaîo komunikat, nie moûe zwolniê pamiëci zajëtej przez treôê komunikatu, dopóki odbiorca nie wyôle odpowiedzi. Oczywiôcie zaleûy to od traktowania przychodzâcych wiadomoôci oraz konwencji przyjëtych przez zwiâzane ze sobâ zadania. Jeûeli pole ReplyPort jest róûne od zera, to kiedy odbiorca odpowie na komunikat, zostanie on wysîany z powrotem do portu, którego adres znajduje sië w powyûszym polu. Gdy zostanie wysîana wiadomoôê, moûliwe jest wykonanie jednej z poniûszych czynnoôci: 1. brak jakiejkolwiek akcji; 2. zasygnalizowanie danego zadania (wyspecyfikowanego przez mp_SigTask); 3. spowodowanie software'owego przerwania (wyspecyfikowanego przez mp_SigTask). Wykonanie czynnoôci zaleûy od wartoôci znajdujâcej sië w polu mp_Flags portu docelowego. WEJÔCIE port -- Wskaúnik do portu komunikacyjnego. message -- Wskaúnik do komunikatu. exec.library/GetMsg ZARYS message (D0) = GetMsg (port)/(A0) -- pobierz nastëpny komunikat z portu FUNKCJA Funkcja ta odbiera wiadomoôê z podanego portu komunikacyjnego. Wykorzystuje ona szybki, "nie-kopiujâcy" mechanizm odbierania komunikatów. Odebrana wiadomoôê jest usuwana z listy komunikatów w porcie. Opisywana funkcja nie czeka na przybycie komunikatu do portu. Jeôli w porcie nie ma ûadnej wiadomoôci, funkcja zwróci zero. Jeôli program musi czekaê na komunikat, naleûy uûyê funkcji Wait(), czekajâcej na sygnaî dla portu lub funkcji WaitPort(). Na dany port moûe czekaê tylko jedno zadanie (dlatego nie moûna czekaê na porty z listy systemowej, bo jakiô Task moûe juû na niego czekaê -- przyp. tîum.). Pobranie komunikatu nie jest dla zadania wysyîajâcego jednoznaczne z tym, ûe komunikat juû jest wolny i ûe moûna np. zwolniê pamiëê przez niego zajmowanâ. Kiedy odbiorca skoïczy analizowaê wiadomoôê, moûe jâ odesîaê z powrotem do nadawcy za pomocâ funkcji ReplyMsg(). Pobranie sygnaîu NIE ZAWSZE równa sië z otrzymaniem komunikatu. Sygnaî informuje, ûe do portu przybyîa wiëcej niû jedna wiadomoôê, sygnaîy zaô mogâ sië ukazywaê bez komunikatów. Najczëôciej musisz zapëtliê GetMsg() do momentu, kiedy zwróci zero, a dopiero potem znowu uûyê Wait() czy WaitPort(). WEJÔCIE port -- Wskaúnik do portu komunikacyjnego odbiorcy. WYJÔCIE message -- Wskaúnik do pierwszego dostëpnego komunikatu. Jeôli brak wiadomoôci, zostanie zwrócone zero. Naleûy byê przygotowanym na zero w kaûdej chwili. (Cdn.)