Skip to content

Commit

Permalink
fixed random GPF with HTTP/1.0 requests
Browse files Browse the repository at this point in the history
- the connection was released in the background thread before that the main accept() thread logged its pointer :)
  • Loading branch information
Arnaud Bouchez committed Jan 14, 2022
1 parent 8175d83 commit 335b2cb
Showing 1 changed file with 30 additions and 25 deletions.
55 changes: 30 additions & 25 deletions src/net/mormot.net.async.pas
Original file line number Diff line number Diff line change
Expand Up @@ -362,7 +362,7 @@ TAsyncConnectionsSockets = class(TPollAsyncSockets)
function Write(connection: TPollAsyncConnection;
data: pointer; datalen: integer; timeout: integer = 5000): boolean; override;
published
/// how many clients have been handled by the poll, from the beginning
/// how many connections have been handled by the poll, from the beginning
property Total: integer
read GetTotal;
end;
Expand Down Expand Up @@ -1024,6 +1024,9 @@ function TPollAsyncSockets.Start(connection: TPollAsyncConnection): boolean;
exit;
LockedInc32(@fProcessingRead);
try
{if fDebugLog <> nil then
DoLog('Start sock=% handle=%',
[pointer(connection.fSocket), connection.Handle]);}
// get sending buffer size from OS (if not already retrieved)
if fSendBufferSize = 0 then
{$ifdef OSWINDOWS}
Expand All @@ -1038,12 +1041,11 @@ function TPollAsyncSockets.Start(connection: TPollAsyncConnection): boolean;
// subscribe for incoming data (async for select/poll, immediate for epoll)
if Assigned(fOnStart) then
result := fOnStart(connection); // e.g. TAsyncConnections.ProcessClientStart
if not result then // if fRead.Subscribe() is not delayed in atpReadPending
// result=true here means that fRead.Subscribe() is delayed in atpReadPending
// warning: result=true may actually make connection.Free before it returns
if not result then
// let ProcessRead handle pseRead+pseError/pseClosed on this socket
result := SubscribeConnection(connection, pseRead);
// now, ProcessRead will handle pseRead+pseError/pseClosed on this socket
if fDebugLog <> nil then
DoLog('Start sock=% handle=%',
[pointer(connection.fSocket), connection.Handle]);
finally
LockedDec32(@fProcessingRead);
end;
Expand Down Expand Up @@ -1632,6 +1634,7 @@ procedure TAsyncConnectionsThread.Execute;
if fOwner.fClients.fRead.Count = 0 then
begin
// avoid void PollForPendingEvents/SleepStep loop
fEvent.ResetEvent;
fWaitForReadPending := true;
fEvent.WaitFor(INFINITE); // blocking until next accept()
start := 0;
Expand Down Expand Up @@ -1671,7 +1674,7 @@ procedure TAsyncConnectionsThread.Execute;
not Terminated do
fOwner.fClients.ProcessRead(notif);
// release atpReadPoll lock above
if fOwner.fThreadReadPoll.fWaitForReadPending then
//if fOwner.fThreadReadPoll.fWaitForReadPending then wrk 30% slower
fOwner.fThreadReadPoll.fEvent.SetEvent;
end;
end;
Expand Down Expand Up @@ -1775,7 +1778,7 @@ procedure TAsyncConnections.Shutdown;
if fClients <> nil then
begin
with fClients do
DoLog('Shutdown threads=% total=% reads=%/% writes=%/% count=%',
DoLog('Shutdown threads=% accept=% reads=%/% writes=%/% count=%',
[length(fThreads), Total, ReadCount, KB(ReadBytes),
WriteCount, KB(WriteBytes), fConnectionCount]);
fClients.Terminate(5000);
Expand Down Expand Up @@ -2451,11 +2454,10 @@ procedure TAsyncServer.Execute;
client: TNetSocket;
connection: TAsyncConnection;
res: TNetResult;
sin: TNetAddr;
ip: RawUtf8;
async: boolean;
start: Int64;
len: integer;
async: boolean;
sin: TNetAddr;
const
AW: array[boolean] of string[1] = ('W', '');
begin
Expand Down Expand Up @@ -2513,6 +2515,8 @@ procedure TAsyncServer.Execute;
(fClients.fRead.PendingCount > fMaxPending) then
begin
// map THttpAsyncServer.HttpQueueLength property value
DoLog(sllTrace, 'Execute: Accept connections=% pending=% overflow',
[fClients.fRead.Count, fClients.fRead.PendingCount], self);
client.ShutdownAndClose({rdwr=}false); // e.g. for load balancing
res := nrTooManyConnections;
end;
Expand All @@ -2530,23 +2534,24 @@ procedure TAsyncServer.Execute;
break;
// if we reached here, we have accepted a connection -> process
start := 0;
ip := sin.IP;
if not ConnectionCreate(client, ip, connection) then
client.ShutdownAndClose({rdwr=}false)
else if fClients.Start(connection) then
if ConnectionCreate(client, sin.IP, connection) then
begin
if acoVerboseLog in fOptions then
DoLog(sllTrace, 'Execute: Accept(%)=%',
[fServer.Port, connection], self);
if (not async) and
not fExecuteAcceptOnly then
// no log here, because already done in ConnectionNew and Start()
// may do connection.Free in atpReadPending background -> log before
if fClients.Start(connection) then
begin
fServer.Sock.MakeAsync; // share thread with Writes
async := true;
end;
if (not async) and
not fExecuteAcceptOnly then
begin
fServer.Sock.MakeAsync; // share thread with Writes
async := true;
end;
end
else if connection <> nil then // connection=nil for custom list
ConnectionDelete(connection);
end
else if connection <> nil then // connection=nil for custom list
ConnectionDelete(connection);
else
client.ShutdownAndClose({rdwr=}false)
until Terminated;
end
else
Expand Down

0 comments on commit 335b2cb

Please sign in to comment.