Memory mapping unter Linux

Für Fragen zur Programmiersprache auf welcher Lazarus aufbaut
mse
Beiträge: 2013
Registriert: Do 16. Okt 2008, 10:22
OS, Lazarus, FPC: Linux,Windows,FreeBSD,(MSEide+MSEgui 4.6,git master FPC 3.0.4,fixes_3_0)
CPU-Target: x86,x64,ARM

Re: Memory mapping unter Linux

Beitrag von mse »

MitjaStachowiak hat geschrieben:Hast du ein Beispiel dazu?

Hier:
https://gitlab.com/mseide-msegui/mseuni ... /sharedmem
Funktioniert bei mir auf 32 und 64 Bit Linux.
Edit: Habe das Beispiel erweitert.
Dateianhänge
sharedmem.png
Zuletzt geändert von mse am Mo 18. Sep 2017, 10:23, insgesamt 1-mal geändert.

Benutzeravatar
m.fuchs
Lazarusforum e. V.
Beiträge: 2636
Registriert: Fr 22. Sep 2006, 19:32
OS, Lazarus, FPC: Winux (Lazarus 2.0.10, FPC 3.2.0)
CPU-Target: x86, x64, arm
Wohnort: Berlin
Kontaktdaten:

Re: Memory mapping unter Linux

Beitrag von m.fuchs »

MitjaStachowiak hat geschrieben:http zur inter-prozess-kommunikation ist irgendwie nicht der richtiger Weg, finde ich. Es soll hier ja nicht über Netzwerk laufen.

HTTP ist eine Möglichkeit für Interprozesskommunikation. Im Gegensatz zu Shared-Memory ist es halt eine Nachrichten-basierte Form.
Hat den Vorteil der besseren Trennung der Prozesse und möglicher Skalierbarkeit. Ist aber langsamer, wenn es um große Datenmengen geht.

Ob es für dich sinnvoll ist, kann ich dir nicht sagen. Dazu ist von dem Anwendungsfall zu wenig bekannt.
Software, Bibliotheken, Vorträge und mehr: https://www.ypa-software.de

MitjaStachowiak
Lazarusforum e. V.
Beiträge: 394
Registriert: Sa 15. Mai 2010, 13:46
CPU-Target: 64 bit
Kontaktdaten:

Re: Memory mapping unter Linux

Beitrag von MitjaStachowiak »

So, ich konnte das Beispiel von mse erfolgreich mit mseide und in vereinfachter Form mit Lazarus kompilieren und ein Handle <> -1 erhalten. Warum es in meinem Programm noch nicht geht, weiß ich nicht, aber das sollte ich auch noch hin bekommen.

Wenn's gut läuft, kann ich am Ende ein Shared-Memory-Beispiel machen, das auf Windows und Linux gleich funktioniert.

marcov
Beiträge: 1100
Registriert: Di 5. Aug 2008, 09:37
OS, Lazarus, FPC: Windows ,Linux,FreeBSD,Dos (L trunk FPC trunk)
CPU-Target: 32/64,PPC(+64), ARM
Wohnort: Eindhoven (Niederlande)

Re: Memory mapping unter Linux

Beitrag von marcov »

m.fuchs hat geschrieben:
MitjaStachowiak hat geschrieben:http zur inter-prozess-kommunikation ist irgendwie nicht der richtiger Weg, finde ich. Es soll hier ja nicht über Netzwerk laufen.

HTTP ist eine Möglichkeit für Interprozesskommunikation. Im Gegensatz zu Shared-Memory ist es halt eine Nachrichten-basierte Form.
Hat den Vorteil der besseren Trennung der Prozesse und möglicher Skalierbarkeit. Ist aber langsamer, wenn es um große Datenmengen geht.


(Aber mit das öffnen einer HTTP Server macht man sich möglich ein Ziel des Antivirens, AppArmor usw)

MitjaStachowiak
Lazarusforum e. V.
Beiträge: 394
Registriert: Sa 15. Mai 2010, 13:46
CPU-Target: 64 bit
Kontaktdaten:

Re: Memory mapping unter Linux

Beitrag von MitjaStachowiak »

Ok, ich habe eine kleine Unit geschrieben, die ein simples MemmoryMapping ohne extravagante Zugriffsbeschränkungen etc. erstellen kann:

Code: Alles auswählen

 
unit sharedmem;
 
{
 This unit provides simple memory mappings for inter-process communication on
 Windows and Linux in a consistent way.
}

 
{$mode objfpc}{$h+}
 
interface
 
uses
 Classes, SysUtils{$IFDEF Windows}, Windows{$ENDIF}{$IFDEF Unix}, baseunix {, ipc}{$ENDIF};
 
function OpenFileMappingSimple(const name:ShortString) : THandle;
function CreateFileMappingSimple(const name:ShortString; Size:QWord) : THandle;
function MapViewOfFileSimple(mapping:THandle; Size:QWord) : Pointer;
procedure UnmapViewOfFileSimple(adr:Pointer; Size:QWord);
procedure CloseFileMappingSimple(const name:ShortString; mapping:THandle);
 
 
implementation
 
{$IFDEF Unix}
const
 {$ifdef FPC}clib = 'c';{$else}clib = 'libc.so.6';{$endif}
 {$ifdef linux}shmlib = 'rt';{$else}shmlib = clib;{$endif}
 
 O_ACCMODE  = $00003;
 O_RDONLY   = $00000;
 O_WRONLY   = $00001;
 O_RDWR     = $00002;
 O_CREAT    = $00040;//&00100;
 O_EXCL     = $00080;//&00200;
 O_NOCTTY   = $00100;//&00400;
 O_TRUNC    = $00200;//&01000;
 O_APPEND   = $00400;//&02000;
 O_NONBLOCK = $00800;//&04000;
 O_NDELAY   = O_NONBLOCK;
 O_SYNC     = $01000;//&010000;
 O_FSYNC    = O_SYNC;
 O_ASYNC    = $02000;//&020000;
 O_CLOEXEC  = $80000;
 
 S_ISUID = $800;
 S_ISGID = $400;
 S_ISVTX = $200;
 
 S_IRUSR = $100;
 S_IWUSR = $80;
 S_IXUSR = $40;
 
type
{$ifdef cpu64}
  size_t = QWord;
  off_t = QWord;
{$else}
  size_t = Cardinal;
  off_t = Cardinal;
{$endif}
 
function shm_open(name: pchar; oflag: longint; mode: Cardinal): longint; cdecl; external shmlib name 'shm_open';
function shm_unlink(name: pchar): longint; cdecl; external shmlib name 'shm_unlink';
function mmap(addr: pointer; lengthint: size_t; prot: longint; flags: longint; fd: longint; offset: off_t): pointer; cdecl; external clib name 'mmap';
function munmap(addr: pointer; length: size_t): longint; cdecl; external clib name 'munmap';
{$ifdef linux}
function ftruncate64(handle: integer; size: int64): integer; cdecl; external clib name 'ftruncate64';
{$else}
function ftruncate64(handle: integer; size: int64): integer; cdecl; external clib name 'ftruncate';
{$endif}
{$endif}
 
 
 
 
 
 
function OpenFileMappingSimple(const name: ShortString): THandle;
var _name : ShortString;
begin
 {$IFDEF Windows}
  _name := name+#0#0;
  Result := OpenFileMapping(FILE_MAP_ALL_ACCESS, False, PChar(@_name[1]));
 {$ENDIF}
 {$IFDEF Unix}
  _name := '/'+name+#0#0;
  Result := shm_open(PChar(@_name[1]), O_RDWR, S_IRUSR or S_IWUSR); //Result := shmget(PInteger(@name[1])^, Size, 0);
  if (Result < 0) then Result := 0
  else Result := Result + 1;
 {$ENDIF}
end;
 
function CreateFileMappingSimple(const name: ShortString; Size: QWord): THandle;
var _name : ShortString;
begin
 {$IFDEF Windows}
  _name := name+#0#0;
  Result := CreateFileMapping(INVALID_HANDLE_VALUE, Windows.LPSecurity_ATTRIBUTES(0), PAGE_READWRITE, 0, Size, PChar(@_name[1]));
 {$ENDIF}
 {$IFDEF Unix}
  _name := '/'+name+#0#0;
  Result := shm_open(PChar(@_name[1]), O_RDWR or O_CREAT, S_IRUSR or S_IWUSR); //Result := shmget(PInteger(@name[1])^, Size, IPC_CREAT or 0777);
  if (Result < 0) then Result := 0
  else begin
   ftruncate64(Result, Size);
   Result := Result + 1;
  end;
 {$ENDIF}
end;
 
function MapViewOfFileSimple(mapping: THandle; Size: QWord): Pointer;
begin
 {$IFDEF Windows}
  Result := MapViewOfFile(mapping, FILE_MAP_ALL_ACCESS, 0, 0, 0);
 {$ENDIF}
 {$IFDEF Unix}
  Result := Fpmmap(nil, Size, PROT_READ or PROT_WRITE, MAP_SHARED, mapping-1, 0); //Result := shmat(mapping, nil, 0);
 {$ENDIF}
end;
 
procedure UnmapViewOfFileSimple(adr: Pointer; Size: QWord);
begin
 {$IFDEF Windows}
  UnmapViewOfFile(adr);
 {$ENDIF}
 {$IFDEF Unix}
  FPMUnMap(adr, Size); //shmdt(adr);
 {$ENDIF}
end;
 
procedure CloseFileMappingSimple(const name: ShortString; mapping: THandle);
var _name:ShortString;
begin
 {$IFDEF Windows}
  CloseHandle(mapping);
 {$ENDIF}
 {$IFDEF Unix}
  _name := '/'+name+#0#0;
  shm_unlink(PChar(@_name[1])); //shmctl(mapping, IPC_RMID, nil);
 {$ENDIF}
end;
 
end.
 


Zur Verwendung:

Code: Alles auswählen

 
// required infos
type
 TMapInfo = record
  Wert1 : Integer;
  Wert2 : Integer;
  //...
 end;
const
 mmfName = 'MessdatenUpload';
var
 mmfHandle : THandle;
 mmfErr : Boolean = false;
 isFirstProcess : Boolean = false;
 
// open/create filemapping
mmfHandle := OpenFileMappingSimple(mmfName);
if (mmfHandle = 0) then begin // auf Linux wird das native Handle +1 gezählt, sodass der invalid-Wert auch 0 ist
 inf.isFirstProcess := true;
 mmfHandle := CreateFileMappingSimple(mmfName, SizeOf(TMapInfo));
 if (mmfHandle = 0) then mmfErr := true;
end;
if (not mmfErr) then begin
 mmf := MapViewOfFileSimple(mmfHandle, SizeOf(TMapInfo));
 // do something with the mapping
end;
 
// close filemapping
if (not mmfErr) then begin
 UnmapViewOfFileSimple(mmf, SizeOf(TMapInfo));
 CloseFileMappingSimple(mmfName, mmfHandle);
end;
mmf := nil;
mmfHandle := 0;
 

Antworten