|
Przykład 1: Tworzenie i zapisywanie do obszarówPrzykład 2: Czytanie plików w obszarze
Przykład 3: Uzyskiwanie dostępu do wyznaczonego obszaru
Przykład 4: Klonowanie i współdzielenie obszaru
Jako prosty przykład tworzenia i używania obszaru, tworzymy tutaj dziesięć stron obszaru i wypełniamy połowę z nich (bez konktretnego sensu) przez wstawienie wskaźnika:
area_id my_area;
char *area_addr, *ptr;
/* Tworzenie obszaru. */
my_area = create_area("mój obszar", /* nazwa przypisana do obszaru */
(void *)&area_addr, /* zwracany adres początkowy */
B_ANY_ADDRESS, /* obszar może się zaczynać gdziekolwiek */
B_PAGE_SIZE*10, /* rozmiar w bajtach */
B_NO_LOCK, /* Blokować w RAM? Nie. */
B_READ_AREA | B_WRITE_AREA); /* pozwolenia */
/* kontrola błedów */
if (my_area < 0) {
printf("Zdarzyło się coś złego!");
return;
}
/* Ustawienie wskaźnika ptr na początku obszaru. */
ptr = area_addr;
/* Wypełniaj połowę obszaru (danymi losowymi). */
for (int i; i < B_PAGE_SIZE*5; i++)
*ptr++ = system_time()%256;Możesz również wywołać memcpy() i strcpy() wewnątrz obszaru:
/* Kopiuj pierwszą połowę obszaru do drugiej połowy. */
memcpy(ptr, area_addr, B_PAGE_SIZE*5);
/* Nadpisanie początku obszaru. */
strcpy(area_addr, "Hej, popatrz gdzie jestem.");Kiedy wykonaliśmy już wszystko, usuwamy obszar:
delete_area(my_area);
Jest taka funkcja, która znajduje plik, otwiera go (ukryty w konstruktorze BFile), i kopiuje jego zawartość do RAM:
#include <File.h>
area_id file_area;
status_t file_reader(const char *pathname)
{
status_t err;
char *area_addr;
BFile file(pathname, B_READ_ONLY);
if ((err=file.InitCheck()) != B_OK) {
printf("%s: Nie można znaleźć lub otworzyć.n", pathname);
return err;
}
err = file.GetSize(&file_size);
if (err != B_OK || file_size == 0) {
printf("%s: Zgubiony? Pusty?n", pathname);
return err;
}
/* Zaokrągla rozmiar do najbliższej strony. */
file_size = (((file_size-1)%B_PAGE_SIZE)+1)*B_PAGE_SIZE;
/* Upewnij się że rozmiar nie przekroczy wartości size_t spec. */
if (file_size >= ((1<<32)-1) ) {
printf("%s: Co byś zrobił? Przeczytałbyś Montanę?n");
return B_NO_MEMORY;
}
file_area = create_area("Obszar pliku", (void *)&area_addr,
B_ANY_ADDRESS, file_size, B_FULL_LOCK,
B_READ_AREA | B_WRITE_AREA);
/* Sprawdza błędy create_area(), jak w poprzednim przykładzie. */
...
/* Przeczytaj plik; usuń obszar jeżeli jest tam błąd. */
if ((err=file.Read(area_addr, file_size)) < B_OK) {
printf("%s: Błąd odczytu pliku.n");
delete_area(file_area);
return err;
}
/* Plik jest automatycznie zamykany gdy jest oparty na stosie
* BFile jest niszczony.
*/
return B_OK;
}
W poprzednim przykładzie, zmienna lokalna (area_addr) była używana do przechwycenia adresu początkowego nowo utworzonego obszaru. Jeżeli trochę inna funkcja chce uzyskać dostęp do obszaru, to musi "ponownie znaleźć" adres początkowy (i długość obszaru, dla sprawdzonych granic). By to zrobić, wywołaj get_area_info().W następującym przykładzie, obszar jest przekazywany przez nazwę; funkcja, która będzie zapisywać jego bufor argumentu do obszaru, wywołuje get_area_info() aby określić początek i zasięg obszaru, a także by upewnić się, że obszar jest częścią tego zespołu. Gdyby obszar był tworzony przez trochę inny zespół, funkcja mogłaby jeszcze zapisać do niego, ale najpierw musiałaby ona sklonować ten obszar (klonowanie jest zademonstrowane w następnym przykładzie).
status_t write_to_area(const char *area_name,
const void *buf,
size_t len)
{
area_id area;
area_info ai;
thread_id thread;
thread_info ti;
status_t err;
if (!area_name)
return B_BAD_VALUE;
area = find_area(area_name);
/* Czy znaleźliśmy go? */
if (area < B_OK) {
printf("Nie mogę znaleźć obszaru %s.n", area_name);
return err;
}
/* Uzyskiwanie informacji. */
err = get_area_info(area, &ai);
if (err < B_OK) {
printf("Nie można uzyskać informacji o obszarze.n");
return err;
}
/* Uzyskaj zespół wywoływanego wątku; aby to zrobić, musimy
*zajrzeć do struktury thread_info.
*/
err = get_thread_info(find_thread(NULL), &ti);
if (err < B_OK) {
printf("Nie można uzyskać informacji o wątku.n");
return err;
}
/* Porównaj ten zespół z zespołem obszaru. */
if (ai.team != ti.team)
printf("Obcy obszar.n");
return B_NOT_ALLOWED;
}
/* Upewnij się nie spowodujemy przepełnienia obszaru,
* i upewnij się, że do tego obszaru można zapisywać.
*/
if (len > ai.size) {
printf("Bufor jest większy niż obszar.n");
return B_BAD_VALUE;
}
if (!(ai.protection & B_WRITE_AREA)) {
printf("Nie można zapisywać do tego obszaru.n");
return B_NOT_ALLOWED;
}
/* Teraz możemy zapisywać. */
memcpy(ai.address, buf, len);
return B_OK;
}Ważne jest to, że zapisujesz tylko do obszarów, które były utworzone albo sklonowane w granicach zespołu wywołującego. Adres początkowy "obcego" obszaru zwykle jest bez znaczenia w granicach twojej własnej przestrzeni adresowej.
Nie musisz sprawdzać ochrony obszaru przed zapisywanem do niego (albo czytaniem z niego). Funkcje uzyskiwania dostępu do pamięci (w tym przykładzie memcpy()) będą zwracać komunikat o błędzie segmentu jeżeli żądany jest nieupoważniony zapis lub odczyt.
W następującym przykładzie, serwer i klient są ustawieni do współdzielenia wspólnego obszaru. To jest serwer:
/* Strona serwera */
class AServer
{
status_t make_shared_area(size_t size);
area_id the_area;
char *area_addr;
};
status_t AServer::make_shared_area(size_t size)
{
/* Rozmiar musi być zaokrąglony do wielkości strony. */
size = ((size % B_PAGE_SIZE)+1) * B_PAGE_SIZE;
the_area = create_area("obszar serwera", (void *)&area_addr
B_ANY_ADDRESS, size, B_NO_LOCK,
B_READ_AREA|B_WRITE_AREA);
if (the_area < B_OK) {
printf("Nie można utworzyć obszaru serwera.n");
return the_area;
return B_OK;
}A to jest klient:
/* Strona klienta */
class AClient
{
status_t make_shared_clone();
area_id the_area;
char *area_addr;
};
status_t AClient::make_shared_clone()
{
area_id src_area;
src_area = find_area("obszar serwera");
if (src_area < B_ERROR) {
printf("Nie można znaleźć obszaru serwera.n");
return src_area;
}
the_area = clone_area("obszar klienta",
(void *)&area_addr,
B_ANY_ADDRESS,
B_READ_AREA | B_WRITE_AREA,
src_area);
if (the_area < B_OK)
printf(" Nie można utworzyć klonu obszaru.n");
return the_area;
}
return B_OK;
}Zauważ, że twórca obszaru (w tym przykładzie serwer) nie musi wyznaczyć utworzonego obszaru jako współdzielonego. Wszystkie obszary są kandytami do klonowania.
Gdy tworzy on obszar sklonowany, wartość area_id klienta (AClient::the_area) będzie inna wartości od serwera. Nawet gdy liczby area_id są globalne, klient powinien odnieść się tylko do liczby area_id serwera w kolejności jego klonowania. Po sklonowaniu, klient mówi do obszaru przez jego własny area_id (wartość przekazana zwrotnie przez clone_area()).
Czasem jest użyteczne dla współdzielonych obszarów (innymi słowy, "źródło" i klon) aby zaczynały się one w tym samym adresie początkowym. Na przykład, jeżeli obszar klonu klienta zaczyna się przy tym samym adresie jak oryginalny obszar serwera , wtedy klient i serwer może przekazać wskaźniki uzyskania dostępu do obszaru tam i z powrotem bez konieczności tłumaczenia adresów. Tutaj modyfikujemy poprzedni przykład by to pokazać:
status_t AClient::make_shared_clone()
{
area_id src_area;
src_area = find_area("obszar serwera");
if (src_area < B_ERROR) {
printf("Nie mozna znaleźć obszaru serwera.n");
return B_BAD_VALUE;
}
/* Tym razem, wyszczególniamy taki adres, przy którym chcemy,
* aby rozpoczynał się klon. Stała B_CLONE_ADDRESS
* robi to za nas.
*/
area_addr = src_info.address;
the_area = clone_area("obszar klienta",
(void *)&area_addr,
B_CLONE_ADDRESS,
B_READ_AREA | B_WRITE_AREA,
src_area);
if (the_area < B_OK)
printf("Nie można utworzyć obszaru klonu.n");
return the_area;
}
return B_OK;
}Oczywiście żądanie, żeby obszar zaczynał się przy określonym adresie może być zbyt ograniczające; jeżeli jakakolwiek pamięć wewnątrz [area_addr, area_addr + src_info.size] jest już przydzielona, klonowanie zawiedzie.
|
Be Book,
...w ślicznym HTML...
dla BeOS wydanie 5
Copyright © 2000 Be, Inc. Wszelkie prawa zastrzeżone.