Watch, Follow, &
Connect with Us

Please visit our new home
community.embarcadero.com.


Welcome, Guest
Guest Settings
Help

Thread: Indy 10 stoping TIdTCPServer freezes the App on iOS


This question is answered.


Permlink Replies: 17 - Last Post: Dec 9, 2014 11:11 AM Last Post By: Remy Lebeau (Te...
Pierre-François...

Posts: 13
Registered: 10/26/12
Indy 10 stoping TIdTCPServer freezes the App on iOS  
Click to report abuse...   Click to reply to this thread Reply
  Posted: Dec 2, 2014 3:13 AM
Stoping the TIdTCPServer by setting it's Active property to false freezes the App when run on iOS (8.1.1), thus, even if no client connected.

See the following simple code just starting and stopping a TIdTCPServer. (Compiled with Indy 10 from Delphi XE6)

unit MainUnit;
 
interface
 
uses
  System.SysUtils, System.Types, System.UITypes, System.Classes, System.Variants,
  FMX.Types, FMX.Controls, FMX.Forms, FMX.Graphics, FMX.Dialogs, IdContext,
  FMX.StdCtrls, FMX.Layouts, FMX.Memo, IdBaseComponent, IdComponent,
  IdCustomTCPServer, IdTCPServer, IdStack;
 
const
  C_PORT = 6000;
 
type
  TMainForm = class(TForm)
    IdTCPServer1: TIdTCPServer;
    Switch1: TSwitch;
    Memo1: TMemo;
    Label1: TLabel;
    procedure IdTCPServer1Execute(AContext: TIdContext);
    procedure IdTCPServer1Exception(AContext: TIdContext;
      AException: Exception);
    procedure Switch1Switch(Sender: TObject);
  private
    { Private declarations }
  public
    { Public declarations }
  end;
 
var
  MainForm: TMainForm;
 
implementation
 
{$R *.fmx}
 
procedure TMainForm.IdTCPServer1Exception(AContext: TIdContext;
  AException: Exception);
begin
  memo1.Lines.Add('TMainForm.IdTCPServer1Exception');
end;
 
procedure TMainForm.IdTCPServer1Execute(AContext: TIdContext);
var
  LLine: String;
begin
  LLine := AContext.Connection.IOHandler.ReadLn;
  AContext.Connection.IOHandler.WriteLn('OK');
end;
 
procedure TMainForm.Switch1Switch(Sender: TObject);
var
  LLine, IP: string;
begin
  if Switch1.IsChecked then begin
    IP := GStack.LocalAddress;
    IdTCPServer1.Bindings.Add.IP := IP;
    IdTCPServer1.Bindings.Add.Port := C_PORT;
    memo1.Lines.Add('Starting Server bind on IP='+IP+' on port #'+ IntToStr(C_PORT));
    IdTCPServer1.Active := True;
  end
  else begin
    memo1.Lines.Add('Stopping Server...');
    Application.ProcessMessages;
    IdTCPServer1.Active := False;   // Freezes the App on iOS !
    memo1.Lines.Add('Done.');
  end;
end;
 
end.


Note that this code runs correctly on Windows. I did'nt tried to run it on other iOS versions nor on Android.

It seems it's an internal deadlock, but what am I doing wrong ???

Any help ? I absolutely need to start and stop my TCP server on iOS. Thanks.
Remy Lebeau (Te...


Posts: 9,447
Registered: 12/23/01
Re: Indy 10 stoping TIdTCPServer freezes the App on iOS
Helpful
Click to report abuse...   Click to reply to this thread Reply
  Posted: Dec 2, 2014 12:18 PM   in response to: Pierre-François... in response to: Pierre-François...
Pierre-François wrote:

Stoping the TIdTCPServer by setting it's Active property to false
freezes the App when run on iOS (8.1.1), thus, even if no client
connected.

TIdTCPServer is a multi-threaded component, its events are triggered in the
context of worker threads. I problem I see is that are directly accessing
a UI control in the OnException event. That is not thread-safe, on any platform.
You MUST synchronize with the main UI thread, such as by using Indy's TIdSync
or TIdNotify classes, or the RTL's TThread.Synchronize() or TThread.Queue()
methods, or another inter-thread sync mechanism of your choosing. However,
the TThread sync methods (which the Indy classes are based on) were broken
in **every version** of FireMonkey prior to XE7, when it was finally fixed:

TThread.Synchronize() and TThread.Queue() do not work correctly in FireMonkey
http://qc.embarcadero.com/wc/qcmain.aspx?d=123579

Also, the GStack.LocalAddress property is not thread-safe, so you should
use the GStack.AddLocalAddressesToList() or GStack.GetLocalAddressList()
method instead. Or, simply set your binding IP to a blank string, then the
server will bind to all available local IPs.

BTW, this code is wrong:

IdTCPServer1.Bindings.Add.IP := IP;
IdTCPServer1.Bindings.Add.Port := C_PORT;


You are creating 2 separate bindings - one bound to the IP on the server's
DefaultPort, and the other bound to all local IPs on C_PORT. You need to
create 1 binding instead:

with IdTCPServer1.Bindings.Add do
begin
  IP := GStack.LocalAddress; // or just ''
  Port := C_PORT;
end;


Or:

IP := GStack.LocalAddress; // or just ''
IdTCPServer1.Bindings.Add.SetBinding(IP, C_PORT, Id_IPv4);


IdTCPServer1.Active := False; // Freezes the App on iOS !

I don't recall if XE6 suffered from this or not, but Indy did have some ARC-related
bugs when support for iOS and Android was first being added to Indy. Those
were eventually fixed. You might want to consider upgrading to the latest
Indy SVN snapshot and see if you are still having the problem.

--
Remy Lebeau (TeamB)
Pierre-François...

Posts: 13
Registered: 10/26/12
Re: Indy 10 stoping TIdTCPServer freezes the App on iOS  
Click to report abuse...   Click to reply to this thread Reply
  Posted: Dec 3, 2014 12:30 AM   in response to: Remy Lebeau (Te... in response to: Remy Lebeau (Te...
Remy Lebeau (TeamB) wrote:
[...] However,
the TThread sync methods (which the Indy classes are based on) were broken
in **every version** of FireMonkey prior to XE7, when it was finally fixed:

TThread.Synchronize() and TThread.Queue() do not work correctly in FireMonkey
http://qc.embarcadero.com/wc/qcmain.aspx?d=123579
Do you mean I mandatory must upgrade my Delphi XE6 to XE7 to solve this issue ?

I fixed my sample test code according to your latest answer and I installed the latest Indy10 SVN Snapshot but the freezing on IdTCPServer1.Active := false remains.

unit MainUnit;
 
interface
 
uses
  System.SysUtils, System.Types, System.UITypes, System.Classes, System.Variants,
  FMX.Types, FMX.Controls, FMX.Forms, FMX.Graphics, FMX.Dialogs, IdContext,
  FMX.StdCtrls, FMX.Layouts, FMX.Memo, IdBaseComponent, IdComponent,
  IdCustomTCPServer, IdTCPServer, IdStack, IdSync;
 
const
  C_PORT = 6000;
 
type
  TMainForm = class(TForm)
    IdTCPServer1: TIdTCPServer;
    Switch1: TSwitch;
    Memo1: TMemo;
    Label1: TLabel;
    procedure IdTCPServer1Execute(AContext: TIdContext);
    procedure IdTCPServer1Exception(AContext: TIdContext;
      AException: Exception);
    procedure Switch1Switch(Sender: TObject);
  private
    { Private declarations }
    procedure LogException;
    // Finds the Local IP address corresponding to the LAN connection:
    function GetLocalIPAddress: string;
 
  public
    { Public declarations }
  end;
 
var
  MainForm: TMainForm;
 
implementation
 
{$R *.fmx}
 
procedure TMainForm.LogException;
begin
  memo1.Lines.Add('TMainForm.IdTCPServer1Exception');
end;
 
function TMainForm.GetLocalIPAddress: string;
var
  IPs: TStringList;
  I: Integer;
  Err: Boolean;
begin
  IPs := TStringList.Create;
  Result := '';
  try
    GStack.AddLocalAddressesToList(IPs);
    for I := 0 to IPs.Count-1 do
    begin
      if Pos('192.168',IPs[I]) = 1 then begin  // Select LAN IP
         Result := IPs[I];
         Break;
      end;
    end;
  finally
    FreeAndNil(IPs);
  end;
end;
 
procedure TMainForm.IdTCPServer1Exception(AContext: TIdContext;
  AException: Exception);
begin
  TIdNotify.NotifyMethod( LogException );
end;
 
procedure TMainForm.IdTCPServer1Execute(AContext: TIdContext);
var
  LLine: String;
begin
  LLine := AContext.Connection.IOHandler.ReadLn;
  AContext.Connection.IOHandler.WriteLn('OK');
end;
 
procedure TMainForm.Switch1Switch(Sender: TObject);
var
  LLine, LocIP: string;
begin
  if Switch1.IsChecked then begin
    LocIP := GetLocalIPAddress;
    with IdTCPServer1.Bindings.Add do begin
      IP := LocIP;
      Port := C_PORT;
    end;
    memo1.Lines.Add('Starting Server bind on IP='+LocIP+' on port #'+ IntToStr(C_PORT));
    IdTCPServer1.Active := True;
  end
  else begin
    memo1.Lines.Add('Stopping Server...');
    Application.ProcessMessages;
    IdTCPServer1.Active := False;   // Freezes the App on iOS !
    memo1.Lines.Add('Done.');
  end;
end;
 
end.


Just a basic question about synchronizing with TIdNotify.NotifyMethod:
How to synchronize a method requiring parameters ? (Suppose I want to pass the AException and/or AContext parameter to my LogException method)

Thank you again for your help.
Remy Lebeau (Te...


Posts: 9,447
Registered: 12/23/01
Re: Indy 10 stoping TIdTCPServer freezes the App on iOS
Helpful
Click to report abuse...   Click to reply to this thread Reply
  Posted: Dec 3, 2014 11:46 AM   in response to: Pierre-François... in response to: Pierre-François...
Pierre-François wrote:

Do you mean I mandatory must upgrade my Delphi XE6 to XE7 to solve
this issue ?

If you want to use TThread.Synchronize(), TThread.Queue(), TIdSync, or TIdNotify
in a FireMonkey project (they work fine in VCL), there is a workaround provided
in the QC ticket:

Until Embarcadero fixes this, a workaround would be to manually call CheckSynchronize()
in a timer in the main thread.

if Pos('192.168',IPs[I]) = 1 then begin // Select LAN IP

Use can use Indy's TextStartsWith() function:

if TextStartsWith(IPs[I], '192.168.') then begin  // Select LAN IP


procedure TMainForm.Switch1Switch(Sender: TObject);

I have seen posts online that suggest TSwitch.OnSwitch runs in a worker thread
rather than the main UI thread. But I have not checked that for myself yet.
Have you?

with IdTCPServer1.Bindings.Add do begin

Something else to keep in mind - if you activate, deactivate, and then re-activate
the server, the previous bindings will still exist unless you remove them,
eg:

IdTCPServer1.Bindings.Clear;
with IdTCPServer1.Bindings.Add do begin
...


You cannot have multiple bindings that use the same IP:Port pair.

Application.ProcessMessages;

You really should get rid of that.

How to synchronize a method requiring parameters ?

You cannot use TIdNotify.NotifyMethod() for that. You will have to derive
a new class from TIdNotify and override its virtual DoNotify() method, then
you can have it do whatever you want. Add class members for the caller to
fill in when creating the notify object, and then have DoNotify() use them
as needed.

Alternatively, use a anonymous procedure with TThread.Queue(), and let it
capture whatever values you need to access.

Suppose I want to pass the AException and/or AContext paramete
to my LogException method

It would not be safe to pass the Exception itself, as it will likely be freed
before the notify is processed (unless you call AcquireExceptionObject()
so the RTL will not free it, and then you can free it yourself when you are
done using it). You could pass the Exception's ClassType and Message values
instead, though.

Same thing with the Context object. The server might free it before the
notify is processed, mainly if a disconnect occurs between the time you issue
the notify and the time it is actually processed. As long as you are just
using the Context object pointer value by itself, that is OK, but if you
are actually accessing the content of the object, that is not OK.

--
Remy Lebeau (TeamB)
Pierre-François...

Posts: 13
Registered: 10/26/12
Re: Indy 10 stoping TIdTCPServer freezes the App on iOS  
Click to report abuse...   Click to reply to this thread Reply
  Posted: Dec 4, 2014 7:31 AM   in response to: Remy Lebeau (Te... in response to: Remy Lebeau (Te...
Remy Lebeau (TeamB) wrote:
If you want to use TThread.Synchronize(), TThread.Queue(), TIdSync, or TIdNotify
in a FireMonkey project (they work fine in VCL), there is a workaround provided
in the QC ticket:

Until Embarcadero fixes this, a workaround would be to manually call CheckSynchronize()
in a timer in the main thread.

Tried. (Timer set to 100ms interval).
Didn't solve the deadlock issue when deactivating the TidTCPServer...

if Pos('192.168',IPs[I]) = 1 then begin // Select LAN IP

Use can use Indy's TextStartsWith() function:

if TextStartsWith(IPs[I], '192.168.') then begin  // Select LAN IP

Interesting. Didn't know this public Indy utility procedure.


procedure TMainForm.Switch1Switch(Sender: TObject);

I have seen posts online that suggest TSwitch.OnSwitch runs in a worker thread
rather than the main UI thread. But I have not checked that for myself yet.
Have you?

I just tried to add the following instruction

CurThreadId := TThread.CurrentThread.ThreadId;

in the main program body, before Application.Initialize, in the MainForm.OnCreate event handler and in the TSwitch.OnSwitch event handler as well.

I started the test program in debug mode on my iOS8.1 device with breakpoints set on these instructrions.

The value of CurThreadId: integer was 3 times the same: 910154204

The surprise is that this Id is exactly the same on each TestApp launching !... So I'm a bit perplex about that... Is that really a valid iOS ThreadId value ?...
What do you think ?


with IdTCPServer1.Bindings.Add do begin

Something else to keep in mind - if you activate, deactivate, and then re-activate
the server, the previous bindings will still exist unless you remove them,
eg:

IdTCPServer1.Bindings.Clear;
with IdTCPServer1.Bindings.Add do begin
...


You cannot have multiple bindings that use the same IP:Port pair.

Yeah I know. My complete app code includes a IdTCPServer1.Bindings.Clear; instruction just after the idTCPServer1.Active := false;

I didn't report it in my sample Test app for simplicity, to focus on the deadlock issue.


Application.ProcessMessages;

You really should get rid of that.

Obviously I know this is an ugly coding practice that should be ban !

I placed it here just to make the Test app as simple as possible, and to make appear the text "Starting server..." in the Memo before deactivating the server.


I'm about to upgrade my Delphi XE6 licence to XE7, but I would like to be sure it will solve my deadlock issue when deactivating the TidTCPServer on Firemonkey.

Are you sure it will ?

Thanks again for your support.

Remy Lebeau (Te...


Posts: 9,447
Registered: 12/23/01
Re: Indy 10 stoping TIdTCPServer freezes the App on iOS  
Click to report abuse...   Click to reply to this thread Reply
  Posted: Dec 4, 2014 11:07 AM   in response to: Pierre-François... in response to: Pierre-François...
Hello Pierre-François Culand,

Didn't solve the deadlock issue when deactivating the TidTCPServer...

Then the deadlock is not related to the TThread sync methods. Something
else is going on. Most likely a deadlock in some other piece of thread-unsafe
code somewhere.

I just tried to add the following instruction

CurThreadId := TThread.CurrentThread.ThreadId;

in the main program body, before Application.Initialize, in the
MainForm.OnCreate event handler

The RTL has its own MainThreadID global variable for that purpose.

and in the TSwitch.OnSwitch event handler as well.

Does TThread.CurrentThread.ThreadId match MainThreadID in the OnSwitch event?
If not, then they are running in different threads, and you will have to
use thread-safe logic inside of your OnSwitch code.

The value of CurThreadId: integer was 3 times the same: 910154204

OK, then OnSwitch is running in the main thread. Provided that OnSwitch
is actually being called, and nothing in your latest server code is using
any thread-blocking syncs, I don't see any reason for a deadlock. Unless
maybe TSwitch itself is doing something internally that is not thread-safe.

The surprise is that this Id is exactly the same on each TestApp
launching !... So I'm a bit perplex about that... Is that really a
valid iOS ThreadId value ?... What do you think ?

On Posix systems, like iOS, the RTL uses the pthreads library for its threading
support (besides, Apple's NSThread framework is based on pthreads internally).
AFAIK, thread IDs in pthreads are not global across the entire OS, like
thread IDs are global in Windows. A pthreads thread ID is a handle to a
thread instance, so it is more like Windows thread handles instead of thread
ID numbers. So it makes sense that multiple processes could have the same
thread IDs, since they are local to the calling process, not global to the
OS as a whole.

TThread.CurrentThread returns a TExternalThread object, and TExternalThread
gets its ThreadId from the GetCurrentThreadId() function, which calls pthread_self()
on Posix systems.

That being said, when comparing thread IDs on pthreads-based systems, you
should use pthread_equal() instead of the '=' operator. The return value
of pthread_self() is opaque and may not be directly comparible on all systems.
Not sure if the '=' operator safe on iOS thread IDs or not.

I placed it here just to make the Test app as simple as possible,
and to make appear the text "Starting server..." in the Memo before
deactivating the server.

Use the Memo's Repaint() or UpdateRect() method instead.

I'm about to upgrade my Delphi XE6 licence to XE7, but I would like
to be sure it will solve my deadlock issue when deactivating the
TidTCPServer on Firemonkey.

Are you sure it will ?

I can't answer that, since we have not identified the cause of the deadlock.
The only way that TIdTCPServer deadlocks when deactivating is if one of
its internal threads is not terminating correctly. If that is not being
caused by inter-thread sync deadlocks in your server event handlers, then
it might be in the server's thread Scheduler itself. There have been ARC-related
bug fixes made in the Scheduler's thread management logic, but I don't recall
if those affected XE6 or not. I think they were made in the XE4/5 timeframe
instead. But I would have to look back through's Indy's change history to
be sure.

At this point, the only thing I can suggest is try not deactivating the server
in the context of the main thread. Create a worker thread whose sole purpose
is to deactivate the server and then terminate. That way, the main thread
is free to process UI operations and sync requests normally. If a deadlock
did occur during server deactivation, at least the main thread would not
be deadlocked anymore.

--
Remy Lebeau (TeamB)
Pierre-François...

Posts: 13
Registered: 10/26/12
Re: Indy 10 stoping TIdTCPServer freezes the App on iOS  
Click to report abuse...   Click to reply to this thread Reply
  Posted: Dec 5, 2014 3:09 AM   in response to: Remy Lebeau (Te... in response to: Remy Lebeau (Te...
Remy Lebeau (TeamB) wrote:
That being said, when comparing thread IDs on pthreads-based systems, you
should use pthread_equal() instead of the '=' operator. The return value
of pthread_self() is opaque and may not be directly comparible on all systems.
Not sure if the '=' operator safe on iOS thread IDs or not.

I didn't find neither pthread_equal() nor pthread_self() routines in the RTL, where are they declared ?


I placed it here just to make the Test app as simple as possible,
and to make appear the text "Starting server..." in the Memo before
deactivating the server.

Use the Memo's Repaint() or UpdateRect() method instead.

AFIK, Repaint() or UpdateRect() will not have visual effect if the following 'TdTCPServer.Active := false;' instruction deadlocks the Main UI thread.


I'm about to upgrade my Delphi XE6 licence to XE7, but I would like
to be sure it will solve my deadlock issue when deactivating the
TidTCPServer on Firemonkey.

Are you sure it will ?

I can't answer that, since we have not identified the cause of the deadlock.
The only way that TIdTCPServer deadlocks when deactivating is if one of
its internal threads is not terminating correctly. If that is not being
caused by inter-thread sync deadlocks in your server event handlers, then
it might be in the server's thread Scheduler itself. There have been ARC-related
bug fixes made in the Scheduler's thread management logic, but I don't recall
if those affected XE6 or not. I think they were made in the XE4/5 timeframe
instead. But I would have to look back through's Indy's change history to
be sure.

Did you look back ?


At this point, the only thing I can suggest is try not deactivating the server
in the context of the main thread. Create a worker thread whose sole purpose
is to deactivate the server and then terminate. That way, the main thread
is free to process UI operations and sync requests normally. If a deadlock
did occur during server deactivation, at least the main thread would not
be deadlocked anymore.

I implemented that in the following source code. The main UI Thread is not deadlocked on the
server deactivation anymore, but the workerThread is deadlocked itself and as long as it cannot
terminate, the user will not be able to reactivate the server...
unit MainUnit;
 
interface
 
uses
  System.SysUtils, System.Types, System.UITypes, System.Classes, System.Variants,
  FMX.Types, FMX.Controls, FMX.Forms, FMX.Graphics, FMX.Dialogs, IdContext,
  FMX.StdCtrls, FMX.Layouts, FMX.Memo, IdGlobal, IdBaseComponent, IdComponent,
  IdCustomTCPServer, IdTCPServer, IdStack, IdSync, WorkerThreadUnit;
 
const
  C_PORT = 6000;
 
type
  TMainForm = class(TForm)
    IdTCPServer1: TIdTCPServer;
    Switch1: TSwitch;
    Memo1: TMemo;
    Label1: TLabel;
    Timer1: TTimer;
    procedure IdTCPServer1Execute(AContext: TIdContext);
    procedure IdTCPServer1Exception(AContext: TIdContext;
      AException: Exception);
    procedure Switch1Switch(Sender: TObject);
    procedure Timer1Timer(Sender: TObject);
  private
    { Private declarations }
    workerThread: TAsyncServerStopWorkerThread;
    procedure LogException;
    // Finds the Local IP address corresponding to the LAN connection:
    function GetLocalIPAddress: string;
  public
    { Public declarations }
  end;
 
var
  MainForm: TMainForm;
 
implementation
 
{$R *.fmx}
 
procedure TMainForm.LogException;
begin
  memo1.Lines.Add('TMainForm.IdTCPServer1Exception');
end;
 
function TMainForm.GetLocalIPAddress: string;
var
  IPs: TStringList;
  I: Integer;
  Err: Boolean;
begin
  IPs := TStringList.Create;
  Result := '';
  try
    GStack.AddLocalAddressesToList(IPs);
    for I := 0 to IPs.Count-1 do
    begin
      if TextStartsWith(IPs[I],'192.168') then begin
         Result := IPs[I];
         Break;
      end;
    end;
  finally
    FreeAndNil(IPs);
  end;
end;
 
procedure TMainForm.IdTCPServer1Exception(AContext: TIdContext;
  AException: Exception);
begin
  TIdNotify.NotifyMethod( LogException );
end;
 
procedure TMainForm.IdTCPServer1Execute(AContext: TIdContext);
var
  LLine: String;
begin
  LLine := AContext.Connection.IOHandler.ReadLn;
  AContext.Connection.IOHandler.WriteLn('OK');
end;
 
procedure TMainForm.Switch1Switch(Sender: TObject);
var
  LLine, LocIP: string;
  CurThreadId : Integer;
begin
  CurThreadId := TThread.CurrentThread.ThreadId;
  Assert(CurThreadId = MainThreadId);
  if Switch1.IsChecked then begin
    if Assigned(workerThread) then begin
      // Do not bind and restart server before its previous async stopping is finsished:
      // (But will actually deadlock since the workerThread will never terminate...)
      workerThread.WaitFor;
    end;
    LocIP := GetLocalIPAddress;
    with IdTCPServer1.Bindings.Add do begin
      IP := LocIP;
      Port := C_PORT;
    end;
    memo1.Lines.Add('Starting Server bind on IP='+LocIP+' on port #'+ IntToStr(C_PORT));
    IdTCPServer1.Active := True;
  end
  else begin
    memo1.Lines.Add('Stopping Server...');
    // Asynchronous Server stopping to prevent deadlock with the main UI thread:
    workerThread := TAsyncServerStopWorkerThread.Create(false);
  end;
end;
 
procedure TMainForm.Timer1Timer(Sender: TObject);
begin
  // Proposed Wworkaround supposed to solve FMX TThread.Synchronize() issue in a
  // FireMonkey project:
  CheckSynchronize();
end;
 
end.


unit WorkerThreadUnit;
 
interface
 
uses
  System.Classes;
 
type
  TAsyncServerStopWorkerThread = class(TThread)
  private
    { Private declarations }
    procedure UpdateUI;
  protected
    procedure Execute; override;
  end;
 
implementation
 
  uses SysUtils, MainUnit;
 
{ TAsyncServerStopWorkerThread }
 
procedure TAsyncServerStopWorkerThread.Execute;
var
  CurThreadId : Integer;
begin
  CurThreadId := TThread.CurrentThread.ThreadId;
  Assert(CurThreadId <> MainThreadId);
  MainForm.IdTCPServer1.Active := false;  // Never returns on iOS !!!
  MainForm.IdTCPServer1.Bindings.Clear;
  FreeOnTerminate := true;
  Synchronize(UpdateUI);
end;
 
procedure TAsyncServerStopWorkerThread.UpdateUI;
begin
  MainForm.Memo1.Lines.Add('...Done. IdTCPServer1 properly stopped.');
end;
 
end.


If the ARc related bugs were alread fixed in XE6 the mystery remains complete about
what causes the TIdTCPServer deactivation deadlock in FireMonkey projects, I'm afraid... :-(
Remy Lebeau (Te...


Posts: 9,447
Registered: 12/23/01
Re: Indy 10 stoping TIdTCPServer freezes the App on iOS
Correct
Click to report abuse...   Click to reply to this thread Reply
  Posted: Dec 5, 2014 11:15 AM   in response to: Pierre-François... in response to: Pierre-François...
Pierre-François wrote:

Did you look back ?

Some changes made it into XE6, but additional changes were added afterwards
and are in XE7 instead.

--
Remy Lebeau (TeamB)
Pierre-François...

Posts: 13
Registered: 10/26/12
Re: Indy 10 stoping TIdTCPServer freezes the App on iOS  
Click to report abuse...   Click to reply to this thread Reply
  Posted: Dec 5, 2014 11:33 AM   in response to: Remy Lebeau (Te... in response to: Remy Lebeau (Te...
Remy Lebeau (TeamB) wrote:
Pierre-François wrote:

Did you look back ?

Some changes made it into XE6, but additional changes were added afterwards
and are in XE7 instead.

Ok, I'll download this weekend an eval copy of Delphi XE7 and will check if the issue is solved.

Thank you for your continuous support.
Pierre-François...

Posts: 13
Registered: 10/26/12
Re: Indy 10 stoping TIdTCPServer freezes the App on iOS  
Click to report abuse...   Click to reply to this thread Reply
  Posted: Dec 7, 2014 4:15 AM   in response to: Pierre-François... in response to: Pierre-François...
ISSUE SOLVED !

I Finally downloaded an eval version of Delphi XE7 and... Yes ! It's working !

No more deadlock in the TIdTCPServer deactivation on IOS !!!

Should have started with that... but I didn't expect FMX XE6 and the included Indy10 library were misfunctionning on iOS for such a basic function like TCP Server deactivation. Because XE6 was sold as a RAD tool supposed to be able to develop apps for IOS...

Hope this will not be the same headache when I'll check to deploy my app on Android tablets...

Thank you again for your help and support Remy.
Remy Lebeau (Te...


Posts: 9,447
Registered: 12/23/01
Re: Indy 10 stoping TIdTCPServer freezes the App on iOS  
Click to report abuse...   Click to reply to this thread Reply
  Posted: Dec 8, 2014 6:06 PM   in response to: Pierre-François... in response to: Pierre-François...
Pierre-François wrote:

Should have started with that... but I didn't expect FMX XE6 and
the included Indy10 library were misfunctionning on iOS for such a
basic function like TCP Server deactivation.

ARC was such a major change to the Delphi memory/threading model that it
has taken Indy several IDE versions to find and fix its ARC-related issues.
An I'm sure I haven't gotten all of them fixed yet, but the major showstopped
ones are, at least.

Hope this will not be the same headache when I'll check to deploy
my app on Android tablets...

It is hard for me to resolve mobile issues in Indy when 1) I don't have any
mobile devices that are compatible with Delphi, and 2) different mobile devices
behave differently even under similar specs. There is not much variety in
the iOS market, but there is tons of variety in the Android market, device/OS
fragmentation is a major issue for Android developers.

--
Remy Lebeau (TeamB)
Remy Lebeau (Te...


Posts: 9,447
Registered: 12/23/01
Re: Indy 10 stoping TIdTCPServer freezes the App on iOS  
Click to report abuse...   Click to reply to this thread Reply
  Posted: Dec 8, 2014 6:08 PM   in response to: Pierre-François... in response to: Pierre-François...
Pierre-François wrote:

Should have started with that... but I didn't expect FMX XE6 and
the included Indy10 library were misfunctionning on iOS for such a
basic function like TCP Server deactivation.

ARC was such a major change to the Delphi memory/threading model that it
has taken Indy several IDE versions to find and fix its ARC-related issues.
An I'm sure I haven't gotten all of them fixed yet, but the major showstopped
ones are, at least.

Hope this will not be the same headache when I'll check to deploy
my app on Android tablets...

It is hard for me to resolve mobile issues in Indy when 1) I don't have any
mobile devices that are compatible with Delphi, and 2) different mobile devices
behave differently even under similar specs. There is not much variety in
the iOS market, but there is tons of variety in the Android market, device/OS
fragmentation is a major issue for Android developers.

--
Remy Lebeau (TeamB)
Pierre-François...

Posts: 13
Registered: 10/26/12
Re: Indy 10 stoping TIdTCPServer freezes the App on iOS  
Click to report abuse...   Click to reply to this thread Reply
  Posted: Dec 8, 2014 11:59 PM   in response to: Remy Lebeau (Te... in response to: Remy Lebeau (Te...
Remy Lebeau (TeamB) wrote:
ARC was such a major change to the Delphi memory/threading model that it
has taken Indy several IDE versions to find and fix its ARC-related issues.
An I'm sure I haven't gotten all of them fixed yet, but the major showstopped
ones are, at least.

Actually I didn't even know what ARC was... But I just found the Marco Cantu explanations here: http://blog.marcocantu.com/blog/automatic_reference_counting_for_delphi.html
I understand it is a big issue for Indy. I didn't want to appear ungrateful or thankless.
My criticism was aimed at Embarcadero. I bought XE5 ultimate last year (for a big price) to devolop mobile apps, I upgraded 6 months later to XE6, and I now have to upgrade to XE7 to get something working (AFIK) on iOS...

It is hard for me to resolve mobile issues in Indy when 1) I don't have any
mobile devices that are compatible with Delphi, and 2) different mobile devices
behave differently even under similar specs. There is not much variety in
the iOS market, but there is tons of variety in the Android market, device/OS
fragmentation is a major issue for Android developers.

The good news is that I just tested Indy TCP Client/Server communication on an Android tablet. It's working fine !
But it's true it's not easy to get a low cost tablet compatible with Delph/FireMonkey...
I had to buy 3 different models to finally find a compatible one !!!
(The two first ones I got were based on the ATOM Intel processor which is not compatible with Delphi/FMX...)
I finally got the one year old (2013) ASUS MeMO Pad HD 7 (ME173X), which includes a Mediatek processor ARMv7 / NEON instruction set based and
runs under Android 4.2.1 (Jelly Bean) for the price of CHF169.- (about 169$)
Note that the new (2014) ASUS 7-inch model: The (149$) MeMO Pad 7 (ME176CX) swaps the MediaTek processor inside last year's model for an incompatible Intel ATOM CPU.

Do you know if there is a chance of getting Delphi/FMX to run under other processor architectures (especially Intel ATOM) in the next future ?

Because it seems that Intel ATOM processors are more and more found on new Android devices.

Edited by: Pierre-François Culand on Dec 9, 2014 9:01 AM
Pierre-François...

Posts: 13
Registered: 10/26/12
Re: Indy 10 stoping TIdTCPServer freezes the App on iOS  
Click to report abuse...   Click to reply to this thread Reply
  Posted: Dec 9, 2014 7:44 AM   in response to: Pierre-François... in response to: Pierre-François...
I wrote a bit too quickly that it was working fine on Android:

Actually, getting the Local IP address of my Android tablet with GStack.AddLocalAddressesToList(IPs); returns only the localhost IP: '127.0.0.1':

But on iOS this indy method returns the genuine LAN Address '192.168.x.x' assigned by the LAN DHCP server.

Do you know how to get that on Android ?

By the way, is that required to frame the call to GStack.AddLocalAddressesToList(IPs); with calls to TIdStack.IncUsage; & TIdStack.DecUsage; this way:

TIdStack.IncUsage;
try
GStack.AddLocalAddressesToList(IPs);
finally
TIdStack.DecUsage;
end;

And if yes, why ?
Remy Lebeau (Te...


Posts: 9,447
Registered: 12/23/01
Re: Indy 10 stoping TIdTCPServer freezes the App on iOS [Edit]  
Click to report abuse...   Click to reply to this thread Reply
  Posted: Dec 9, 2014 11:11 AM   in response to: Pierre-François... in response to: Pierre-François...
Pierre-François wrote:

Do you know if there is a chance of getting Delphi/FMX to run under
other processor architectures (especially Intel ATOM) in the next
future ?

Intel CPUs are on the roadmap for "after 2014". Beyond that, there has been
no other word from Embarcadero about which architectures they are going to
be targetting.

--
Remy Lebeau (TeamB)
Daniel Fields

Posts: 622
Registered: 11/29/04
Re: Indy 10 stoping TIdTCPServer freezes the App on iOS  
Click to report abuse...   Click to reply to this thread Reply
  Posted: Dec 2, 2014 3:19 PM   in response to: Pierre-François... in response to: Pierre-François...
It also looks like a synchronous event, "procedure Switch1Switch(Sender: TObject)". Have you tried it asynchronously?
Remy Lebeau (Te...


Posts: 9,447
Registered: 12/23/01
Re: Indy 10 stoping TIdTCPServer freezes the App on iOS  
Click to report abuse...   Click to reply to this thread Reply
  Posted: Dec 2, 2014 4:06 PM   in response to: Daniel Fields in response to: Daniel Fields
Daniel wrote:

It also looks like a synchronous event, "procedure
Switch1Switch(Sender: TObject)".

It is an event handler for a TSwitch.OnSwitch event.

Have you tried it asynchronously?

And how would you propose making a UI event run asynchronously? It is already
running in the main thread, blocking the main thread until finished.

--
Remy Lebeau (TeamB)
Daniel Fields

Posts: 622
Registered: 11/29/04
Re: Indy 10 stoping TIdTCPServer freezes the App on iOS  
Click to report abuse...   Click to reply to this thread Reply
  Posted: Dec 2, 2014 5:22 PM   in response to: Remy Lebeau (Te... in response to: Remy Lebeau (Te...
I meant in addition to everything you said. Not instead of. I agree 100% about making UI changes in a thread, even with Synchronize. Having to do so usually means you have a design flaw. Typically, it means the thread is doing too much.
Legend
Helpful Answer (5 pts)
Correct Answer (10 pts)

Server Response from: ETNAJIVE02