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
78 procedure release; virtual;
\r
79 destructor destroy; override;
\r
82 tlasio = class(tlcomponent)
\r
84 state : tsocketstate ;
\r
85 ComponentOptions : TWSocketOptions;
\r
86 fdhandlein : Longint ; {file discriptor}
\r
87 fdhandleout : Longint ; {file discriptor}
\r
89 onsessionclosed : tsocketevent ;
\r
90 ondataAvailable : tsocketevent ;
\r
91 onsessionAvailable : tsocketevent ;
\r
93 onsessionconnected : tsocketevent ;
\r
94 onsenddata : tsenddata ;
\r
95 ondatasent : tsocketevent ;
\r
96 //connected : boolean ;
\r
101 OnBgException : TBgExceptionEvent ;
\r
102 //connectread : boolean ;
\r
104 closehandles : boolean ;
\r
105 writtenthiscycle : boolean ;
\r
106 onfdwrite : procedure (Sender: TObject; Error: word) of object; //added for bewarehttpd
\r
108 destroying:boolean;
\r
109 recvbufsize:integer;
\r
110 function receivestr:string; virtual;
\r
113 procedure internalclose(error:word); virtual;
\r
114 constructor Create(AOwner: TComponent); override;
\r
116 destructor destroy; override;
\r
117 procedure fdcleanup;
\r
118 procedure HandleBackGroundException(E: Exception);
\r
119 procedure handlefdtrigger(readtrigger,writetrigger:boolean); virtual;
\r
120 procedure dup(invalue:longint);
\r
122 function sendflush : integer;
\r
123 procedure sendstr(const str : string);virtual;
\r
124 procedure putstringinsendbuffer(const newstring : string);
\r
125 function send(data:pointer;len:integer):integer;virtual;
\r
126 procedure putdatainsendbuffer(data:pointer;len:integer); virtual;
\r
127 procedure deletebuffereddata;
\r
129 //procedure messageloop;
\r
130 function Receive(Buf:Pointer;BufSize:integer):integer; virtual;
\r
131 procedure flush;virtual;
\r
132 procedure dodatasent(wparam,lparam:longint);
\r
133 procedure doreceiveloop(wparam,lparam:longint);
\r
134 procedure sinkdata(sender:tobject;error:word);
\r
136 procedure release; override; {test -beware}
\r
138 function RealSend(Data : Pointer; Len : Integer) : Integer; //added for bewarehttpd
\r
140 procedure myfdclose(fd : integer); virtual;{$ifdef win32}abstract;{$endif}
\r
141 function myfdwrite(fd: LongInt;const buf;size: LongInt):LongInt; virtual;{$ifdef win32}abstract;{$endif}
\r
142 function myfdread(fd: LongInt;var buf;size: LongInt):LongInt; virtual;{$ifdef win32}abstract;{$endif}
\r
144 procedure dupnowatch(invalue:longint);
\r
146 ttimerwrapperinterface=class(tlcomponent)
\r
148 function createwrappedtimer : tobject;virtual;abstract;
\r
149 // procedure setinitialevent(wrappedtimer : tobject;newvalue : boolean);virtual;abstract;
\r
150 procedure setontimer(wrappedtimer : tobject;newvalue:tnotifyevent);virtual;abstract;
\r
151 procedure setenabled(wrappedtimer : tobject;newvalue : boolean);virtual;abstract;
\r
152 procedure setinterval(wrappedtimer : tobject;newvalue : integer);virtual;abstract;
\r
156 timerwrapperinterface : ttimerwrapperinterface;
\r
164 tltimer=class(tlcomponent)
\r
168 wrappedtimer : tobject;
\r
171 // finitialevent : boolean ;
\r
172 fontimer : tnotifyevent ;
\r
173 fenabled : boolean ;
\r
174 finterval : integer ; {miliseconds, default 1000}
\r
176 procedure resettimes;
\r
178 // procedure setinitialevent(newvalue : boolean);
\r
179 procedure setontimer(newvalue:tnotifyevent);
\r
180 procedure setenabled(newvalue : boolean);
\r
181 procedure setinterval(newvalue : integer);
\r
183 //making theese public for now, this code should probablly be restructured later though
\r
184 prevtimer : tltimer ;
\r
185 nexttimer : tltimer ;
\r
186 nextts : ttimeval ;
\r
188 constructor create(aowner:tcomponent);override;
\r
189 destructor destroy;override;
\r
190 // property initialevent : boolean read finitialevent write setinitialevent;
\r
191 property ontimer : tnotifyevent read fontimer write setontimer;
\r
192 property enabled : boolean read fenabled write setenabled;
\r
193 property interval : integer read finterval write setinterval;
\r
197 ttaskevent=procedure(wparam,lparam:longint) of object;
\r
199 tltask=class(tobject)
\r
201 handler : ttaskevent;
\r
206 constructor create(ahandler:ttaskevent;aobj:tobject;awparam,alparam:longint);
\r
213 procedure processmessages; virtual;abstract;
\r
214 procedure messageloop; virtual;abstract;
\r
215 procedure exitmessageloop; virtual;abstract;
\r
216 procedure setfdreverse(fd : integer;reverseto : tlasio);virtual;abstract;
\r
217 procedure rmasterset(fd : integer;islistensocket : boolean); virtual;abstract;
\r
218 procedure rmasterclr(fd: integer); virtual;abstract;
\r
219 procedure wmasterset(fd : integer); virtual;abstract;
\r
220 procedure wmasterclr(fd: integer); virtual;abstract;
\r
223 eventcore : teventcore;
\r
225 procedure processmessages;
\r
226 procedure messageloop;
\r
227 procedure exitmessageloop;
\r
230 firstasin : tlasio ;
\r
231 firsttimer : tltimer ;
\r
232 firsttask , lasttask , currenttask : tltask ;
\r
234 numread : integer ;
\r
235 mustrefreshfds : boolean ;
\r
236 { lcoretestcount:integer;}
\r
238 asinreleaseflag:boolean;
\r
241 procedure disconnecttasks(aobj:tobject);
\r
242 procedure addtask(ahandler:ttaskevent;aobj:tobject;awparam,alparam:longint);
\r
244 tonaddtask = procedure(ahandler:ttaskevent;aobj:tobject;awparam,alparam:longint);
\r
246 onaddtask : tonaddtask;
\r
249 procedure sleep(i:integer);
\r
251 procedure prepsigpipe;{$ifndef ver1_0}inline;{$endif}
\r
257 uses {sockets,}lloopback,lsignal;
\r
260 uses windows,winsock;
\r
263 {$include unixstuff.inc}
\r
265 {$include ltimevalstuff.inc}
\r
268 {!!! added sleep call -beware}
\r
269 procedure sleep(i:integer);
\r
276 tv.tv_sec := i div 1000;
\r
277 tv.tv_usec := (i mod 1000) * 1000;
\r
278 select(0,nil,nil,nil,@tv);
\r
282 destructor tlcomponent.destroy;
\r
284 disconnecttasks(self);
\r
291 procedure tlcomponent.release;
\r
296 procedure tlasio.release;
\r
298 asinreleaseflag := true;
\r
302 procedure tlasio.doreceiveloop;
\r
304 if recvq.size = 0 then exit;
\r
305 if assigned(ondataavailable) then ondataavailable(self,0);
\r
306 if not (wsonoreceiveloop in componentoptions) then
\r
307 if recvq.size > 0 then tltask.create(self.doreceiveloop,self,0,0);
\r
310 function tlasio.receivestr;
\r
312 setlength(result,recvq.size);
\r
313 receive(@result[1],length(result));
\r
316 function tlasio.receive(Buf:Pointer;BufSize:integer):integer;
\r
322 if recvq.size < i then i := recvq.size;
\r
324 while (a < i) do begin
\r
325 b := recvq.get(p,i-a);
\r
327 inc(taddrint(buf),b);
\r
332 if wsonoreceiveloop in componentoptions then begin
\r
333 if recvq.size = 0 then eventcore.rmasterset(fdhandlein,false);
\r
337 constructor tlasio.create;
\r
339 inherited create(AOwner);
\r
340 if not assigned(eventcore) then raise exception.create('no event core');
\r
341 sendq := tfifo.create;
\r
342 recvq := tfifo.create;
\r
346 nextasin := firstasin;
\r
348 if assigned(nextasin) then nextasin.prevasin := self;
\r
354 destructor tlasio.destroy;
\r
356 destroying := true;
\r
357 if state <> wsclosed then close;
\r
358 if prevasin <> nil then begin
\r
359 prevasin.nextasin := nextasin;
\r
361 firstasin := nextasin;
\r
363 if nextasin <> nil then begin
\r
364 nextasin.prevasin := prevasin;
\r
371 procedure tlasio.close;
\r
376 procedure tlasio.abort;
\r
381 procedure tlasio.fdcleanup;
\r
383 if fdhandlein <> -1 then begin
\r
384 eventcore.rmasterclr(fdhandlein); //fd_clr(fdhandlein,fdsrmaster)
\r
386 if fdhandleout <> -1 then begin
\r
387 eventcore.wmasterclr(fdhandleout);//fd_clr(fdhandleout,fdswmaster)
\r
389 if fdhandlein=fdhandleout then begin
\r
390 if fdhandlein <> -1 then begin
\r
391 myfdclose(fdhandlein);
\r
394 if fdhandlein <> -1 then begin
\r
395 myfdclose(fdhandlein);
\r
397 if fdhandleout <> -1 then begin
\r
398 myfdclose(fdhandleout);
\r
405 procedure tlasio.internalclose(error:word);
\r
407 if (state<>wsclosed) and (state<>wsinvalidstate) then begin
\r
408 // -2 is a special indication that we should just exist silently
\r
409 // (used for connect failure handling when socket creation fails)
\r
410 if (fdhandlein = -2) and (fdhandleout = -2) then exit;
\r
411 if (fdhandlein < 0) or (fdhandleout < 0) then raise exception.create('internalclose called with invalid fd handles');
\r
412 eventcore.rmasterclr(fdhandlein);//fd_clr(fdhandlein,fdsrmaster);
\r
413 eventcore.wmasterclr(fdhandleout);//fd_clr(fdhandleout,fdswmaster);
\r
415 if closehandles then begin
\r
417 //anyone remember why this is here? --plugwash
\r
418 fcntl(fdhandlein,F_SETFL,0);
\r
420 myfdclose(fdhandlein);
\r
421 if fdhandleout <> fdhandlein then begin
\r
423 fcntl(fdhandleout,F_SETFL,0);
\r
425 myfdclose(fdhandleout);
\r
427 eventcore.setfdreverse(fdhandlein,nil);
\r
428 eventcore.setfdreverse(fdhandleout,nil);
\r
435 if assigned(onsessionclosed) then if not destroying then onsessionclosed(self,error);
\r
437 if assigned(sendq) then sendq.del(maxlongint);
\r
441 {* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
\r
442 { All exceptions *MUST* be handled. If an exception is not handled, the }
\r
443 { application will most likely be shut down ! }
\r
444 procedure tlasio.HandleBackGroundException(E: Exception);
\r
446 CanAbort : Boolean;
\r
449 { First call the error event handler, if any }
\r
450 if Assigned(OnBgException) then begin
\r
452 OnBgException(Self, E, CanAbort);
\r
456 { Then abort the socket }
\r
457 if CanAbort then begin
\r
465 procedure tlasio.sendstr(const str : string);
\r
467 putstringinsendbuffer(str);
\r
471 procedure tlasio.putstringinsendbuffer(const newstring : string);
\r
473 if newstring <> '' then putdatainsendbuffer(@newstring[1],length(newstring));
\r
476 function tlasio.send(data:pointer;len:integer):integer;
\r
478 if state <> wsconnected then begin
\r
482 if len < 0 then len := 0;
\r
484 putdatainsendbuffer(data,len);
\r
489 procedure tlasio.putdatainsendbuffer(data:pointer;len:integer);
\r
491 sendq.add(data,len);
\r
494 function tlasio.sendflush : integer;
\r
498 // fdstestr : fdset;
\r
499 // fdstestw : fdset;
\r
501 if state <> wsconnected then exit;
\r
503 lensent := sendq.get(data,packetbasesize*2);
\r
504 if assigned(data) then result := myfdwrite(fdhandleout,data^,lensent) else result := 0;
\r
506 if result = -1 then lensent := 0 else lensent := result;
\r
508 //sendq := copy(sendq,lensent+1,length(sendq)-lensent);
\r
509 sendq.del(lensent);
\r
511 //fd_clr(fdhandleout,fdsw); // this prevents the socket being closed by a write
\r
512 // that sends nothing because a previous socket has
\r
513 // slready flushed this socket when the message loop
\r
515 // if sendq.size > 0 then begin
\r
516 eventcore.wmasterset(fdhandleout);//fd_set(fdhandleout,fdswmaster);
\r
518 // wmasterclr(fdhandleout);//fd_clr(fdhandleout,fdswmaster);
\r
520 if result > 0 then begin
\r
521 if assigned(onsenddata) then onsenddata(self,result);
\r
522 // if sendq.size=0 then if assigned(ondatasent) then begin
\r
523 // tltask.create(self.dodatasent,self,0,0);
\r
524 // //begin test code
\r
525 // fd_zero(fdstestr);
\r
526 // fd_zero(fdstestw);
\r
527 // fd_set(fdhandlein,fdstestr);
\r
528 // fd_set(fdhandleout,fdstestw);
\r
529 // select(maxs,@fdstestr,@fdstestw,nil,0);
\r
530 // writeln(fd_isset(fdhandlein,fdstestr),' ',fd_isset(fdhandleout,fdstestw));
\r
534 writtenthiscycle := true;
\r
538 procedure tlasio.dupnowatch(invalue:longint);
\r
540 { debugout('invalue='+inttostr(invalue));}
\r
542 if state<> wsclosed then close;
\r
543 fdhandlein := invalue;
\r
544 fdhandleout := invalue;
\r
545 eventcore.setfdreverse(fdhandlein,self);
\r
547 fcntl(fdhandlein,F_SETFL,OPEN_NONBLOCK);
\r
549 state := wsconnected;
\r
554 procedure tlasio.dup(invalue:longint);
\r
556 dupnowatch(invalue);
\r
557 eventcore.rmasterset(fdhandlein,false);//fd_set(fdhandlein,fdsrmaster);
\r
558 eventcore.wmasterclr(fdhandleout);//fd_clr(fdhandleout,fdswmaster);
\r
562 procedure tlasio.handlefdtrigger(readtrigger,writetrigger:boolean);
\r
564 sendflushresult : integer;
\r
565 tempbuf:array[0..receivebufsize-1] of byte;
\r
568 if (state=wsconnected) and writetrigger then begin
\r
569 //writeln('write trigger');
\r
571 if (sendq.size >0) then begin
\r
573 sendflushresult := sendflush;
\r
574 if (sendflushresult <= 0) and (not writtenthiscycle) then begin
\r
575 if sendflushresult=0 then begin // linuxerror := 0;
\r
580 if getlasterror=WSAEWOULDBLOCK then begin
\r
581 //the asynchronous nature of windows messages means we sometimes
\r
582 //get here with the buffer full
\r
583 //so do nothing in that case
\r
587 internalclose({$ifdef win32}getlasterror{$else}linuxerror{$endif});
\r
593 //everything is sent fire off ondatasent event
\r
594 if fdhandleout >= 0 then eventcore.wmasterclr(fdhandleout);//fd_clr(fdhandleout,fdswmaster);
\r
595 if assigned(ondatasent) then tltask.create(self.dodatasent,self,0,0);
\r
597 if assigned(onfdwrite) then onfdwrite(self,0);
\r
599 writtenthiscycle := false;
\r
600 if (state =wsconnected) and readtrigger then begin
\r
601 if recvq.size=0 then begin
\r
603 if (a <= 0) or (a > sizeof(tempbuf)) then a := sizeof(tempbuf);
\r
604 numread := myfdread(fdhandlein,tempbuf,a);
\r
605 if (numread=0) and (not mustrefreshfds) then begin
\r
606 {if i remember correctly numread=0 is caused by eof
\r
607 if this isn't dealt with then you get a cpu eating infinite loop
\r
608 however if onsessionconencted has called processmessages that could
\r
609 cause us to drop to here with an empty recvq and nothing left to read
\r
610 and we don't want that to cause the socket to close}
\r
613 end else if (numread=-1) then begin
\r
615 //sometimes on windows we get stale messages due to the inherent delays
\r
616 //in the windows message queue
\r
617 if WSAGetLastError = wsaewouldblock then begin
\r
623 internalclose({$ifdef win32}wsagetlasterror{$else}linuxerror{$endif});
\r
625 end else if numread > 0 then recvq.add(@tempbuf,numread);
\r
628 if recvq.size > 0 then begin
\r
629 if wsonoreceiveloop in componentoptions then eventcore.rmasterclr(fdhandlein); //fd_clr(fdhandlein,fdsrmaster);
\r
630 if assigned(ondataavailable) then ondataAvailable(self,0);
\r
631 if not (wsonoreceiveloop in componentoptions) then if recvq.size > 0 then
\r
632 tltask.create(self.doreceiveloop,self,0,0);
\r
634 //until (numread = 0) or (currentsocket.state<>wsconnected);
\r
635 { debugout('inner loop complete');}
\r
639 procedure tlasio.flush;
\r
641 type fdset = tfdset;
\r
647 fd_set(fdhandleout,fds);
\r
648 while sendq.size>0 do begin
\r
649 select(fdhandleout+1,nil,@fds,nil,nil);
\r
650 if sendflush <= 0 then exit;
\r
654 procedure tlasio.dodatasent(wparam,lparam:longint);
\r
656 if assigned(ondatasent) then ondatasent(self,lparam);
\r
659 procedure tlasio.deletebuffereddata;
\r
661 sendq.del(maxlongint);
\r
664 procedure tlasio.sinkdata(sender:tobject;error:word);
\r
666 tlasio(sender).recvq.del(maxlongint);
\r
670 procedure tltimer.resettimes;
\r
672 gettimeofday(nextts);
\r
673 {if not initialevent then} tv_add(nextts,interval);
\r
677 {procedure tltimer.setinitialevent(newvalue : boolean);
\r
679 if newvalue <> finitialevent then begin
\r
680 finitialevent := newvalue;
\r
681 if assigned(timerwrapperinterface) then begin
\r
682 timerwrapperinterface.setinitialevent(wrappedtimer,newvalue);
\r
689 procedure tltimer.setontimer(newvalue:tnotifyevent);
\r
691 if @newvalue <> @fontimer then begin
\r
692 fontimer := newvalue;
\r
693 if assigned(timerwrapperinterface) then begin
\r
694 timerwrapperinterface.setontimer(wrappedtimer,newvalue);
\r
703 procedure tltimer.setenabled(newvalue : boolean);
\r
705 if newvalue <> fenabled then begin
\r
706 fenabled := newvalue;
\r
707 if assigned(timerwrapperinterface) then begin
\r
708 timerwrapperinterface.setenabled(wrappedtimer,newvalue);
\r
711 raise exception.create('non wrapper timers are not permitted on windows');
\r
719 procedure tltimer.setinterval(newvalue:integer);
\r
721 if newvalue <> finterval then begin
\r
722 finterval := newvalue;
\r
723 if assigned(timerwrapperinterface) then begin
\r
724 timerwrapperinterface.setinterval(wrappedtimer,newvalue);
\r
727 raise exception.create('non wrapper timers are not permitted on windows');
\r
739 constructor tltimer.create;
\r
741 inherited create(AOwner);
\r
742 if assigned(timerwrapperinterface) then begin
\r
743 wrappedtimer := timerwrapperinterface.createwrappedtimer;
\r
747 nexttimer := firsttimer;
\r
750 if assigned(nexttimer) then nexttimer.prevtimer := self;
\r
751 firsttimer := self;
\r
759 destructor tltimer.destroy;
\r
761 if assigned(timerwrapperinterface) then begin
\r
764 if prevtimer <> nil then begin
\r
765 prevtimer.nexttimer := nexttimer;
\r
767 firsttimer := nexttimer;
\r
769 if nexttimer <> nil then begin
\r
770 nexttimer.prevtimer := prevtimer;
\r
777 constructor tltask.create(ahandler:ttaskevent;aobj:tobject;awparam,alparam:longint);
\r
780 if assigned(onaddtask) then onaddtask(ahandler,aobj,awparam,alparam);
\r
781 handler := ahandler;
\r
785 {nexttask := firsttask;
\r
786 firsttask := self;}
\r
787 if assigned(lasttask) then begin
\r
788 lasttask.nexttask := self;
\r
793 //ahandler(wparam,lparam);
\r
796 procedure addtask(ahandler:ttaskevent;aobj:tobject;awparam,alparam:longint);
\r
799 tltask.create(ahandler,aobj,awparam,alparam);
\r
803 procedure prepsigpipe;{$ifndef ver1_0}inline;
\r
806 starthandlesignal(sigpipe);
\r
807 if not assigned(signalloopback) then begin
\r
808 signalloopback := tlloopback.create(nil);
\r
809 signalloopback.ondataAvailable := signalloopback.sinkdata;
\r
816 procedure processtasks;//inline;
\r
818 temptask : tltask ;
\r
822 if not assigned(currenttask) then begin
\r
823 currenttask := firsttask;
\r
827 while assigned(currenttask) do begin
\r
829 if assigned(currenttask.handler) then currenttask.handler(currenttask.wparam,currenttask.lparam);
\r
830 if assigned(currenttask) then begin
\r
831 temptask := currenttask;
\r
832 currenttask := currenttask.nexttask;
\r
835 //writeln('processed a task');
\r
843 procedure disconnecttasks(aobj:tobject);
\r
845 currenttasklocal : tltask ;
\r
848 for counter := 0 to 1 do begin
\r
849 if counter = 0 then begin
\r
850 currenttasklocal := firsttask; //main list of tasks
\r
852 currenttasklocal := currenttask; //needed in case called from a task
\r
854 // note i don't bother to sestroy the links here as that will happen when
\r
855 // the list of tasks is processed anyway
\r
856 while assigned(currenttasklocal) do begin
\r
857 if currenttasklocal.obj = aobj then begin
\r
858 currenttasklocal.obj := nil;
\r
859 currenttasklocal.handler := nil;
\r
861 currenttasklocal := currenttasklocal.nexttask;
\r
867 procedure processmessages;
\r
869 eventcore.processmessages;
\r
871 procedure messageloop;
\r
873 eventcore.messageloop;
\r
876 procedure exitmessageloop;
\r
878 eventcore.exitmessageloop;
\r
881 function tlasio.RealSend(Data : Pointer; Len : Integer) : Integer;
\r
883 result := myfdwrite(fdhandleout,data^,len);
\r
884 if (result > 0) and assigned(onsenddata) then onsenddata(self,result);
\r
885 eventcore.wmasterset(fdhandleout);
\r
888 procedure tlasio.myfdclose(fd : integer);
\r
892 function tlasio.myfdwrite(fd: LongInt;const buf;size: LongInt):LongInt;
\r
894 result := fdwrite(fd,buf,size);
\r
897 function tlasio.myfdread(fd: LongInt;var buf;size: LongInt):LongInt;
\r
899 result := fdread(fd,buf,size);
\r
912 signalloopback := nil;
\r