123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219 |
- {% lepolleventer.inc included by levents.pas }
- {$ifdef Linux}
- { TLEpollEventer }
- const
- BASE_SIZE = 100;
- // bug in fpc 2.0.4-
- EPOLL_CTL_ADD = 1;
- EPOLL_CTL_DEL = 2;
- EPOLL_CTL_MOD = 3;
-
- EPOLLIN = $01; { The associated file is available for read(2) operations. }
- EPOLLPRI = $02; { There is urgent data available for read(2) operations. }
- EPOLLOUT = $04; { The associated file is available for write(2) operations. }
- EPOLLERR = $08; { Error condition happened on the associated file descriptor. }
- EPOLLHUP = $10; { Hang up happened on the associated file descriptor. }
- EPOLLONESHOT = 1 shl 30;
- EPOLLET = 1 shl 31; { Sets the Edge Triggered behaviour for the associated file descriptor. }
- constructor TLEpollEventer.Create;
- var
- lEvent: TEpollEvent;
- begin
- inherited Create;
- FFreeList := TFPObjectList.Create;
- Inflate;
- FTimeout := 0;
- FEpollFD := epoll_create(BASE_SIZE);
- FEpollReadFD := epoll_create(BASE_SIZE);
- FEpollMasterFD := epoll_create(2);
- if (FEPollFD < 0) or (FEpollReadFD < 0) or (FEpollMasterFD < 0) then
- raise Exception.Create('Unable to create epoll: ' + StrError(fpgeterrno));
- lEvent.events := EPOLLIN or EPOLLOUT or EPOLLPRI or EPOLLERR or EPOLLHUP or EPOLLET;
- lEvent.data.fd := FEpollFD;
- if epoll_ctl(FEpollMasterFD, EPOLL_CTL_ADD, FEpollFD, @lEvent) < 0 then
- raise Exception.Create('Unable to add FDs to master epoll FD: ' + StrError(fpGetErrno));
- lEvent.data.fd := FEpollReadFD;
- if epoll_ctl(FEpollMasterFD, EPOLL_CTL_ADD, FEpollReadFD, @lEvent) < 0 then
- raise Exception.Create('Unable to add FDs to master epoll FD: ' + StrError(fpGetErrno));
- end;
- destructor TLEpollEventer.Destroy;
- begin
- fpClose(FEpollFD);
- FFreeList.Free;
- inherited Destroy;
- end;
- function TLEpollEventer.GetTimeout: Integer;
- begin
- Result := FTimeout;
- end;
- procedure TLEpollEventer.SetTimeout(const Value: Integer);
- begin
- if Value >= 0 then
- FTimeout := Value
- else
- FTimeout := -1;
- end;
- procedure TLEpollEventer.HandleIgnoreRead(aHandle: TLHandle);
- var
- lEvent: TEpollEvent;
- begin
- lEvent.data.ptr := aHandle;
- lEvent.events := EPOLLIN or EPOLLPRI or EPOLLHUP;
- if not aHandle.IgnoreRead then begin
- if epoll_ctl(FEpollReadFD, EPOLL_CTL_ADD, aHandle.Handle, @lEvent) < 0 then
- Bail('Error modifying handle for reads', LSocketError);
- end else begin
- if epoll_ctl(FEpollReadFD, EPOLL_CTL_DEL, aHandle.Handle, @lEvent) < 0 then
- Bail('Error modifying handle for reads', LSocketError);
- end;
- end;
- procedure TLEpollEventer.Inflate;
- var
- OldLength: Integer;
- begin
- OldLength := Length(FEvents);
- if OldLength > 1 then
- SetLength(FEvents, Sqr(OldLength))
- else
- SetLength(FEvents, BASE_SIZE);
- SetLength(FEventsRead, Length(FEvents));
- end;
- function TLEpollEventer.AddHandle(aHandle: TLHandle): Boolean;
- var
- lEvent: TEpollEvent;
- begin
- Result := inherited AddHandle(aHandle);
- if Result then begin
- Result := False;
- lEvent.events := EPOLLET or EPOLLOUT or EPOLLERR;
- lEvent.data.ptr := aHandle;
- if epoll_ctl(FEpollFD, EPOLL_CTL_ADD, aHandle.FHandle, @lEvent) < 0 then
- Bail('Error adding handle to epoll', LSocketError);
- lEvent.events := EPOLLIN or EPOLLPRI or EPOLLHUP;
- if not aHandle.IgnoreRead then begin
- if epoll_ctl(FEpollReadFD, EPOLL_CTL_ADD, aHandle.FHandle, @lEvent) < 0 then
- Bail('Error adding handle to epoll', LSocketError);
- end;
- if FCount > High(FEvents) then
- Inflate;
- end;
- end;
- function Max(const a, b: Integer): Integer; inline;
- begin
- if a > b then
- Result := a
- else
- Result := b;
- end;
- function TLEpollEventer.CallAction: Boolean;
- var
- i, MasterChanges, Changes, ReadChanges: Integer;
- Temp, TempRead: TLHandle;
- MasterEvents: array[0..1] of TEpollEvent;
- begin
- Result := False;
- if FInLoop then
- Exit;
-
- Changes := 0;
- ReadChanges := 0;
- MasterChanges := epoll_wait(FEpollMasterFD, @MasterEvents[0], 2, FTimeout);
- if MasterChanges > 0 then begin
- for i := 0 to MasterChanges - 1 do
- if MasterEvents[i].Data.fd = FEpollFD then
- Changes := epoll_wait(FEpollFD, @FEvents[0], FCount, 0)
- else
- ReadChanges := epoll_wait(FEpollReadFD, @FEventsRead[0], FCount, 0);
- if (Changes < 0) or (ReadChanges < 0) then
- Bail('Error on epoll', LSocketError)
- else
- Result := Changes + ReadChanges > 0;
-
- if Result then begin
- FInLoop := True;
- for i := 0 to Max(Changes, ReadChanges) - 1 do begin
- Temp := nil;
- if i < Changes then begin
- Temp := TLHandle(FEvents[i].data.ptr);
- if (not Temp.FDispose)
- and (FEvents[i].events and EPOLLOUT = EPOLLOUT) then
- if Assigned(Temp.FOnWrite) and not Temp.IgnoreWrite then
- Temp.FOnWrite(Temp);
- if Temp.FDispose then
- AddForFree(Temp);
- end; // writes
- if i < ReadChanges then begin
- TempRead := TLHandle(FEventsRead[i].data.ptr);
- if (not TempRead.FDispose)
- and ((FEventsRead[i].events and EPOLLIN = EPOLLIN)
- or (FEventsRead[i].events and EPOLLHUP = EPOLLHUP)
- or (FEventsRead[i].events and EPOLLPRI = EPOLLPRI)) then
- if Assigned(TempRead.FOnRead) and not TempRead.IgnoreRead then
- TempRead.FOnRead(TempRead);
- if TempRead.FDispose then
- AddForFree(TempRead);
- end; // reads
-
- if i < Changes then begin
- if not Assigned(Temp) then
- Temp := TLHandle(FEvents[i].data.ptr);
- if (not Temp.FDispose)
- and (FEvents[i].events and EPOLLERR = EPOLLERR) then
- if Assigned(Temp.FOnError) and not Temp.IgnoreError then
- Temp.FOnError(Temp, 'Handle error' + LStrError(LSocketError));
- if Temp.FDispose then
- AddForFree(Temp);
- end; // errors
- end;
- FInLoop := False;
- if Assigned(FFreeRoot) then
- FreeHandles;
- end;
- end else if MasterChanges < 0 then
- Bail('Error on epoll', LSocketError);
- end;
- function BestEventerClass: TLEventerClass;
- var
- tmp: THandle;
- begin
- {$IFNDEF FORCE_SELECT}
- try
- tmp := epoll_create(1);
- if tmp >= 0 then begin
- FpClose(tmp);
- Result := TLEpollEventer;
- end else
- Result := TLSelectEventer;
- except
- Result := TLSelectEventer;
- end;
- {$ELSE}
- Result := TLSelectEventer;
- {$ENDIF}
- end;
- {$endif} // Linux
|