131 views
in GUI Development by

Hi,

Our code is getting crashed after some time when it is kept running continuously for unit testing.

I would like to brief you about it:

GUI screen is controlled by gRPC protocol – gRPC is a modern open-source high performance Remote Procedure Call (RPC) framework that can run in any environment – it is acting as middle layer which sends request to EW Application as per Main Application requirement and related screen and screen live data is shown at EW Code and on key pressed event, response is sent back to Main Application through gRPC.

Currently request and response is running continuously and only 2 screens are getting displayed one by one in loop.

After some time, it is getting crashed.

It could be segmentation fault due to pointer behaviour; we are digging into it.

But would like to understand below code part from Core.c (it is for Linux Profile) and possible reason of crash and how to debug it.

 

On first screen some texts are there along with % value for loading(similar to battery management) and 1 bitmap image which is getting loaded through External Bitmap method + 5 functional keys.

Second screen consists of 12 Text Widgets – each widget has 2 texts + 5 texts + 16 (39*39 size) icons/images + 5 functional keys.

 

Observation – the loop is running approximately 400 times and gets crashed.

Crashing is observed on win32 profile as well.

Attached is the log observed for both the profile Win32/Linux profile 

Note: Similar issue was not observed with Lower version i.e 8

https://ask.embedded-wizard.de/?qa=blob&qa_blobid=2618858202834056435

https://ask.embedded-wizard.de/?qa=blob&qa_blobid=1169565748581249156

1 Answer

0 votes
by

Hi Pidea,

I'm not sure if your support request is related to GUI development with Embedded Wizard so that we can help you here efficiently.

So far I'm not familiar with gRPC. Can you provide a reproducible example without gRPC?

One important note: The entire GUI application has to be executed/accessed only within the GUI thread/task.

Can you ensure that the GUI application is never accessed from a different task? 

Best regards,

Manfred.

 

by
Hi Manfred,

I am testing on my side.with minimum functionality. Starting from rootscreen to navigate to other screen(from system event) with one trace statement .

Some observation are removing the traces from the code. Code last for more than 1 hour .

Any inputs if you can give me ?
by
Hi ,

 

1. What will be the steps On Win32 to send and receive message through Message Queue on Embedded Wizard side

2. As per my understanding in Win32 we have <windows.h> which has

SendMessageA(
    _In_ HWND hWnd,
    _In_ UINT Msg,
    _Pre_maybenull_ _Post_valid_ WPARAM wParam,
    _Pre_maybenull_ _Post_valid_ LPARAM lParam);

GetMessageA(
    _Out_ LPMSG lpMsg,
    _In_opt_ HWND hWnd,
    _In_ UINT wMsgFilterMin,
    _In_ UINT wMsgFilterMax);

Can it be used for implementation of message queue at windows side and using native statement "GetMessageA" and SendMessageA can it be used at Embedded Wizard side also ?
by

Hello Pidea,

to communicate between two threads in a Win32 application is suitable the Win32 function PostThreadMessage(). The following is a modified main.c module belonging to Embedded Wizard Win32 Platform Package. It creates a worker thread and the thread posts messages to the GUI thread. Please note the 3 modifications identified by comment STEP 1, STEP 2 and STEP 3:

/* ... */

#include "ewapp.h"
#include "Core.h"
#include "Example.h"

/* Exclude rarely-used stuff from Windows headers */
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#include <process.h>
#include <malloc.h>


/* Under Win32 we need a separate console window for print outputs */
#if ( defined EW_PRINT_MEMORY_USAGE  || defined EW_PRINT_GFX_TASKS    ||         \
      defined EW_RUN_BENCHMARK_SHORT || defined EW_RUN_BENCHMARK_FULL ||         \
      defined EW_RUN_VERIFICATION ) && !defined EW_OPEN_CONSOLE
  #define EW_OPEN_CONSOLE
#endif


/* STEP 1: Some common pre-declarations and the worker thread function */

/* Unique IDs for Window messages to exchange between the worker and the GUI
   thread. */
#define WM_YOUR_MESSAGE   ( WM_USER + 1 )

/* Some data structure intended to store the message content. */
typedef struct
{
  int SomeData1;
  int SomeData2;
  int SomeDataN;
} MessageData;

/* Global variable identifying the GUI thread. */
static volatile DWORD ThreadID_GUI;

/* Some worker function running in context of a foreign thread. */
static void __cdecl ThreadProc( void* aArg )
{
  MessageData* data;

  for ( ;; )
  {
    Sleep( 500 );

    /* Allocate memory for a new message data structure */
    data = (MessageData*)malloc( sizeof( *data ));

    /* Initialize the message data structure with some information to transfer
       to the GUI thread. */
    data->SomeData1 = 1234;
    data->SomeData2 = 4567;
    data->SomeDataN = 7894;

    /* Post a message to the GUI thread together with the just initialized
       data structure */
    PostThreadMessage( ThreadID_GUI, WM_YOUR_MESSAGE, 0, (LPARAM)data );
  }
}

/* END STEP 1 */


/* This is the main function of the MS Windows application */
int APIENTRY WinMain( HINSTANCE aInstance, HINSTANCE aPrevInstance, 
  LPSTR aCmdLine, int aCmdShow )
{
  MSG      msg;
  CoreRoot rootObject;

  EW_UNUSED_ARG( aInstance );
  EW_UNUSED_ARG( aPrevInstance );
  EW_UNUSED_ARG( aCmdLine );
  EW_UNUSED_ARG( aCmdShow );

  /* STEP 2: Start the worker thread */
  {
    /* Store the ID of the GUI thread in a global variable */
    ThreadID_GUI = GetCurrentThreadId();

    /* Start some background thread */
    _beginthread( ThreadProc, 0, 0 );
  }
  /* END STEP 2 */

  /* Before we initialize the GUI application, configure caches, queues and
     memory allocation strategies of Graphics Engine and Runtime Environment
     according to settings from the ewconfig.h file or Make file. */
  EwConfigRuntimeEnvironment();
  EwConfigGraphicsEngine();

  /* The following EwOpenConsole() call is optional. It opens a console window
     for printf() outputs. */
  #ifdef EW_OPEN_CONSOLE
    EwOpenConsole();
  #endif

  /* Initialize the Graphics Engine and Runtime Environment */
  EwInitGraphicsEngine( 0 );

  /* Create the applications root object ... */
  rootObject = (CoreRoot)EwNewObjectIndirect( EwApplicationClass, 0 );
  EwLockObject( rootObject );

  /* ... and initialize the application object. */
  CoreRoot__Initialize( rootObject, EwScreenSize );

  /* Open the viewer window to display the framebuffer's content */
  EwOpenViewer( rootObject );

  /* Process MS-Windows messages */
  while( GetMessage( &msg, NULL, 0, 0 ))
  {
    /* STEP 3: React on the message sent from the foreign thread */
    if ( msg.message == WM_YOUR_MESSAGE )
    {
      MessageData*       data   = (MessageData*)msg.lParam;
      ExampleDeviceClass object = EwGetAutoObject( &ExampleDevice, ExampleDeviceClass );

      /* Evaluate the data found in the associated data structure and e.g. trigger
         an Embedded Wizard System Event */
      if ( data->SomeData1 == 1234 )
        ExampleDeviceClass__TriggerEvent( object );

      /* Free the data structure associated to the message */
      free( data );
    }
    /* END STEP 3 */

    TranslateMessage( &msg );
    DispatchMessage( &msg );

    /* Process expired timers */
    EwProcessTimers();

    /* The following do/while loop is responsible for the idle processing.
       This loop is executed as long as any signals are pending and no other
       user inputs are received by the Viewer application. */
    do
    {
      /* Process the pending signals */
      EwProcessSignals();

      /* Refresh the screen, if something has changed and draw its content in
         the viewer window */
      EwUpdateViewer();

      /* After each processed message start the garbage collection */
      EwReclaimMemory();
    }
    while ( EwAnyPendingSignals() &&
      #if WINVER >= 0x0602
        !GetQueueStatus( QS_KEY | QS_MOUSE | QS_TIMER ) &&
        !GetQueueStatus( QS_TOUCH ));
      #else
        !GetQueueStatus( QS_KEY | QS_MOUSE | QS_TIMER ));
      #endif

    /* Show the memory statistic */
    #ifdef EW_PRINT_MEMORY_USAGE
      EwPrintProfilerStatistic( 0 );
    #endif
  }

  /* Finished -> release unused resources */
  EwUnlockObject( rootObject );
  EwReclaimMemory();

  /* ... and deinitialize the Graphics Engine */
  EwDoneGraphicsEngine();

  /* Show the finaly memory statistic */
  #ifdef EW_PRINT_MEMORY_USAGE
    EwPrintProfilerStatistic( 0 );
  #endif

  /* Return the exit-code of the viewer */
 	return msg.wParam;
}


/* pba */

I hope it helps you further. If you need more details concerning the message exchange under Win32 I would recommend the respective Microsoft documentation. In fact it is an aspect beyond our Embedded Wizard competency.

Best regards

Paul Banach

by
hi Paul,

 

thanks for the reply.
by
hi Paul,

 

I have implemented the code as per your feedback. But it is not working .I want to explain how I have implemented

I have server.cpp /server.h

/* Some worker function running in context of a foreign thread */
void __cdecl ThreadProc( void* aArg )
{
  MessageData* data;

  for ( ;; )
  {
    Sleep( 500 );

    /* Allocate memory for a new message data structure */
    data = (MessageData*)malloc( sizeof( *data ));

    /* Initialize the message data structure with some information to transfer
       to the GUI thread. */
    data->SomeData1 = 1234;
    data->SomeData2 = 4567;
    data->SomeDataN = 7894;

    /* Post a message to the GUI thread together with the just initialized
       data structure */
    PostThreadMessage( ThreadID_GUI, WM_YOUR_MESSAGE, 0, (LPARAM)data );
  }
}

 

Client.h ie. GUI

main.c

/* This is the main function of the MS Windows application */
int APIENTRY WinMain( HINSTANCE aInstance, HINSTANCE aPrevInstance,
  LPSTR aCmdLine, int aCmdShow )
{
  MSG      msg;
  CoreRoot rootObject;

  EW_UNUSED_ARG( aInstance );
  EW_UNUSED_ARG( aPrevInstance );
  EW_UNUSED_ARG( aCmdLine );
  EW_UNUSED_ARG( aCmdShow );

  /* STEP 2: Start the worker thread */
  {
    /* Store the ID of the GUI thread in a global variable */
    ThreadID_GUI = GetCurrentThreadId();

    /* Start some background thread */
    _beginthread( ThreadProc, 0, 0 );
  }
  /* END STEP 2 */

  /* Before we initialize the GUI application, configure caches, queues and
     memory allocation strategies of Graphics Engine and Runtime Environment
     according to settings from the ewconfig.h file or Make file. */
  EwConfigRuntimeEnvironment();
  EwConfigGraphicsEngine();

  /* The following EwOpenConsole() call is optional. It opens a console window
     for printf() outputs. */
  #ifdef EW_OPEN_CONSOLE
    EwOpenConsole();
  #endif

  /* Initialize the Graphics Engine and Runtime Environment */
  EwInitGraphicsEngine( 0 );

  /* Create the applications root object ... */
  rootObject = (CoreRoot)EwNewObjectIndirect( EwApplicationClass, 0 );
  EwLockObject( rootObject );

  /* ... and initialize the application object. */
  CoreRoot__Initialize( rootObject, EwScreenSize );

  /* Open the viewer window to display the framebuffer's content */
  EwOpenViewer( rootObject );

  /* Process MS-Windows messages */
  while( GetMessage( &msg, NULL, 0, 0 ))
  {
    /* STEP 3: React on the message sent from the foreign thread */
    if ( msg.message == WM_YOUR_MESSAGE )
    {
      MessageData*       data   = (MessageData*)msg.lParam;
      ExampleDeviceClass object = EwGetAutoObject( &ExampleDevice, ExampleDeviceClass );

      /* Evaluate the data found in the associated data structure and e.g. trigger
         an Embedded Wizard System Event */
      if ( data->SomeData1 == 1234 )
        ExampleDeviceClass__TriggerEvent( object );

      /* Free the data structure associated to the message */
      free( data );
    }
    /* END STEP 3 */

    TranslateMessage( &msg );
    DispatchMessage( &msg );

    /* Process expired timers */
    EwProcessTimers();

    /* The following do/while loop is responsible for the idle processing.
       This loop is executed as long as any signals are pending and no other
       user inputs are received by the Viewer application. */
    do
    {
      /* Process the pending signals */
      EwProcessSignals();

      /* Refresh the screen, if something has changed and draw its content in
         the viewer window */
      EwUpdateViewer();

      /* After each processed message start the garbage collection */
      EwReclaimMemory();
    }
    while ( EwAnyPendingSignals() &&
      #if WINVER >= 0x0602
        !GetQueueStatus( QS_KEY | QS_MOUSE | QS_TIMER ) &&
        !GetQueueStatus( QS_TOUCH ));
      #else
        !GetQueueStatus( QS_KEY | QS_MOUSE | QS_TIMER ));
      #endif

    /* Show the memory statistic */
    #ifdef EW_PRINT_MEMORY_USAGE
      EwPrintProfilerStatistic( 0 );
    #endif
  }

  /* Finished -> release unused resources */
  EwUnlockObject( rootObject );
  EwReclaimMemory();

  /* ... and deinitialize the Graphics Engine */
  EwDoneGraphicsEngine();

  /* Show the finaly memory statistic */
  #ifdef EW_PRINT_MEMORY_USAGE
    EwPrintProfilerStatistic( 0 );
  #endif

  /* Return the exit-code of the viewer */
     return msg.wParam;
}

 

I always receive data as NULL. It seems there is no connection between server and client
by
Hi Paul,

 

One more Question, Is there any Message Queue Which can be used on GUI side ?
by

Hello Pidea,

difficult to say why it is not working in your case. I have tested this code in advance and it worked as expected. From your description I assume, the following if-condition is entered, but data is NULL:

if ( msg.message == WM_YOUR_MESSAGE )
{
  MessageData*       data   = (MessageData*)msg.lParam;
  ExampleDeviceClass object = EwGetAutoObject( &ExampleDevice, ExampleDeviceClass );

  /* Evaluate the data found in the associated data structure and e.g. trigger
     an Embedded Wizard System Event */
  if ( data->SomeData1 == 1234 )
    ExampleDeviceClass__TriggerEvent( object );

  /* Free the data structure associated to the message */
  free( data );
}

If this is the case, data can be NULL only when the original message was posted with NULL in the last parameter (so-called LParam) in the invocation of PostThreadMessage(). Since we pass here a pointer to a data structure allocated previously by malloc() this should never be NULL:

/* Allocate memory for a new message data structure */
data = (MessageData*)malloc( sizeof( *data ));

/* Initialize the message data structure with some information to transfer
   to the GUI thread. */
data->SomeData1 = 1234;
data->SomeData2 = 4567;
data->SomeDataN = 7894;

/* Post a message to the GUI thread together with the just initialized
   data structure */
PostThreadMessage( ThreadID_GUI, WM_YOUR_MESSAGE, 0, (LPARAM)data );

The unique possibility is, the ID of the message WM_YOUR_MESSAGE is not unique. In other words, someone else in your application uses already this message ID. In such case you can try to change the definition to another value, e.g.:

#define WM_YOUR_MESSAGE ( WM_USER + 10 )

Concerning your last question:

One more Question, Is there any Message Queue Which can be used on GUI side ?

Well, if you are using Windows, then it provides diverse Inter-Process-Communication services suitable to exchange data between two threads, processes and even machines. The above used PostThreadMessage() is the simplest of them and it works very well - as long as you limit to exchange data between threads sharing the same process space. It is not intended to communicate between two machines. This leads me to the following question:

What do you mean with server/client? Do you intend to run 2 separate executables and exchange data between them by using PostThreadMessage()?

Best regards

Paul Banach

by
What do you mean with server/client? Do you intend to run 2 separate executables and exchange data between them by using PostThreadMessage()?

Yes we have two separate executables.

One exe is client side and

other exe is Server side i.e GUI
by

Hello Pidea,

So far I have understood, you are using gRPC for communication purpose between Server/Client, right? The usage of the above PostThraedMessage() function was intended ONLY to exchange data from the gRPC thread to GUI thread. This has to occur within the same GUI process.

Best regards

Paul Banach

by

Yes the communication protocol we used between Microcontroller and GUI is gRPC 

gRPC client act as  Microcontroller and gRPC server act as a GUI 

PostThraedMessage() function was intended ONLY to exchange data from the gRPC thread to GUI thread. - Yes we using the same.

 This has to occur within the same GUI process : 

There is one file gRPCservice.cpp where all the data resides so i have implemented ThreadProc function in this file 

#define WM_YOUR_MESSAGE   ( WM_USER + 1 )

/* Some data structure intended to store the message content. */
typedef struct
{
  int SomeData1;
  int SomeData2;
  int SomeDataN;
} MessageData;

/* Global variable identifying the GUI thread. */
static volatile DWORD ThreadID_GUI;

/* Some worker function running in context of a foreign thread. GUIService.cpp - setSplash */
static void __cdecl ThreadProc( void* aArg ) // main.c //RunGUIService
{
  MessageData* data;

  for ( ;; )
  {
    Sleep( 500 );

    /* Allocate memory for a new message data structure */
    data = (MessageData*)malloc( sizeof( *data ));

    /* Initialize the message data structure with some information to transfer
       to the GUI thread. */
    data->SomeData1 = 1234;
    data->SomeData2 = 4567;
    data->SomeDataN = 7894;

    /* Post a message to the GUI thread together with the just initialized
       data structure */
    PostThreadMessage( ThreadID_GUI, WM_YOUR_MESSAGE, 0, (LPARAM)data );
  }
}

///////////////////////////

From main .c ()

#include <gRPCService.h>

int APIENTRY WinMain( HINSTANCE aInstance, HINSTANCE aPrevInstance, 
  LPSTR aCmdLine, int aCmdShow )
{
  MSG      msg;
  CoreRoot rootObject;

  EW_UNUSED_ARG( aInstance );
  EW_UNUSED_ARG( aPrevInstance );
  EW_UNUSED_ARG( aCmdLine );
  EW_UNUSED_ARG( aCmdShow );

  /* STEP 2: Start the worker thread */
  {
    /* Store the ID of the GUI thread in a global variable */
   // ThreadID_GUI = GetCurrentThreadId();

    /* Start some background thread */
    _beginthread( ThreadProc, 0, 0 );
  }
  /* END STEP 2 */

  /* Before we initialize the GUI application, configure caches, queues and
     memory allocation strategies of Graphics Engine and Runtime Environment
     according to settings from the ewconfig.h file or Make file. */
  EwConfigRuntimeEnvironment();
  EwConfigGraphicsEngine();

  /* The following EwOpenConsole() call is optional. It opens a console window
     for printf() outputs. */
  #ifdef EW_OPEN_CONSOLE
    EwOpenConsole();
  #endif

  /* Initialize the Graphics Engine and Runtime Environment */
  EwInitGraphicsEngine( 0 );

  /* Create the applications root object ... */
  rootObject = (CoreRoot)EwNewObjectIndirect( EwApplicationClass, 0 );
  EwLockObject( rootObject );

  /* ... and initialize the application object. */
  CoreRoot__Initialize( rootObject, EwScreenSize );

  /* Open the viewer window to display the framebuffer's content */
  EwOpenViewer( rootObject );

  /* Process MS-Windows messages */
  while( GetMessage( &msg, NULL, 0, 0 ))
  {
    /* STEP 3: React on the message sent from the foreign thread */
    if ( msg.message == WM_YOUR_MESSAGE )
    {
      MessageData*       data   = (MessageData*)msg.lParam;
      ExampleDeviceClass object = EwGetAutoObject( &ExampleDevice, ExampleDeviceClass );

      /* Evaluate the data found in the associated data structure and e.g. trigger
         an Embedded Wizard System Event */
      if ( data->SomeData1 == 1234 )
        ExampleDeviceClass__TriggerEvent( object );

      /* Free the data structure associated to the message */
      free( data );
    }
    /* END STEP 3 */

    TranslateMessage( &msg );
    DispatchMessage( &msg );

    /* Process expired timers */
    EwProcessTimers();

    /* The following do/while loop is responsible for the idle processing.
       This loop is executed as long as any signals are pending and no other
       user inputs are received by the Viewer application. */
    do
    {
      /* Process the pending signals */
      EwProcessSignals();

      /* Refresh the screen, if something has changed and draw its content in
         the viewer window */
      EwUpdateViewer();

      /* After each processed message start the garbage collection */
      EwReclaimMemory();
    }
    while ( EwAnyPendingSignals() &&
      #if WINVER >= 0x0602
        !GetQueueStatus( QS_KEY | QS_MOUSE | QS_TIMER ) &&
        !GetQueueStatus( QS_TOUCH ));
      #else
        !GetQueueStatus( QS_KEY | QS_MOUSE | QS_TIMER ));
      #endif

    /* Show the memory statistic */
    #ifdef EW_PRINT_MEMORY_USAGE
      EwPrintProfilerStatistic( 0 );
    #endif
  }

  /* Finished -> release unused resources */
  EwUnlockObject( rootObject );
  EwReclaimMemory();

  /* ... and deinitialize the Graphics Engine */
  EwDoneGraphicsEngine();

  /* Show the finaly memory statistic */
  #ifdef EW_PRINT_MEMORY_USAGE
    EwPrintProfilerStatistic( 0 );
  #endif

  /* Return the exit-code of the viewer */
     return msg.wParam;
}

and also 

if ( msg.message == WM_YOUR_MESSAGE )

this above condition does not get satisfied and msg.lparam is null 

by
Hello Pidea,

I followed the discussion here and it seems that we are moving far far away from support concerning GUI development with Embedded Wizard.

It turned out, that the initial "code crash" was caused by accessing GUI code from different threads, which has to be avoided in any case.

Additionally, a tested code snippet was provided in the above discussion, that demonstrates how to post and receive message between Win32 threads.

However, all other topics concerning communication between your master and slave, between two Win32 executables or via gRPC are not related to Embedded Wizard. Let me recommend to study the documentation of Microsoft or gRPC to understand their technology. I hope for your understanding that we cannot provide free-of-charge support for third-party software stacks.

Thank you and best regards,

Manfred.
by
sure thanks for the reply
by

hi,

If i want to debug the statemennt in core.c

Is it posible to modify the core.c and take a log for the same

https://ask.embedded-wizard.de/?qa=blob&qa_blobid=17038744164630216977

by

Hello Pidea,

for debugging purpose, of course, you can modify the generated Core.c file and add some printf(), etc. code for logging purpose. Doing this, don't forget that when you generate the code again, the modifications are overwritten. However, I'm not sure whether it will help you to solve the crash problem.

From the attached screenshot I deduce that there is some invalid Task object existing in a TaskQueue. The TaskQueue refers to an object 0xDDDDDDDD which is surely not a valid object address. Such error indicates that EmWi code has been called from a foreign thread or native code has overwritten Embedded Wizard memory areas. Whatever happened, the existing Task or TaskQueue object is corrupted now.

If your application does still use threads which invoke EmWi code, I would focus on this issue to ensure that no thread does call EmWi code. Please note the parallel discussion via e-mail concerning the threads invoking ApplicationDeviceClass_HomeTriggerEvent() Embedded Wizard function. Exactly this function will create and append a new Task on a global TaskQueue (to store the event inside it). Doing this in context of a foreign thread will surely lead to the observed crash. So my question: have you solved this multi-threading issue already?

Best regards

Paul Banach

by
Hi Paul,

 

I am working on multi-threading issue. But also I want to find out the cause for crashing .

Ask Embedded Wizard

Welcome to the question and answer site for Embedded Wizard users and UI developers.

Ask your question and receive answers from the Embedded Wizard support team or from other members of the community!

Embedded Wizard Website | Privacy Policy | Imprint

...