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,sockets,
\r
33 classes,pgtypes,bfifo,ltimevalstuff;
\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
43 packetbasesize is deprecated and should not be used anymore
\r
45 packetbasesize = 1432;
\r
46 receivebufsize=16384;
\r
49 absolutemaxs:integer=0;
\r
53 sigset= array[0..31] of longint;
\r
56 ESocketException = class(Exception);
\r
57 TBgExceptionEvent = procedure (Sender : TObject;
\r
59 var CanClose : Boolean) of object;
\r
61 // note : tsocketstate is defined in the same way as it is in François PIETTE's twsocket
\r
62 // however tlsocket currently only uses wsClosed wsConnecting wsconnected and wsListening
\r
63 TSocketState = (wsInvalidState,
\r
65 wsConnecting, wsConnected,
\r
66 wsAccepting, wsListening,
\r
69 TWSocketOption = (wsoNoReceiveLoop, wsoTcpNoDelay);
\r
70 TWSocketOptions = set of TWSocketOption;
\r
72 TSocketevent = procedure(Sender: TObject; Error: word) of object;
\r
73 //Tdataavailevent = procedure(data : string);
\r
74 TSendData = procedure (Sender: TObject; BytesSent: Integer) of object;
\r
76 tlcomponent = class(tcomponent)
\r
78 procedure releasetaskhandler(wparam,lparam:longint);
\r
80 procedure release; virtual;
\r
81 destructor destroy; override;
\r
84 tlasio = class(tlcomponent)
\r
86 state : tsocketstate ;
\r
87 ComponentOptions : TWSocketOptions;
\r
88 fdhandlein : Longint ; {file descriptor}
\r
89 fdhandleout : Longint ; {file descriptor}
\r
91 onsessionclosed : tsocketevent ;
\r
92 ondataAvailable : tsocketevent ;
\r
93 onsessionAvailable : tsocketevent ;
\r
95 onsessionconnected : tsocketevent ;
\r
96 onsenddata : tsenddata ;
\r
97 ondatasent : tsocketevent ;
\r
98 //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 datasentcalled:boolean;
\r
112 sendflushlasterror:integer;
\r
115 sendflushmaxwrite:integer;
\r
116 //how much to write to the socket internally in one go. higher values allow faster throughput especially if latency is high
\r
117 //but it also causes onsenddata to be called less often (typically once for every sendflushmaxwrite bytes)
\r
119 function receivestr:tbufferstring; virtual;
\r
122 procedure internalclose(error:word); virtual;
\r
123 constructor Create(AOwner: TComponent); override;
\r
125 destructor destroy; override;
\r
126 procedure fdcleanup;
\r
127 procedure HandleBackGroundException(E: Exception);
\r
128 procedure handlefdtrigger(readtrigger,writetrigger:boolean); virtual;
\r
129 procedure dup(invalue:longint);
\r
131 function sendflush : integer;
\r
132 procedure sendstr(const str : tbufferstring);virtual;
\r
133 procedure putstringinsendbuffer(const newstring : tbufferstring);
\r
134 function send(data:pointer;len:integer):integer;virtual;
\r
135 procedure putdatainsendbuffer(data:pointer;len:integer); virtual;
\r
136 procedure deletebuffereddata;
\r
138 //procedure messageloop;
\r
139 function Receive(Buf:Pointer;BufSize:integer):integer; virtual;
\r
140 procedure flush;virtual;
\r
141 procedure dodatasent(wparam,lparam:longint);
\r
142 procedure doreceiveloop(wparam,lparam:longint);
\r
143 procedure sinkdata(sender:tobject;error:word);
\r
145 procedure release; override; {test -beware}
\r
147 function RealSend(Data : Pointer; Len : Integer) : Integer; //added for bewarehttpd
\r
149 procedure myfdclose(fd : integer); virtual;{$ifdef mswindows}abstract;{$endif}
\r
150 function myfdwrite(fd: LongInt;const buf;size: LongInt):LongInt; virtual;{$ifdef mswindows}abstract;{$endif}
\r
151 function myfdread(fd: LongInt;var buf;size: LongInt):LongInt; virtual;{$ifdef mswindows}abstract;{$endif}
\r
153 procedure dupnowatch(invalue:longint);
\r
155 ttimerwrapperinterface=class(tlcomponent)
\r
157 function createwrappedtimer : tobject;virtual;abstract;
\r
158 // procedure setinitialevent(wrappedtimer : tobject;newvalue : boolean);virtual;abstract;
\r
159 procedure setontimer(wrappedtimer : tobject;newvalue:tnotifyevent);virtual;abstract;
\r
160 procedure setenabled(wrappedtimer : tobject;newvalue : boolean);virtual;abstract;
\r
161 procedure setinterval(wrappedtimer : tobject;newvalue : integer);virtual;abstract;
\r
165 timerwrapperinterface : ttimerwrapperinterface;
\r
167 tltimer=class(tlcomponent)
\r
171 wrappedtimer : tobject;
\r
174 // finitialevent : boolean ;
\r
175 fontimer : tnotifyevent ;
\r
176 fenabled : boolean ;
\r
177 finterval : integer ; {milliseconds, default 1000}
\r
178 {$ifndef mswindows}
\r
179 procedure resettimes;
\r
181 // procedure setinitialevent(newvalue : boolean);
\r
182 procedure setontimer(newvalue:tnotifyevent);
\r
183 procedure setenabled(newvalue : boolean);
\r
184 procedure setinterval(newvalue : integer);
\r
186 //making these public for now, this code should probably be restructured later though
\r
187 prevtimer : tltimer ;
\r
188 nexttimer : tltimer ;
\r
189 nextts : ttimeval ;
\r
191 constructor create(aowner:tcomponent);override;
\r
192 destructor destroy;override;
\r
193 // property initialevent : boolean read finitialevent write setinitialevent;
\r
194 property ontimer : tnotifyevent read fontimer write setontimer;
\r
195 property enabled : boolean read fenabled write setenabled;
\r
196 property interval : integer read finterval write setinterval;
\r
200 ttaskevent=procedure(wparam,lparam:longint) of object;
\r
202 tltask=class(tobject)
\r
204 handler : ttaskevent;
\r
209 constructor create(ahandler:ttaskevent;aobj:tobject;awparam,alparam:longint);
\r
216 procedure processmessages; virtual;abstract;
\r
217 procedure messageloop; virtual;abstract;
\r
218 procedure exitmessageloop; virtual;abstract;
\r
219 procedure setfdreverse(fd : integer;reverseto : tlasio);virtual;abstract;
\r
220 procedure rmasterset(fd : integer;islistensocket : boolean); virtual;abstract;
\r
221 procedure rmasterclr(fd: integer); virtual;abstract;
\r
222 procedure wmasterset(fd : integer); virtual;abstract;
\r
223 procedure wmasterclr(fd: integer); virtual;abstract;
\r
226 eventcore : teventcore;
\r
228 procedure processmessages;
\r
229 procedure messageloop;
\r
230 procedure exitmessageloop;
\r
233 firsttimer : tltimer ;
\r
234 firsttask , lasttask : tltask ;
\r
236 numread : integer ;
\r
237 mustrefreshfds : boolean ;
\r
238 { lcoretestcount:integer;}
\r
240 asinreleaseflag:boolean;
\r
243 procedure disconnecttasks(aobj:tobject);
\r
244 procedure addtask(ahandler:ttaskevent;aobj:tobject;awparam,alparam:longint);
\r
246 tonaddtask = procedure(ahandler:ttaskevent;aobj:tobject;awparam,alparam:longint);
\r
248 onaddtask : tonaddtask;
\r
251 procedure sleep(i:integer);
\r
253 procedure prepsigpipe;{$ifndef ver1_0}inline;{$endif}
\r
259 uses {sockets,}lloopback,lsignal;
\r
262 uses windows,winsock;
\r
264 {$ifndef mswindows}
\r
265 {$include unixstuff.inc}
\r
269 {!!! added sleep call -beware}
\r
270 procedure sleep(i:integer);
\r
278 tv.tv_sec := i div 1000;
\r
279 tv.tv_usec := (i mod 1000) * 1000;
\r
280 select(0,nil,nil,nil,@tv);
\r
285 destructor tlcomponent.destroy;
\r
287 disconnecttasks(self);
\r
291 procedure tlcomponent.releasetaskhandler(wparam,lparam:longint);
\r
297 procedure tlcomponent.release;
\r
299 addtask(releasetaskhandler,self,0,0);
\r
302 procedure tlasio.release;
\r
304 asinreleaseflag := true;
\r
308 procedure tlasio.doreceiveloop;
\r
310 if recvq.size = 0 then exit;
\r
311 if assigned(ondataavailable) then ondataavailable(self,0);
\r
312 if not (wsonoreceiveloop in componentoptions) then
\r
313 if recvq.size > 0 then tltask.create(self.doreceiveloop,self,0,0);
\r
316 function tlasio.receivestr;
\r
318 setlength(result,recvq.size);
\r
319 receive(@result[1],length(result));
\r
322 function tlasio.receive(Buf:Pointer;BufSize:integer):integer;
\r
328 if recvq.size < i then i := recvq.size;
\r
330 while (a < i) do begin
\r
331 b := recvq.get(p,i-a);
\r
333 inc(taddrint(buf),b);
\r
338 if wsonoreceiveloop in componentoptions then begin
\r
339 if recvq.size = 0 then eventcore.rmasterset(fdhandlein,false);
\r
343 constructor tlasio.create;
\r
345 inherited create(AOwner);
\r
346 if not assigned(eventcore) then raise exception.create('no event core');
\r
347 sendq := tfifo.create;
\r
348 recvq := tfifo.create;
\r
352 sendflushmaxwrite := 16384;
\r
355 destructor tlasio.destroy;
\r
357 destroying := true;
\r
358 if state <> wsclosed then close;
\r
364 procedure tlasio.close;
\r
369 procedure tlasio.abort;
\r
374 procedure tlasio.fdcleanup;
\r
376 if fdhandlein <> -1 then begin
\r
377 eventcore.rmasterclr(fdhandlein); //fd_clr(fdhandlein,fdsrmaster)
\r
379 if fdhandleout <> -1 then begin
\r
380 eventcore.wmasterclr(fdhandleout);//fd_clr(fdhandleout,fdswmaster)
\r
382 if fdhandlein=fdhandleout then begin
\r
383 if fdhandlein <> -1 then begin
\r
384 myfdclose(fdhandlein);
\r
387 if fdhandlein <> -1 then begin
\r
388 myfdclose(fdhandlein);
\r
390 if fdhandleout <> -1 then begin
\r
391 myfdclose(fdhandleout);
\r
398 procedure tlasio.internalclose(error:word);
\r
400 if (state<>wsclosed) and (state<>wsinvalidstate) then begin
\r
401 // -2 is a special indication that we should just exist silently
\r
402 // (used for connect failure handling when socket creation fails)
\r
403 if (fdhandlein = -2) and (fdhandleout = -2) then exit;
\r
404 if (fdhandlein < 0) or (fdhandleout < 0) then raise exception.create('internalclose called with invalid fd handles');
\r
405 eventcore.rmasterclr(fdhandlein);//fd_clr(fdhandlein,fdsrmaster);
\r
406 eventcore.wmasterclr(fdhandleout);//fd_clr(fdhandleout,fdswmaster);
\r
408 if closehandles then begin
\r
409 {$ifndef mswindows}
\r
410 //anyone remember why this is here? --plugwash
\r
411 fcntl(fdhandlein,F_SETFL,0);
\r
413 myfdclose(fdhandlein);
\r
414 if fdhandleout <> fdhandlein then begin
\r
415 {$ifndef mswindows}
\r
416 fcntl(fdhandleout,F_SETFL,0);
\r
418 myfdclose(fdhandleout);
\r
420 eventcore.setfdreverse(fdhandlein,nil);
\r
421 eventcore.setfdreverse(fdhandleout,nil);
\r
428 if assigned(onsessionclosed) then if not destroying then onsessionclosed(self,error);
\r
430 if assigned(sendq) then sendq.del(maxlongint);
\r
434 {* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
\r
435 { All exceptions *MUST* be handled. If an exception is not handled, the }
\r
436 { application will most likely be shut down ! }
\r
437 procedure tlasio.HandleBackGroundException(E: Exception);
\r
439 CanAbort : Boolean;
\r
442 { First call the error event handler, if any }
\r
443 if Assigned(OnBgException) then begin
\r
445 OnBgException(Self, E, CanAbort);
\r
449 { Then abort the socket }
\r
450 if CanAbort then begin
\r
458 procedure tlasio.sendstr(const str : tbufferstring);
\r
460 putstringinsendbuffer(str);
\r
464 procedure tlasio.putstringinsendbuffer(const newstring : tbufferstring);
\r
466 if newstring <> '' then putdatainsendbuffer(@newstring[1],length(newstring));
\r
469 function tlasio.send(data:pointer;len:integer):integer;
\r
471 if state <> wsconnected then begin
\r
475 if len < 0 then len := 0;
\r
477 putdatainsendbuffer(data,len);
\r
482 procedure tlasio.putdatainsendbuffer(data:pointer;len:integer);
\r
484 sendq.add(data,len);
\r
487 function tlasio.sendflush : integer;
\r
491 // fdstestr : fdset;
\r
492 // fdstestw : fdset;
\r
494 if state <> wsconnected then begin
\r
498 datasentcalled := false;
\r
500 lensent := sendflushmaxwrite;
\r
501 if (lensent <= 0) then lensent := sendq.size;
\r
503 lensent := sendq.get(data,lensent);
\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
509 if (result = -1) then sendflushlasterror := getlasterror else sendflushlasterror := 0;
\r
512 //sendq := copy(sendq,lensent+1,length(sendq)-lensent);
\r
513 sendq.del(lensent);
\r
515 //fd_clr(fdhandleout,fdsw); // this prevents the socket being closed by a write
\r
516 // that sends nothing because a previous socket has
\r
517 // slready flushed this socket when the message loop
\r
519 // if sendq.size > 0 then begin
\r
520 eventcore.wmasterset(fdhandleout);//fd_set(fdhandleout,fdswmaster);
\r
522 // wmasterclr(fdhandleout);//fd_clr(fdhandleout,fdswmaster);
\r
524 if result > 0 then begin
\r
525 if assigned(onsenddata) then onsenddata(self,result);
\r
526 // if sendq.size=0 then if assigned(ondatasent) then begin
\r
527 // tltask.create(self.dodatasent,self,0,0);
\r
528 // //begin test code
\r
529 // fd_zero(fdstestr);
\r
530 // fd_zero(fdstestw);
\r
531 // fd_set(fdhandlein,fdstestr);
\r
532 // fd_set(fdhandleout,fdstestw);
\r
533 // select(maxs,@fdstestr,@fdstestw,nil,0);
\r
534 // writeln(fd_isset(fdhandlein,fdstestr),' ',fd_isset(fdhandleout,fdstestw));
\r
538 writtenthiscycle := true;
\r
542 procedure tlasio.dupnowatch(invalue:longint);
\r
544 { debugout('invalue='+inttostr(invalue));}
\r
546 if state<> wsclosed then close;
\r
547 fdhandlein := invalue;
\r
548 fdhandleout := invalue;
\r
549 eventcore.setfdreverse(fdhandlein,self);
\r
550 {$ifndef mswindows}
\r
551 fcntl(fdhandlein,F_SETFL,OPEN_NONBLOCK);
\r
553 state := wsconnected;
\r
558 procedure tlasio.dup(invalue:longint);
\r
560 dupnowatch(invalue);
\r
561 eventcore.rmasterset(fdhandlein,false);//fd_set(fdhandlein,fdsrmaster);
\r
562 eventcore.wmasterclr(fdhandleout);//fd_clr(fdhandleout,fdswmaster);
\r
566 procedure tlasio.handlefdtrigger(readtrigger,writetrigger:boolean);
\r
568 sendflushresult : integer;
\r
569 tempbuf:array[0..receivebufsize-1] of byte;
\r
572 if (state=wsconnected) and writetrigger then begin
\r
573 //writeln('write trigger');
\r
575 if (sendq.size >0) then begin
\r
577 sendflushresult := sendflush;
\r
578 if (sendflushresult <= 0) and (not writtenthiscycle) then begin
\r
579 if sendflushresult=0 then begin // linuxerror := 0;
\r
584 if sendflushlasterror=WSAEWOULDBLOCK then begin
\r
585 //the asynchronous nature of windows messages means we sometimes
\r
586 //get here with the buffer full
\r
587 //so do nothing in that case
\r
591 internalclose({$ifdef mswindows}sendflushlasterror{$else}linuxerror{$endif});
\r
597 //everything is sent fire off ondatasent event
\r
598 if fdhandleout >= 0 then eventcore.wmasterclr(fdhandleout);//fd_clr(fdhandleout,fdswmaster);
\r
599 if assigned(ondatasent) then begin
\r
600 if not datasentcalled then begin
\r
601 tltask.create(self.dodatasent,self,0,0);
\r
602 datasentcalled := true;
\r
607 if assigned(onfdwrite) then onfdwrite(self,0);
\r
609 writtenthiscycle := false;
\r
610 if (state =wsconnected) and readtrigger then begin
\r
611 if recvq.size=0 then begin
\r
613 if (a <= 0) or (a > sizeof(tempbuf)) then a := sizeof(tempbuf);
\r
614 numread := myfdread(fdhandlein,tempbuf,a);
\r
615 if (numread=0) and (not mustrefreshfds) then begin
\r
616 {if i remember correctly numread=0 is caused by eof
\r
617 if this isn't dealt with then you get a cpu eating infinite loop
\r
618 however if onsessionconnected has called processmessages that could
\r
619 cause us to drop to here with an empty recvq and nothing left to read
\r
620 and we don't want that to cause the socket to close}
\r
623 end else if (numread=-1) then begin
\r
625 //sometimes on windows we get stale messages due to the inherent delays
\r
626 //in the windows message queue
\r
627 if WSAGetLastError = wsaewouldblock then begin
\r
633 internalclose({$ifdef mswindows}wsagetlasterror{$else}linuxerror{$endif});
\r
635 end else if numread > 0 then recvq.add(@tempbuf,numread);
\r
638 if recvq.size > 0 then begin
\r
639 if wsonoreceiveloop in componentoptions then eventcore.rmasterclr(fdhandlein); //fd_clr(fdhandlein,fdsrmaster);
\r
640 if assigned(ondataavailable) then ondataAvailable(self,0);
\r
641 if not (wsonoreceiveloop in componentoptions) then if recvq.size > 0 then
\r
642 tltask.create(self.doreceiveloop,self,0,0);
\r
644 //until (numread = 0) or (currentsocket.state<>wsconnected);
\r
645 { debugout('inner loop complete');}
\r
649 procedure tlasio.flush;
\r
651 type fdset = tfdset;
\r
657 fd_set(fdhandleout,fds);
\r
658 while sendq.size>0 do begin
\r
659 select(fdhandleout+1,nil,@fds,nil,nil);
\r
660 if sendflush <= 0 then exit;
\r
664 procedure tlasio.dodatasent(wparam,lparam:longint);
\r
666 if assigned(ondatasent) then ondatasent(self,lparam);
\r
669 procedure tlasio.deletebuffereddata;
\r
671 sendq.del(maxlongint);
\r
674 procedure tlasio.sinkdata(sender:tobject;error:word);
\r
676 tlasio(sender).recvq.del(maxlongint);
\r
679 {$ifndef mswindows}
\r
680 procedure tltimer.resettimes;
\r
682 gettimemonotonic(nextts);
\r
683 {if not initialevent then} tv_add(nextts,interval);
\r
687 {procedure tltimer.setinitialevent(newvalue : boolean);
\r
689 if newvalue <> finitialevent then begin
\r
690 finitialevent := newvalue;
\r
691 if assigned(timerwrapperinterface) then begin
\r
692 timerwrapperinterface.setinitialevent(wrappedtimer,newvalue);
\r
699 procedure tltimer.setontimer(newvalue:tnotifyevent);
\r
701 if @newvalue <> @fontimer then begin
\r
702 fontimer := newvalue;
\r
703 if assigned(timerwrapperinterface) then begin
\r
704 timerwrapperinterface.setontimer(wrappedtimer,newvalue);
\r
713 procedure tltimer.setenabled(newvalue : boolean);
\r
715 if newvalue <> fenabled then begin
\r
716 fenabled := newvalue;
\r
717 if assigned(timerwrapperinterface) then begin
\r
718 timerwrapperinterface.setenabled(wrappedtimer,newvalue);
\r
721 raise exception.create('non wrapper timers are not permitted on windows');
\r
729 procedure tltimer.setinterval(newvalue:integer);
\r
731 if newvalue <> finterval then begin
\r
732 finterval := newvalue;
\r
733 if assigned(timerwrapperinterface) then begin
\r
734 timerwrapperinterface.setinterval(wrappedtimer,newvalue);
\r
737 raise exception.create('non wrapper timers are not permitted on windows');
\r
749 constructor tltimer.create;
\r
751 inherited create(AOwner);
\r
752 if assigned(timerwrapperinterface) then begin
\r
753 wrappedtimer := timerwrapperinterface.createwrappedtimer;
\r
757 nexttimer := firsttimer;
\r
760 if assigned(nexttimer) then nexttimer.prevtimer := self;
\r
761 firsttimer := self;
\r
767 destructor tltimer.destroy;
\r
769 if assigned(timerwrapperinterface) then begin
\r
772 if prevtimer <> nil then begin
\r
773 prevtimer.nexttimer := nexttimer;
\r
775 firsttimer := nexttimer;
\r
777 if nexttimer <> nil then begin
\r
778 nexttimer.prevtimer := prevtimer;
\r
785 constructor tltask.create(ahandler:ttaskevent;aobj:tobject;awparam,alparam:longint);
\r
788 if assigned(onaddtask) then onaddtask(ahandler,aobj,awparam,alparam);
\r
789 handler := ahandler;
\r
793 {nexttask := firsttask;
\r
794 firsttask := self;}
\r
795 if assigned(lasttask) then begin
\r
796 lasttask.nexttask := self;
\r
801 //ahandler(wparam,lparam);
\r
804 procedure addtask(ahandler:ttaskevent;aobj:tobject;awparam,alparam:longint);
\r
807 tltask.create(ahandler,aobj,awparam,alparam);
\r
811 procedure prepsigpipe;{$ifndef ver1_0}inline;
\r
814 starthandlesignal(sigpipe);
\r
815 if not assigned(signalloopback) then begin
\r
816 signalloopback := tlloopback.create(nil);
\r
817 signalloopback.ondataAvailable := signalloopback.sinkdata;
\r
824 procedure processtasks;//inline;
\r
826 currenttask:tltask;
\r
829 while assigned(firsttask) do begin
\r
830 currenttask := firsttask;
\r
831 firsttask := firsttask.nexttask;
\r
832 if not assigned(firsttask) then lasttask := nil;
\r
834 if assigned(currenttask.handler) then currenttask.handler(currenttask.wparam,currenttask.lparam);
\r
837 currenttask := nil;
\r
843 procedure disconnecttasks(aobj:tobject);
\r
845 currenttasklocal : tltask ;
\r
848 currenttasklocal := firsttask; //main list of tasks
\r
850 // note i don't bother to destroy the links here as that will happen when
\r
851 // the list of tasks is processed anyway
\r
852 while assigned(currenttasklocal) do begin
\r
853 if currenttasklocal.obj = aobj then begin
\r
854 currenttasklocal.obj := nil;
\r
855 currenttasklocal.handler := nil;
\r
857 currenttasklocal := currenttasklocal.nexttask;
\r
862 procedure processmessages;
\r
864 eventcore.processmessages;
\r
866 procedure messageloop;
\r
868 eventcore.messageloop;
\r
871 procedure exitmessageloop;
\r
873 eventcore.exitmessageloop;
\r
876 function tlasio.RealSend(Data : Pointer; Len : Integer) : Integer;
\r
878 result := myfdwrite(fdhandleout,data^,len);
\r
879 if (result > 0) and assigned(onsenddata) then onsenddata(self,result);
\r
880 eventcore.wmasterset(fdhandleout);
\r
882 {$ifndef mswindows}
\r
883 procedure tlasio.myfdclose(fd : integer);
\r
887 function tlasio.myfdwrite(fd: LongInt;const buf;size: LongInt):LongInt;
\r
889 result := fdwrite(fd,buf,size);
\r
892 function tlasio.myfdread(fd: LongInt;var buf;size: LongInt):LongInt;
\r
894 result := fdread(fd,buf,size);
\r
906 signalloopback := nil;
\r