3 {io and timer code by plugwash}
\r
5 { Copyright (C) 2005 Bas Steendijk and Peter Green
\r
6 For conditions of distribution and use, see copyright notice in zlib_license.txt
\r
7 which is included in the package
\r
8 ----------------------------------------------------------------------------- }
\r
10 {note: you must use the @ in the last param to tltask.create not doing so will
\r
11 compile without error but will cause an access violation -pg}
\r
13 //note: events after release are normal and are the apps responsibility to deal with safely
\r
29 baseunix,unix,unixutil,
\r
33 classes,pgtypes,bfifo;
\r
34 procedure processtasks;
\r
38 {how this number is made up:
\r
39 - ethernet: MTU 1500
\r
40 - be safe for either "ethernet v1" or "PPPoE", both take 8 bytes
\r
41 - IPv6 header: 40 bytes (IPv4 is 20)
\r
42 - TCP/UDP header: 20 bytes
\r
44 packetbasesize = 1432;
\r
45 receivebufsize=packetbasesize*8;
\r
48 absoloutemaxs:integer=0;
\r
52 sigset= array[0..31] of longint;
\r
55 ESocketException = class(Exception);
\r
56 TBgExceptionEvent = procedure (Sender : TObject;
\r
58 var CanClose : Boolean) of object;
\r
60 // note : tsocketstate is defined in the same way as it is in François PIETTE's twsocket
\r
61 // however tlsocket currently only uses wsClosed wsConnecting wsconnected and wsListening
\r
62 TSocketState = (wsInvalidState,
\r
64 wsConnecting, wsConnected,
\r
65 wsAccepting, wsListening,
\r
68 TWSocketOption = (wsoNoReceiveLoop, wsoTcpNoDelay);
\r
69 TWSocketOptions = set of TWSocketOption;
\r
71 TSocketevent = procedure(Sender: TObject; Error: word) of object;
\r
72 //Tdataavailevent = procedure(data : string);
\r
73 TSendData = procedure (Sender: TObject; BytesSent: Integer) of object;
\r
75 tlcomponent = class(tcomponent)
\r
77 procedure releasetaskhandler(wparam,lparam:longint);
79 procedure release; virtual;
\r
80 destructor destroy; override;
\r
83 tlasio = class(tlcomponent)
\r
85 state : tsocketstate ;
\r
86 ComponentOptions : TWSocketOptions;
\r
87 fdhandlein : Longint ; {file discriptor}
\r
88 fdhandleout : Longint ; {file discriptor}
\r
90 onsessionclosed : tsocketevent ;
\r
91 ondataAvailable : tsocketevent ;
\r
92 onsessionAvailable : tsocketevent ;
\r
94 onsessionconnected : tsocketevent ;
\r
95 onsenddata : tsenddata ;
\r
96 ondatasent : tsocketevent ;
\r
97 //connected : boolean ;
\r
100 OnBgException : TBgExceptionEvent ;
\r
101 //connectread : boolean ;
\r
103 closehandles : boolean ;
\r
104 writtenthiscycle : boolean ;
\r
105 onfdwrite : procedure (Sender: TObject; Error: word) of object; //added for bewarehttpd
\r
107 destroying:boolean;
\r
108 recvbufsize:integer;
\r
109 function receivestr:string; virtual;
\r
112 procedure internalclose(error:word); virtual;
\r
113 constructor Create(AOwner: TComponent); override;
\r
115 destructor destroy; override;
\r
116 procedure fdcleanup;
\r
117 procedure HandleBackGroundException(E: Exception);
\r
118 procedure handlefdtrigger(readtrigger,writetrigger:boolean); virtual;
\r
119 procedure dup(invalue:longint);
\r
121 function sendflush : integer;
\r
122 procedure sendstr(const str : string);virtual;
\r
123 procedure putstringinsendbuffer(const newstring : string);
\r
124 function send(data:pointer;len:integer):integer;virtual;
\r
125 procedure putdatainsendbuffer(data:pointer;len:integer); virtual;
\r
126 procedure deletebuffereddata;
\r
128 //procedure messageloop;
\r
129 function Receive(Buf:Pointer;BufSize:integer):integer; virtual;
\r
130 procedure flush;virtual;
\r
131 procedure dodatasent(wparam,lparam:longint);
\r
132 procedure doreceiveloop(wparam,lparam:longint);
\r
133 procedure sinkdata(sender:tobject;error:word);
\r
135 procedure release; override; {test -beware}
\r
137 function RealSend(Data : Pointer; Len : Integer) : Integer; //added for bewarehttpd
\r
139 procedure myfdclose(fd : integer); virtual;{$ifdef win32}abstract;{$endif}
\r
140 function myfdwrite(fd: LongInt;const buf;size: LongInt):LongInt; virtual;{$ifdef win32}abstract;{$endif}
\r
141 function myfdread(fd: LongInt;var buf;size: LongInt):LongInt; virtual;{$ifdef win32}abstract;{$endif}
\r
143 procedure dupnowatch(invalue:longint);
\r
145 ttimerwrapperinterface=class(tlcomponent)
\r
147 function createwrappedtimer : tobject;virtual;abstract;
\r
148 // procedure setinitialevent(wrappedtimer : tobject;newvalue : boolean);virtual;abstract;
\r
149 procedure setontimer(wrappedtimer : tobject;newvalue:tnotifyevent);virtual;abstract;
\r
150 procedure setenabled(wrappedtimer : tobject;newvalue : boolean);virtual;abstract;
\r
151 procedure setinterval(wrappedtimer : tobject;newvalue : integer);virtual;abstract;
\r
155 timerwrapperinterface : ttimerwrapperinterface;
\r
163 tltimer=class(tlcomponent)
\r
167 wrappedtimer : tobject;
\r
170 // finitialevent : boolean ;
\r
171 fontimer : tnotifyevent ;
\r
172 fenabled : boolean ;
\r
173 finterval : integer ; {miliseconds, default 1000}
\r
175 procedure resettimes;
\r
177 // procedure setinitialevent(newvalue : boolean);
\r
178 procedure setontimer(newvalue:tnotifyevent);
\r
179 procedure setenabled(newvalue : boolean);
\r
180 procedure setinterval(newvalue : integer);
\r
182 //making theese public for now, this code should probablly be restructured later though
\r
183 prevtimer : tltimer ;
\r
184 nexttimer : tltimer ;
\r
185 nextts : ttimeval ;
\r
187 constructor create(aowner:tcomponent);override;
\r
188 destructor destroy;override;
\r
189 // property initialevent : boolean read finitialevent write setinitialevent;
\r
190 property ontimer : tnotifyevent read fontimer write setontimer;
\r
191 property enabled : boolean read fenabled write setenabled;
\r
192 property interval : integer read finterval write setinterval;
\r
196 ttaskevent=procedure(wparam,lparam:longint) of object;
\r
198 tltask=class(tobject)
\r
200 handler : ttaskevent;
\r
205 constructor create(ahandler:ttaskevent;aobj:tobject;awparam,alparam:longint);
\r
212 procedure processmessages; virtual;abstract;
\r
213 procedure messageloop; virtual;abstract;
\r
214 procedure exitmessageloop; virtual;abstract;
\r
215 procedure setfdreverse(fd : integer;reverseto : tlasio);virtual;abstract;
\r
216 procedure rmasterset(fd : integer;islistensocket : boolean); virtual;abstract;
\r
217 procedure rmasterclr(fd: integer); virtual;abstract;
\r
218 procedure wmasterset(fd : integer); virtual;abstract;
\r
219 procedure wmasterclr(fd: integer); virtual;abstract;
\r
222 eventcore : teventcore;
\r
224 procedure processmessages;
\r
225 procedure messageloop;
\r
226 procedure exitmessageloop;
\r
229 firsttimer : tltimer ;
\r
230 firsttask , lasttask , currenttask : tltask ;
\r
232 numread : integer ;
\r
233 mustrefreshfds : boolean ;
\r
234 { lcoretestcount:integer;}
\r
236 asinreleaseflag:boolean;
\r
239 procedure disconnecttasks(aobj:tobject);
\r
240 procedure addtask(ahandler:ttaskevent;aobj:tobject;awparam,alparam:longint);
\r
242 tonaddtask = procedure(ahandler:ttaskevent;aobj:tobject;awparam,alparam:longint);
\r
244 onaddtask : tonaddtask;
\r
247 procedure sleep(i:integer);
\r
249 procedure prepsigpipe;{$ifndef ver1_0}inline;{$endif}
\r
255 uses {sockets,}lloopback,lsignal;
\r
258 uses windows,winsock;
\r
261 {$include unixstuff.inc}
\r
263 {$include ltimevalstuff.inc}
\r
266 {!!! added sleep call -beware}
\r
267 procedure sleep(i:integer);
\r
274 tv.tv_sec := i div 1000;
\r
275 tv.tv_usec := (i mod 1000) * 1000;
\r
276 select(0,nil,nil,nil,@tv);
\r
280 destructor tlcomponent.destroy;
\r
282 disconnecttasks(self);
\r
286 procedure tlcomponent.releasetaskhandler(wparam,lparam:longint);
292 procedure tlcomponent.release;
\r
294 addtask(releasetaskhandler,self,0,0);
297 procedure tlasio.release;
\r
299 asinreleaseflag := true;
\r
303 procedure tlasio.doreceiveloop;
\r
305 if recvq.size = 0 then exit;
\r
306 if assigned(ondataavailable) then ondataavailable(self,0);
\r
307 if not (wsonoreceiveloop in componentoptions) then
\r
308 if recvq.size > 0 then tltask.create(self.doreceiveloop,self,0,0);
\r
311 function tlasio.receivestr;
\r
313 setlength(result,recvq.size);
\r
314 receive(@result[1],length(result));
\r
317 function tlasio.receive(Buf:Pointer;BufSize:integer):integer;
\r
323 if recvq.size < i then i := recvq.size;
\r
325 while (a < i) do begin
\r
326 b := recvq.get(p,i-a);
\r
328 inc(taddrint(buf),b);
\r
333 if wsonoreceiveloop in componentoptions then begin
\r
334 if recvq.size = 0 then eventcore.rmasterset(fdhandlein,false);
\r
338 constructor tlasio.create;
\r
340 inherited create(AOwner);
\r
341 if not assigned(eventcore) then raise exception.create('no event core');
\r
342 sendq := tfifo.create;
\r
343 recvq := tfifo.create;
\r
349 destructor tlasio.destroy;
\r
351 destroying := true;
\r
352 if state <> wsclosed then close;
\r
358 procedure tlasio.close;
\r
363 procedure tlasio.abort;
\r
368 procedure tlasio.fdcleanup;
\r
370 if fdhandlein <> -1 then begin
\r
371 eventcore.rmasterclr(fdhandlein); //fd_clr(fdhandlein,fdsrmaster)
\r
373 if fdhandleout <> -1 then begin
\r
374 eventcore.wmasterclr(fdhandleout);//fd_clr(fdhandleout,fdswmaster)
\r
376 if fdhandlein=fdhandleout then begin
\r
377 if fdhandlein <> -1 then begin
\r
378 myfdclose(fdhandlein);
\r
381 if fdhandlein <> -1 then begin
\r
382 myfdclose(fdhandlein);
\r
384 if fdhandleout <> -1 then begin
\r
385 myfdclose(fdhandleout);
\r
392 procedure tlasio.internalclose(error:word);
\r
394 if (state<>wsclosed) and (state<>wsinvalidstate) then begin
\r
395 // -2 is a special indication that we should just exist silently
\r
396 // (used for connect failure handling when socket creation fails)
\r
397 if (fdhandlein = -2) and (fdhandleout = -2) then exit;
\r
398 if (fdhandlein < 0) or (fdhandleout < 0) then raise exception.create('internalclose called with invalid fd handles');
\r
399 eventcore.rmasterclr(fdhandlein);//fd_clr(fdhandlein,fdsrmaster);
\r
400 eventcore.wmasterclr(fdhandleout);//fd_clr(fdhandleout,fdswmaster);
\r
402 if closehandles then begin
\r
404 //anyone remember why this is here? --plugwash
\r
405 fcntl(fdhandlein,F_SETFL,0);
\r
407 myfdclose(fdhandlein);
\r
408 if fdhandleout <> fdhandlein then begin
\r
410 fcntl(fdhandleout,F_SETFL,0);
\r
412 myfdclose(fdhandleout);
\r
414 eventcore.setfdreverse(fdhandlein,nil);
\r
415 eventcore.setfdreverse(fdhandleout,nil);
\r
422 if assigned(onsessionclosed) then if not destroying then onsessionclosed(self,error);
\r
424 if assigned(sendq) then sendq.del(maxlongint);
\r
428 {* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
\r
429 { All exceptions *MUST* be handled. If an exception is not handled, the }
\r
430 { application will most likely be shut down ! }
\r
431 procedure tlasio.HandleBackGroundException(E: Exception);
\r
433 CanAbort : Boolean;
\r
436 { First call the error event handler, if any }
\r
437 if Assigned(OnBgException) then begin
\r
439 OnBgException(Self, E, CanAbort);
\r
443 { Then abort the socket }
\r
444 if CanAbort then begin
\r
452 procedure tlasio.sendstr(const str : string);
\r
454 putstringinsendbuffer(str);
\r
458 procedure tlasio.putstringinsendbuffer(const newstring : string);
\r
460 if newstring <> '' then putdatainsendbuffer(@newstring[1],length(newstring));
\r
463 function tlasio.send(data:pointer;len:integer):integer;
\r
465 if state <> wsconnected then begin
\r
469 if len < 0 then len := 0;
\r
471 putdatainsendbuffer(data,len);
\r
476 procedure tlasio.putdatainsendbuffer(data:pointer;len:integer);
\r
478 sendq.add(data,len);
\r
481 function tlasio.sendflush : integer;
\r
485 // fdstestr : fdset;
\r
486 // fdstestw : fdset;
\r
488 if state <> wsconnected then begin
\r
493 lensent := sendq.get(data,packetbasesize*2);
\r
494 if assigned(data) then result := myfdwrite(fdhandleout,data^,lensent) else result := 0;
\r
496 if result = -1 then lensent := 0 else lensent := result;
\r
498 //sendq := copy(sendq,lensent+1,length(sendq)-lensent);
\r
499 sendq.del(lensent);
\r
501 //fd_clr(fdhandleout,fdsw); // this prevents the socket being closed by a write
\r
502 // that sends nothing because a previous socket has
\r
503 // slready flushed this socket when the message loop
\r
505 // if sendq.size > 0 then begin
\r
506 eventcore.wmasterset(fdhandleout);//fd_set(fdhandleout,fdswmaster);
\r
508 // wmasterclr(fdhandleout);//fd_clr(fdhandleout,fdswmaster);
\r
510 if result > 0 then begin
\r
511 if assigned(onsenddata) then onsenddata(self,result);
\r
512 // if sendq.size=0 then if assigned(ondatasent) then begin
\r
513 // tltask.create(self.dodatasent,self,0,0);
\r
514 // //begin test code
\r
515 // fd_zero(fdstestr);
\r
516 // fd_zero(fdstestw);
\r
517 // fd_set(fdhandlein,fdstestr);
\r
518 // fd_set(fdhandleout,fdstestw);
\r
519 // select(maxs,@fdstestr,@fdstestw,nil,0);
\r
520 // writeln(fd_isset(fdhandlein,fdstestr),' ',fd_isset(fdhandleout,fdstestw));
\r
524 writtenthiscycle := true;
\r
528 procedure tlasio.dupnowatch(invalue:longint);
\r
530 { debugout('invalue='+inttostr(invalue));}
\r
532 if state<> wsclosed then close;
\r
533 fdhandlein := invalue;
\r
534 fdhandleout := invalue;
\r
535 eventcore.setfdreverse(fdhandlein,self);
\r
537 fcntl(fdhandlein,F_SETFL,OPEN_NONBLOCK);
\r
539 state := wsconnected;
\r
544 procedure tlasio.dup(invalue:longint);
\r
546 dupnowatch(invalue);
\r
547 eventcore.rmasterset(fdhandlein,false);//fd_set(fdhandlein,fdsrmaster);
\r
548 eventcore.wmasterclr(fdhandleout);//fd_clr(fdhandleout,fdswmaster);
\r
552 procedure tlasio.handlefdtrigger(readtrigger,writetrigger:boolean);
\r
554 sendflushresult : integer;
\r
555 tempbuf:array[0..receivebufsize-1] of byte;
\r
558 if (state=wsconnected) and writetrigger then begin
\r
559 //writeln('write trigger');
\r
561 if (sendq.size >0) then begin
\r
563 sendflushresult := sendflush;
\r
564 if (sendflushresult <= 0) and (not writtenthiscycle) then begin
\r
565 if sendflushresult=0 then begin // linuxerror := 0;
\r
570 if getlasterror=WSAEWOULDBLOCK then begin
\r
571 //the asynchronous nature of windows messages means we sometimes
\r
572 //get here with the buffer full
\r
573 //so do nothing in that case
\r
577 internalclose({$ifdef win32}getlasterror{$else}linuxerror{$endif});
\r
583 //everything is sent fire off ondatasent event
\r
584 if fdhandleout >= 0 then eventcore.wmasterclr(fdhandleout);//fd_clr(fdhandleout,fdswmaster);
\r
585 if assigned(ondatasent) then tltask.create(self.dodatasent,self,0,0);
\r
587 if assigned(onfdwrite) then onfdwrite(self,0);
\r
589 writtenthiscycle := false;
\r
590 if (state =wsconnected) and readtrigger then begin
\r
591 if recvq.size=0 then begin
\r
593 if (a <= 0) or (a > sizeof(tempbuf)) then a := sizeof(tempbuf);
\r
594 numread := myfdread(fdhandlein,tempbuf,a);
\r
595 if (numread=0) and (not mustrefreshfds) then begin
\r
596 {if i remember correctly numread=0 is caused by eof
\r
597 if this isn't dealt with then you get a cpu eating infinite loop
\r
598 however if onsessionconencted has called processmessages that could
\r
599 cause us to drop to here with an empty recvq and nothing left to read
\r
600 and we don't want that to cause the socket to close}
\r
603 end else if (numread=-1) then begin
\r
605 //sometimes on windows we get stale messages due to the inherent delays
\r
606 //in the windows message queue
\r
607 if WSAGetLastError = wsaewouldblock then begin
\r
613 internalclose({$ifdef win32}wsagetlasterror{$else}linuxerror{$endif});
\r
615 end else if numread > 0 then recvq.add(@tempbuf,numread);
\r
618 if recvq.size > 0 then begin
\r
619 if wsonoreceiveloop in componentoptions then eventcore.rmasterclr(fdhandlein); //fd_clr(fdhandlein,fdsrmaster);
\r
620 if assigned(ondataavailable) then ondataAvailable(self,0);
\r
621 if not (wsonoreceiveloop in componentoptions) then if recvq.size > 0 then
\r
622 tltask.create(self.doreceiveloop,self,0,0);
\r
624 //until (numread = 0) or (currentsocket.state<>wsconnected);
\r
625 { debugout('inner loop complete');}
\r
629 procedure tlasio.flush;
\r
631 type fdset = tfdset;
\r
637 fd_set(fdhandleout,fds);
\r
638 while sendq.size>0 do begin
\r
639 select(fdhandleout+1,nil,@fds,nil,nil);
\r
640 if sendflush <= 0 then exit;
\r
644 procedure tlasio.dodatasent(wparam,lparam:longint);
\r
646 if assigned(ondatasent) then ondatasent(self,lparam);
\r
649 procedure tlasio.deletebuffereddata;
\r
651 sendq.del(maxlongint);
\r
654 procedure tlasio.sinkdata(sender:tobject;error:word);
\r
656 tlasio(sender).recvq.del(maxlongint);
\r
660 procedure tltimer.resettimes;
\r
662 gettimeofday(nextts);
\r
663 {if not initialevent then} tv_add(nextts,interval);
\r
667 {procedure tltimer.setinitialevent(newvalue : boolean);
\r
669 if newvalue <> finitialevent then begin
\r
670 finitialevent := newvalue;
\r
671 if assigned(timerwrapperinterface) then begin
\r
672 timerwrapperinterface.setinitialevent(wrappedtimer,newvalue);
\r
679 procedure tltimer.setontimer(newvalue:tnotifyevent);
\r
681 if @newvalue <> @fontimer then begin
\r
682 fontimer := newvalue;
\r
683 if assigned(timerwrapperinterface) then begin
\r
684 timerwrapperinterface.setontimer(wrappedtimer,newvalue);
\r
693 procedure tltimer.setenabled(newvalue : boolean);
\r
695 if newvalue <> fenabled then begin
\r
696 fenabled := newvalue;
\r
697 if assigned(timerwrapperinterface) then begin
\r
698 timerwrapperinterface.setenabled(wrappedtimer,newvalue);
\r
701 raise exception.create('non wrapper timers are not permitted on windows');
\r
709 procedure tltimer.setinterval(newvalue:integer);
\r
711 if newvalue <> finterval then begin
\r
712 finterval := newvalue;
\r
713 if assigned(timerwrapperinterface) then begin
\r
714 timerwrapperinterface.setinterval(wrappedtimer,newvalue);
\r
717 raise exception.create('non wrapper timers are not permitted on windows');
\r
729 constructor tltimer.create;
\r
731 inherited create(AOwner);
\r
732 if assigned(timerwrapperinterface) then begin
\r
733 wrappedtimer := timerwrapperinterface.createwrappedtimer;
\r
737 nexttimer := firsttimer;
\r
740 if assigned(nexttimer) then nexttimer.prevtimer := self;
\r
741 firsttimer := self;
\r
747 destructor tltimer.destroy;
\r
749 if assigned(timerwrapperinterface) then begin
\r
752 if prevtimer <> nil then begin
\r
753 prevtimer.nexttimer := nexttimer;
\r
755 firsttimer := nexttimer;
\r
757 if nexttimer <> nil then begin
\r
758 nexttimer.prevtimer := prevtimer;
\r
765 constructor tltask.create(ahandler:ttaskevent;aobj:tobject;awparam,alparam:longint);
\r
768 if assigned(onaddtask) then onaddtask(ahandler,aobj,awparam,alparam);
\r
769 handler := ahandler;
\r
773 {nexttask := firsttask;
\r
774 firsttask := self;}
\r
775 if assigned(lasttask) then begin
\r
776 lasttask.nexttask := self;
\r
781 //ahandler(wparam,lparam);
\r
784 procedure addtask(ahandler:ttaskevent;aobj:tobject;awparam,alparam:longint);
\r
787 tltask.create(ahandler,aobj,awparam,alparam);
\r
791 procedure prepsigpipe;{$ifndef ver1_0}inline;
\r
794 starthandlesignal(sigpipe);
\r
795 if not assigned(signalloopback) then begin
\r
796 signalloopback := tlloopback.create(nil);
\r
797 signalloopback.ondataAvailable := signalloopback.sinkdata;
\r
804 procedure processtasks;//inline;
\r
806 temptask : tltask ;
\r
810 if not assigned(currenttask) then begin
\r
811 currenttask := firsttask;
\r
815 while assigned(currenttask) do begin
\r
817 if assigned(currenttask.handler) then currenttask.handler(currenttask.wparam,currenttask.lparam);
\r
818 if assigned(currenttask) then begin
\r
819 temptask := currenttask;
\r
820 currenttask := currenttask.nexttask;
\r
823 //writeln('processed a task');
\r
831 procedure disconnecttasks(aobj:tobject);
\r
833 currenttasklocal : tltask ;
\r
836 for counter := 0 to 1 do begin
\r
837 if counter = 0 then begin
\r
838 currenttasklocal := firsttask; //main list of tasks
\r
840 currenttasklocal := currenttask; //needed in case called from a task
\r
842 // note i don't bother to sestroy the links here as that will happen when
\r
843 // the list of tasks is processed anyway
\r
844 while assigned(currenttasklocal) do begin
\r
845 if currenttasklocal.obj = aobj then begin
\r
846 currenttasklocal.obj := nil;
\r
847 currenttasklocal.handler := nil;
\r
849 currenttasklocal := currenttasklocal.nexttask;
\r
855 procedure processmessages;
\r
857 eventcore.processmessages;
\r
859 procedure messageloop;
\r
861 eventcore.messageloop;
\r
864 procedure exitmessageloop;
\r
866 eventcore.exitmessageloop;
\r
869 function tlasio.RealSend(Data : Pointer; Len : Integer) : Integer;
\r
871 result := myfdwrite(fdhandleout,data^,len);
\r
872 if (result > 0) and assigned(onsenddata) then onsenddata(self,result);
\r
873 eventcore.wmasterset(fdhandleout);
\r
876 procedure tlasio.myfdclose(fd : integer);
\r
880 function tlasio.myfdwrite(fd: LongInt;const buf;size: LongInt):LongInt;
\r
882 result := fdwrite(fd,buf,size);
\r
885 function tlasio.myfdread(fd: LongInt;var buf;size: LongInt):LongInt;
\r
887 result := fdread(fd,buf,size);
\r
899 signalloopback := nil;
\r