open62541 1.4.15
Open source implementation of OPC UA
Loading...
Searching...
No Matches
eventloop.h
Go to the documentation of this file.
1/** This Source Code Form is subject to the terms of the Mozilla Public
2 * License, v. 2.0. If a copy of the MPL was not distributed with this
3 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
4 *
5 * Copyright 2021 (c) Fraunhofer IOSB (Author: Julius Pfrommer)
6 * Copyright 2021 (c) Fraunhofer IOSB (Author: Jan Hermes)
7 */
8
9#ifndef UA_EVENTLOOP_H_
10#define UA_EVENTLOOP_H_
11
12#include <open62541/types.h>
14#include <open62541/util.h>
16
18
19struct UA_EventLoop;
21
22struct UA_EventSource;
24
27
30
31
32
37
38
39
40typedef void (*UA_Callback)(void *application, void *context);
41
42/** Delayed callbacks are executed not when they are registered, but in the
43 * following EventLoop cycle */
44typedef struct UA_DelayedCallback {
45 struct UA_DelayedCallback *next; /* Singly-linked list */
48 void *context;
50
51typedef enum {
55 UA_EVENTLOOPSTATE_STOPPING /* Stopping in progress, needs EventLoop
56 * cycles to finish */
58
60 /* Configuration
61 * ~~~~~~~~~~~~~~~
62 * The configuration should be set before the EventLoop is started */
63
65 UA_KeyValueMap *params; /* See the implementation-specific documentation */
66
67 /* EventLoop Lifecycle
68 * ~~~~~~~~~~~~~~~~~~~~
69 * The EventLoop state also controls the state of the configured
70 * EventSources. Stopping the EventLoop gracefully closes e.g. the open
71 * network connections. The only way to process incoming events is to call
72 * the 'run' method. Events are then triggering their respective callbacks
73 * from within that method.*/
74
75 const volatile UA_EventLoopState state; /* Only read the state from outside */
76
77 /* Start the EventLoop and start all already registered EventSources */
79
80 /* Stop all EventSources. This is asynchronous and might need a few
81 * iterations of the main-loop to succeed. */
82 void (*stop)(UA_EventLoop *el);
83
84 /* Process events for at most "timeout" ms or until an unrecoverable error
85 * occurs. If timeout==0, then only already received events are
86 * processed. */
88
89 /* Clean up the EventLoop and free allocated memory. Can fail if the
90 * EventLoop is not stopped. */
92
93 /* EventLoop Time Domain
94 * ~~~~~~~~~~~~~~~~~~~~~
95 * Each EventLoop instance can manage its own time domain. This affects the
96 * execution of timed/cyclic callbacks and time-based sending of network
97 * packets (if this is implemented). Managing independent time domains is
98 * important when different parts of a system a synchronized to different
99 * external (network-wide) clocks.
100 *
101 * Note that the logger configured in the EventLoop generates timestamps
102 * internally as well. If the logger uses a different time domain than the
103 * EventLoop, discrepancies may appear in the logs.
104 *
105 * The time domain of the EventLoop is exposed via the following functons.
106 * See `open62541/types.h` for the documentation of their equivalent
107 * globally defined functions. */
108
109 UA_DateTime (*dateTime_now)(UA_EventLoop *el);
112
113 /* Timed Callbacks
114 * ~~~~~~~~~~~~~~~
115 * Cyclic callbacks are executed regularly with an interval. A timed
116 * callback is executed only once. The timer subsystem always uses the
117 * monotonic clock. */
118
119 /* Time of the next cyclic callback. Returns the max DateTime if no cyclic
120 * callback is registered. Returns the current monotonic time if a delayed
121 * callback is registered for immediate execution. */
122 UA_DateTime (*nextCyclicTime)(UA_EventLoop *el);
123
124 /* The execution interval is in ms. Returns the callbackId if the pointer is
125 * non-NULL. */
127 (*addCyclicCallback)(UA_EventLoop *el, UA_Callback cb, void *application,
128 void *data, UA_Double interval_ms, UA_DateTime *baseTime,
129 UA_TimerPolicy timerPolicy, UA_UInt64 *callbackId);
130
133 UA_Double interval_ms, UA_DateTime *baseTime,
134 UA_TimerPolicy timerPolicy);
135
137
138 /* Like a cyclic callback, but executed only once */
140 (*addTimedCallback)(UA_EventLoop *el, UA_Callback cb, void *application,
141 void *data, UA_DateTime date, UA_UInt64 *callbackId);
142
143 /* Delayed Callbacks
144 * ~~~~~~~~~~~~~~~~~
145 * Delayed callbacks are executed once in the next iteration of the
146 * EventLoop and then deregistered automatically. A typical use case is to
147 * delay a resource cleanup to a point where it is known that the resource
148 * has no remaining users.
149 *
150 * The delayed callbacks are processed in each of the cycle of the EventLoop
151 * between the handling of timed cyclic callbacks and polling for (network)
152 * events. The memory for the delayed callback is *NOT* automatically freed
153 * after the execution. */
154
157
158 /* EventSources
159 * ~~~~~~~~~~~~
160 * EventSources are stored in a singly-linked list for direct access. But
161 * only the below methods shall be used for adding and removing - this
162 * impacts the lifecycle of the EventSource. For example it may be
163 * auto-started if the EventLoop is already running. */
164
165 /* Linked list of EventSources */
167
168 /* Register the ES. Immediately starts the ES if the EventLoop is already
169 * started. Otherwise the ES is started together with the EventLoop. */
172
173 /* Stops the EventSource before deregistrering it */
176
177 /* Locking
178 * ~~~~~~~
179 *
180 * For multi-threading the EventLoop is protected by a mutex. The mutex is
181 * expected to be recursive (can be taken more than once from the same
182 * thread). A common approach to avoid deadlocks is to establish an absolute
183 * ordering between the locks. Where the "lower" locks needs to be taken
184 * before the "upper" lock. The EventLoop-mutex is exposed here to allow it
185 * to be taken from the outside. */
186 void (*lock)(UA_EventLoop *el);
187 void (*unlock)(UA_EventLoop *el);
188};
189
190
191
192typedef enum {
194 UA_EVENTSOURCESTATE_STOPPED, /* Registered but stopped */
197 UA_EVENTSOURCESTATE_STOPPING /* Stopping in progress, needs
198 * EventLoop cycles to finish */
200
201/** Type-tag for proper casting of the difference EventSource (e.g. when they are
202 * looked up via UA_EventLoop_findEventSource). */
207
209 struct UA_EventSource *next; /* Singly-linked list for use by the
210 * application that registered the ES */
211
213
214 /* Configuration
215 * ~~~~~~~~~~~~~ */
216 UA_String name; /* Unique name of the ES */
217 UA_EventLoop *eventLoop; /* EventLoop where the ES is registered */
219
220 /* Lifecycle
221 * ~~~~~~~~~ */
224 void (*stop)(UA_EventSource *es); /* Asynchronous. Iterate theven EventLoop
225 * until the EventSource is stopped. */
227};
228
229
230
231/** The ConnectionCallback is the only interface from the connection back to
232 * the application.
233 *
234 * - The connectionId is initially unknown to the target application and
235 * "announced" to the application when first used first in this callback.
236 *
237 * - The context is attached to the connection. Initially a default context
238 * is set. The context can be replaced within the callback (via the
239 * double-pointer).
240 *
241 * - The state argument indicates the lifecycle of the connection. Every
242 * connection calls the callback a last time with UA_CONNECTIONSTATE_CLOSING.
243 * Protocols individually can forward diagnostic information relevant to the
244 * state as part of the key-value parameters.
245 *
246 * - The parameters are a key-value list with additional information. The
247 * possible keys and their meaning are documented for the individual
248 * ConnectionManager implementations.
249 *
250 * - The msg ByteString is the message (or packet) received on the
251 * connection. Can be empty. */
252typedef void
254 (UA_ConnectionManager *cm, uintptr_t connectionId,
255 void *application, void **connectionContext, UA_ConnectionState state,
257
259 /* Every ConnectionManager is treated like an EventSource from the
260 * perspective of the EventLoop. */
262
263 /* Name of the protocol supported by the ConnectionManager. For example
264 * "mqtt", "udp", "mqtt". */
266
267 /* Open a Connection
268 * ~~~~~~~~~~~~~~~~~
269 * Connecting is asynchronous. The connection-callback is called when the
270 * connection is open (status=GOOD) or aborted (status!=GOOD) when
271 * connecting failed.
272 *
273 * Some ConnectionManagers can also passively listen for new connections.
274 * Configuration parameters for this are passed via the key-value list. The
275 * `context` pointer of the listening connection is also set as the initial
276 * context of newly opened connections.
277 *
278 * The parameters describe the connection. For example hostname and port
279 * (for TCP). Other protocols (e.g. MQTT, AMQP, etc.) may required
280 * additional arguments to open a connection in the key-value list.
281 *
282 * The provided context is set as the initial context attached to this
283 * connection. It is already set before the first call to
284 * connectionCallback.
285 *
286 * The connection can be opened synchronously or asynchronously.
287 *
288 * - For synchronous connection, the connectionCallback is called with the
289 * status UA_CONNECTIONSTATE_ESTABLISHED immediately from within the
290 * openConnection operation.
291 *
292 * - In the asynchronous case the connectionCallback is called immediately
293 * from within the openConnection operation with the status
294 * UA_CONNECTIONSTATE_OPENING. The connectionCallback is called with the
295 * status UA_CONNECTIONSTATE_ESTABLISHED once the connection has fully
296 * opened.
297 *
298 * Note that a single call to openConnection might open multiple
299 * connections. For example listening on IPv4 and IPv6 for a single
300 * hostname. Each protocol implementation documents whether multiple
301 * connections might be opened at once. */
304 void *application, void *context,
305 UA_ConnectionManager_connectionCallback connectionCallback);
306
307 /* Send a message over a Connection
308 * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
309 * Sending is asynchronous. That is, the function returns before the message
310 * is ACKed from remote. The memory for the buffer is expected to be
311 * allocated with allocNetworkBuffer and is released internally (also if
312 * sending fails).
313 *
314 * Some ConnectionManagers can accept additional parameters for sending. For
315 * example a tx-time for sending in time-synchronized TSN settings. */
317 (*sendWithConnection)(UA_ConnectionManager *cm, uintptr_t connectionId,
318 const UA_KeyValueMap *params, UA_ByteString *buf);
319
320 /* Close a Connection
321 * ~~~~~~~~~~~~~~~~~~
322 * When a connection is closed its `connectionCallback` is called with
323 * (status=BadConnectionClosed, msg=empty). Then the connection is cleared
324 * up inside the ConnectionManager. This is the case both for connections
325 * that are actively closed and those that are closed remotely. The return
326 * code is non-good only if the connection is already closed. */
328 (*closeConnection)(UA_ConnectionManager *cm, uintptr_t connectionId);
329
330 /* Buffer Management
331 * ~~~~~~~~~~~~~~~~~
332 * Each ConnectionManager allocates and frees his own memory for the network
333 * buffers. This enables, for example, zero-copy neworking mechanisms. The
334 * connectionId is part of the API to enable cases where memory is
335 * statically allocated for every connection */
337 (*allocNetworkBuffer)(UA_ConnectionManager *cm, uintptr_t connectionId,
338 UA_ByteString *buf, size_t bufSize);
339 void
340 (*freeNetworkBuffer)(UA_ConnectionManager *cm, uintptr_t connectionId,
341 UA_ByteString *buf);
342};
343
344
345
346/** Interrupts can have additional key-value 'instanceInfos' for each individual
347 * triggering. See the architecture-specific documentation. */
348typedef void
350 uintptr_t interruptHandle, void *interruptContext,
351 const UA_KeyValueMap *instanceInfos);
352
354 /* Every InterruptManager is treated like an EventSource from the
355 * perspective of the EventLoop. */
357
358 /* Register an interrupt. The handle and context information is passed
359 * through to the callback.
360 *
361 * The interruptHandle is a numerical identifier of the interrupt. In some
362 * cases, such as POSIX signals, this is enough information to register
363 * callback. For other interrupt systems (architectures) additional
364 * parameters may be required and can be passed in via the parameters
365 * key-value list. See the implementation-specific documentation.
366 *
367 * The interruptContext is opaque user-defined information and passed
368 * through to the callback without modification. */
370 (*registerInterrupt)(UA_InterruptManager *im, uintptr_t interruptHandle,
371 const UA_KeyValueMap *params,
372 UA_InterruptCallback callback, void *interruptContext);
373
374 /* Remove a registered interrupt. Returns no error code if the interrupt is
375 * already deregistered. */
376 void
377 (*deregisterInterrupt)(UA_InterruptManager *im, uintptr_t interruptHandle);
378};
379
380
381
382#if defined(UA_ARCHITECTURE_POSIX) || defined(UA_ARCHITECTURE_WIN32)
383
384UA_EXPORT UA_EventLoop *
385UA_EventLoop_new_POSIX(const UA_Logger *logger);
386
387
388UA_EXPORT UA_ConnectionManager *
389UA_ConnectionManager_new_POSIX_TCP(const UA_String eventSourceName);
390
391
392UA_EXPORT UA_ConnectionManager *
393UA_ConnectionManager_new_POSIX_UDP(const UA_String eventSourceName);
394
395#if defined(__linux__) /* Linux only so far */
396
397UA_EXPORT UA_ConnectionManager *
398UA_ConnectionManager_new_POSIX_Ethernet(const UA_String eventSourceName);
399#endif
400
401
402UA_EXPORT UA_ConnectionManager *
403UA_ConnectionManager_new_MQTT(const UA_String eventSourceName);
404
405
406UA_EXPORT UA_InterruptManager *
407UA_InterruptManager_new_POSIX(const UA_String eventSourceName);
408
409#endif /* defined(UA_ARCHITECTURE_POSIX) || defined(UA_ARCHITECTURE_WIN32) */
410
412
413#endif /* UA_EVENTLOOP_H_ */
UA_ConnectionState
Definition common.h:122
#define _UA_BEGIN_DECLS
#undef UA_DEBUG_DUMP_PKGS
Definition config.h:100
#define _UA_END_DECLS
Definition config.h:107
UA_EventLoopState
Definition eventloop.h:51
@ UA_EVENTLOOPSTATE_STOPPING
Definition eventloop.h:55
@ UA_EVENTLOOPSTATE_STARTED
Definition eventloop.h:54
@ UA_EVENTLOOPSTATE_STOPPED
Definition eventloop.h:53
@ UA_EVENTLOOPSTATE_FRESH
Definition eventloop.h:52
UA_EventSourceType
Type-tag for proper casting of the difference EventSource (e.g.
Definition eventloop.h:203
@ UA_EVENTSOURCETYPE_INTERRUPTMANAGER
Definition eventloop.h:205
@ UA_EVENTSOURCETYPE_CONNECTIONMANAGER
Definition eventloop.h:204
void(* UA_InterruptCallback)(UA_InterruptManager *im, uintptr_t interruptHandle, void *interruptContext, const UA_KeyValueMap *instanceInfos)
Interrupts can have additional key-value 'instanceInfos' for each individual triggering.
Definition eventloop.h:349
void(* UA_ConnectionManager_connectionCallback)(UA_ConnectionManager *cm, uintptr_t connectionId, void *application, void **connectionContext, UA_ConnectionState state, const UA_KeyValueMap *params, UA_ByteString msg)
The ConnectionCallback is the only interface from the connection back to the application.
Definition eventloop.h:254
void(* UA_Callback)(void *application, void *context)
Definition eventloop.h:40
UA_TimerPolicy
Definition eventloop.h:33
@ UA_TIMER_HANDLE_CYCLEMISS_WITH_CURRENTTIME
Definition eventloop.h:34
@ UA_TIMER_HANDLE_CYCLEMISS_WITH_BASETIME
Definition eventloop.h:35
UA_EventSourceState
Definition eventloop.h:192
@ UA_EVENTSOURCESTATE_STOPPED
Definition eventloop.h:194
@ UA_EVENTSOURCESTATE_STOPPING
Definition eventloop.h:197
@ UA_EVENTSOURCESTATE_STARTING
Definition eventloop.h:195
@ UA_EVENTSOURCESTATE_FRESH
Definition eventloop.h:193
@ UA_EVENTSOURCESTATE_STARTED
Definition eventloop.h:196
static UA_LogCategory const char * msg
Definition log.h:58
UA_StatusCode(* sendWithConnection)(UA_ConnectionManager *cm, uintptr_t connectionId, const UA_KeyValueMap *params, UA_ByteString *buf)
Definition eventloop.h:317
UA_EventSource eventSource
Definition eventloop.h:261
UA_StatusCode(* openConnection)(UA_ConnectionManager *cm, const UA_KeyValueMap *params, void *application, void *context, UA_ConnectionManager_connectionCallback connectionCallback)
Definition eventloop.h:303
UA_StatusCode(* allocNetworkBuffer)(UA_ConnectionManager *cm, uintptr_t connectionId, UA_ByteString *buf, size_t bufSize)
Definition eventloop.h:337
void(* freeNetworkBuffer)(UA_ConnectionManager *cm, uintptr_t connectionId, UA_ByteString *buf)
Definition eventloop.h:340
UA_StatusCode(* closeConnection)(UA_ConnectionManager *cm, uintptr_t connectionId)
Definition eventloop.h:328
Delayed callbacks are executed not when they are registered, but in the following EventLoop cycle.
Definition eventloop.h:44
UA_Callback callback
Definition eventloop.h:46
struct UA_DelayedCallback * next
Definition eventloop.h:45
UA_StatusCode(* run)(UA_EventLoop *el, UA_UInt32 timeout)
Definition eventloop.h:87
UA_DateTime(* nextCyclicTime)(UA_EventLoop *el)
Definition eventloop.h:122
UA_StatusCode(* addTimedCallback)(UA_EventLoop *el, UA_Callback cb, void *application, void *data, UA_DateTime date, UA_UInt64 *callbackId)
Definition eventloop.h:140
UA_StatusCode(* registerEventSource)(UA_EventLoop *el, UA_EventSource *es)
Definition eventloop.h:171
void(* removeCyclicCallback)(UA_EventLoop *el, UA_UInt64 callbackId)
Definition eventloop.h:136
UA_DateTime(* dateTime_now)(UA_EventLoop *el)
Definition eventloop.h:109
void(* removeDelayedCallback)(UA_EventLoop *el, UA_DelayedCallback *dc)
Definition eventloop.h:156
void(* lock)(UA_EventLoop *el)
Definition eventloop.h:186
UA_EventSource * eventSources
Definition eventloop.h:166
UA_StatusCode(* addCyclicCallback)(UA_EventLoop *el, UA_Callback cb, void *application, void *data, UA_Double interval_ms, UA_DateTime *baseTime, UA_TimerPolicy timerPolicy, UA_UInt64 *callbackId)
Definition eventloop.h:127
const UA_Logger * logger
Definition eventloop.h:64
UA_Int64(* dateTime_localTimeUtcOffset)(UA_EventLoop *el)
Definition eventloop.h:111
void(* unlock)(UA_EventLoop *el)
Definition eventloop.h:187
UA_StatusCode(* deregisterEventSource)(UA_EventLoop *el, UA_EventSource *es)
Definition eventloop.h:175
void(* stop)(UA_EventLoop *el)
Definition eventloop.h:82
void(* addDelayedCallback)(UA_EventLoop *el, UA_DelayedCallback *dc)
Definition eventloop.h:155
UA_StatusCode(* free)(UA_EventLoop *el)
Definition eventloop.h:91
UA_StatusCode(* modifyCyclicCallback)(UA_EventLoop *el, UA_UInt64 callbackId, UA_Double interval_ms, UA_DateTime *baseTime, UA_TimerPolicy timerPolicy)
Definition eventloop.h:132
UA_StatusCode(* start)(UA_EventLoop *el)
Definition eventloop.h:78
UA_KeyValueMap * params
Definition eventloop.h:65
UA_DateTime(* dateTime_nowMonotonic)(UA_EventLoop *el)
Definition eventloop.h:110
const volatile UA_EventLoopState state
Definition eventloop.h:75
UA_EventSourceState state
Definition eventloop.h:222
UA_EventLoop * eventLoop
Definition eventloop.h:217
UA_EventSourceType eventSourceType
Definition eventloop.h:212
struct UA_EventSource * next
Definition eventloop.h:209
UA_StatusCode(* start)(UA_EventSource *es)
Definition eventloop.h:223
UA_KeyValueMap params
Definition eventloop.h:218
void(* stop)(UA_EventSource *es)
Definition eventloop.h:224
UA_String name
Definition eventloop.h:216
UA_StatusCode(* free)(UA_EventSource *es)
Definition eventloop.h:226
void(* deregisterInterrupt)(UA_InterruptManager *im, uintptr_t interruptHandle)
Definition eventloop.h:377
UA_StatusCode(* registerInterrupt)(UA_InterruptManager *im, uintptr_t interruptHandle, const UA_KeyValueMap *params, UA_InterruptCallback callback, void *interruptContext)
Definition eventloop.h:370
UA_EventSource eventSource
Definition eventloop.h:356
uint32_t UA_UInt32
Definition types.h:57
uint32_t UA_StatusCode
Definition types.h:82
double UA_Double
Definition types.h:77
uint64_t UA_UInt64
Definition types.h:67
int64_t UA_Int64
Definition types.h:62