Mercurial > ecos
comparison packages/net/common/current/tests/tcp_echo.c @ 208:e0c0827131d1 ecos
Merge from eCos master repository on 2002-05-20-20:11:54-BST
| author | jlarmour |
|---|---|
| date | Mon, 20 May 2002 22:19:26 +0000 |
| parents | |
| children | 94b558c9fb67 |
comparison
equal
deleted
inserted
replaced
| 207:74c807ddde34 | 208:e0c0827131d1 |
|---|---|
| 1 //========================================================================== | |
| 2 // | |
| 3 // tests/tcp_echo.c | |
| 4 // | |
| 5 // Simple TCP throughput test - echo component | |
| 6 // | |
| 7 //========================================================================== | |
| 8 //####BSDCOPYRIGHTBEGIN#### | |
| 9 // | |
| 10 // ------------------------------------------- | |
| 11 // | |
| 12 // Portions of this software may have been derived from OpenBSD or other sources, | |
| 13 // and are covered by the appropriate copyright disclaimers included herein. | |
| 14 // | |
| 15 // ------------------------------------------- | |
| 16 // | |
| 17 //####BSDCOPYRIGHTEND#### | |
| 18 //========================================================================== | |
| 19 //#####DESCRIPTIONBEGIN#### | |
| 20 // | |
| 21 // Author(s): gthomas | |
| 22 // Contributors: gthomas | |
| 23 // Date: 2000-01-10 | |
| 24 // Purpose: | |
| 25 // Description: This is the middle part of a three part test. The idea is | |
| 26 // to test the throughput of box in a configuration like this: | |
| 27 // | |
| 28 // +------+ port +----+ port +----+ | |
| 29 // |SOURCE|=========>|ECHO|============>|SINK| | |
| 30 // +------+ 9990 +----+ 9991 +----+ | |
| 31 // | |
| 32 // | |
| 33 //####DESCRIPTIONEND#### | |
| 34 // | |
| 35 //========================================================================== | |
| 36 | |
| 37 #include <pkgconf/system.h> | |
| 38 #include <pkgconf/net.h> | |
| 39 | |
| 40 #ifdef CYGBLD_DEVS_ETH_DEVICE_H // Get the device config if it exists | |
| 41 #include CYGBLD_DEVS_ETH_DEVICE_H // May provide CYGTST_DEVS_ETH_TEST_NET_REALTIME | |
| 42 #endif | |
| 43 | |
| 44 #ifdef CYGPKG_NET_TESTS_USE_RT_TEST_HARNESS // do we use the rt test? | |
| 45 # ifdef CYGTST_DEVS_ETH_TEST_NET_REALTIME // Get the test ancilla if it exists | |
| 46 # include CYGTST_DEVS_ETH_TEST_NET_REALTIME | |
| 47 # endif | |
| 48 #endif | |
| 49 | |
| 50 | |
| 51 // Fill in the blanks if necessary | |
| 52 #ifndef TNR_OFF | |
| 53 # define TNR_OFF() | |
| 54 #endif | |
| 55 #ifndef TNR_ON | |
| 56 # define TNR_ON() | |
| 57 #endif | |
| 58 #ifndef TNR_INIT | |
| 59 # define TNR_INIT() | |
| 60 #endif | |
| 61 #ifndef TNR_PRINT_ACTIVITY | |
| 62 # define TNR_PRINT_ACTIVITY() | |
| 63 #endif | |
| 64 | |
| 65 | |
| 66 // Network throughput test code | |
| 67 | |
| 68 #include <lib/libkern/libkern.h> | |
| 69 | |
| 70 #include <network.h> | |
| 71 | |
| 72 #define SOURCE_PORT 9990 | |
| 73 #define SINK_PORT 9991 | |
| 74 | |
| 75 #define MAX_BUF 8192 | |
| 76 static unsigned char data_buf[MAX_BUF]; | |
| 77 | |
| 78 struct test_params { | |
| 79 long nbufs; | |
| 80 long bufsize; | |
| 81 long load; | |
| 82 }; | |
| 83 | |
| 84 struct test_status { | |
| 85 long ok; | |
| 86 }; | |
| 87 | |
| 88 #ifndef CYGPKG_LIBC_STDIO | |
| 89 #define perror(s) diag_printf(#s ": %s\n", strerror(errno)) | |
| 90 #endif | |
| 91 | |
| 92 #define STACK_SIZE (CYGNUM_HAL_STACK_SIZE_TYPICAL + 0x1000) | |
| 93 static char stack[STACK_SIZE]; | |
| 94 static cyg_thread thread_data; | |
| 95 static cyg_handle_t thread_handle; | |
| 96 | |
| 97 // Background load stuff | |
| 98 #define NUM_LOAD_THREADS 20 // Get 5% granularity | |
| 99 #define IDLE_THREAD_PRIORITY CYGPKG_NET_THREAD_PRIORITY+3 | |
| 100 #define LOAD_THREAD_PRIORITY CYGPKG_NET_THREAD_PRIORITY-3 | |
| 101 #define MAIN_THREAD_PRIORITY CYGPKG_NET_THREAD_PRIORITY-4 | |
| 102 #define DESIRED_BACKGROUND_LOAD 50 // should be accurate enough over range | |
| 103 | |
| 104 // starting points for load calculation | |
| 105 #define MAX_LOAD_THREAD_LEVEL 100 | |
| 106 #define MIN_LOAD_THREAD_LEVEL 0 | |
| 107 | |
| 108 static char idle_thread_stack[STACK_SIZE]; | |
| 109 static cyg_thread idle_thread_data; | |
| 110 static cyg_handle_t idle_thread_handle; | |
| 111 static cyg_sem_t idle_thread_sem; | |
| 112 volatile static long long idle_thread_count; | |
| 113 static char load_thread_stack[NUM_LOAD_THREADS][STACK_SIZE]; | |
| 114 static cyg_thread load_thread_data[NUM_LOAD_THREADS]; | |
| 115 static cyg_handle_t load_thread_handle[NUM_LOAD_THREADS]; | |
| 116 static cyg_sem_t load_thread_sem[NUM_LOAD_THREADS]; | |
| 117 static long load_thread_level; | |
| 118 static void calibrate_load(int load); | |
| 119 static void start_load(int load); | |
| 120 static void do_some_random_computation(int p,int id); | |
| 121 #define abs(n) ((n) < 0 ? -(n) : (n)) | |
| 122 | |
| 123 static long long no_load_idle_count_1_second; | |
| 124 | |
| 125 extern void | |
| 126 cyg_test_exit(void); | |
| 127 | |
| 128 void | |
| 129 pexit(char *s) | |
| 130 { | |
| 131 TNR_OFF(); | |
| 132 perror(s); | |
| 133 cyg_test_exit(); | |
| 134 } | |
| 135 | |
| 136 int | |
| 137 do_read(int s, void *_buf, int len) | |
| 138 { | |
| 139 int total, slen, rlen; | |
| 140 unsigned char *buf = (unsigned char *)_buf; | |
| 141 total = 0; | |
| 142 rlen = len; | |
| 143 while (total < len) { | |
| 144 slen = read(s, buf, rlen); | |
| 145 if (slen != rlen) { | |
| 146 if (slen < 0) { | |
| 147 diag_printf("Error after reading %d bytes\n", total); | |
| 148 return -1; | |
| 149 } | |
| 150 rlen -= slen; | |
| 151 buf += slen; | |
| 152 } | |
| 153 total += slen; | |
| 154 } | |
| 155 return total; | |
| 156 } | |
| 157 | |
| 158 int | |
| 159 do_write(int s, void *_buf, int len) | |
| 160 { | |
| 161 int total, slen, rlen; | |
| 162 unsigned char *buf = (unsigned char *)_buf; | |
| 163 total = 0; | |
| 164 rlen = len; | |
| 165 while (total < len) { | |
| 166 slen = write(s, buf, rlen); | |
| 167 if (slen != rlen) { | |
| 168 if (slen < 0) { | |
| 169 diag_printf("Error after writing %d bytes\n", total); | |
| 170 return -1; | |
| 171 } | |
| 172 rlen -= slen; | |
| 173 buf += slen; | |
| 174 } | |
| 175 total += slen; | |
| 176 } | |
| 177 return total; | |
| 178 } | |
| 179 | |
| 180 // | |
| 181 // This function is called to calibrate the "background load" which can be | |
| 182 // applied during testing. It will be called before any commands from the | |
| 183 // host are managed. | |
| 184 // | |
| 185 static void | |
| 186 calibrate_load(int desired_load) | |
| 187 { | |
| 188 long long no_load_idle, load_idle; | |
| 189 int percent_load; | |
| 190 int high, low; | |
| 191 | |
| 192 // Set limits | |
| 193 high = MAX_LOAD_THREAD_LEVEL; | |
| 194 low = MIN_LOAD_THREAD_LEVEL; | |
| 195 | |
| 196 // Compute the "no load" idle value | |
| 197 idle_thread_count = 0; | |
| 198 cyg_semaphore_post(&idle_thread_sem); // Start idle thread | |
| 199 cyg_thread_delay(1*100); // Pause for one second | |
| 200 cyg_semaphore_wait(&idle_thread_sem); // Stop idle thread | |
| 201 no_load_idle = idle_thread_count; | |
| 202 diag_printf("No load = %d\n", (int)idle_thread_count); | |
| 203 | |
| 204 // First ensure that the HIGH level is indeed higher | |
| 205 while (true) { | |
| 206 load_thread_level = high; | |
| 207 start_load(desired_load); // Start up a given load | |
| 208 idle_thread_count = 0; | |
| 209 cyg_semaphore_post(&idle_thread_sem); // Start idle thread | |
| 210 cyg_thread_delay(1*100); // Pause for one second | |
| 211 cyg_semaphore_wait(&idle_thread_sem); // Stop idle thread | |
| 212 load_idle = idle_thread_count; | |
| 213 start_load(0); // Shut down background load | |
| 214 percent_load = 100 - ((load_idle * 100) / no_load_idle); | |
| 215 diag_printf("High Load[%d] = %d => %d%%\n", load_thread_level, | |
| 216 (int)idle_thread_count, percent_load); | |
| 217 if ( percent_load > desired_load ) | |
| 218 break; // HIGH level is indeed higher | |
| 219 low = load_thread_level; // known to be lower | |
| 220 high *= 2; // else double it and try again | |
| 221 } | |
| 222 | |
| 223 // Now chop down to the level required | |
| 224 while (true) { | |
| 225 load_thread_level = (high + low) / 2; | |
| 226 start_load(desired_load); // Start up a given load | |
| 227 idle_thread_count = 0; | |
| 228 cyg_semaphore_post(&idle_thread_sem); // Start idle thread | |
| 229 cyg_thread_delay(1*100); // Pause for one second | |
| 230 cyg_semaphore_wait(&idle_thread_sem); // Stop idle thread | |
| 231 load_idle = idle_thread_count; | |
| 232 start_load(0); // Shut down background load | |
| 233 percent_load = 100 - ((load_idle * 100) / no_load_idle); | |
| 234 diag_printf("Load[%d] = %d => %d%%\n", load_thread_level, | |
| 235 (int)idle_thread_count, percent_load); | |
| 236 if (((high-low) <= 1) || (abs(desired_load-percent_load) <= 2)) break; | |
| 237 if (percent_load < desired_load) { | |
| 238 low = load_thread_level; | |
| 239 } else { | |
| 240 high = load_thread_level; | |
| 241 } | |
| 242 } | |
| 243 | |
| 244 // Now we are within a few percent of the target; scale the load | |
| 245 // factor to get a better fit, and test it, print the answer. | |
| 246 load_thread_level *= desired_load; | |
| 247 load_thread_level /= percent_load; | |
| 248 start_load(desired_load); // Start up a given load | |
| 249 idle_thread_count = 0; | |
| 250 cyg_semaphore_post(&idle_thread_sem); // Start idle thread | |
| 251 cyg_thread_delay(1*100); // Pause for one second | |
| 252 cyg_semaphore_wait(&idle_thread_sem); // Stop idle thread | |
| 253 load_idle = idle_thread_count; | |
| 254 start_load(0); // Shut down background load | |
| 255 percent_load = 100 - ((load_idle * 100) / no_load_idle); | |
| 256 diag_printf("Final load[%d] = %d => %d%%\n", load_thread_level, | |
| 257 (int)idle_thread_count, percent_load); | |
| 258 no_load_idle_count_1_second = no_load_idle; | |
| 259 } | |
| 260 | |
| 261 // | |
| 262 // This function is called to set up a load level of 'load' percent (given | |
| 263 // as a whole number, e.g. start_load(20) would mean initiate a background | |
| 264 // load of 20%, leaving the cpu 80% idle). | |
| 265 // | |
| 266 static void | |
| 267 start_load(int load) | |
| 268 { | |
| 269 static int prev_load = 0; | |
| 270 int i; | |
| 271 if (load == 0) { | |
| 272 diag_printf("Set no background load\n"); | |
| 273 if (prev_load == 0) return; // Nothing out there to stop | |
| 274 for (i = 0; i < prev_load * NUM_LOAD_THREADS/100; i++) { | |
| 275 cyg_semaphore_wait(&load_thread_sem[i]); | |
| 276 } | |
| 277 prev_load = 0; | |
| 278 } else { | |
| 279 diag_printf("Set background load = %d%% starting %d threads\n", | |
| 280 load, load * NUM_LOAD_THREADS/100 ); | |
| 281 for (i = 0; i < load * NUM_LOAD_THREADS/100; i++) { | |
| 282 cyg_semaphore_post(&load_thread_sem[i]); | |
| 283 } | |
| 284 prev_load = load; | |
| 285 } | |
| 286 } | |
| 287 | |
| 288 // | |
| 289 // These thread(s) do some amount of "background" computing. This is used | |
| 290 // to simulate a given load level. They need to be run at a higher priority | |
| 291 // than the network code itself. | |
| 292 // | |
| 293 // Like the "idle" thread, they run as long as their "switch" (aka semaphore) | |
| 294 // is enabled. | |
| 295 // | |
| 296 void | |
| 297 net_load(cyg_addrword_t who) | |
| 298 { | |
| 299 int i; | |
| 300 while (true) { | |
| 301 cyg_semaphore_wait(&load_thread_sem[who]); | |
| 302 for (i = 0; i < load_thread_level; i++) { | |
| 303 do_some_random_computation(i,who); | |
| 304 } | |
| 305 cyg_thread_delay(1); // Wait until the next 'tick' | |
| 306 cyg_semaphore_post(&load_thread_sem[who]); | |
| 307 } | |
| 308 } | |
| 309 | |
| 310 // | |
| 311 // Some arbitrary computation, designed to use up the CPU and cause associated | |
| 312 // cache "thrash" behaviour - part of background load modelling. | |
| 313 // | |
| 314 static void | |
| 315 do_some_random_computation(int p,int id) | |
| 316 { | |
| 317 // Just something that might be "hard" | |
| 318 #if 0 | |
| 319 { | |
| 320 volatile double x; | |
| 321 x = ((p * 10) * 3.14159) / 180.0; // radians | |
| 322 } | |
| 323 #endif | |
| 324 #if 1 | |
| 325 { | |
| 326 static int footle[0x10001]; | |
| 327 static int counter = 0; | |
| 328 register int i; | |
| 329 | |
| 330 i = (p << 8) + id + counter++; | |
| 331 i &= 0xffff; | |
| 332 footle[ i+1 ] += footle[ i ] + 1; | |
| 333 } | |
| 334 #endif | |
| 335 } | |
| 336 | |
| 337 // | |
| 338 // This thread does nothing but count. It will be allowed to count | |
| 339 // as long as the semaphore is "free". | |
| 340 // | |
| 341 void | |
| 342 net_idle(cyg_addrword_t param) | |
| 343 { | |
| 344 while (true) { | |
| 345 cyg_semaphore_wait(&idle_thread_sem); | |
| 346 idle_thread_count++; | |
| 347 cyg_semaphore_post(&idle_thread_sem); | |
| 348 } | |
| 349 } | |
| 350 | |
| 351 static void | |
| 352 echo_test(cyg_addrword_t p) | |
| 353 { | |
| 354 int s_source, s_sink, e_source, e_sink; | |
| 355 struct sockaddr_in e_source_addr, e_sink_addr, local; | |
| 356 int one = 1; | |
| 357 fd_set in_fds; | |
| 358 int i, num, len; | |
| 359 struct test_params params,nparams; | |
| 360 struct test_status status,nstatus; | |
| 361 | |
| 362 cyg_tick_count_t starttime, stoptime; | |
| 363 | |
| 364 s_source = socket(AF_INET, SOCK_STREAM, 0); | |
| 365 if (s_source < 0) { | |
| 366 pexit("stream socket"); | |
| 367 } | |
| 368 if (setsockopt(s_source, SOL_SOCKET, SO_REUSEADDR, &one, sizeof(one))) { | |
| 369 pexit("setsockopt /source/ SO_REUSEADDR"); | |
| 370 } | |
| 371 if (setsockopt(s_source, SOL_SOCKET, SO_REUSEPORT, &one, sizeof(one))) { | |
| 372 pexit("setsockopt /source/ SO_REUSEPORT"); | |
| 373 } | |
| 374 memset(&local, 0, sizeof(local)); | |
| 375 local.sin_family = AF_INET; | |
| 376 local.sin_len = sizeof(local); | |
| 377 local.sin_port = ntohs(SOURCE_PORT); | |
| 378 local.sin_addr.s_addr = INADDR_ANY; | |
| 379 if(bind(s_source, (struct sockaddr *) &local, sizeof(local)) < 0) { | |
| 380 pexit("bind /source/ error"); | |
| 381 } | |
| 382 listen(s_source, SOMAXCONN); | |
| 383 | |
| 384 s_sink = socket(AF_INET, SOCK_STREAM, 0); | |
| 385 if (s_sink < 0) { | |
| 386 pexit("stream socket"); | |
| 387 } | |
| 388 memset(&local, 0, sizeof(local)); | |
| 389 local.sin_family = AF_INET; | |
| 390 local.sin_len = sizeof(local); | |
| 391 local.sin_port = ntohs(SINK_PORT); | |
| 392 local.sin_addr.s_addr = INADDR_ANY; | |
| 393 if(bind(s_sink, (struct sockaddr *) &local, sizeof(local)) < 0) { | |
| 394 pexit("bind /sink/ error"); | |
| 395 } | |
| 396 if (setsockopt(s_sink, SOL_SOCKET, SO_REUSEADDR, &one, sizeof(one))) { | |
| 397 pexit("setsockopt /sink/ SO_REUSEADDR"); | |
| 398 } | |
| 399 if (setsockopt(s_sink, SOL_SOCKET, SO_REUSEPORT, &one, sizeof(one))) { | |
| 400 pexit("setsockopt /sink/ SO_REUSEPORT"); | |
| 401 } | |
| 402 listen(s_sink, SOMAXCONN); | |
| 403 | |
| 404 e_source = 0; e_sink = 0; | |
| 405 while (true) { | |
| 406 // Wait for a connection on either of the ports | |
| 407 FD_ZERO(&in_fds); | |
| 408 FD_SET(s_source, &in_fds); | |
| 409 FD_SET(s_sink, &in_fds); | |
| 410 num = select(max(s_sink,s_source)+1, &in_fds, 0, 0, 0); | |
| 411 if (FD_ISSET(s_source, &in_fds)) { | |
| 412 len = sizeof(e_source_addr); | |
| 413 if ((e_source = accept(s_source, (struct sockaddr *)&e_source_addr, &len)) < 0) { | |
| 414 pexit("accept /source/"); | |
| 415 } | |
| 416 diag_printf("SOURCE connection from %s:%d\n", | |
| 417 inet_ntoa(e_source_addr.sin_addr), ntohs(e_source_addr.sin_port)); | |
| 418 } | |
| 419 if (FD_ISSET(s_sink, &in_fds)) { | |
| 420 len = sizeof(e_sink_addr); | |
| 421 if ((e_sink = accept(s_sink, (struct sockaddr *)&e_sink_addr, &len)) < 0) { | |
| 422 pexit("accept /sink/"); | |
| 423 } | |
| 424 diag_printf("SINK connection from %s:%d\n", | |
| 425 inet_ntoa(e_sink_addr.sin_addr), ntohs(e_sink_addr.sin_port)); | |
| 426 } | |
| 427 // Continue with test once a connection is established in both directions | |
| 428 if ((e_source != 0) && (e_sink != 0)) { | |
| 429 break; | |
| 430 } | |
| 431 } | |
| 432 | |
| 433 // Wait for "source" to tell us the testing paramters | |
| 434 if (do_read(e_source, &nparams, sizeof(nparams)) != sizeof(nparams)) { | |
| 435 pexit("Can't read initialization parameters"); | |
| 436 } | |
| 437 | |
| 438 params.nbufs = ntohl(nparams.nbufs); | |
| 439 params.bufsize = ntohl(nparams.bufsize); | |
| 440 params.load = ntohl(nparams.load); | |
| 441 | |
| 442 diag_printf("Using %d buffers of %d bytes each, %d%% background load\n", | |
| 443 params.nbufs, params.bufsize, params.load); | |
| 444 | |
| 445 // Tell the sink what the parameters are | |
| 446 if (do_write(e_sink, &nparams, sizeof(nparams)) != sizeof(nparams)) { | |
| 447 pexit("Can't write initialization parameters"); | |
| 448 } | |
| 449 | |
| 450 status.ok = 1; | |
| 451 nstatus.ok = htonl(status.ok); | |
| 452 | |
| 453 // Tell the "source" to start - we're all connected and ready to go! | |
| 454 if (do_write(e_source, &nstatus, sizeof(nstatus)) != sizeof(nstatus)) { | |
| 455 pexit("Can't send ACK to 'source' host"); | |
| 456 } | |
| 457 | |
| 458 idle_thread_count = 0; | |
| 459 cyg_semaphore_post(&idle_thread_sem); // Start idle thread | |
| 460 starttime = cyg_current_time(); | |
| 461 start_load(params.load); | |
| 462 | |
| 463 TNR_ON(); | |
| 464 | |
| 465 // Echo the data from the source to the sink hosts | |
| 466 for (i = 0; i < params.nbufs; i++) { | |
| 467 if ((len = do_read(e_source, data_buf, params.bufsize)) != params.bufsize) { | |
| 468 TNR_OFF(); | |
| 469 diag_printf("Can't read buf #%d: ", i+1); | |
| 470 if (len < 0) { | |
| 471 perror("I/O error"); | |
| 472 } else { | |
| 473 diag_printf("short read - only %d bytes\n", len); | |
| 474 } | |
| 475 TNR_ON(); | |
| 476 } | |
| 477 if ((len = do_write(e_sink, data_buf, params.bufsize)) != params.bufsize) { | |
| 478 TNR_OFF(); | |
| 479 diag_printf("Can't write buf #%d: ", i+1); | |
| 480 if (len < 0) { | |
| 481 perror("I/O error"); | |
| 482 } else { | |
| 483 diag_printf("short write - only %d bytes\n", len); | |
| 484 } | |
| 485 TNR_ON(); | |
| 486 } | |
| 487 } | |
| 488 | |
| 489 TNR_OFF(); | |
| 490 | |
| 491 // Wait for the data to drain and the "sink" to tell us all is OK. | |
| 492 if (do_read(e_sink, &status, sizeof(status)) != sizeof(status)) { | |
| 493 pexit("Can't receive ACK from 'sink' host"); | |
| 494 } | |
| 495 | |
| 496 start_load(0); | |
| 497 cyg_semaphore_wait(&idle_thread_sem); // Stop idle thread | |
| 498 stoptime = cyg_current_time(); | |
| 499 stoptime -= starttime; // time taken in cS | |
| 500 // expected idle loops in that time period for an idle system: | |
| 501 starttime = no_load_idle_count_1_second * stoptime / 100; | |
| 502 diag_printf( "%d ticks elapsed, %d kloops predicted for an idle system\n", | |
| 503 (int)stoptime, (int)(starttime/1000) ); | |
| 504 diag_printf( "actual kloops %d, CPU was %d%% idle during transfer\n", | |
| 505 (int)(idle_thread_count/1000), | |
| 506 (int)(idle_thread_count * 100 / starttime) ); | |
| 507 | |
| 508 // Now examine how close that loading actually was: | |
| 509 start_load(params.load); // Start up a given load | |
| 510 idle_thread_count = 0; | |
| 511 cyg_semaphore_post(&idle_thread_sem); // Start idle thread | |
| 512 cyg_thread_delay(1*100); // Pause for one second | |
| 513 cyg_semaphore_wait(&idle_thread_sem); // Stop idle thread | |
| 514 start_load(0); // Shut down background load | |
| 515 i = 100 - ((idle_thread_count * 100) / no_load_idle_count_1_second ); | |
| 516 diag_printf("Final load[%d] = %d => %d%%\n", load_thread_level, | |
| 517 (int)idle_thread_count, i); | |
| 518 | |
| 519 //#ifdef CYGDBG_USE_ASSERTS | |
| 520 #ifdef CYGDBG_NET_TIMING_STATS | |
| 521 { | |
| 522 extern void show_net_times(void); | |
| 523 show_net_times(); | |
| 524 } | |
| 525 #endif | |
| 526 //#endif | |
| 527 } | |
| 528 | |
| 529 void | |
| 530 net_test(cyg_addrword_t param) | |
| 531 { | |
| 532 diag_printf("Start TCP test - ECHO mode\n"); | |
| 533 init_all_network_interfaces(); | |
| 534 calibrate_load(DESIRED_BACKGROUND_LOAD); | |
| 535 TNR_INIT(); | |
| 536 #ifdef CYGPKG_SNMPAGENT | |
| 537 { | |
| 538 extern void cyg_net_snmp_init(void); | |
| 539 cyg_net_snmp_init(); | |
| 540 } | |
| 541 #endif | |
| 542 echo_test(param); | |
| 543 TNR_PRINT_ACTIVITY(); | |
| 544 cyg_test_exit(); | |
| 545 } | |
| 546 | |
| 547 void | |
| 548 cyg_start(void) | |
| 549 { | |
| 550 int i; | |
| 551 // Create a main thread which actually runs the test | |
| 552 cyg_thread_create(MAIN_THREAD_PRIORITY, // Priority | |
| 553 net_test, // entry | |
| 554 0, // entry parameter | |
| 555 "Network test", // Name | |
| 556 &stack[0], // Stack | |
| 557 STACK_SIZE, // Size | |
| 558 &thread_handle, // Handle | |
| 559 &thread_data // Thread data structure | |
| 560 ); | |
| 561 cyg_thread_resume(thread_handle); // Start it | |
| 562 // Create the idle thread environment | |
| 563 cyg_semaphore_init(&idle_thread_sem, 0); | |
| 564 cyg_thread_create(IDLE_THREAD_PRIORITY, // Priority | |
| 565 net_idle, // entry | |
| 566 0, // entry parameter | |
| 567 "Network idle", // Name | |
| 568 &idle_thread_stack[0], // Stack | |
| 569 STACK_SIZE, // Size | |
| 570 &idle_thread_handle, // Handle | |
| 571 &idle_thread_data // Thread data structure | |
| 572 ); | |
| 573 cyg_thread_resume(idle_thread_handle); // Start it | |
| 574 // Create the load threads and their environment(s) | |
| 575 for (i = 0; i < NUM_LOAD_THREADS; i++) { | |
| 576 cyg_semaphore_init(&load_thread_sem[i], 0); | |
| 577 cyg_thread_create(LOAD_THREAD_PRIORITY, // Priority | |
| 578 net_load, // entry | |
| 579 i, // entry parameter | |
| 580 "Background load", // Name | |
| 581 &load_thread_stack[i][0], // Stack | |
| 582 STACK_SIZE, // Size | |
| 583 &load_thread_handle[i], // Handle | |
| 584 &load_thread_data[i] // Thread data structure | |
| 585 ); | |
| 586 cyg_thread_resume(load_thread_handle[i]); // Start it | |
| 587 } | |
| 588 cyg_scheduler_start(); | |
| 589 } | |
| 590 | |
| 591 // EOF tcp_echo.c |
