This commit is contained in:
Pavel 2024-02-07 18:58:52 +03:00
parent b586dfe33b
commit a25aed2dba
13 changed files with 4869 additions and 180 deletions

View File

@ -598,6 +598,18 @@
<Filename Value="sys\host_ipc.pas"/>
<IsPartOfProject Value="True"/>
</Unit>
<Unit>
<Filename Value="sys\md\md_pipe.pas"/>
<IsPartOfProject Value="True"/>
</Unit>
<Unit>
<Filename Value="sys\md\md_host_ipc.pas"/>
<IsPartOfProject Value="True"/>
</Unit>
<Unit>
<Filename Value="rtl\evbuffer.pas"/>
<IsPartOfProject Value="True"/>
</Unit>
</Units>
</ProjectOptions>
<CompilerOptions>

View File

@ -8,13 +8,17 @@ uses
windows,
Classes,
SysUtils,
md_pipe,
host_ipc,
md_host_ipc,
game_info;
var
//FLogUpdate:Integer=0;
t_wr_handle:THandle;
mgui_ipc:THostIpcConnect=nil;
kern_ipc:THostIpcConnect=nil;
procedure run_item(Item:TGameItem);
implementation
@ -31,7 +35,6 @@ uses
md_exception, //<- install custom
kern_proc,
host_ipc,
md_systm,
//internal libs
@ -47,16 +50,6 @@ uses
var
runing:Boolean=False;
procedure WakeMainThread;
begin
//System.InterlockedIncrement(FLogUpdate);
if Assigned(Classes.WakeMainThread) then
begin
Classes.WakeMainThread(nil);
end;
end;
procedure re_init_tty; register;
var
i:Integer;
@ -65,18 +58,18 @@ begin
begin
//std_tty[i].t_rd_handle:=GetStdHandle(STD_INPUT_HANDLE);
//std_tty[i].t_wr_handle:=t_wr_handle;
std_tty[i].t_update :=@WakeMainThread;
//std_tty[i].t_update :=@WakeMainThread;
end;
For i:=0 to High(deci_tty) do
begin
//deci_tty[i].t_rd_handle:=GetStdHandle(STD_INPUT_HANDLE);
//deci_tty[i].t_wr_handle:=t_wr_handle;
deci_tty[i].t_update :=@WakeMainThread;
//deci_tty[i].t_update :=@WakeMainThread;
end;
//debug_tty.t_wr_handle:=t_wr_handle;
debug_tty.t_update :=@WakeMainThread;
//debug_tty.t_update :=@WakeMainThread;
end;
procedure prepare(Item:TGameItem); SysV_ABI_CDecl;
@ -86,8 +79,6 @@ var
len:Integer;
exec:array[0..PATH_MAX] of Char;
argv:array[0..1] of PChar;
host_ipc:THostIpcConnect;
begin
//re_init_tty;
//init_tty:=@re_init_tty;
@ -95,17 +86,15 @@ begin
//init all
sys_init;
Writeln('Hollo World!');
PROC_INIT_HOST_IPC(kern_ipc);
Writeln(Item.FGameInfo.Exec);
//host_ipc:=THostIpcConnect(THostIpcSimpleKERN.Create);
//PROC_INIT_HOST_IPC(host_ipc);
Writeln(Item.FMountList.app0);
Writeln(Item.FMountList.system);
Writeln(Item.FMountList.data);
//fs guest host
err:=vfs_mount_mkdir('ufs','/app0' ,pchar(Item.FMountList.app0 ),nil,0);
Assert(err=0);
@ -162,11 +151,16 @@ var
td:p_kthread;
r:Integer;
pipefd:THandle;
parent:THandle;
mem:TPCharStream;
Item:TGameItem;
begin
mem:=TPCharStream.Create(data,size);
mem.Read(pipefd,SizeOf(THandle));
Item:=TGameItem.Create;
Item.Deserialize(mem);
@ -175,9 +169,12 @@ begin
//free shared
md_fork_unshare;
//sys_init;
parent:=md_pidfd_open(md_getppid);
//sleep(-1);
pipefd:=md_pidfd_getfd(parent,pipefd);
kern_ipc:=THostIpcConnect(THostIpcPipeKERN.Create);
THostIpcPipeKERN(kern_ipc).set_pipe(pipefd);
td:=nil;
r:=kthread_add(@prepare,Item,@td,'[main]');
@ -186,11 +183,16 @@ begin
sleep(-1);
end;
const
fork_proc:Boolean=True;
procedure run_item(Item:TGameItem);
var
td:p_kthread;
r:Integer;
kern2mgui:array[0..1] of THandle;
mem:TMemoryStream;
begin
if Item.FLock then Exit;
@ -200,21 +202,36 @@ begin
SetStdHandle(STD_ERROR_HANDLE ,t_wr_handle);
SetStdHandle(STD_OUTPUT_HANDLE,t_wr_handle);
mem:=TMemoryStream.Create;
if fork_proc then
begin
md_pipe2(@kern2mgui,MD_PIPE_ASYNC0 or MD_PIPE_ASYNC1);
Item.Serialize(mem);
mgui_ipc:=THostIpcConnect(THostIpcPipeMGUI.Create);
THostIpcPipeMGUI(mgui_ipc).set_pipe(kern2mgui[0]);
//mem.Position:=0;
//
md_fork_process(@fork_process,mem.Memory,mem.Size);
mem:=TMemoryStream.Create;
mem.Free;
mem.Write(kern2mgui[1],SizeOf(THandle));
{
td:=nil;
r:=kthread_add(@prepare,Item,@td,'[main]');
Assert(r=0);
}
Item.Serialize(mem);
md_fork_process(@fork_process,mem.Memory,mem.Size);
mem.Free;
end else
begin
kern_ipc:=THostIpcConnect(THostIpcSimpleKERN.Create);
mgui_ipc:=THostIpcConnect(THostIpcSimpleMGUI.Create);
THostIpcSimpleKERN(kern_ipc).FDest:=THostIpcSimpleMGUI(mgui_ipc);
THostIpcSimpleMGUI(mgui_ipc).FDest:=THostIpcSimpleKERN(kern_ipc);
td:=nil;
r:=kthread_add(@prepare,Item,@td,'[main]');
Assert(r=0);
end;
runing:=True;
end;

View File

@ -8,7 +8,9 @@ uses
Classes, SysUtils, Forms, Controls, Graphics, Dialogs, ComCtrls, Grids, Menus,
game_info,
game_edit;
game_edit,
host_ipc;
type
@ -73,6 +75,9 @@ uses
TypInfo,
Rtti,
evbuffer,
evpoll,
game_run;
//
@ -113,6 +118,20 @@ var
const
section_prefix='game-';
type
TGuiIpcHandler=class(THostIpcHandler)
Form:TfrmMain;
Procedure OnMessage(mtype:t_mtype;mlen:DWORD;buf:Pointer); override;
end;
Procedure TGuiIpcHandler.OnMessage(mtype:t_mtype;mlen:DWORD;buf:Pointer);
begin
ShowMessage(GetEnumName(TypeInfo(mtype),ord(mtype)));
end;
var
IpcHandler:TGuiIpcHandler;
procedure TfrmMain.ReadIniFile;
var
i,c:Integer;
@ -121,6 +140,9 @@ var
List:TStringList;
Item:TGameItem;
begin
IpcHandler:=TGuiIpcHandler.Create;
IpcHandler.Form:=Self;
//main
FMainInfo.ReadIni(FIniFile,'main');
//main
@ -262,18 +284,20 @@ procedure TfrmMain.OnIdleUpdate(Sender:TObject;var Done:Boolean);
begin
Done:=True;
if (GetTickCount64-FLogUpdateTime)>500 then
if (GetTickCount64-FLogUpdateTime)>100 then
begin
//if (System.InterlockedExchange(FLogUpdate,0)<>0) then
if (FList<>nil) then
begin
FList.Update;
end;
FLogUpdateTime:=GetTickCount64;
end;
if (mgui_ipc<>nil) then
begin
mgui_ipc.Update(IpcHandler);
end;
end;
procedure TfrmMain.MIAddClick(Sender: TObject);

View File

@ -238,34 +238,13 @@ end;
procedure TSynEditLineStream.Reset;
var
i,c,ffcnt,delta:Integer;
tend:Boolean;
ffcnt,delta:Integer;
begin
BeginUpdate;
//
i:=FSynLog.TopLine+FSynLog.LinesInWindow+3;
//
FStream.Reset;
ffcnt:=FStream.GetCount;
delta:=FStream.Update;
//
tend:=(i>=ffcnt);
//
if tend then
begin
i:=FSynLog.LinesInWindow;
c:=FStream.GetCount;
//
if (c>i) then
begin
i:=c-i+1;
end else
begin
i:=1;
end;
//
FSynLog.TopLine:=i;
end;
FStream.Reset;
delta:=-ffcnt;
//
IncreaseTextChangeStamp;
//

571
rtl/evbuffer.pas Normal file
View File

@ -0,0 +1,571 @@
{ IO event buffer
Copyright (C) 2018-2023 Red_prig
This library is free software; you can redistribute it and/or modify it
under the terms of the GNU Library General Public License as published by
the Free Software Foundation; either version 2 of the License, or (at your
option) any later version 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.
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. See the GNU Library General Public License
for more details.
}
unit evbuffer;
{$mode ObjFPC}{$H+}
interface
uses
atomic;
type
TfuncFree=Function(p:pointer):SizeUInt; register;
Peviovec=^Teviovec;
Teviovec=object
private
next_:Peviovec;
public
base:Pointer;
len :SizeUInt;
pos :SizeUInt;
buf_free:TfuncFree;
vec_free:TfuncFree;
end;
Pevbuffer=^Tevbuffer;
Tevbuffer=object
private
Var
len :SizeUInt;
tail_,head_:Peviovec;
stub_:Pointer;
public
end;
Procedure eviovec_free(P:Peviovec);
function eviovec_next(buf:Pevbuffer;vec:Peviovec):Peviovec;
function eviovec_getdata(vec:Peviovec):Pointer;
function eviovec_getlen(vec:Peviovec):SizeUInt;
procedure evbuffer_init(buf:Pevbuffer);
function evbuffer_new:Pevbuffer;
procedure evbuffer_free(buf:Pevbuffer);
procedure evbuffer_clear(buf:Pevbuffer);
Function evbuffer_isempty(buf:Pevbuffer):Boolean;
function evbuffer_push(buf:Pevbuffer;Node:Peviovec):Boolean;
function evbuffer_pop(buf:Pevbuffer):Peviovec;
function evbuffer_peek(buf:Pevbuffer):Peviovec;
function evbuffer_add_ref(buf:Pevbuffer;data:pointer;datapos,datalen:SizeUInt;ff:TfuncFree):Boolean;
function evbuffer_remove_ref(buf:Pevbuffer;var data:pointer;var datapos,datalen:SizeUInt;var ff:TfuncFree):Boolean;
function evbuffer_add(buf:Pevbuffer;data:pointer;datalen:SizeUInt):Boolean;
function evbuffer_remove(buf:Pevbuffer;data:pointer;datalen:SizeUInt):SizeUInt;
function evbuffer_copy(buf:Pevbuffer;data:pointer;datalen:SizeUInt):SizeUInt;
function evbuffer_drain(buf:Pevbuffer;datalen:SizeUInt):SizeUInt;
function evbuffer_get_length(buf:Pevbuffer):SizeUInt;
function evbuffer_get_contiguous_space(buf:Pevbuffer):SizeUInt;
function evbuffer_get_atmost_size(buf:Pevbuffer;size:SizeUint):SizeUInt;
function evbuffer_get_atless_size(buf:Pevbuffer;size:SizeUint):SizeUInt;
function evbuffer_move(Src,Dst:Pevbuffer):SizeUInt;
function evbuffer_move_length(Src,Dst:Pevbuffer;length:SizeUInt):SizeUInt;
function Freemem_ptr:TfuncFree;
implementation
function Freemem_ptr:TfuncFree;
Var
MemMgr:TMemoryManager;
begin
MemMgr:=Default(TMemoryManager);
GetMemoryManager(MemMgr);
Result:=MemMgr.Freemem;
end;
//
Procedure eviovec_free(P:Peviovec);
begin
if not Assigned(P) then Exit;
if Assigned(P^.buf_free) then
begin
P^.buf_free(P^.base);
end;
if Assigned(P^.vec_free) then
begin
P^.vec_free(P);
end;
end;
function eviovec_next(buf:Pevbuffer;vec:Peviovec):Peviovec;
Var
tail,n:Peviovec;
begin
Result:=nil;
if (not Assigned(buf)) or
(not Assigned(vec)) then Exit;
With vec^ do
begin
tail:=vec^.next_;
if not Assigned(tail) then Exit;
n:=load_consume(tail^.next_);
if tail=@buf^.stub_ then
begin
if n=nil then Exit;
tail:=n;
end;
Result:=tail;
end;
end;
function eviovec_getdata(vec:Peviovec):Pointer;
begin
Result:=nil;
if not Assigned(vec) then Exit;
Result:=@PByte(vec^.base)[vec^.pos];
end;
function eviovec_getlen(vec:Peviovec):SizeUInt;
begin
Result:=0;
if not Assigned(vec) then Exit;
Result:=vec^.len;
end;
//--evbuffer--
procedure evbuffer_init(buf:Pevbuffer);
begin
if not Assigned(buf) then Exit;
buf^:=Default(Tevbuffer);
With buf^ do
begin
head_:=Peviovec(@stub_);
tail_:=Peviovec(@stub_);
end;
ReadWriteBarrier;
end;
function evbuffer_new:Pevbuffer;
begin
Result:=GetMem(SizeOf(Tevbuffer));
evbuffer_init(Result);
end;
procedure evbuffer_free(buf:Pevbuffer);
begin
if not Assigned(buf) then Exit;
evbuffer_clear(buf);
FreeMem(buf);
end;
procedure evbuffer_clear(buf:Pevbuffer);
Var
Node:Peviovec;
begin
if not Assigned(buf) then Exit;
repeat
Node:=evbuffer_pop(buf);
eviovec_free(Node);
until (Node=nil);
end;
Function evbuffer_isempty(buf:Pevbuffer):Boolean;
begin
if not Assigned(buf) then Exit(true);
Result:=(load_acquire(buf^.head_)=@buf^.stub_);
end;
function evbuffer_push(buf:Pevbuffer;Node:Peviovec):Boolean;
Var
prev:Peviovec;
begin
if (not Assigned(buf)) or (not Assigned(Node)) then Exit(False);
With buf^ do
begin
store_release(Node^.next_,nil);
prev:=XCHG(head_,Node);
store_release(prev^.next_,Node);
fetch_add(len,Node^.len);
end;
Result:=True;
end;
function evbuffer_pop(buf:Pevbuffer):Peviovec;
Var
tail,n,head:Peviovec;
begin
Result:=nil;
if not Assigned(buf) then Exit;
With buf^ do
begin
tail:=tail_;
n:=load_consume(tail^.next_);
if tail=@stub_ then
begin
if n=nil then Exit;
store_release(tail_,n);
tail:=n;
n:=load_consume(n^.next_);
end;
if n<>nil then
begin
store_release(tail_,n);
Result:=tail;
store_release(tail^.next_,nil);
fetch_sub(len,Result^.len);
Exit;
end;
head:=head_;
if tail<>head then Exit;
stub_:=nil;
n:=XCHG(head_,@stub_);
store_release(n^.next_,@stub_);
n:=load_consume(tail^.next_);
if n<>nil then
begin
store_release(tail_,n);
Result:=tail;
store_release(tail^.next_,nil);
fetch_sub(len,Result^.len);
Exit;
end;
end;
end;
function evbuffer_peek(buf:Pevbuffer):Peviovec;
Var
tail,n:Peviovec;
begin
Result:=nil;
if not Assigned(buf) then Exit;
With buf^ do
begin
tail:=tail_;
if not Assigned(tail) then Exit;
n:=load_consume(tail^.next_);
if tail=@stub_ then
begin
if not Assigned(n) then Exit;
tail:=n;
end;
Result:=tail;
end;
end;
function evbuffer_get_atmost_size(buf:Pevbuffer;size:SizeUint):SizeUInt;
Var
vec:Peviovec;
begin
Result:=0;
if size=0 then Exit;
vec:=evbuffer_peek(buf);
if not Assigned(vec) then Exit;
Result:=vec^.len;
if Result>=size then
begin
Result:=size;
end else
begin
repeat
vec:=eviovec_next(buf,vec);
if not Assigned(vec) then Break;
if Result+vec^.len>size then Break;
Result:=Result+vec^.len;
until false;
end;
end;
function evbuffer_get_atless_size(buf:Pevbuffer;size:SizeUint):SizeUInt;
Var
vec:Peviovec;
begin
Result:=0;
if size=0 then Exit;
vec:=evbuffer_peek(buf);
if not Assigned(vec) then Exit;
Result:=vec^.len;
if Result<size then
begin
repeat
vec:=eviovec_next(buf,vec);
if not Assigned(vec) then Break;
Result:=Result+vec^.len;
if Result>=size then Break;
until false;
end;
end;
function evbuffer_move(Src,Dst:Pevbuffer):SizeUInt;
Var
vec:Peviovec;
begin
Result:=0;
if Assigned(Dst) then
repeat
vec:=evbuffer_pop(Src);
if vec=nil then Exit;
Result:=Result+vec^.len;
evbuffer_push(Dst,vec);
until false;
end;
function evbuffer_move_length(Src,Dst:Pevbuffer;length:SizeUInt):SizeUInt;
var
i:SizeUInt;
vec:Peviovec;
begin
Result:=0;
if Assigned(Dst) then
repeat
vec:=evbuffer_peek(Src);
if vec=nil then Exit;
i:=Result+vec^.len;
if i>length then
begin
i:=length-Result;
evbuffer_add(Dst,eviovec_getdata(vec),i);
evbuffer_drain(Src,i);
Result:=length;
Exit;
end else
begin
evbuffer_push(Dst,evbuffer_pop(Src));
Result:=i;
if length=Result then Exit;
end;
until false;
end;
Var
cache_peviovec:Peviovec=nil;
Function get_peviovec:peviovec;
begin
Result:=XCHG(cache_peviovec,nil);
if Result=nil then
begin
Result:=GetMem(SizeOf(Teviovec));
end;
end;
Function free_peviovec(p:pointer):SizeUInt;
begin
Result:=FreeMem(XCHG(cache_peviovec,p));
end;
function evbuffer_add_ref(buf:Pevbuffer;data:pointer;datapos,datalen:SizeUInt;ff:TfuncFree):Boolean;
Var
Node:Peviovec;
begin
Result:=False;
if (not Assigned(buf)) or
(not Assigned(data)) or
(datalen=0) then Exit;
//Node:=GetMem(SizeOf(Teviovec));
Node:=get_peviovec;
if Node=nil then Exit;
With Node^ do
begin
base:=data;
len:=datalen;
pos:=datapos;
buf_free:=ff;
//vec_free:=Freemem_ptr;
vec_free:=@free_peviovec;
end;
Result:=evbuffer_push(buf,Node);
end;
function evbuffer_remove_ref(buf:Pevbuffer;var data:pointer;var datapos,datalen:SizeUInt;var ff:TfuncFree):Boolean;
Var
Node:Peviovec;
begin
Node:=evbuffer_pop(buf);
Result:=Assigned(Node);
if Result then
begin
data :=Node^.base;
datapos:=Node^.pos;
datalen:=Node^.len;
ff :=Node^.buf_free;
if Assigned(Node^.vec_free) then
begin
Node^.vec_free(Node);
end;
end;
end;
function _evbuffer_add_opt(buf:Pevbuffer;data:pointer;datalen:SizeUInt):Boolean;
Var
Node:Peviovec;
begin
Result:=False;
Node:=GetMem(datalen+SizeOf(Teviovec));
if Node=nil then Exit;
With Node^ do
begin
base:=@PByte(Node)[SizeOf(Teviovec)];
len:=datalen;
pos:=0;
buf_free:=nil;
vec_free:=Freemem_ptr;
end;
Move(data^,Node^.base^,datalen);
Result:=evbuffer_push(buf,Node);
end;
function evbuffer_add(buf:Pevbuffer;data:pointer;datalen:SizeUInt):Boolean;
Const
optimal_size=4*1024-SizeOf(Teviovec)-2*SizeOf(Pointer);
Var
base:Pointer;
begin
Result:=False;
if (not Assigned(buf)) or
(not Assigned(data)) or
(datalen=0) then Exit;
if (datalen<=optimal_size) then
begin
Result:=_evbuffer_add_opt(buf,data,datalen);
end else
begin
base:=GetMem(datalen);
Move(data^,base^,datalen);
Result:=evbuffer_add_ref(buf,base,0,datalen,Freemem_ptr);
end;
end;
function evbuffer_remove(buf:Pevbuffer;data:pointer;datalen:SizeUInt):SizeUInt;
Var
vec:Peviovec;
begin
Result:=0;
if not Assigned(data) then Exit;
While (datalen<>0) do
begin
vec:=evbuffer_peek(buf);
if not Assigned(vec) then Break;
With vec^ do
begin
if (len>datalen) then
begin
Move(PByte(base)[pos],data^,datalen);
pos:=pos+datalen;
len:=len-datalen;
Result:=Result+datalen;
fetch_sub(buf^.len,datalen);
Break;
end else
begin
Move(PByte(base)[pos],data^,len);
datalen:=datalen-len;
Result:=Result+len;
data:=@PByte(data)[len];
eviovec_free(evbuffer_pop(buf));
end;
end;
end;
end;
function evbuffer_copy(buf:Pevbuffer;data:pointer;datalen:SizeUInt):SizeUInt;
Var
vec:Peviovec;
begin
Result:=0;
if not Assigned(data) then Exit;
vec:=evbuffer_peek(buf);
While (datalen<>0) and Assigned(vec) do
begin
With vec^ do
begin
if (len>datalen) then
begin
Move(PByte(base)[pos],data^,datalen);
Result:=Result+datalen;
Break;
end else
begin
Move(PByte(base)[pos],data^,len);
datalen:=datalen-len;
Result:=Result+len;
data:=@PByte(data)[len];
vec:=eviovec_next(buf,vec);
end;
end;
end;
end;
function evbuffer_drain(buf:Pevbuffer;datalen:SizeUInt):SizeUInt;
Var
vec:Peviovec;
begin
Result:=0;
While (datalen<>0) do
begin
vec:=evbuffer_peek(buf);
if not Assigned(vec) then Break;
With vec^ do
begin
if (len>datalen) then
begin
pos:=pos+datalen;
len:=len-datalen;
Result:=Result+datalen;
fetch_sub(buf^.len,datalen);
Break;
end else
begin
datalen:=datalen-len;
Result:=Result+len;
eviovec_free(evbuffer_pop(buf));
end;
end;
end;
end;
function evbuffer_get_length(buf:Pevbuffer):SizeUInt;
begin
Result:=0;
if not Assigned(buf) then Exit;
Result:=buf^.len;
end;
function evbuffer_get_contiguous_space(buf:Pevbuffer):SizeUInt;
Var
vec:Peviovec;
begin
Result:=0;
vec:=evbuffer_peek(buf);
if Assigned(vec) then
begin
Result:=vec^.len;
end;
end;
end.

3617
rtl/evpoll.pas Normal file

File diff suppressed because it is too large Load Diff

View File

@ -45,9 +45,15 @@ const
STATUS_FILE_CORRUPT_ERROR =$C0000102; //EIO
STATUS_NOT_A_DIRECTORY =$C0000103; //ENOTDIR
STATUS_NAME_TOO_LONG =$C0000106; //ENAMETOOLONG
STATUS_CANCELLED =$C0000120;
STATUS_PAGEFILE_QUOTA_EXCEEDED=$C000012C; //ENOMEM
STATUS_COMMITMENT_LIMIT =$C000012D; //ENOMEM
STATUS_LOCAL_DISCONNECT =$C000013B;
STATUS_IO_DEVICE_ERROR =$C0000185; //EIO
STATUS_CONNECTION_RESET =$C000020D;
STATUS_CONNECTION_REFUSED =$C0000236;
STATUS_GRACEFUL_DISCONNECT =$C0000237;
STATUS_CONNECTION_ABORTED =$C0000241;
STATUS_TOO_MANY_LINKS =$C0000265; //EMLINK
STATUS_COMMITMENT_MINIMUM =$C00002C8; //ENOMEM
STATUS_CANT_CROSS_RM_BOUNDARY =$C0190038; //EXDEV
@ -100,22 +106,25 @@ const
PROCESS_PRIORITY_CLASS_ABOVE_NORMAL=6;
//FileInformationClass
FileBasicInformation = 4;
FileStandardInformation = 5;
FileInternalInformation = 6;
FileEaInformation = 7;
FileAccessInformation = 8;
FileRenameInformation =10;
FileLinkInformation =11;
FileNamesInformation =12;
FileDispositionInformation =13;
FilePositionInformation =14;
FileModeInformation =16;
FileAlignmentInformation =17;
FileAllInformation =18;
FileAllocationInformation =19;
FileEndOfFileInformation =20;
FileIdFullDirectoryInformation=38;
FileBasicInformation = 4;
FileStandardInformation = 5;
FileInternalInformation = 6;
FileEaInformation = 7;
FileAccessInformation = 8;
FileRenameInformation =10;
FileLinkInformation =11;
FileNamesInformation =12;
FileDispositionInformation =13;
FilePositionInformation =14;
FileModeInformation =16;
FileAlignmentInformation =17;
FileAllInformation =18;
FileAllocationInformation =19;
FileEndOfFileInformation =20;
FilePipeInformation =23;
FileCompletionInformation =30;
FileIdFullDirectoryInformation =38;
FileReplaceCompletionInformation=61;
FileFsFullSizeInformation=7;
@ -227,6 +236,8 @@ const
FSCTL_SET_REPARSE_POINT=$000900A4;
FSCTL_GET_REPARSE_POINT=$000900A8;
FSCTL_PIPE_PEEK=$11400c;
// ReparseTag
IO_REPARSE_TAG_SYMLINK =$A000000C;
@ -236,6 +247,18 @@ const
// Privileges
SE_CREATE_SYMBOLIC_LINK_PRIVILEGE=35;
//NamedPipeType
FILE_PIPE_BYTE_STREAM_TYPE=$00000000;
FILE_PIPE_MESSAGE_TYPE =$00000001;
//ReadMode
FILE_PIPE_BYTE_STREAM_MODE=$00000000;
FILE_PIPE_MESSAGE_MODE =$00000001;
//CompletionMode
FILE_PIPE_QUEUE_OPERATION =$00000000;
FILE_PIPE_COMPLETE_OPERATION=$00000001;
type
PIO_STATUS_BLOCK=^IO_STATUS_BLOCK;
IO_STATUS_BLOCK=packed record
@ -319,6 +342,19 @@ type
FileName :record end; //WCHAR
end;
PFILE_COMPLETION_INFORMATION=^FILE_COMPLETION_INFORMATION;
FILE_COMPLETION_INFORMATION=packed record
Port:THandle;
Key :Pointer;
end;
PFILE_IO_COMPLETION_INFORMATION=^FILE_IO_COMPLETION_INFORMATION;
FILE_IO_COMPLETION_INFORMATION=packed record
KeyContext :Pointer;
ApcContext :Pointer;
IoStatusBlock:IO_STATUS_BLOCK;
end;
PFILE_ALL_INFORMATION=^FILE_ALL_INFORMATION;
FILE_ALL_INFORMATION=packed record
BasicInformation :FILE_BASIC_INFORMATION;
@ -495,6 +531,14 @@ type
Enable :ULONG;
end;
T_PIPE_PEEK=packed record
NamedPipeState :DWORD;
ReadDataAvailable:DWORD;
NumberOfMessages :DWORD;
MessageLength :DWORD;
data :record end;
end;
function NtClose(Handle:THandle):DWORD; stdcall; external 'ntdll';
function NtDuplicateObject(
@ -600,6 +644,13 @@ function NtSuspendThread(
SuspendCount:PULONG
):DWORD; stdcall; external 'ntdll';
function NtOpenProcess(
ProcessHandle :PHandle;
DesiredAccess :DWORD;
ObjectAttributes:POBJECT_ATTRIBUTES;
ClientId :PCLIENT_ID
):DWORD; stdcall; external 'ntdll';
function NtSuspendProcess(
ProcessHandle:THandle
):DWORD; stdcall; external 'ntdll';
@ -694,6 +745,23 @@ function NtQuerySystemInformation(
ReturnLength :PULONG
):DWORD; stdcall; external 'ntdll';
function NtCreateNamedPipeFile(
FileHandle :PHandle;
DesiredAccess :ACCESS_MASK;
ObjectAttributes :POBJECT_ATTRIBUTES;
IoStatusBlock :PIO_STATUS_BLOCK;
ShareAccess :ULONG;
CreateDisposition:ULONG;
CreateOptions :ULONG;
NamedPipeType :ULONG;
ReadMode :ULONG;
CompletionMode :ULONG;
MaximumInstances :ULONG;
InboundQuota :ULONG;
OutboundQuota :ULONG;
DefaultTimeout :PLARGE_INTEGER
):DWORD; stdcall; external 'ntdll';
function NtCreateFile(
FileHandle :PHandle;
DesiredAccess :ACCESS_MASK;
@ -849,6 +917,21 @@ function NtQueryVolumeInformationFile(
):DWORD; stdcall; external 'ntdll';
function NtCreateIoCompletion(
IoCompletionHandle:PHandle;
DesiredAccess :ACCESS_MASK;
ObjectAttributes :POBJECT_ATTRIBUTES;
Count :ULONG
):DWORD; stdcall; external 'ntdll';
function NtRemoveIoCompletionEx(
IoCompletionHandle :THandle;
IoCompletionInformation:PFILE_IO_COMPLETION_INFORMATION;
Count :ULONG;
NumEntriesRemoved :PULONG;
Timeout :PLARGE_INTEGER;
Alertable :Boolean
):DWORD; stdcall; external 'ntdll';
function NtCreateEvent(
EventHandle :PHandle;

View File

@ -15,6 +15,20 @@ type
iKNOTE
);
PNodeHeader=^TNodeHeader;
TNodeHeader=packed record
mtype:DWORD;
mlen :DWORD;
buf :record end;
end;
PQNode=^TQNode;
TQNode=packed record
next_ :PQNode;
header:TNodeHeader;
buf :record end;
end;
PHostIpcKnote=^THostIpcKnote;
THostIpcKnote=packed record
pid :Integer;
@ -22,53 +36,46 @@ type
hint :QWORD
end;
PQNode=^TQNode;
TQNode=packed record
next_:PQNode;
mtype:DWORD;
mlen :DWORD;
buf :record end;
end;
THostIpcCb=procedure(node,data:Pointer); register;
THostIpcCbRec=record
cbs :THostIpcCb;
data:Pointer;
THostIpcHandler=class
Procedure OnMessage(mtype:t_mtype;mlen:DWORD;buf:Pointer); virtual;
end;
THostIpcConnect=class
FQueue:TIntrusiveMPSCQueue;
FCbReg:array[t_mtype] of THostIpcCbRec;
//
procedure knote(pid,filter:Integer;hint:QWORD);
//
procedure Send(mtype:t_mtype;mlen:DWORD;buf:Pointer); virtual;
procedure Pack(mtype:t_mtype;mlen:DWORD;buf:Pointer);
function Recv:PQNode;
procedure Update; virtual;
procedure Update(Handler:THostIpcHandler); virtual;
//
Constructor Create;
end;
THostIpcSimpleKERN=class;
THostIpcSimpleGUI=class(THostIpcConnect)
THostIpcSimpleMGUI=class(THostIpcConnect)
FDest:THostIpcSimpleKERN;
procedure Send(mtype:t_mtype;mlen:DWORD;buf:Pointer); override;
end;
THostIpcSimpleKERN=class(THostIpcConnect)
FDest:THostIpcSimpleGUI;
FDest:THostIpcSimpleMGUI;
FEvent:PRTLEvent;
Constructor Create;
Destructor Destroy; override;
procedure Send(mtype:t_mtype;mlen:DWORD;buf:Pointer); override;
procedure Update; override;
procedure Update(Handler:THostIpcHandler); override;
end;
implementation
Procedure THostIpcHandler.OnMessage(mtype:t_mtype;mlen:DWORD;buf:Pointer);
begin
//
end;
Constructor THostIpcConnect.Create;
begin
FQueue.Create;
@ -79,9 +86,11 @@ var
node:PQNode;
begin
node:=AllocMem(SizeOf(TQNode)+mlen);
node^.mtype:=DWORD(mtype);
node^.mlen :=mlen;
node^.header.mtype:=DWORD(mtype);
node^.header.mlen :=mlen;
Move(buf^,node^.buf,mlen);
//
FQueue.Push(node);
end;
function THostIpcConnect.Recv:PQNode;
@ -90,18 +99,17 @@ begin
FQueue.Pop(Result);
end;
procedure THostIpcConnect.Update;
procedure THostIpcConnect.Update(Handler:THostIpcHandler);
var
node:PQNode;
rec:THostIpcCbRec;
begin
node:=Recv;
while (node<>nil) do
begin
rec:=FCbReg[t_mtype(node^.mtype)];
if (rec.cbs<>nil) then
//
if (Handler<>nil) then
begin
rec.cbs(@node^.buf,rec.data);
Handler.OnMessage(t_mtype(node^.header.mtype),node^.header.mlen,@node^.buf);
end;
//
FreeMem(node);
@ -130,7 +138,7 @@ begin
//
end;
procedure THostIpcSimpleGUI.Send(mtype:t_mtype;mlen:DWORD;buf:Pointer);
procedure THostIpcSimpleMGUI.Send(mtype:t_mtype;mlen:DWORD;buf:Pointer);
begin
if (FDest<>nil) then
begin
@ -153,10 +161,13 @@ begin
inherited;
end;
procedure THostIpcSimpleKERN.Update;
procedure THostIpcSimpleKERN.Update(Handler:THostIpcHandler);
begin
RTLEventWaitFor(FEvent);
inherited;
if FQueue.IsEmpty then
begin
RTLEventWaitFor(FEvent);
end;
inherited Update(Handler);
end;
procedure THostIpcSimpleKERN.Send(mtype:t_mtype;mlen:DWORD;buf:Pointer);

248
sys/md/md_host_ipc.pas Normal file
View File

@ -0,0 +1,248 @@
unit md_host_ipc;
{$mode ObjFPC}{$H+}
interface
uses
Classes,
kern_thr,
kern_thread,
evbuffer,
evpoll,
host_ipc;
type
t_push_cb=Function(Node:Pointer):Boolean of object;
t_ipc_proto=object
Fbev :Pbufferevent;
Finput :Pevbuffer;
Foutput:Pevbuffer;
FHeader:TNodeHeader;
FState :Integer;
FPush :t_push_cb;
procedure Send(mtype:t_mtype;mlen:DWORD;buf:Pointer);
procedure Recv;
end;
THostIpcPipe=class(THostIpcConnect)
evpoll:Tevpoll;
proto:t_ipc_proto;
procedure set_pipe(fd:THandle);
procedure Recv; virtual;
Function Push(Node:Pointer):Boolean; virtual;
procedure thread_new; virtual;
procedure thread_free; virtual;
procedure Send(mtype:t_mtype;mlen:DWORD;buf:Pointer); override;
Constructor Create;
Destructor Destroy; override;
end;
THostIpcPipeMGUI=class(THostIpcPipe)
Ftd:TThreadID;
procedure Recv; override;
procedure thread_new; override;
procedure thread_free; override;
end;
THostIpcPipeKERN=class(THostIpcPipe)
Ftd:p_kthread;
Handler:THostIpcHandler;
procedure Recv; override;
procedure thread_new; override;
procedure thread_free; override;
end;
implementation
procedure t_ipc_proto.Send(mtype:t_mtype;mlen:DWORD;buf:Pointer);
var
node:PNodeHeader;
begin
node:=AllocMem(SizeOf(TNodeHeader)+mlen);
node^.mtype:=DWORD(mtype);
node^.mlen :=mlen;
Move(buf^,node^.buf,mlen);
evbuffer_add_ref(Foutput,node,0,SizeOf(TNodeHeader)+mlen,Freemem_ptr);
bufferevent_write(Fbev);
end;
procedure t_ipc_proto.Recv;
var
node:PQNode;
begin
repeat
case FState of
0:
begin
if (evbuffer_get_length(Finput)<SizeOf(TNodeHeader)) then Exit;
evbuffer_remove(Finput,@FHeader,SizeOf(TNodeHeader));
FState:=1;
end;
1:
begin
if (evbuffer_get_length(Finput)<FHeader.mlen) then Exit;
node:=AllocMem(SizeOf(TQNode)+FHeader.mlen);
node^.header:=FHeader;
evbuffer_remove(Finput,@node^.buf,FHeader.mlen);
FPush(node);
FState:=0;
end;
else;
end;
until (evbuffer_get_length(Finput)=0);
end;
function pipe_gui_thread(parameter:pointer):ptrint;
begin
Result:=0;
evpoll_loop(parameter);
end;
procedure pipe_kern_thread(parameter:pointer); SysV_ABI_CDecl;
begin
evpoll_loop(parameter);
end;
Procedure eventcb(bev:Pbufferevent;events:SizeUInt;ctx:pointer);
begin
if ((events and (BEV_EVENT_ERROR or BEV_EVENT_EOF))<>0) then
begin
Exit;
end;
if (events and BEV_EVENT_READING)<>0 then
begin
THostIpcPipe(ctx).Recv;
bufferevent_read(bev);
end;
if (events and BEV_EVENT_WRITING)<>0 then
begin
bufferevent_write(bev);
end;
end;
procedure THostIpcPipe.set_pipe(fd:THandle);
begin
proto.Fbev :=bufferevent_pipe_new (@evpoll,fd);
proto.Finput :=bufferevent_get_input (proto.Fbev);
proto.Foutput:=bufferevent_get_output(proto.Fbev);
proto.FPush :=@Self.Push;
bufferevent_setcb(proto.Fbev,@eventcb,Pointer(Self));
bufferevent_enable(proto.Fbev);
end;
procedure THostIpcPipe.Recv;
begin
proto.Recv;
end;
Function THostIpcPipe.Push(Node:Pointer):Boolean;
begin
Result:=FQueue.Push(node);
end;
procedure THostIpcPipe.thread_new;
begin
//
end;
procedure THostIpcPipe.thread_free;
begin
//
end;
procedure THostIpcPipe.Send(mtype:t_mtype;mlen:DWORD;buf:Pointer);
begin
proto.Send(mtype,mlen,buf);
end;
Constructor THostIpcPipe.Create;
begin
inherited;
evpoll_init(@evpoll,nil);
thread_new;
end;
Destructor THostIpcPipe.Destroy;
begin
evpoll_break(@evpoll);
thread_free;
bufferevent_free(proto.Fbev);
evpoll_free(@evpoll);
inherited;
end;
//
procedure THostIpcPipeMGUI.Recv;
begin
inherited;
//
if Assigned(Classes.WakeMainThread) then
begin
Classes.WakeMainThread(nil);
end;
end;
procedure THostIpcPipeMGUI.thread_new;
begin
Ftd:=BeginThread(@pipe_gui_thread,@evpoll);
end;
procedure THostIpcPipeMGUI.thread_free;
begin
WaitForThreadTerminate(Ftd,0);
CloseThread(Ftd);
end;
//
procedure THostIpcPipeKERN.Recv;
begin
inherited;
Update(Handler);
end;
procedure THostIpcPipeKERN.thread_new;
begin
Ftd:=nil;
kthread_add(@pipe_kern_thread,@evpoll,@Ftd,'[ipc_pipe]');
end;
procedure THostIpcPipeKERN.thread_free;
begin
thread_dec_ref(Ftd);
end;
end.

123
sys/md/md_pipe.pas Normal file
View File

@ -0,0 +1,123 @@
unit md_pipe;
{$mode ObjFPC}{$H+}
{$CALLING SysV_ABI_CDecl}
interface
uses
windows,
ntapi;
Const
MD_PIPE_ASYNC0=1;
MD_PIPE_ASYNC1=2;
function md_pipe2(pipefd:PHandle;flags:Integer):Integer;
implementation
const
FILE_SHARE_VALID_FLAGS=FILE_SHARE_READ or
FILE_SHARE_WRITE or
FILE_SHARE_DELETE;
Const
NamedPipe:PWideChar='\Device\NamedPipe\';
function md_pipe2(pipefd:PHandle;flags:Integer):Integer;
var
BLK:IO_STATUS_BLOCK;
UNAME:UNICODE_STRING;
OATTR:OBJECT_ATTRIBUTES;
timeout:LARGE_INTEGER;
hDirectory:THandle;
hFd:array[0..1] of THandle;
begin
Result:=0;
BLK:=Default(IO_STATUS_BLOCK);
UNAME:=Default(UNICODE_STRING);
UNAME.Length :=Length(NamedPipe)*SizeOf(WideChar);
UNAME.MaximumLength:=(Length(NamedPipe)+1)*SizeOf(WideChar);
UNAME.Buffer :=NamedPipe;
OATTR:=Default(OBJECT_ATTRIBUTES);
OATTR.Length :=SizeOf(OBJECT_ATTRIBUTES);
OATTR.ObjectName:=@UNAME;
OATTR.Attributes:=OBJ_CASE_INSENSITIVE;
hDirectory:=0;
Result:=NtOpenFile(@hDirectory,
SYNCHRONIZE,
@OATTR,
@BLK,
FILE_SHARE_VALID_FLAGS,
0);
if (Result<>0) then Exit;
timeout.QuadPart:=-500000;
BLK:=Default(IO_STATUS_BLOCK);
UNAME:=Default(UNICODE_STRING);
OATTR.RootDirectory:=hDirectory;
hFd[0]:=0;
Result:=NtCreateNamedPipeFile(@hFd[0],
SYNCHRONIZE or
FILE_READ_ATTRIBUTES or FILE_READ_DATA or
FILE_WRITE_ATTRIBUTES or FILE_WRITE_DATA or
FILE_CREATE_PIPE_INSTANCE,
@OATTR,
@BLK,
FILE_SHARE_READ or FILE_SHARE_WRITE,
FILE_CREATE,
(ord((flags and MD_PIPE_ASYNC0)=0)*FILE_SYNCHRONOUS_IO_NONALERT),
FILE_PIPE_BYTE_STREAM_TYPE,
FILE_PIPE_BYTE_STREAM_MODE,
FILE_PIPE_QUEUE_OPERATION,
$ffffffff,
0,
0,
@timeout);
if (Result<>0) then
begin
NtClose(hDirectory);
Exit;
end;
BLK:=Default(IO_STATUS_BLOCK);
OATTR.RootDirectory:=hFd[0];
OATTR.Attributes:=OBJ_CASE_INSENSITIVE or OBJ_INHERIT;
hFd[1]:=0;
Result:=NtOpenFile(@hFd[1],
SYNCHRONIZE or
FILE_READ_ATTRIBUTES or FILE_READ_DATA or
FILE_WRITE_ATTRIBUTES or FILE_WRITE_DATA,
@OATTR,
@BLK,
FILE_SHARE_VALID_FLAGS,
(ord((flags and MD_PIPE_ASYNC1)=0)*FILE_SYNCHRONOUS_IO_NONALERT)
);
if (Result<>0) then
begin
NtClose(hFd[0]);
NtClose(hDirectory);
Exit;
end;
NtClose(hDirectory);
pipefd[0]:=hFd[0];
pipefd[1]:=hFd[1];
end;
end.

View File

@ -19,6 +19,10 @@ function md_copyout(hProcess:THandle;kaddr,udaddr:Pointer;len:ptruint;lencopied
function md_copyin (udaddr,kaddr:Pointer;len:ptruint;lencopied:pptruint):Integer;
function md_copyout(kaddr,udaddr:Pointer;len:ptruint;lencopied:pptruint):Integer;
function md_getppid:DWORD;
function md_pidfd_getfd(pidfd,targetfd:THandle):THandle;
function md_pidfd_open (pid:DWORD):THandle;
procedure md_run_forked;
procedure md_fork_unshare;
function md_fork_process(proc:Pointer;data:Pointer;size:QWORD):THandle;
@ -32,6 +36,9 @@ uses
errno,
md_map;
var
ppid:DWORD=0;
function md_copyin(hProcess:THandle;udaddr,kaddr:Pointer;len:ptruint;lencopied:pptruint):Integer;
var
num:DWORD;
@ -78,6 +85,56 @@ begin
Result:=md_copyout(NtCurrentProcess,kaddr,udaddr,len,lencopied);
end;
function md_getppid:DWORD;
begin
Result:=ppid;
end;
function md_pidfd_getfd(pidfd,targetfd:THandle):THandle;
begin
Result:=0;
NtDuplicateObject(
pidfd,
targetfd,
NtCurrentProcess,
@Result,
0,
0,
DUPLICATE_SAME_ACCESS
);
end;
function md_dup_to_pidfd(pidfd,targetfd:THandle):THandle;
begin
Result:=0;
NtDuplicateObject(
NtCurrentProcess,
targetfd,
pidfd,
@Result,
0,
0,
DUPLICATE_SAME_ACCESS
);
end;
function md_pidfd_open(pid:DWORD):THandle;
var
ClientId:TCLIENT_ID;
OATTR:OBJECT_ATTRIBUTES;
R:DWORD;
begin
Result:=0;
ClientId.UniqueProcess:=pid;
ClientId.UniqueThread :=0;
OATTR:=Default(OBJECT_ATTRIBUTES);
OATTR.Length:=SizeOf(OBJECT_ATTRIBUTES);
R:=NtOpenProcess(@Result,PROCESS_DUP_HANDLE,@OATTR,@ClientId);
end;
const
JobObjectExtendedLimitInformation=9;
JOB_OBJECT_LIMIT_KILL_ON_JOB_CLOSE=$00002000;
@ -293,38 +350,10 @@ begin
until (prev>=addr);
end;
function md_pidfd_getfd(pidfd,targetfd:THandle):THandle;
begin
Result:=0;
NtDuplicateObject(
pidfd,
targetfd,
NtCurrentProcess,
@Result,
0,
0,
DUPLICATE_SAME_ACCESS
);
end;
function md_dup_to_pidfd(pidfd,targetfd:THandle):THandle;
begin
Result:=0;
NtDuplicateObject(
NtCurrentProcess,
targetfd,
pidfd,
@Result,
0,
0,
DUPLICATE_SAME_ACCESS
);
end;
type
p_shared_info=^t_shared_info;
t_shared_info=record
hParent :THandle;
ppid :QWORD;
hStdInput :THandle;
hStdOutput:THandle;
hStdError :THandle;
@ -340,15 +369,6 @@ var
len:ULONG_PTR;
proc:Pointer;
{
F:THandle;
F2:THandle;
S:RAwByteString;
BLK:IO_STATUS_BLOCK;
OFFSET:Int64;
R:DWORD;
}
begin
base:=Pointer(WIN_SHARED_ADDR);
@ -364,7 +384,7 @@ begin
if (info.State=MEM_FREE) then Exit;
//sleep(-1);
ppid:=base^.ppid;
SetStdHandle(STD_INPUT_HANDLE ,base^.hStdInput );
SetStdHandle(STD_ERROR_HANDLE ,base^.hStdOutput);
@ -374,36 +394,6 @@ begin
if (proc=nil) then Exit;
{
F:=FileCreate('log2.txt');
S:='0x'+HexStr(Pointer(proc))+#13#10;
FileWrite(F,PChar(S)^,Length(S));
S:='hParent:'+IntToStr(base^.hParent)+':'+#13#10;
FileWrite(F,PChar(S)^,Length(S));
F2:=GetStdHandle(STD_OUTPUT_HANDLE);
//F2:=md_pidfd_getfd(base^.hParent,F2);
S:='[NtWriteFile] hParent:'+IntToStr(base^.hParent)+'-'+#13#10;
//FileWrite(F2,PChar(S)^,Length(S));
BLK:=Default(IO_STATUS_BLOCK);
OFFSET:=Int64(FILE_WRITE_TO_END_OF_FILE_L);
R:=NtWriteFile(F2,0,nil,nil,@BLK,PChar(S),Length(S),@OFFSET,nil);
S:='F2:'+IntToStr(F2)+':'+#13#10;
FileWrite(F,PChar(S)^,Length(S));
S:='R:0x'+HexStr(R,8)+#13#10;
FileWrite(F,PChar(S)^,Length(S));
}
//writeln('test!');
//sleep(-1);
t_fork_cb(proc)(@base^.data,base^.size);
NtTerminateProcess(NtCurrentProcess, 0);
@ -453,7 +443,7 @@ begin
shared_info:=Default(t_shared_info);
shared_info.hParent :=md_dup_to_pidfd(hProcess,NtCurrentProcess);
shared_info.ppid :=GetCurrentProcessId;
shared_info.hStdInput :=md_dup_to_pidfd(hProcess,GetStdHandle(STD_INPUT_HANDLE));
shared_info.hStdOutput:=md_dup_to_pidfd(hProcess,GetStdHandle(STD_OUTPUT_HANDLE));

View File

@ -168,6 +168,7 @@ var
BUF:TWRITE_BUF;
i:QWORD;
td:p_kthread;
R:DWORD;
begin
Result:=0;
//init
@ -195,7 +196,16 @@ begin
Inc(iov_base,i);
Dec(iov_len ,i);
//
NtWriteFile(tp^.t_wr_handle,0,nil,nil,@BLK,@BUF.BUF,BUF.LEN,@OFFSET,nil);
R:=NtWriteFile(tp^.t_wr_handle,0,nil,nil,@BLK,@BUF.BUF,BUF.LEN,@OFFSET,nil);
//
if (R=STATUS_PENDING) then
begin
R:=NtWaitForSingleObject(tp^.t_wr_handle,False,nil);
if (R=0) then
begin
R:=BLK.Status;
end;
end;
//
BUF.INIT();
end;

View File

@ -2383,6 +2383,10 @@ begin
if (R=STATUS_PENDING) then
begin
R:=NtWaitForSingleObject(F,False,nil);
if (R=0) then
begin
R:=BLK.Status;
end;
end;
Result:=ntf2px(R);