UPD: Use poll() thread for ipc (less cpu usage)

This commit is contained in:
Alexander Koblov 2015-10-11 14:38:55 +00:00
commit 0153669ca7
5 changed files with 187 additions and 30 deletions

25
doc/COPYING.FPC.txt Normal file
View file

@ -0,0 +1,25 @@
This is the file COPYING.FPC, it applies to the Free Pascal Run-Time Library
(RTL) and packages (packages) distributed by members of the Free Pascal
Development Team.
The source code of the Free Pascal Runtime Libraries and packages are
distributed under the Library GNU General Public License
(see the file COPYING) with the following modification:
As a special exception, the copyright holders of this library give you
permission to link this library with independent modules to produce an
executable, regardless of the license terms of these independent modules,
and to copy and distribute the resulting executable under terms of your choice,
provided that you also meet, for each linked independent module, the terms
and conditions of the license of that module. An independent module is a module
which is not derived from or based on this library. If you modify this
library, you may extend this exception to your version of the library, but you are
not obligated to do so. If you do not wish to do so, delete this exception
statement from your version.
If you didn't receive a copy of the file COPYING, contact:
Free Software Foundation
675 Mass Ave
Cambridge, MA 02139
USA

View file

@ -0,0 +1,145 @@
{
Double Commander
-------------------------------------------------------------------------
Unix implementation of one-way IPC between 2 processes
Copyright (C) 2015 Alexander Koblov (alexx2000@mail.ru)
Based on simpleipc.inc from Free Component Library.
Copyright (c) 2005 by Michael Van Canneyt, member of
the Free Pascal development team
See the file COPYING.FPC.txt, included in this distribution,
for details about the copyright.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
}
unit uPipeServer;
{$mode objfpc}{$H+}
interface
uses
Classes, SysUtils, SimpleIPC, BaseUnix;
Type
{ TPipeServerComm }
TPipeServerComm = Class(TIPCServerComm)
Private
FFileName: String;
FStream: TFileStream;
private
procedure Handler(Sender: TObject);
Public
Constructor Create(AOWner : TSimpleIPCServer); override;
Procedure StartServer; override;
Procedure StopServer; override;
Function PeekMessage(TimeOut : Integer) : Boolean; override;
Procedure ReadMessage ; override;
Function GetInstanceID : String;override;
Property FileName : String Read FFileName;
Property Stream : TFileStream Read FStream;
end;
implementation
uses
uPollThread;
ResourceString
SErrFailedToCreatePipe = 'Failed to create named pipe: %s';
SErrFailedToRemovePipe = 'Failed to remove named pipe: %s';
type
TUnixIPCServer = class(TSimpleIPCServer);
procedure TPipeServerComm.Handler(Sender: TObject);
begin
TThread.Synchronize(nil, @TUnixIPCServer(Owner).ReadMessage);
end;
constructor TPipeServerComm.Create(AOWner: TSimpleIPCServer);
Var
D : String;
begin
inherited Create(AOWner);
FFileName:=Owner.ServerID;
If Not Owner.Global then
FFileName:=FFileName+'-'+IntToStr(fpGetPID);
D:='/tmp/'; // Change to something better later
FFileName:=D+FFileName;
end;
procedure TPipeServerComm.StartServer;
const
PrivateRights = S_IRUSR or S_IWUSR;
GlobalRights = PrivateRights or S_IRGRP or S_IWGRP or S_IROTH or S_IWOTH;
Rights : Array [Boolean] of Integer = (PrivateRights,GlobalRights);
begin
If not FileExists(FFileName) then
If (fpmkFifo(FFileName,438)<>0) then
DoError(SErrFailedToCreatePipe,[FFileName]);
FStream:=TFileStream.Create(FFileName,fmOpenReadWrite+fmShareDenyNone,Rights[Owner.Global]);
AddPoll(FStream.Handle, POLLIN, @Handler, False);
end;
procedure TPipeServerComm.StopServer;
begin
RemovePoll(FStream.Handle);
FreeAndNil(FStream);
if Not DeleteFile(FFileName) then
DoError(SErrFailedtoRemovePipe,[FFileName]);
end;
function TPipeServerComm.PeekMessage(TimeOut: Integer): Boolean;
Var
FDS : TFDSet;
begin
fpfd_zero(FDS);
fpfd_set(FStream.Handle,FDS);
Result:=fpSelect(FStream.Handle+1,@FDS,Nil,Nil,TimeOut)>0;
end;
procedure TPipeServerComm.ReadMessage;
Var
Count : Integer;
Hdr : TMsgHeader;
M : TStream;
begin
FStream.ReadBuffer(Hdr,SizeOf(Hdr));
SetMsgType(Hdr.MsgType);
Count:=Hdr.MsgLen;
M:=MsgData;
if count > 0 then
begin
M.Seek(0,soFrombeginning);
M.CopyFrom(FStream,Count);
end
else
M.Size := 0;
end;
function TPipeServerComm.GetInstanceID: String;
begin
Result:=IntToStr(fpGetPID);
end;
initialization
DefaultIPCServerClass:= TPipeServerComm;
end.

View file

@ -8,6 +8,7 @@ uses
Classes, SysUtils, Unix, BaseUnix;
procedure AddPoll(fd: cint; events: cshort; handler: TNotifyEvent; CloseOnDestroy: Boolean = True);
procedure RemovePoll(fd: cint);
implementation
@ -56,6 +57,20 @@ begin
PollThread.AddPoll(fd, events, handler, CloseOnDestroy);
end;
procedure RemovePoll(fd: cint);
var
Index: Integer;
begin
for Index:= 0 to PollThread.FCount - 1 do
begin
if PollThread.FDesc[Index].fd = fd then
begin
PollThread.FDesc[Index].events:= 0;
Break;
end;
end;
end;
{ TPollThread }
procedure TPollThread.Clear(Sender: TObject);

View file

@ -598,7 +598,7 @@ begin
// This fd will get passed to poll()
fd := udev_monitor_get_fd(udev_monitor);
AddPoll(fd, POLLIN, Handler, True);
AddPoll(fd, POLLIN, Handler, False);
Print('Begin monitoring');
end;

View file

@ -23,7 +23,6 @@ type
FServernameByUser: String;
{$IF DEFINED(UNIX)}
FMyProgramCreateSemaphore:Boolean;
FPeekThread: TThreadID;
{$ENDIF}
procedure OnNative(Sender: TObject);
@ -70,28 +69,10 @@ uses
{$IF DEFINED(MSWINDOWS)}
Windows,
{$ELSEIF DEFINED(UNIX)}
ipc, baseunix,
ipc, baseunix, uPipeServer,
{$ENDIF}
Forms, StrUtils, FileUtil, uGlobs, uDebug;
{$IF DEFINED(UNIX)}
type
TUnixIPCServer = class(TSimpleIPCServer) end;
function PeekMessage(Parameter: Pointer): PtrInt;
var
UnixIPC: TUnixIPCServer absolute Parameter;
begin
Result:= 0;
while UnixIPC.Active do
begin
if UnixIPC.PeekMessage(100, False) then
TThread.Synchronize(nil, @UnixIPC.ReadMessage);
Sleep(1); // Fix crash under OS X
end;
end;
{$ENDIF}
{ TUniqueInstance }
procedure TUniqueInstance.OnNative(Sender: TObject);
@ -268,9 +249,6 @@ begin
FServerIPC.ServerID:= FInstanceName;
FServerIPC.Global:= True;
FServerIPC.StartServer;
{$IF DEFINED(UNIX)}
FPeekThread:= BeginThread(@PeekMessage, FServerIPC);
{$ENDIF}
end;
procedure TUniqueInstance.StopListen;
@ -278,12 +256,6 @@ begin
DisposeMutex;
if FServerIPC = nil then Exit;
FServerIPC.StopServer;
{$IF DEFINED(UNIX)}
DCDebug('Waiting for UniqueInstance thread');
WaitForThreadTerminate(FPeekThread, 0);
DCDebug('Close UniqueInstance thread');
CloseThread(FPeekThread);
{$ENDIF}
end;
function TUniqueInstance.isAnotherDCRunningWhileIamRunning:boolean;