Coverage Report

Created: 2025-06-16 06:15

/src/S2OPC/src/Common/helpers/sopc_event_handler.c
Line
Count
Source (jump to first uncovered line)
1
/*
2
 * Licensed to Systerel under one or more contributor license
3
 * agreements. See the NOTICE file distributed with this work
4
 * for additional information regarding copyright ownership.
5
 * Systerel licenses this file to you under the Apache
6
 * License, Version 2.0 (the "License"); you may not use this
7
 * file except in compliance with the License. You may obtain
8
 * a copy of the License at
9
 *
10
 *   http://www.apache.org/licenses/LICENSE-2.0
11
 *
12
 * Unless required by applicable law or agreed to in writing,
13
 * software distributed under the License is distributed on an
14
 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15
 * KIND, either express or implied.  See the License for the
16
 * specific language governing permissions and limitations
17
 * under the License.
18
 */
19
20
#include "sopc_event_handler.h"
21
22
#include "sopc_array.h"
23
#include "sopc_assert.h"
24
#include "sopc_async_queue.h"
25
#include "sopc_mem_alloc.h"
26
#include "sopc_threads.h"
27
28
static void* POISON_PILL = (void*) 0x01;
29
30
struct _SOPC_EventHandler
31
{
32
    SOPC_Looper* looper;
33
    SOPC_EventHandler_Callback* callback;
34
};
35
36
struct _SOPC_Looper
37
{
38
    SOPC_Thread thread;
39
    SOPC_AsyncQueue* queue;
40
    SOPC_Array* handlers;
41
};
42
43
struct Event
44
{
45
    SOPC_EventHandler* handler;
46
    int32_t code;
47
    uint32_t id;
48
    uintptr_t params;
49
    uintptr_t auxParam;
50
};
51
52
static void event_handler_delete(SOPC_EventHandler** handler)
53
0
{
54
0
    SOPC_Free(*handler);
55
0
}
56
57
static SOPC_ReturnStatus post(SOPC_EventHandler* handler,
58
                              int32_t event,
59
                              uint32_t eltId,
60
                              uintptr_t params,
61
                              uintptr_t auxParam,
62
                              bool asNext)
63
0
{
64
0
    if (NULL == handler)
65
0
    {
66
0
        return SOPC_STATUS_INVALID_PARAMETERS;
67
0
    }
68
0
    struct Event* ev = SOPC_Calloc(1, sizeof(struct Event));
69
70
0
    if (ev == NULL)
71
0
    {
72
0
        return SOPC_STATUS_OUT_OF_MEMORY;
73
0
    }
74
75
0
    ev->handler = handler;
76
0
    ev->code = event;
77
0
    ev->id = eltId;
78
0
    ev->params = params;
79
0
    ev->auxParam = auxParam;
80
81
0
    SOPC_ReturnStatus status = asNext ? SOPC_AsyncQueue_BlockingEnqueueFirstOut(handler->looper->queue, ev)
82
0
                                      : SOPC_AsyncQueue_BlockingEnqueue(handler->looper->queue, ev);
83
84
0
    if (status != SOPC_STATUS_OK)
85
0
    {
86
0
        SOPC_Free(ev);
87
0
    }
88
89
0
    return status;
90
0
}
91
92
static void* looper_loop(void* user_data)
93
0
{
94
0
    SOPC_AsyncQueue* queue = user_data;
95
96
0
    while (true)
97
0
    {
98
0
        void* item = NULL;
99
0
        SOPC_ReturnStatus status = SOPC_AsyncQueue_BlockingDequeue(queue, (void**) &item);
100
0
        SOPC_ASSERT(SOPC_STATUS_OK == status);
101
102
0
        if (item == POISON_PILL)
103
0
        {
104
0
            return NULL;
105
0
        }
106
107
0
        struct Event* ev = item;
108
0
        ev->handler->callback(ev->handler, ev->code, ev->id, ev->params, ev->auxParam);
109
0
        SOPC_Free(ev);
110
0
    }
111
112
0
    return NULL;
113
0
}
114
115
SOPC_EventHandler* SOPC_EventHandler_Create(SOPC_Looper* looper, SOPC_EventHandler_Callback* callback)
116
0
{
117
0
    SOPC_EventHandler* handler = SOPC_Calloc(1, sizeof(SOPC_EventHandler));
118
119
0
    if (handler == NULL)
120
0
    {
121
0
        return NULL;
122
0
    }
123
124
0
    handler->looper = looper;
125
0
    handler->callback = callback;
126
127
0
    if (!SOPC_Array_Append(looper->handlers, handler))
128
0
    {
129
0
        event_handler_delete(&handler);
130
0
        return NULL;
131
0
    }
132
133
0
    return handler;
134
0
}
135
136
uint32_t SOPC_EventHandler_Get_QueueSize(SOPC_EventHandler* handler)
137
0
{
138
0
    return (NULL == handler ? 0 : SOPC_AsyncQueue_GetSize(handler->looper->queue));
139
0
}
140
141
SOPC_ReturnStatus SOPC_EventHandler_Post(SOPC_EventHandler* handler,
142
                                         int32_t event,
143
                                         uint32_t eltId,
144
                                         uintptr_t params,
145
                                         uintptr_t auxParam)
146
0
{
147
0
    return post(handler, event, eltId, params, auxParam, false);
148
0
}
149
150
SOPC_ReturnStatus SOPC_EventHandler_PostAsNext(SOPC_EventHandler* handler,
151
                                               int32_t event,
152
                                               uint32_t eltId,
153
                                               uintptr_t params,
154
                                               uintptr_t auxParam)
155
0
{
156
0
    return post(handler, event, eltId, params, auxParam, true);
157
0
}
158
159
SOPC_Looper* SOPC_Looper_Create(const char* threadName)
160
0
{
161
0
    SOPC_Looper* looper = SOPC_Calloc(1, sizeof(SOPC_Looper));
162
0
    SOPC_AsyncQueue* queue = NULL;
163
0
    SOPC_Array* handlers =
164
0
        SOPC_Array_Create(sizeof(SOPC_EventHandler*), 0, (SOPC_Array_Free_Func*) event_handler_delete);
165
166
0
    if (looper == NULL || handlers == NULL || SOPC_AsyncQueue_Init(&queue, threadName) != SOPC_STATUS_OK ||
167
0
        SOPC_Thread_Create(&looper->thread, looper_loop, queue, threadName) != SOPC_STATUS_OK)
168
0
    {
169
0
        SOPC_AsyncQueue_Free(&queue);
170
0
        SOPC_Array_Delete(handlers);
171
0
        SOPC_Free(looper);
172
0
        return NULL;
173
0
    }
174
175
0
    looper->queue = queue;
176
0
    looper->handlers = handlers;
177
178
0
    return looper;
179
0
}
180
181
void SOPC_Looper_Delete(SOPC_Looper* looper)
182
0
{
183
0
    if (looper == NULL)
184
0
    {
185
0
        return;
186
0
    }
187
188
0
    SOPC_ReturnStatus status = SOPC_AsyncQueue_BlockingEnqueue(looper->queue, POISON_PILL);
189
0
    SOPC_ASSERT(status == SOPC_STATUS_OK);
190
191
0
    status = SOPC_Thread_Join(&looper->thread);
192
0
    SOPC_ASSERT(status == SOPC_STATUS_OK);
193
194
0
    SOPC_AsyncQueue_Free(&looper->queue);
195
0
    SOPC_Array_Delete(looper->handlers);
196
0
    SOPC_Free(looper);
197
0
}