176404edcSAsim Jamshed #include <stdio.h> 276404edcSAsim Jamshed #include <stdlib.h> 376404edcSAsim Jamshed #include <string.h> 476404edcSAsim Jamshed #include <unistd.h> 576404edcSAsim Jamshed #include <stdint.h> 676404edcSAsim Jamshed #include <time.h> 776404edcSAsim Jamshed #include <sys/time.h> 876404edcSAsim Jamshed #include <sys/types.h> 976404edcSAsim Jamshed #include <sys/stat.h> 1076404edcSAsim Jamshed #include <fcntl.h> 1176404edcSAsim Jamshed #include <pthread.h> 1276404edcSAsim Jamshed #include <signal.h> 1376404edcSAsim Jamshed #include <sys/socket.h> 1476404edcSAsim Jamshed #include <netinet/in.h> 1576404edcSAsim Jamshed #include <arpa/inet.h> 1676404edcSAsim Jamshed #include <sys/queue.h> 1776404edcSAsim Jamshed #include <assert.h> 1876404edcSAsim Jamshed 1976404edcSAsim Jamshed #include <mos_api.h> 2076404edcSAsim Jamshed #include "cpu.h" 2176404edcSAsim Jamshed #include "rss.h" 2276404edcSAsim Jamshed #include "http_parsing.h" 2376404edcSAsim Jamshed #include "debug.h" 2476404edcSAsim Jamshed #include "applib.h" 2576404edcSAsim Jamshed 2676404edcSAsim Jamshed #define CONFIG_FILE "config/epwget.conf" 2776404edcSAsim Jamshed static struct conf_var g_conf[] = { 2876404edcSAsim Jamshed { "url", {0} }, 2976404edcSAsim Jamshed { "total_flows", {0} }, 3076404edcSAsim Jamshed { "core_limit", {0} }, 3176404edcSAsim Jamshed { "total_concurrency", {0} }, 3276404edcSAsim Jamshed { "dest_port", {0} }, 3376404edcSAsim Jamshed }; 3476404edcSAsim Jamshed #define NUM_CONF_VAR (sizeof(g_conf) / sizeof(struct conf_var)) 3576404edcSAsim Jamshed 3676404edcSAsim Jamshed #define PORT_NUM 80 3776404edcSAsim Jamshed //#define PORT_NUM 3333 3876404edcSAsim Jamshed 3976404edcSAsim Jamshed #define MAX_URL_LEN 128 4076404edcSAsim Jamshed #define MAX_FILE_LEN 128 4176404edcSAsim Jamshed #define HTTP_HEADER_LEN 1024 4276404edcSAsim Jamshed 4376404edcSAsim Jamshed #define IP_RANGE 1 4476404edcSAsim Jamshed #define MAX_IP_STR_LEN 16 4576404edcSAsim Jamshed 4676404edcSAsim Jamshed #define BUF_SIZE (8*1024) 4776404edcSAsim Jamshed 4876404edcSAsim Jamshed /*----------------------------------------------------------------------------*/ 4976404edcSAsim Jamshed struct mtcp_conf g_mcfg; 5076404edcSAsim Jamshed static pthread_t mtcp_thread[MAX_CPUS]; 5176404edcSAsim Jamshed /*----------------------------------------------------------------------------*/ 5276404edcSAsim Jamshed static mctx_t g_mctx[MAX_CPUS]; 5376404edcSAsim Jamshed static int done[MAX_CPUS]; 5476404edcSAsim Jamshed /*----------------------------------------------------------------------------*/ 5576404edcSAsim Jamshed static int num_cores; 5676404edcSAsim Jamshed static int core_limit; 5776404edcSAsim Jamshed /*----------------------------------------------------------------------------*/ 5876404edcSAsim Jamshed static int fio = FALSE; 5976404edcSAsim Jamshed static char outfile[MAX_FILE_LEN + 1]; 6076404edcSAsim Jamshed /*----------------------------------------------------------------------------*/ 6176404edcSAsim Jamshed static char host[MAX_IP_STR_LEN + 1]; 6276404edcSAsim Jamshed static char path[MAX_URL_LEN + 1]; 6376404edcSAsim Jamshed static in_addr_t daddr; 6476404edcSAsim Jamshed static in_port_t dport; 6576404edcSAsim Jamshed static in_addr_t saddr; 6676404edcSAsim Jamshed /*----------------------------------------------------------------------------*/ 6776404edcSAsim Jamshed static int total_flows; 6876404edcSAsim Jamshed static int flows[MAX_CPUS]; 6976404edcSAsim Jamshed static int flowcnt = 0; 7076404edcSAsim Jamshed static int concurrency; 7176404edcSAsim Jamshed static int max_fds; 7276404edcSAsim Jamshed static uint16_t dest_port; 7376404edcSAsim Jamshed /*----------------------------------------------------------------------------*/ 7476404edcSAsim Jamshed struct wget_stat 7576404edcSAsim Jamshed { 7676404edcSAsim Jamshed uint64_t waits; 7776404edcSAsim Jamshed uint64_t events; 7876404edcSAsim Jamshed uint64_t connects; 7976404edcSAsim Jamshed uint64_t reads; 8076404edcSAsim Jamshed uint64_t writes; 8176404edcSAsim Jamshed uint64_t completes; 8276404edcSAsim Jamshed 8376404edcSAsim Jamshed uint64_t errors; 8476404edcSAsim Jamshed uint64_t timedout; 8576404edcSAsim Jamshed 8676404edcSAsim Jamshed uint64_t sum_resp_time; 8776404edcSAsim Jamshed uint64_t max_resp_time; 8876404edcSAsim Jamshed }; 8976404edcSAsim Jamshed /*----------------------------------------------------------------------------*/ 9076404edcSAsim Jamshed struct thread_context 9176404edcSAsim Jamshed { 9276404edcSAsim Jamshed int core; 9376404edcSAsim Jamshed 9476404edcSAsim Jamshed mctx_t mctx; 9576404edcSAsim Jamshed int ep; 9676404edcSAsim Jamshed struct wget_vars *wvars; 9776404edcSAsim Jamshed 9876404edcSAsim Jamshed int target; 9976404edcSAsim Jamshed int started; 10076404edcSAsim Jamshed int errors; 10176404edcSAsim Jamshed int incompletes; 10276404edcSAsim Jamshed int done; 10376404edcSAsim Jamshed int pending; 10476404edcSAsim Jamshed 10576404edcSAsim Jamshed int maxevents; 10676404edcSAsim Jamshed struct mtcp_epoll_event *events; 10776404edcSAsim Jamshed 10876404edcSAsim Jamshed struct wget_stat stat; 10976404edcSAsim Jamshed }; 11076404edcSAsim Jamshed typedef struct thread_context* thread_context_t; 11176404edcSAsim Jamshed /*----------------------------------------------------------------------------*/ 11276404edcSAsim Jamshed struct wget_vars 11376404edcSAsim Jamshed { 11476404edcSAsim Jamshed int request_sent; 11576404edcSAsim Jamshed 11676404edcSAsim Jamshed char response[HTTP_HEADER_LEN]; 11776404edcSAsim Jamshed int resp_len; 11876404edcSAsim Jamshed int headerset; 11976404edcSAsim Jamshed uint32_t header_len; 12076404edcSAsim Jamshed uint64_t file_len; 12176404edcSAsim Jamshed uint64_t recv; 12276404edcSAsim Jamshed uint64_t write; 12376404edcSAsim Jamshed 12476404edcSAsim Jamshed struct timeval t_start; 12576404edcSAsim Jamshed struct timeval t_end; 12676404edcSAsim Jamshed 12776404edcSAsim Jamshed int fd; 12876404edcSAsim Jamshed }; 12976404edcSAsim Jamshed /*----------------------------------------------------------------------------*/ 13076404edcSAsim Jamshed static struct thread_context *g_ctx[MAX_CPUS]; 13176404edcSAsim Jamshed static struct wget_stat *g_stat[MAX_CPUS]; 13276404edcSAsim Jamshed /*----------------------------------------------------------------------------*/ 13376404edcSAsim Jamshed static thread_context_t 13476404edcSAsim Jamshed CreateContext(mctx_t mctx) 13576404edcSAsim Jamshed { 13676404edcSAsim Jamshed thread_context_t ctx; 13776404edcSAsim Jamshed 13876404edcSAsim Jamshed ctx = (thread_context_t)calloc(1, sizeof(struct thread_context)); 13976404edcSAsim Jamshed if (!ctx) { 14076404edcSAsim Jamshed perror("malloc"); 14176404edcSAsim Jamshed TRACE_ERROR("Failed to allocate memory for thread context.\n"); 14276404edcSAsim Jamshed return NULL; 14376404edcSAsim Jamshed } 14476404edcSAsim Jamshed 14576404edcSAsim Jamshed ctx->mctx = mctx; 14676404edcSAsim Jamshed ctx->core = mctx->cpu; 14776404edcSAsim Jamshed 14876404edcSAsim Jamshed g_mctx[ctx->core] = mctx; 14976404edcSAsim Jamshed 15076404edcSAsim Jamshed return ctx; 15176404edcSAsim Jamshed } 15276404edcSAsim Jamshed /*----------------------------------------------------------------------------*/ 15376404edcSAsim Jamshed static void 15476404edcSAsim Jamshed DestroyContext(thread_context_t ctx) 15576404edcSAsim Jamshed { 15676404edcSAsim Jamshed free(ctx); 15776404edcSAsim Jamshed } 15876404edcSAsim Jamshed /*----------------------------------------------------------------------------*/ 15976404edcSAsim Jamshed static inline int 16076404edcSAsim Jamshed CreateConnection(thread_context_t ctx) 16176404edcSAsim Jamshed { 16276404edcSAsim Jamshed mctx_t mctx = ctx->mctx; 16376404edcSAsim Jamshed struct mtcp_epoll_event ev; 16476404edcSAsim Jamshed struct sockaddr_in addr; 16576404edcSAsim Jamshed int sockid; 16676404edcSAsim Jamshed int ret; 16776404edcSAsim Jamshed 16876404edcSAsim Jamshed assert(mctx); 16976404edcSAsim Jamshed 17076404edcSAsim Jamshed errno = 0; 17176404edcSAsim Jamshed sockid = mtcp_socket(mctx, AF_INET, SOCK_STREAM, 0); 17276404edcSAsim Jamshed if (sockid < 0) { 17376404edcSAsim Jamshed TRACE_INFO("Failed to create socket! (%s)\n", 17476404edcSAsim Jamshed strerror(errno)); 17576404edcSAsim Jamshed return -1; 17676404edcSAsim Jamshed } 17776404edcSAsim Jamshed memset(&ctx->wvars[sockid], 0, sizeof(struct wget_vars)); 17876404edcSAsim Jamshed ret = mtcp_setsock_nonblock(mctx, sockid); 17976404edcSAsim Jamshed if (ret < 0) { 18076404edcSAsim Jamshed TRACE_ERROR("Failed to set socket in nonblocking mode.\n"); 18176404edcSAsim Jamshed exit(-1); 18276404edcSAsim Jamshed } 18376404edcSAsim Jamshed 18476404edcSAsim Jamshed addr.sin_family = AF_INET; 18576404edcSAsim Jamshed addr.sin_addr.s_addr = daddr; 18676404edcSAsim Jamshed addr.sin_port = dport; 18776404edcSAsim Jamshed 18876404edcSAsim Jamshed ret = mtcp_connect(mctx, sockid, 18976404edcSAsim Jamshed (struct sockaddr *)&addr, sizeof(struct sockaddr_in)); 19076404edcSAsim Jamshed if (ret < 0) { 19176404edcSAsim Jamshed if (errno != EINPROGRESS) { 19276404edcSAsim Jamshed perror("mtcp_connect"); 19376404edcSAsim Jamshed mtcp_close(mctx, sockid); 19476404edcSAsim Jamshed return -1; 19576404edcSAsim Jamshed } 19676404edcSAsim Jamshed } 19776404edcSAsim Jamshed 19876404edcSAsim Jamshed ctx->started++; 19976404edcSAsim Jamshed ctx->pending++; 20076404edcSAsim Jamshed ctx->stat.connects++; 20176404edcSAsim Jamshed 20276404edcSAsim Jamshed ev.events = MOS_EPOLLOUT; 20376404edcSAsim Jamshed ev.data.sock = sockid; 20476404edcSAsim Jamshed mtcp_epoll_ctl(mctx, ctx->ep, MOS_EPOLL_CTL_ADD, sockid, &ev); 20576404edcSAsim Jamshed 20676404edcSAsim Jamshed return sockid; 20776404edcSAsim Jamshed } 20876404edcSAsim Jamshed /*----------------------------------------------------------------------------*/ 20976404edcSAsim Jamshed static inline void 21076404edcSAsim Jamshed CloseConnection(thread_context_t ctx, int sockid) 21176404edcSAsim Jamshed { 21276404edcSAsim Jamshed mtcp_epoll_ctl(ctx->mctx, ctx->ep, MOS_EPOLL_CTL_DEL, sockid, NULL); 21376404edcSAsim Jamshed mtcp_close(ctx->mctx, sockid); 21476404edcSAsim Jamshed ctx->pending--; 21576404edcSAsim Jamshed ctx->done++; 21676404edcSAsim Jamshed assert(ctx->pending >= 0); 21776404edcSAsim Jamshed while (/*ctx->pending*/ mtcp_get_connection_cnt(ctx->mctx) < concurrency && ctx->started < ctx->target) { 21876404edcSAsim Jamshed if (CreateConnection(ctx) < 0) { 21976404edcSAsim Jamshed done[ctx->core] = TRUE; 22076404edcSAsim Jamshed break; 22176404edcSAsim Jamshed } 22276404edcSAsim Jamshed } 22376404edcSAsim Jamshed } 22476404edcSAsim Jamshed /*----------------------------------------------------------------------------*/ 22576404edcSAsim Jamshed static inline int 22676404edcSAsim Jamshed SendHTTPRequest(thread_context_t ctx, int sockid, struct wget_vars *wv) 22776404edcSAsim Jamshed { 22876404edcSAsim Jamshed char request[HTTP_HEADER_LEN]; 22976404edcSAsim Jamshed struct mtcp_epoll_event ev; 23076404edcSAsim Jamshed int wr; 23176404edcSAsim Jamshed int len; 23276404edcSAsim Jamshed 23376404edcSAsim Jamshed wv->headerset = FALSE; 23476404edcSAsim Jamshed wv->recv = 0; 23576404edcSAsim Jamshed wv->header_len = wv->file_len = 0; 23676404edcSAsim Jamshed 23776404edcSAsim Jamshed snprintf(request, HTTP_HEADER_LEN, "GET %s HTTP/1.0\r\n" 23876404edcSAsim Jamshed "User-Agent: Wget/1.12 (linux-gnu)\r\n" 23976404edcSAsim Jamshed "Accept: */*\r\n" 24076404edcSAsim Jamshed "Host: %s\r\n" 24176404edcSAsim Jamshed // "Connection: Keep-Alive\r\n\r\n", 24276404edcSAsim Jamshed "Connection: Close\r\n\r\n", 24376404edcSAsim Jamshed path, host); 24476404edcSAsim Jamshed len = strlen(request); 24576404edcSAsim Jamshed 24676404edcSAsim Jamshed wr = mtcp_write(ctx->mctx, sockid, request, len); 24776404edcSAsim Jamshed if (wr < len) { 24876404edcSAsim Jamshed TRACE_ERROR("Socket %d: Sending HTTP request failed. " 24976404edcSAsim Jamshed "try: %d, sent: %d\n", sockid, len, wr); 25076404edcSAsim Jamshed CloseConnection(ctx, sockid); 25176404edcSAsim Jamshed } 25276404edcSAsim Jamshed ctx->stat.writes += wr; 25376404edcSAsim Jamshed TRACE_APP("Socket %d HTTP Request of %d bytes. sent.\n", sockid, wr); 25476404edcSAsim Jamshed wv->request_sent = TRUE; 25576404edcSAsim Jamshed 25676404edcSAsim Jamshed ev.events = MOS_EPOLLIN; 25776404edcSAsim Jamshed ev.data.sock = sockid; 25876404edcSAsim Jamshed mtcp_epoll_ctl(ctx->mctx, ctx->ep, MOS_EPOLL_CTL_MOD, sockid, &ev); 25976404edcSAsim Jamshed 26076404edcSAsim Jamshed gettimeofday(&wv->t_start, NULL); 26176404edcSAsim Jamshed 26276404edcSAsim Jamshed char fname[MAX_FILE_LEN + 1]; 26376404edcSAsim Jamshed if (fio) { 26476404edcSAsim Jamshed snprintf(fname, MAX_FILE_LEN, "%s.%d", outfile, flowcnt++); 26576404edcSAsim Jamshed wv->fd = open(fname, O_WRONLY | O_CREAT | O_TRUNC, 0644); 26676404edcSAsim Jamshed if (wv->fd < 0) { 26776404edcSAsim Jamshed TRACE_APP("Failed to open file descriptor for %s\n", fname); 26876404edcSAsim Jamshed exit(1); 26976404edcSAsim Jamshed } 27076404edcSAsim Jamshed } 27176404edcSAsim Jamshed 27276404edcSAsim Jamshed return 0; 27376404edcSAsim Jamshed } 27476404edcSAsim Jamshed /*----------------------------------------------------------------------------*/ 27576404edcSAsim Jamshed static inline int 27676404edcSAsim Jamshed DownloadComplete(thread_context_t ctx, int sockid, struct wget_vars *wv) 27776404edcSAsim Jamshed { 27876404edcSAsim Jamshed #ifdef APP 27976404edcSAsim Jamshed mctx_t mctx = ctx->mctx; 28076404edcSAsim Jamshed #endif 28176404edcSAsim Jamshed uint64_t tdiff; 28276404edcSAsim Jamshed 28376404edcSAsim Jamshed TRACE_APP("Socket %d File download complete!\n", sockid); 28476404edcSAsim Jamshed gettimeofday(&wv->t_end, NULL); 28576404edcSAsim Jamshed CloseConnection(ctx, sockid); 28676404edcSAsim Jamshed ctx->stat.completes++; 28776404edcSAsim Jamshed 28876404edcSAsim Jamshed if (wv->recv - wv->header_len != wv->file_len) { 28976404edcSAsim Jamshed fprintf(stderr, "Response size mismatch! " 29076404edcSAsim Jamshed "actual recved: %ld, expected to recved: %ld\n", 29176404edcSAsim Jamshed wv->recv-wv->header_len, wv->file_len); 29276404edcSAsim Jamshed } 29376404edcSAsim Jamshed 29476404edcSAsim Jamshed tdiff = (wv->t_end.tv_sec - wv->t_start.tv_sec) * 1000000 + 29576404edcSAsim Jamshed (wv->t_end.tv_usec - wv->t_start.tv_usec); 29676404edcSAsim Jamshed TRACE_APP("Socket %d Total received bytes: %lu (%luMB)\n", 29776404edcSAsim Jamshed sockid, wv->recv, wv->recv / 1000000); 29876404edcSAsim Jamshed TRACE_APP("Socket %d Total spent time: %lu us\n", sockid, tdiff); 29976404edcSAsim Jamshed if (tdiff > 0) { 30076404edcSAsim Jamshed TRACE_APP("Socket %d Average bandwidth: %lf[MB/s]\n", 30176404edcSAsim Jamshed sockid, (double)wv->recv / tdiff); 30276404edcSAsim Jamshed } 30376404edcSAsim Jamshed ctx->stat.sum_resp_time += tdiff; 30476404edcSAsim Jamshed if (tdiff > ctx->stat.max_resp_time) 30576404edcSAsim Jamshed ctx->stat.max_resp_time = tdiff; 30676404edcSAsim Jamshed 30776404edcSAsim Jamshed if (fio && wv->fd > 0) 30876404edcSAsim Jamshed close(wv->fd); 30976404edcSAsim Jamshed 31076404edcSAsim Jamshed return 0; 31176404edcSAsim Jamshed } 31276404edcSAsim Jamshed /*----------------------------------------------------------------------------*/ 31376404edcSAsim Jamshed static inline int 31476404edcSAsim Jamshed HandleReadEvent(thread_context_t ctx, int sockid, struct wget_vars *wv) 31576404edcSAsim Jamshed { 31676404edcSAsim Jamshed mctx_t mctx = ctx->mctx; 31776404edcSAsim Jamshed char buf[BUF_SIZE]; 31876404edcSAsim Jamshed char *pbuf; 31976404edcSAsim Jamshed int rd, copy_len; 32076404edcSAsim Jamshed 32176404edcSAsim Jamshed rd = 1; 32276404edcSAsim Jamshed while (rd > 0) { 32376404edcSAsim Jamshed rd = mtcp_read(mctx, sockid, buf, BUF_SIZE); 32476404edcSAsim Jamshed if (rd <= 0) 32576404edcSAsim Jamshed break; 32676404edcSAsim Jamshed ctx->stat.reads += rd; 32776404edcSAsim Jamshed 32876404edcSAsim Jamshed TRACE_APP("Socket %d: mtcp_read ret: %d, total_recv: %lu, " 32976404edcSAsim Jamshed "header_set: %d, header_len: %u, file_len: %lu\n", 33076404edcSAsim Jamshed sockid, rd, wv->recv + rd, 33176404edcSAsim Jamshed wv->headerset, wv->header_len, wv->file_len); 33276404edcSAsim Jamshed 33376404edcSAsim Jamshed pbuf = buf; 33476404edcSAsim Jamshed if (!wv->headerset) { 33576404edcSAsim Jamshed copy_len = MIN(rd, HTTP_HEADER_LEN - wv->resp_len); 33676404edcSAsim Jamshed memcpy(wv->response + wv->resp_len, buf, copy_len); 33776404edcSAsim Jamshed wv->resp_len += copy_len; 33876404edcSAsim Jamshed wv->header_len = find_http_header(wv->response, wv->resp_len); 33976404edcSAsim Jamshed if (wv->header_len > 0) { 34076404edcSAsim Jamshed wv->response[wv->header_len] = '\0'; 34176404edcSAsim Jamshed wv->file_len = http_header_long_val(wv->response, 34276404edcSAsim Jamshed CONTENT_LENGTH_HDR, sizeof(CONTENT_LENGTH_HDR) - 1); 34376404edcSAsim Jamshed TRACE_APP("Socket %d Parsed response header. " 34476404edcSAsim Jamshed "Header length: %u, File length: %lu (%luMB)\n", 34576404edcSAsim Jamshed sockid, wv->header_len, 34676404edcSAsim Jamshed wv->file_len, wv->file_len / 1024 / 1024); 34776404edcSAsim Jamshed wv->headerset = TRUE; 34876404edcSAsim Jamshed wv->recv += (rd - (wv->resp_len - wv->header_len)); 34976404edcSAsim Jamshed 35076404edcSAsim Jamshed pbuf += (rd - (wv->resp_len - wv->header_len)); 351*d8823779SAsim Jamshed rd = (wv->resp_len - wv->header_len); 35276404edcSAsim Jamshed 35376404edcSAsim Jamshed } else { 35476404edcSAsim Jamshed /* failed to parse response header */ 35576404edcSAsim Jamshed wv->recv += rd; 35676404edcSAsim Jamshed rd = 0; 35776404edcSAsim Jamshed ctx->stat.errors++; 35876404edcSAsim Jamshed ctx->errors++; 35976404edcSAsim Jamshed CloseConnection(ctx, sockid); 36076404edcSAsim Jamshed return 0; 36176404edcSAsim Jamshed } 36276404edcSAsim Jamshed } 36376404edcSAsim Jamshed wv->recv += rd; 36476404edcSAsim Jamshed 36576404edcSAsim Jamshed if (fio && wv->fd > 0) { 36676404edcSAsim Jamshed int wr = 0; 36776404edcSAsim Jamshed while (wr < rd) { 36876404edcSAsim Jamshed int _wr = write(wv->fd, pbuf + wr, rd - wr); 36976404edcSAsim Jamshed assert (_wr == rd - wr); 37076404edcSAsim Jamshed if (_wr < 0) { 37176404edcSAsim Jamshed perror("write"); 37276404edcSAsim Jamshed TRACE_ERROR("Failed to write.\n"); 37376404edcSAsim Jamshed assert(0); 37476404edcSAsim Jamshed break; 37576404edcSAsim Jamshed } 37676404edcSAsim Jamshed wr += _wr; 37776404edcSAsim Jamshed wv->write += _wr; 37876404edcSAsim Jamshed } 37976404edcSAsim Jamshed } 38076404edcSAsim Jamshed 38176404edcSAsim Jamshed if (wv->header_len && (wv->recv >= wv->header_len + wv->file_len)) { 38276404edcSAsim Jamshed break; 38376404edcSAsim Jamshed } 38476404edcSAsim Jamshed } 38576404edcSAsim Jamshed 38676404edcSAsim Jamshed if (rd > 0) { 38776404edcSAsim Jamshed if (wv->header_len && (wv->recv >= wv->header_len + wv->file_len)) { 38876404edcSAsim Jamshed TRACE_APP("Socket %d Done Write: " 38976404edcSAsim Jamshed "header: %u file: %lu recv: %lu write: %lu\n", 39076404edcSAsim Jamshed sockid, wv->header_len, wv->file_len, 39176404edcSAsim Jamshed wv->recv - wv->header_len, wv->write); 39276404edcSAsim Jamshed DownloadComplete(ctx, sockid, wv); 39376404edcSAsim Jamshed 39476404edcSAsim Jamshed return 0; 39576404edcSAsim Jamshed } 39676404edcSAsim Jamshed 39776404edcSAsim Jamshed } else if (rd == 0) { 39876404edcSAsim Jamshed /* connection closed by remote host */ 39976404edcSAsim Jamshed TRACE_DBG("Socket %d connection closed with server.\n", sockid); 40076404edcSAsim Jamshed 40176404edcSAsim Jamshed if (wv->header_len && (wv->recv >= wv->header_len + wv->file_len)) { 40276404edcSAsim Jamshed DownloadComplete(ctx, sockid, wv); 40376404edcSAsim Jamshed } else { 40476404edcSAsim Jamshed ctx->stat.errors++; 40576404edcSAsim Jamshed ctx->incompletes++; 40676404edcSAsim Jamshed CloseConnection(ctx, sockid); 40776404edcSAsim Jamshed } 40876404edcSAsim Jamshed 40976404edcSAsim Jamshed } else if (rd < 0) { 41076404edcSAsim Jamshed if (errno != EAGAIN) { 41176404edcSAsim Jamshed TRACE_DBG("Socket %d: mtcp_read() error %s\n", 41276404edcSAsim Jamshed sockid, strerror(errno)); 41376404edcSAsim Jamshed ctx->stat.errors++; 41476404edcSAsim Jamshed ctx->errors++; 41576404edcSAsim Jamshed CloseConnection(ctx, sockid); 41676404edcSAsim Jamshed } 41776404edcSAsim Jamshed } 41876404edcSAsim Jamshed 41976404edcSAsim Jamshed return 0; 42076404edcSAsim Jamshed } 42176404edcSAsim Jamshed /*----------------------------------------------------------------------------*/ 42276404edcSAsim Jamshed static void 42376404edcSAsim Jamshed PrintStats() 42476404edcSAsim Jamshed { 42576404edcSAsim Jamshed struct wget_stat total = {0}; 42676404edcSAsim Jamshed struct wget_stat *st; 42776404edcSAsim Jamshed uint64_t avg_resp_time; 42876404edcSAsim Jamshed uint64_t total_resp_time = 0; 42976404edcSAsim Jamshed int i; 43076404edcSAsim Jamshed 43176404edcSAsim Jamshed for (i = 0; i < core_limit; i++) { 43276404edcSAsim Jamshed st = g_stat[i]; 43376404edcSAsim Jamshed if (!st) 43476404edcSAsim Jamshed continue; 43576404edcSAsim Jamshed avg_resp_time = st->completes? st->sum_resp_time / st->completes : 0; 43676404edcSAsim Jamshed 43776404edcSAsim Jamshed total.waits += st->waits; 43876404edcSAsim Jamshed total.events += st->events; 43976404edcSAsim Jamshed total.connects += st->connects; 44076404edcSAsim Jamshed total.reads += st->reads; 44176404edcSAsim Jamshed total.writes += st->writes; 44276404edcSAsim Jamshed total.completes += st->completes; 44376404edcSAsim Jamshed total_resp_time += avg_resp_time; 44476404edcSAsim Jamshed if (st->max_resp_time > total.max_resp_time) 44576404edcSAsim Jamshed total.max_resp_time = st->max_resp_time; 44676404edcSAsim Jamshed total.errors += st->errors; 44776404edcSAsim Jamshed total.timedout += st->timedout; 44876404edcSAsim Jamshed 44976404edcSAsim Jamshed memset(st, 0, sizeof(struct wget_stat)); 45076404edcSAsim Jamshed } 45176404edcSAsim Jamshed fprintf(stderr, "[ ALL ] connect: %7lu, read: %4lu MB, write: %4lu MB, " 45276404edcSAsim Jamshed "completes: %7lu (resp_time avg: %4lu, max: %6lu us)\n", 45376404edcSAsim Jamshed total.connects, 454e160edcaSAsim Jamshed total.reads / 1024 / 1024, total.writes / 1024 / 1024, 45576404edcSAsim Jamshed total.completes, total_resp_time / core_limit, total.max_resp_time); 45676404edcSAsim Jamshed } 45776404edcSAsim Jamshed /*----------------------------------------------------------------------------*/ 45876404edcSAsim Jamshed static void 45976404edcSAsim Jamshed GlbInitWget() 46076404edcSAsim Jamshed { 46176404edcSAsim Jamshed struct mtcp_conf mcfg; 46276404edcSAsim Jamshed char *url; 46376404edcSAsim Jamshed int total_concurrency = 0; 46476404edcSAsim Jamshed int flow_per_thread; 46576404edcSAsim Jamshed int flow_remainder_cnt; 46676404edcSAsim Jamshed int i; 46776404edcSAsim Jamshed 46876404edcSAsim Jamshed num_cores = GetNumCPUs(); 46976404edcSAsim Jamshed core_limit = num_cores; 47076404edcSAsim Jamshed concurrency = 100; 47176404edcSAsim Jamshed total_flows = -1; 47276404edcSAsim Jamshed 47376404edcSAsim Jamshed LoadConfig(CONFIG_FILE, g_conf, NUM_CONF_VAR); 47476404edcSAsim Jamshed 47576404edcSAsim Jamshed url = g_conf[0].value; 47676404edcSAsim Jamshed total_flows = atoi(g_conf[1].value); 47776404edcSAsim Jamshed core_limit = atoi(g_conf[2].value); 47876404edcSAsim Jamshed total_concurrency = atoi(g_conf[3].value); 47976404edcSAsim Jamshed dest_port = atoi(g_conf[4].value); 48076404edcSAsim Jamshed 48176404edcSAsim Jamshed if ((strlen(url) == 0) 48276404edcSAsim Jamshed || (strlen(url) > MAX_URL_LEN) 48376404edcSAsim Jamshed || (total_flows <= 0)) { 48476404edcSAsim Jamshed TRACE_INFO("Invalid configuration\n"); 48576404edcSAsim Jamshed exit(0); 48676404edcSAsim Jamshed } 48776404edcSAsim Jamshed 48876404edcSAsim Jamshed char* slash_p = strchr(url, '/'); 48976404edcSAsim Jamshed if (slash_p) { 49076404edcSAsim Jamshed strncpy(host, url, slash_p - url); 49176404edcSAsim Jamshed strncpy(path, strchr(url, '/'), MAX_URL_LEN); 49276404edcSAsim Jamshed } else { 49376404edcSAsim Jamshed strncpy(host, url, MAX_IP_STR_LEN); 49476404edcSAsim Jamshed strncpy(path, "/", 1); 49576404edcSAsim Jamshed } 49676404edcSAsim Jamshed 49776404edcSAsim Jamshed daddr = inet_addr(host); 49876404edcSAsim Jamshed dport = (dest_port == 0) ? htons(PORT_NUM) : htons(dest_port); 49976404edcSAsim Jamshed saddr = INADDR_ANY; 50076404edcSAsim Jamshed 50176404edcSAsim Jamshed if (total_flows < core_limit) { 50276404edcSAsim Jamshed core_limit = total_flows; 50376404edcSAsim Jamshed } 50476404edcSAsim Jamshed 50576404edcSAsim Jamshed /* per-core concurrency = total_concurrency / # cores */ 50676404edcSAsim Jamshed if (total_concurrency > 0) 50776404edcSAsim Jamshed concurrency = total_concurrency / core_limit; 50876404edcSAsim Jamshed 50976404edcSAsim Jamshed /* set the max number of fds 3x larger than concurrency */ 51076404edcSAsim Jamshed max_fds = concurrency * 3; 51176404edcSAsim Jamshed 51276404edcSAsim Jamshed TRACE_CONFIG("Application configuration:\n"); 51376404edcSAsim Jamshed TRACE_CONFIG("URL: %s\n", path); 51476404edcSAsim Jamshed TRACE_CONFIG("# of total_flows: %d\n", total_flows); 51576404edcSAsim Jamshed TRACE_CONFIG("# of cores: %d\n", core_limit); 51676404edcSAsim Jamshed TRACE_CONFIG("Concurrency: %d\n", total_concurrency); 51776404edcSAsim Jamshed 51876404edcSAsim Jamshed mtcp_getconf(&mcfg); 51976404edcSAsim Jamshed mcfg.max_concurrency = max_fds; 52076404edcSAsim Jamshed mcfg.max_num_buffers = max_fds; 52176404edcSAsim Jamshed mtcp_setconf(&mcfg); 52276404edcSAsim Jamshed 52376404edcSAsim Jamshed flow_per_thread = total_flows / core_limit; 52476404edcSAsim Jamshed flow_remainder_cnt = total_flows % core_limit; 52576404edcSAsim Jamshed 52676404edcSAsim Jamshed for (i = 0; i < MAX_CPUS; i++) { 52776404edcSAsim Jamshed done[i] = FALSE; 52876404edcSAsim Jamshed flows[i] = flow_per_thread; 52976404edcSAsim Jamshed 53076404edcSAsim Jamshed if (flow_remainder_cnt-- > 0) 53176404edcSAsim Jamshed flows[i]++; 53276404edcSAsim Jamshed } 53376404edcSAsim Jamshed 53476404edcSAsim Jamshed return; 53576404edcSAsim Jamshed } 53676404edcSAsim Jamshed /*----------------------------------------------------------------------------*/ 53776404edcSAsim Jamshed static void 53876404edcSAsim Jamshed InitWget(mctx_t mctx, void **app_ctx) 53976404edcSAsim Jamshed { 54076404edcSAsim Jamshed thread_context_t ctx; 54176404edcSAsim Jamshed int ep; 54276404edcSAsim Jamshed 54376404edcSAsim Jamshed assert(mctx); 54476404edcSAsim Jamshed 54576404edcSAsim Jamshed int core = mctx->cpu; 54676404edcSAsim Jamshed 54776404edcSAsim Jamshed ctx = CreateContext(mctx); 54876404edcSAsim Jamshed if (!ctx) 54976404edcSAsim Jamshed exit(-1); 55076404edcSAsim Jamshed g_ctx[core] = ctx; 55176404edcSAsim Jamshed g_stat[core] = &ctx->stat; 55276404edcSAsim Jamshed srand(time(NULL)); 55376404edcSAsim Jamshed 55476404edcSAsim Jamshed mtcp_init_rss(mctx, saddr, IP_RANGE, daddr, dport); 55576404edcSAsim Jamshed 55676404edcSAsim Jamshed if (flows[core] == 0) { 55776404edcSAsim Jamshed TRACE_DBG("Application thread %d finished.\n", core); 55876404edcSAsim Jamshed exit(-1); 55976404edcSAsim Jamshed } 56076404edcSAsim Jamshed ctx->target = flows[core]; 56176404edcSAsim Jamshed 56276404edcSAsim Jamshed /* Initialization */ 56376404edcSAsim Jamshed ctx->maxevents = max_fds * 3; 56476404edcSAsim Jamshed ep = mtcp_epoll_create(mctx, ctx->maxevents); 56576404edcSAsim Jamshed if (ep < 0) { 56676404edcSAsim Jamshed TRACE_ERROR("Failed to create epoll struct!n"); 56776404edcSAsim Jamshed exit(EXIT_FAILURE); 56876404edcSAsim Jamshed } 56976404edcSAsim Jamshed ctx->events = (struct mtcp_epoll_event *) 57076404edcSAsim Jamshed calloc(ctx->maxevents, sizeof(struct mtcp_epoll_event)); 57176404edcSAsim Jamshed if (!ctx->events) { 57276404edcSAsim Jamshed TRACE_ERROR("Failed to allocate events!\n"); 57376404edcSAsim Jamshed exit(EXIT_FAILURE); 57476404edcSAsim Jamshed } 57576404edcSAsim Jamshed ctx->ep = ep; 57676404edcSAsim Jamshed 57776404edcSAsim Jamshed ctx->wvars = (struct wget_vars *)calloc(max_fds, sizeof(struct wget_vars)); 57876404edcSAsim Jamshed if (!ctx->wvars) { 57976404edcSAsim Jamshed TRACE_ERROR("Failed to create wget variables!\n"); 58076404edcSAsim Jamshed exit(EXIT_FAILURE); 58176404edcSAsim Jamshed } 58276404edcSAsim Jamshed 58376404edcSAsim Jamshed ctx->started = ctx->done = ctx->pending = 0; 58476404edcSAsim Jamshed ctx->errors = ctx->incompletes = 0; 58576404edcSAsim Jamshed 58676404edcSAsim Jamshed *app_ctx = ctx; 58776404edcSAsim Jamshed 58876404edcSAsim Jamshed return; 58976404edcSAsim Jamshed } 59076404edcSAsim Jamshed /*----------------------------------------------------------------------------*/ 59176404edcSAsim Jamshed static void 59276404edcSAsim Jamshed RunWget(mctx_t mctx, void **app_ctx) 59376404edcSAsim Jamshed { 59476404edcSAsim Jamshed struct in_addr daddr_in; 59576404edcSAsim Jamshed struct timeval cur_tv, prev_tv; 59676404edcSAsim Jamshed int nevents; 59776404edcSAsim Jamshed int i; 59876404edcSAsim Jamshed 59976404edcSAsim Jamshed assert(mctx); 60076404edcSAsim Jamshed assert(*app_ctx); 60176404edcSAsim Jamshed 60276404edcSAsim Jamshed thread_context_t ctx = *app_ctx; 60376404edcSAsim Jamshed int core = ctx->core; 60476404edcSAsim Jamshed 60576404edcSAsim Jamshed daddr_in.s_addr = daddr; 60676404edcSAsim Jamshed fprintf(stderr, "Thread %d handles %d flows. connecting to %s:%u\n", 60776404edcSAsim Jamshed core, flows[core], inet_ntoa(daddr_in), ntohs(dport)); 60876404edcSAsim Jamshed 60976404edcSAsim Jamshed gettimeofday(&cur_tv, NULL); 61076404edcSAsim Jamshed prev_tv = cur_tv; 61176404edcSAsim Jamshed 61276404edcSAsim Jamshed while (!done[core]) { 61376404edcSAsim Jamshed gettimeofday(&cur_tv, NULL); 61476404edcSAsim Jamshed 61576404edcSAsim Jamshed /* print statistics every second */ 61676404edcSAsim Jamshed if (core == 0 && cur_tv.tv_sec > prev_tv.tv_sec) { 61776404edcSAsim Jamshed PrintStats(); 61876404edcSAsim Jamshed prev_tv = cur_tv; 61976404edcSAsim Jamshed } 62076404edcSAsim Jamshed 62176404edcSAsim Jamshed while (/*ctx->pending*/ mtcp_get_connection_cnt(ctx->mctx) < concurrency && ctx->started < ctx->target) { 62276404edcSAsim Jamshed if (CreateConnection(ctx) < 0) { 62376404edcSAsim Jamshed done[core] = TRUE; 62476404edcSAsim Jamshed break; 62576404edcSAsim Jamshed } 62676404edcSAsim Jamshed } 62776404edcSAsim Jamshed 62876404edcSAsim Jamshed nevents = mtcp_epoll_wait(mctx, ctx->ep, 62976404edcSAsim Jamshed ctx->events, ctx->maxevents, ctx->pending ? -1 : 10); 63076404edcSAsim Jamshed ctx->stat.waits++; 63176404edcSAsim Jamshed 63276404edcSAsim Jamshed if (nevents < 0) { 63376404edcSAsim Jamshed if (errno != EINTR) { 63476404edcSAsim Jamshed TRACE_ERROR("mtcp_epoll_wait failed! ret: %d\n", nevents); 63576404edcSAsim Jamshed } 63676404edcSAsim Jamshed done[core] = TRUE; 63776404edcSAsim Jamshed break; 63876404edcSAsim Jamshed } else { 63976404edcSAsim Jamshed ctx->stat.events += nevents; 64076404edcSAsim Jamshed } 64176404edcSAsim Jamshed 64276404edcSAsim Jamshed for (i = 0; i < nevents; i++) { 64376404edcSAsim Jamshed 64476404edcSAsim Jamshed if (ctx->events[i].events & MOS_EPOLLERR) { 64576404edcSAsim Jamshed int err; 64676404edcSAsim Jamshed socklen_t len = sizeof(err); 64776404edcSAsim Jamshed 64876404edcSAsim Jamshed TRACE_APP("[CPU %d] Error on socket %d\n", 64976404edcSAsim Jamshed core, ctx->events[i].data.sockid); 65076404edcSAsim Jamshed ctx->stat.errors++; 65176404edcSAsim Jamshed ctx->errors++; 65276404edcSAsim Jamshed if (mtcp_getsockopt(mctx, ctx->events[i].data.sock, 65376404edcSAsim Jamshed SOL_SOCKET, SO_ERROR, (void *)&err, &len) == 0) { 65476404edcSAsim Jamshed if (err == ETIMEDOUT) 65576404edcSAsim Jamshed ctx->stat.timedout++; 65676404edcSAsim Jamshed } 65776404edcSAsim Jamshed CloseConnection(ctx, ctx->events[i].data.sock); 65876404edcSAsim Jamshed 65976404edcSAsim Jamshed } else if (ctx->events[i].events & MOS_EPOLLIN) { 66076404edcSAsim Jamshed HandleReadEvent(ctx, 66176404edcSAsim Jamshed ctx->events[i].data.sock, 66276404edcSAsim Jamshed &ctx->wvars[ctx->events[i].data.sock]); 66376404edcSAsim Jamshed 66476404edcSAsim Jamshed } else if (ctx->events[i].events == MOS_EPOLLOUT) { 66576404edcSAsim Jamshed struct wget_vars *wv = &ctx->wvars[ctx->events[i].data.sock]; 66676404edcSAsim Jamshed 66776404edcSAsim Jamshed if (!wv->request_sent) { 66876404edcSAsim Jamshed SendHTTPRequest(ctx, ctx->events[i].data.sock, wv); 66976404edcSAsim Jamshed } else { 67076404edcSAsim Jamshed //TRACE_DBG("Request already sent.\n"); 67176404edcSAsim Jamshed } 67276404edcSAsim Jamshed 67376404edcSAsim Jamshed } else { 67476404edcSAsim Jamshed TRACE_ERROR("Socket %d: event: %s\n", 67576404edcSAsim Jamshed ctx->events[i].data.sock, 67676404edcSAsim Jamshed EventToString(ctx->events[i].events)); 67776404edcSAsim Jamshed assert(0); 67876404edcSAsim Jamshed } 67976404edcSAsim Jamshed } 68076404edcSAsim Jamshed 68176404edcSAsim Jamshed if (ctx->done >= ctx->target) { 68276404edcSAsim Jamshed fprintf(stdout, "Completed %d connections, " 68376404edcSAsim Jamshed "errors: %d incompletes: %d\n", 68476404edcSAsim Jamshed ctx->done, ctx->errors, ctx->incompletes); 68576404edcSAsim Jamshed break; 68676404edcSAsim Jamshed } 68776404edcSAsim Jamshed } 68876404edcSAsim Jamshed 68976404edcSAsim Jamshed TRACE_INFO("Wget thread %d waiting for mtcp to be destroyed.\n", core); 69076404edcSAsim Jamshed 69176404edcSAsim Jamshed g_stat[core] = NULL; 69276404edcSAsim Jamshed g_ctx[core] = NULL; 69376404edcSAsim Jamshed DestroyContext(ctx); 69476404edcSAsim Jamshed 69576404edcSAsim Jamshed return; 69676404edcSAsim Jamshed } 69776404edcSAsim Jamshed /*----------------------------------------------------------------------------*/ 69876404edcSAsim Jamshed void 69976404edcSAsim Jamshed RunApplication(mctx_t mctx) 70076404edcSAsim Jamshed { 70176404edcSAsim Jamshed void *app_ctx; 70276404edcSAsim Jamshed 70376404edcSAsim Jamshed app_ctx = (void *)calloc(1, sizeof(void *)); 70476404edcSAsim Jamshed if (!app_ctx) { 70576404edcSAsim Jamshed TRACE_ERROR("calloc failure\n"); 70676404edcSAsim Jamshed return; 70776404edcSAsim Jamshed } 70876404edcSAsim Jamshed 70976404edcSAsim Jamshed TRACE_INFO("run application on core %d\n", mctx->cpu); 71076404edcSAsim Jamshed InitWget(mctx, &(app_ctx)); 71176404edcSAsim Jamshed RunWget(mctx, &(app_ctx)); 71276404edcSAsim Jamshed } 71376404edcSAsim Jamshed /*----------------------------------------------------------------------------*/ 71476404edcSAsim Jamshed void * 71576404edcSAsim Jamshed RunMTCP(void *arg) 71676404edcSAsim Jamshed { 71776404edcSAsim Jamshed int core = *(int *)arg; 71876404edcSAsim Jamshed mctx_t mctx; 71976404edcSAsim Jamshed 72076404edcSAsim Jamshed mtcp_core_affinitize(core); 72176404edcSAsim Jamshed 72276404edcSAsim Jamshed /* mTCP Initialization */ 72376404edcSAsim Jamshed mctx = mtcp_create_context(core); 72476404edcSAsim Jamshed if (!mctx) { 72576404edcSAsim Jamshed pthread_exit(NULL); 72676404edcSAsim Jamshed TRACE_ERROR("Failed to craete mtcp context.\n"); 72776404edcSAsim Jamshed return NULL; 72876404edcSAsim Jamshed } 72976404edcSAsim Jamshed 73076404edcSAsim Jamshed /* Run application here */ 73176404edcSAsim Jamshed RunApplication(mctx); 73276404edcSAsim Jamshed 73376404edcSAsim Jamshed /* mTCP Tear Down */ 73476404edcSAsim Jamshed mtcp_destroy_context(mctx); 73576404edcSAsim Jamshed pthread_exit(NULL); 73676404edcSAsim Jamshed 73776404edcSAsim Jamshed return NULL; 73876404edcSAsim Jamshed } 73976404edcSAsim Jamshed /*----------------------------------------------------------------------------*/ 74076404edcSAsim Jamshed int 74176404edcSAsim Jamshed main(int argc, char **argv) 74276404edcSAsim Jamshed { 74376404edcSAsim Jamshed int ret, i; 74476404edcSAsim Jamshed int cores[MAX_CPUS]; 74576404edcSAsim Jamshed char *fname = "config/mos.conf"; 74676404edcSAsim Jamshed 74776404edcSAsim Jamshed int opt; 74876404edcSAsim Jamshed while ((opt = getopt(argc, argv, "f:")) != -1) { 74976404edcSAsim Jamshed switch (opt) { 75076404edcSAsim Jamshed case 'f': 75176404edcSAsim Jamshed fname = optarg; 75276404edcSAsim Jamshed break; 75376404edcSAsim Jamshed default: 75476404edcSAsim Jamshed printf("Usage: %s [-f config_file]\n", argv[0]); 75576404edcSAsim Jamshed return 0; 75676404edcSAsim Jamshed } 75776404edcSAsim Jamshed 75876404edcSAsim Jamshed } 75976404edcSAsim Jamshed 76076404edcSAsim Jamshed core_limit = sysconf(_SC_NPROCESSORS_ONLN); 76176404edcSAsim Jamshed 76276404edcSAsim Jamshed ret = mtcp_init(fname); 76376404edcSAsim Jamshed if (ret) { 76476404edcSAsim Jamshed TRACE_ERROR("Failed to initialize mtcp.\n"); 76576404edcSAsim Jamshed exit(EXIT_FAILURE); 76676404edcSAsim Jamshed } 76776404edcSAsim Jamshed 76876404edcSAsim Jamshed mtcp_getconf(&g_mcfg); 76976404edcSAsim Jamshed 77076404edcSAsim Jamshed core_limit = g_mcfg.num_cores; 77176404edcSAsim Jamshed 77276404edcSAsim Jamshed GlbInitWget(); 77376404edcSAsim Jamshed 77476404edcSAsim Jamshed for (i = 0; i < core_limit; i++) { 77576404edcSAsim Jamshed cores[i] = i; 77676404edcSAsim Jamshed 77776404edcSAsim Jamshed /* Run mtcp thread */ 77876404edcSAsim Jamshed if ((g_mcfg.cpu_mask & (1L << i)) && 77976404edcSAsim Jamshed pthread_create(&mtcp_thread[i], NULL, RunMTCP, (void *)&cores[i])) { 78076404edcSAsim Jamshed perror("pthread_create"); 78176404edcSAsim Jamshed TRACE_ERROR("Failed to create msg_test thread.\n"); 78276404edcSAsim Jamshed exit(-1); 78376404edcSAsim Jamshed } 78476404edcSAsim Jamshed } 78576404edcSAsim Jamshed 78676404edcSAsim Jamshed for (i = 0; i < core_limit; i++) { 78776404edcSAsim Jamshed if (g_mcfg.cpu_mask & (1L << i)) 78876404edcSAsim Jamshed pthread_join(mtcp_thread[i], NULL); 78976404edcSAsim Jamshed TRACE_INFO("Message test thread %d joined.\n", i); 79076404edcSAsim Jamshed } 79176404edcSAsim Jamshed 79276404edcSAsim Jamshed mtcp_destroy(); 79376404edcSAsim Jamshed return 0; 79476404edcSAsim Jamshed } 79576404edcSAsim Jamshed /*----------------------------------------------------------------------------*/ 796