[fpc-pascal] Re: WSAGetLastError returns 0 when it shouldn't but I cannot see why

Luca Olivetti luca at ventoso.org
Mon Mar 3 10:14:46 CET 2008


En/na Luca Olivetti ha escrit:
> En/na L ha escrit:
> =

>>> Found the problem using my brute force writeln('') skills. It is an =

>>> issue with freepascal's stack or something to do with buggy threads =

>>> methinks. As it is when you call lasterror within another procedure =

>>> with local variables.. they are corrupted or something.
>>>
>> Aha.. I changed the by Value parameter to a CONST parameter in the =

>> error procedure (Perror).. And this solves the issue..
>>
>> So something to do with calling by Value within a thread versus a =

>> const (pointer?).
> =

> This seriously worries me, since I use threads extensively, and I mostly =

> use call by value parameters.

I finally had time to test this (do you remember that dilber strip where =

he asks his PHB which one of the 3 projects he's juggling should be =

finished on schedule, and the PHB replies he should finish them all on =

schedule? well, I'm pretty much in the same situation now).
Changing my "procedure PError(msg:string)" to "procedure PError(const =

msg:string)" in TSocketThread.Execute in project2 also fixes the problem.
This smells like a bug somewhere in fpc/rtl, since I don't think it =

should make a difference.
Anyway, this gives me no clue on how to "fix" synapse.
Synapse does this:

function TBlockSocket.SockCheck(SockResult: Integer): Integer;
begin
   ResetLastError;
   if SockResult =3D integer(SOCKET_ERROR) then
   begin
     FLastError :=3D synsock.WSAGetLastError;
     FLastErrorDesc :=3D GetErrorDescEx;
   end;
   Result :=3D FLastError;
end;


then in a connect it wraps the connect call in SockCheck:

procedure TBlockSocket.Connect(IP, Port: string);
var
   Sin: TVarSin;
begin
   SetSin(Sin, IP, Port);
   if FLastError =3D 0 then
   begin
     if FSocket =3D INVALID_SOCKET then
       InternalCreateSocket(Sin);
     SockCheck(synsock.Connect(FSocket, Sin));
     if FLastError =3D 0 then
       GetSins;
     FBuffer :=3D '';
     FLastCR :=3D False;
     FLastLF :=3D False;
   end;
   ExceptCheck;
   DoStatus(HR_Connect, IP + ':' + Port);
end;


Changing

function TBlockSocket.SockCheck(SockResult: Integer): Integer;

to

function TBlockSocket.SockCheck(const SockResult: Integer): Integer;

does nothing.

Moreover, something really fishy is going on: look at the attached =

project4 (now using synapse).
First I try outside a thread, and it correctly reports error 10060, then =

inside a thread, where it reports 0, then again outside the thread (same =

procedure) and this time it reports 0!

What's going on?

Bye
-- =

Luca

-------------- next part --------------
program project4;

{$mode objfpc}{$H+}

uses
  blcksock, Classes;

type
  { TInlineSocketThread }

  TNotifyError =3D procedure (m:string;n:integer) of object;

  TSocketThread =3D class(TThread)
  private
    FAddress:string;
    FPort:string;
    FErrMessage:string;
    FErrNum:integer;
    FUseSynchronize:boolean;
    FFinished:boolean;
    FOnError:TNotifyError;
    procedure SyncProcError;
    procedure ErrMsg(m:string;n:integer);
  public
    constructor Create(Address, Port:string; UseSynchronize:boolean);
    destructor Destroy;override;
    procedure Execute;override;
    property OnError:TNotifyError read FOnError write FOnError;
    property Finished:boolean read FFinished;
  end;

{ TSocketThread }

procedure TSocketThread.SyncProcError;
begin
  if Assigned(FOnError) then FOnError(FErrMessage,FErrNum);
end;

procedure TSocketThread.ErrMsg(m: string;n:integer);
begin
  if not Assigned(FOnError) then exit;
  FErrMessage:=3Dm;
  FErrNum:=3Dn;
  if FUseSynchronize then Synchronize(@SyncProcError) else SyncProcError;
end;


constructor TSocketThread.Create(Address,Port:string; UseSynchronize: boole=
an);
begin
  FAddress:=3DAddress;
  FPort:=3DPort;
  FUseSynchronize:=3DUseSynchronize;
  inherited create(true); //create suspended
end;

destructor TSocketThread.Destroy;
begin
  terminate;
  while not FFinished do
      CheckSynchronize(100);
  inherited Destroy;
end;

procedure TSocketThread.Execute;
var s:TTCPBlockSocket;
    Connected:boolean;
  procedure PError(const msg:string);
  var e:integer;
  begin
    e:=3Ds.LastError;
    if Connected then s.CloseSocket;
    Connected:=3Dfalse;
    ErrMsg(msg,e);
  end;
begin
  Connected:=3Dfalse;
  S:=3DTTCPBlockSocket.create;
  S.Connect(FAddress,FPort);
  if S.LastError=3D0 then
  begin
    connected:=3Dtrue;
    ErrMsg('connected',0);
  end else
  begin
    Perror('connect');
  end;
  if Connected then
    S.CloseSocket;
  FFinished:=3DTrue;
end;

procedure SocketNoThread(FAddress,FPort:string);
var s:TTcpBlockSocket;
    Connected:boolean;
  procedure PError(msg:string);
  var e:integer;
  begin
    e:=3Ds.LastError;
    if Connected then s.CloseSocket;
    Connected:=3Dfalse;
    Writeln(msg,' ',e);
  end;
begin
  Connected:=3Dfalse;
  S:=3DTTCPBlockSocket.create;
  S.Connect(FAddress,FPort);
  if S.LastError=3D0 then
  begin
    writeln('connected');
  end else
  begin
    PError('connect');
  end;
  if Connected then S.CloseSocket;
end;

{ TTest }
type
TTest=3Dclass
  FSocketThread:TsocketThread;
  procedure SockError(m:string;n:integer);
  constructor Create;
  destructor Destroy;override;
end;

{ TTest }

procedure TTest.SockError(m: string;n:integer);
begin
  writeln(m,' ',n);
end;

constructor TTest.Create;
begin
  FSocketThread:=3DTSocketThread.Create('1.2.3.4','1000',true);
  FSocketThread.OnError:=3D at SockError;
  FSocketThread.Resume;
  writeln('Thread started');
end;

destructor TTest.Destroy;
begin
  FSocketThread.Free;
  inherited Destroy;
end;


var Test:TTest;
begin
   Writeln('Each try should report "connect 10060"');
   Writeln('First try, no thread');
   SocketNoThread('1.2.3.4','1000');
   Writeln('Second try, in thread');
   Test:=3DTTest.Create;
   while not Test.FSocketThread.Finished do CheckSynchronize(100);
   Writeln('thread finished');
   Writeln('Third try, no thread');
   SocketNoThread('1.2.3.4','1000');
end.



More information about the fpc-pascal mailing list