diff --git a/libudpard/udpard.c b/libudpard/udpard.c index 9ff828b..c77b018 100644 --- a/libudpard/udpard.c +++ b/libudpard/udpard.c @@ -5,6 +5,7 @@ #include "udpard.h" #include "_udpard_cavl.h" + #include // --------------------------------------------- BUILD CONFIGURATION --------------------------------------------- @@ -280,9 +281,6 @@ typedef struct { struct UdpardTxItem base; enum UdpardPriority priority; ///< Do we need this exposed in the public structure? We already have DSCP there. - // The MISRA violation here is hard to get rid of without having to allocate a separate memory block for the - // payload, which is much more costly risk-wise. - byte_t payload_buffer[]; // NOSONAR MISRA C 18.7 Flexible array member. } TxItem; /// Chain of TX frames prepared for insertion into a TX queue. @@ -293,15 +291,21 @@ typedef struct size_t count; } TxChain; -static inline TxItem* txNewItem(const struct UdpardMemoryResource memory, - const uint_least8_t dscp_value_per_priority[UDPARD_PRIORITY_MAX + 1U], - const UdpardMicrosecond deadline_usec, - const enum UdpardPriority priority, - const struct UdpardUDPIPEndpoint endpoint, - const size_t datagram_payload_size, - void* const user_transfer_reference) +static inline bool txValidateMemoryResources(const struct UdpardTxMemoryResources memory) +{ + return (memory.fragment.allocate != NULL) && (memory.fragment.deallocate != NULL) && + (memory.payload.allocate != NULL) && (memory.payload.deallocate != NULL); +} + +static inline TxItem* txNewItem(const struct UdpardTxMemoryResources memory, + const uint_least8_t dscp_value_per_priority[UDPARD_PRIORITY_MAX + 1U], + const UdpardMicrosecond deadline_usec, + const enum UdpardPriority priority, + const struct UdpardUDPIPEndpoint endpoint, + const size_t datagram_payload_size, + void* const user_transfer_reference) { - TxItem* const out = (TxItem*) memAlloc(memory, sizeof(TxItem) + datagram_payload_size); + TxItem* out = memAlloc(memory.fragment, sizeof(TxItem)); if (out != NULL) { // No tree linkage by default. @@ -317,9 +321,18 @@ static inline TxItem* txNewItem(const struct UdpardMemoryResource memory, out->base.dscp = dscp_value_per_priority[priority]; out->base.destination = endpoint; out->base.user_transfer_reference = user_transfer_reference; - // The payload points to the buffer already allocated. - out->base.datagram_payload.size = datagram_payload_size; - out->base.datagram_payload.data = &out->payload_buffer[0]; + + void* const payload_data = memAlloc(memory.payload, datagram_payload_size); + if (NULL != payload_data) + { + out->base.datagram_payload.data = payload_data; + out->base.datagram_payload.size = datagram_payload_size; + } + else + { + memFree(memory.fragment, sizeof(TxItem), out); + out = NULL; + } } return out; } @@ -390,14 +403,14 @@ static inline byte_t* txSerializeHeader(byte_t* const destination_buffe /// Produces a chain of Tx queue items for later insertion into the Tx queue. The tail is NULL if OOM. /// The caller is responsible for freeing the memory allocated for the chain. -static inline TxChain txMakeChain(const struct UdpardMemoryResource memory, - const uint_least8_t dscp_value_per_priority[UDPARD_PRIORITY_MAX + 1U], - const size_t mtu, - const UdpardMicrosecond deadline_usec, - const TransferMetadata meta, - const struct UdpardUDPIPEndpoint endpoint, - const struct UdpardPayload payload, - void* const user_transfer_reference) +static inline TxChain txMakeChain(const struct UdpardTxMemoryResources memory, + const uint_least8_t dscp_value_per_priority[UDPARD_PRIORITY_MAX + 1U], + const size_t mtu, + const UdpardMicrosecond deadline_usec, + const TransferMetadata meta, + const struct UdpardUDPIPEndpoint endpoint, + const struct UdpardPayload payload, + void* const user_transfer_reference) { UDPARD_ASSERT(mtu > 0); UDPARD_ASSERT((payload.data != NULL) || (payload.size == 0U)); @@ -430,8 +443,9 @@ static inline TxChain txMakeChain(const struct UdpardMemoryResource memory, { break; } - const bool last = (payload_size_with_crc - offset) <= mtu; - byte_t* write_ptr = txSerializeHeader(&item->payload_buffer[0], meta, (uint32_t) out.count, last); + const bool last = (payload_size_with_crc - offset) <= mtu; + byte_t* const dst_buffer = item->base.datagram_payload.data; + byte_t* write_ptr = txSerializeHeader(dst_buffer, meta, (uint32_t) out.count, last); if (offset < payload.size) { const size_t progress = smaller(payload.size - offset, mtu); @@ -446,7 +460,7 @@ static inline TxChain txMakeChain(const struct UdpardMemoryResource memory, { const size_t crc_offset = offset - payload.size; UDPARD_ASSERT(crc_offset < TRANSFER_CRC_SIZE_BYTES); - const size_t available = item->base.datagram_payload.size - (size_t) (write_ptr - &item->payload_buffer[0]); + const size_t available = item->base.datagram_payload.size - (size_t) (write_ptr - dst_buffer); UDPARD_ASSERT(available <= TRANSFER_CRC_SIZE_BYTES); const size_t write_size = smaller(TRANSFER_CRC_SIZE_BYTES - crc_offset, available); // NOLINTNEXTLINE(clang-analyzer-security.insecureAPI.DeprecatedOrUnsafeBufferHandling) @@ -517,7 +531,7 @@ static inline int32_t txPush(struct UdpardTx* const tx, while (head != NULL) { struct UdpardTxItem* const next = head->next_in_transfer; - memFree(tx->memory, sizeof(TxItem) + head->datagram_payload.size, head); + udpardTxFree(tx->memory, head); head = next; } } @@ -526,13 +540,13 @@ static inline int32_t txPush(struct UdpardTx* const tx, return out; } -int_fast8_t udpardTxInit(struct UdpardTx* const self, - const UdpardNodeID* const local_node_id, - const size_t queue_capacity, - const struct UdpardMemoryResource memory) +int_fast8_t udpardTxInit(struct UdpardTx* const self, + const UdpardNodeID* const local_node_id, + const size_t queue_capacity, + const struct UdpardTxMemoryResources memory) { int_fast8_t ret = -UDPARD_ERROR_ARGUMENT; - if ((NULL != self) && (NULL != local_node_id) && (memory.allocate != NULL) && (memory.deallocate != NULL)) + if ((NULL != self) && (NULL != local_node_id) && txValidateMemoryResources(memory)) { ret = 0; memZero(sizeof(*self), self); @@ -639,14 +653,14 @@ int32_t udpardTxRespond(struct UdpardTx* const self, return out; } -const struct UdpardTxItem* udpardTxPeek(const struct UdpardTx* const self) +struct UdpardTxItem* udpardTxPeek(const struct UdpardTx* const self) { - const struct UdpardTxItem* out = NULL; + struct UdpardTxItem* out = NULL; if (self != NULL) { // Paragraph 6.7.2.1.15 of the C standard says: // A pointer to a structure object, suitably converted, points to its initial member, and vice versa. - out = (const struct UdpardTxItem*) (void*) cavlFindExtremum(self->root, false); + out = (struct UdpardTxItem*) (void*) cavlFindExtremum(self->root, false); } return out; } @@ -671,11 +685,16 @@ struct UdpardTxItem* udpardTxPop(struct UdpardTx* const self, const struct Udpar return out; } -void udpardTxFree(const struct UdpardMemoryResource memory, struct UdpardTxItem* const item) +void udpardTxFree(const struct UdpardTxMemoryResources memory, struct UdpardTxItem* const item) { if (item != NULL) { - memFree(memory, sizeof(TxItem) + item->datagram_payload.size, item); + if (item->datagram_payload.data != NULL) + { + memFree(memory.payload, item->datagram_payload.size, item->datagram_payload.data); + } + + memFree(memory.fragment, sizeof(TxItem), item); } } diff --git a/libudpard/udpard.h b/libudpard/udpard.h index 0df85b9..3223d32 100644 --- a/libudpard/udpard.h +++ b/libudpard/udpard.h @@ -373,6 +373,28 @@ struct UdpardMemoryResource // ================================================= TX PIPELINE ================================================= // ===================================================================================================================== +/// The set of memory resources is used per an TX pipeline instance. +/// These are used to serve the memory needs of the library to keep state while assembling outgoing frames. +/// Several memory resources are provided to enable fine control over the allocated memory. +/// +/// This TX queue uses these memory resources for allocating the enqueued items (UDP datagrams). +/// There are exactly two allocations per enqueued item: +/// - the first for bookkeeping purposes (UdpardTxItem) +/// - second for payload storage (the frame data) +/// In a simple application, there would be just one memory resource shared by all parts of the library. +/// If the application knows its MTU, it can use block allocation to avoid extrinsic fragmentation. +/// +struct UdpardTxMemoryResources +{ + /// The fragment handles are allocated per payload fragment; each handle contains a pointer to its fragment. + /// Each instance is of a very small fixed size, so a trivial zero-fragmentation block allocator is enough. + struct UdpardMemoryResource fragment; + + /// The payload fragments are allocated per payload frame; each payload fragment is at most MTU-sized buffer, + /// so a trivial zero-fragmentation MTU-sized block allocator is enough if MTU is known in advance. + struct UdpardMemoryResource payload; +}; + /// The transmission pipeline is a prioritized transmission queue that keeps UDP datagrams (aka transport frames) /// destined for transmission via one network interface. /// Applications with redundant network interfaces are expected to have one instance of this type per interface. @@ -424,12 +446,8 @@ struct UdpardTx /// The value can be changed arbitrarily at any time between enqueue operations. uint_least8_t dscp_value_per_priority[UDPARD_PRIORITY_MAX + 1U]; - /// The memory resource used by this queue for allocating the enqueued items (UDP datagrams). - /// There is exactly one allocation per enqueued item, each allocation contains both the UdpardTxItem - /// and its payload, hence the size is variable. - /// In a simple application there would be just one memory resource shared by all parts of the library. - /// If the application knows its MTU, it can use block allocation to avoid extrinsic fragmentation. - struct UdpardMemoryResource memory; + /// Refer to UdpardTxMemoryResources. + struct UdpardTxMemoryResources memory; /// The number of frames that are currently contained in the queue, initially zero. /// READ-ONLY @@ -490,10 +508,10 @@ struct UdpardTxItem /// /// The return value is zero on success, otherwise it is a negative error code. /// The time complexity is constant. This function does not invoke the dynamic memory manager. -int_fast8_t udpardTxInit(struct UdpardTx* const self, - const UdpardNodeID* const local_node_id, - const size_t queue_capacity, - const struct UdpardMemoryResource memory); +int_fast8_t udpardTxInit(struct UdpardTx* const self, + const UdpardNodeID* const local_node_id, + const size_t queue_capacity, + const struct UdpardTxMemoryResources memory); /// This function serializes a message transfer into a sequence of UDP datagrams and inserts them into the prioritized /// transmission queue at the appropriate position. Afterwards, the application is supposed to take the enqueued frames @@ -613,23 +631,20 @@ int32_t udpardTxRespond(struct UdpardTx* const self, /// /// If the queue is non-empty, the returned value is a pointer to its top element (i.e., the next item to transmit). /// The returned pointer points to an object allocated in the dynamic storage; it should be eventually freed by the -/// application by calling udpardTxFree with UdpardTx::memory. The memory shall not be freed before the item is removed +/// application by calling `udpardTxFree`. The memory shall not be freed before the item is removed /// from the queue by calling udpardTxPop; this is because until udpardTxPop is executed, the library retains /// ownership of the item. The pointer retains validity until explicitly freed by the application; in other words, /// calling udpardTxPop does not invalidate the object. /// -/// The payload buffer is located shortly after the object itself, in the same memory fragment. The application shall -/// not attempt to free it. -/// /// Calling functions that modify the queue may cause the next invocation to return a different pointer. /// /// The time complexity is logarithmic of the queue size. This function does not invoke the dynamic memory manager. -const struct UdpardTxItem* udpardTxPeek(const struct UdpardTx* const self); +struct UdpardTxItem* udpardTxPeek(const struct UdpardTx* const self); /// This function transfers the ownership of the specified item of the prioritized transmission queue from the queue /// to the application. The item does not necessarily need to be the top one -- it is safe to dequeue any item. /// The item is dequeued but not invalidated; it is the responsibility of the application to deallocate its memory -/// later. The memory SHALL NOT be deallocated UNTIL this function is invoked. +/// later. The memory SHALL NOT be deallocated UNTIL this function is invoked (use `udpardTxFree` helper). /// The function returns the same pointer that it is given except that it becomes mutable. /// /// If any of the arguments are NULL, the function has no effect and returns NULL. @@ -637,11 +652,12 @@ const struct UdpardTxItem* udpardTxPeek(const struct UdpardTx* const self); /// The time complexity is logarithmic of the queue size. This function does not invoke the dynamic memory manager. struct UdpardTxItem* udpardTxPop(struct UdpardTx* const self, const struct UdpardTxItem* const item); -/// This is a simple helper that frees the memory allocated for the item with the correct size. -/// It is needed because the application does not have access to the required context to compute the size. -/// If the chosen allocator does not leverage the size information, the deallocation function can be invoked directly. +/// This is a simple helper that frees the memory allocated for the item and its payload, +/// using the correct sizes and memory resources. /// If the item argument is NULL, the function has no effect. The time complexity is constant. -void udpardTxFree(const struct UdpardMemoryResource memory, struct UdpardTxItem* const item); +/// If the item frame payload is NULL then it is assumed that the payload buffer was already freed, +/// or moved to a different owner (f.e. to media layer). +void udpardTxFree(const struct UdpardTxMemoryResources memory, struct UdpardTxItem* const item); // ===================================================================================================================== // ================================================= RX PIPELINE ================================================= diff --git a/tests/src/test_e2e.cpp b/tests/src/test_e2e.cpp index d3437aa..b7de0ee 100644 --- a/tests/src/test_e2e.cpp +++ b/tests/src/test_e2e.cpp @@ -73,7 +73,10 @@ void testPubSub() instrumentedAllocatorNew(&alloc_rx_session); instrumentedAllocatorNew(&alloc_rx_fragment); instrumentedAllocatorNew(&alloc_rx_payload); - const auto mem_tx = instrumentedAllocatorMakeMemoryResource(&alloc_tx); + const UdpardTxMemoryResources mem_tx{ + .fragment = instrumentedAllocatorMakeMemoryResource(&alloc_tx), + .payload = instrumentedAllocatorMakeMemoryResource(&alloc_tx), + }; const UdpardRxMemoryResources mem_rx{ .session = instrumentedAllocatorMakeMemoryResource(&alloc_rx_session), .fragment = instrumentedAllocatorMakeMemoryResource(&alloc_rx_fragment), @@ -152,7 +155,7 @@ void testPubSub() makePayload(Dark), nullptr)); TEST_ASSERT_EQUAL(7, tx.queue_size); - TEST_ASSERT_EQUAL(7, alloc_tx.allocated_fragments); + TEST_ASSERT_EQUAL(7 * 2ULL, alloc_tx.allocated_fragments); // Transmit the enqueued frames by pushing them into the subscribers. // Here we pop the frames one by one ensuring that they come out in the correct order. @@ -212,7 +215,7 @@ void testPubSub() TEST_ASSERT_EQUAL(0, alloc_rx_payload.allocated_fragments); // Free the TX item. udpardTxFree(mem_tx, udpardTxPop(&tx, tx_item)); - TEST_ASSERT_EQUAL(6, alloc_tx.allocated_fragments); + TEST_ASSERT_EQUAL(6 * 2ULL, alloc_tx.allocated_fragments); // Second transfer. tx_item = udpardTxPeek(&tx); @@ -247,7 +250,7 @@ void testPubSub() TEST_ASSERT_EQUAL(0, alloc_rx_payload.allocated_fragments); // Free the TX item. udpardTxFree(mem_tx, udpardTxPop(&tx, tx_item)); - TEST_ASSERT_EQUAL(5, alloc_tx.allocated_fragments); + TEST_ASSERT_EQUAL(5 * 2ULL, alloc_tx.allocated_fragments); // Third transfer. This one is anonymous. tx_item = udpardTxPeek(&tx); @@ -282,7 +285,7 @@ void testPubSub() TEST_ASSERT_EQUAL(0, alloc_rx_payload.allocated_fragments); // Free the TX item. udpardTxFree(mem_tx, udpardTxPop(&tx, tx_item)); - TEST_ASSERT_EQUAL(4, alloc_tx.allocated_fragments); + TEST_ASSERT_EQUAL(4 * 2ULL, alloc_tx.allocated_fragments); // Fourth transfer. This one contains multiple frames. We process them one-by-one. // Frame #0. @@ -305,7 +308,7 @@ void testPubSub() TEST_ASSERT_EQUAL(1, alloc_rx_payload.allocated_fragments); // Free the TX item. udpardTxFree(mem_tx, udpardTxPop(&tx, tx_item)); - TEST_ASSERT_EQUAL(3, alloc_tx.allocated_fragments); + TEST_ASSERT_EQUAL(3 * 2ULL, alloc_tx.allocated_fragments); // Frame #1. tx_item = udpardTxPeek(&tx); TEST_ASSERT_NOT_NULL(tx_item); @@ -327,7 +330,7 @@ void testPubSub() TEST_ASSERT_EQUAL(2, alloc_rx_payload.allocated_fragments); // Free the TX item. udpardTxFree(mem_tx, udpardTxPop(&tx, tx_item)); - TEST_ASSERT_EQUAL(2, alloc_tx.allocated_fragments); + TEST_ASSERT_EQUAL(2 * 2ULL, alloc_tx.allocated_fragments); // Frame #2. tx_item = udpardTxPeek(&tx); TEST_ASSERT_NOT_NULL(tx_item); @@ -349,7 +352,7 @@ void testPubSub() TEST_ASSERT_EQUAL(3, alloc_rx_payload.allocated_fragments); // Free the TX item. udpardTxFree(mem_tx, udpardTxPop(&tx, tx_item)); - TEST_ASSERT_EQUAL(1, alloc_tx.allocated_fragments); + TEST_ASSERT_EQUAL(1 * 2ULL, alloc_tx.allocated_fragments); // Frame #3. This is the last frame of the transfer. The payload is truncated, see the extent. tx_item = udpardTxPeek(&tx); TEST_ASSERT_NOT_NULL(tx_item); @@ -410,7 +413,10 @@ void testRPC() instrumentedAllocatorNew(&alloc_rx_session); instrumentedAllocatorNew(&alloc_rx_fragment); instrumentedAllocatorNew(&alloc_rx_payload); - const auto mem_tx = instrumentedAllocatorMakeMemoryResource(&alloc_tx); + const UdpardTxMemoryResources mem_tx{ + .fragment = instrumentedAllocatorMakeMemoryResource(&alloc_tx), + .payload = instrumentedAllocatorMakeMemoryResource(&alloc_tx), + }; const UdpardRxMemoryResources mem_rx{ .session = instrumentedAllocatorMakeMemoryResource(&alloc_rx_session), .fragment = instrumentedAllocatorMakeMemoryResource(&alloc_rx_fragment), @@ -529,7 +535,7 @@ void testRPC() TEST_ASSERT_EQUAL(0, alloc_rx_payload.allocated_fragments); // Free the TX item. udpardTxFree(mem_tx, udpardTxPop(&tx, tx_item)); - TEST_ASSERT_EQUAL(1, alloc_tx.allocated_fragments); + TEST_ASSERT_EQUAL(1 * 2ULL, alloc_tx.allocated_fragments); // Second transfer. tx_item = udpardTxPeek(&tx); diff --git a/tests/src/test_intrusive_tx.c b/tests/src/test_intrusive_tx.c index bdd57d7..05ef2c5 100644 --- a/tests/src/test_intrusive_tx.c +++ b/tests/src/test_intrusive_tx.c @@ -94,7 +94,10 @@ static void testMakeChainEmpty(void) { InstrumentedAllocator alloc; instrumentedAllocatorNew(&alloc); - struct UdpardMemoryResource mem = instrumentedAllocatorMakeMemoryResource(&alloc); + const struct UdpardTxMemoryResources mem = { + .fragment = instrumentedAllocatorMakeMemoryResource(&alloc), + .payload = instrumentedAllocatorMakeMemoryResource(&alloc), + }; char user_transfer_referent = '\0'; const TransferMetadata meta = { .priority = UdpardPriorityFast, @@ -111,7 +114,7 @@ static void testMakeChainEmpty(void) (UdpardUDPIPEndpoint){.ip_address = 0x0A0B0C0DU, .udp_port = 0x1234}, (UdpardPayload){.size = 0, .data = ""}, &user_transfer_referent); - TEST_ASSERT_EQUAL(1, alloc.allocated_fragments); + TEST_ASSERT_EQUAL(1 * 2ULL, alloc.allocated_fragments); TEST_ASSERT_EQUAL(sizeof(TxItem) + HEADER_SIZE_BYTES + 4, alloc.allocated_bytes); TEST_ASSERT_EQUAL(1, chain.count); TEST_ASSERT_EQUAL(chain.head, chain.tail); @@ -130,7 +133,7 @@ static void testMakeChainEmpty(void) (byte_t*) (chain.head->base.datagram_payload.data) + HEADER_SIZE_BYTES, 4)); TEST_ASSERT_EQUAL(&user_transfer_referent, chain.head->base.user_transfer_reference); - memFree(mem, sizeof(TxItem) + HEADER_SIZE_BYTES + 4, chain.head); + udpardTxFree(mem, &chain.head->base); TEST_ASSERT_EQUAL(0, alloc.allocated_fragments); } @@ -138,7 +141,10 @@ static void testMakeChainSingleMaxMTU(void) { InstrumentedAllocator alloc; instrumentedAllocatorNew(&alloc); - struct UdpardMemoryResource mem = instrumentedAllocatorMakeMemoryResource(&alloc); + const struct UdpardTxMemoryResources mem = { + .fragment = instrumentedAllocatorMakeMemoryResource(&alloc), + .payload = instrumentedAllocatorMakeMemoryResource(&alloc), + }; char user_transfer_referent = '\0'; const TransferMetadata meta = { .priority = UdpardPrioritySlow, @@ -155,7 +161,7 @@ static void testMakeChainSingleMaxMTU(void) (UdpardUDPIPEndpoint){.ip_address = 0x0A0B0C00U, .udp_port = 7474}, (UdpardPayload){.size = DetailOfTheCosmosSize, .data = DetailOfTheCosmos}, &user_transfer_referent); - TEST_ASSERT_EQUAL(1, alloc.allocated_fragments); + TEST_ASSERT_EQUAL(1 * 2ULL, alloc.allocated_fragments); TEST_ASSERT_EQUAL(sizeof(TxItem) + HEADER_SIZE_BYTES + DetailOfTheCosmosSize + TRANSFER_CRC_SIZE_BYTES, alloc.allocated_bytes); TEST_ASSERT_EQUAL(1, chain.count); @@ -181,7 +187,7 @@ static void testMakeChainSingleMaxMTU(void) DetailOfTheCosmosSize, TRANSFER_CRC_SIZE_BYTES)); TEST_ASSERT_EQUAL(&user_transfer_referent, chain.head->base.user_transfer_reference); - memFree(mem, sizeof(TxItem) + HEADER_SIZE_BYTES + DetailOfTheCosmosSize + TRANSFER_CRC_SIZE_BYTES, chain.head); + udpardTxFree(mem, &chain.head->base); TEST_ASSERT_EQUAL(0, alloc.allocated_fragments); } @@ -189,7 +195,10 @@ static void testMakeChainSingleFrameDefaultMTU(void) { InstrumentedAllocator alloc; instrumentedAllocatorNew(&alloc); - struct UdpardMemoryResource mem = instrumentedAllocatorMakeMemoryResource(&alloc); + const struct UdpardTxMemoryResources mem = { + .fragment = instrumentedAllocatorMakeMemoryResource(&alloc), + .payload = instrumentedAllocatorMakeMemoryResource(&alloc), + }; const byte_t payload[UDPARD_MTU_DEFAULT_MAX_SINGLE_FRAME + 1] = {0}; { // Ensure UDPARD_MTU_DEFAULT_MAX_SINGLE_FRAME bytes fit in a single frame with the default MTU. const TxChain chain = txMakeChain(mem, @@ -204,16 +213,14 @@ static void testMakeChainSingleFrameDefaultMTU(void) (UdpardUDPIPEndpoint){.ip_address = 0x0A0B0C00U, .udp_port = 7474}, (UdpardPayload){.size = UDPARD_MTU_DEFAULT_MAX_SINGLE_FRAME, .data = payload}, NULL); - TEST_ASSERT_EQUAL(1, alloc.allocated_fragments); + TEST_ASSERT_EQUAL(1 * 2ULL, alloc.allocated_fragments); TEST_ASSERT_EQUAL(sizeof(TxItem) + HEADER_SIZE_BYTES + UDPARD_MTU_DEFAULT_MAX_SINGLE_FRAME + TRANSFER_CRC_SIZE_BYTES, alloc.allocated_bytes); TEST_ASSERT_EQUAL(1, chain.count); TEST_ASSERT_EQUAL(chain.head, chain.tail); TEST_ASSERT_EQUAL(NULL, chain.head->base.next_in_transfer); - memFree(mem, - sizeof(TxItem) + HEADER_SIZE_BYTES + UDPARD_MTU_DEFAULT_MAX_SINGLE_FRAME + TRANSFER_CRC_SIZE_BYTES, - chain.head); + udpardTxFree(mem, &chain.head->base); TEST_ASSERT_EQUAL(0, alloc.allocated_fragments); } { // Increase the payload by 1 byte and ensure it spills over. @@ -230,7 +237,7 @@ static void testMakeChainSingleFrameDefaultMTU(void) (UdpardUDPIPEndpoint){.ip_address = 0x0A0B0C00U, .udp_port = 7474}, (UdpardPayload){.size = UDPARD_MTU_DEFAULT_MAX_SINGLE_FRAME + 1, .data = payload}, NULL); - TEST_ASSERT_EQUAL(2, alloc.allocated_fragments); + TEST_ASSERT_EQUAL(2 * 2ULL, alloc.allocated_fragments); TEST_ASSERT_EQUAL((sizeof(TxItem) + HEADER_SIZE_BYTES) * 2 + UDPARD_MTU_DEFAULT_MAX_SINGLE_FRAME + 1 + TRANSFER_CRC_SIZE_BYTES, alloc.allocated_bytes); @@ -238,8 +245,8 @@ static void testMakeChainSingleFrameDefaultMTU(void) TEST_ASSERT_NOT_EQUAL(chain.head, chain.tail); TEST_ASSERT_EQUAL((UdpardTxItem*) chain.tail, chain.head->base.next_in_transfer); TEST_ASSERT_EQUAL(NULL, chain.tail->base.next_in_transfer); - memFree(mem, sizeof(TxItem) + HEADER_SIZE_BYTES + UDPARD_MTU_DEFAULT, chain.head); - memFree(mem, alloc.allocated_bytes, chain.tail); + udpardTxFree(mem, &chain.head->base); + udpardTxFree(mem, &chain.tail->base); TEST_ASSERT_EQUAL(0, alloc.allocated_fragments); } } @@ -248,7 +255,10 @@ static void testMakeChainThreeFrames(void) { InstrumentedAllocator alloc; instrumentedAllocatorNew(&alloc); - struct UdpardMemoryResource mem = instrumentedAllocatorMakeMemoryResource(&alloc); + const struct UdpardTxMemoryResources mem = { + .fragment = instrumentedAllocatorMakeMemoryResource(&alloc), + .payload = instrumentedAllocatorMakeMemoryResource(&alloc), + }; char user_transfer_referent = '\0'; const TransferMetadata meta = { .priority = UdpardPriorityNominal, @@ -266,14 +276,14 @@ static void testMakeChainThreeFrames(void) (UdpardUDPIPEndpoint){.ip_address = 0xBABADEDAU, .udp_port = 0xD0ED}, (UdpardPayload){.size = EtherealStrengthSize, .data = EtherealStrength}, &user_transfer_referent); - TEST_ASSERT_EQUAL(3, alloc.allocated_fragments); + TEST_ASSERT_EQUAL(3 * 2ULL, alloc.allocated_fragments); TEST_ASSERT_EQUAL(3 * (sizeof(TxItem) + HEADER_SIZE_BYTES) + EtherealStrengthSize + 4U, alloc.allocated_bytes); TEST_ASSERT_EQUAL(3, chain.count); - const UdpardTxItem* const first = &chain.head->base; + UdpardTxItem* const first = &chain.head->base; TEST_ASSERT_NOT_EQUAL(NULL, first); - const UdpardTxItem* const second = first->next_in_transfer; + UdpardTxItem* const second = first->next_in_transfer; TEST_ASSERT_NOT_EQUAL(NULL, second); - const UdpardTxItem* const third = second->next_in_transfer; + UdpardTxItem* const third = second->next_in_transfer; TEST_ASSERT_NOT_EQUAL(NULL, third); TEST_ASSERT_EQUAL(NULL, third->next_in_transfer); TEST_ASSERT_EQUAL((UdpardTxItem*) chain.tail, third); @@ -320,9 +330,9 @@ static void testMakeChainThreeFrames(void) TEST_ASSERT_EQUAL(&user_transfer_referent, third->user_transfer_reference); // Clean up. - memFree(mem, sizeof(TxItem) + HEADER_SIZE_BYTES + mtu, (void*) first); - memFree(mem, sizeof(TxItem) + HEADER_SIZE_BYTES + mtu, (void*) second); - memFree(mem, alloc.allocated_bytes, (void*) third); + udpardTxFree(mem, first); + udpardTxFree(mem, second); + udpardTxFree(mem, third); TEST_ASSERT_EQUAL(0, alloc.allocated_fragments); } @@ -330,7 +340,10 @@ static void testMakeChainCRCSpill1(void) { InstrumentedAllocator alloc; instrumentedAllocatorNew(&alloc); - struct UdpardMemoryResource mem = instrumentedAllocatorMakeMemoryResource(&alloc); + const struct UdpardTxMemoryResources mem = { + .fragment = instrumentedAllocatorMakeMemoryResource(&alloc), + .payload = instrumentedAllocatorMakeMemoryResource(&alloc), + }; char user_transfer_referent = '\0'; const TransferMetadata meta = { .priority = UdpardPriorityNominal, @@ -348,7 +361,7 @@ static void testMakeChainCRCSpill1(void) (UdpardUDPIPEndpoint){.ip_address = 0xBABADEDAU, .udp_port = 0xD0ED}, (UdpardPayload){.size = InterstellarWarSize, .data = InterstellarWar}, &user_transfer_referent); - TEST_ASSERT_EQUAL(2, alloc.allocated_fragments); + TEST_ASSERT_EQUAL(2 * 2ULL, alloc.allocated_fragments); TEST_ASSERT_EQUAL(2 * (sizeof(TxItem) + HEADER_SIZE_BYTES) + InterstellarWarSize + 4U, alloc.allocated_bytes); TEST_ASSERT_EQUAL(2, chain.count); TEST_ASSERT_NOT_EQUAL(chain.head, chain.tail); @@ -393,8 +406,8 @@ static void testMakeChainCRCSpill1(void) TEST_ASSERT_EQUAL(&user_transfer_referent, chain.tail->base.user_transfer_reference); // Clean up. - memFree(mem, sizeof(TxItem) + HEADER_SIZE_BYTES + mtu, chain.head); - memFree(mem, alloc.allocated_bytes, chain.tail); + udpardTxFree(mem, &chain.head->base); + udpardTxFree(mem, &chain.tail->base); TEST_ASSERT_EQUAL(0, alloc.allocated_fragments); } @@ -402,7 +415,10 @@ static void testMakeChainCRCSpill2(void) { InstrumentedAllocator alloc; instrumentedAllocatorNew(&alloc); - struct UdpardMemoryResource mem = instrumentedAllocatorMakeMemoryResource(&alloc); + const struct UdpardTxMemoryResources mem = { + .fragment = instrumentedAllocatorMakeMemoryResource(&alloc), + .payload = instrumentedAllocatorMakeMemoryResource(&alloc), + }; char user_transfer_referent = '\0'; const TransferMetadata meta = { .priority = UdpardPriorityNominal, @@ -420,7 +436,7 @@ static void testMakeChainCRCSpill2(void) (UdpardUDPIPEndpoint){.ip_address = 0xBABADEDAU, .udp_port = 0xD0ED}, (UdpardPayload){.size = InterstellarWarSize, .data = InterstellarWar}, &user_transfer_referent); - TEST_ASSERT_EQUAL(2, alloc.allocated_fragments); + TEST_ASSERT_EQUAL(2 * 2ULL, alloc.allocated_fragments); TEST_ASSERT_EQUAL(2 * (sizeof(TxItem) + HEADER_SIZE_BYTES) + InterstellarWarSize + 4U, alloc.allocated_bytes); TEST_ASSERT_EQUAL(2, chain.count); TEST_ASSERT_NOT_EQUAL(chain.head, chain.tail); @@ -465,8 +481,8 @@ static void testMakeChainCRCSpill2(void) TEST_ASSERT_EQUAL(&user_transfer_referent, chain.tail->base.user_transfer_reference); // Clean up. - memFree(mem, sizeof(TxItem) + HEADER_SIZE_BYTES + mtu, chain.head); - memFree(mem, alloc.allocated_bytes, chain.tail); + udpardTxFree(mem, &chain.head->base); + udpardTxFree(mem, &chain.tail->base); TEST_ASSERT_EQUAL(0, alloc.allocated_fragments); } @@ -474,7 +490,10 @@ static void testMakeChainCRCSpill3(void) { InstrumentedAllocator alloc; instrumentedAllocatorNew(&alloc); - struct UdpardMemoryResource mem = instrumentedAllocatorMakeMemoryResource(&alloc); + const struct UdpardTxMemoryResources mem = { + .fragment = instrumentedAllocatorMakeMemoryResource(&alloc), + .payload = instrumentedAllocatorMakeMemoryResource(&alloc), + }; char user_transfer_referent = '\0'; const TransferMetadata meta = { .priority = UdpardPriorityNominal, @@ -492,7 +511,7 @@ static void testMakeChainCRCSpill3(void) (UdpardUDPIPEndpoint){.ip_address = 0xBABADEDAU, .udp_port = 0xD0ED}, (UdpardPayload){.size = InterstellarWarSize, .data = InterstellarWar}, &user_transfer_referent); - TEST_ASSERT_EQUAL(2, alloc.allocated_fragments); + TEST_ASSERT_EQUAL(2 * 2ULL, alloc.allocated_fragments); TEST_ASSERT_EQUAL(2 * (sizeof(TxItem) + HEADER_SIZE_BYTES) + InterstellarWarSize + 4U, alloc.allocated_bytes); TEST_ASSERT_EQUAL(2, chain.count); TEST_ASSERT_NOT_EQUAL(chain.head, chain.tail); @@ -537,8 +556,8 @@ static void testMakeChainCRCSpill3(void) TEST_ASSERT_EQUAL(&user_transfer_referent, chain.tail->base.user_transfer_reference); // Clean up. - memFree(mem, sizeof(TxItem) + HEADER_SIZE_BYTES + mtu, chain.head); - memFree(mem, alloc.allocated_bytes, chain.tail); + udpardTxFree(mem, &chain.head->base); + udpardTxFree(mem, &chain.tail->base); TEST_ASSERT_EQUAL(0, alloc.allocated_fragments); } @@ -546,7 +565,10 @@ static void testMakeChainCRCSpillFull(void) { InstrumentedAllocator alloc; instrumentedAllocatorNew(&alloc); - struct UdpardMemoryResource mem = instrumentedAllocatorMakeMemoryResource(&alloc); + const struct UdpardTxMemoryResources mem = { + .fragment = instrumentedAllocatorMakeMemoryResource(&alloc), + .payload = instrumentedAllocatorMakeMemoryResource(&alloc), + }; char user_transfer_referent = '\0'; const TransferMetadata meta = { .priority = UdpardPriorityNominal, @@ -564,7 +586,7 @@ static void testMakeChainCRCSpillFull(void) (UdpardUDPIPEndpoint){.ip_address = 0xBABADEDAU, .udp_port = 0xD0ED}, (UdpardPayload){.size = InterstellarWarSize, .data = InterstellarWar}, &user_transfer_referent); - TEST_ASSERT_EQUAL(2, alloc.allocated_fragments); + TEST_ASSERT_EQUAL(2 * 2ULL, alloc.allocated_fragments); TEST_ASSERT_EQUAL(2 * (sizeof(TxItem) + HEADER_SIZE_BYTES) + InterstellarWarSize + 4U, alloc.allocated_bytes); TEST_ASSERT_EQUAL(2, chain.count); TEST_ASSERT_NOT_EQUAL(chain.head, chain.tail); @@ -605,8 +627,8 @@ static void testMakeChainCRCSpillFull(void) TEST_ASSERT_EQUAL(&user_transfer_referent, chain.tail->base.user_transfer_reference); // Clean up. - memFree(mem, sizeof(TxItem) + HEADER_SIZE_BYTES + mtu, chain.head); - memFree(mem, alloc.allocated_bytes, chain.tail); + udpardTxFree(mem, &chain.head->base); + udpardTxFree(mem, &chain.tail->base); TEST_ASSERT_EQUAL(0, alloc.allocated_fragments); } @@ -614,7 +636,10 @@ static void testPushPeekPopFree(void) { InstrumentedAllocator alloc; instrumentedAllocatorNew(&alloc); - struct UdpardMemoryResource mem = instrumentedAllocatorMakeMemoryResource(&alloc); + const struct UdpardTxMemoryResources mem = { + .fragment = instrumentedAllocatorMakeMemoryResource(&alloc), + .payload = instrumentedAllocatorMakeMemoryResource(&alloc), + }; const UdpardNodeID node_id = 1234; // UdpardTx tx = { @@ -641,7 +666,7 @@ static void testPushPeekPopFree(void) (UdpardUDPIPEndpoint){.ip_address = 0xBABADEDAU, .udp_port = 0xD0ED}, (UdpardPayload){.size = EtherealStrengthSize, .data = EtherealStrength}, &user_transfer_referent)); - TEST_ASSERT_EQUAL(3, alloc.allocated_fragments); + TEST_ASSERT_EQUAL(3 * 2ULL, alloc.allocated_fragments); TEST_ASSERT_EQUAL(3 * (sizeof(TxItem) + HEADER_SIZE_BYTES) + EtherealStrengthSize + 4U, alloc.allocated_bytes); TEST_ASSERT_EQUAL(3, tx.queue_size); @@ -656,7 +681,7 @@ static void testPushPeekPopFree(void) TEST_ASSERT_EQUAL(0, memcmp(makeHeader(meta, 0, false).data, frame->datagram_payload.data, HEADER_SIZE_BYTES)); udpardTxFree(tx.memory, udpardTxPop(&tx, frame)); - TEST_ASSERT_EQUAL(2, alloc.allocated_fragments); + TEST_ASSERT_EQUAL(2 * 2ULL, alloc.allocated_fragments); TEST_ASSERT_EQUAL(2, tx.queue_size); frame = udpardTxPeek(&tx); @@ -670,7 +695,7 @@ static void testPushPeekPopFree(void) TEST_ASSERT_EQUAL(0, memcmp(makeHeader(meta, 1, false).data, frame->datagram_payload.data, HEADER_SIZE_BYTES)); udpardTxFree(tx.memory, udpardTxPop(&tx, frame)); - TEST_ASSERT_EQUAL(1, alloc.allocated_fragments); + TEST_ASSERT_EQUAL(1 * 2ULL, alloc.allocated_fragments); TEST_ASSERT_EQUAL(1, tx.queue_size); frame = udpardTxPeek(&tx); @@ -693,7 +718,10 @@ static void testPushPrioritization(void) { InstrumentedAllocator alloc; instrumentedAllocatorNew(&alloc); - struct UdpardMemoryResource mem = instrumentedAllocatorMakeMemoryResource(&alloc); + const struct UdpardTxMemoryResources mem = { + .fragment = instrumentedAllocatorMakeMemoryResource(&alloc), + .payload = instrumentedAllocatorMakeMemoryResource(&alloc), + }; const UdpardNodeID node_id = 1234; // UdpardTx tx = { @@ -720,7 +748,7 @@ static void testPushPrioritization(void) (UdpardUDPIPEndpoint){.ip_address = 0xAAAAAAAA, .udp_port = 0xAAAA}, (UdpardPayload){.size = EtherealStrengthSize, .data = EtherealStrength}, NULL)); - TEST_ASSERT_EQUAL(3, alloc.allocated_fragments); + TEST_ASSERT_EQUAL(3 * 2ULL, alloc.allocated_fragments); TEST_ASSERT_EQUAL(3, tx.queue_size); const UdpardTxItem* frame = udpardTxPeek(&tx); TEST_ASSERT_NOT_EQUAL(NULL, frame); @@ -740,7 +768,7 @@ static void testPushPrioritization(void) (UdpardUDPIPEndpoint){.ip_address = 0xBBBBBBBB, .udp_port = 0xBBBB}, (UdpardPayload){.size = DetailOfTheCosmosSize, .data = DetailOfTheCosmos}, NULL)); - TEST_ASSERT_EQUAL(4, alloc.allocated_fragments); + TEST_ASSERT_EQUAL(4 * 2ULL, alloc.allocated_fragments); TEST_ASSERT_EQUAL(4, tx.queue_size); frame = udpardTxPeek(&tx); TEST_ASSERT_NOT_EQUAL(NULL, frame); @@ -760,7 +788,7 @@ static void testPushPrioritization(void) (UdpardUDPIPEndpoint){.ip_address = 0xCCCCCCCC, .udp_port = 0xCCCC}, (UdpardPayload){.size = InterstellarWarSize, .data = InterstellarWar}, NULL)); - TEST_ASSERT_EQUAL(5, alloc.allocated_fragments); + TEST_ASSERT_EQUAL(5 * 2ULL, alloc.allocated_fragments); TEST_ASSERT_EQUAL(5, tx.queue_size); frame = udpardTxPeek(&tx); TEST_ASSERT_NOT_EQUAL(NULL, frame); @@ -780,7 +808,7 @@ static void testPushPrioritization(void) (UdpardUDPIPEndpoint){.ip_address = 0xDDDDDDDD, .udp_port = 0xDDDD}, (UdpardPayload){.size = InterstellarWarSize, .data = InterstellarWar}, NULL)); - TEST_ASSERT_EQUAL(6, alloc.allocated_fragments); + TEST_ASSERT_EQUAL(6 * 2ULL, alloc.allocated_fragments); TEST_ASSERT_EQUAL(6, tx.queue_size); frame = udpardTxPeek(&tx); TEST_ASSERT_NOT_EQUAL(NULL, frame); @@ -800,7 +828,7 @@ static void testPushPrioritization(void) (UdpardUDPIPEndpoint){.ip_address = 0xEEEEEEEE, .udp_port = 0xEEEE}, (UdpardPayload){.size = InterstellarWarSize, .data = InterstellarWar}, NULL)); - TEST_ASSERT_EQUAL(7, alloc.allocated_fragments); + TEST_ASSERT_EQUAL(7 * 2ULL, alloc.allocated_fragments); TEST_ASSERT_EQUAL(7, tx.queue_size); frame = udpardTxPeek(&tx); TEST_ASSERT_NOT_EQUAL(NULL, frame); @@ -809,14 +837,14 @@ static void testPushPrioritization(void) // Now, unwind the queue and ensure the frames are popped in the right order. // E udpardTxFree(tx.memory, udpardTxPop(&tx, frame)); - TEST_ASSERT_EQUAL(6, alloc.allocated_fragments); + TEST_ASSERT_EQUAL(6 * 2ULL, alloc.allocated_fragments); TEST_ASSERT_EQUAL(6, tx.queue_size); // B frame = udpardTxPeek(&tx); TEST_ASSERT_NOT_EQUAL(NULL, frame); TEST_ASSERT_EQUAL(0xBBBBBBBB, frame->destination.ip_address); udpardTxFree(tx.memory, udpardTxPop(&tx, frame)); - TEST_ASSERT_EQUAL(5, alloc.allocated_fragments); + TEST_ASSERT_EQUAL(5 * 2ULL, alloc.allocated_fragments); TEST_ASSERT_EQUAL(5, tx.queue_size); // A1, three frames. frame = udpardTxPeek(&tx); @@ -824,7 +852,7 @@ static void testPushPrioritization(void) TEST_ASSERT_EQUAL(0xAAAAAAAA, frame->destination.ip_address); TEST_ASSERT_EQUAL(0, memcmp(makeHeader(meta_a, 0, false).data, frame->datagram_payload.data, HEADER_SIZE_BYTES)); udpardTxFree(tx.memory, udpardTxPop(&tx, frame)); - TEST_ASSERT_EQUAL(4, alloc.allocated_fragments); + TEST_ASSERT_EQUAL(4 * 2ULL, alloc.allocated_fragments); TEST_ASSERT_EQUAL(4, tx.queue_size); // A2 frame = udpardTxPeek(&tx); @@ -832,7 +860,7 @@ static void testPushPrioritization(void) TEST_ASSERT_EQUAL(0xAAAAAAAA, frame->destination.ip_address); TEST_ASSERT_EQUAL(0, memcmp(makeHeader(meta_a, 1, false).data, frame->datagram_payload.data, HEADER_SIZE_BYTES)); udpardTxFree(tx.memory, udpardTxPop(&tx, frame)); - TEST_ASSERT_EQUAL(3, alloc.allocated_fragments); + TEST_ASSERT_EQUAL(3 * 2ULL, alloc.allocated_fragments); TEST_ASSERT_EQUAL(3, tx.queue_size); // A3 frame = udpardTxPeek(&tx); @@ -840,14 +868,14 @@ static void testPushPrioritization(void) TEST_ASSERT_EQUAL(0xAAAAAAAA, frame->destination.ip_address); TEST_ASSERT_EQUAL(0, memcmp(makeHeader(meta_a, 2, true).data, frame->datagram_payload.data, HEADER_SIZE_BYTES)); udpardTxFree(tx.memory, udpardTxPop(&tx, frame)); - TEST_ASSERT_EQUAL(2, alloc.allocated_fragments); + TEST_ASSERT_EQUAL(2 * 2ULL, alloc.allocated_fragments); TEST_ASSERT_EQUAL(2, tx.queue_size); // C frame = udpardTxPeek(&tx); TEST_ASSERT_NOT_EQUAL(NULL, frame); TEST_ASSERT_EQUAL(0xCCCCCCCC, frame->destination.ip_address); udpardTxFree(tx.memory, udpardTxPop(&tx, frame)); - TEST_ASSERT_EQUAL(1, alloc.allocated_fragments); + TEST_ASSERT_EQUAL(1 * 2ULL, alloc.allocated_fragments); TEST_ASSERT_EQUAL(1, tx.queue_size); // D frame = udpardTxPeek(&tx); @@ -864,7 +892,10 @@ static void testPushCapacityLimit(void) { InstrumentedAllocator alloc; instrumentedAllocatorNew(&alloc); - struct UdpardMemoryResource mem = instrumentedAllocatorMakeMemoryResource(&alloc); + const struct UdpardTxMemoryResources mem = { + .fragment = instrumentedAllocatorMakeMemoryResource(&alloc), + .payload = instrumentedAllocatorMakeMemoryResource(&alloc), + }; const UdpardNodeID node_id = 1234; // UdpardTx tx = { @@ -899,7 +930,10 @@ static void testPushOOM(void) { InstrumentedAllocator alloc; instrumentedAllocatorNew(&alloc); - struct UdpardMemoryResource mem = instrumentedAllocatorMakeMemoryResource(&alloc); + const struct UdpardTxMemoryResources mem = { + .fragment = instrumentedAllocatorMakeMemoryResource(&alloc), + .payload = instrumentedAllocatorMakeMemoryResource(&alloc), + }; const UdpardNodeID node_id = 1234; // UdpardTx tx = { @@ -935,7 +969,10 @@ static void testPushAnonymousMultiFrame(void) { InstrumentedAllocator alloc; instrumentedAllocatorNew(&alloc); - struct UdpardMemoryResource mem = instrumentedAllocatorMakeMemoryResource(&alloc); + const struct UdpardTxMemoryResources mem = { + .fragment = instrumentedAllocatorMakeMemoryResource(&alloc), + .payload = instrumentedAllocatorMakeMemoryResource(&alloc), + }; const UdpardNodeID node_id = 0xFFFFU; // UdpardTx tx = { @@ -970,7 +1007,10 @@ static void testPushAnonymousService(void) { InstrumentedAllocator alloc; instrumentedAllocatorNew(&alloc); - struct UdpardMemoryResource mem = instrumentedAllocatorMakeMemoryResource(&alloc); + const struct UdpardTxMemoryResources mem = { + .fragment = instrumentedAllocatorMakeMemoryResource(&alloc), + .payload = instrumentedAllocatorMakeMemoryResource(&alloc), + }; const UdpardNodeID node_id = 0xFFFFU; // UdpardTx tx = { diff --git a/tests/src/test_tx.cpp b/tests/src/test_tx.cpp index 9579744..9eda8af 100644 --- a/tests/src/test_tx.cpp +++ b/tests/src/test_tx.cpp @@ -29,49 +29,55 @@ void testInit() std::monostate user_referent; const UdpardNodeID node_id = 0; { - const UdpardMemoryResource memory{ + const UdpardMemoryResource mr{ .user_reference = &user_referent, .deallocate = &dummyAllocatorDeallocate, .allocate = &dummyAllocatorAllocate, }; + const UdpardTxMemoryResources memory = {.fragment = mr, .payload = mr}; TEST_ASSERT_EQUAL(-UDPARD_ERROR_ARGUMENT, udpardTxInit(nullptr, &node_id, 0, memory)); } { UdpardTx tx{}; - const UdpardMemoryResource memory{ + const UdpardMemoryResource mr{ .user_reference = &user_referent, .deallocate = &dummyAllocatorDeallocate, .allocate = &dummyAllocatorAllocate, }; + const UdpardTxMemoryResources memory = {.fragment = mr, .payload = mr}; TEST_ASSERT_EQUAL(-UDPARD_ERROR_ARGUMENT, udpardTxInit(&tx, nullptr, 0, memory)); } { UdpardTx tx{}; - const UdpardMemoryResource memory{ + const UdpardMemoryResource mr{ .user_reference = &user_referent, .deallocate = &dummyAllocatorDeallocate, .allocate = nullptr, }; + const UdpardTxMemoryResources memory = {.fragment = mr, .payload = mr}; TEST_ASSERT_EQUAL(-UDPARD_ERROR_ARGUMENT, udpardTxInit(&tx, &node_id, 0, memory)); } { UdpardTx tx{}; - const UdpardMemoryResource memory{ + const UdpardMemoryResource mr{ .user_reference = &user_referent, .deallocate = nullptr, .allocate = &dummyAllocatorAllocate, }; + const UdpardTxMemoryResources memory = {.fragment = mr, .payload = mr}; TEST_ASSERT_EQUAL(-UDPARD_ERROR_ARGUMENT, udpardTxInit(&tx, &node_id, 0, memory)); } { UdpardTx tx{}; - const UdpardMemoryResource memory{ + const UdpardMemoryResource mr{ .user_reference = &user_referent, .deallocate = &dummyAllocatorDeallocate, .allocate = &dummyAllocatorAllocate, }; + const UdpardTxMemoryResources memory = {.fragment = mr, .payload = mr}; TEST_ASSERT_EQUAL(0, udpardTxInit(&tx, &node_id, 0, memory)); - TEST_ASSERT_EQUAL(&user_referent, tx.memory.user_reference); + TEST_ASSERT_EQUAL(&user_referent, tx.memory.fragment.user_reference); + TEST_ASSERT_EQUAL(&user_referent, tx.memory.payload.user_reference); TEST_ASSERT_EQUAL(UDPARD_MTU_DEFAULT, tx.mtu); } } @@ -80,7 +86,10 @@ void testPublish() { InstrumentedAllocator alloc; instrumentedAllocatorNew(&alloc); - const struct UdpardMemoryResource mem = instrumentedAllocatorMakeMemoryResource(&alloc); + const UdpardTxMemoryResources mem = { + .fragment = instrumentedAllocatorMakeMemoryResource(&alloc), + .payload = instrumentedAllocatorMakeMemoryResource(&alloc), + }; const UdpardNodeID node_id = 1234; // UdpardTx tx{ @@ -102,7 +111,7 @@ void testPublish() transfer_id++, {.size = FleetingEvents.size(), .data = FleetingEvents.data()}, &user_transfer_referent)); - TEST_ASSERT_EQUAL(1, alloc.allocated_fragments); + TEST_ASSERT_EQUAL(1 * 2ULL, alloc.allocated_fragments); TEST_ASSERT_EQUAL(1, tx.queue_size); const auto* frame = udpardTxPeek(&tx); std::cout << hexdump::hexdump(frame->datagram_payload.data, frame->datagram_payload.size) << "\n\n"; @@ -212,7 +221,10 @@ void testRequest() { InstrumentedAllocator alloc; instrumentedAllocatorNew(&alloc); - const UdpardMemoryResource mem = instrumentedAllocatorMakeMemoryResource(&alloc); + const UdpardTxMemoryResources mem = { + .fragment = instrumentedAllocatorMakeMemoryResource(&alloc), + .payload = instrumentedAllocatorMakeMemoryResource(&alloc), + }; const UdpardNodeID node_id = 1234; // UdpardTx tx{ @@ -235,7 +247,7 @@ void testRequest() transfer_id++, {.size = FleetingEvents.size(), .data = FleetingEvents.data()}, &user_transfer_referent)); - TEST_ASSERT_EQUAL(1, alloc.allocated_fragments); + TEST_ASSERT_EQUAL(1 * 2ULL, alloc.allocated_fragments); TEST_ASSERT_EQUAL(1, tx.queue_size); const auto* frame = udpardTxPeek(&tx); std::cout << hexdump::hexdump(frame->datagram_payload.data, frame->datagram_payload.size) << "\n\n"; @@ -362,7 +374,10 @@ void testRespond() { InstrumentedAllocator alloc; instrumentedAllocatorNew(&alloc); - const UdpardMemoryResource mem = instrumentedAllocatorMakeMemoryResource(&alloc); + const UdpardTxMemoryResources mem = { + .fragment = instrumentedAllocatorMakeMemoryResource(&alloc), + .payload = instrumentedAllocatorMakeMemoryResource(&alloc), + }; const UdpardNodeID node_id = 1234; // UdpardTx tx{ @@ -384,7 +399,7 @@ void testRespond() 9876543210, {.size = FleetingEvents.size(), .data = FleetingEvents.data()}, &user_transfer_referent)); - TEST_ASSERT_EQUAL(1, alloc.allocated_fragments); + TEST_ASSERT_EQUAL(1 * 2ULL, alloc.allocated_fragments); TEST_ASSERT_EQUAL(1, tx.queue_size); const auto* frame = udpardTxPeek(&tx); std::cout << hexdump::hexdump(frame->datagram_payload.data, frame->datagram_payload.size) << "\n\n";