kernel: pipe: fix !K_NO_WAIT and >= min_xfer bytes transferred

If timeout != K_NO_WAIT, then return immediately when not all
bytes_to_read or bytes_to_write have been transfered, but >=
min_xfer have been transferred.

Fixes #24485

Signed-off-by: Christopher Friedt <chrisfriedt@gmail.com>
This commit is contained in:
Christopher Friedt 2020-04-27 21:44:38 -04:00 committed by Carles Cufí
commit d650f4b494
3 changed files with 80 additions and 5 deletions

View file

@ -529,7 +529,20 @@ int z_pipe_put_internal(struct k_pipe *pipe, struct k_pipe_async *async_desc,
return 0;
}
/* Not all data was copied. */
if (!K_TIMEOUT_EQ(timeout, K_NO_WAIT)
&& num_bytes_written >= min_xfer
&& min_xfer > 0) {
*bytes_written = num_bytes_written;
#if (CONFIG_NUM_PIPE_ASYNC_MSGS > 0)
if (async_desc != NULL) {
pipe_async_finish(async_desc);
}
#endif
k_sched_unlock();
return 0;
}
/* Not all data was copied */
#if (CONFIG_NUM_PIPE_ASYNC_MSGS > 0)
if (async_desc != NULL) {
@ -695,7 +708,17 @@ int z_impl_k_pipe_get(struct k_pipe *pipe, void *data, size_t bytes_to_read,
return 0;
}
/* Not all data was read. */
if (!K_TIMEOUT_EQ(timeout, K_NO_WAIT)
&& num_bytes_read >= min_xfer
&& min_xfer > 0) {
k_sched_unlock();
*bytes_read = num_bytes_read;
return 0;
}
/* Not all data was read */
struct k_pipe_desc pipe_desc;

View file

@ -14,6 +14,8 @@ extern void test_pipe_get_on_empty_pipe(void);
extern void test_pipe_forever_timeout(void);
extern void test_pipe_get_timeout(void);
extern void test_pipe_get_invalid_size(void);
extern void test_pipe_get_min_xfer(void);
extern void test_pipe_put_min_xfer(void);
extern struct k_pipe test_pipe;
extern struct k_sem put_sem, get_sem, sync_sem, multiple_send_sem;
@ -36,7 +38,9 @@ void test_main(void)
ztest_user_unit_test(test_pipe_get_on_empty_pipe),
ztest_user_unit_test(test_pipe_forever_timeout),
ztest_user_unit_test(test_pipe_get_timeout),
ztest_user_unit_test(test_pipe_get_invalid_size)
ztest_user_unit_test(test_pipe_get_invalid_size),
ztest_user_unit_test(test_pipe_get_min_xfer),
ztest_user_unit_test(test_pipe_put_min_xfer)
);
ztest_run_test_suite(test_pipe);

View file

@ -97,8 +97,6 @@ static const struct pipe_sequence wait_elements[] = {
{ PIPE_SIZE + 1, ALL_BYTES, PIPE_SIZE + 1, RETURN_SUCCESS },
{ PIPE_SIZE - 1, ATLEAST_1, PIPE_SIZE - 1, RETURN_SUCCESS },
{ PIPE_SIZE, ATLEAST_1, PIPE_SIZE, RETURN_SUCCESS },
{ PIPE_SIZE + 1, ATLEAST_1, PIPE_SIZE + 1, RETURN_SUCCESS }
};
static const struct pipe_sequence timeout_elements[] = {
@ -826,3 +824,53 @@ void test_pipe_get_invalid_size(void)
zassert_equal(ret, -EINVAL,
"fault didn't occur for min_xfer <= bytes_to_read");
}
/**
* @brief Test pipe get returns immediately if >= min_xfer is available
* @ingroup kernel_pipe_tests
* @see k_pipe_get()
*/
void test_pipe_get_min_xfer(void)
{
int res;
size_t bytes_written = 0;
size_t bytes_read = 0;
char buf[8] = {};
res = k_pipe_put(&test_pipe, "Hi!", 3, &bytes_written,
3 /* min_xfer */, K_FOREVER);
zassert_equal(res, 0, "did not write entire message");
zassert_equal(bytes_written, 3, "did not write entire message");
res = k_pipe_get(&test_pipe, buf, sizeof(buf), &bytes_read,
1 /* min_xfer */, K_FOREVER);
zassert_equal(res, 0, "did not read at least one byte");
zassert_equal(bytes_read, 3, "did not read all bytes available");
}
/**
* @brief Test pipe put returns immediately if >= min_xfer is available
* @ingroup kernel_pipe_tests
* @see k_pipe_put()
*/
void test_pipe_put_min_xfer(void)
{
int res;
size_t bytes_written = 0;
/* write 6 bytes into the pipe, so that 2 bytes are still free */
for (size_t i = 0; i < 2; ++i) {
bytes_written = 0;
res = k_pipe_put(&test_pipe, "Hi!", 3, &bytes_written,
3 /* min_xfer */, K_FOREVER);
zassert_equal(res, 0, "did not write entire message");
zassert_equal(bytes_written, 3, "did not write entire message");
}
/* attempt to write 3 bytes, but allow success if >= 1 byte */
bytes_written = 0;
res = k_pipe_put(&test_pipe, "Hi!", 3, &bytes_written,
1 /* min_xfer */, K_FOREVER);
zassert_equal(res, 0, "did not write min_xfer");
zassert_true(bytes_written >= 1, "did not write min_xfer");
}