Delphi SuperTCP server stuck in 100% CPU loop

RemObjects SDK v10.0.0.1613 with Delphi 12.3

Server is TROSuperTCPServer, clients are TROSuperTcpChannel.

I was running my server standalone EXE via the Delphi IDE and connecting to it with mobile clients when I noticed the clients were freezing at startup and reporting they could not obtain a connection.

Looking at Task Manager on the server machine I saw that the RO standalone EXE server was consuming a full CPU core and was presumably not responding to requests from the clients.

The server was running under the IDE at the time and I was able to pause it in the debugger and then identify the offending thread by freezing threads one at a time and seeing what the impact was in Task Manager. After some stepping through the offending thread to identify the issue I took a screenshot of the debugger which appears to identify the problem nicely.

If you look at the debugger screenshot, the while loop in uROSocketUtils.RO_SendBuffer appears to be the cause. Note that l_total variable has a very suspicious value and keeps getting lower by a few more thousand each time I let it run for another few seconds.

At the time this screenshot was taken there were no longer any client applications running. I am unsure whether this state was triggered by a client connecting to the server or not.

This system is not yet in production so I do not have good information on the frequency of how often this may occur. While developing I have noticed high CPU usage from this standalone EXE server every so often (with no clients connected) but it usually lasts for no more than 10 seconds.

Hi,

this is known issue and was already fixed in the latest builds.

update uROSocketUtils.pas as

function RO_SendBuffer(aSocket: THandle; Buffer: Pointer; Len: Integer): Integer;
var
  l_total: Integer;
  l_bytesLeft: Integer;
  l_delta: Integer;
  l_retry: Boolean;
begin
  l_total := 0;
  l_bytesLeft := Len;
  while (l_total < Len) do begin
    if g_BufSize > l_bytesLeft then
      l_delta := l_bytesLeft
    else
      l_delta := g_BufSize;
    repeat
      l_retry := False;
      Result := RO_Send(aSocket, PByteArray(Buffer)^[l_total], l_delta, MSG_NOSIGNAL);
      if Result = SOCKET_ERROR then
        l_retry := RO_GetLastError = EWOULDBLOCK;
    until not l_retry;
    if Result = SOCKET_ERROR then Exit;
    Inc(l_total, Result);
    Dec(l_bytesLeft, Result);
  end;
  Result := l_total;
end;

P.S. You can launch install_DA.cmd (or install_RO.cmd) with admin rights for rebuilding .dcu and .bpl.
File is located in C:\Program Files (x86)\RemObjects Software\Build