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 : }