Program Freezes because FEventThread won't Stop

TMS Async: v1.5.0 (also tested v1.9.2)
IDE: Delphi XE2 Update 4 (also tested Delphi 7)

Problem Summary: An exception is raised while serial input is being processed in VaComm.OnRxChar from a COM port. The exception is unhandled so gets caught by Application.OnException where I attempt to VaComm.Close() the port, but this makes the program freeze (not crash).

Here is the step-by-step:

1) An ERangeError exception is raised in TfrmUartComm.OnSpecificRES(). This is what the call stack looks like at this point:

-> :751cc42d KERNELBASE.RaiseException + 0x58
   :006ca67e HookedRaiseException + $5E
   :0040995a DynArraySetLength + $2A
   :0040995a DynArraySetLength + $2A
   :00409ad6 @DynArraySetLength + $A
   UartComm.TfrmUartComm.OnSpecificRES($2259530,$10B543E0)
   UartComm.TfrmUartComm.OnSpecificPktRX($220A920,$10B543E0)
   UartComm.TfrmUartComm.DisplayUartFrame($220A920,$10B543E0,0)
   UartComm.TfrmUartComm.UartVaComm1RxChar($220A920,0)
   VaComm.TVaCustomComm.HandleDataEvent
   VaComm.TVaCommEventThread.DoEvent


2) The exception is unhandled so it falls all the way to VaComm.TVaCommEventThread.DoEvent(). There it's caught by the line:

Application.HandleException(Self);

which calls the routine Application.OnException is bound to, in my case LogExceptions.ExceptionHandler().

3) In LogExceptions.ExceptionHandler() I run some wrapper code that eventually closes the VaComm1: TVaComm object which is contained in frmConnection: TForm:

procedure TfrmConnection.Disconnect;
begin
  if VaComm1.Active then
    VaComm1.Close();
end;


4) VaComm1.Close() calls VaComm.TVaCustomComm.DestroyThreads() and the program freezes on the marked line:

procedure TVaCustomComm.DestroyThreads;
begin
  if FEventThread <> nil then
  begin
    FEventThread.StopThread;
    FEventThread.WaitFor;  // <-- FREEZES WHEN IT EXECUTES THIS LINE.

Here is the callstack at this point:

 -> VaComm.TVaCustomComm.DestroyThreads
   VaComm.TVaCustomComm.Close
   Connection.TfrmConnection.Disconnect
   UartComm.TfrmUartComm.DisconFromCOMPort
   Main.TfrmMain.Disconnect
   LogExceptions.TLogExceptions.ExceptionHandler($22F09E0,$10BA0ED8)
   :00583438 TApplication.HandleException + $64



Note that it doesn't crash; there's no error. Execution continues forever and the GUI is frozen.

If I use the IDE to "Tools -> Program Pause" it shows the CPU window is executing:

ntdll.RtlUserThreadStart

then it executes:

ntdll.RtlInitializeExceptionChain:


Every time I run and re-pause it, it shows the same thing.

Also note that at the time ERangeError exception is raised, no more bytes are being received on the serial connection: so communication isn't active.

I don't understand why this problem happens or how to fix it. Let me know if you need more info.




I don't know how to edit the post but I wanted to add that the port closes just fine under normal circumstance: before or after I receive communication on the COM port.

And port closes just fine if I raise an error anywhere (like on a button click), but not if raised in the method VaComm.OnRxChar is bound to, or any further routines this method calls. So it's something to do with this VaComm.OnRxChar method...

It would appear to me that you're trying to prematurely close the serial port and thus, that you'd then never get all data that is being received. Is that the intention? If you want to make sure you only close the port when all data is received, this should be handled at your protocol level or at least perform a check like Vacomm.ReadBufUsed = 0 before you close the port.

Yes, if an unexpected error happens while processing serial communication it should close the port.

Like I said in first post, there's no serial communication at this point. Both at the point when the unhandled exception was raised, and the point before I call `VaComm1.Close()`, `VaComm1.ReadBufUsed()` returns 0.

I don't know how events work in Delphi, but maybe do you think when `VaComm.OnRxChar()` returns this is registered somewhere: that it finished and returned successfully? So if an exception happens inside `OnRxChar()` it never `return`s that it finished? So `FEventThread.WaitFor()` is waiting for `OnRxChar()` to finish and return?

Bump. Can I get some support for this issue please? 

Are you somehow holding up vacomm with your code in OnRxChar?

You should make sure your code does not remain busy in OnRxChar, certainly not when you'll close vacomm.

Yes Bruno, I'm sure. Here is a minimal example reproducing the problem:  

1) Create a new project in Delphi XE2 (but this probably works with all Delphi versions) with one unit:

2) Inside "Unit1.pas" put:

unit Unit1;

interface

uses
  Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics,
  Vcl.Controls, Vcl.Forms, Vcl.Dialogs, VaClasses, VaComm;

type
  TForm1 = class(TForm)
    VaComm1: TVaComm;
     procedure FormCreate(Sender: TObject);
         procedure RxChar(Sender: TObject; Count: Integer);
    procedure HandleException(Sender: TObject; E: Exception);
  private
  public

  end;

var
  Form1: TForm1;
  onlyonce: Integer = 0;

implementation

{$R *.dfm}

procedure TForm1.FormCreate(Sender: TObject)   ;
begin
   VaComm1.OnRxChar := RxChar;
   Application.OnException := HandleException;
   Vacomm1.PortNum := 8;
   VaComm1.Baudrate := 9600;
   VaComm1.Open();
end;

procedure TForm1.RxChar(Sender: TObject; Count: Integer)   ;
begin
  if onlyonce = 0 then
  begin
    onlyonce := 1;
    Assert(2+2=5);
  end;
end;

procedure TForm1.HandleException(Sender: TObject; E: Exception);
var
  i : Integer;
begin
   VaComm1.Close();
   i := 1;

end;

end.

3) Inside "Unit1.dfm" put:

object Form1: TForm1
  Left = 0
  Top = 0
  Caption = 'Form1'
  ClientHeight = 300
  ClientWidth = 635
  Color = clBtnFace
  Font.Charset = DEFAULT_CHARSET
  Font.Color = clWindowText
  Font.Height = -11
  Font.Name = 'Tahoma'
  Font.Style = []
  OldCreateOrder = False
  OnCreate = FormCreate
  PixelsPerInch = 96
  TextHeight = 13
  object VaComm1: TVaComm
    Baudrate = brUser
    FlowControl.OutCtsFlow = False
    FlowControl.OutDsrFlow = False
    FlowControl.ControlDtr = dtrDisabled
    FlowControl.ControlRts = rtsDisabled
    FlowControl.XonXoffOut = False
    FlowControl.XonXoffIn = False
    FlowControl.DsrSensitivity = False
    FlowControl.TxContinueOnXoff = False
    DeviceName = 'COM%d'
    MonitorEvents = [ceError, ceRxChar]
    Buffers.ReadSize = 20000
    Buffers.WriteSize = 4096
    Buffers.ReadTimeout = 3000
    Buffers.WriteTimeout = 3000
    WritePriority = tpHigher
    UserBaudrate = 500000
    Version = '1.5.0.0'
    Left = 24
    Top = 32
  end
end

4) In `FormCreate()` set the `PortNum` and `BaudRate` how you like it.

5) Start the application. An empty form will show. You can drag this window around; it's responsive.

6) Send exactly 1 byte through the COM port.

7) The window is now frozen forever; you can't move it around.


If you comment out `VaComm1.Close()` and re-run the application it will say an exception was raised but this exception is suppressed and the window is not frozen. This is the expected behaviour.


I'm on Windows 7 Professional SP1, if it matters.

When you trigger the exception, the exception handler will invoke the vacomm.Close() and that means you do a close before the OnRxChar event could terminate. So, Close() can't close because OnRxChar is busy and the exception handler in OnRxChar is held up because of this. The result is a freeze. 
So, please move calling Close() out of the OnRxChar event.

Thank you for your help. What I did was create a Timer that does `VaComm.Close()`, and enabled this Timer from inside `Application.OnException`.