OLD | NEW |
1 /* | 1 /* |
2 * Copyright (c) 2015 Carlos Pizano-Uribe cpu@chromium.org | 2 * Copyright (c) 2015 Carlos Pizano-Uribe cpu@chromium.org |
3 * | 3 * |
4 * Permission is hereby granted, free of charge, to any person obtaining | 4 * Permission is hereby granted, free of charge, to any person obtaining |
5 * a copy of this software and associated documentation files | 5 * a copy of this software and associated documentation files |
6 * (the "Software"), to deal in the Software without restriction, | 6 * (the "Software"), to deal in the Software without restriction, |
7 * including without limitation the rights to use, copy, modify, merge, | 7 * including without limitation the rights to use, copy, modify, merge, |
8 * publish, distribute, sublicense, and/or sell copies of the Software, | 8 * publish, distribute, sublicense, and/or sell copies of the Software, |
9 * and to permit persons to whom the Software is furnished to do so, | 9 * and to permit persons to whom the Software is furnished to do so, |
10 * subject to the following conditions: | 10 * subject to the following conditions: |
11 * | 11 * |
12 * The above copyright notice and this permission notice shall be | 12 * The above copyright notice and this permission notice shall be |
13 * included in all copies or substantial portions of the Software. | 13 * included in all copies or substantial portions of the Software. |
14 * | 14 * |
15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, | 15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, |
16 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF | 16 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF |
17 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. | 17 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. |
18 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY | 18 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY |
19 * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, | 19 * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, |
20 * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE | 20 * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE |
21 * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. | 21 * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. |
22 */ | 22 */ |
23 | 23 |
24 #include <debug.h> | 24 #include <debug.h> |
25 #include <err.h> | 25 #include <err.h> |
| 26 #include <rand.h> |
26 #include <string.h> | 27 #include <string.h> |
27 #include <rand.h> | 28 #include <trace.h> |
28 | 29 |
29 #include <kernel/port.h> | 30 #include <kernel/port.h> |
30 #include <kernel/thread.h> | 31 #include <kernel/thread.h> |
31 | 32 |
32 #include <platform.h> | 33 #include <platform.h> |
33 | 34 |
| 35 #define LOCAL_TRACE 0 |
| 36 |
34 void* context1 = (void*) 0x53; | 37 void* context1 = (void*) 0x53; |
35 | 38 |
36 static void dump_port_result(const port_result_t* result) | 39 static void dump_port_result(const port_result_t* result) |
37 { | 40 { |
38 const port_packet_t* p = &result->packet; | 41 const port_packet_t* p = &result->packet; |
39 printf("[%02x %02x %02x %02x %02x %02x %02x %02x]\n", | 42 LTRACEF("[%02x %02x %02x %02x %02x %02x %02x %02x]\n", |
40 p->value[0], p->value[1], p->value[2], p->value[3], | 43 p->value[0], p->value[1], p->value[2], p->value[3], |
41 p->value[4], p->value[5], p->value[6], p->value[7]); | 44 p->value[4], p->value[5], p->value[6], p->value[7]); |
42 } | 45 } |
43 | 46 |
44 static int single_thread_basic(void) | 47 static int single_thread_basic(void) |
45 { | 48 { |
46 port_t w_port; | 49 port_t w_port; |
47 status_t st = port_create("sh_prt1", PORT_MODE_UNICAST, &w_port); | 50 status_t st = port_create("sh_prt1", PORT_MODE_UNICAST, &w_port); |
48 if (st < 0) { | 51 if (st < 0) { |
49 printf("could not create port, status = %d\n", st); | 52 printf("could not create port, status = %d\n", st); |
50 return __LINE__; | 53 return __LINE__; |
51 } | 54 } |
52 | 55 |
53 port_t r_port; | 56 port_t r_port; |
54 st = port_open("sh_prt0", context1, &r_port); | 57 st = port_open("sh_prt0", context1, &r_port); |
55 if (st != ERR_NOT_FOUND) { | 58 if (st != ERR_NOT_FOUND) { |
56 printf("expected not to find port, status = %d\n", st); | 59 printf("expected not to find port, status = %d\n", st); |
57 return __LINE__; | 60 return __LINE__; |
58 } | 61 } |
59 | 62 |
60 st = port_open("sh_prt1", context1, &r_port); | 63 st = port_open("sh_prt1", context1, &r_port); |
61 if (st < 0) { | 64 if (st < 0) { |
62 printf("could not open port, status = %d\n", st); | 65 printf("could not open port, status = %d\n", st); |
63 return __LINE__; | 66 return __LINE__; |
64 } | 67 } |
65 | 68 |
66 | |
67 port_packet_t packet[3] = { | 69 port_packet_t packet[3] = { |
68 {{0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08}}, | 70 {{0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08}}, |
69 {{0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10, 0x11}}, | 71 {{0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10, 0x11}}, |
70 {{0x33, 0x66, 0x99, 0xcc, 0x33, 0x66, 0x99, 0xcc}}, | 72 {{0x33, 0x66, 0x99, 0xcc, 0x33, 0x66, 0x99, 0xcc}}, |
71 }; | 73 }; |
72 | 74 |
73 st = port_write(w_port, &packet[0], 1); | 75 st = port_write(w_port, &packet[0], 1); |
74 if (st < 0) { | 76 if (st < 0) { |
75 printf("could not write port, status = %d\n", st); | 77 printf("could not write port, status = %d\n", st); |
76 return __LINE__; | 78 return __LINE__; |
(...skipping 317 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
394 if (retcode) | 396 if (retcode) |
395 goto fail; | 397 goto fail; |
396 | 398 |
397 return 0; | 399 return 0; |
398 | 400 |
399 fail: | 401 fail: |
400 printf("child thread exited with %d\n", retcode); | 402 printf("child thread exited with %d\n", retcode); |
401 return __LINE__; | 403 return __LINE__; |
402 } | 404 } |
403 | 405 |
| 406 #define CMD_PORT_CTX ((void*) 0x77) |
| 407 #define TS1_PORT_CTX ((void*) 0x11) |
| 408 #define TS2_PORT_CTX ((void*) 0x12) |
| 409 |
| 410 typedef enum { |
| 411 ADD_PORT, |
| 412 QUIT |
| 413 } action_t; |
| 414 |
| 415 typedef struct { |
| 416 action_t what; |
| 417 port_t port; |
| 418 } watcher_cmd; |
| 419 |
| 420 status_t send_watcher_cmd(port_t cmd_port, action_t action, port_t port) |
| 421 { |
| 422 watcher_cmd cmd = {action, port}; |
| 423 return port_write(cmd_port, ((port_packet_t*) &cmd), 1);; |
| 424 } |
| 425 |
| 426 static int group_watcher_thread(void *arg) |
| 427 { |
| 428 port_t watched[8] = {0}; |
| 429 status_t st = port_open("grp_ctrl", CMD_PORT_CTX, &watched[0]); |
| 430 if (st < 0) { |
| 431 printf("could not open port, status = %d\n", st); |
| 432 return __LINE__; |
| 433 } |
| 434 |
| 435 size_t count = 1; |
| 436 port_t group; |
| 437 int ctx_count = -1; |
| 438 |
| 439 while (true) { |
| 440 st = port_group(watched, count, &group); |
| 441 if (st < 0) { |
| 442 printf("could not make group, status = %d\n", st); |
| 443 return __LINE__; |
| 444 } |
| 445 |
| 446 port_result_t pr; |
| 447 while (true) { |
| 448 st = port_read(group, INFINITE_TIME, &pr); |
| 449 if (st < 0) { |
| 450 printf("could not read port, status = %d\n", st); |
| 451 return __LINE__; |
| 452 } |
| 453 |
| 454 if (pr.ctx == CMD_PORT_CTX) { |
| 455 break; |
| 456 } else if (pr.ctx == TS1_PORT_CTX) { |
| 457 ctx_count += 1; |
| 458 } else if (pr.ctx == TS2_PORT_CTX) { |
| 459 ctx_count += 2; |
| 460 } else { |
| 461 printf("unknown context %p\n", pr.ctx); |
| 462 return __LINE__; |
| 463 } |
| 464 } |
| 465 |
| 466 // Either adding a port or exiting; either way close the |
| 467 // existing group port and create a new one if needed |
| 468 // at the top of the loop. |
| 469 |
| 470 port_close(group); |
| 471 watcher_cmd* wc = (watcher_cmd*) &pr.packet; |
| 472 |
| 473 if (wc->what == ADD_PORT) { |
| 474 watched[count++] = wc->port; |
| 475 } else if (wc->what == QUIT) { |
| 476 break; |
| 477 } else { |
| 478 printf("unknown command %d\n", wc->what); |
| 479 return __LINE__; |
| 480 } |
| 481 } |
| 482 |
| 483 if (ctx_count != 2) { |
| 484 printf("unexpected context count %d", ctx_count); |
| 485 return __LINE__; |
| 486 } |
| 487 |
| 488 printf("group watcher shutdown\n"); |
| 489 |
| 490 for (size_t ix = 0; ix != count; ++ix) { |
| 491 st = port_close(watched[ix]); |
| 492 if (st < 0) { |
| 493 printf("failed to close read port, status = %d\n", st); |
| 494 return __LINE__; |
| 495 } |
| 496 } |
| 497 |
| 498 return 0; |
| 499 } |
| 500 |
| 501 static status_t make_port_pair(const char* name, void* ctx, port_t* write, port_
t* read) |
| 502 { |
| 503 status_t st = port_create(name, PORT_MODE_UNICAST, write); |
| 504 if (st < 0) |
| 505 return st; |
| 506 return port_open(name,ctx, read); |
| 507 } |
| 508 |
| 509 int group_basic(void) |
| 510 { |
| 511 // we spin a thread that connects to a well known port, then we |
| 512 // send two ports that it will add to a group port. |
| 513 port_t cmd_port; |
| 514 status_t st = port_create("grp_ctrl", PORT_MODE_UNICAST, &cmd_port); |
| 515 if (st < 0 ) { |
| 516 printf("could not create port, status = %d\n", st); |
| 517 return __LINE__; |
| 518 } |
| 519 |
| 520 thread_t* wt = thread_create( |
| 521 "g_watcher", &group_watcher_thread, NULL, DEFAULT_PRIORIT
Y, DEFAULT_STACK_SIZE); |
| 522 thread_resume(wt); |
| 523 |
| 524 port_t w_test_port1, r_test_port1; |
| 525 st = make_port_pair("tst_port1", TS1_PORT_CTX, &w_test_port1, &r_test_port1)
; |
| 526 if (st < 0) |
| 527 return __LINE__; |
| 528 |
| 529 port_t w_test_port2, r_test_port2; |
| 530 st = make_port_pair("tst_port2", TS2_PORT_CTX, &w_test_port2, &r_test_port2)
; |
| 531 if (st < 0) |
| 532 return __LINE__; |
| 533 |
| 534 st = send_watcher_cmd(cmd_port, ADD_PORT, r_test_port1); |
| 535 if (st < 0) |
| 536 return __LINE__; |
| 537 |
| 538 st = send_watcher_cmd(cmd_port, ADD_PORT, r_test_port2); |
| 539 if (st < 0) |
| 540 return __LINE__; |
| 541 |
| 542 thread_sleep(50); |
| 543 |
| 544 port_packet_t pp = {{0}}; |
| 545 st = port_write(w_test_port1, &pp, 1); |
| 546 if (st < 0) |
| 547 return __LINE__; |
| 548 |
| 549 st = port_write(w_test_port2, &pp, 1); |
| 550 if (st < 0) |
| 551 return __LINE__; |
| 552 |
| 553 st = send_watcher_cmd(cmd_port, QUIT, 0); |
| 554 if (st < 0) |
| 555 return __LINE__; |
| 556 |
| 557 int retcode = -1; |
| 558 thread_join(wt, &retcode, INFINITE_TIME); |
| 559 if (retcode) { |
| 560 printf("child thread exited with %d\n", retcode); |
| 561 return __LINE__; |
| 562 } |
| 563 |
| 564 st = port_close(w_test_port1); |
| 565 if (st < 0) |
| 566 return __LINE__; |
| 567 st = port_close(w_test_port2); |
| 568 if (st < 0) |
| 569 return __LINE__; |
| 570 st = port_close(cmd_port); |
| 571 if (st < 0) |
| 572 return __LINE__; |
| 573 st = port_destroy(w_test_port1); |
| 574 if (st < 0) |
| 575 return __LINE__; |
| 576 st = port_destroy(w_test_port2); |
| 577 if (st < 0) |
| 578 return __LINE__; |
| 579 st = port_destroy(cmd_port); |
| 580 if (st < 0) |
| 581 return __LINE__; |
| 582 |
| 583 return 0; |
| 584 } |
| 585 |
404 #define RUN_TEST(t) result = t(); if (result) goto fail | 586 #define RUN_TEST(t) result = t(); if (result) goto fail |
405 | 587 |
406 int port_tests(void) | 588 int port_tests(void) |
407 { | 589 { |
408 int result; | 590 int result; |
409 int count = 2; | 591 int count = 3; |
410 while (count--) { | 592 while (count--) { |
411 RUN_TEST(single_thread_basic); | 593 RUN_TEST(single_thread_basic); |
412 RUN_TEST(two_threads_basic); | 594 RUN_TEST(two_threads_basic); |
| 595 RUN_TEST(group_basic); |
413 } | 596 } |
414 | 597 |
415 printf("all tests passed\n"); | 598 printf("all tests passed\n"); |
416 return 0; | 599 return 0; |
417 fail: | 600 fail: |
418 printf("test failed at line %d\n", result); | 601 printf("test failed at line %d\n", result); |
419 return 1; | 602 return 1; |
420 } | 603 } |
421 | 604 |
422 #undef RUN_TEST | 605 #undef RUN_TEST |
OLD | NEW |