Skip to content

Commit

Permalink
kernel: pipe: fix !K_NO_WAIT and >= min_xfer bytes transferred
Browse files Browse the repository at this point in the history
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 zephyrproject-rtos#24485

Signed-off-by: Christopher Friedt <chrisfriedt@gmail.com>
  • Loading branch information
cfriedt authored and Sandeep Tripathy committed Apr 30, 2020
1 parent 65a7395 commit 1cd5ef9
Show file tree
Hide file tree
Showing 3 changed files with 80 additions and 5 deletions.
27 changes: 25 additions & 2 deletions kernel/pipes.c
Original file line number Diff line number Diff line change
Expand Up @@ -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) {
Expand Down Expand Up @@ -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;

Expand Down
6 changes: 5 additions & 1 deletion tests/kernel/pipe/pipe/src/main.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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);
Expand Down
52 changes: 50 additions & 2 deletions tests/kernel/pipe/pipe/src/test_pipe.c
Original file line number Diff line number Diff line change
Expand Up @@ -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[] = {
Expand Down Expand Up @@ -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");
}

0 comments on commit 1cd5ef9

Please sign in to comment.