ZADANIE SEMESTRALNE Z LABORATORIUM PROGRAMOWANIA WSPOLBIEZNEGO 1995 Napisac serwer do grupowej asynchronicznej komunikacji miedzy procesami wykonujacymi sie we wspolnej pamieci operacyjnej (czyli na tej samej maszynie). Komunikacja grupowa polega na tym, ze proces wysyla jeden komunikat do wszystkich czlonkow wskazanej grupy (z wyjatkiem siebie samego). Serwer dostarcza ten komunikat czlonkom grupy na ich zadanie (czyt. zondanie). Rozwiazanie musi zapewniac, ze komunikaty beda dostarczane kazdemu odbiorcy w takiej samej kolejnosci, w jakiej zostaly nadane do serwera. Slowo "asynchroniczne" oznacza tu, ze nadawca komunikatu jest wstrzymywany jedynie do chwili odebrania go przez serwer, a nie do chwili odebrania go przez wszystkich czlonkow grupy. Odbieranie komunikatow jest synchroniczne, przy czym mozna probowac odebrac komunikat w sposob nieblokujacy. Serwer nie powinien wypisywac zadnych informacji na standardowy strumien wyjsciowy (ani zaden inny). Dla programow uzytkowych serwer ma byc dostepny przez nastepujace funkcje biblioteczne: grp_create() - tworzy nowa grupe i dodaje do niej jej tworce; grp_join() - dodaje wywolujacy proces do wskazanej grupy; grp_leave() - usuwa wywolujacy proces ze wskazanej grupy (proces powinien do tej grupy nalezec) i usuwa pusta grupe; grp_send() - wysyla komunikat do wskazanej grupy (do ktorej sam nalezy), jesli brak miejsca w buforach serwera na przechowanie tego komunikatu, to operacja jest blokujaca; grp_receive() - odbiera kolejny komunikat przeznaczony do wskazanej grupy, (proces powinien do tej grupy nalezec); jesli nie ma zadnego komunikatu, jest to operacja blokujaca; grp_info() - przekazuje aktualny stan serwera. A oto dokladna specyfikacja tego interfejsu: #define ERR_BADARG -1 /* bledny argument */ #define ERR_NOMEM -2 /* brak pamieci na bufory */ #define ERR_EXISTS -3 /* grupa juz istnieje */ #define ERR_NOGRP -4 /* grupa nie istnieje */ #define ERR_BELONGS -5 /* proces nalezy juz do tej grupy */ #define ERR_NOPLACE -6 /* grupa juz osiagnela maksymalna wielkosc */ #define ERR_NOTBEL -7 /* proces nie nalezy do grupy */ #define ERR_NOTSND -8 /* komunikatu nie wyslano */ #define ERR_NOTRCV -9 /* komunikatu nie odebrano */ #define NO_WAIT 1 /* proces nie czeka na wyslanie/odbior */ #define STANDARD 2 /* proces czeka */ /* funkcja grp_create przekazuje dodatni identyfikator grupy lub liczbe ujemna informujaca o przyczynie bledu (ERR_BADARG, ERR_NOMEM, ERR_EXISTS) */ int grp_create(key, maxgroup, bufsize) long key; /* klucz identyfikujacy grupe */ int maxgroup; /* maksymalny rozmiar grupy (> 0) */ int bufsize; /* rozmiar puli buforow */ /* funkcja grp_join przekazuje (dodatni) identyfikator grupy lub liczbe ujemna informujaca o przyczynie bledu (ERR_NOGRP, ERR_BELONGS, ERR_NOPLACE) */ int grp_join(key) long key; /* klucz identyfikujacy grupe */ /* Funkcja grp_leave przekazuje 0 lub liczbe ujemna informujaca o przyczynie bledu (ERR_NOGRP, ERR_NOTBEL) */ int grp_leave(grpid) int grpid; /* identyfikator grupy */ /* Funkcja grp_send przekazuje 0 lub liczbe ujemna informujaca o przyczynie bledu (ERR_NOGRP, ERR_NOTBEL, ERR_NOTSND) */ int grp_send(grpid, buf, size, flags) int grpid; /* klucz identyfikujacy grupe */ char *buf; /* bufor z komunikatem */ int size; /* rozmiar bufora */ int flags; /* flagi: STANDARD - proces czeka na wstawienie komunikatu do bufora serwera, NO_WAIT - utrata komunikatu, jesli serwer nie ma nan miejsca */ /* Funkcja grp_receive przekazuje liczbe przeczytanych bajtow lub liczbe ujemna informujaca o przyczynie bledu (ERR_NOGRP, ERR_NOTBEL, ERR_NOTRCV) */ int grp_receive(grpid, buf, size, flags) int grpid; /* klucz identyfikujacy grupe */ char *buf; /* bufor na komunikat */ int size; /* rozmiar bufora */ int flags; /* flagi: STANDARD - proces czeka na odebranie komunikatu, jesli nie ma go w buforze sewera, NO_WAIT - proces nie czeka */ grpstat grp_info(param) struct par { } param; struct grpstat{ } /* Zawartosc tych struktur moze byc przedmiotem dyskusji */ Mozna zastosowac dowolny znany mechanizm do komunikacji miedzy procesami (potoki, kolejki FIFO, kolejki komunikatow, semafory, pamiec dzielona, a nawet zdalne wywolania procedury). Kryteria doboru narzedzi komunikacji beda jednak oceniane. Preferowane beda rozwiazania wydajniejsze i mniej "pamieciozerne". Termin realizacji pierwszego etapu tego zadania mija 14.06.1995. Do tego czasu kazdy student powinien dostarczyc: - dokumentacje techniczna i uzytkowa swojego rozwiazania, - kod zrodlowy serwera i funkcji bibliotecznych, - kod wykonywalny serwera i skompilowana biblioteke funkcji dostepu do serwera. W drugim etapie kazdy student otrzyma 5 kodow wykonywalnych serwerow (w tym zapewne swoj) oraz 5 odpowiadajacych im implementacji bibliotek. Zadaniem studenta bedzie opracowanie i przeprowadzenie intensywnych testow, ktorych celem jest porownanie dzialania serwerow w roznych warunkach. Testy powinny badac przepustowosc serwera dla roznych rozkladow wielkosci przesylanych komunikatow i wielkosci grup, wykorzystanie przez niego pamieci, odpornosc serwera na zjawiska zaglodzenia i blokady. Testy powinny byc takze udokumentowane. W dokumentacji do drugiego etapu powinny sie znalezc: - opis przeprowadzonych testow z uzasadnieniem ich doboru, - zestawienie uzyskanych wynikow w postaci tabelek badz wykresow, - wnioski, a w nich ocena testowanych rozwiazan. Termin realizacji drugiego etapu mija 30.06.1995. Jesli odpowiednia liczba studentow ukonczy pierwszy etap przed wyznaczonym terminem, to beda oni mogli wczesniej przystapic do realizacji etapu drugiego.