OLD | NEW |
(Empty) | |
| 1 /* |
| 2 * Copyright (c) 2015 Carlos Pizano-Uribe cpu@chromium.org |
| 3 * |
| 4 * Permission is hereby granted, free of charge, to any person obtaining |
| 5 * a copy of this software and associated documentation files |
| 6 * (the "Software"), to deal in the Software without restriction, |
| 7 * including without limitation the rights to use, copy, modify, merge, |
| 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, |
| 10 * subject to the following conditions: |
| 11 * |
| 12 * The above copyright notice and this permission notice shall be |
| 13 * included in all copies or substantial portions of the Software. |
| 14 * |
| 15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, |
| 16 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF |
| 17 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. |
| 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, |
| 20 * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE |
| 21 * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. |
| 22 */ |
| 23 |
| 24 #include <debug.h> |
| 25 #include <err.h> |
| 26 #include <string.h> |
| 27 #include <rand.h> |
| 28 |
| 29 #include <kernel/port.h> |
| 30 #include <kernel/thread.h> |
| 31 |
| 32 #include <platform.h> |
| 33 |
| 34 void* context1 = (void*) 0x53; |
| 35 |
| 36 static void dump_port_result(const port_result_t* result) |
| 37 { |
| 38 const port_packet_t* p = &result->packet; |
| 39 printf("[%02x %02x %02x %02x %02x %02x %02x %02x]\n", |
| 40 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]); |
| 42 } |
| 43 |
| 44 static int single_thread_basic(void) |
| 45 { |
| 46 port_t w_port; |
| 47 status_t st = port_create("sh_prt1", PORT_MODE_UNICAST, &w_port); |
| 48 if (st < 0) { |
| 49 printf("could not create port, status = %d\n", st); |
| 50 return __LINE__; |
| 51 } |
| 52 |
| 53 port_t r_port; |
| 54 st = port_open("sh_prt0", context1, &r_port); |
| 55 if (st != ERR_NOT_FOUND) { |
| 56 printf("expected not to find port, status = %d\n", st); |
| 57 return __LINE__; |
| 58 } |
| 59 |
| 60 st = port_open("sh_prt1", context1, &r_port); |
| 61 if (st < 0) { |
| 62 printf("could not open port, status = %d\n", st); |
| 63 return __LINE__; |
| 64 } |
| 65 |
| 66 |
| 67 port_packet_t packet[3] = { |
| 68 {{0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08}}, |
| 69 {{0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10, 0x11}}, |
| 70 {{0x33, 0x66, 0x99, 0xcc, 0x33, 0x66, 0x99, 0xcc}}, |
| 71 }; |
| 72 |
| 73 st = port_write(w_port, &packet[0], 1); |
| 74 if (st < 0) { |
| 75 printf("could not write port, status = %d\n", st); |
| 76 return __LINE__; |
| 77 } |
| 78 |
| 79 printf("reading from port:\n"); |
| 80 |
| 81 port_result_t res = {0}; |
| 82 |
| 83 st = port_read(r_port, 0, &res); |
| 84 if (st < 0) { |
| 85 printf("could not read port, status = %d\n", st); |
| 86 return __LINE__; |
| 87 } |
| 88 if (res.ctx != context1) { |
| 89 printf("bad context! = %p\n", res.ctx); |
| 90 return __LINE__; |
| 91 } |
| 92 |
| 93 st = port_read(r_port, 0, &res); |
| 94 if (st != ERR_TIMED_OUT) { |
| 95 printf("expected timeout, status = %d\n", st); |
| 96 return __LINE__; |
| 97 } |
| 98 |
| 99 st = port_write(w_port, &packet[1], 1); |
| 100 if (st < 0) { |
| 101 printf("could not write port, status = %d\n", st); |
| 102 return __LINE__; |
| 103 } |
| 104 |
| 105 st = port_write(w_port, &packet[0], 1); |
| 106 if (st < 0) { |
| 107 printf("could not write port, status = %d\n", st); |
| 108 return __LINE__; |
| 109 } |
| 110 |
| 111 st = port_write(w_port, &packet[2], 1); |
| 112 if (st < 0) { |
| 113 printf("could not write port, status = %d\n", st); |
| 114 return __LINE__; |
| 115 } |
| 116 |
| 117 int expected_count = 3; |
| 118 while (true) { |
| 119 st = port_read(r_port, 0, &res); |
| 120 if (st < 0) |
| 121 break; |
| 122 dump_port_result(&res); |
| 123 --expected_count; |
| 124 } |
| 125 |
| 126 if (expected_count != 0) { |
| 127 printf("invalid read count = %d\n", expected_count); |
| 128 return __LINE__; |
| 129 } |
| 130 |
| 131 printf("\n"); |
| 132 |
| 133 // port should be empty. should be able to write 8 packets. |
| 134 expected_count = 8; |
| 135 while (true) { |
| 136 st = port_write(w_port, &packet[1], 1); |
| 137 if (st < 0) |
| 138 break; |
| 139 --expected_count; |
| 140 st = port_write(w_port, &packet[2], 1); |
| 141 if (st < 0) |
| 142 break; |
| 143 --expected_count; |
| 144 } |
| 145 |
| 146 if (expected_count != 0) { |
| 147 printf("invalid write count = %d\n", expected_count); |
| 148 return __LINE__; |
| 149 } |
| 150 |
| 151 // tod(cpu) fix this possibly wrong error. |
| 152 if (st != ERR_PARTIAL_WRITE) { |
| 153 printf("expected buffer error, status =%d\n", st); |
| 154 return __LINE__; |
| 155 } |
| 156 |
| 157 // read 3 packets. |
| 158 for (int ix = 0; ix != 3; ++ix) { |
| 159 st = port_read(r_port, 0, &res); |
| 160 if (st < 0) { |
| 161 printf("could not read port, status = %d\n", st); |
| 162 return __LINE__; |
| 163 } |
| 164 } |
| 165 |
| 166 // there are 5 packets, now we add another 3. |
| 167 st = port_write(w_port, packet, 3); |
| 168 if (st < 0) { |
| 169 printf("could not write port, status = %d\n", st); |
| 170 return __LINE__; |
| 171 } |
| 172 |
| 173 expected_count = 8; |
| 174 while (true) { |
| 175 st = port_read(r_port, 0, &res); |
| 176 if (st < 0) |
| 177 break; |
| 178 dump_port_result(&res); |
| 179 --expected_count; |
| 180 } |
| 181 |
| 182 if (expected_count != 0) { |
| 183 printf("invalid read count = %d\n", expected_count); |
| 184 return __LINE__; |
| 185 } |
| 186 |
| 187 // attempt to use the wrong port. |
| 188 st = port_write(r_port, &packet[1], 1); |
| 189 if (st != ERR_BAD_HANDLE) { |
| 190 printf("expected bad handle error, status = %d\n", st); |
| 191 return __LINE__; |
| 192 } |
| 193 |
| 194 st = port_read(w_port, 0, &res); |
| 195 if (st != ERR_BAD_HANDLE) { |
| 196 printf("expected bad handle error, status = %d\n", st); |
| 197 return __LINE__; |
| 198 } |
| 199 |
| 200 st = port_close(r_port); |
| 201 if (st < 0) { |
| 202 printf("could not close read port, status = %d\n", st); |
| 203 return __LINE__; |
| 204 } |
| 205 |
| 206 st = port_close(w_port); |
| 207 if (st < 0) { |
| 208 printf("could not close write port, status = %d\n", st); |
| 209 return __LINE__; |
| 210 } |
| 211 |
| 212 st = port_close(r_port); |
| 213 if (st != ERR_BAD_HANDLE) { |
| 214 printf("expected bad handle error, status = %d\n", st); |
| 215 return __LINE__; |
| 216 } |
| 217 |
| 218 st = port_close(w_port); |
| 219 if (st != ERR_BAD_HANDLE) { |
| 220 printf("expected bad handle error, status = %d\n", st); |
| 221 return __LINE__; |
| 222 } |
| 223 |
| 224 st = port_destroy(w_port); |
| 225 if (st < 0) { |
| 226 printf("could not destroy port, status = %d\n", st); |
| 227 return __LINE__; |
| 228 } |
| 229 |
| 230 printf("single_thread_basic : ok\n"); |
| 231 return 0; |
| 232 } |
| 233 |
| 234 static int ping_pong_thread(void *arg) |
| 235 { |
| 236 port_t r_port; |
| 237 status_t st = port_open("ping_port", NULL, &r_port); |
| 238 if (st < 0) { |
| 239 printf("thread: could not open port, status = %d\n", st); |
| 240 return __LINE__; |
| 241 } |
| 242 |
| 243 bool should_dispose_pong_port = true; |
| 244 port_t w_port; |
| 245 st = port_create("pong_port", PORT_MODE_UNICAST, &w_port); |
| 246 if (st == ERR_ALREADY_EXISTS) { |
| 247 // won the race to create the port. |
| 248 should_dispose_pong_port = false; |
| 249 } else if (st < 0) { |
| 250 printf("thread: could not open port, status = %d\n", st); |
| 251 return __LINE__; |
| 252 } |
| 253 |
| 254 port_result_t pr; |
| 255 |
| 256 // the loop is read-mutate-write until the write port |
| 257 // is closed by the master thread. |
| 258 while (true) { |
| 259 st = port_read(r_port, INFINITE_TIME, &pr); |
| 260 |
| 261 if (st == ERR_CANCELLED) { |
| 262 break; |
| 263 } else if (st < 0) { |
| 264 printf("thread: could not read port, status = %d\n", st); |
| 265 return __LINE__; |
| 266 } |
| 267 |
| 268 pr.packet.value[0]++; |
| 269 pr.packet.value[5]--; |
| 270 |
| 271 st = port_write(w_port, &pr.packet, 1); |
| 272 if (st < 0) { |
| 273 printf("thread: could not write port, status = %d\n", st); |
| 274 return __LINE__; |
| 275 } |
| 276 } |
| 277 |
| 278 port_close(r_port); |
| 279 |
| 280 if (should_dispose_pong_port) { |
| 281 port_close(w_port); |
| 282 port_destroy(w_port); |
| 283 } |
| 284 |
| 285 return 0; |
| 286 |
| 287 bail: |
| 288 return __LINE__; |
| 289 } |
| 290 |
| 291 |
| 292 int two_threads_basic(void) |
| 293 { |
| 294 port_t w_port; |
| 295 status_t st = port_create("ping_port", PORT_MODE_BROADCAST, &w_port); |
| 296 if (st < 0) { |
| 297 printf("could not create port, status = %d\n", st); |
| 298 return __LINE__; |
| 299 } |
| 300 |
| 301 thread_t* t1 = thread_create( |
| 302 "worker1", &ping_pong_thread, NULL, DEFAULT_PRIORITY, DEF
AULT_STACK_SIZE); |
| 303 thread_t* t2 = thread_create( |
| 304 "worker2", &ping_pong_thread, NULL, DEFAULT_PRIORITY, DEF
AULT_STACK_SIZE); |
| 305 thread_resume(t1); |
| 306 thread_resume(t2); |
| 307 |
| 308 // wait for the pong port to be created, the two threads race to do it. |
| 309 port_t r_port; |
| 310 while (true) { |
| 311 status_t st = port_open("pong_port", NULL, &r_port); |
| 312 if (st == NO_ERROR) { |
| 313 break; |
| 314 } else if (st == ERR_NOT_FOUND) { |
| 315 thread_sleep(100); |
| 316 } else { |
| 317 printf("could not open port, status = %d\n", st); |
| 318 return __LINE__; |
| 319 } |
| 320 } |
| 321 |
| 322 // We have two threads listening to the ping port. Which both reply |
| 323 // on the pong port, so we get two packets in per packet out. |
| 324 const int passes = 256; |
| 325 printf("two_threads_basic test, %d passes\n", passes); |
| 326 |
| 327 port_packet_t packet_out = {{0xaf, 0x77, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05}
}; |
| 328 |
| 329 port_result_t pr; |
| 330 for (int ix = 0; ix != passes; ++ix) { |
| 331 const size_t count = 1 + ((unsigned int)rand() % 3); |
| 332 |
| 333 for (size_t jx = 0; jx != count; ++jx) { |
| 334 st = port_write(w_port, &packet_out, 1); |
| 335 if (st < 0) { |
| 336 printf("could not write port, status = %d\n", st); |
| 337 return __LINE__; |
| 338 } |
| 339 } |
| 340 |
| 341 packet_out.value[0]++; |
| 342 packet_out.value[5]--; |
| 343 |
| 344 for (size_t jx = 0; jx != count * 2; ++jx) { |
| 345 st = port_read(r_port, INFINITE_TIME, &pr); |
| 346 if (st < 0) { |
| 347 printf("could not read port, status = %d\n", st); |
| 348 return __LINE__; |
| 349 } |
| 350 |
| 351 if ((pr.packet.value[0] != packet_out.value[0]) || |
| 352 (pr.packet.value[5] != packet_out.value[5])) { |
| 353 printf("unexpected data in packet, loop %d", ix); |
| 354 return __LINE__; |
| 355 } |
| 356 } |
| 357 } |
| 358 |
| 359 thread_sleep(100); |
| 360 |
| 361 // there should be no more packets to read. |
| 362 st = port_read(r_port, 0, &pr); |
| 363 if (st != ERR_TIMED_OUT) { |
| 364 printf("unexpected packet, status = %d\n", st); |
| 365 return __LINE__; |
| 366 } |
| 367 |
| 368 printf("two_threads_basic master shutdown\n"); |
| 369 |
| 370 st = port_close(r_port); |
| 371 if (st < 0) { |
| 372 printf("could not close port, status = %d\n", st); |
| 373 return __LINE__; |
| 374 } |
| 375 |
| 376 st = port_close(w_port); |
| 377 if (st < 0) { |
| 378 printf("could not close port, status = %d\n", st); |
| 379 return __LINE__; |
| 380 } |
| 381 |
| 382 st = port_destroy(w_port); |
| 383 if (st < 0) { |
| 384 printf("could not destroy port, status = %d\n", st); |
| 385 return __LINE__; |
| 386 } |
| 387 |
| 388 int retcode = -1; |
| 389 thread_join(t1, &retcode, INFINITE_TIME); |
| 390 if (retcode) |
| 391 goto fail; |
| 392 |
| 393 thread_join(t2, &retcode, INFINITE_TIME); |
| 394 if (retcode) |
| 395 goto fail; |
| 396 |
| 397 return 0; |
| 398 |
| 399 fail: |
| 400 printf("child thread exited with %d\n", retcode); |
| 401 return __LINE__; |
| 402 } |
| 403 |
| 404 #define RUN_TEST(t) result = t(); if (result) goto fail |
| 405 |
| 406 int port_tests(void) |
| 407 { |
| 408 int result; |
| 409 int count = 2; |
| 410 while (count--) { |
| 411 RUN_TEST(single_thread_basic); |
| 412 RUN_TEST(two_threads_basic); |
| 413 } |
| 414 |
| 415 printf("all tests passed\n"); |
| 416 return 0; |
| 417 fail: |
| 418 printf("test failed at line %d\n", result); |
| 419 return 1; |
| 420 } |
| 421 |
| 422 #undef RUN_TEST |
OLD | NEW |