Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(729)

Unified Diff: app/tests/port_tests.c

Issue 1437453002: [kernel][ports] Add basic ports functionality (Closed) Base URL: https://github.com/travisg/lk.git@master
Patch Set: fix Created 5 years, 1 month ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « app/tests/include/app/tests.h ('k') | app/tests/rules.mk » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: app/tests/port_tests.c
diff --git a/app/tests/port_tests.c b/app/tests/port_tests.c
new file mode 100644
index 0000000000000000000000000000000000000000..447c5d236e70e447c645aff2e9b4630c97ea9580
--- /dev/null
+++ b/app/tests/port_tests.c
@@ -0,0 +1,422 @@
+/*
+ * Copyright (c) 2015 Carlos Pizano-Uribe cpu@chromium.org
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files
+ * (the "Software"), to deal in the Software without restriction,
+ * including without limitation the rights to use, copy, modify, merge,
+ * publish, distribute, sublicense, and/or sell copies of the Software,
+ * and to permit persons to whom the Software is furnished to do so,
+ * subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+ * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+ * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+ * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+#include <debug.h>
+#include <err.h>
+#include <string.h>
+#include <rand.h>
+
+#include <kernel/port.h>
+#include <kernel/thread.h>
+
+#include <platform.h>
+
+void* context1 = (void*) 0x53;
+
+static void dump_port_result(const port_result_t* result)
+{
+ const port_packet_t* p = &result->packet;
+ printf("[%02x %02x %02x %02x %02x %02x %02x %02x]\n",
+ p->value[0], p->value[1], p->value[2], p->value[3],
+ p->value[4], p->value[5], p->value[6], p->value[7]);
+}
+
+static int single_thread_basic(void)
+{
+ port_t w_port;
+ status_t st = port_create("sh_prt1", PORT_MODE_UNICAST, &w_port);
+ if (st < 0) {
+ printf("could not create port, status = %d\n", st);
+ return __LINE__;
+ }
+
+ port_t r_port;
+ st = port_open("sh_prt0", context1, &r_port);
+ if (st != ERR_NOT_FOUND) {
+ printf("expected not to find port, status = %d\n", st);
+ return __LINE__;
+ }
+
+ st = port_open("sh_prt1", context1, &r_port);
+ if (st < 0) {
+ printf("could not open port, status = %d\n", st);
+ return __LINE__;
+ }
+
+
+ port_packet_t packet[3] = {
+ {{0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08}},
+ {{0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10, 0x11}},
+ {{0x33, 0x66, 0x99, 0xcc, 0x33, 0x66, 0x99, 0xcc}},
+ };
+
+ st = port_write(w_port, &packet[0], 1);
+ if (st < 0) {
+ printf("could not write port, status = %d\n", st);
+ return __LINE__;
+ }
+
+ printf("reading from port:\n");
+
+ port_result_t res = {0};
+
+ st = port_read(r_port, 0, &res);
+ if (st < 0) {
+ printf("could not read port, status = %d\n", st);
+ return __LINE__;
+ }
+ if (res.ctx != context1) {
+ printf("bad context! = %p\n", res.ctx);
+ return __LINE__;
+ }
+
+ st = port_read(r_port, 0, &res);
+ if (st != ERR_TIMED_OUT) {
+ printf("expected timeout, status = %d\n", st);
+ return __LINE__;
+ }
+
+ st = port_write(w_port, &packet[1], 1);
+ if (st < 0) {
+ printf("could not write port, status = %d\n", st);
+ return __LINE__;
+ }
+
+ st = port_write(w_port, &packet[0], 1);
+ if (st < 0) {
+ printf("could not write port, status = %d\n", st);
+ return __LINE__;
+ }
+
+ st = port_write(w_port, &packet[2], 1);
+ if (st < 0) {
+ printf("could not write port, status = %d\n", st);
+ return __LINE__;
+ }
+
+ int expected_count = 3;
+ while (true) {
+ st = port_read(r_port, 0, &res);
+ if (st < 0)
+ break;
+ dump_port_result(&res);
+ --expected_count;
+ }
+
+ if (expected_count != 0) {
+ printf("invalid read count = %d\n", expected_count);
+ return __LINE__;
+ }
+
+ printf("\n");
+
+ // port should be empty. should be able to write 8 packets.
+ expected_count = 8;
+ while (true) {
+ st = port_write(w_port, &packet[1], 1);
+ if (st < 0)
+ break;
+ --expected_count;
+ st = port_write(w_port, &packet[2], 1);
+ if (st < 0)
+ break;
+ --expected_count;
+ }
+
+ if (expected_count != 0) {
+ printf("invalid write count = %d\n", expected_count);
+ return __LINE__;
+ }
+
+ // tod(cpu) fix this possibly wrong error.
+ if (st != ERR_PARTIAL_WRITE) {
+ printf("expected buffer error, status =%d\n", st);
+ return __LINE__;
+ }
+
+ // read 3 packets.
+ for (int ix = 0; ix != 3; ++ix) {
+ st = port_read(r_port, 0, &res);
+ if (st < 0) {
+ printf("could not read port, status = %d\n", st);
+ return __LINE__;
+ }
+ }
+
+ // there are 5 packets, now we add another 3.
+ st = port_write(w_port, packet, 3);
+ if (st < 0) {
+ printf("could not write port, status = %d\n", st);
+ return __LINE__;
+ }
+
+ expected_count = 8;
+ while (true) {
+ st = port_read(r_port, 0, &res);
+ if (st < 0)
+ break;
+ dump_port_result(&res);
+ --expected_count;
+ }
+
+ if (expected_count != 0) {
+ printf("invalid read count = %d\n", expected_count);
+ return __LINE__;
+ }
+
+ // attempt to use the wrong port.
+ st = port_write(r_port, &packet[1], 1);
+ if (st != ERR_BAD_HANDLE) {
+ printf("expected bad handle error, status = %d\n", st);
+ return __LINE__;
+ }
+
+ st = port_read(w_port, 0, &res);
+ if (st != ERR_BAD_HANDLE) {
+ printf("expected bad handle error, status = %d\n", st);
+ return __LINE__;
+ }
+
+ st = port_close(r_port);
+ if (st < 0) {
+ printf("could not close read port, status = %d\n", st);
+ return __LINE__;
+ }
+
+ st = port_close(w_port);
+ if (st < 0) {
+ printf("could not close write port, status = %d\n", st);
+ return __LINE__;
+ }
+
+ st = port_close(r_port);
+ if (st != ERR_BAD_HANDLE) {
+ printf("expected bad handle error, status = %d\n", st);
+ return __LINE__;
+ }
+
+ st = port_close(w_port);
+ if (st != ERR_BAD_HANDLE) {
+ printf("expected bad handle error, status = %d\n", st);
+ return __LINE__;
+ }
+
+ st = port_destroy(w_port);
+ if (st < 0) {
+ printf("could not destroy port, status = %d\n", st);
+ return __LINE__;
+ }
+
+ printf("single_thread_basic : ok\n");
+ return 0;
+}
+
+static int ping_pong_thread(void *arg)
+{
+ port_t r_port;
+ status_t st = port_open("ping_port", NULL, &r_port);
+ if (st < 0) {
+ printf("thread: could not open port, status = %d\n", st);
+ return __LINE__;
+ }
+
+ bool should_dispose_pong_port = true;
+ port_t w_port;
+ st = port_create("pong_port", PORT_MODE_UNICAST, &w_port);
+ if (st == ERR_ALREADY_EXISTS) {
+ // won the race to create the port.
+ should_dispose_pong_port = false;
+ } else if (st < 0) {
+ printf("thread: could not open port, status = %d\n", st);
+ return __LINE__;
+ }
+
+ port_result_t pr;
+
+ // the loop is read-mutate-write until the write port
+ // is closed by the master thread.
+ while (true) {
+ st = port_read(r_port, INFINITE_TIME, &pr);
+
+ if (st == ERR_CANCELLED) {
+ break;
+ } else if (st < 0) {
+ printf("thread: could not read port, status = %d\n", st);
+ return __LINE__;
+ }
+
+ pr.packet.value[0]++;
+ pr.packet.value[5]--;
+
+ st = port_write(w_port, &pr.packet, 1);
+ if (st < 0) {
+ printf("thread: could not write port, status = %d\n", st);
+ return __LINE__;
+ }
+ }
+
+ port_close(r_port);
+
+ if (should_dispose_pong_port) {
+ port_close(w_port);
+ port_destroy(w_port);
+ }
+
+ return 0;
+
+bail:
+ return __LINE__;
+}
+
+
+int two_threads_basic(void)
+{
+ port_t w_port;
+ status_t st = port_create("ping_port", PORT_MODE_BROADCAST, &w_port);
+ if (st < 0) {
+ printf("could not create port, status = %d\n", st);
+ return __LINE__;
+ }
+
+ thread_t* t1 = thread_create(
+ "worker1", &ping_pong_thread, NULL, DEFAULT_PRIORITY, DEFAULT_STACK_SIZE);
+ thread_t* t2 = thread_create(
+ "worker2", &ping_pong_thread, NULL, DEFAULT_PRIORITY, DEFAULT_STACK_SIZE);
+ thread_resume(t1);
+ thread_resume(t2);
+
+ // wait for the pong port to be created, the two threads race to do it.
+ port_t r_port;
+ while (true) {
+ status_t st = port_open("pong_port", NULL, &r_port);
+ if (st == NO_ERROR) {
+ break;
+ } else if (st == ERR_NOT_FOUND) {
+ thread_sleep(100);
+ } else {
+ printf("could not open port, status = %d\n", st);
+ return __LINE__;
+ }
+ }
+
+ // We have two threads listening to the ping port. Which both reply
+ // on the pong port, so we get two packets in per packet out.
+ const int passes = 256;
+ printf("two_threads_basic test, %d passes\n", passes);
+
+ port_packet_t packet_out = {{0xaf, 0x77, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05}};
+
+ port_result_t pr;
+ for (int ix = 0; ix != passes; ++ix) {
+ const size_t count = 1 + ((unsigned int)rand() % 3);
+
+ for (size_t jx = 0; jx != count; ++jx) {
+ st = port_write(w_port, &packet_out, 1);
+ if (st < 0) {
+ printf("could not write port, status = %d\n", st);
+ return __LINE__;
+ }
+ }
+
+ packet_out.value[0]++;
+ packet_out.value[5]--;
+
+ for (size_t jx = 0; jx != count * 2; ++jx) {
+ st = port_read(r_port, INFINITE_TIME, &pr);
+ if (st < 0) {
+ printf("could not read port, status = %d\n", st);
+ return __LINE__;
+ }
+
+ if ((pr.packet.value[0] != packet_out.value[0]) ||
+ (pr.packet.value[5] != packet_out.value[5])) {
+ printf("unexpected data in packet, loop %d", ix);
+ return __LINE__;
+ }
+ }
+ }
+
+ thread_sleep(100);
+
+ // there should be no more packets to read.
+ st = port_read(r_port, 0, &pr);
+ if (st != ERR_TIMED_OUT) {
+ printf("unexpected packet, status = %d\n", st);
+ return __LINE__;
+ }
+
+ printf("two_threads_basic master shutdown\n");
+
+ st = port_close(r_port);
+ if (st < 0) {
+ printf("could not close port, status = %d\n", st);
+ return __LINE__;
+ }
+
+ st = port_close(w_port);
+ if (st < 0) {
+ printf("could not close port, status = %d\n", st);
+ return __LINE__;
+ }
+
+ st = port_destroy(w_port);
+ if (st < 0) {
+ printf("could not destroy port, status = %d\n", st);
+ return __LINE__;
+ }
+
+ int retcode = -1;
+ thread_join(t1, &retcode, INFINITE_TIME);
+ if (retcode)
+ goto fail;
+
+ thread_join(t2, &retcode, INFINITE_TIME);
+ if (retcode)
+ goto fail;
+
+ return 0;
+
+fail:
+ printf("child thread exited with %d\n", retcode);
+ return __LINE__;
+}
+
+#define RUN_TEST(t) result = t(); if (result) goto fail
+
+int port_tests(void)
+{
+ int result;
+ int count = 2;
+ while (count--) {
+ RUN_TEST(single_thread_basic);
+ RUN_TEST(two_threads_basic);
+ }
+
+ printf("all tests passed\n");
+ return 0;
+fail:
+ printf("test failed at line %d\n", result);
+ return 1;
+}
+
+#undef RUN_TEST
« no previous file with comments | « app/tests/include/app/tests.h ('k') | app/tests/rules.mk » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698