Skip to content

Commit 01b14e7

Browse files
committed
more docs and unit tests #sonar
1 parent 7901638 commit 01b14e7

File tree

2 files changed

+66
-9
lines changed

2 files changed

+66
-9
lines changed

libudpard/udpard.h

Lines changed: 25 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -174,6 +174,7 @@
174174
/// Typically, if block pool allocators are used, the following block sizes should be served:
175175
///
176176
/// - (MTU+library overhead) blocks for the TX and RX pipelines (usually less than 2048 bytes);
177+
/// - TX fragment item sized blocks for the TX pipeline (less than 128 bytes).
177178
/// - RX session object sized blocks for the RX pipeline (less than 512 bytes);
178179
/// - RX fragment handle sized blocks for the RX pipeline (less than 128 bytes).
179180
///
@@ -373,11 +374,11 @@ struct UdpardMemoryResource
373374
// ================================================= TX PIPELINE =================================================
374375
// =====================================================================================================================
375376

376-
/// The set of memory resources is used per an TX pipeline instance.
377+
/// The set of memory resources is used per a TX pipeline instance.
377378
/// These are used to serve the memory needs of the library to keep state while assembling outgoing frames.
378379
/// Several memory resources are provided to enable fine control over the allocated memory.
379380
///
380-
/// This TX queue uses these memory resources for allocating the enqueued items (UDP datagrams).
381+
/// A TX queue uses these memory resources for allocating the enqueued items (UDP datagrams).
381382
/// There are exactly two allocations per enqueued item:
382383
/// - the first for bookkeeping purposes (UdpardTxItem)
383384
/// - second for payload storage (the frame data)
@@ -401,8 +402,6 @@ struct UdpardTxMemoryResources
401402
/// Applications that are not interested in transmission may have zero such instances.
402403
///
403404
/// All operations are logarithmic in complexity on the number of enqueued items.
404-
/// There is exactly one memory allocation per element;
405-
/// the size of each allocation is sizeof(UdpardTxItem) plus the size of the datagram.
406405
///
407406
/// Once initialized, instances cannot be copied.
408407
///
@@ -461,7 +460,9 @@ struct UdpardTx
461460
/// One transport frame (UDP datagram) stored in the UdpardTx transmission queue along with its metadata.
462461
/// The datagram should be sent to the indicated UDP/IP endpoint with the specified DSCP value.
463462
/// The datagram should be discarded (transmission aborted) if the deadline has expired.
464-
/// All fields are READ-ONLY.
463+
/// All fields are READ-ONLY except mutable payload `datagram_payload` field, which could be nullified to indicate
464+
/// a transfer of the payload memory ownership to somewhere else.
465+
///
465466
struct UdpardTxItem
466467
{
467468
/// Internal use only; do not access this field.
@@ -568,10 +569,13 @@ int_fast8_t udpardTxInit(struct UdpardTx* const self,
568569
/// In such cases, all frames allocated for this transfer (if any) will be deallocated automatically.
569570
/// In other words, either all frames of the transfer are enqueued successfully, or none are.
570571
///
571-
/// The memory allocation requirement is one allocation per datagram:
572-
/// a single-frame transfer takes one allocation; a multi-frame transfer of N frames takes N allocations.
573-
/// The size of each allocation is (sizeof(UdpardTxItem) + MTU) except for the last datagram where the payload may be
574-
/// smaller than the MTU.
572+
/// The memory allocation requirement is two allocations per datagram:
573+
/// a single-frame transfer takes two allocations; a multi-frame transfer of N frames takes N*2 allocations.
574+
/// In each pair of allocations:
575+
/// - the first allocation is for `UdpardTxItem`; the size is `sizeof(UdpardTxItem)`;
576+
/// the TX queue `memory.fragment` memory resource is used for this allocation (and later for deallocation);
577+
/// - the second allocation is for payload storage (the frame data) - size is normally MTU but could be less for
578+
/// the last frame of the transfer; the TX queue `memory.payload` memory resource is used for this allocation.
575579
///
576580
/// The time complexity is O(p + log e), where p is the amount of payload in the transfer, and e is the number of
577581
/// frames already enqueued in the transmission queue.
@@ -641,6 +645,18 @@ int32_t udpardTxRespond(struct UdpardTx* const self,
641645
///
642646
/// Calling functions that modify the queue may cause the next invocation to return a different pointer.
643647
///
648+
/// The payload buffer is allocated in the dynamic storage of the queue. The application may transfer ownership of
649+
/// the payload to a different application component (f.e. to transmission media) by copying the pointer and then
650+
/// (if the ownership transfer was accepted) by nullifying `datagram_payload` fields of the frame (`size` & `data`).
651+
/// If these fields stay with their original values, the `udpardTxFree` (after proper `udpardTxPop` of course) will
652+
/// deallocate the payload buffer. In any case, the payload has to be eventually deallocated by using the TX queue
653+
/// `memory.payload` memory resource. It will be automatically done by the `udpardTxFree` (if the payload still
654+
/// stays in the item), OR if moved, it is the responsibility of the application to eventually (f.e. at the end of
655+
/// transmission) deallocate the memory with the TX queue `memory.payload` memory resource.
656+
/// Note that the mentioned above nullification of the `datagram_payload` fields is the
657+
/// only reason why a returned TX item pointer is mutable. It was constant in the past (before v2),
658+
/// but it was changed to be mutable to allow the payload ownership transfer.
659+
///
644660
/// The time complexity is logarithmic of the queue size. This function does not invoke the dynamic memory manager.
645661
struct UdpardTxItem* udpardTxPeek(const struct UdpardTx* const self);
646662

tests/src/test_intrusive_tx.c

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -937,6 +937,46 @@ static void testPushOOM(void)
937937
TEST_ASSERT_EQUAL(0, tx.queue_size);
938938
}
939939

940+
static void testPushPayloadOOM(void)
941+
{
942+
InstrumentedAllocator alloc;
943+
instrumentedAllocatorNew(&alloc);
944+
const struct UdpardTxMemoryResources mem = {
945+
.fragment = instrumentedAllocatorMakeMemoryResource(&alloc),
946+
.payload = instrumentedAllocatorMakeMemoryResource(&alloc),
947+
};
948+
const UdpardNodeID node_id = 1234;
949+
//
950+
UdpardTx tx = {
951+
.local_node_id = &node_id,
952+
.queue_capacity = 10000U,
953+
.mtu = EtherealStrengthSize + HEADER_CRC_SIZE_BYTES,
954+
.dscp_value_per_priority = {0, 1, 2, 3, 4, 5, 6, 7},
955+
.memory = mem,
956+
.queue_size = 0,
957+
.root = NULL,
958+
};
959+
const TransferMetadata meta = {
960+
.priority = UdpardPriorityNominal,
961+
.src_node_id = 4321,
962+
.dst_node_id = 5432,
963+
.data_specifier = 7766,
964+
.transfer_id = 0x0123456789ABCDEFULL,
965+
};
966+
// There is memory of the item, but 1 byte short for payload.
967+
alloc.limit_bytes = sizeof(UdpardTxItem) + (HEADER_SIZE_BYTES + EtherealStrengthSize + HEADER_CRC_SIZE_BYTES - 1);
968+
TEST_ASSERT_EQUAL(-UDPARD_ERROR_MEMORY,
969+
txPush(&tx,
970+
1234567890U,
971+
meta,
972+
(UdpardUDPIPEndpoint){.ip_address = 0xBABADEDAU, .udp_port = 0xD0ED},
973+
(UdpardPayload){.size = EtherealStrengthSize, .data = EtherealStrength},
974+
NULL));
975+
TEST_ASSERT_EQUAL(0, alloc.allocated_fragments);
976+
TEST_ASSERT_EQUAL(0, alloc.allocated_bytes);
977+
TEST_ASSERT_EQUAL(0, tx.queue_size);
978+
}
979+
940980
static void testPushAnonymousMultiFrame(void)
941981
{
942982
InstrumentedAllocator alloc;
@@ -1033,6 +1073,7 @@ int main(void)
10331073
RUN_TEST(testPushPrioritization);
10341074
RUN_TEST(testPushCapacityLimit);
10351075
RUN_TEST(testPushOOM);
1076+
RUN_TEST(testPushPayloadOOM);
10361077
RUN_TEST(testPushAnonymousMultiFrame);
10371078
RUN_TEST(testPushAnonymousService);
10381079
return UNITY_END();

0 commit comments

Comments
 (0)