Coverage Report

Created: 2026-08-31 07:11

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/open62541/arch/posix/eventloop_posix_interrupt.c
Line
Count
Source
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, 2024 (c) Fraunhofer IOSB (Author: Julius Pfrommer)
6
 *    Copyright 2026 (c) o6 Automation GmbH (Author: Julius Pfrommer)
7
 */
8
9
#include "eventloop_posix.h"
10
#include <signal.h>
11
12
#if defined(UA_ARCHITECTURE_POSIX) && !defined(UA_ARCHITECTURE_LWIP)
13
14
12.9k
#define UA_MAX_INTERRUPT_MANAGERS 8
15
#ifdef NSIG
16
0
# define UA_INTERRUPT_SIGNAL_SLOTS NSIG
17
#else
18
# define UA_INTERRUPT_SIGNAL_SLOTS 128
19
#endif
20
21
typedef struct UA_RegisteredSignal {
22
    LIST_ENTRY(UA_RegisteredSignal) listPointers;
23
    UA_EventSource *eventSource;
24
25
    UA_InterruptCallback signalCallback;
26
    void *context;
27
    int signal; /* POSIX identifier of the interrupt signal */
28
29
    UA_Boolean active; /* Signals are only active when the EventLoop is started */
30
} UA_RegisteredSignal;
31
32
typedef struct UA_POSIXInterruptManager {
33
    UA_InterruptManager im;
34
35
    LIST_HEAD(, UA_RegisteredSignal) signals; /* Registered signals */
36
37
    UA_RegisteredFD readfd;
38
    UA_FD writefd;
39
    UA_atomic(struct UA_POSIXInterruptManager*)* managerSlot;
40
} UA_POSIXInterruptManager;
41
42
/* Signal handlers are process-global. Route each signal marker to all active
43
 * interrupt managers so multiple EventLoops can coexist. */
44
static UA_atomic(UA_POSIXInterruptManager*) interruptManagers[UA_MAX_INTERRUPT_MANAGERS];
45
static UA_atomic(uintptr_t) interruptWriteFDs[UA_INTERRUPT_SIGNAL_SLOTS][UA_MAX_INTERRUPT_MANAGERS];
46
static UA_atomic(uintptr_t) signalRefCounts[UA_INTERRUPT_SIGNAL_SLOTS];
47
48
/* Keep the previous action to restore when we deregister a signal */
49
static struct sigaction previousActions[UA_INTERRUPT_SIGNAL_SLOTS];
50
51
static UA_Boolean
52
0
signalIsSupported(int signal) {
53
0
    return (signal >= 0 &&
54
0
            signal < UA_INTERRUPT_SIGNAL_SLOTS &&
55
0
            signal <= UCHAR_MAX);
56
0
}
57
58
static UA_Boolean
59
12.9k
registerInterruptManager(UA_POSIXInterruptManager *pim) {
60
12.9k
    for(size_t i = 0; i < UA_MAX_INTERRUPT_MANAGERS; i++) {
61
12.9k
        UA_POSIXInterruptManager *prev = NULL;
62
12.9k
        UA_atomic_cmpxchg(&interruptManagers[i], &prev, pim);
63
12.9k
        if(prev == NULL) {
64
12.9k
            pim->managerSlot = &interruptManagers[i];
65
12.9k
            return true;
66
12.9k
        }
67
12.9k
    }
68
0
    return false;
69
12.9k
}
70
71
static void
72
12.9k
unregisterInterruptManager(UA_POSIXInterruptManager *pim) {
73
12.9k
    UA_assert(*pim->managerSlot == pim);
74
12.9k
    UA_atomic_store(pim->managerSlot, NULL);
75
12.9k
    pim->managerSlot = NULL;
76
12.9k
}
77
78
static void
79
12.8k
closeSignalPipe(UA_POSIXInterruptManager *pim) {
80
12.8k
    UA_EventLoopPOSIX *el = (UA_EventLoopPOSIX*)pim->im.eventSource.eventLoop;
81
12.8k
    (void)el;
82
12.8k
    UA_LOCK_ASSERT(&el->elMutex);
83
84
12.8k
    if(pim->readfd.fd == UA_INVALID_FD)
85
0
        return;
86
87
12.8k
    UA_EventLoopPOSIX_deregisterFD(el, &pim->readfd);
88
12.8k
    UA_close(pim->readfd.fd);
89
12.8k
    UA_close(pim->writefd);
90
12.8k
    pim->readfd.fd = UA_INVALID_FD;
91
12.8k
    pim->writefd = UA_INVALID_FD;
92
12.8k
}
93
94
static void
95
handlePOSIXInterruptEvent(UA_EventSource *es, UA_RegisteredFD *rfd,
96
0
                          short event) {
97
0
    UA_EventLoopPOSIX *el = (UA_EventLoopPOSIX *)es->eventLoop;
98
0
    (void)el;
99
0
    (void)event;
100
0
    UA_LOCK_ASSERT(&el->elMutex);
101
102
0
    UA_POSIXInterruptManager *pim = (UA_POSIXInterruptManager*)es;
103
0
    unsigned char buf[32];
104
105
0
    for(;;) {
106
0
        ssize_t received = UA_recv(rfd->fd, (char*)buf, sizeof(buf), 0);
107
0
        if(received > 0) {
108
0
            for(ssize_t i = 0; i < received; i++) {
109
0
                UA_RegisteredSignal *rs;
110
0
                LIST_FOREACH(rs, &pim->signals, listPointers) {
111
0
                    if(rs->signal == (int)buf[i] && rs->active)
112
0
                        break;
113
0
                }
114
0
                if(!rs)
115
0
                    continue;
116
117
0
                UA_LOG_DEBUG(es->eventLoop->logger, UA_LOGCATEGORY_EVENTLOOP,
118
0
                             "Interrupt %u\t| Received signal %u",
119
0
                             (unsigned)rfd->fd, (unsigned)rs->signal);
120
0
                UA_UNLOCK(&el->elMutex);
121
0
                rs->signalCallback((UA_InterruptManager *)es,
122
0
                                   (uintptr_t)rs->signal, rs->context,
123
0
                                   &UA_KEYVALUEMAP_NULL);
124
0
                UA_LOCK(&el->elMutex);
125
0
            }
126
0
            continue;
127
0
        }
128
129
0
        if(received == 0) {
130
0
            closeSignalPipe(pim);
131
0
            return;
132
0
        }
133
134
0
        if(UA_ERRNO == UA_INTERRUPTED)
135
0
            continue;
136
137
0
        if(UA_ERRNO == UA_AGAIN || UA_ERRNO == UA_WOULDBLOCK)
138
0
            return;
139
140
0
        closeSignalPipe(pim);
141
0
        return;
142
0
    }
143
0
}
144
145
static UA_StatusCode
146
12.8k
openSignalPipe(UA_POSIXInterruptManager *pim) {
147
12.8k
    UA_EventLoopPOSIX *el = (UA_EventLoopPOSIX*)pim->im.eventSource.eventLoop;
148
12.8k
    (void)el;
149
12.8k
    UA_LOCK_ASSERT(&el->elMutex);
150
151
12.8k
    if(pim->readfd.fd != UA_INVALID_FD)
152
0
        return UA_STATUSCODE_GOOD;
153
154
12.8k
    UA_FD fds[2];
155
12.8k
    int err = UA_EventLoopPOSIX_pipe(fds);
156
12.8k
    if(err != 0) {
157
0
        UA_LOG_SOCKET_ERRNO_WRAP(
158
0
           UA_LOG_WARNING(el->eventLoop.logger, UA_LOGCATEGORY_EVENTLOOP,
159
0
                          "Interrupt\t| Could not create the signal pipe: %s",
160
0
                          errno_str));
161
0
        return UA_STATUSCODE_BADINTERNALERROR;
162
0
    }
163
164
12.8k
    pim->readfd.es = &pim->im.eventSource;
165
12.8k
    pim->readfd.eventSourceCB = handlePOSIXInterruptEvent;
166
12.8k
    pim->readfd.listenEvents = UA_FDEVENT_IN;
167
12.8k
    pim->readfd.fd = fds[0];
168
12.8k
    pim->writefd = fds[1];
169
170
12.8k
    UA_StatusCode res = UA_EventLoopPOSIX_registerFD(el, &pim->readfd);
171
12.8k
    if(res != UA_STATUSCODE_GOOD) {
172
0
        UA_LOG_WARNING(el->eventLoop.logger, UA_LOGCATEGORY_EVENTLOOP,
173
0
                       "Interrupt\t| Could not register the signal pipe in "
174
0
                       "the EventLoop");
175
0
        UA_close(pim->readfd.fd);
176
0
        UA_close(pim->writefd);
177
0
        pim->readfd.fd = UA_INVALID_FD;
178
0
        pim->writefd = UA_INVALID_FD;
179
0
        return res;
180
0
    }
181
182
12.8k
    return UA_STATUSCODE_GOOD;
183
12.8k
}
184
185
/* Signal handlers can only perform async-signal-safe operations. Writing one
186
 * byte into the signal-specific pipe wakes up the EventLoop. */
187
static void
188
0
triggerPOSIXInterruptEvent(int sig) {
189
0
    if(!signalIsSupported(sig))
190
0
        return;
191
192
193
0
    int savedErrno = errno;
194
0
    unsigned char signalMarker = (unsigned char)sig;
195
196
0
    for(size_t i = 0; i < UA_MAX_INTERRUPT_MANAGERS; i++) {
197
0
        uintptr_t encodedFD = UA_atomic_load(&interruptWriteFDs[sig][i]);
198
0
        UA_FD writefd = UA_INVALID_FD;
199
0
        if(encodedFD != 0)
200
0
            writefd = (UA_FD)(encodedFD - 1u);
201
0
        if(writefd == UA_INVALID_FD)
202
0
            continue;
203
204
0
        ssize_t res;
205
0
        do {
206
0
            res = UA_send(writefd, (const char*)&signalMarker, 1, 0);
207
0
        } while(res == -1 && UA_ERRNO == UA_INTERRUPTED);
208
0
    }
209
210
0
    errno = savedErrno;
211
0
}
212
213
static void
214
0
activateSignal(UA_RegisteredSignal *rs) {
215
0
    UA_EventLoopPOSIX *el = (UA_EventLoopPOSIX*)rs->eventSource->eventLoop;
216
0
    (void)el;
217
0
    UA_LOCK_ASSERT(&el->elMutex);
218
219
0
    if(rs->active)
220
0
        return;
221
222
0
    UA_POSIXInterruptManager *pim = (UA_POSIXInterruptManager*)rs->eventSource;
223
0
    UA_assert(pim->managerSlot != NULL);
224
225
0
    size_t managerSlot = (size_t)(pim->managerSlot - interruptManagers);
226
227
    /* Store the fd to be picked up by triggerPOSIXInterruptEvent */
228
0
    rs->active = true;
229
0
    UA_atomic_store(&interruptWriteFDs[rs->signal][managerSlot],
230
0
                    ((uintptr_t)pim->writefd) + 1u);
231
232
    /* signalRefCounts is an atomic state machine:
233
     *   0                         -> signal handler not installed
234
     *   1..N                      -> installed and referenced by N managers
235
     *   >= UINT16_MAX             -> handler is being installed (sentinel)
236
     * Only the thread that flips 0 -> UINT16_MAX installs the handler.
237
     * Other threads can increment the refcount even if the sentinel is present. */
238
0
    for(;;) {
239
0
        uintptr_t refCount = UA_atomic_load(&signalRefCounts[rs->signal]);
240
241
        /* Interrupt installing or already installed. Just increment. */
242
0
        if(refCount > 0) {
243
0
            uintptr_t expected = refCount;
244
0
            UA_atomic_cmpxchg(&signalRefCounts[rs->signal], &expected, refCount + 1);
245
0
            if(expected != refCount)
246
0
                continue; /* Another thread changed the refCount. Retry. */
247
0
            return; /* Done */
248
0
        }
249
250
        /* Set the sentinel */
251
0
        uintptr_t expected = 0;
252
0
        UA_atomic_cmpxchg(&signalRefCounts[rs->signal], &expected, UINT16_MAX);
253
0
        if(expected != 0)
254
0
            continue;  /* Another thread changed the refCount. Retry. */
255
0
        break; /* This thread installs the interrupt handler */
256
0
    }
257
258
0
    UA_LOG_TRACE(el->eventLoop.logger, UA_LOGCATEGORY_EVENTLOOP,
259
0
                 "Interrupt %i\t| Register Wait %u", rs->signal,
260
0
                 signalRefCounts[rs->signal]);
261
262
    /* From here on we are the first (and only) thread to register the signal.
263
     * There might still be an ongoing deactivateSignal which reached
264
     * refCount==0 just before. Loop until previousAction is zeroed to make sure
265
     * no deactivateSignal is ongoing. */
266
0
    UA_atomic(uintptr_t)* action_sentinel =
267
0
        (UA_atomic(uintptr_t)*)&previousActions[rs->signal];
268
0
    for(;;) {
269
0
        if(UA_atomic_load(action_sentinel) == 0)
270
0
            break;
271
0
    }
272
273
0
    UA_LOG_TRACE(el->eventLoop.logger, UA_LOGCATEGORY_EVENTLOOP,
274
0
                 "Interrupt %i\t| Register Begin %u", rs->signal,
275
0
                 signalRefCounts[rs->signal]);
276
277
0
    UA_LOG_INFO(el->eventLoop.logger, UA_LOGCATEGORY_EVENTLOOP,
278
0
                "Interrupt\t| Registering the handler for signal %i", rs->signal);
279
280
    /* Install the interrupt handler */
281
0
    struct sigaction previousAction;
282
0
    struct sigaction action;
283
0
    memset(&action, 0, sizeof(action));
284
0
    action.sa_handler = triggerPOSIXInterruptEvent;
285
0
    sigemptyset(&action.sa_mask);
286
0
    action.sa_flags = 0;
287
0
    if(sigaction(rs->signal, &action, &previousAction) == 0) {
288
        /* Store previous action with non-NULL value.
289
         * Use 0x01 to indicate no previous action was stored. */
290
0
        uintptr_t *prevContent = (uintptr_t*)&previousAction;
291
0
        if(*prevContent == 0)
292
0
            *prevContent = 0x01;
293
0
        previousActions[rs->signal] = previousAction;
294
0
    } else {
295
0
        UA_LOG_SOCKET_ERRNO_WRAP(
296
0
           UA_LOG_ERROR(el->eventLoop.logger, UA_LOGCATEGORY_EVENTLOOP,
297
0
                        "Interrupt\t| Could not register the signal handler: %s",
298
0
                        errno_str));
299
0
    }
300
301
    /* Subtract UINT16_MAX - 1 for the final refcount */
302
0
    for(;;) {
303
0
        uintptr_t refCount = UA_atomic_load(&signalRefCounts[rs->signal]);
304
0
        UA_assert(refCount >= UA_UINT16_MAX);
305
0
        uintptr_t expected = refCount;
306
0
        UA_atomic_cmpxchg(&signalRefCounts[rs->signal], &expected,
307
0
                          refCount - (UA_UINT16_MAX - 1u));
308
0
        if(expected == refCount)
309
0
            break;
310
0
    }
311
312
0
    UA_LOG_TRACE(el->eventLoop.logger, UA_LOGCATEGORY_EVENTLOOP,
313
0
                 "Interrupt %i\t| Register End %u", rs->signal,
314
0
                 signalRefCounts[rs->signal]);
315
0
}
316
317
static void
318
0
deactivateSignal(UA_RegisteredSignal *rs) {
319
0
    UA_EventLoopPOSIX *el = (UA_EventLoopPOSIX*)rs->eventSource->eventLoop;
320
0
    (void)el;
321
0
    UA_LOCK_ASSERT(&el->elMutex);
322
323
0
    UA_POSIXInterruptManager *pim = (UA_POSIXInterruptManager*)rs->eventSource;
324
0
    UA_assert(pim->managerSlot != NULL);
325
326
0
    if(!rs->active)
327
0
        return;
328
329
0
    UA_LOG_TRACE(el->eventLoop.logger, UA_LOGCATEGORY_EVENTLOOP,
330
0
                 "Interrupt %i\t| Register Decrease Begin %u", rs->signal,
331
0
                 signalRefCounts[rs->signal]);
332
333
0
    size_t managerSlot = (size_t)(pim->managerSlot - interruptManagers);
334
335
    /* Stop routing new signals to this interrupt manager */
336
0
    UA_atomic_store(&interruptWriteFDs[rs->signal][managerSlot], 0);
337
0
    rs->active = false;
338
339
    /* Decrease the refcount */
340
0
    uintptr_t refCount;
341
0
    for(;;) {
342
0
        refCount = UA_atomic_load(&signalRefCounts[rs->signal]);
343
0
        uintptr_t expected = refCount;
344
0
        UA_atomic_cmpxchg(&signalRefCounts[rs->signal], &expected, refCount - 1);
345
0
        if(expected == refCount)
346
0
            break;
347
0
    }
348
0
    refCount--; /* Adjust, this is still the old refCount before decreasing */
349
350
0
    UA_LOG_TRACE(el->eventLoop.logger, UA_LOGCATEGORY_EVENTLOOP,
351
0
                 "Interrupt %i\t| Register Decrease End %u", rs->signal,
352
0
                 signalRefCounts[rs->signal]);
353
354
    /* Another interrupt manager still uses the signal */
355
0
    if(refCount > 0)
356
0
        return;
357
358
0
    UA_LOG_TRACE(el->eventLoop.logger, UA_LOGCATEGORY_EVENTLOOP,
359
0
                 "Interrupt %i\t| Deregister Begin", rs->signal);
360
361
0
    UA_LOG_INFO(el->eventLoop.logger, UA_LOGCATEGORY_EVENTLOOP,
362
0
                "Interrupt\t| Deregistering the handler for signal %i", rs->signal);
363
364
    /* Deactivate the signal, reset to the previous action */
365
0
    struct sigaction prev = previousActions[rs->signal];
366
0
    uintptr_t *prevContent = (uintptr_t*)&prev;
367
0
    if(*prevContent == 0x01)
368
0
        *prevContent = 0x0;
369
0
    sigaction(rs->signal, &prev, NULL);
370
371
    /* Zero out the previousAction. So an activateSignal that has already
372
     * started knows we are done. */
373
0
    UA_atomic(uintptr_t)* action_sentinel =
374
0
        (UA_atomic(uintptr_t)*)&previousActions[rs->signal];
375
0
    UA_atomic_store(action_sentinel, 0);
376
377
0
    UA_LOG_TRACE(el->eventLoop.logger, UA_LOGCATEGORY_EVENTLOOP,
378
0
                 "Interrupt %i\t| Deregister End", rs->signal);
379
0
}
380
381
static UA_StatusCode
382
registerPOSIXInterrupt(UA_InterruptManager *im, uintptr_t interruptHandle,
383
                       const UA_KeyValueMap *params,
384
0
                       UA_InterruptCallback callback, void *interruptContext) {
385
0
    UA_EventLoopPOSIX *el = (UA_EventLoopPOSIX *)im->eventSource.eventLoop;
386
0
    if(!UA_KeyValueMap_isEmpty(params)) {
387
0
        UA_LOG_ERROR(el->eventLoop.logger, UA_LOGCATEGORY_EVENTLOOP,
388
0
                     "Interrupt\t| Supplied parameters invalid for the "
389
0
                     "POSIX InterruptManager");
390
0
        return UA_STATUSCODE_BADINTERNALERROR;
391
0
    }
392
393
0
    UA_LOCK(&el->elMutex);
394
395
    /* Was the signal already registered? */
396
0
    int signal = (int)interruptHandle;
397
0
    UA_POSIXInterruptManager *pim = (UA_POSIXInterruptManager *)im;
398
0
    UA_RegisteredSignal *rs;
399
0
    LIST_FOREACH(rs, &pim->signals, listPointers) {
400
0
        if(rs->signal == signal)
401
0
            break;
402
0
    }
403
0
    if(rs) {
404
0
        UA_LOG_WARNING(el->eventLoop.logger, UA_LOGCATEGORY_EVENTLOOP,
405
0
                       "Interrupt\t| Signal %u already registered",
406
0
                       (unsigned)interruptHandle);
407
0
        UA_UNLOCK(&el->elMutex);
408
0
        return UA_STATUSCODE_BADINTERNALERROR;
409
0
    }
410
411
    /* Create and populate the new context object */
412
0
    rs = (UA_RegisteredSignal *)UA_calloc(1, sizeof(UA_RegisteredSignal));
413
0
    if(!rs) {
414
0
        UA_UNLOCK(&el->elMutex);
415
0
        return UA_STATUSCODE_BADOUTOFMEMORY;
416
0
    }
417
418
0
    if(!signalIsSupported(signal)) {
419
0
        UA_LOG_ERROR(el->eventLoop.logger, UA_LOGCATEGORY_EVENTLOOP,
420
0
                     "Interrupt\t| Signal %u is out of range",
421
0
                     (unsigned)interruptHandle);
422
0
        UA_free(rs);
423
0
        UA_UNLOCK(&el->elMutex);
424
0
        return UA_STATUSCODE_BADINTERNALERROR;
425
0
    }
426
427
    /* Set the callback and context */
428
0
    rs->eventSource = &im->eventSource;
429
0
    rs->signal = (int)interruptHandle;
430
0
    rs->signalCallback = callback;
431
0
    rs->context = interruptContext;
432
433
    /* Add to the InterruptManager */
434
0
    LIST_INSERT_HEAD(&pim->signals, rs, listPointers);
435
436
    /* Activate if we are already running */
437
0
    if(pim->im.eventSource.state == UA_EVENTSOURCESTATE_STARTED)
438
0
        activateSignal(rs);
439
440
0
    UA_UNLOCK(&el->elMutex);
441
0
    return UA_STATUSCODE_GOOD;
442
0
}
443
444
static void
445
0
deregisterPOSIXInterrupt(UA_InterruptManager *im, uintptr_t interruptHandle) {
446
0
    UA_EventLoopPOSIX *el = (UA_EventLoopPOSIX *)im->eventSource.eventLoop;
447
0
    (void)el;
448
0
    UA_POSIXInterruptManager *pim = (UA_POSIXInterruptManager *)im;
449
0
    UA_LOCK(&el->elMutex);
450
451
0
    int signal = (int)interruptHandle;
452
0
    UA_RegisteredSignal *rs;
453
0
    LIST_FOREACH(rs, &pim->signals, listPointers) {
454
0
        if(rs->signal == signal)
455
0
            break;
456
0
    }
457
0
    if(rs) {
458
0
        deactivateSignal(rs);
459
0
        LIST_REMOVE(rs, listPointers);
460
0
        UA_free(rs);
461
0
    }
462
463
0
    UA_UNLOCK(&el->elMutex);
464
0
}
465
466
static UA_StatusCode
467
12.8k
startPOSIXInterruptManager(UA_EventSource *es) {
468
12.8k
    UA_EventLoopPOSIX *el = (UA_EventLoopPOSIX *)es->eventLoop;
469
12.8k
    (void)el;
470
12.8k
    UA_LOCK(&el->elMutex);
471
472
    /* Check the state */
473
12.8k
    if(es->state != UA_EVENTSOURCESTATE_STOPPED) {
474
0
        UA_LOG_ERROR(es->eventLoop->logger, UA_LOGCATEGORY_EVENTLOOP,
475
0
                     "Interrupt\t| To start the InterruptManager, "
476
0
                     "it has to be registered in an EventLoop and not started");
477
0
        UA_UNLOCK(&el->elMutex);
478
0
        return UA_STATUSCODE_BADINTERNALERROR;
479
0
    }
480
481
12.8k
    UA_POSIXInterruptManager *pim = (UA_POSIXInterruptManager *)es;
482
12.8k
    UA_LOG_DEBUG(es->eventLoop->logger, UA_LOGCATEGORY_EVENTLOOP,
483
12.8k
                 "Interrupt\t| Starting the InterruptManager");
484
485
12.8k
    UA_StatusCode res = openSignalPipe(pim);
486
12.8k
    if(res != UA_STATUSCODE_GOOD) {
487
0
        UA_UNLOCK(&el->elMutex);
488
0
        return res;
489
0
    }
490
491
    /* Activate the registered signal handlers */
492
12.8k
    UA_RegisteredSignal*rs;
493
12.8k
    LIST_FOREACH(rs, &pim->signals, listPointers) {
494
0
        activateSignal(rs);
495
0
    }
496
497
    /* Set the EventSource to the started state */
498
12.8k
    es->state = UA_EVENTSOURCESTATE_STARTED;
499
500
12.8k
    UA_UNLOCK(&el->elMutex);
501
12.8k
    return UA_STATUSCODE_GOOD;
502
12.8k
}
503
504
static void
505
18.7k
stopPOSIXInterruptManager(UA_EventSource *es) {
506
18.7k
    UA_EventLoopPOSIX *el = (UA_EventLoopPOSIX *)es->eventLoop;
507
18.7k
    (void)el;
508
18.7k
    UA_LOCK(&el->elMutex);
509
510
18.7k
    if(es->state != UA_EVENTSOURCESTATE_STARTED) {
511
0
        UA_UNLOCK(&el->elMutex);
512
0
        return;
513
0
    }
514
515
18.7k
    UA_LOG_DEBUG(es->eventLoop->logger, UA_LOGCATEGORY_EVENTLOOP,
516
18.7k
                 "Interrupt\t| Stopping the InterruptManager");
517
518
    /* Close all registered signals */
519
18.7k
    UA_POSIXInterruptManager *pim = (UA_POSIXInterruptManager *)es;
520
18.7k
    UA_RegisteredSignal*rs;
521
18.7k
    LIST_FOREACH(rs, &pim->signals, listPointers) {
522
0
        deactivateSignal(rs);
523
0
    }
524
525
18.7k
    closeSignalPipe(pim);
526
527
    /* Immediately set to stopped */
528
18.7k
    es->state = UA_EVENTSOURCESTATE_STOPPED;
529
530
18.7k
    UA_UNLOCK(&el->elMutex);
531
18.7k
}
532
533
static UA_StatusCode
534
18.8k
freePOSIXInterruptmanager(UA_EventSource *es) {
535
18.8k
    UA_EventLoopPOSIX *el = (UA_EventLoopPOSIX *)es->eventLoop;
536
18.8k
    (void)el;
537
18.8k
    UA_LOCK_ASSERT(&el->elMutex);
538
539
18.8k
    if(es->state >= UA_EVENTSOURCESTATE_STARTING) {
540
0
        UA_LOG_ERROR(es->eventLoop->logger, UA_LOGCATEGORY_EVENTLOOP,
541
0
                     "Interrupt\t| The EventSource must be stopped "
542
0
                     "before it can be deleted");
543
0
        return UA_STATUSCODE_BADINTERNALERROR;
544
0
    }
545
546
    /* Deactivate and remove all registered signals */
547
18.8k
    UA_POSIXInterruptManager *pim = (UA_POSIXInterruptManager *)es;
548
18.8k
    UA_RegisteredSignal *rs, *rs_tmp;
549
18.8k
    LIST_FOREACH_SAFE(rs, &pim->signals, listPointers, rs_tmp) {
550
0
        deactivateSignal(rs);
551
0
        LIST_REMOVE(rs, listPointers);
552
0
        UA_free(rs);
553
0
    }
554
555
18.8k
    UA_String_clear(&es->name);
556
18.8k
    unregisterInterruptManager(pim);
557
18.8k
    UA_free(es);
558
559
18.8k
    return UA_STATUSCODE_GOOD;
560
18.8k
}
561
562
UA_InterruptManager *
563
12.9k
UA_InterruptManager_new_POSIX(const UA_String eventSourceName) {
564
12.9k
    UA_POSIXInterruptManager *pim = (UA_POSIXInterruptManager *)
565
12.9k
        UA_calloc(1, sizeof(UA_POSIXInterruptManager));
566
12.9k
    if(!pim)
567
0
        return NULL;
568
569
    /* Initialize the FD as invalid before adding the interrupt manager to the
570
     * global array */
571
12.9k
    pim->readfd.fd = UA_INVALID_FD;
572
12.9k
    pim->writefd = UA_INVALID_FD;
573
12.9k
    pim->managerSlot = NULL;
574
575
12.9k
    if(!registerInterruptManager(pim)) {
576
0
        UA_free(pim);
577
0
        return NULL;
578
0
    }
579
580
12.9k
    UA_InterruptManager *im = &pim->im;
581
12.9k
    im->eventSource.eventSourceType = UA_EVENTSOURCETYPE_INTERRUPTMANAGER;
582
12.9k
    UA_String_copy(&eventSourceName, &im->eventSource.name);
583
12.9k
    im->eventSource.start = startPOSIXInterruptManager;
584
12.9k
    im->eventSource.stop = stopPOSIXInterruptManager;
585
12.9k
    im->eventSource.free = freePOSIXInterruptmanager;
586
12.9k
    im->registerInterrupt = registerPOSIXInterrupt;
587
12.9k
    im->deregisterInterrupt = deregisterPOSIXInterrupt;
588
12.9k
    return im;
589
12.9k
}
590
591
#endif