unit host_ipc_interface; {$mode ObjFPC}{$H+} interface uses Classes, CharStream, murmurhash, HAMT, sys_event, game_info; const iRESULT=0; { type t_mtype=( iRESULT, iERROR, iKEV_CHANGE, iKEV_EVENT, iMOUNT, iMAIN_WINDOWS, iCAPTION_FPS ); } type TOnMessage=function(mlen:DWORD;buf:Pointer):Ptruint of object; TOnObject =function(obj:TObject):Ptruint of object; THostIpcHandler=class private type PCBNode=^TCBNode; TCBNode=object cb:TOnMessage; end; // PCBNodeObject=^TCBNodeObject; TCBNodeObject=object(TCBNode) Creator:TAbstractObjectClass; cb_obj :TOnObject; function OnObject(mlen:DWORD;buf:Pointer):Ptruint; end; var FLock :Pointer; FMsgTable:TSTUB_HAMT32; public Destructor Destroy; override; // Procedure AddCallback(const msg:RawByteString;cb:TOnMessage); Procedure AddCallback(const msg:RawByteString;cb:TOnObject;Creator:TAbstractObjectClass); Procedure DelCallback(const msg:RawByteString); Function GetCallback(mtype:DWORD):TOnMessage; end; THostIpcInterface=class public FHandler:THostIpcHandler; Ftd :Pointer; //p_kthread FStop :Boolean; // procedure error(const s:RawByteString); procedure kevent(kev:p_kevent;count:Integer); function OpenMainWindows():THandle; procedure SetCaptionFps(Ffps:QWORD); // Function GetCallback(mtype:DWORD):TOnMessage; virtual; function NewSyncKey:Pointer; virtual; abstract; procedure FreeSyncKey (key:Pointer); virtual; abstract; procedure WaitSyncKey (key:Pointer); virtual; abstract; function GetSyncValue(key:Pointer):Ptruint; virtual; abstract; procedure Send(mtype,mlen:DWORD;buf,key:Pointer); virtual; abstract; procedure Update (); virtual; // function SendSync(mtype,mlen:DWORD;buf:Pointer):Ptruint; procedure SendAsyn(mtype,mlen:DWORD;buf:Pointer); function SendSync(const msg:RawByteString):Ptruint; function SendSync(mtype:DWORD;obj:TAbstractObject):Ptruint; procedure SendAsyn(mtype:DWORD;obj:TAbstractObject); function SendSync(const msg:RawByteString;obj:TAbstractObject):Ptruint; procedure SendAsyn(const msg:RawByteString;obj:TAbstractObject); // end; Function HashIpcStr(const msg:RawByteString):DWORD; //id cache var iERROR :DWORD=0; iKEV_CHANGE :DWORD=0; iKEV_EVENT :DWORD=0; iMAIN_WINDOWS:DWORD=0; iCAPTION_FPS :DWORD=0; implementation uses kern_rwlock; Function HashIpcStr(const msg:RawByteString):DWORD; var i:QWORD; begin i:=MurmurHash64A(@msg[1],Length(msg),$F1F0C0DE); Result:=DWORD(i) xor DWORD(i shr 32); end; //// procedure _clear_hamt(data,userdata:Pointer); begin FreeMem(data); end; Destructor THostIpcHandler.Destroy; begin HAMT_clear32(@FMsgTable,@_clear_hamt,nil); inherited; end; Procedure THostIpcHandler.AddCallback(const msg:RawByteString;cb:TOnMessage); var hash:DWORD; ptr :PCBNode; data:PPointer; begin hash:=HashIpcStr(msg); Assert(hash<>iRESULT,'Hash is zero!'); ptr:=AllocMem(SizeOf(TCBNode)); ptr^.cb:=cb; rw_wlock(FLock); data:=HAMT_insert32(@FMsgTable,hash,ptr); if (data<>nil) then begin if (data^=ptr) then begin // end else begin Assert(False,'AddCallback'); //FreeMem(data^); //free old //data^:=ptr; //set new end; end else begin Assert(False,'NOMEM'); end; rw_wunlock(FLock); end; function THostIpcHandler.TCBNodeObject.OnObject(mlen:DWORD;buf:Pointer):Ptruint; var mem:TPCharStream; obj:TAbstractObject; begin if (Creator=nil) or (cb_obj=nil) then begin Exit(Ptruint(-1)); end; if (mlen=0) then begin obj:=nil; end else begin mem:=TPCharStream.Create(buf,mlen); obj:=Creator.Create; obj.Deserialize(mem); mem.Free; end; Result:=cb_obj(obj); end; Procedure THostIpcHandler.AddCallback(const msg:RawByteString;cb:TOnObject;Creator:TAbstractObjectClass); var hash:DWORD; ptr :PCBNodeObject; data:PPointer; begin hash:=HashIpcStr(msg); Assert(hash<>iRESULT,'Hash is zero!'); ptr:=AllocMem(SizeOf(TCBNodeObject)); ptr^.cb:=@ptr^.OnObject; ptr^.Creator:=Creator; ptr^.cb_obj :=cb; rw_wlock(FLock); data:=HAMT_insert32(@FMsgTable,hash,ptr); if (data<>nil) then begin if (data^=ptr) then begin // end else begin Assert(False,'AddCallback'); //FreeMem(data^); //free old //data^:=ptr; //set new end; end else begin Assert(False,'NOMEM'); end; rw_wunlock(FLock); end; Procedure THostIpcHandler.DelCallback(const msg:RawByteString); var hash:DWORD; ptr:PCBNode; begin hash:=HashIpcStr(msg); Assert(hash<>iRESULT,'Hash is zero!'); rw_wlock(FLock); ptr:=nil; if HAMT_delete32(@FMsgTable,hash,@ptr) then begin FreeMem(ptr); end; rw_wunlock(FLock); end; Function THostIpcHandler.GetCallback(mtype:DWORD):TOnMessage; var ptr :PCBNode; data:PPointer; begin Result:=nil; rw_rlock(FLock); data:=HAMT_search32(@FMsgTable,mtype); if (data<>nil) then begin ptr:=data^; if (ptr<>nil) then begin Result:=ptr^.cb; end; end; rw_runlock(FLock); end; Function THostIpcInterface.GetCallback(mtype:DWORD):TOnMessage; begin Result:=nil; if (FHandler<>nil) then begin Result:=FHandler.GetCallback(mtype); end; end; function THostIpcInterface.SendSync(mtype,mlen:DWORD;buf:Pointer):Ptruint; var key:Pointer; begin key:=NewSyncKey; Send(mtype,mlen,buf,key); WaitSyncKey(key); Result:=GetSyncValue(key); FreeSyncKey(key); end; procedure THostIpcInterface.SendAsyn(mtype,mlen:DWORD;buf:Pointer); begin Send(mtype,mlen,buf,nil); end; procedure THostIpcInterface.Update(); begin // end; // function THostIpcInterface.SendSync(const msg:RawByteString):Ptruint; begin Result:=SendSync(HashIpcStr(msg),0,nil); end; function THostIpcInterface.SendSync(mtype:DWORD;obj:TAbstractObject):Ptruint; var key:Pointer; mem:TMemoryStream; begin if (obj<>nil) then begin mem:=TMemoryStream.Create; obj.Serialize(mem); end; key:=NewSyncKey; if (obj<>nil) then begin Send(mtype,mem.Size,mem.Memory,key); mem.Free; end else begin Send(mtype,0,nil,key); end; WaitSyncKey(key); Result:=GetSyncValue(key); FreeSyncKey(key); end; procedure THostIpcInterface.SendAsyn(mtype:DWORD;obj:TAbstractObject); var mem:TMemoryStream; begin if (obj<>nil) then begin mem:=TMemoryStream.Create; obj.Serialize(mem); Send(mtype,mem.Size,mem.Memory,nil); mem.Free; end else begin Send(mtype,0,nil,nil); end; end; function THostIpcInterface.SendSync(const msg:RawByteString;obj:TAbstractObject):Ptruint; begin Result:=SendSync(HashIpcStr(msg),obj); end; procedure THostIpcInterface.SendAsyn(const msg:RawByteString;obj:TAbstractObject); begin SendAsyn(HashIpcStr(msg),obj); end; // procedure THostIpcInterface.error(const s:RawByteString); begin if (self=nil) then Exit; if (iERROR=0) then iERROR:=HashIpcStr('ERROR'); SendSync(iERROR,Length(s)+1,pchar(s)); end; procedure THostIpcInterface.kevent(kev:p_kevent;count:Integer); begin if (self=nil) then Exit; if (iKEV_CHANGE=0) then iKEV_CHANGE:=HashIpcStr('KEV_CHANGE'); SendAsyn(iKEV_CHANGE,count*SizeOf(t_kevent),kev); end; function THostIpcInterface.OpenMainWindows():THandle; begin if (self=nil) then Exit(0); if (iMAIN_WINDOWS=0) then iMAIN_WINDOWS:=HashIpcStr('MAIN_WINDOWS'); Result:=THandle(SendSync(iMAIN_WINDOWS,0,nil)); end; procedure THostIpcInterface.SetCaptionFps(Ffps:QWORD); begin if (self=nil) then Exit; if (iCAPTION_FPS=0) then iCAPTION_FPS:=HashIpcStr('CAPTION_FPS'); SendAsyn(iCAPTION_FPS,SizeOf(Ffps),@Ffps); end; end.