Branch data Line data Source code
1 : : /* SPDX-FileCopyrightText: Copyright 2026 Cozens Software Solutions Limited
2 : : * SPDX-License-Identifier: PolyForm-Noncommercial-1.0.0 OR LicenseRef-PolyForm-Internal-Use-1.0.0 OR LicenseRef-COSOSO-Commercial
3 : : */
4 : :
5 : : #include "SolidSyslogConfig.h"
6 : :
7 : : #include <stdbool.h>
8 : : #include <stddef.h>
9 : : #include <stdint.h>
10 : :
11 : : #include "SolidSyslogError.h"
12 : : #include "SolidSyslogErrorCategory.h"
13 : : #include "SolidSyslogErrors.h"
14 : : #include "SolidSyslogFormatter.h"
15 : : #include "SolidSyslogPendingEvents.h"
16 : : #include "SolidSyslogPoolAllocator.h"
17 : : #include "SolidSyslogPrival.h"
18 : : #include "SolidSyslogPrivate.h"
19 : : #include "SolidSyslogTunables.h"
20 : :
21 : : static inline size_t SolidSyslog_IndexFromHandle(const struct SolidSyslog* handle);
22 : : static inline void SolidSyslog_CleanupAtIndex(size_t index, void* context);
23 : : static void SolidSyslog_EnsureNullInstancePopulated(void);
24 : :
25 : : static bool SolidSyslog_InUse[SOLIDSYSLOG_POOL_SIZE];
26 : : static struct SolidSyslog SolidSyslog_Pool[SOLIDSYSLOG_POOL_SIZE];
27 : : static struct SolidSyslogPoolAllocator SolidSyslog_Allocator = {SolidSyslog_InUse, SOLIDSYSLOG_POOL_SIZE};
28 : :
29 : : /* Exhaustion-fallback handle. Populated lazily on first reach because
30 : : * the SolidSyslogNull* Get() siblings return runtime addresses (no file-scope
31 : : * designated initialiser will accept them). Sits outside SolidSyslog_Pool[] so
32 : : * IndexFromHandle naturally returns invalid for it - SolidSyslog_Destroy(
33 : : * &NullInstance) fires WARNING + ignore, while SolidSyslog_Log /
34 : : * SolidSyslog_Service against it route through the public Null* siblings and
35 : : * silently drop. */
36 : : static struct SolidSyslog SolidSyslog_NullInstance;
37 : :
38 : 461 : struct SolidSyslog* SolidSyslog_Create(const struct SolidSyslogConfig* config)
39 : : {
40 : 461 : SolidSyslog_EnsureNullInstancePopulated();
41 : 461 : struct SolidSyslog* result = &SolidSyslog_NullInstance;
42 [ + + ]: 461 : if (config == NULL)
43 : : {
44 : 4 : SolidSyslog_Report(
45 : : SOLIDSYSLOG_BAD_CONFIG_FATAL_SEVERITY,
46 : : SOLIDSYSLOG_CAT_BAD_CONFIG,
47 : : SOLIDSYSLOG_ERROR_CREATE_NULL_CONFIG
48 : : );
49 : : }
50 : : else
51 : : {
52 : 457 : size_t index = SolidSyslogPoolAllocator_AcquireFirstFree(&SolidSyslog_Allocator);
53 [ + + ]: 457 : if (SolidSyslogPoolAllocator_IndexIsValid(&SolidSyslog_Allocator, index))
54 : : {
55 : : /* Each pool entry's record slot, kept beside the pool rather than
56 : : * in the struct so that the fallback carries none. Formatter
57 : : * storage, so that Service formats its own report in place. */
58 : : static SolidSyslogFormatterStorage
59 : : records[SOLIDSYSLOG_POOL_SIZE][SOLIDSYSLOG_FORMATTER_STORAGE_SIZE(SOLIDSYSLOG_MAX_MESSAGE_SIZE)];
60 : 451 : SolidSyslog_Initialise(&SolidSyslog_Pool[index], config, records[index], SOLIDSYSLOG_MAX_MESSAGE_SIZE);
61 : 451 : result = &SolidSyslog_Pool[index];
62 : : }
63 : : else
64 : : {
65 : 6 : SolidSyslog_Report(
66 : : SOLIDSYSLOG_POOL_EXHAUSTED_SEVERITY,
67 : : SOLIDSYSLOG_CAT_POOL_EXHAUSTED,
68 : : SOLIDSYSLOG_ERROR_POOL_EXHAUSTED
69 : : );
70 : : }
71 : : }
72 : 461 : return result;
73 : : }
74 : :
75 : 461 : static void SolidSyslog_EnsureNullInstancePopulated(void)
76 : : {
77 : : static bool populated = false;
78 [ + + ]: 461 : if (!populated)
79 : : {
80 : : /* The safe defaults a destroyed slot is left with are the ones the
81 : : * fallback needs, so there is one place that says what they are. */
82 : 3 : SolidSyslog_Cleanup(&SolidSyslog_NullInstance);
83 : 3 : populated = true;
84 : : }
85 : 461 : }
86 : :
87 : 462 : void SolidSyslog_Destroy(struct SolidSyslog* handle)
88 : : {
89 : 462 : size_t index = SolidSyslog_IndexFromHandle(handle);
90 : 462 : bool released =
91 [ + + + + ]: 914 : SolidSyslogPoolAllocator_IndexIsValid(&SolidSyslog_Allocator, index) &&
92 : 452 : SolidSyslogPoolAllocator_FreeIfInUse(&SolidSyslog_Allocator, index, SolidSyslog_CleanupAtIndex, NULL);
93 [ + + ]: 462 : if (released)
94 : : {
95 : 451 : SolidSyslogPendingEvents_Clear();
96 : : }
97 : : else
98 : : {
99 : 11 : SolidSyslog_Report(
100 : : SOLIDSYSLOG_UNKNOWN_DESTROY_SEVERITY,
101 : : SOLIDSYSLOG_CAT_UNKNOWN_DESTROY,
102 : : SOLIDSYSLOG_ERROR_UNKNOWN_DESTROY
103 : : );
104 : : }
105 : 462 : }
106 : :
107 : 462 : static inline size_t SolidSyslog_IndexFromHandle(const struct SolidSyslog* handle)
108 : : {
109 : 462 : size_t result = SOLIDSYSLOG_POOL_SIZE;
110 [ + + ]: 472 : for (size_t poolIndex = 0U; poolIndex < SOLIDSYSLOG_POOL_SIZE; poolIndex++)
111 : : {
112 [ + + ]: 462 : if (handle == &SolidSyslog_Pool[poolIndex])
113 : : {
114 : 452 : result = poolIndex;
115 : 452 : break;
116 : : }
117 : : }
118 : 462 : return result;
119 : : }
120 : :
121 : 451 : static inline void SolidSyslog_CleanupAtIndex(size_t index, void* context)
122 : : {
123 : : (void) context;
124 : 451 : SolidSyslog_Cleanup(&SolidSyslog_Pool[index]);
125 : 451 : }
|