to get the file
Transkrypt
to get the file
Systemy Transputerowe Programowanie transputerów Transputer Toolset Rozwój ● PP preprocesor „C” ● TCX kompilator ● TASM Transputer assembler ● TLINK linker/lokator ● TLIB obsługa bibliotek ● MAKE narzędzie do utrzymywania programu Ładowanie ● LD-ONE – loader do pojedynczego transputera ● LD-NET – loader do sieci transputerów ● CIO – host driver dla „C’ wejścia/wyjścia na transputerze ● TIO – prosty przykład drivera dla standardowego we/wy *.c ---> *.pp ---> *.tal ---> *.tlr ---> *.tld Kompilacja PP plik_wejściowy.c [-opcje] -o inna_nazwa -c 0 Nadmiar białych znaków redukowany do pojedynczego -c 1 pozwala na podmienienie makra w bloku #pragma asm -c 2 pozwala na rekursywne komentarze -c 3 zagnieżdżone dyrektywy # ##. -c 4 pozwala na ponowne #define tego samego symbolu przed #undefine -c 5 pozwala na rozpoznawanie i tłumaczenie 3znakowego kodu, znaków (tak jak w unixie) Kompilacja -d<nazwa_symbolu_makro>[=wartosc_marko] – pozwala na zdefiniowanie makra prosto z linii poleceń. Jak nie ma wartości makro to jest ona domyślnie = 1. Np. pp foo.c -dhi lub pp foo.c –dhi=1 -e nawet gdy wystąpią błędy to nie przerywaj. -i podajemy inna ścieżkę do includów. Ścieżka musi być jedna na jedno i. -l a numeracja lini #<line_number> -l l numeracja lini #line <line-number> -l n brak numeracji -s generuj statystyki Kompilacja -t a <string_of_char> dodaj wszystkie te znaki do preprocesora by wiedział że to są znaki -t n <string_of_char> to samo tylko odejmij te znaki które występują w string_of_char -u <macro_symbol_name> wprowadzenie makro symbolu -v tryb „gadatliwy” -z włączenie trybu debugowania. Tylko dostępny gdy właczono przy kompilacji w pp.h definicje DEBUG na TRUE -? pomoc Predefiniowane symbole __LINE__ __FILE__ __DATE__ __TIME__ __NEXT__ __NOW__ __PREV__ - numer lini - nazwa pliku - data systemowa - czas systemowy - symbole używane do kontrolowania aktywności generatora liczb unikalnych. TCX Cross kompilator tłumaczący na assembler transputerowy. Wywołanie: tcx plik_wejsciowy.pp [-options] Opcje: -c skompresuj wyjście przez usuwanie źródłowych informacji debugujących. -d włączenie debugowania samego kompilatora. -e mimo błędów zapisz na wyjściu to co się da TCX -f1..2 ustawia precyzję floatów, double i wyników pośrednich 32b lub 64b -i kompilator używa plików tymczasowych -mc<number> ustawia domyślny numer modułu do zapisu kodu? -mi<number> ustawia domyślny numer modułu do zapisu danych zainicjowanych -mu<number> ustawia domyślny numer modułu do zapisu danych niezainicjowanych -o <plik_wyjsciowy> nazwa pliku wyjsciowego TCX -p0 generuj kod zawierający tylko instrukcje do 32b transputerów. -p2 do transputerów T212/T222 -p25 do transputerów T225 -p4 do T414 -p45 dla T400/T425 -p8 dla T800 -p85 dla T801/T805 -pc typ czysty char zrób signed (domyślnie jest unsigned) -ps ?? -q0 wyłącz wewnętrzny post-pass optymalizer. -q1 -q2 -r -s -ti -to inne opcje optymalizacyjne. -v wyłącz „gadatliwy” tryb -w0 –w1 –w2 warning level TASM użycie: tasm plik_wejsciowy [<tymczasowy_katalog>] -[options] plik wejściowy podajemy bez rozszerzenia, pliki te mają domyślnie *.tal wiec podajemy np. dla foo.tal: tasm foo wynikiem jest *.tlr opcje: -c kompresja pliku wynikowego, pozbycie się opcji debugowania -l wygeneruj listning w assemblerze -o <plik_wyjsciowy> określenie nazwy pliku wyjsciowego -q{0|1|2} poziomom optymalizacji -v włącznik/wyłącznik trybu „gadatliwego” TLINK użycie: tlnk [plik_komend] najlepiej używać z plikiem komend a w nim FLAG „falgs (A|a|C|c|S|s) [none]:” TEMP „Temp file path [.]:” LIST „Listing file [NUL]:” INPUT „Input file(s) [.trl]” ENTRY „Entry point [_main]:” LIB „Library file(s) [.tld]:” OUTPUT „Output file [????????.tld]:” LOAD „Load address [0x????????]:” STACK „Stack address [0x????????]:” TLINK a – kolejność sortowania symboli c – usuń informacje debugerskie s – linkuj statycznie TEMP – ścieżka do pliku tymczasowego LIST – tworzenie pliku mapującego INPUT – plik wejściowy ENTRY – punkt wejścia LIB – biblioteki OUTPUT – plik wyjściowy LOAD – początkowy adres programu STACK – Adres stosu Uruchomienie LD-ONE Wywołanie: ld-one <plik_wykonywalny> <host_executable_filename> przykład ld-one hello cio LD-NET Wywołanie: ld-net <plik_opisujący_sieć> <argumenty> przykład ld-net line plik opisujący sieć ma rozszerzenie nif Plik *.nif 1, prog1, R0, 0, 2, , , 2, prog1, R1, 1, 3, , , 3, prog2, R2, 2, 4,4 , , 4, prog2, R2, 3, , 3, , 2 2 2 2 0 T1 1 0 T1 1 0 T1 1 0 T1 1 3 3 3 3 Biblioteka CONC Współbieżność w języku ansi C osiągnięta została za pomocą funkcji bibliotecznych wykonujących następujące operacje: tworzenie, szeregowanie, uruchamianie procesów ● komunikacja za pośrednictwem kanałów ● wyboru gotowego wejścia ● semaforowe ● Biblioteka CONC Oraz 3 typy danych Process – struktura opisująca każdy zadeklarowany proces <process.h> ● Channel – wskaźnik danej typu void wykorzystywany do tworzenia kanału <channel.h> ● Semaphor – struktura opisująca informacje o semforach <semaphor.h> ● Proces Procesy są zdefiniowane tak samo jak zwykłe funkcje języka C, z tym że wymagają stałego, pierwszego parametru. Musi nim być jej własny wskaźnik typu process. #include <process.h> void proc(Process *p, int a , int b) { p=p; /* tylko po to by nie było komunikatu „unused pointer...” */ /* tresc funkcji */ } Proces Przed pierwszym wywołaniem procesu musi nastąpić przydział pamięci oraz zainicjowanie struktury Process. ● Dokonuje się tego za pomocą funkcji ProcAlloc ● Procesy mogą działać synchronicznie lub asynchronicznie ● Te drugie działają nie zależnie od procesu który je wywołał i mogą działać nawet po zakończeniu rodziców. ● W trybie synchronicznym sterowanie powraca do rodzica w momencie zakończenia wszystkich procesów z wywołanej grupy ● Istnieje specjalny kanał przeznaczony do informowania o stanie procesów ● Stan procesów można zmieniać tyko za pośrednictwem kanałów. ● Proces ● Przydział pamięci i inicjacja odbywa się za pomocą Process *ProcAlloc(int (*func)(),int sp, int nparam,...); func - wskaźnik funkcji o wyniku int, z której zostanie utworzony równoległy proces, sp - rozmiar stosu w bajtach 4KB dla 32 bitowego i 1KB dla 16b. nparam – liczba słów wymaganych do przekazania parametrów funkcji; W przypadku niepowodzenia wartość zwrotna = NULL W przypadku sukcesu zwracany jest wskaźnik do struktury Process Proces Jeżeli chcemy wykorzystać już przydzieloną pamięć i chcemy tyko zainicjować to wołamy funkcję ProcInit. #include <con.h> ProcInit(p, func, ws, wssize, nparam, p1, p2, ..., pn) Process *p; int (*func)(); char *ws; int wssize; int nparam; parametry jej podobne ale ma jeszcze wskaźnik do procesu p oraz wskaźnik stosu ws i rozmiar wssize Proces #include <process.h> #include <stdlib.h> #define SIZE 4096 Process *p; char *ws; int nparam=2; if ((p=Process *)malloc(sizeof(Process))) == NULL) abort(); if (( ws = (int*)malloc(SIZE))==NULL) abort(); if (ProcInit(p,proc,ws,SIZE,nparam,1,2)) abort(); gdy funkcja się uda zwracane jest 0 Proces Do zmiany parametrów procesu z zarezerwowaną pamięcią służy ProcParam #include <process.h> void ProcParam(Process *p,...); liczba parametrów określonych ma być taka sama jak podana w deklaracji procesu. Proces Struktura Process wygląda następująco: typedef struct { Process *link; /* lista procesów */ int wsret; /* położenie końca obszaru roboczego */ int *wbase; /* wskaźnik stosu */ int wsize; /* rozmiar stosu */ int *wp; /* wskaźnik początku obszaru roboczego */ int psize; /*liczba słów zajmowanych przez parametry */ void (*func)(); /* wskaźnik funkcji (process) */ } Process; Proces Zwalnianie pamięci void ProcAllocCean(Process *p); void ProcInitClean(Process *p); proces zainicjowany przez ProcAlloc musi być zwalniany tylko przez ProcAllocClean proces zainicjowany przez ProcInit musi być zwalniany tylko przez ProcInitClean a następnie przez np. zwykłe free jak był przydzielany przez malloc. Proces Wywoływanie procesów void ProcPar(Process *p1, Process *p2,...,NULL); void ProcParList(Process **plist); Obie te funkcje służą do wywoływania procesów synchronicznie void ProcPriPar(Process *phigh, Process *plow); wywołuję parę procesów pierwszy o priorytecie wysokim drugi o priorytecie niskim Proces void ProcRun(Process *p); uruchamia proces asynchronicznie z priorytetem taki jak rodzic void ProcRunHigh(Process *p); uruchamia proces asynchronicznie z priorytetem wyższym void ProcRunLow(Process *p); uruchamia proces asynchronicznie z priorytetem niższym Proces Zarządzanie procesami void ProcAfter(int czas); opóźnienie w wykonywaniu do czasu nadejścia chwili określonej ilością kwantów czasu wskazywaną przez rejestr Timer0 lub Timer1 czyli (1uS lub 64uS) void ProcWait(int czas); Zawieszenie procesu na zadany ilością kwantów czas. void ProcReschedule(void); Przesunięcie aktywnego procesu na koniec kolejki procesów. Umożliwia to reazlicację operacji aktywnego czekania. Proces void ProcStop(void); Zatrzymuje bieżący proces przez ciągłe ustawianie go na końcu kolejki. Zatrzymany w ten sposób proces nie może zostać wznowiony. int ProcGetPriority(void); zwraca priorytet procesu, PROC_HIGH = 1 lub PROC_LOW = 0. Proces Pomiar czasu int ProcTime(); służy do określania czasu, zwraca bieżącą wartość zegara transputera int ProcTimePlus(const int czas1, const int czas2); int ProcTimeMinus(const int czas1, const int czas2); Funkcje te zwracają wynik dodawania i różnicy modulo dla argumentów wyznaczanych z funkcji ProcTime(); int ProcTimeAfter(const int czas1, const int czas2); zwraca 1 gdy moment czas1 nastąpił po czas2 lub 0 w przeciwnym razie. Kanały Przykład: #include <channel.h> #include <stdlib.h> Channel c1, *c2; ChanInit(&c1); ChanInit(c2=(channel*)malloc(sizeof(channel))); Kanały Wejście wyjście przez kanał void ChanOut(Channel *ch, void *cp, int count); zapisuje do kanału ch dane z cp o ilości count void ChanIn(Channel *ch, void *cp, int count ); Odczytuje dane z kanału dane do cp o ilości count. Kanały void ChanOutChar(Channel *ch, char c); zapisuje do kanału ch znak c. char ChaninChar(Channel *ch); odczytuje znak z kanału ch i zwraca jako wartość; void ChanOutInt(Channel *ch, int n); zapisuje wartość int n do kanału ch int ChanInInt(Channel *ch); odczytuje wartość int z kanału ch i zwraca jako wartość. Kanały Adresy kanałów są zdefiniowane następująco: #define #define #define #define #define #define #define #define LINK0OUT LINK1OUT LINK2OUT LINK3OUT LINK0IN LINK1IN LINK2IN LINK3IN ((Channel*) ((Channel*) ((Channel*) ((Channel*) ((Channel*) ((Channel*) ((Channel*) ((Channel*) 0x80000000) 0x80000004) 0x80000008) 0x8000000C) 0x80000010) 0x80000014) 0x80000018) 0x8000001C) Kanały #include #include #include #include #include <stdio.h> <string.h> <stdlib.h> <process.h> <channel.h> void we(Process *p, Channel *kan) { char inf[21]; p=p; printf(„\nWprowadz tekst (maks 20 znakow):”); gets(inf); ChanOut(kan,inf,21); } void wysw(Process *p,Channel *kan) { char nazwa[21]; p=p; ChanIn(kan,nazwa,21); printf(„\n%s”,nazwa); } Kanały int main() { process *p1, *p2; Channel *kan; if ((kan=ChanAlloc())) == NULL) exit(1); if ((p1=ProcAlloc(we,1024,1,kan)) == NULL) exit(1); if ((p2=ProcAlloc(wysw,1024,1,kan)) == NULL) exit(1); ProcPar(p1,p2,NULL); exit(0); } Niezawodne protokoły Omówione wcześniej funkcje nie gwarantują rozpoznania uszkodzenia linku. Osiągnięto to przez parametr time-out w grupie funkcji TimeFail, lub specjalnego dodatkowego kanału monitorującego obsługiwanego przez grupę ChanFail. Niezawodne protokoły int ChanOutTimeFail(Channel *ch, void *cp, int count, int time); Jeżeli w czasie time nie uda się wysłać danych zwróć błąd int ChanOutChanFail(Channel *ch, void *cp, int count, Channel *failc); Jeżeli w czasie time nie uda się wysłać danych wyślij do kanału failc int ChanInFail(Channel *ch, void *cp, int count, int time); Jeżeli w czasie time nie uda się odebrać danych zwróć błąd int ChanInChanFail(Channel *ch, void *cp, int count, Channel *failc); Jeżeli w czasie time nie uda się odebrać danych wyślij do kanału failc. Niezawodne protokoły cp to wskaźnik obszaru gdzie dane zostaną umieszczone bądź skąd zostaną pobrane. ● ilość danych określa count ● time określa czas po którego upływie w razie braku komunikacji zostaje wykonywane przerwanie. ● failc jest wskaźnikiem kanału z procesu monitorującego sprawność połączenia przez link. ● wartość 0 zwracana przez powyższe funkcje to pomyślne zakończenie w przeciwnym wypadku –1. ● Wybór gotowego wejścia intProcAlt(Channel *c1,Channel *c2,...,NULL); intProcAltList(Channel **chlist); Służą do wybrania z podanej listy kanału gotowego do czytania. ● Zawieszają dany proces do momentu aż któryś z kanałów nie będzie gotowy. ● Jak już będzie to zwracany jest indeks z podanej listy kanałów licząc od 0. ● Wybór gotowego wejścia int ProcSkipAlt(Channel *c1, Channel *c2,...,NULL); int ProcSkipAltList(Channel **chanlist); ● Podobnie jak poprzednie z tym że tu nie czekają, jak nie ma to zwracane jest –1. int ProcTimerAlt(int timer, Channel *c1, Channel *c2,...,NULL); int ProcTimerAltList(int timer, Channel **chanlist); ● Tu czekają tylko określoną ilość czasu jak nie to zwracana jest -1 Semafory Mechanizm semaforów gwarantuje niepodzielny dostęp do zasobów. Rozwiązanie zaproponowane przez Holenderskiego matematyka Dijkstrę w 1965 r. Definicja typu semaforowego Semafor jest zmienną całkowitoliczbową ● przyjmuje wartości nieujemne ● Jedyne operacje, za wyjątkiem inicjacji, to ● WAIT, P(holenderskie słowo passeren przejść, proberen próbować), opuszczanie ● SIGNAL, V(vrijmaken – zwolnić, verhogen zwiększyć), podnoszenie. ● Operacje te są nie podzielne. ● Inicjacja jest dokonywana poza procesami, które z niego korzystają ● Na semaforach nie wykonujemy operacji sprawdzania. ● Semafor ogólny P(S): jeśli S>0 to S:= S-1, w przeciwnym przypadku wstrzymaj działanie procesu wykonującego tę operację. V(S): jeśli są procesy wstrzymane w wyniku P(S), to wznów jeden z nich, w przeciwnym przypadku S:=S+1. Operacje Semaforowe Rozpoczęcie wykonywania operacji semaforowych musi być poprzedzone deklaracją i inicjowaniem semafora przez jedną z dwóch dostępnych po dołączeniu zbioru semaphor.h funkcji: Semaphore *SemAlloc(int wartosc); zainicjuje i przydzieli pamięć void SemInit(Semaphore *sem,int wartosc); tylko zainicjuje więc pamięć przydzielona już musi być. Operacje Semaforowe void SemWait(Semaphore *sem); (P) opuszczenie semafora void SemSignal(Semaphore *sem); (V) podniesienie semafora Operacje semaforowe #include #include #include #include <stdio.h> <stdlib.h> <process.h> <semaphor.h> double x=10; Semaphore *sek_kryt, *sek_gl; void proc_1(Process *p) { SemWait(sek_kryt); p=p; x=2*x; printf(„%g”,x); SemSignal(sek_kryt); SemSignal(sek_gl); } int main(void) { Process *p1; sek_kryt = SemAlloc(1); sek_gl=SemAlloc(0); if ((p1=ProcAlloc(proc_1,0,0) == NULL) exit(1); ProcRun(p1); Sem(Wait(sek_gl); exit(0); }