SolidSyslog coverage report
Current view: top level - Core/Source - SolidSyslogCircularBuffer.c (source / functions) Coverage Total Hit
Test: SolidSyslog Lines: 100.0 % 163 163
Test Date: 2026-11-12 23:14:35 Functions: 100.0 % 29 29
Branches: 100.0 % 50 50

             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 "SolidSyslogCircularBuffer.h"
       6                 :             : 
       7                 :             : #include <stdbool.h>
       8                 :             : #include <stddef.h>
       9                 :             : #include <stdint.h>
      10                 :             : #include <string.h>
      11                 :             : 
      12                 :             : #include "SolidSyslogBufferCategories.h"
      13                 :             : #include "SolidSyslogBufferDefinition.h"
      14                 :             : #include "SolidSyslogCircularBufferErrors.h"
      15                 :             : #include "SolidSyslogCircularBufferPrivate.h"
      16                 :             : #include "SolidSyslogError.h"
      17                 :             : #include "SolidSyslogErrorCategory.h"
      18                 :             : #include "SolidSyslogMutex.h"
      19                 :             : #include "SolidSyslogNullBuffer.h"
      20                 :             : #include "SolidSyslogPrival.h"
      21                 :             : #include "SolidSyslogTunables.h"
      22                 :             : 
      23                 :             : const struct SolidSyslogErrorSource SolidSyslogCircularBufferErrorSource = {
      24                 :             :     "CircularBuffer",
      25                 :             :     SolidSyslogCircularBufferErrors_Name
      26                 :             : };
      27                 :             : 
      28                 :             : enum
      29                 :             : {
      30                 :             :     HEADER_BYTES = SOLIDSYSLOG_CIRCULAR_BUFFER_HEADER_BYTES
      31                 :             : };
      32                 :             : 
      33                 :             : /* Which run of losses, if any, a write has just started. */
      34                 :             : enum SolidSyslogCircularBufferRunStarted
      35                 :             : {
      36                 :             :     RUN_STARTED_NONE,
      37                 :             :     RUN_STARTED_REFUSALS,
      38                 :             :     RUN_STARTED_EVICTIONS
      39                 :             : };
      40                 :             : 
      41                 :             : static bool CircularBuffer_Read(struct SolidSyslogBuffer* base, void* data, size_t maxSize, size_t* bytesRead);
      42                 :             : static void CircularBuffer_Write(struct SolidSyslogBuffer* base, const void* data, size_t size);
      43                 :             : static bool CircularBuffer_IsFull(struct SolidSyslogBuffer* base);
      44                 :             : 
      45                 :             : static inline struct SolidSyslogCircularBuffer* CircularBuffer_SelfFromBase(struct SolidSyslogBuffer* base);
      46                 :             : static inline void CircularBuffer_InstallDiscardPolicy(
      47                 :             :     struct SolidSyslogCircularBuffer* self,
      48                 :             :     SolidSyslogDiscardPolicyFunction configured,
      49                 :             :     void* context
      50                 :             : );
      51                 :             : 
      52                 :             : static inline void CircularBuffer_ReportRecordTooLarge(void);
      53                 :             : static enum SolidSyslogCircularBufferRunStarted CircularBuffer_StoreApplyingPolicy(
      54                 :             :     struct SolidSyslogCircularBuffer* self,
      55                 :             :     enum SolidSyslogDiscardPolicy policy,
      56                 :             :     const void* data,
      57                 :             :     size_t size
      58                 :             : );
      59                 :             : static inline bool CircularBuffer_PolicyEvictsFor(
      60                 :             :     const struct SolidSyslogCircularBuffer* self,
      61                 :             :     size_t recordBytes,
      62                 :             :     enum SolidSyslogDiscardPolicy policy
      63                 :             : );
      64                 :             : static inline bool CircularBuffer_CouldHoldWhenEmpty(const struct SolidSyslogCircularBuffer* self, size_t recordBytes);
      65                 :             : static inline void CircularBuffer_EvictUntilRecordFits(struct SolidSyslogCircularBuffer* self, size_t recordBytes);
      66                 :             : static inline void CircularBuffer_DropHead(struct SolidSyslogCircularBuffer* self);
      67                 :             : static inline enum SolidSyslogCircularBufferRunStarted CircularBuffer_KeepRecord(
      68                 :             :     struct SolidSyslogCircularBuffer* self,
      69                 :             :     const void* data,
      70                 :             :     size_t size,
      71                 :             :     bool evicted
      72                 :             : );
      73                 :             : static inline enum SolidSyslogCircularBufferRunStarted CircularBuffer_RefuseRecord(
      74                 :             :     struct SolidSyslogCircularBuffer* self,
      75                 :             :     size_t recordBytes
      76                 :             : );
      77                 :             : static void CircularBuffer_ReportRunStarted(enum SolidSyslogCircularBufferRunStarted started);
      78                 :             : static inline void CircularBuffer_ReportRecordExceedsMaxMessageSize(void);
      79                 :             : 
      80                 :             : static inline bool CircularBuffer_IsEmpty(const struct SolidSyslogCircularBuffer* self);
      81                 :             : static inline bool CircularBuffer_IsWrapped(const struct SolidSyslogCircularBuffer* self);
      82                 :             : static inline bool CircularBuffer_HeadAtWrapPoint(const struct SolidSyslogCircularBuffer* self);
      83                 :             : static inline bool CircularBuffer_RecordFits(const struct SolidSyslogCircularBuffer* self, size_t recordBytes);
      84                 :             : static inline bool CircularBuffer_RecordFitsAtTail(const struct SolidSyslogCircularBuffer* self, size_t recordBytes);
      85                 :             : static inline bool CircularBuffer_RecordFitsAfterWrap(const struct SolidSyslogCircularBuffer* self, size_t recordBytes);
      86                 :             : static inline void CircularBuffer_ResetToStart(struct SolidSyslogCircularBuffer* self);
      87                 :             : static inline void CircularBuffer_WrapTail(struct SolidSyslogCircularBuffer* self);
      88                 :             : static inline void CircularBuffer_ConsumeWrapMarker(struct SolidSyslogCircularBuffer* self);
      89                 :             : static inline void CircularBuffer_StoreRecord(struct SolidSyslogCircularBuffer* self, const void* data, size_t size);
      90                 :             : static inline void CircularBuffer_LoadRecord(struct SolidSyslogCircularBuffer* self, void* data, size_t* bytesRead);
      91                 :             : static inline size_t CircularBuffer_PeekRecordSize(const struct SolidSyslogCircularBuffer* self);
      92                 :             : 
      93                 :         234 : void SolidSyslogCircularBuffer_Initialise(
      94                 :             :     struct SolidSyslogBuffer* base,
      95                 :             :     struct SolidSyslogMutex* mutex,
      96                 :             :     uint8_t* ring,
      97                 :             :     size_t ringBytes,
      98                 :             :     SolidSyslogDiscardPolicyFunction getDiscardPolicy,
      99                 :             :     void* discardPolicyContext
     100                 :             : )
     101                 :             : {
     102                 :         234 :     struct SolidSyslogCircularBuffer* self = CircularBuffer_SelfFromBase(base);
     103                 :         234 :     self->Base.Read = CircularBuffer_Read;
     104                 :         234 :     self->Base.Write = CircularBuffer_Write;
     105                 :         234 :     self->Base.IsFull = CircularBuffer_IsFull;
     106                 :         234 :     self->Mutex = mutex;
     107                 :         234 :     self->Ring = ring;
     108                 :         234 :     self->Capacity = ringBytes;
     109                 :         234 :     CircularBuffer_InstallDiscardPolicy(self, getDiscardPolicy, discardPolicyContext);
     110                 :         234 :     self->LossReported = false;
     111                 :         234 :     self->EvictionReported = false;
     112                 :         234 :     self->TooLargeReported = false;
     113                 :         234 :     self->Full = false;
     114                 :         234 :     CircularBuffer_ResetToStart(self);
     115                 :         234 : }
     116                 :             : 
     117                 :         234 : static inline void CircularBuffer_InstallDiscardPolicy(
     118                 :             :     struct SolidSyslogCircularBuffer* self,
     119                 :             :     SolidSyslogDiscardPolicyFunction configured,
     120                 :             :     void* context
     121                 :             : )
     122                 :             : {
     123                 :         234 :     self->GetDiscardPolicy = SolidSyslogDiscardPolicy_Default;
     124                 :         234 :     self->DiscardPolicyContext = NULL;
     125         [ +  + ]:         234 :     if (configured != NULL)
     126                 :             :     {
     127                 :         215 :         self->GetDiscardPolicy = configured;
     128                 :         215 :         self->DiscardPolicyContext = context;
     129                 :             :     }
     130                 :         234 : }
     131                 :             : 
     132                 :         234 : void SolidSyslogCircularBuffer_Cleanup(struct SolidSyslogBuffer* base)
     133                 :             : {
     134                 :             :     /* Overwrite the abstract base with the shared NullBuffer vtable so
     135                 :             :      * use-after-destroy is a safe no-op rather than a NULL-fn-pointer crash. Derived
     136                 :             :      * fields are private to this TU; the next SolidSyslogCircularBuffer_Initialise overwrites them. */
     137                 :         234 :     *base = *SolidSyslogNullBuffer_Get();
     138                 :         234 : }
     139                 :             : 
     140                 :        8574 : static bool CircularBuffer_Read(struct SolidSyslogBuffer* base, void* data, size_t maxSize, size_t* bytesRead)
     141                 :             : {
     142                 :        8574 :     struct SolidSyslogCircularBuffer* self = CircularBuffer_SelfFromBase(base);
     143                 :        8574 :     bool tooLargeRunStarted = false;
     144                 :        8574 :     SolidSyslogMutex_Lock(self->Mutex);
     145                 :        8574 :     *bytesRead = 0;
     146                 :        8574 :     bool delivered = !CircularBuffer_IsEmpty(self);
     147         [ +  + ]:        8574 :     if (delivered)
     148                 :             :     {
     149         [ +  + ]:        4916 :         if (CircularBuffer_HeadAtWrapPoint(self))
     150                 :             :         {
     151                 :          12 :             CircularBuffer_ConsumeWrapMarker(self);
     152                 :             :         }
     153         [ +  + ]:        4916 :         if (CircularBuffer_PeekRecordSize(self) <= maxSize)
     154                 :             :         {
     155                 :        4902 :             CircularBuffer_LoadRecord(self, data, bytesRead);
     156                 :        4902 :             self->Full = false;
     157                 :        4902 :             self->TooLargeReported = false;
     158                 :             :         }
     159                 :             :         else
     160                 :             :         {
     161                 :          14 :             tooLargeRunStarted = !self->TooLargeReported;
     162                 :          14 :             self->TooLargeReported = true;
     163                 :          14 :             delivered = false;
     164                 :             :         }
     165                 :             :     }
     166                 :        8574 :     SolidSyslogMutex_Unlock(self->Mutex);
     167                 :             : 
     168                 :             :     /* Reported after the unlock: the handler is integrator code and may log,
     169                 :             :      * which re-enters Write and would deadlock on this same non-recursive mutex.
     170                 :             :      * The oversized branch changes only its latch, set under the mutex, so
     171                 :             :      * deferring the report costs nothing. */
     172         [ +  + ]:        8574 :     if (tooLargeRunStarted)
     173                 :             :     {
     174                 :           8 :         CircularBuffer_ReportRecordTooLarge();
     175                 :             :     }
     176                 :        8574 :     return delivered;
     177                 :             : }
     178                 :             : 
     179                 :           8 : static inline void CircularBuffer_ReportRecordTooLarge(void)
     180                 :             : {
     181                 :           8 :     CircularBuffer_Report(
     182                 :             :         SOLIDSYSLOG_SEVERITY_ERROR,
     183                 :             :         SOLIDSYSLOG_CAT_BUFFER_BACKEND_FAILED,
     184                 :             :         SOLIDSYSLOG_CIRCULAR_BUFFER_ERROR_RECORD_TOO_LARGE
     185                 :             :     );
     186                 :           8 : }
     187                 :             : 
     188                 :       16073 : static inline struct SolidSyslogCircularBuffer* CircularBuffer_SelfFromBase(struct SolidSyslogBuffer* base)
     189                 :             : {
     190                 :       16073 :     return (struct SolidSyslogCircularBuffer*) base;
     191                 :             : }
     192                 :             : 
     193                 :       15962 : static inline bool CircularBuffer_IsEmpty(const struct SolidSyslogCircularBuffer* self)
     194                 :             : {
     195                 :       15962 :     return self->Head == self->Tail;
     196                 :             : }
     197                 :             : 
     198                 :        5650 : static inline bool CircularBuffer_HeadAtWrapPoint(const struct SolidSyslogCircularBuffer* self)
     199                 :             : {
     200                 :        5650 :     return self->Head >= self->WrapPoint;
     201                 :             : }
     202                 :             : 
     203                 :          31 : static inline void CircularBuffer_ConsumeWrapMarker(struct SolidSyslogCircularBuffer* self)
     204                 :             : {
     205                 :          31 :     self->Head = 0;
     206                 :          31 :     self->WrapPoint = self->Capacity;
     207                 :          31 : }
     208                 :             : 
     209                 :       10552 : static inline size_t CircularBuffer_PeekRecordSize(const struct SolidSyslogCircularBuffer* self)
     210                 :             : {
     211                 :       10552 :     return ((size_t) self->Ring[self->Head]) | (((size_t) self->Ring[self->Head + 1U]) << 8U);
     212                 :             : }
     213                 :             : 
     214                 :        4902 : static inline void CircularBuffer_LoadRecord(struct SolidSyslogCircularBuffer* self, void* data, size_t* bytesRead)
     215                 :             : {
     216                 :        4902 :     size_t recordSize = CircularBuffer_PeekRecordSize(self);
     217                 :        4902 :     (void) memcpy(data, &self->Ring[self->Head + HEADER_BYTES], recordSize);
     218                 :        4902 :     self->Head += HEADER_BYTES + recordSize;
     219                 :        4902 :     *bytesRead = recordSize;
     220                 :        4902 : }
     221                 :             : 
     222                 :        6656 : static void CircularBuffer_Write(struct SolidSyslogBuffer* base, const void* data, size_t size)
     223                 :             : {
     224                 :        6656 :     struct SolidSyslogCircularBuffer* self = CircularBuffer_SelfFromBase(base);
     225         [ +  + ]:        6656 :     if (size <= SOLIDSYSLOG_MAX_MESSAGE_SIZE)
     226                 :             :     {
     227                 :             :         /* The policy is asked before the lock and the loss reported after it,
     228                 :             :          * as Read reports: both are integrator code that may log, which
     229                 :             :          * re-enters Write. */
     230                 :        6654 :         enum SolidSyslogDiscardPolicy policy = self->GetDiscardPolicy(self->DiscardPolicyContext);
     231                 :        6654 :         enum SolidSyslogCircularBufferRunStarted started = CircularBuffer_StoreApplyingPolicy(self, policy, data, size);
     232                 :        6654 :         CircularBuffer_ReportRunStarted(started);
     233                 :             :     }
     234                 :             :     else
     235                 :             :     {
     236                 :           2 :         CircularBuffer_ReportRecordExceedsMaxMessageSize();
     237                 :             :     }
     238                 :        6656 : }
     239                 :             : 
     240                 :             : /* Stores the record, making room for it first where the discard policy says
     241                 :             :  * to, and says which run of losses, if any, this write starts: the one write
     242                 :             :  * of each run that is reported. A run is marked under the lock, so a write
     243                 :             :  * from the handler reporting it finds it already reported. */
     244                 :        6654 : static enum SolidSyslogCircularBufferRunStarted CircularBuffer_StoreApplyingPolicy(
     245                 :             :     struct SolidSyslogCircularBuffer* self,
     246                 :             :     enum SolidSyslogDiscardPolicy policy,
     247                 :             :     const void* data,
     248                 :             :     size_t size
     249                 :             : )
     250                 :             : {
     251                 :        6654 :     enum SolidSyslogCircularBufferRunStarted started = RUN_STARTED_NONE;
     252                 :        6654 :     SolidSyslogMutex_Lock(self->Mutex);
     253         [ +  + ]:        6654 :     if (CircularBuffer_IsEmpty(self))
     254                 :             :     {
     255                 :        2320 :         CircularBuffer_ResetToStart(self);
     256                 :             :     }
     257                 :        6654 :     size_t recordBytes = HEADER_BYTES + size;
     258                 :        6654 :     bool evicted = false;
     259   [ +  +  +  + ]:        6654 :     if (!CircularBuffer_RecordFits(self, recordBytes) && CircularBuffer_PolicyEvictsFor(self, recordBytes, policy))
     260                 :             :     {
     261                 :         718 :         CircularBuffer_EvictUntilRecordFits(self, recordBytes);
     262                 :         718 :         evicted = true;
     263                 :             :     }
     264         [ +  + ]:        6654 :     if (CircularBuffer_RecordFits(self, recordBytes))
     265                 :             :     {
     266                 :        5737 :         started = CircularBuffer_KeepRecord(self, data, size, evicted);
     267                 :             :     }
     268                 :             :     else
     269                 :             :     {
     270                 :         917 :         started = CircularBuffer_RefuseRecord(self, recordBytes);
     271                 :             :     }
     272                 :        6654 :     SolidSyslogMutex_Unlock(self->Mutex);
     273                 :        6654 :     return started;
     274                 :             : }
     275                 :             : 
     276                 :             : /* Only Oldest makes room, and only for a record the ring could hold at all:
     277                 :             :  * evicting everything for one that still would not fit loses records for
     278                 :             :  * nothing. */
     279                 :        1635 : static inline bool CircularBuffer_PolicyEvictsFor(
     280                 :             :     const struct SolidSyslogCircularBuffer* self,
     281                 :             :     size_t recordBytes,
     282                 :             :     enum SolidSyslogDiscardPolicy policy
     283                 :             : )
     284                 :             : {
     285   [ +  +  +  + ]:        1635 :     return CircularBuffer_CouldHoldWhenEmpty(self, recordBytes) && (policy == SOLIDSYSLOG_DISCARD_POLICY_OLDEST);
     286                 :             : }
     287                 :             : 
     288                 :        2552 : static inline bool CircularBuffer_CouldHoldWhenEmpty(const struct SolidSyslogCircularBuffer* self, size_t recordBytes)
     289                 :             : {
     290                 :        2552 :     return recordBytes <= self->Capacity;
     291                 :             : }
     292                 :             : 
     293                 :             : /* Drops records from the head until the new one fits; an emptied ring always
     294                 :             :  * fits a record it could hold at all, so this ends. */
     295                 :         718 : static inline void CircularBuffer_EvictUntilRecordFits(struct SolidSyslogCircularBuffer* self, size_t recordBytes)
     296                 :             : {
     297         [ +  + ]:        1452 :     while (!CircularBuffer_RecordFits(self, recordBytes))
     298                 :             :     {
     299                 :         734 :         CircularBuffer_DropHead(self);
     300                 :             :     }
     301                 :         718 : }
     302                 :             : 
     303                 :             : /* Skips the head record as Read would take it, without copying it out. */
     304                 :         734 : static inline void CircularBuffer_DropHead(struct SolidSyslogCircularBuffer* self)
     305                 :             : {
     306         [ +  + ]:         734 :     if (CircularBuffer_HeadAtWrapPoint(self))
     307                 :             :     {
     308                 :          19 :         CircularBuffer_ConsumeWrapMarker(self);
     309                 :             :     }
     310                 :         734 :     self->Head += HEADER_BYTES + CircularBuffer_PeekRecordSize(self);
     311         [ +  + ]:         734 :     if (CircularBuffer_IsEmpty(self))
     312                 :             :     {
     313                 :          10 :         CircularBuffer_ResetToStart(self);
     314                 :             :     }
     315                 :         734 : }
     316                 :             : 
     317                 :             : /* A record kept ends a run of refusals; one kept without evicting ends a run
     318                 :             :  * of evictions. The ring is full afterwards only if it had to make room. */
     319                 :        5737 : static inline enum SolidSyslogCircularBufferRunStarted CircularBuffer_KeepRecord(
     320                 :             :     struct SolidSyslogCircularBuffer* self,
     321                 :             :     const void* data,
     322                 :             :     size_t size,
     323                 :             :     bool evicted
     324                 :             : )
     325                 :             : {
     326                 :        5737 :     enum SolidSyslogCircularBufferRunStarted started = RUN_STARTED_NONE;
     327         [ +  + ]:        5737 :     if (!CircularBuffer_RecordFitsAtTail(self, HEADER_BYTES + size))
     328                 :             :     {
     329                 :          33 :         CircularBuffer_WrapTail(self);
     330                 :             :     }
     331                 :        5737 :     CircularBuffer_StoreRecord(self, data, size);
     332                 :        5737 :     self->LossReported = false;
     333   [ +  +  +  + ]:        5737 :     if (evicted && !self->EvictionReported)
     334                 :             :     {
     335                 :          29 :         started = RUN_STARTED_EVICTIONS;
     336                 :             :     }
     337                 :        5737 :     self->EvictionReported = evicted;
     338                 :        5737 :     self->Full = evicted;
     339                 :        5737 :     return started;
     340                 :             : }
     341                 :             : 
     342                 :             : /* A refusal evicts nothing, so it ends a run of evictions. It leaves the ring
     343                 :             :  * full unless the record could never have fitted, which is a configuration
     344                 :             :  * fault rather than Log outrunning Service. */
     345                 :         917 : static inline enum SolidSyslogCircularBufferRunStarted CircularBuffer_RefuseRecord(
     346                 :             :     struct SolidSyslogCircularBuffer* self,
     347                 :             :     size_t recordBytes
     348                 :             : )
     349                 :             : {
     350                 :         917 :     enum SolidSyslogCircularBufferRunStarted started = self->LossReported ? RUN_STARTED_NONE : RUN_STARTED_REFUSALS;
     351                 :         917 :     self->LossReported = true;
     352                 :         917 :     self->EvictionReported = false;
     353                 :         917 :     self->Full = CircularBuffer_CouldHoldWhenEmpty(self, recordBytes);
     354                 :         917 :     return started;
     355                 :             : }
     356                 :             : 
     357                 :        6654 : static void CircularBuffer_ReportRunStarted(enum SolidSyslogCircularBufferRunStarted started)
     358                 :             : {
     359         [ +  + ]:        6654 :     if (started == RUN_STARTED_REFUSALS)
     360                 :             :     {
     361                 :          52 :         CircularBuffer_Report(
     362                 :             :             SOLIDSYSLOG_SEVERITY_WARNING,
     363                 :             :             SOLIDSYSLOG_CAT_BUFFER_RECORDS_LOST,
     364                 :             :             SOLIDSYSLOG_CIRCULAR_BUFFER_ERROR_RECORD_REFUSED
     365                 :             :         );
     366                 :             :     }
     367         [ +  + ]:        6602 :     else if (started == RUN_STARTED_EVICTIONS)
     368                 :             :     {
     369                 :          29 :         CircularBuffer_Report(
     370                 :             :             SOLIDSYSLOG_SEVERITY_WARNING,
     371                 :             :             SOLIDSYSLOG_CAT_BUFFER_RECORDS_LOST,
     372                 :             :             SOLIDSYSLOG_CIRCULAR_BUFFER_ERROR_RECORDS_EVICTED
     373                 :             :         );
     374                 :             :     }
     375                 :             :     else
     376                 :             :     {
     377                 :             :         /* Kept without loss, or a run already reported. */
     378                 :             :     }
     379                 :        6654 : }
     380                 :             : 
     381                 :         609 : static bool CircularBuffer_IsFull(struct SolidSyslogBuffer* base)
     382                 :             : {
     383                 :         609 :     struct SolidSyslogCircularBuffer* self = CircularBuffer_SelfFromBase(base);
     384                 :         609 :     SolidSyslogMutex_Lock(self->Mutex);
     385                 :         609 :     bool full = self->Full;
     386                 :         609 :     SolidSyslogMutex_Unlock(self->Mutex);
     387                 :         609 :     return full;
     388                 :             : }
     389                 :             : 
     390                 :             : /* SolidSyslog_Log never formats a message this large, so only a caller writing
     391                 :             :  * to the buffer directly can hand one over. */
     392                 :           2 : static inline void CircularBuffer_ReportRecordExceedsMaxMessageSize(void)
     393                 :             : {
     394                 :           2 :     CircularBuffer_Report(
     395                 :             :         SOLIDSYSLOG_BAD_ARGUMENT_SEVERITY,
     396                 :             :         SOLIDSYSLOG_CAT_BAD_ARGUMENT,
     397                 :             :         SOLIDSYSLOG_CIRCULAR_BUFFER_ERROR_RECORD_EXCEEDS_MAX_MESSAGE_SIZE
     398                 :             :     );
     399                 :           2 : }
     400                 :             : 
     401                 :       23849 : static inline bool CircularBuffer_IsWrapped(const struct SolidSyslogCircularBuffer* self)
     402                 :             : {
     403                 :       23849 :     return self->Head > self->Tail;
     404                 :             : }
     405                 :             : 
     406                 :       14760 : static inline bool CircularBuffer_RecordFits(const struct SolidSyslogCircularBuffer* self, size_t recordBytes)
     407                 :             : {
     408   [ +  +  +  + ]:       14760 :     return CircularBuffer_RecordFitsAtTail(self, recordBytes) || CircularBuffer_RecordFitsAfterWrap(self, recordBytes);
     409                 :             : }
     410                 :             : 
     411                 :       20497 : static inline bool CircularBuffer_RecordFitsAtTail(const struct SolidSyslogCircularBuffer* self, size_t recordBytes)
     412                 :             : {
     413                 :       20497 :     bool fits = false;
     414         [ +  + ]:       20497 :     if (CircularBuffer_IsWrapped(self))
     415                 :             :     {
     416                 :        3418 :         fits = (self->Tail + recordBytes) < self->Head;
     417                 :             :     }
     418                 :             :     else
     419                 :             :     {
     420                 :       17079 :         fits = (self->Tail + recordBytes) <= self->Capacity;
     421                 :             :     }
     422                 :       20497 :     return fits;
     423                 :             : }
     424                 :             : 
     425                 :        3352 : static inline bool CircularBuffer_RecordFitsAfterWrap(const struct SolidSyslogCircularBuffer* self, size_t recordBytes)
     426                 :             : {
     427   [ +  +  +  + ]:        3352 :     return (!CircularBuffer_IsWrapped(self)) && (recordBytes < self->Head);
     428                 :             : }
     429                 :             : 
     430                 :        2564 : static inline void CircularBuffer_ResetToStart(struct SolidSyslogCircularBuffer* self)
     431                 :             : {
     432                 :        2564 :     self->Head = 0;
     433                 :        2564 :     self->Tail = 0;
     434                 :        2564 :     self->WrapPoint = self->Capacity;
     435                 :        2564 : }
     436                 :             : 
     437                 :          33 : static inline void CircularBuffer_WrapTail(struct SolidSyslogCircularBuffer* self)
     438                 :             : {
     439                 :          33 :     self->WrapPoint = self->Tail;
     440                 :          33 :     self->Tail = 0;
     441                 :          33 : }
     442                 :             : 
     443                 :        5737 : static inline void CircularBuffer_StoreRecord(struct SolidSyslogCircularBuffer* self, const void* data, size_t size)
     444                 :             : {
     445                 :        5737 :     self->Ring[self->Tail] = (uint8_t) (size & 0xFFU);
     446                 :        5737 :     self->Ring[self->Tail + 1U] = (uint8_t) ((size >> 8U) & 0xFFU);
     447                 :        5737 :     (void) memcpy(&self->Ring[self->Tail + HEADER_BYTES], data, size);
     448                 :        5737 :     self->Tail += HEADER_BYTES + size;
     449                 :        5737 : }
        

Generated by: LCOV version 2.0-1