7 output
: ^tMemoryStream
;
10 event
: procedure of object; {notification on statuc change}
11 procedure Init(const args
:ppchar
; var ioutput
:tMemoryStream
);
15 procedure PipeEvent(ev
:word);
26 procedure IOCHECK(prfx
: string);
29 e
:=eOSError
.CreateFmt('%S %U',[prfx
,fpGetErrno
]);
30 e
.ErrorCode
:=fpGetErrno
;
34 procedure tapx
.PipeEvent(ev
:word);
38 if (ev
and POLLIN
)>0 then begin
39 if output
^.WRBufLen
=0 then begin
40 fpKill(pid
,SIGPIPE
); {no space left for output, kill}
42 rl
:=fpRead(opipe
,output
^.WRBuf
,output
^.wrbuflen
);
43 if rl
=-1 then IOCHECK('read from pipe');
45 //writeln('pipeRead ',rl,' ev=',inttohex(ev,4));
48 if (ev
and POLLHUP
)>0 then begin
50 ServerLoop
.WatchFD(opipe
,nil);
52 fpWaitPid(pid
,ecode
,0); {wait to terminate and remove zombie}
53 {this could block it child closed stdout but did not terminate}
55 if wifexited(ecode
) then exitcode
:=wexitstatus(ecode
);
56 if wifsignaled(ecode
) then exitsignal
:=wtermsig(ecode
);
57 if assigned(event
) then event
;
61 procedure tapx
.Init(const args
:ppchar
; var ioutput
:tMemoryStream
);
69 if fpPipe(pipes
)=-1 then IOCHECK('pipe()');
71 if spid
<0 then IOCHECK('fork()');
74 Opipe
:=pipes
[0]; {save reading end}
75 fpClose(pipes
[1]); {close input of pipe}
76 ServerLoop
.WatchFD(opipe
,@PipeEvent
);
78 fpDup2(pipes
[1],1); {stdout:=pipeinput}
79 fpClose(0); {stdin:=nil}
82 fpExecv(args
[0],args
);
83 halt(127); {this is another process, cannot really raise here if exec fails}
90 ServerLoop
.WatchFD(opipe
,nil);
93 fpWaitPid(pid
,ecode
,0);