LCOV - code coverage report
Current view: top level - core - direct_buffer.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 62 66 93.9 %
Date: 2026-02-22 12:14:12 Functions: 8 8 100.0 %

          Line data    Source code
       1             : /* direct_buffer.c - Tier 2 direct buffers for large messages
       2             :  *
       3             :  * Implements pre-allocated buffers for messages > 256 bytes.
       4             :  * One buffer per peer per direction avoids memory fragmentation
       5             :  * and provides predictable memory usage on Classic Mac.
       6             :  */
       7             : 
       8             : #include "direct_buffer.h"
       9             : #include "pt_compat.h"
      10             : #include "../../include/peertalk.h"
      11             : 
      12             : /* ========================================================================
      13             :  * Buffer Lifecycle
      14             :  * ======================================================================== */
      15             : 
      16         144 : int pt_direct_buffer_init(pt_direct_buffer *buf, uint16_t capacity)
      17             : {
      18         144 :     if (!buf) {
      19           1 :         return PT_ERR_INVALID_PARAM;
      20             :     }
      21             : 
      22             :     /* Validate capacity */
      23         143 :     if (capacity == 0) {
      24           1 :         capacity = PT_DIRECT_DEFAULT_SIZE;
      25             :     }
      26         143 :     if (capacity > PT_DIRECT_MAX_SIZE) {
      27           1 :         return PT_ERR_INVALID_PARAM;
      28             :     }
      29             : 
      30             :     /* Allocate data buffer */
      31         142 :     buf->data = (uint8_t *)pt_alloc(capacity);
      32         142 :     if (!buf->data) {
      33           0 :         return PT_ERR_NO_MEMORY;
      34             :     }
      35             : 
      36             :     /* Initialize state */
      37         142 :     buf->state = PT_DIRECT_IDLE;
      38         142 :     buf->length = 0;
      39         142 :     buf->capacity = capacity;
      40         142 :     buf->priority = PT_PRIORITY_NORMAL;
      41         142 :     buf->msg_flags = 0;
      42             : 
      43         142 :     return PT_OK;
      44             : }
      45             : 
      46          17 : void pt_direct_buffer_free(pt_direct_buffer *buf)
      47             : {
      48          17 :     if (!buf) {
      49           1 :         return;
      50             :     }
      51             : 
      52          16 :     if (buf->data) {
      53          16 :         pt_free(buf->data);
      54          16 :         buf->data = NULL;
      55             :     }
      56             : 
      57          16 :     buf->state = PT_DIRECT_IDLE;
      58          16 :     buf->length = 0;
      59          16 :     buf->capacity = 0;
      60             : }
      61             : 
      62             : /* ========================================================================
      63             :  * Send Path Operations
      64             :  * ======================================================================== */
      65             : 
      66          90 : int pt_direct_buffer_queue(pt_direct_buffer *buf, const void *data,
      67             :                            uint16_t length, uint8_t priority)
      68             : {
      69          90 :     if (!buf || !data || length == 0) {
      70           2 :         return PT_ERR_INVALID_PARAM;
      71             :     }
      72             : 
      73             :     /* Check if buffer is available */
      74          88 :     if (buf->state != PT_DIRECT_IDLE) {
      75           2 :         return PT_ERR_WOULD_BLOCK;
      76             :     }
      77             : 
      78             :     /* Check message size */
      79          86 :     if (length > buf->capacity) {
      80           1 :         return PT_ERR_MESSAGE_TOO_LARGE;
      81             :     }
      82             : 
      83             :     /* Copy data to buffer */
      84          85 :     pt_memcpy(buf->data, data, length);
      85          85 :     buf->length = length;
      86          85 :     buf->priority = priority;
      87          85 :     buf->msg_flags = 0;  /* Caller can override for fragments */
      88             : 
      89             :     /* Mark as queued - atomic write last for visibility */
      90          85 :     buf->state = PT_DIRECT_QUEUED;
      91             : 
      92          85 :     return PT_OK;
      93             : }
      94             : 
      95          81 : int pt_direct_buffer_mark_sending(pt_direct_buffer *buf)
      96             : {
      97          81 :     if (!buf) {
      98           0 :         return -1;
      99             :     }
     100             : 
     101          81 :     if (buf->state != PT_DIRECT_QUEUED) {
     102           1 :         return -1;
     103             :     }
     104             : 
     105          80 :     buf->state = PT_DIRECT_SENDING;
     106          80 :     return 0;
     107             : }
     108             : 
     109          80 : void pt_direct_buffer_complete(pt_direct_buffer *buf)
     110             : {
     111          80 :     if (!buf) {
     112           0 :         return;
     113             :     }
     114             : 
     115             :     /* Reset to idle - buffer available for next message */
     116          80 :     buf->length = 0;
     117          80 :     buf->state = PT_DIRECT_IDLE;
     118             : }
     119             : 
     120         321 : int pt_direct_buffer_ready(const pt_direct_buffer *buf)
     121             : {
     122         321 :     if (!buf) {
     123           1 :         return 0;
     124             :     }
     125         320 :     return (buf->state == PT_DIRECT_QUEUED) ? 1 : 0;
     126             : }
     127             : 
     128           4 : int pt_direct_buffer_available(const pt_direct_buffer *buf)
     129             : {
     130           4 :     if (!buf) {
     131           1 :         return 0;
     132             :     }
     133           3 :     return (buf->state == PT_DIRECT_IDLE) ? 1 : 0;
     134             : }
     135             : 
     136             : /* ========================================================================
     137             :  * Receive Path Operations
     138             :  * ======================================================================== */
     139             : 
     140           2 : int pt_direct_buffer_receive(pt_direct_buffer *buf, const void *data,
     141             :                              uint16_t length)
     142             : {
     143           2 :     if (!buf || !data) {
     144           0 :         return PT_ERR_INVALID_PARAM;
     145             :     }
     146             : 
     147             :     /* Check message size */
     148           2 :     if (length > buf->capacity) {
     149           1 :         return PT_ERR_MESSAGE_TOO_LARGE;
     150             :     }
     151             : 
     152             :     /* Copy incoming data
     153             :      * Note: For receive path, we don't track state - data is delivered
     154             :      * immediately to application callback. Buffer is just temporary storage.
     155             :      */
     156           1 :     pt_memcpy(buf->data, data, length);
     157           1 :     buf->length = length;
     158             : 
     159           1 :     return PT_OK;
     160             : }

Generated by: LCOV version 1.14