nc6_test_slave.c

来自「ecos实时嵌入式操作系统」· C语言 代码 · 共 909 行 · 第 1/2 页

C
909
字号
            tdp->len = htonl(td_len);            if (write(test_chan, tdp, td_len) != td_len) {                perror("write");                if (errno == ENOBUFS) {                    // Saturated the system                    test_delay(25);                } else {                    // What else to do?                    close(test_chan);                    return;                }            } else {                nsent++;            }        }        seq++;    }    results.key1 = htonl(NC_TEST_RESULT_KEY1);    results.key2 = htonl(NC_TEST_RESULT_KEY2);    results.seq = req->seq;    results.nsent = htonl(nsent);    results.nrecvd = htonl(nrecvd);    if (write(test_chan, &results, sizeof(results)) != sizeof(results)) {        perror("write");    }    close(test_chan);}#define MAXSOCK 16  // Max # sockets to listen onstatic intwaitfor(int *socks, int len, int last_sock){    fd_set src_fds;    int i, s, num;    // Wait for some activity on one of the ports    FD_ZERO(&src_fds);    for (s = 0;  s < len;  s++) {        FD_SET(socks[s], &src_fds);    }    num = select(last_sock+1, &src_fds, 0, 0, 0);    if (num > 0) {        for (i = 0;  i < len; i++) {            s = socks[i];            if (FD_ISSET(s, &src_fds)) {                return s;  // Return first available socket            }        }        pexit("select, but no socket!");    } else {        pexit("select");    }    return 0;}//// Protocol driver for testing slave.//// This function is the main routine running here, handling requests sent from// the master and providing various responses.//static voidnc_slave(test_param_t param){    int sock_indx, s, err, last_sock, socks[MAXSOCK], masterlen;    struct sockaddr_storage master;    struct nc_request req;    struct nc_reply reply;    int done = false;    struct addrinfo *ai, *addrs, hints;    char addr_buf[256];    test_printf("Start test for eth%d\n", param);    bzero(&hints, sizeof(hints));    hints.ai_family = PF_UNSPEC;    hints.ai_socktype = SOCK_DGRAM;    hints.ai_flags = AI_PASSIVE;    if ((err = getaddrinfo(NULL, _string(NC_SLAVE_PORT), &hints, &addrs)) != EAI_NONE) {        test_printf("<ERROR> can't getaddrinfo(): %s\n", gai_strerror(err));        pexit("getaddrinfo");    }    // Prepare a socket for each connection type    sock_indx = 0;  last_sock = -1;    ai = addrs;    while (ai) {#ifdef __ECOS        _inet_ntop(ai->ai_addr, addr_buf, sizeof(addr_buf));        test_printf("Family: %d, Socket: %d, Addr: %s\n", ai->ai_family, ai->ai_socktype, addr_buf);#else        test_printf("Family: %d, Socket: %d\n", ai->ai_family, ai->ai_socktype);#endif#ifdef __linux// This code is very sensitive on Linux        s = socket(ai->ai_family, ai->ai_socktype, 0);        if (s < 0) {            test_printf("Can't bind socket\n");//            pexit("dgram socket");        } else {            if(bind(s, ai->ai_addr, sa_len(ai->ai_addr)) < 0) {                test_printf("Failed to bind family: %d\n", ai->ai_family);//            pexit("bind server error");            } else {                socks[sock_indx++] = s;                if (sock_indx >= MAXSOCK) {                    pexit("Too many address types");                }            }        }#else        s = socket(ai->ai_family, ai->ai_socktype, 0);        if (s < 0) {            pexit("dgram socket");        }        if(bind(s, ai->ai_addr, sa_len(ai->ai_addr)) < 0) {            test_printf("Failed to bind family: %d\n", ai->ai_family);            pexit("bind server error");        }        socks[sock_indx++] = s;        if (sock_indx >= MAXSOCK) {            pexit("Too many address types");        }#endif        ai = ai->ai_next;        if (s > last_sock) last_sock = s;    }    while (!done && (s = waitfor(socks, sock_indx, last_sock))) {        // Data is available from socket 's'        masterlen = sizeof(master);        if (recvfrom(s, &req, sizeof(req), 0, (struct sockaddr *)&master, &masterlen) < 0) {            pexit("recvfrom service");        }#if 0        _inet_ntop((struct sockaddr *)&master, addr_buf, sizeof(addr_buf));        test_printf("Request %d %s(%d)\n", ntohl(req.type), addr_buf,                     (struct sockaddr *)_inet_port(&master));#endif        reply.response = htonl(NC_REPLY_ACK);        reply.seq = req.seq;        switch (ntohl(req.type)) {        case NC_REQUEST_DISCONNECT:            done = true;            test_printf("Master has issued disconnect - I quit!\n");            break;        case NC_REQUEST_UDP_SEND:            test_printf("UDP send - %d buffers, %d bytes\n", ntohl(req.nbufs), ntohl(req.buflen));            break;        case NC_REQUEST_UDP_RECV:            test_printf("UDP recv - %d buffers, %d bytes\n", ntohl(req.nbufs), ntohl(req.buflen));            break;        case NC_REQUEST_UDP_ECHO:            test_printf("UDP echo - %d buffers, %d bytes\n", ntohl(req.nbufs), ntohl(req.buflen));            break;        case NC_REQUEST_TCP_SEND:            test_printf("TCP send - %d buffers, %d bytes\n", ntohl(req.nbufs), ntohl(req.buflen));            break;        case NC_REQUEST_TCP_RECV:            test_printf("TCP recv - %d buffers, %d bytes\n", ntohl(req.nbufs), ntohl(req.buflen));            break;        case NC_REQUEST_TCP_ECHO:            test_printf("TCP echo - %d buffers, %d bytes\n", ntohl(req.nbufs), ntohl(req.buflen));            break;#ifdef __ECOS        case NC_REQUEST_SET_LOAD:            start_load(ntohl(req.nbufs));            break;        case NC_REQUEST_START_IDLE:            test_printf("Start IDLE thread\n");            idle_thread_count = 0;            idle_thread_start_time = cyg_current_time();            cyg_semaphore_post(&idle_thread_sem);            break;        case NC_REQUEST_STOP_IDLE:            cyg_semaphore_wait(&idle_thread_sem);            idle_thread_stop_time = cyg_current_time();            test_printf("Stop IDLE thread\n");            reply.misc.idle_results.elapsed_time = htonl(idle_thread_stop_time - idle_thread_start_time);            reply.misc.idle_results.count[0] = htonl(idle_thread_count >> 32);            reply.misc.idle_results.count[1] = htonl((long)idle_thread_count);            break;#endif        default:            test_printf("Unrecognized request: %d\n", ntohl(req.type));            reply.response = htonl(NC_REPLY_NAK);            reply.reason = htonl(NC_REPLY_NAK_UNKNOWN_REQUEST);            break;        }        if (sendto(s, &reply, sizeof(reply), 0, (struct sockaddr *)&master, masterlen) < 0) {            pexit("sendto");        }        if (reply.response == ntohl(NC_REPLY_NAK)) {            continue;        }        switch (ntohl(req.type)) {        case NC_REQUEST_UDP_SEND:        case NC_REQUEST_UDP_RECV:        case NC_REQUEST_UDP_ECHO:            do_udp_test(s, &req, (struct sockaddr *)&master);            break;        case NC_REQUEST_TCP_SEND:        case NC_REQUEST_TCP_RECV:        case NC_REQUEST_TCP_ECHO:            do_tcp_test(s, &req, (struct sockaddr *)&master);            break;        case NC_REQUEST_START_IDLE:        case NC_REQUEST_STOP_IDLE:        case NC_REQUEST_SET_LOAD:        default:            break;        }//        cyg_kmem_print_stats();    }}voidnet_test(test_param_t param){//    int i;    if (param == 0) {        test_printf("Start Network Characterization - SLAVE\n");#ifdef __ECOS        init_all_network_interfaces();        calibrate_load(DESIRED_BACKGROUND_LOAD);#if 0// I can see what this is trying to do, but I get "bind: Address already in// use" errors from the 2nd interface - and the parameter is not used// anyway, so one thread does quite well enough (but only tests one i/f at// once).// Comment in the 'int i' above too.        for (i = 1;  i < CYGHWR_NET_DRIVERS;  i++) {            cyg_thread_resume(main_thread_handle[i]);   // Start other threads        }#endif#endif    }    nc_slave(param);#ifdef CYGDBG_NET_TIMING_STATS    show_net_times();#endif    cyg_test_exit();}#ifdef __ECOS//// This function is called to calibrate the "background load" which can be// applied during testing.  It will be called before any commands from the// host are managed.//static voidcalibrate_load(int desired_load){    long long no_load_idle, load_idle;    int percent_load;    int high, low;    // Set limits    high = MAX_LOAD_THREAD_LEVEL;    low = MIN_LOAD_THREAD_LEVEL;    // Compute the "no load" idle value    idle_thread_count = 0;    cyg_semaphore_post(&idle_thread_sem);  // Start idle thread    cyg_thread_delay(1*100);               // Pause for one second    cyg_semaphore_wait(&idle_thread_sem);  // Stop idle thread    no_load_idle = idle_thread_count;    diag_printf("No load = %d\n", (int)idle_thread_count);    // First ensure that the HIGH level is indeed higher    while (true) {        load_thread_level = high;        start_load(desired_load);              // Start up a given load        idle_thread_count = 0;        cyg_semaphore_post(&idle_thread_sem);  // Start idle thread        cyg_thread_delay(1*100);               // Pause for one second        cyg_semaphore_wait(&idle_thread_sem);  // Stop idle thread        load_idle = idle_thread_count;        start_load(0);                         // Shut down background load        percent_load = 100 - ((load_idle * 100) / no_load_idle);        diag_printf("High Load[%d] = %d => %d%%\n", load_thread_level,                     (int)idle_thread_count, percent_load);        if ( percent_load > desired_load )            break; // HIGH level is indeed higher        low = load_thread_level; // known to be lower        high *= 2; // else double it and try again    }    // Now chop down to the level required    while (true) {        load_thread_level = (high + low) / 2;        start_load(desired_load);              // Start up a given load        idle_thread_count = 0;        cyg_semaphore_post(&idle_thread_sem);  // Start idle thread        cyg_thread_delay(1*100);               // Pause for one second        cyg_semaphore_wait(&idle_thread_sem);  // Stop idle thread        load_idle = idle_thread_count;        start_load(0);                         // Shut down background load        percent_load = 100 - ((load_idle * 100) / no_load_idle);        diag_printf("Load[%d] = %d => %d%%\n", load_thread_level,                     (int)idle_thread_count, percent_load);        if (((high-low) <= 1) || (abs(desired_load-percent_load) <= 2)) break;        if (percent_load < desired_load) {            low = load_thread_level;        } else {                        high = load_thread_level;        }    }    // Now we are within a few percent of the target; scale the load    // factor to get a better fit, and test it, print the answer.    load_thread_level *= desired_load;    load_thread_level /= percent_load;    start_load(desired_load);              // Start up a given load    idle_thread_count = 0;    cyg_semaphore_post(&idle_thread_sem);  // Start idle thread    cyg_thread_delay(1*100);               // Pause for one second    cyg_semaphore_wait(&idle_thread_sem);  // Stop idle thread    load_idle = idle_thread_count;    start_load(0);                         // Shut down background load    percent_load = 100 - ((load_idle * 100) / no_load_idle);    diag_printf("Final load[%d] = %d => %d%%\n", load_thread_level,                 (int)idle_thread_count, percent_load);//    no_load_idle_count_1_second = no_load_idle;}//// This function is called to set up a load level of 'load' percent (given// as a whole number, e.g. start_load(20) would mean initiate a background// load of 20%, leaving the cpu 80% idle).//static voidstart_load(int load){    static int prev_load = 0;    int i;    test_printf("Set background load = %d%%\n", load);    if (load == 0) {        if (prev_load == 0) return;  // Nothing out there to stop        for (i = 0;  i < prev_load/10;  i++) {            cyg_semaphore_wait(&load_thread_sem[i]);        }        prev_load = 0;    } else {        for (i = 0;  i < load/10;  i++) {            cyg_semaphore_post(&load_thread_sem[i]);        }        prev_load = load;    }}//// These thread(s) do some amount of "background" computing.  This is used// to simulate a given load level.  They need to be run at a higher priority // than the network code itself.//// Like the "idle" thread, they run as long as their "switch" (aka semaphore)// is enabled.//voidnet_load(cyg_addrword_t who){    int i;    while (true) {        cyg_semaphore_wait(&load_thread_sem[who]);        for (i = 0;  i < load_thread_level;  i++) {            do_some_random_computation(i);        }        cyg_thread_delay(1);  // Wait until the next 'tick'        cyg_semaphore_post(&load_thread_sem[who]);    }}//// Some arbitrary computation, designed to use up the CPU and cause associated// cache "thrash" behaviour - part of background load modelling.//static voiddo_some_random_computation(int p){    // Just something that might be "hard"    volatile double x;    x = ((p * 10) * 3.14159) / 180.0;  // radians}//// This thread does nothing but count.  It will be allowed to count// as long as the semaphore is "free".  //voidnet_idle(cyg_addrword_t param){    while (true) {        cyg_semaphore_wait(&idle_thread_sem);        idle_thread_count++;        cyg_semaphore_post(&idle_thread_sem);    }}voidcyg_start(void){    int i;    // Create processing threads    for (i = 0;  i < CYGHWR_NET_DRIVERS;  i++) {        cyg_thread_create(MAIN_THREAD_PRIORITY,     // Priority                          net_test,                 // entry                          i,                        // entry parameter                          "Network test",           // Name                          &main_thread_stack[i][0], // Stack                          STACK_SIZE,               // Size                          &main_thread_handle[i],   // Handle                          &main_thread_data[i]      // Thread data structure            );    }    cyg_thread_resume(main_thread_handle[0]);   // Start first one    // Create the idle thread environment    cyg_semaphore_init(&idle_thread_sem, 0);    cyg_thread_create(IDLE_THREAD_PRIORITY,     // Priority                      net_idle,                 // entry                      0,                        // entry parameter                      "Network idle",           // Name                      &idle_thread_stack[0],    // Stack                      STACK_SIZE,               // Size                      &idle_thread_handle,      // Handle                      &idle_thread_data         // Thread data structure            );    cyg_thread_resume(idle_thread_handle);      // Start it    // Create the load threads and their environment(s)    for (i = 0;  i < NUM_LOAD_THREADS;  i++) {        cyg_semaphore_init(&load_thread_sem[i], 0);        cyg_thread_create(LOAD_THREAD_PRIORITY,     // Priority                          net_load,                 // entry                          i,                        // entry parameter                          "Background load",        // Name                          &load_thread_stack[i][0], // Stack                          STACK_SIZE,               // Size                          &load_thread_handle[i],   // Handle                          &load_thread_data[i]      // Thread data structure            );        cyg_thread_resume(load_thread_handle[i]);   // Start it    }    cyg_scheduler_start();}#elseint main(int argc, char *argv[]){    net_test(0);}#endif

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?