# [Legato] Layered Publish-Subscribe Handlers
> Legato 官網對 Layered Publish-Subscribe Handlers 的說明:https://docs.legato.io/latest/c_eventLoop.html#c_event_layeredPublishSubscribe
在使用 Legato 框架做開發時,若需要讓 client 因 server 發佈某個 event 而去執行 handler function,這時就可以用 Legato 的 Layered Publish-Subscribe Handler 機制。
Layered Publish-Subscribe Handlers 的 `Layered` 是指有兩層的 handler,第一層 handler 由 server 端執行,第二層 handler 由 client 端執行,當第一層 handler 執行完就會去呼叫第二層 handler。
基本流程:
1. Server 發布一個 event
2. Server 先執行第一層 handler,並且有需要的話可以在第一層 handler 內處理 event data。然後在第一層 handler 內呼叫第二層 handler,並且將剛剛處理過的 event data 一起傳給第二層 handler
3. 最後 client 執行第二層 handler。
在介紹 Layered Publish-Subscribe Handlers 的用法之前,必須要先介紹在 `.api` 檔案內使用 `EVENT` 和 `HANDLER` 的用法。
## `EVENT` & `HANDLER` in API File
我們可以在 `.api` 檔案裡面設定 `EVENT` 和 `HANDLER` 給 client。由於官網對這兩者實際的用途好像說明不多,查了 Legato github 裡面的 sample code,`EVENT` 和 `HANDLER` 似乎主要都是用在 [Layered Publish-Subscribe Handlers](https://docs.legato.io/latest/c_eventLoop.html#c_event_layeredPublishSubscribe)。所以以下主要以 [Layered Publish-Subscribe Handlers](https://docs.legato.io/latest/c_eventLoop.html#c_event_layeredPublishSubscribe) 的角度來介紹關於在 `.api` 裡面使用 `EVENT` 和 `HANDLER` 的用法。
### Syntax
#### `HANDLER`
以下是在 `.api` 內定義一個 `HANDLER` 的語法:
```api
HANDLER <handlerType>
(
[<parameterList>]
);
```
- `parameterList` 可以是一個參數,或者是多個參數(由逗號分開),或者如果沒有參數的話也可以是空的。
- `parameterList` 僅能是 scalar type 或者是 `string` type。
- 所有的 parameter 都應該是 `IN` parameters
Example:
```api
HANDLER MyHandler
(
int32 n1,
int32 n2
);
```
#### `EVENT`
以下是在 `.api` 內定義一個 `EVENT` 的語法:
```api
EVENT <eventType>
(
<parameterList>
);
```
- `parameterList` 可以是一個參數,或者是多個參數(由逗號分開)。
- 只要對 function 是合法的,都可以是參數。
- 其中一個參數一定要是 handler(也就是處理這個 `EVENT` 的 `HANDLER`)。
- The parameters are used when registering a handler for the specified event.
Example:
```
EVENT MyEvent
(
int32 eventParam1, // Used when registering the handler i.e. it is
// passed into the generated ADD_HANDLER function.
MyHandler handler // 每個 EVENT 一定要有一個參數是 HANDLER
);
```
:::info
定義在 API 檔裡面的 `HANDLER` 和 `EVENT`,若是用在 Layered Publish-Subscribe Handlers 的情境,Handler 就是指第二層的 handler,是由 client 實做的,而 Event 則是由 server 所發布。
:::
## `EVENT` and `HANDLER` in C
接下來看 `.api` 裡面的 `EVENT` 和 `HANDLER` 在 C 語言會被轉換成什麼樣子。假設有以下的 project structure:
```
~/eventHandlerAPI
├── clientApp
│ ├── layeredHandlerClientApp.adef
│ └── layeredHandlerClientComp
│ ├── Component.cdef
│ └── layeredHandlerClient.c
├── serverApp
│ ├── layeredHandlerServerApp.adef
│ └── layeredHandlerServerComp
│ ├── Component.cdef
│ └── layeredHandlerServer.c
└── serverAPI.api
```
`serverAPI.api`
```api
HANDLER MyHandler
(
int32 myHandlerParam1 IN,
int32 myHandlerParam2 IN
);
EVENT MyEvent
(
int32 myEventParam1,
int32 myEventParam2,
int32 myEventParam3,
MyHandler handler
);
```
`serverApp/layeredHandlerServerComp/Component.cdef`
在這裡可以看到 server 端的 interface 名稱是 `serverInterface`:
```cdef
sources:
{
layeredHandlerServer.c
}
provides:
{
api:
{
serverInterface = serverAPI.api
}
}
```
`clientApp/layeredHandlerClientComp/Component.cdef`
在這裡可以看到 client 端的 interface 名稱是 `clientInterface`:
```cdef
sources:
{
layeredHandlerClient.c
}
requires:
{
api:
{
clientInterface = serverAPI.api
}
}
```
對這兩個 App 執行 `mkapp`:
```bash
~/eventHandlerAPI$ mkapp -t simulation -i ./ serverApp/layeredHandlerServerApp.adef
~/eventHandlerAPI$ mkapp -t simulation -i ./ clientApp/layeredHandlerClientApp.adef
```
執行完以上步驟後,會產生 `_build_layeredHandlerServerApp` 和 `_build_layeredHandlerClientApp` 這兩個資料夾。
`_build_layeredHandlerServerApp/simulation/api/042696e536911f5b64f43e65f41e5464/serverAPI_common.h`
```cpp=21
//--------------------------------------------------------------------------------------------------
/**
* Reference type used by Add/Remove functions for EVENT 'serverAPI_MyEvent'
*/
//--------------------------------------------------------------------------------------------------
typedef struct serverAPI_MyEventHandler* serverAPI_MyEventHandlerRef_t;
//--------------------------------------------------------------------------------------------------
/**
*/
//--------------------------------------------------------------------------------------------------
typedef void (*serverAPI_MyHandlerFunc_t)
(
int32_t myHandlerParam1,
///<
int32_t myHandlerParam2,
///<
void* contextPtr
///<
);
```
`_build_layeredHandlerServerApp/simulation/api/042696e536911f5b64f43e65f41e5464/server/serverInterface_server.h`
```cpp=52
//--------------------------------------------------------------------------------------------------
/**
*/
//--------------------------------------------------------------------------------------------------
typedef serverAPI_MyHandlerFunc_t serverInterface_MyHandlerFunc_t;
//--------------------------------------------------------------------------------------------------
/**
* Reference type used by Add/Remove functions for EVENT 'serverInterface_MyEvent'
*/
//--------------------------------------------------------------------------------------------------
typedef serverAPI_MyEventHandlerRef_t serverInterface_MyEventHandlerRef_t;
//--------------------------------------------------------------------------------------------------
/**
* Add handler function for EVENT 'serverInterface_MyEvent'
*/
//--------------------------------------------------------------------------------------------------
serverInterface_MyEventHandlerRef_t serverInterface_AddMyEventHandler
(
int32_t myEventParam1,
///< [IN]
int32_t myEventParam2,
///< [IN]
int32_t myEventParam3,
///< [IN]
serverInterface_MyHandlerFunc_t handlerPtr,
///< [IN]
void* contextPtr
///< [IN]
);
//--------------------------------------------------------------------------------------------------
/**
* Remove handler function for EVENT 'serverInterface_MyEvent'
*/
//--------------------------------------------------------------------------------------------------
void serverInterface_RemoveMyEventHandler
(
serverInterface_MyEventHandlerRef_t handlerRef
///< [IN]
);
```
`_build_layeredHandlerClientApp/simulation/api/042696e536911f5b64f43e65f41e5464/serverAPI_common.h`
```cpp=21
//--------------------------------------------------------------------------------------------------
/**
* Reference type used by Add/Remove functions for EVENT 'serverAPI_MyEvent'
*/
//--------------------------------------------------------------------------------------------------
typedef struct serverAPI_MyEventHandler* serverAPI_MyEventHandlerRef_t;
//--------------------------------------------------------------------------------------------------
/**
*/
//--------------------------------------------------------------------------------------------------
typedef void (*serverAPI_MyHandlerFunc_t)
(
int32_t myHandlerParam1,
///<
int32_t myHandlerParam2,
///<
void* contextPtr
///<
);
```
`_build_layeredHandlerClientApp/simulation/api/042696e536911f5b64f43e65f41e5464/client/clientInterface_interface.h`
```cpp=122
//--------------------------------------------------------------------------------------------------
/**
*/
//--------------------------------------------------------------------------------------------------
typedef serverAPI_MyHandlerFunc_t clientInterface_MyHandlerFunc_t;
//--------------------------------------------------------------------------------------------------
/**
* Reference type used by Add/Remove functions for EVENT 'clientInterface_MyEvent'
*/
//--------------------------------------------------------------------------------------------------
typedef serverAPI_MyEventHandlerRef_t clientInterface_MyEventHandlerRef_t;
//--------------------------------------------------------------------------------------------------
/**
* Add handler function for EVENT 'clientInterface_MyEvent'
*/
//--------------------------------------------------------------------------------------------------
clientInterface_MyEventHandlerRef_t clientInterface_AddMyEventHandler
(
int32_t myEventParam1,
///< [IN]
int32_t myEventParam2,
///< [IN]
int32_t myEventParam3,
///< [IN]
clientInterface_MyHandlerFunc_t handlerPtr,
///< [IN]
void* contextPtr
///< [IN]
);
//--------------------------------------------------------------------------------------------------
/**
* Remove handler function for EVENT 'clientInterface_MyEvent'
*/
//--------------------------------------------------------------------------------------------------
void clientInterface_RemoveMyEventHandler
(
clientInterface_MyEventHandlerRef_t handlerRef
///< [IN]
);
```
可以看到 server 端跟 client 端都會產生以下的 prototype:
1. `<interface_name>_Add<event_name>Handler`
2. `<interface_name>_Remove<event_name>Handler`
3.
```cpp
type void (*<interface_name>_<handler_name>Func_t)
(
<handler parameter_list>,
void *contextPtr
);
```
以上三者在 Layered Publish-Subscribe Handlers 的使用情境:
- `<handler_name>Func_t`:
- 就是前面所說的 second layer handler function
- 由 client 端實作
- `Add<event_name>Handler` 和 `Remove<event_name>Handler`:
- 兩者皆由 server 端實作
- Server 在 `Add<event_name>Handler` 內呼叫 [`le_event_AddLayeredHandler`](https://docs.legato.io/latest/le__eventLoop_8h.html#a8b906d38935f64953482f42c745e1c18) 來指定:
1. Event ID
2. 前項的 event 被發佈後,server 欲執行的 first layer handler
3. Second layer handler
- Client 使用 `Add<event_name>Handler` 來:
1. 傳送 event parameter
2. 指定說若 server 發佈 event 了,那要呼叫哪個 second layer handler function
3. 設定欲傳給 second layer handler 使用的 context
- Client 使用 `Remove<event_name>Handler` 來取消 second layer handler
## Layered Publish-Subscribe Handlers
### 實作流程
<!-- #### 1. 假設有以下 `.api` 檔案:
```api
HANDLER MyHandler
(
int32 myHandlerParam1 IN,
int32 myHandlerParam2 IN
);
// 這是 second layer handler,由 client 實作此 handler function
EVENT MyEvent
(
int32 myEventParam1,
int32 myEventParam2,
int32 myEventParam3,
MyHandler handler
);
// 此 event 由 server 發佈
```
#### 2. Server 實作 First Layer Handler、`Add<event>Handler`、以及 `Remove<event>Handler`
```cpp
void FirstLayerHandlerFunc
(
void *reportPtr,
void *secondLayerHandlerFunc
)
{
// do something in the first layer handler
serverInterface_MyHandlerFunc_t clientHandlerFunc = secondLayerHandlerFunc;
// 在 first layer handler 最後要呼叫 second layer handler
clientHandlerFunc(myHandlerParam1, myHandlerParam2, le_event_GetContextPtr());
// 我們要用 le_event_GetContextPtr() 將 contextPtr 傳到 second layer handler
}
```
:::info
First Layer Handler 的 Prototype:
```cpp
typedef void (*le_event_LayeredHandlerFunc_t) ( void *reportPtr,
void *secondLayerFunc
)
```
:::
-->

之後,當 server 發佈該 event:
1. Server 執行 first layer handler,並在 first layer handler 內最後呼叫 second layer handler
2. Client 執行 second layer handler
最後,若 client 呼叫 `Remove<event>Handler`,server 就會執行 `Remove<event>Handler`。
### Example
以下例子,`EVENT` 有三個參數,都是 `int32_t`,`HANDLER` 則有兩個 `int32_t` 參數。
此外,event data 用以下 structure 來傳遞:
```cpp
typedef struct
{
int32_t n1;
int32_t n2;
int32_t n3;
} MyEventData_t;
```
Server 總共會發布五次 event,每次發布 event 時會連同 event data 一起發布,並且在 first layer handler 內將 event data 的 `n1` 和 `n3` 相加,並傳入 second layer handler 的第一個參數,以及將 event data 的 `n2` 傳入 second layer handler 的第二個參數。
Client 的 second layer handler 被觸發後,就會將收到的兩個參數印出來。
#### Project Structure
```
~/layeredHandlerAPI$ tree
.
├── clientApp
│ ├── layeredHandlerClientApp.adef
│ └── layeredHandlerClientComp
│ ├── Component.cdef
│ └── layeredHandlerClient.c
├── serverApp
│ ├── layeredHandlerServerApp.adef
│ └── layeredHandlerServerComp
│ ├── Component.cdef
│ └── layeredHandlerServer.c
└── serverAPI.api
```
#### `serverAPI.api`
```api
HANDLER MyHandler
(
int32 myHandlerParam1 IN,
int32 myHandlerParam2 IN
);
EVENT MyEvent
(
int32 myEventParam1,
int32 myEventParam2,
int32 myEventParam3,
MyHandler handler
);
```
#### `serverApp/layeredHandlerServerApp.adef`
```adef
executables:
{
layeredHandlerServerExec = ( layeredHandlerServerComp )
}
processes:
{
run:
{
layeredHandlerServerProc = ( layeredHandlerServerExec )
}
}
extern:
{
interfaceAlias = layeredHandlerServerExec.layeredHandlerServerComp.serverInterface
}
```
#### `serverApp/layeredHandlerServerComp/Component.cdef`
```cdef
sources:
{
layeredHandlerServer.c
}
provides:
{
api:
{
serverInterface = serverAPI.api
}
}
```
#### `serverApp/layeredHandlerServerComp/layeredHandlerServer.c`
```cpp
#include "legato.h"
#include "interfaces.h"
static le_event_Id_t myTestEvent;
static le_thread_Ref_t workerThreadRef = NULL;
static le_sem_Ref_t semaphoreRef = NULL;
typedef struct
{
int32_t n1;
int32_t n2;
int32_t n3;
} MyEventData_t;
MyEventData_t clientSideEventParams = {.n1 = 0, .n2 = 0, .n3 = 0};
// function prototype for FirstLayerHandlerFunc:
// typedef void(* le_event_LayeredHandlerFunc_t) (void *reportPtr, void *secondLayerFunc)
static void FirstLayerHandlerFunc
(
void *reportPtr,
void *secondLayerHandlerFunc
)
{
MyEventData_t *eventDataPtr = (MyEventData_t *) reportPtr;
int32_t myHandlerParam1 = eventDataPtr->n1 + eventDataPtr->n3;
int32_t myHandlerParam2 = eventDataPtr->n2;
LE_INFO("[SERVER] inside FirstLayerHandlerFunc, n1: %d, n2: %d", eventDataPtr->n1, eventDataPtr->n2);
serverInterface_MyHandlerFunc_t clientHandlerFunc = secondLayerHandlerFunc;
// call client handler
// 我們只能使用 le_event_GetContextPtr() 來傳遞 contextPtr
clientHandlerFunc(myHandlerParam1, myHandlerParam2, le_event_GetContextPtr());
}
// the server side Add<event_name>Handler function will not be called
// until the client has called the client side Add<event_name>Handler function
serverInterface_MyEventHandlerRef_t serverInterface_AddMyEventHandler
(
int32_t myEventParam1,
int32_t myEventParam2,
int32_t myEventParam3,
serverInterface_MyHandlerFunc_t handlerPtr,
void *contextPtr
)
{
LE_INFO("[SERVER] inside serverInterface_AddMyEventHandler");
LE_INFO("Event Paramters from Client: myEventParam1: %d, myEventParam2: %d, myEventParam3: %d", myEventParam1, myEventParam2, myEventParam3);
clientSideEventParams.n1 = myEventParam1;
clientSideEventParams.n2 = myEventParam2;
clientSideEventParams.n3 = myEventParam3;
LE_INFO("value of contextPtr: %p", contextPtr);
// 設定 event、first layer handler、以及 second layer handler
le_event_HandlerRef_t handlerRef = le_event_AddLayeredHandler("MyLayeredHandler", myTestEvent, FirstLayerHandlerFunc, (le_event_HandlerFunc_t) handlerPtr);
// 只能用這方式處理 contextPtr
le_event_SetContextPtr(handlerRef, contextPtr);
le_sem_Post(semaphoreRef);
return (serverInterface_MyEventHandlerRef_t) (handlerRef);
}
void serverInterface_RemoveMyEventHandler
(
serverInterface_MyEventHandlerRef_t addHandlerRef
)
{
LE_INFO("[SERVER] inside serverInterface_RemoveMyEventHandler");
le_event_RemoveHandler((le_event_HandlerRef_t) addHandlerRef);
}
void *workerThreadFunc(void *context)
{
LE_INFO("[SERVER] inside wokerThreadFunc");
MyEventData_t eventData = {.n1 = 2, .n2 = 5000, .n3 = 500};
LE_INFO("address of evenData: %p", (void *) &eventData);
// wait until the AddHandler function actually starts
le_sem_Wait(semaphoreRef);
for (int i = 0; i < 5; ++i)
{
le_event_Report(myTestEvent, &eventData, sizeof(eventData));
LE_INFO("report event (%d)", i + 1);
eventData.n1 += clientSideEventParams.n1;
eventData.n2 += clientSideEventParams.n2;
eventData.n3 += clientSideEventParams.n3;
le_thread_Sleep(2);
}
return NULL;
}
COMPONENT_INIT
{
LE_INFO("[SERVER] inside COMPONENT_INIT");
myTestEvent = le_event_CreateId("MyTestingEvent", sizeof(MyEventData_t));
semaphoreRef = le_sem_Create("MySemaphore", 0);
workerThreadRef = le_thread_Create("MyWorkerThread", workerThreadFunc, NULL);
le_thread_Start(workerThreadRef);
LE_INFO("[SERVER] just started the worker thread");
}
```
#### `clientApp/layeredHandlerClientApp.adef`
```adef
executables:
{
layeredHandlerClientExec = ( layeredHandlerClientComp )
}
processes:
{
run:
{
layeredHandlerClientProc = ( layeredHandlerClientExec )
}
}
bindings:
{
layeredHandlerClientExec.layeredHandlerClientComp.clientInterface -> serverApp.interfaceAlias
}
```
#### `clientApp/layeredHandlerClientComp/Component.cdef`
```cdef
sources:
{
layeredHandlerClient.c
}
requires:
{
api:
{
clientInterface = serverAPI.api
}
}
```
#### `clientApp/layeredHandlerClientComp/layeredHandlerClient.c`
```cpp
#include "legato.h"
#include "interfaces.h"
static int secondLayeredHandlerCalledTime = 0;
static le_thread_Ref_t workerThreadRef = NULL;
static clientInterface_MyEventHandlerRef_t MyEventHandlerRef;
// the handlerRef can be used to remove handler
// function prototype of the secondLayerHandlerFunc:
// void clientInterface_MyHandlerFunc_t(int32_t myHandlerParam1, int32_t myHandlerParam2, void *contextPtr)
void secondLayerHandlerFunc(int32_t myHandlerParam1, int32_t myHandlerParam2, void *contextPtr)
{
LE_INFO("[CLIENT] inside secondLayerHandlerFunc");
secondLayeredHandlerCalledTime += 1;
LE_INFO("myHandlerParam1: %d, myHandlerParam2: %d, contextPtr: %p, *contextPtr: %s", myHandlerParam1, myHandlerParam2, contextPtr, (char *) contextPtr);
if (secondLayeredHandlerCalledTime == 5)
{
le_thread_Exit(NULL);
}
}
void workerThreadDestructor(void *context)
{
LE_INFO("[CLIENT] inside workerThreadDestructor");
LE_INFO("[CLIENT] is going to unregister the second layered handler");
clientInterface_RemoveMyEventHandler(MyEventHandlerRef);
LE_INFO("[CLIENT] just unregistered the second layered handler");
}
void *workerThreadFunc(void *context)
{
LE_INFO("[CLIENT] inside workerThreadFunc");
clientInterface_ConnectService();
int32_t myEventParam1 = 10, myEventParam2 = 20, myEventParam3 = 30;
char *msgFromClient = "Hello from Client";
LE_INFO("[CLIENT] is going to call the Add<event_name>Handler function");
MyEventHandlerRef = clientInterface_AddMyEventHandler(myEventParam1, myEventParam2, myEventParam3, secondLayerHandlerFunc, (void *) msgFromClient);
le_thread_AddDestructor(workerThreadDestructor, NULL);
le_event_RunLoop();
return NULL;
}
COMPONENT_INIT
{
LE_INFO("[CLIENT] inside COMPONENT_INIT");
workerThreadRef = le_thread_Create("WorkerThread", workerThreadFunc, NULL);
le_thread_Start(workerThreadRef);
}
```
#### Result
```
Sep 24 07:44:20 simulation user.info TelAF: INFO | layeredHandlerServerProc[2758]/layeredHandlerServerComp T=main | layeredHandlerServer.c _layeredHandlerServerComp_COMPONENT_INIT() 107 | [SERVER] inside COMPONENT_INIT
Sep 24 07:44:20 simulation user.info TelAF: INFO | layeredHandlerServerProc[2758]/layeredHandlerServerComp T=main | layeredHandlerServer.c _layeredHandlerServerComp_COMPONENT_INIT() 116 | [SERVER] just started the worker thread
Sep 24 07:44:20 simulation user.info TelAF: INFO | layeredHandlerServerProc[2758]/layeredHandlerServerComp T=MyWorkerThread | layeredHandlerServer.c workerThreadFunc() 79 | [SERVER] inside wokerThreadFunc
Sep 24 07:44:21 simulation user.info TelAF: INFO | layeredHandlerClientProc[2779]/layeredHandlerClientComp T=main | layeredHandlerClient.c _layeredHandlerClientComp_COMPONENT_INIT() 58 | [CLIENT] inside COMPONENT_INIT
Sep 24 07:44:21 simulation user.info TelAF: INFO | layeredHandlerClientProc[2779]/layeredHandlerClientComp T=WorkerThread | layeredHandlerClient.c workerThreadFunc() 36 | [CLIENT] inside workerThreadFunc
Sep 24 07:44:21 simulation user.info TelAF: INFO | layeredHandlerClientProc[2779]/layeredHandlerClientComp T=WorkerThread | layeredHandlerClient.c workerThreadFunc() 42 | Address of msgFromClient: 0x14f809d19b89
Sep 24 07:44:21 simulation user.info TelAF: INFO | layeredHandlerClientProc[2779]/layeredHandlerClientComp T=WorkerThread | layeredHandlerClient.c workerThreadFunc() 44 | [CLIENT] is going to call the Add<event_name>Handler function
Sep 24 07:44:21 simulation user.info TelAF: INFO | layeredHandlerServerProc[2758]/layeredHandlerServerComp T=main | layeredHandlerServer.c serverInterface_AddMyEventHandler() 48 | [SERVER] inside serverInterface_AddMyEventHandler
Sep 24 07:44:21 simulation user.info TelAF: INFO | layeredHandlerServerProc[2758]/layeredHandlerServerComp T=main | layeredHandlerServer.c serverInterface_AddMyEventHandler() 50 | Event Paramters from Client: myEventParam1: 10, myEventParam2: 20, myEventParam3: 30
Sep 24 07:44:21 simulation user.info TelAF: INFO | layeredHandlerServerProc[2758]/layeredHandlerServerComp T=main | layeredHandlerServer.c serverInterface_AddMyEventHandler() 55 | The address pointed by contextPtr: 0x148f5f6f13b0
Sep 24 07:44:21 simulation user.info TelAF: INFO | layeredHandlerServerProc[2758]/layeredHandlerServerComp T=MyWorkerThread | layeredHandlerServer.c workerThreadFunc() 88 | report event (1)
Sep 24 07:44:21 simulation user.info TelAF: INFO | layeredHandlerServerProc[2758]/layeredHandlerServerComp T=main | layeredHandlerServer.c FirstLayerHandlerFunc() 29 | [SERVER] inside FirstLayerHandlerFunc, n1: 2, n2: 5000
Sep 24 07:44:21 simulation user.info TelAF: INFO | layeredHandlerClientProc[2779]/layeredHandlerClientComp T=WorkerThread | layeredHandlerClient.c secondLayerHandlerFunc() 13 | [CLIENT] inside secondLayerHandlerFunc
Sep 24 07:44:21 simulation user.info TelAF: INFO | layeredHandlerClientProc[2779]/layeredHandlerClientComp T=WorkerThread | layeredHandlerClient.c secondLayerHandlerFunc() 16 | myHandlerParam1: 502, myHandlerParam2: 5000
Sep 24 07:44:21 simulation user.info TelAF: INFO | layeredHandlerClientProc[2779]/layeredHandlerClientComp T=WorkerThread | layeredHandlerClient.c secondLayerHandlerFunc() 17 | contextPtr: 0x14f809d19b89, *contextPtr: Hello from Client
Sep 24 07:44:23 simulation user.info TelAF: INFO | layeredHandlerServerProc[2758]/layeredHandlerServerComp T=MyWorkerThread | layeredHandlerServer.c workerThreadFunc() 88 | report event (2)
Sep 24 07:44:23 simulation user.info TelAF: INFO | layeredHandlerServerProc[2758]/layeredHandlerServerComp T=main | layeredHandlerServer.c FirstLayerHandlerFunc() 29 | [SERVER] inside FirstLayerHandlerFunc, n1: 12, n2: 5020
Sep 24 07:44:23 simulation user.info TelAF: INFO | layeredHandlerClientProc[2779]/layeredHandlerClientComp T=WorkerThread | layeredHandlerClient.c secondLayerHandlerFunc() 13 | [CLIENT] inside secondLayerHandlerFunc
Sep 24 07:44:23 simulation user.info TelAF: INFO | layeredHandlerClientProc[2779]/layeredHandlerClientComp T=WorkerThread | layeredHandlerClient.c secondLayerHandlerFunc() 16 | myHandlerParam1: 542, myHandlerParam2: 5020
Sep 24 07:44:23 simulation user.info TelAF: INFO | layeredHandlerClientProc[2779]/layeredHandlerClientComp T=WorkerThread | layeredHandlerClient.c secondLayerHandlerFunc() 17 | contextPtr: 0x14f809d19b89, *contextPtr: Hello from Client
Sep 24 07:44:25 simulation user.info TelAF: INFO | layeredHandlerServerProc[2758]/layeredHandlerServerComp T=MyWorkerThread | layeredHandlerServer.c workerThreadFunc() 88 | report event (3)
Sep 24 07:44:25 simulation user.info TelAF: INFO | layeredHandlerServerProc[2758]/layeredHandlerServerComp T=main | layeredHandlerServer.c FirstLayerHandlerFunc() 29 | [SERVER] inside FirstLayerHandlerFunc, n1: 22, n2: 5040
Sep 24 07:44:25 simulation user.info TelAF: INFO | layeredHandlerClientProc[2779]/layeredHandlerClientComp T=WorkerThread | layeredHandlerClient.c secondLayerHandlerFunc() 13 | [CLIENT] inside secondLayerHandlerFunc
Sep 24 07:44:25 simulation user.info TelAF: INFO | layeredHandlerClientProc[2779]/layeredHandlerClientComp T=WorkerThread | layeredHandlerClient.c secondLayerHandlerFunc() 16 | myHandlerParam1: 582, myHandlerParam2: 5040
Sep 24 07:44:25 simulation user.info TelAF: INFO | layeredHandlerClientProc[2779]/layeredHandlerClientComp T=WorkerThread | layeredHandlerClient.c secondLayerHandlerFunc() 17 | contextPtr: 0x14f809d19b89, *contextPtr: Hello from Client
Sep 24 07:44:27 simulation user.info TelAF: INFO | layeredHandlerServerProc[2758]/layeredHandlerServerComp T=MyWorkerThread | layeredHandlerServer.c workerThreadFunc() 88 | report event (4)
Sep 24 07:44:27 simulation user.info TelAF: INFO | layeredHandlerServerProc[2758]/layeredHandlerServerComp T=main | layeredHandlerServer.c FirstLayerHandlerFunc() 29 | [SERVER] inside FirstLayerHandlerFunc, n1: 32, n2: 5060
Sep 24 07:44:27 simulation user.info TelAF: INFO | layeredHandlerClientProc[2779]/layeredHandlerClientComp T=WorkerThread | layeredHandlerClient.c secondLayerHandlerFunc() 13 | [CLIENT] inside secondLayerHandlerFunc
Sep 24 07:44:27 simulation user.info TelAF: INFO | layeredHandlerClientProc[2779]/layeredHandlerClientComp T=WorkerThread | layeredHandlerClient.c secondLayerHandlerFunc() 16 | myHandlerParam1: 622, myHandlerParam2: 5060
Sep 24 07:44:27 simulation user.info TelAF: INFO | layeredHandlerClientProc[2779]/layeredHandlerClientComp T=WorkerThread | layeredHandlerClient.c secondLayerHandlerFunc() 17 | contextPtr: 0x14f809d19b89, *contextPtr: Hello from Client
Sep 24 07:44:29 simulation user.info TelAF: INFO | layeredHandlerServerProc[2758]/layeredHandlerServerComp T=MyWorkerThread | layeredHandlerServer.c workerThreadFunc() 88 | report event (5)
Sep 24 07:44:29 simulation user.info TelAF: INFO | layeredHandlerServerProc[2758]/layeredHandlerServerComp T=main | layeredHandlerServer.c FirstLayerHandlerFunc() 29 | [SERVER] inside FirstLayerHandlerFunc, n1: 42, n2: 5080
Sep 24 07:44:29 simulation user.info TelAF: INFO | layeredHandlerClientProc[2779]/layeredHandlerClientComp T=WorkerThread | layeredHandlerClient.c secondLayerHandlerFunc() 13 | [CLIENT] inside secondLayerHandlerFunc
Sep 24 07:44:29 simulation user.info TelAF: INFO | layeredHandlerClientProc[2779]/layeredHandlerClientComp T=WorkerThread | layeredHandlerClient.c secondLayerHandlerFunc() 16 | myHandlerParam1: 662, myHandlerParam2: 5080
Sep 24 07:44:29 simulation user.info TelAF: INFO | layeredHandlerClientProc[2779]/layeredHandlerClientComp T=WorkerThread | layeredHandlerClient.c secondLayerHandlerFunc() 17 | contextPtr: 0x14f809d19b89, *contextPtr: Hello from Client
Sep 24 07:44:29 simulation user.info TelAF: INFO | layeredHandlerClientProc[2779]/layeredHandlerClientComp T=WorkerThread | layeredHandlerClient.c workerThreadDestructor() 27 | [CLIENT] inside workerThreadDestructor
Sep 24 07:44:29 simulation user.info TelAF: INFO | layeredHandlerClientProc[2779]/layeredHandlerClientComp T=WorkerThread | layeredHandlerClient.c workerThreadDestructor() 29 | [CLIENT] is going to unregister the second layered handler
Sep 24 07:44:29 simulation user.info TelAF: INFO | layeredHandlerServerProc[2758]/layeredHandlerServerComp T=main | layeredHandlerServer.c serverInterface_RemoveMyEventHandler() 73 | [SERVER] inside serverInterface_RemoveMyEventHandler
Sep 24 07:44:29 simulation user.info TelAF: INFO | layeredHandlerClientProc[2779]/layeredHandlerClientComp T=WorkerThread | layeredHandlerClient.c workerThreadDestructor() 31 | [CLIENT] just unregistered the second layered handler
```