Index: app/tests/port_tests.c |
diff --git a/app/tests/port_tests.c b/app/tests/port_tests.c |
index 447c5d236e70e447c645aff2e9b4630c97ea9580..591096c714f8daecb82ad649e7cc8cfca579628e 100644 |
--- a/app/tests/port_tests.c |
+++ b/app/tests/port_tests.c |
@@ -23,22 +23,25 @@ |
#include <debug.h> |
#include <err.h> |
-#include <string.h> |
#include <rand.h> |
+#include <string.h> |
+#include <trace.h> |
#include <kernel/port.h> |
#include <kernel/thread.h> |
#include <platform.h> |
+#define LOCAL_TRACE 0 |
+ |
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]); |
+ LTRACEF("[%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) |
@@ -63,7 +66,6 @@ static int single_thread_basic(void) |
return __LINE__; |
} |
- |
port_packet_t packet[3] = { |
{{0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08}}, |
{{0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10, 0x11}}, |
@@ -401,15 +403,196 @@ fail: |
return __LINE__; |
} |
+#define CMD_PORT_CTX ((void*) 0x77) |
+#define TS1_PORT_CTX ((void*) 0x11) |
+#define TS2_PORT_CTX ((void*) 0x12) |
+ |
+typedef enum { |
+ ADD_PORT, |
+ QUIT |
+} action_t; |
+ |
+typedef struct { |
+ action_t what; |
+ port_t port; |
+} watcher_cmd; |
+ |
+status_t send_watcher_cmd(port_t cmd_port, action_t action, port_t port) |
+{ |
+ watcher_cmd cmd = {action, port}; |
+ return port_write(cmd_port, ((port_packet_t*) &cmd), 1);; |
+} |
+ |
+static int group_watcher_thread(void *arg) |
+{ |
+ port_t watched[8] = {0}; |
+ status_t st = port_open("grp_ctrl", CMD_PORT_CTX, &watched[0]); |
+ if (st < 0) { |
+ printf("could not open port, status = %d\n", st); |
+ return __LINE__; |
+ } |
+ |
+ size_t count = 1; |
+ port_t group; |
+ int ctx_count = -1; |
+ |
+ while (true) { |
+ st = port_group(watched, count, &group); |
+ if (st < 0) { |
+ printf("could not make group, status = %d\n", st); |
+ return __LINE__; |
+ } |
+ |
+ port_result_t pr; |
+ while (true) { |
+ st = port_read(group, INFINITE_TIME, &pr); |
+ if (st < 0) { |
+ printf("could not read port, status = %d\n", st); |
+ return __LINE__; |
+ } |
+ |
+ if (pr.ctx == CMD_PORT_CTX) { |
+ break; |
+ } else if (pr.ctx == TS1_PORT_CTX) { |
+ ctx_count += 1; |
+ } else if (pr.ctx == TS2_PORT_CTX) { |
+ ctx_count += 2; |
+ } else { |
+ printf("unknown context %p\n", pr.ctx); |
+ return __LINE__; |
+ } |
+ } |
+ |
+ // Either adding a port or exiting; either way close the |
+ // existing group port and create a new one if needed |
+ // at the top of the loop. |
+ |
+ port_close(group); |
+ watcher_cmd* wc = (watcher_cmd*) &pr.packet; |
+ |
+ if (wc->what == ADD_PORT) { |
+ watched[count++] = wc->port; |
+ } else if (wc->what == QUIT) { |
+ break; |
+ } else { |
+ printf("unknown command %d\n", wc->what); |
+ return __LINE__; |
+ } |
+ } |
+ |
+ if (ctx_count != 2) { |
+ printf("unexpected context count %d", ctx_count); |
+ return __LINE__; |
+ } |
+ |
+ printf("group watcher shutdown\n"); |
+ |
+ for (size_t ix = 0; ix != count; ++ix) { |
+ st = port_close(watched[ix]); |
+ if (st < 0) { |
+ printf("failed to close read port, status = %d\n", st); |
+ return __LINE__; |
+ } |
+ } |
+ |
+ return 0; |
+} |
+ |
+static status_t make_port_pair(const char* name, void* ctx, port_t* write, port_t* read) |
+{ |
+ status_t st = port_create(name, PORT_MODE_UNICAST, write); |
+ if (st < 0) |
+ return st; |
+ return port_open(name,ctx, read); |
+} |
+ |
+int group_basic(void) |
+{ |
+ // we spin a thread that connects to a well known port, then we |
+ // send two ports that it will add to a group port. |
+ port_t cmd_port; |
+ status_t st = port_create("grp_ctrl", PORT_MODE_UNICAST, &cmd_port); |
+ if (st < 0 ) { |
+ printf("could not create port, status = %d\n", st); |
+ return __LINE__; |
+ } |
+ |
+ thread_t* wt = thread_create( |
+ "g_watcher", &group_watcher_thread, NULL, DEFAULT_PRIORITY, DEFAULT_STACK_SIZE); |
+ thread_resume(wt); |
+ |
+ port_t w_test_port1, r_test_port1; |
+ st = make_port_pair("tst_port1", TS1_PORT_CTX, &w_test_port1, &r_test_port1); |
+ if (st < 0) |
+ return __LINE__; |
+ |
+ port_t w_test_port2, r_test_port2; |
+ st = make_port_pair("tst_port2", TS2_PORT_CTX, &w_test_port2, &r_test_port2); |
+ if (st < 0) |
+ return __LINE__; |
+ |
+ st = send_watcher_cmd(cmd_port, ADD_PORT, r_test_port1); |
+ if (st < 0) |
+ return __LINE__; |
+ |
+ st = send_watcher_cmd(cmd_port, ADD_PORT, r_test_port2); |
+ if (st < 0) |
+ return __LINE__; |
+ |
+ thread_sleep(50); |
+ |
+ port_packet_t pp = {{0}}; |
+ st = port_write(w_test_port1, &pp, 1); |
+ if (st < 0) |
+ return __LINE__; |
+ |
+ st = port_write(w_test_port2, &pp, 1); |
+ if (st < 0) |
+ return __LINE__; |
+ |
+ st = send_watcher_cmd(cmd_port, QUIT, 0); |
+ if (st < 0) |
+ return __LINE__; |
+ |
+ int retcode = -1; |
+ thread_join(wt, &retcode, INFINITE_TIME); |
+ if (retcode) { |
+ printf("child thread exited with %d\n", retcode); |
+ return __LINE__; |
+ } |
+ |
+ st = port_close(w_test_port1); |
+ if (st < 0) |
+ return __LINE__; |
+ st = port_close(w_test_port2); |
+ if (st < 0) |
+ return __LINE__; |
+ st = port_close(cmd_port); |
+ if (st < 0) |
+ return __LINE__; |
+ st = port_destroy(w_test_port1); |
+ if (st < 0) |
+ return __LINE__; |
+ st = port_destroy(w_test_port2); |
+ if (st < 0) |
+ return __LINE__; |
+ st = port_destroy(cmd_port); |
+ if (st < 0) |
+ return __LINE__; |
+ |
+ return 0; |
+} |
+ |
#define RUN_TEST(t) result = t(); if (result) goto fail |
int port_tests(void) |
{ |
int result; |
- int count = 2; |
+ int count = 3; |
while (count--) { |
RUN_TEST(single_thread_basic); |
RUN_TEST(two_threads_basic); |
+ RUN_TEST(group_basic); |
} |
printf("all tests passed\n"); |