2017-05-13 8 views
9

Czy możliwe jest - i jeśli jest to rozsądne - użycie sendfile() (lub jego kuzyna Darwin/BSD) w celu przenoszenia danych bezpośrednio między współdzielonymi obiekt pamięci i plik?Kopiowanie danych z obiektu odwzorowanego w pamięci dzielonej przy użyciu funkcji sendfile()/fcopyfile()

Funkcje takie jak sendfile() i fcopyfile() może wykonywać wszystkie mechanicznych potrzeb leżących u podstaw takich transferów danych całkowicie bez wychodzenia kernel-przestrzeń - można przejść wzdłuż dwóch otwartych deskryptorów, źródła i miejsca przeznaczenia, podczas wywoływania tych funkcji, i biorą go stamtąd.

Inne środki kopiowania danych niezmiennie wymagają ręcznego manewrowania przez granicę między przestrzenią jądra i przestrzenią użytkownika; takie przełączniki kontekstu są z natury dość kosztowne, pod względem wydajności.

Nie mogę znaleźć niczego definitywnego na temat użycia deskryptora pamięci dzielonej jako argumentu w następujący sposób: brak artykułów za lub przeciw praktyce; nic na odpowiednich stronach; żadne tweety publicznie nie biorą pod uwagę sendfile() - szkodliwe są deskryptory pamięci dzielonej; & c ... Ale tak, myślę, że powinien być w stanie zrobić coś takiego:

char const* name = "/yo-dogg-i-heard-you-like-shm"; /// only one slash, at zero-index 
int len = A_REASONABLE_POWER_OF_TWO;    /// valid per shm_open() 
int descriptor = shm_open(name, O_RDWR | O_CREAT, 0600); 
int destination = open("/tmp/yodogg.block", O_RDWR | O_CREAT, 0644); 
void* memory = mmap(NULL, len, PROT_READ | PROT_WRITE, MAP_SHARED, descriptor, 0); 
off_t bytescopied = 0; 
sendfile(destination, descriptor, &bytescopied, len); 
/// --> insert other stuff with memset(…), memcopy(…) &c. here, possibly 
munmap(memory, len); 
close(descriptor); close(destination); 
shm_unlink(name); 

... Jest to błędne, lub ważny technika?

A jeśli to drugie, czy można dostosować rozmiar udostępnionej mapy w pamięci przed skopiowaniem danych?


EDYCJA: Rozwijam projekt, którego dotyczy to zapytanie na temat systemu MacOS 10.12.4; Dążę do tego, aby działał pod Linuksem, z ewentualną interoperacyjnością FreeBSD.

+0

Co się stało, gdy próbowałeś? – EJP

+0

@EJP Nie próbowałem tego dokładnego schematu - 3-uderzeniowe uderzenie combo 'shm_open()', 'mmap (..., MAP_SHARED, ...)' i 'sendfile()' - jeszcze z dwóch powodów. Po pierwsze, pomniejszy punkt: jestem teraz rozwijający się natywnie na macOS, więc mój 'sendfile()' jest polyfill przy użyciu 'fcopyfile()' ... po drugie: moje bieżące zadanie polega na zaimplementowaniu dostępu do mapowanej pamięci przez odwzorowanie jej pamięci klasa wrapper (które to opakowanie oferuje już tylko mapy pamięci tylko do odczytu, qv https://github.com/fish2000/libimread/blob/master/src/file.cpp#L115-L140); Będę używał tego, czego się nauczyłem, robiąc to i z SO, na problemie z dzieloną pamięcią. – fish2000

Odpowiedz

3

Kopiowanie danych między dwiema "rzeczami" zmapowanymi w pamięci - jak w powyższym przykładzie - rzeczywiście będzie wymagało skopiowania rzeczy z jądra do przestrzeni użytkownika, a następnie z powrotem. I nie, naprawdę nie można używać funkcji systemowej sendfile (2) do wysyłania do deskryptora plików, obawiam się.

Ale powinieneś być w stanie zrobić to tak:

  1. Tworzenie obiekt udostępniony pamięci (lub plik, naprawdę; ze względu na drugim etapie zostanie ona wspólną pamięć i tak
  2. mapę w pamięci, z MAP_SHARED; dostaniesz wskaźnik
  3. Otwórz plik docelowy
  4. write (destination_fd, source_pointer, source_length)

W tym przypadku system zapisu nie będzie musiał kopiować danych do procesu. Nie jestem jednak pewien, jaka będzie rzeczywista charakterystyka wydajności. Pomóc może inteligentne wykorzystanie madvise (2).

+0

Dobrze wiedzieć - i dzięki za podpowiedź na temat używania 'write (...)'.Przy pierwszym pędzlu wydaje się, że rozsądne użycie zarówno 'madvise (...)' i 'fadvise (...)' (z 'FADV_SEQUENTIAL') może być w celu uzyskania optymalnych rezultatów na platformę. – fish2000

Powiązane problemy