From 776c915df9fb13fc343bcae5f1a60b41abd920ea Mon Sep 17 00:00:00 2001 From: Christopher Friedt Date: Tue, 19 May 2020 16:36:20 -0400 Subject: [PATCH 1/2] net: socket: socketpair: mitigate possible race condition There was a possible race condition between sock_is_nonblock() and k_sem_take() in spair_read() and spair_write() that was mitigated. Also clarified some of the conditional branching in those functions. Signed-off-by: Christopher Friedt --- subsys/net/lib/sockets/socketpair.c | 70 ++++++++++++++++++----------- 1 file changed, 43 insertions(+), 27 deletions(-) diff --git a/subsys/net/lib/sockets/socketpair.c b/subsys/net/lib/sockets/socketpair.c index 5cec71bdd43ef..4d7c739f7fbdd 100644 --- a/subsys/net/lib/sockets/socketpair.c +++ b/subsys/net/lib/sockets/socketpair.c @@ -369,13 +369,13 @@ int z_vrfy_zsock_socketpair(int family, int type, int proto, static ssize_t spair_write(void *obj, const void *buffer, size_t count) { int res; - bool is_connected; + int key; size_t avail; bool is_nonblock; - bool will_block; size_t bytes_written; bool have_local_sem = false; bool have_remote_sem = false; + bool will_block = false; struct spair *const spair = (struct spair *)obj; struct spair *remote = NULL; @@ -385,9 +385,10 @@ static ssize_t spair_write(void *obj, const void *buffer, size_t count) goto out; } + key = irq_lock(); is_nonblock = sock_is_nonblock(spair); - res = k_sem_take(&spair->sem, K_NO_WAIT); + irq_unlock(key); if (res < 0) { if (is_nonblock) { errno = EAGAIN; @@ -401,6 +402,7 @@ static ssize_t spair_write(void *obj, const void *buffer, size_t count) res = -1; goto out; } + is_nonblock = sock_is_nonblock(spair); } have_local_sem = true; @@ -408,10 +410,7 @@ static ssize_t spair_write(void *obj, const void *buffer, size_t count) remote = z_get_fd_obj(spair->remote, (const struct fd_op_vtable *)&spair_fd_op_vtable, 0); - is_connected = sock_is_connected(spair); - is_nonblock = sock_is_nonblock(spair); - - if (!is_connected) { + if (remote == NULL) { errno = EPIPE; res = -1; goto out; @@ -434,14 +433,17 @@ static ssize_t spair_write(void *obj, const void *buffer, size_t count) have_remote_sem = true; - avail = is_connected ? spair_write_avail(spair) : 0; - if (avail == 0 && is_nonblock) { - errno = EAGAIN; - res = -1; - goto out; + avail = spair_write_avail(spair); + + if (avail == 0) { + if (is_nonblock) { + errno = EAGAIN; + res = -1; + goto out; + } + will_block = true; } - will_block = (count > avail) && !is_nonblock; if (will_block) { for (int signaled = false, result = -1; !signaled; @@ -464,6 +466,16 @@ static ssize_t spair_write(void *obj, const void *buffer, size_t count) goto out; } + remote = z_get_fd_obj(spair->remote, + (const struct fd_op_vtable *) + &spair_fd_op_vtable, 0); + + if (remote == NULL) { + errno = EPIPE; + res = -1; + goto out; + } + res = k_sem_take(&remote->sem, K_NO_WAIT); if (res < 0) { if (is_nonblock) { @@ -569,14 +581,13 @@ static ssize_t spair_write(void *obj, const void *buffer, size_t count) static ssize_t spair_read(void *obj, void *buffer, size_t count) { int res; - + int key; bool is_connected; size_t avail; bool is_nonblock; - bool will_block; size_t bytes_read; - bool have_local_sem = false; + bool will_block = false; struct spair *const spair = (struct spair *)obj; if (obj == NULL || buffer == NULL || count == 0) { @@ -585,9 +596,10 @@ static ssize_t spair_read(void *obj, void *buffer, size_t count) goto out; } + key = irq_lock(); is_nonblock = sock_is_nonblock(spair); - res = k_sem_take(&spair->sem, K_NO_WAIT); + irq_unlock(key); if (res < 0) { if (is_nonblock) { errno = EAGAIN; @@ -601,24 +613,28 @@ static ssize_t spair_read(void *obj, void *buffer, size_t count) res = -1; goto out; } + is_nonblock = sock_is_nonblock(spair); } have_local_sem = true; is_connected = sock_is_connected(spair); avail = spair_read_avail(spair); - will_block = (avail == 0) && !is_nonblock; - if (avail == 0 && !is_connected) { - /* signal EOF */ - res = 0; - goto out; - } + if (avail == 0) { + if (!is_connected) { + /* signal EOF */ + res = 0; + goto out; + } - if (avail == 0 && is_nonblock) { - errno = EAGAIN; - res = -1; - goto out; + if (is_nonblock) { + errno = EAGAIN; + res = -1; + goto out; + } + + will_block = true; } if (will_block) { From 849b5180a3e50ef23d261d7da5e75da8ac27dbf2 Mon Sep 17 00:00:00 2001 From: Christopher Friedt Date: Tue, 19 May 2020 16:40:36 -0400 Subject: [PATCH 2/2] tests: socket: socketpair: fix userspace thread permissions Kernel objects were being directly accessed without previously calling k_thread_access_grant(). This change allows each test that requires an asynchronous event to send it to a common work queue with correct permissions. Signed-off-by: Christopher Friedt --- tests/net/socket/socketpair/prj.conf | 2 - tests/net/socket/socketpair/src/main.c | 83 ++++++------- .../socketpair/src/test_socketpair_block.c | 76 ++++-------- .../socketpair/src/test_socketpair_poll.c | 114 +++++++++--------- .../socketpair/src/test_socketpair_thread.h | 14 +++ 5 files changed, 140 insertions(+), 149 deletions(-) create mode 100644 tests/net/socket/socketpair/src/test_socketpair_thread.h diff --git a/tests/net/socket/socketpair/prj.conf b/tests/net/socket/socketpair/prj.conf index b073017230e0c..97fa3bf991fe2 100644 --- a/tests/net/socket/socketpair/prj.conf +++ b/tests/net/socket/socketpair/prj.conf @@ -1,5 +1,3 @@ -CONFIG_MP_NUM_CPUS=1 - # General config CONFIG_NEWLIB_LIBC=y diff --git a/tests/net/socket/socketpair/src/main.c b/tests/net/socket/socketpair/src/main.c index 046f17b0d1780..e1292626eebb0 100644 --- a/tests/net/socket/socketpair/src/main.c +++ b/tests/net/socket/socketpair/src/main.c @@ -6,22 +6,12 @@ #include +#include "test_socketpair_thread.h" + /* in happy_path.c */ extern void test_socketpair_AF_LOCAL__SOCK_STREAM__0(void); extern void test_socketpair_AF_UNIX__SOCK_STREAM__0(void); -/* in nonblock.c */ -extern void test_socketpair_write_nonblock(void); -extern void test_socketpair_read_nonblock(void); - -/* in block.c */ -extern void test_socketpair_write_block(void); -extern void test_socketpair_read_block(void); - -/* in closed_ends.c */ -extern void test_socketpair_close_one_end_and_write_to_the_other(void); -extern void test_socketpair_close_one_end_and_read_from_the_other(void); - /* in expected_failures.c */ extern void test_socketpair_expected_failures(void); @@ -31,63 +21,74 @@ extern void test_socketpair_unsupported_calls(void); /* in fcntl.c */ extern void test_socketpair_fcntl(void); +/* in nonblock.c */ +extern void test_socketpair_read_nonblock(void); +extern void test_socketpair_write_nonblock(void); + +/* in block.c */ +extern void test_socketpair_read_block(void); +extern void test_socketpair_write_block(void); + +/* in closed_ends.c */ +extern void test_socketpair_close_one_end_and_read_from_the_other(void); +extern void test_socketpair_close_one_end_and_write_to_the_other(void); + /* in poll.c */ extern void test_socketpair_poll_timeout(void); extern void test_socketpair_poll_timeout_nonblocking(void); -extern void test_socketpair_poll_close_remote_end_POLLIN(void); -extern void test_socketpair_poll_close_remote_end_POLLOUT(void); extern void test_socketpair_poll_immediate_data(void); extern void test_socketpair_poll_delayed_data(void); +extern void test_socketpair_poll_close_remote_end_POLLIN(void); +extern void test_socketpair_poll_close_remote_end_POLLOUT(void); + +/* work queue for tests that need an async event */ +static K_THREAD_STACK_DEFINE(test_socketpair_work_q_stack, 512); +struct k_work_q test_socketpair_work_q; void test_main(void) { k_thread_system_pool_assign(k_current_get()); + k_thread_access_grant(k_current_get(), + &test_socketpair_work_q.queue); + + k_work_q_start(&test_socketpair_work_q, test_socketpair_work_q_stack, + K_THREAD_STACK_SIZEOF(test_socketpair_work_q_stack), + CONFIG_MAIN_THREAD_PRIORITY); + ztest_test_suite( socketpair, + ztest_user_unit_test(test_socketpair_AF_LOCAL__SOCK_STREAM__0), ztest_user_unit_test(test_socketpair_AF_UNIX__SOCK_STREAM__0), - ztest_user_unit_test(test_socketpair_write_nonblock), - ztest_user_unit_test(test_socketpair_read_nonblock), - - ztest_user_unit_test( - test_socketpair_close_one_end_and_write_to_the_other), - ztest_user_unit_test( - test_socketpair_close_one_end_and_read_from_the_other), - ztest_user_unit_test(test_socketpair_expected_failures), - ztest_user_unit_test(test_socketpair_unsupported_calls), ztest_user_unit_test(test_socketpair_fcntl), + ztest_user_unit_test(test_socketpair_read_nonblock), + ztest_user_unit_test(test_socketpair_write_nonblock), + + ztest_user_unit_test(test_socketpair_read_block), + ztest_user_unit_test(test_socketpair_write_block), + + ztest_user_unit_test( + test_socketpair_close_one_end_and_read_from_the_other), + ztest_user_unit_test( + test_socketpair_close_one_end_and_write_to_the_other), + ztest_user_unit_test(test_socketpair_poll_timeout), ztest_user_unit_test( test_socketpair_poll_timeout_nonblocking), - ztest_user_unit_test(test_socketpair_poll_immediate_data) - ); - - ztest_run_test_suite(socketpair); - -/* 20200509: @cfriedt: experiencing some issues with userspace thread - * / memory permissions that will require some sorting out. Currently - * these tests succeeed for native_posix_64. - * - * This feature is experimental at present. - */ -#if 0 - ztest_test_suite( - socketpair_only_kernel, - ztest_user_unit_test(test_socketpair_write_block), - ztest_user_unit_test(test_socketpair_read_block), + ztest_user_unit_test(test_socketpair_poll_immediate_data), ztest_user_unit_test(test_socketpair_poll_delayed_data), + ztest_user_unit_test( test_socketpair_poll_close_remote_end_POLLIN), ztest_user_unit_test( test_socketpair_poll_close_remote_end_POLLOUT) ); - ztest_run_test_suite(socketpair_only_kernel); -#endif + ztest_run_test_suite(socketpair); } diff --git a/tests/net/socket/socketpair/src/test_socketpair_block.c b/tests/net/socket/socketpair/src/test_socketpair_block.c index b5a9cada0a6d9..ab8a1b917a9af 100644 --- a/tests/net/socket/socketpair/src/test_socketpair_block.c +++ b/tests/net/socket/socketpair/src/test_socketpair_block.c @@ -16,14 +16,14 @@ LOG_MODULE_REGISTER(net_test, CONFIG_NET_SOCKETS_LOG_LEVEL); #include +#include "test_socketpair_thread.h" + #undef read #define read(fd, buf, len) zsock_recv(fd, buf, len, 0) #undef write #define write(fd, buf, len) zsock_send(fd, buf, len, 0) -#define TIMEOUT K_FOREVER - struct ctx { /* true if test is write_block(), false if test is read_block() */ bool write; @@ -31,32 +31,16 @@ struct ctx { int fd; /* the count of the main thread */ atomic_t m; - /* the count of the secondary thread */ - size_t n; - /* true when secondary thread is done */ - bool done; - /* true if both main and secondary thread should immediately quit */ - bool fail; - /* thread id of the secondary thread */ - k_tid_t tid; }; -ZTEST_BMEM struct ctx ctx; -#define STACK_SIZE 512 -/* thread structure for secondary thread */ -ZTEST_BMEM struct k_thread th; -/* stack for the secondary thread */ -static K_THREAD_STACK_DEFINE(th_stack, STACK_SIZE); - -static void th_fun(void *arg0, void *arg1, void *arg2) -{ - (void) arg0; - (void) arg1; - (void) arg2; +static ZTEST_BMEM struct ctx ctx; +static ZTEST_BMEM struct k_work work; +static void work_handler(struct k_work *work) +{ int res; char c = '\0'; - LOG_DBG("secondary thread running"); + LOG_DBG("doing work"); while (true) { if (ctx.write) { @@ -74,7 +58,7 @@ static void th_fun(void *arg0, void *arg1, void *arg2) break; } - LOG_DBG("%sing 1 byte %s fd %d", ctx.write ? "read" : "write", + LOG_DBG("%sing 1 byte %s fd %d", ctx.write ? "read" : "writ", ctx.write ? "from" : "to", ctx.fd); if (ctx.write) { res = read(ctx.fd, &c, 1); @@ -84,15 +68,9 @@ static void th_fun(void *arg0, void *arg1, void *arg2) if (-1 == res || 1 != res) { LOG_DBG("%s(2) failed: %d", ctx.write ? "read" : "write", errno); - goto out; + } else { + LOG_DBG("%s 1 byte", ctx.write ? "read" : "wrote"); } - LOG_DBG("%s 1 byte", ctx.write ? "read" : "wrote"); - ctx.n = 1; - -out: - ctx.done = true; - - LOG_DBG("terminating.."); } void test_socketpair_write_block(void) @@ -113,13 +91,12 @@ void test_socketpair_write_block(void) ctx.write = true; ctx.fd = sv[(!i) & 1]; - LOG_DBG("creating secondary thread"); - ctx.tid = k_thread_create(&th, th_stack, - STACK_SIZE, th_fun, - NULL, NULL, NULL, - CONFIG_MAIN_THREAD_PRIORITY, - K_INHERIT_PERMS, K_NO_WAIT); - LOG_DBG("created secondary thread %p", ctx.tid); + LOG_DBG("queueing work"); + k_work_init(&work, work_handler); + res = k_work_submit_to_user_queue(&test_socketpair_work_q, + &work); + zassert_equal(res, 0, + "k_work_submit_to_user_queue() failed: %d", res); /* fill up the buffer */ for (ctx.m = 0; atomic_get(&ctx.m) @@ -142,8 +119,6 @@ void test_socketpair_write_block(void) zassert_equal(res, 1, "wrote %d bytes instead of 1", res); LOG_DBG("success!"); - - k_thread_join(&th, K_MSEC(1000)); } close(sv[0]); @@ -153,8 +128,8 @@ void test_socketpair_write_block(void) void test_socketpair_read_block(void) { int res; - int sv[2] = {-1, -1}; char x; + int sv[2] = {-1, -1}; LOG_DBG("creating socketpair.."); res = socketpair(AF_UNIX, SOCK_STREAM, 0, sv); @@ -162,20 +137,19 @@ void test_socketpair_read_block(void) for (size_t i = 0; i < 2; ++i) { - LOG_DBG("data direction %d -> %d", sv[i], sv[(!i) & 1]); + LOG_DBG("data direction %d <- %d", sv[i], sv[(!i) & 1]); LOG_DBG("setting up context"); memset(&ctx, 0, sizeof(ctx)); ctx.write = false; ctx.fd = sv[(!i) & 1]; - LOG_DBG("creating secondary thread"); - ctx.tid = k_thread_create(&th, th_stack, - STACK_SIZE, th_fun, - NULL, NULL, NULL, - CONFIG_MAIN_THREAD_PRIORITY, - K_INHERIT_PERMS, K_NO_WAIT); - LOG_DBG("created secondary thread %p", ctx.tid); + LOG_DBG("queueing work"); + k_work_init(&work, work_handler); + res = k_work_submit_to_user_queue(&test_socketpair_work_q, + &work); + zassert_equal(res, 0, + "k_work_submit_to_user_queue() failed: %d", res); /* try to read one byte */ LOG_DBG("reading from fd %d", sv[i]); @@ -185,8 +159,6 @@ void test_socketpair_read_block(void) zassert_equal(res, 1, "read %d bytes instead of 1", res); LOG_DBG("success!"); - - k_thread_join(&th, K_MSEC(1000)); } close(sv[0]); diff --git a/tests/net/socket/socketpair/src/test_socketpair_poll.c b/tests/net/socket/socketpair/src/test_socketpair_poll.c index 2b3b9c7364f4c..3f1483796c4c4 100644 --- a/tests/net/socket/socketpair/src/test_socketpair_poll.c +++ b/tests/net/socket/socketpair/src/test_socketpair_poll.c @@ -16,17 +16,21 @@ LOG_MODULE_REGISTER(net_test, CONFIG_NET_SOCKETS_LOG_LEVEL); #include +#include "test_socketpair_thread.h" + #undef read #define read(fd, buf, len) zsock_recv(fd, buf, len, 0) #undef write #define write(fd, buf, len) zsock_send(fd, buf, len, 0) -#define STACK_SIZE 512 -/* stack for the secondary thread */ -static K_THREAD_STACK_DEFINE(th_stack, STACK_SIZE); -static struct k_thread th; -static k_tid_t tid; +struct ctx { + bool should_write; + int fd; + k_timeout_t delay; +}; +static ZTEST_BMEM struct ctx ctx; +static ZTEST_BMEM struct k_work work; /* * Timeout should work the same for blocking & non-blocking threads @@ -94,17 +98,17 @@ void test_socketpair_poll_timeout_nonblocking(void) test_socketpair_poll_timeout_common(sv); } -static void close_fun(void *arg1, void *arg2, void *arg3) +static void close_fun(struct k_work *work) { - (void)arg2; - (void)arg3; + (void)work; - const int *const fd = (const int *)arg1; - - k_sleep(K_MSEC(1000)); + if (!(K_TIMEOUT_EQ(ctx.delay, K_NO_WAIT) + || K_TIMEOUT_EQ(ctx.delay, K_FOREVER))) { + k_sleep(ctx.delay); + } - LOG_DBG("about to close fd %d", *fd); - close(*fd); + LOG_DBG("about to close fd %d", ctx.fd); + close(ctx.fd); } /* @@ -134,19 +138,19 @@ void test_socketpair_poll_close_remote_end_POLLIN(void) fds[0].fd = sv[0]; fds[0].events |= POLLIN; - tid = k_thread_create(&th, th_stack, - K_THREAD_STACK_SIZEOF(th_stack), close_fun, - &sv[1], NULL, NULL, - CONFIG_MAIN_THREAD_PRIORITY + 1, - K_USER, K_NO_WAIT); + memset(&ctx, 0, sizeof(ctx)); + ctx.fd = sv[1]; + ctx.delay = K_MSEC(1000); + + LOG_DBG("scheduling work"); + k_work_init(&work, close_fun); + res = k_work_submit_to_user_queue(&test_socketpair_work_q, &work); + zassert_equal(res, 0, "k_work_submit_to_user_queue() failed: %d", res); res = poll(fds, 1, -1); zassert_equal(res, 1, "poll(2) failed: %d", res); zassert_equal(fds[0].revents & POLLIN, POLLIN, "POLLIN not set"); - res = k_thread_join(&th, K_MSEC(5000)); - zassert_false(res < 0, "k_thread_join failed: %d", res); - res = read(sv[0], &c, 1); zassert_equal(res, 0, "read did not return EOF"); @@ -177,19 +181,19 @@ void test_socketpair_poll_close_remote_end_POLLOUT(void) fds[0].fd = sv[0]; fds[0].events |= POLLOUT; - tid = k_thread_create(&th, th_stack, - K_THREAD_STACK_SIZEOF(th_stack), close_fun, - &sv[1], NULL, NULL, - CONFIG_MAIN_THREAD_PRIORITY + 1, - K_USER, K_NO_WAIT); + memset(&ctx, 0, sizeof(ctx)); + ctx.fd = sv[1]; + ctx.delay = K_MSEC(1000); + + LOG_DBG("scheduling work"); + k_work_init(&work, close_fun); + res = k_work_submit_to_user_queue(&test_socketpair_work_q, &work); + zassert_equal(res, 0, "k_work_submit_to_user_queue() failed: %d", res); res = poll(fds, 1, -1); zassert_equal(res, 1, "poll(2) failed: %d", res); zassert_equal(fds[0].revents & POLLHUP, POLLHUP, "POLLHUP not set"); - res = k_thread_join(&th, K_MSEC(5000)); - zassert_false(res < 0, "k_thread_join failed: %d", res); - res = write(sv[0], "x", 1); zassert_equal(res, -1, "write(2): expected: -1 actual: %d", res); zassert_equal(errno, EPIPE, "errno: expected: EPIPE actual: %d", errno); @@ -249,21 +253,21 @@ void test_socketpair_poll_immediate_data(void) close(sv[1]); } -static void rw_fun(void *arg1, void *arg2, void *arg3) +static void rw_fun(struct k_work *work) { - (void)arg3; - - const bool *const should_write = (const bool *) arg1; - const int *const fd = (const int *)arg2; + (void)work; int res; char c; - k_sleep(K_MSEC(1000)); + if (!(K_TIMEOUT_EQ(ctx.delay, K_NO_WAIT) + || K_TIMEOUT_EQ(ctx.delay, K_FOREVER))) { + k_sleep(ctx.delay); + } - if (*should_write) { + if (ctx.should_write) { LOG_DBG("about to write 1 byte"); - res = write(*fd, "x", 1); + res = write(ctx.fd, "x", 1); if (-1 == res) { LOG_DBG("write(2) failed: %d", errno); } else { @@ -271,7 +275,7 @@ static void rw_fun(void *arg1, void *arg2, void *arg3) } } else { LOG_DBG("about to read 1 byte"); - res = read(*fd, &c, 1); + res = read(ctx.fd, &c, 1); if (-1 == res) { LOG_DBG("read(2) failed: %d", errno); } else { @@ -290,8 +294,6 @@ void test_socketpair_poll_delayed_data(void) int sv[2] = {-1, -1}; int res; - bool should_write; - struct pollfd fds[1]; res = socketpair(AF_UNIX, SOCK_STREAM, 0, sv); @@ -300,19 +302,21 @@ void test_socketpair_poll_delayed_data(void) memset(fds, 0, sizeof(fds)); fds[0].fd = sv[0]; fds[0].events |= POLLIN; - should_write = true; - tid = k_thread_create(&th, th_stack, - K_THREAD_STACK_SIZEOF(th_stack), rw_fun, - &should_write, &sv[1], NULL, - CONFIG_MAIN_THREAD_PRIORITY + 1, - K_USER, K_NO_WAIT); + memset(&ctx, 0, sizeof(ctx)); + ctx.fd = sv[1]; + ctx.should_write = true; + ctx.delay = K_MSEC(100); + + LOG_DBG("scheduling work"); + k_work_init(&work, rw_fun); + res = k_work_submit_to_user_queue(&test_socketpair_work_q, &work); + zassert_equal(res, 0, "k_work_submit_to_user_queue() failed: %d", res); res = poll(fds, 1, 5000); zassert_not_equal(res, -1, "poll(2) failed: %d", errno); zassert_equal(res, 1, "poll(2): expected: 1 actual: %d", res); zassert_not_equal(fds[0].revents & POLLIN, 0, "POLLIN not set"); - k_thread_join(&th, K_FOREVER); for (size_t i = 0; i < CONFIG_NET_SOCKETPAIR_BUFFER_SIZE; ++i) { res = write(sv[0], "x", 1); @@ -322,19 +326,21 @@ void test_socketpair_poll_delayed_data(void) memset(fds, 0, sizeof(fds)); fds[0].fd = sv[0]; fds[0].events |= POLLOUT; - should_write = false; - tid = k_thread_create(&th, th_stack, - K_THREAD_STACK_SIZEOF(th_stack), rw_fun, - &should_write, &sv[1], NULL, - CONFIG_MAIN_THREAD_PRIORITY + 1, - K_USER, K_NO_WAIT); + memset(&ctx, 0, sizeof(ctx)); + ctx.fd = sv[1]; + ctx.should_write = false; + ctx.delay = K_MSEC(100); + + LOG_DBG("scheduling work"); + k_work_init(&work, rw_fun); + res = k_work_submit_to_user_queue(&test_socketpair_work_q, &work); + zassert_equal(res, 0, "k_work_submit_to_user_queue() failed: %d", res); res = poll(fds, 1, 5000); zassert_not_equal(res, -1, "poll(2) failed: %d", errno); zassert_equal(res, 1, "poll(2): expected: 1 actual: %d", res); zassert_not_equal(fds[0].revents & POLLOUT, 0, "POLLOUT was not set"); - k_thread_join(&th, K_FOREVER); close(sv[0]); close(sv[1]); diff --git a/tests/net/socket/socketpair/src/test_socketpair_thread.h b/tests/net/socket/socketpair/src/test_socketpair_thread.h new file mode 100644 index 0000000000000..5890febd3a2b9 --- /dev/null +++ b/tests/net/socket/socketpair/src/test_socketpair_thread.h @@ -0,0 +1,14 @@ +/* + * Copyright (c) 2020 Friedt Professional Engineering Services, Inc + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef TEST_SOCKETPAIR_THREAD_H_ +#define TEST_SOCKETPAIR_THREAD_H_ + +#include + +extern struct k_work_q test_socketpair_work_q; + +#endif /* TEST_SOCKETPAIR_THREAD_H_ */