a read/take returning no data must be a no-op
In all cases where read/take allocates memory for storing samples but
the result turns out to be an empty set, the (observable) state of the
system should end up unchanged.
It turns out several cases were/are considered:
* application supplies buffers (i.e., buf[0] != NULL): no memory
allocated, so no issue.
* reader has no cached set ("m_loan" in the current code): read/take
allocated memory, cached the address and marked it as in use
("m_loan_out"), and modified buf[0] (and subsequent entries).
To undo this on returning an empty set, it now: resets the
"m_loan_out" flag to allow the cached buffer to be reused, and sets
buf[0] back to NULL.
* reader has a cached set, but it is not marked in use: read/take
marked it as in use and modified buf[0] (and subsequent entries).
To undo this, it now resets "m_loan_out" to indicate the cached buffer
is not in use, and sets buf[0] back to NULL.
* reader has a cached set that is currently in use: read/take allocated
memory and updated buf[0] (and subsequent entries) but left the cached
state alone.
To undo this, it now frees the memory and sets buf[0] back to NULL.
With this, in any path where the application lets dds_read/dds_take
allocate memory for the samples:
* it can still safely call dds_return_loan with buf[0] and the actual
return value of read/take (even if an error code), and whatever memory
was allocated will not be leaked;
* but it no longer has to do so when the result was empty (or error).
Signed-off-by: Erik Boasson <eb@ilities.com>
This commit is contained in:
parent
a6d92aac8c
commit
d16264fd82
1 changed files with 31 additions and 8 deletions
|
|
@ -94,6 +94,10 @@ dds_read_impl(
|
|||
dds_retcode_t rc;
|
||||
struct dds_reader * rd;
|
||||
struct dds_readcond * cond;
|
||||
unsigned nodata_cleanups = 0;
|
||||
#define NC_CLEAR_LOAN_OUT 1u
|
||||
#define NC_FREE_BUF 2u
|
||||
#define NC_RESET_BUF 4u
|
||||
|
||||
if (buf == NULL) {
|
||||
DDS_ERROR("The provided buffer is NULL\n");
|
||||
|
|
@ -140,21 +144,25 @@ dds_read_impl(
|
|||
/* Allocate, use or reallocate loan cached on reader */
|
||||
if (rd->m_loan_out) {
|
||||
ddsi_sertopic_realloc_samples (buf, rd->m_topic->m_stopic, NULL, 0, maxs);
|
||||
nodata_cleanups = NC_FREE_BUF | NC_RESET_BUF;
|
||||
} else {
|
||||
if (rd->m_loan) {
|
||||
if (rd->m_loan_size < maxs) {
|
||||
ddsi_sertopic_realloc_samples (buf, rd->m_topic->m_stopic, rd->m_loan, rd->m_loan_size, maxs);
|
||||
rd->m_loan = buf[0];
|
||||
rd->m_loan_size = maxs;
|
||||
nodata_cleanups = NC_RESET_BUF;
|
||||
} else {
|
||||
buf[0] = rd->m_loan;
|
||||
buf[0] = rd->m_loan;
|
||||
nodata_cleanups = NC_RESET_BUF;
|
||||
}
|
||||
} else {
|
||||
ddsi_sertopic_realloc_samples (buf, rd->m_topic->m_stopic, NULL, 0, maxs);
|
||||
rd->m_loan = buf[0];
|
||||
rd->m_loan_size = maxs;
|
||||
}
|
||||
} else {
|
||||
ddsi_sertopic_realloc_samples (buf, rd->m_topic->m_stopic, NULL, 0, maxs);
|
||||
rd->m_loan = buf[0];
|
||||
rd->m_loan_size = maxs;
|
||||
}
|
||||
rd->m_loan_out = true;
|
||||
nodata_cleanups |= NC_CLEAR_LOAN_OUT;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -169,9 +177,24 @@ dds_read_impl(
|
|||
ddsrt_mutex_unlock (&rd->m_entity.m_observers_lock);
|
||||
|
||||
if (take) {
|
||||
ret = (dds_return_t)dds_rhc_take(rd->m_rd->rhc, lock, buf, si, maxs, mask, hand, cond);
|
||||
ret = (dds_return_t) dds_rhc_take (rd->m_rd->rhc, lock, buf, si, maxs, mask, hand, cond);
|
||||
} else {
|
||||
ret = (dds_return_t)dds_rhc_read(rd->m_rd->rhc, lock, buf, si, maxs, mask, hand, cond);
|
||||
ret = (dds_return_t) dds_rhc_read (rd->m_rd->rhc, lock, buf, si, maxs, mask, hand, cond);
|
||||
}
|
||||
|
||||
/* if no data read, restore the state to what it was before the call, with the sole
|
||||
exception of holding on to a buffer we just allocated and that is pointed to by
|
||||
rd->m_loan */
|
||||
if (ret <= 0 && nodata_cleanups) {
|
||||
if (nodata_cleanups & NC_CLEAR_LOAN_OUT) {
|
||||
rd->m_loan_out = false;
|
||||
}
|
||||
if (nodata_cleanups & NC_FREE_BUF) {
|
||||
ddsi_sertopic_free_samples (rd->m_topic->m_stopic, buf[0], maxs, DDS_FREE_ALL);
|
||||
}
|
||||
if (nodata_cleanups & NC_RESET_BUF) {
|
||||
buf[0] = NULL;
|
||||
}
|
||||
}
|
||||
dds_read_unlock(rd, cond);
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue