/* timeout is in milliseconds */ static int wait_for_start(struct bluetooth_data *data, int timeout) { a2dp_state_t state = data->state; struct timeval tv; struct timespec ts; int err = 0; #ifdef ENABLE_TIMING uint64_t begin, end; begin = get_microseconds(); #endif gettimeofday(&tv, (struct timezone *) NULL); ts.tv_sec = tv.tv_sec + (timeout / 1000); ts.tv_nsec = (tv.tv_usec + (timeout % 1000) * 1000L ) * 1000L; pthread_mutex_lock(&data->mutex); while (state != A2DP_STATE_STARTED) { if (state == A2DP_STATE_NONE) __set_command(data, A2DP_CMD_INIT); else if (state == A2DP_STATE_INITIALIZED) __set_command(data, A2DP_CMD_CONFIGURE); else if (state == A2DP_STATE_CONFIGURED) { __set_command(data, A2DP_CMD_START); } again: err = pthread_cond_timedwait(&data->client_wait, &data->mutex, &ts); if (err) { /* don't timeout if we're done */ if (data->state == A2DP_STATE_STARTED) { err = 0; break; } if (err == ETIMEDOUT) break; goto again; } if (state == data->state) goto again; state = data->state; if (state == A2DP_STATE_NONE) { err = ENODEV; break; } } pthread_mutex_unlock(&data->mutex); #ifdef ENABLE_TIMING end = get_microseconds(); print_time("wait_for_start", begin, end); #endif /* pthread_cond_timedwait returns positive errors */ return -err; }
static int avdtp_write(struct bluetooth_data *data) { int ret = 0; struct rtp_header *header; struct rtp_payload *payload; uint64_t now; long duration = data->frame_duration * data->frame_count; #ifdef ENABLE_TIMING uint64_t begin, end, begin2, end2; begin = get_microseconds(); #endif header = (struct rtp_header *)data->buffer; #ifdef TN_JPN_NTT_BT_SCMS-T payload = (struct rtp_payload *)(data->buffer + sizeof(*header) + data->sizeof_scms_t); memset(data->buffer, 0, sizeof(*header) + sizeof(*payload) + data->sizeof_scms_t); if (data->sizeof_scms_t) { /* * In theory, this should be setable on the fly to 0x01 to "protect" * the stream and 0x00 to allow capture by remote device. In practice, * all I've ever seem is "protect", or 0x01. */ data->buffer[sizeof(*header)] = SCMS_T_COPY_NOT_ALLOWED; } #else payload = (struct rtp_payload *)(data->buffer + sizeof(*header)); memset(data->buffer, 0, sizeof(*header) + sizeof(*payload)); #endif payload->frame_count = data->frame_count; header->v = 2; header->pt = 1; header->sequence_number = htons(data->seq_num); header->timestamp = htonl(data->nsamples); header->ssrc = htonl(1); data->stream.revents = 0; #ifdef ENABLE_TIMING begin2 = get_microseconds(); #endif ret = poll(&data->stream, 1, POLL_TIMEOUT); #ifdef ENABLE_TIMING end2 = get_microseconds(); print_time("poll", begin2, end2); #endif if (ret == 1 && data->stream.revents == POLLOUT) { long ahead = 0; now = get_microseconds(); if (data->next_write) { ahead = data->next_write - now; #ifdef ENABLE_TIMING DBG("duration: %ld, ahead: %ld", duration, ahead); #endif if (ahead > 0) { /* too fast, need to throttle */ usleep(ahead); } } else { data->next_write = now; } if (ahead <= -CATCH_UP_TIMEOUT * 1000) { /* fallen too far behind, don't try to catch up */ VDBG("ahead < %d, reseting next_write timestamp", -CATCH_UP_TIMEOUT * 1000); data->next_write = 0; } else { data->next_write += duration; } #ifdef ENABLE_TIMING begin2 = get_microseconds(); #endif ret = send(data->stream.fd, data->buffer, data->count, MSG_NOSIGNAL); #ifdef ENABLE_TIMING end2 = get_microseconds(); print_time("send", begin2, end2); #endif if (ret < 0) { /* can happen during normal remote disconnect */ VDBG("send() failed: %d (errno %s)", ret, strerror(errno)); } if (ret == -EPIPE) { bluetooth_close(data); } } else { /* can happen during normal remote disconnect */ VDBG("poll() failed: %d (revents = %d, errno %s)", ret, data->stream.revents, strerror(errno)); data->next_write = 0; } /* Reset buffer of data to send */ #ifdef TN_JPN_NTT_BT_SCMS-T data->count = sizeof(struct rtp_header) + sizeof(struct rtp_payload) + data->sizeof_scms_t; #else data->count = sizeof(struct rtp_header) + sizeof(struct rtp_payload); #endif data->frame_count = 0; data->samples = 0; data->seq_num++; #ifdef ENABLE_TIMING end = get_microseconds(); print_time("avdtp_write", begin, end); #endif return 0; /* always return success */ }
int a2dp_write(a2dpData d, const void* buffer, int count) { struct bluetooth_data* data = (struct bluetooth_data*)d; uint8_t* src = (uint8_t *)buffer; int codesize; int err, ret = 0; long frames_left = count; int encoded; unsigned int written; const char *buff; int did_configure = 0; #ifdef ENABLE_TIMING uint64_t begin, end; DBG("********** a2dp_write **********"); begin = get_microseconds(); #endif err = wait_for_start(data, WRITE_TIMEOUT); if (err < 0) return err; codesize = data->codesize; while (frames_left >= codesize) { /* Enough data to encode (sbc wants 512 byte blocks) */ encoded = sbc_encode(&(data->sbc), src, codesize, data->buffer + data->count, sizeof(data->buffer) - data->count, &written); if (encoded <= 0) { ERR("Encoding error %d", encoded); goto done; } VDBG("sbc_encode returned %d, codesize: %d, written: %d\n", encoded, codesize, written); src += encoded; data->count += written; data->frame_count++; data->samples += encoded; data->nsamples += encoded; /* No space left for another frame then send */ if ((data->count + written >= data->link_mtu) || (data->count + written >= BUFFER_SIZE)) { VDBG("sending packet %d, count %d, link_mtu %u", data->seq_num, data->count, data->link_mtu); err = avdtp_write(data); if (err < 0) return err; } ret += encoded; frames_left -= encoded; } if (frames_left > 0) ERR("%ld bytes left at end of a2dp_write\n", frames_left); done: #ifdef ENABLE_TIMING end = get_microseconds(); print_time("a2dp_write total", begin, end); #endif return ret; }
ubyte64 System::get_time() { return (get_microseconds() / 1000); }
static int avdtp_write(struct bluetooth_data *data) { int ret = 0; struct rtp_header *header; struct rtp_payload *payload; uint64_t now; long duration = data->frame_duration * data->frame_count; #ifdef ENABLE_TIMING uint64_t begin, end, begin2, end2; begin = get_microseconds(); #endif header = (struct rtp_header *)data->buffer; payload = (struct rtp_payload *)(data->buffer + sizeof(*header)); memset(data->buffer, 0, sizeof(*header) + sizeof(*payload)); payload->frame_count = data->frame_count; header->v = 2; header->pt = 1; header->sequence_number = htons(data->seq_num); header->timestamp = htonl(data->nsamples); header->ssrc = htonl(1); data->stream.revents = 0; #ifdef ENABLE_TIMING begin2 = get_microseconds(); #endif ret = poll(&data->stream, 1, POLL_TIMEOUT); #ifdef ENABLE_TIMING end2 = get_microseconds(); print_time("poll Time Taken", begin2, end2); #endif if (ret == 1 && data->stream.revents == POLLOUT) { long ahead = 0; now = get_microseconds(); if (data->next_write) { ahead = data->next_write - now; #ifdef ENABLE_TIMING DBG("duration: %ld, ahead: %ld", duration, ahead); #endif if (ahead > 0) { /* too fast, need to throttle */ usleep(ahead); } } else { data->next_write = now; } //DBG("duration: %ld, ahead: %ld", duration, ahead); //DBG("decrease_bitpool %d",decrease_bitpool); if(ahead <= -30*1000){ decrease_bitpool++; if(decrease_bitpool > 2 ) { DBG("duration: %ld, ahead: %ld", duration, ahead); VDBG("calibrating Bitpool Decrease"); calibrate_bitpool(data,0); decrease_bitpool = 0; avdtp_good_counter=0; } } else if(ahead >= 10000){ if(data->sbc.bitpool != data->sbc_capabilities.max_bitpool){ avdtp_good_counter++; if(avdtp_good_counter > 1000){//about 10 secs DBG("duration: %ld, ahead: %ld avdtp_good_counter: %ld", duration, ahead, avdtp_good_counter); calibrate_bitpool(data,1); skip_avdtp_flow_check=0; } } decrease_bitpool = 0; } if (ahead <= -CATCH_UP_TIMEOUT * 1000) { /* fallen too far behind, don't try to catch up */ DBG("ahead < %d, reseting next_write timestamp", -CATCH_UP_TIMEOUT * 1000); data->next_write = 0; } else { data->next_write += duration; } #ifdef ENABLE_TIMING begin2 = get_microseconds(); #endif pthread_mutex_lock(&data->lock); if (data->stream.fd == -1) { pthread_mutex_unlock(&data->lock); return EBADF; } else { ret = send(data->stream.fd, data->buffer, data->count, MSG_NOSIGNAL); } pthread_mutex_unlock(&data->lock); #ifdef ENABLE_TIMING end2 = get_microseconds(); print_time("send", begin2, end2); #endif if (ret < 0) { /* can happen during normal remote disconnect */ VDBG("send() failed: %d (errno %s)", ret, strerror(errno)); } if (ret == -EPIPE) { bluetooth_close(data); } } else { /* can happen during normal remote disconnect */ VDBG("poll() failed: %d (revents = %d, errno %s)", ret, data->stream.revents, strerror(errno)); data->next_write = 0; } /* Reset buffer of data to send */ data->count = sizeof(struct rtp_header) + sizeof(struct rtp_payload); data->frame_count = 0; data->samples = 0; data->seq_num++; #ifdef ENABLE_TIMING end = get_microseconds(); print_time("avdtp_write", begin, end); #endif return 0; /* always return success */ }
static void a2dp_sig_thread(void *d) { struct bluetooth_data *data = d; a2dp_state_t state = data->state; int err = 0; struct timeval tv; struct timespec ts; #ifdef ENABLE_TIMING uint64_t begin, end; begin = get_microseconds(); #endif gettimeofday(&tv, (struct timezone *) NULL); ts.tv_sec = tv.tv_sec + (WRITE_TIMEOUT / 1000); ts.tv_nsec = (tv.tv_usec + (WRITE_TIMEOUT % 1000) * 1000L ) * 1000L; pthread_mutex_lock(&data->mutex); while (state != A2DP_STATE_STARTED) { if (state == A2DP_STATE_NONE) __set_command(data, A2DP_CMD_INIT); else if (state == A2DP_STATE_INITIALIZED) __set_command(data, A2DP_CMD_CONFIGURE); else if (state == A2DP_STATE_CONFIGURED) { __set_command(data, A2DP_CMD_START); } again: err = pthread_cond_timedwait(&data->client_wait, &data->mutex, &ts); if (err) { /* don't timeout if we're done */ if (data->state == A2DP_STATE_STARTED) { err = 0; break; } if (err == ETIMEDOUT) { DBG(" Time out"); break; } goto again; } if (state == data->state) goto again; state = data->state; if (state == A2DP_STATE_NONE) { err = ENODEV; break; } } pthread_mutex_unlock(&data->mutex); #ifdef ENABLE_TIMING end = get_microseconds(); print_time("signalling process took", begin, end); #endif data->signalling_thread = 0; DBG("error returned is %d", err); /* pthread_cond_timedwait returns positive errors */ return; }
my_bool str_to_time(const char *str, uint length, MYSQL_TIME *l_time, ulonglong fuzzydate, MYSQL_TIME_STATUS *status) { ulong date[5]; ulonglong value; const char *end=str+length, *end_of_days; my_bool found_days,found_hours, neg= 0; uint UNINIT_VAR(state); my_time_status_init(status); for (; str != end && my_isspace(&my_charset_latin1,*str) ; str++) length--; if (str != end && *str == '-') { neg=1; str++; length--; } if (str == end) { status->warnings|= MYSQL_TIME_WARN_TRUNCATED; goto err; } /* Check first if this is a full TIMESTAMP */ if (length >= 12) { /* Probably full timestamp */ (void) str_to_datetime(str, length, l_time, (fuzzydate & ~TIME_TIME_ONLY) | TIME_DATETIME_ONLY, status); if (l_time->time_type >= MYSQL_TIMESTAMP_ERROR) return l_time->time_type == MYSQL_TIMESTAMP_ERROR; my_time_status_init(status); } l_time->neg= neg; /* Not a timestamp. Try to get this as a DAYS_TO_SECOND string */ for (value=0; str != end && my_isdigit(&my_charset_latin1,*str) ; str++) value=value*10L + (long) (*str - '0'); /* Skip all space after 'days' */ end_of_days= str; for (; str != end && my_isspace(&my_charset_latin1, str[0]) ; str++) ; found_days=found_hours=0; if ((uint) (end-str) > 1 && str != end_of_days && my_isdigit(&my_charset_latin1, *str)) { /* Found days part */ date[0]= (ulong) value; state= 1; /* Assume next is hours */ found_days= 1; } else if ((end-str) > 1 && *str == time_separator && my_isdigit(&my_charset_latin1, str[1])) { date[0]= 0; /* Assume we found hours */ date[1]= (ulong) value; state=2; found_hours=1; str++; /* skip ':' */ } else { /* String given as one number; assume HHMMSS format */ date[0]= 0; date[1]= (ulong) (value/10000); date[2]= (ulong) (value/100 % 100); date[3]= (ulong) (value % 100); state=4; goto fractional; } /* Read hours, minutes and seconds */ for (;;) { for (value=0; str != end && my_isdigit(&my_charset_latin1,*str) ; str++) value=value*10L + (long) (*str - '0'); date[state++]= (ulong) value; if (state == 4 || (end-str) < 2 || *str != time_separator || !my_isdigit(&my_charset_latin1,str[1])) break; str++; /* Skip time_separator (':') */ } if (state != 4) { /* Not HH:MM:SS */ /* Fix the date to assume that seconds was given */ if (!found_hours && !found_days) { bmove_upp((uchar*) (date+4), (uchar*) (date+state), sizeof(long)*(state-1)); bzero((uchar*) date, sizeof(long)*(4-state)); } else bzero((uchar*) (date+state), sizeof(long)*(4-state)); } fractional: /* Get fractional second part */ if (!status->warnings && str < end && *str == '.') { uint number_of_fields= 0; str++; get_microseconds(&date[4], status, &number_of_fields, &str, end); } else date[4]= 0; /* Check for exponent part: E<gigit> | E<sign><digit> */ /* (may occur as result of %g formatting of time value) */ if ((end - str) > 1 && (*str == 'e' || *str == 'E') && (my_isdigit(&my_charset_latin1, str[1]) || ((str[1] == '-' || str[1] == '+') && (end - str) > 2 && my_isdigit(&my_charset_latin1, str[2])))) { status->warnings|= MYSQL_TIME_WARN_TRUNCATED; goto err; } if (internal_format_positions[7] != 255) { /* Read a possible AM/PM */ while (str != end && my_isspace(&my_charset_latin1, *str)) str++; if (str+2 <= end && (str[1] == 'M' || str[1] == 'm')) { if (str[0] == 'p' || str[0] == 'P') { str+= 2; date[1]= date[1]%12 + 12; } else if (str[0] == 'a' || str[0] == 'A') str+=2; } } /* Integer overflow checks */ if (date[0] > UINT_MAX || date[1] > UINT_MAX || date[2] > UINT_MAX || date[3] > UINT_MAX || date[4] > UINT_MAX) { status->warnings|= MYSQL_TIME_WARN_OUT_OF_RANGE; goto err; } l_time->year= 0; /* For protocol::store_time */ l_time->month= 0; l_time->day= 0; l_time->hour= date[1] + date[0] * 24; /* Mix days and hours */ l_time->minute= date[2]; l_time->second= date[3]; l_time->second_part= date[4]; l_time->time_type= MYSQL_TIMESTAMP_TIME; /* Check if the value is valid and fits into MYSQL_TIME range */ if (check_time_range(l_time, 6, &status->warnings)) return TRUE; /* Check if there is garbage at end of the MYSQL_TIME specification */ if (str != end) { do { if (!my_isspace(&my_charset_latin1,*str)) { status->warnings|= MYSQL_TIME_WARN_TRUNCATED; break; } } while (++str != end); } return FALSE; err: bzero((char*) l_time, sizeof(*l_time)); l_time->time_type= MYSQL_TIMESTAMP_ERROR; return TRUE; }
my_bool str_to_datetime(const char *str, uint length, MYSQL_TIME *l_time, ulonglong flags, MYSQL_TIME_STATUS *status) { const char *end=str+length, *pos; uint number_of_fields= 0, digits, year_length, not_zero_date; DBUG_ENTER("str_to_datetime"); bzero(l_time, sizeof(*l_time)); if (flags & TIME_TIME_ONLY) { my_bool ret= str_to_time(str, length, l_time, flags, status); DBUG_RETURN(ret); } my_time_status_init(status); /* Skip space at start */ for (; str != end && my_isspace(&my_charset_latin1, *str) ; str++) ; if (str == end || ! my_isdigit(&my_charset_latin1, *str)) { status->warnings= MYSQL_TIME_WARN_TRUNCATED; l_time->time_type= MYSQL_TIMESTAMP_NONE; DBUG_RETURN(1); } /* Calculate number of digits in first part. If length= 8 or >= 14 then year is of format YYYY. (YYYY-MM-DD, YYYYMMDD, YYYYYMMDDHHMMSS) */ pos= str; digits= skip_digits(&pos, end); if (pos < end && *pos == 'T') /* YYYYYMMDDHHMMSSThhmmss is supported too */ { pos++; digits+= skip_digits(&pos, end); } if (pos < end && *pos == '.' && digits >= 12) /* YYYYYMMDDHHMMSShhmmss.uuuuuu is supported too */ { pos++; skip_digits(&pos, end); // ignore the return value } if (pos == end) { /* Found date in internal format (only numbers like [YY]YYMMDD[T][hhmmss[.uuuuuu]]) */ year_length= (digits == 4 || digits == 8 || digits >= 14) ? 4 : 2; if (get_digits(&l_time->year, &number_of_fields, &str, end, year_length) || get_digits(&l_time->month, &number_of_fields, &str, end, 2) || get_digits(&l_time->day, &number_of_fields, &str, end, 2) || get_maybe_T(&str, end) || get_digits(&l_time->hour, &number_of_fields, &str, end, 2) || get_digits(&l_time->minute, &number_of_fields, &str, end, 2) || get_digits(&l_time->second, &number_of_fields, &str, end, 2)) status->warnings|= MYSQL_TIME_WARN_TRUNCATED; } else { const char *start= str; if (get_number(&l_time->year, &number_of_fields, &str, end)) status->warnings|= MYSQL_TIME_WARN_TRUNCATED; year_length= str - start; if (!status->warnings && (get_punct(&str, end) || get_number(&l_time->month, &number_of_fields, &str, end) || get_punct(&str, end) || get_number(&l_time->day, &number_of_fields, &str, end) || get_date_time_separator(&number_of_fields, flags, &str, end) || get_number(&l_time->hour, &number_of_fields, &str, end) || get_punct(&str, end) || get_number(&l_time->minute, &number_of_fields, &str, end) || get_punct(&str, end) || get_number(&l_time->second, &number_of_fields, &str, end))) status->warnings|= MYSQL_TIME_WARN_TRUNCATED; } /* we're ok if date part is correct. even if the rest is truncated */ if (number_of_fields < 3) { l_time->time_type= MYSQL_TIMESTAMP_NONE; status->warnings|= MYSQL_TIME_WARN_TRUNCATED; DBUG_RETURN(TRUE); } if (!status->warnings && str < end && *str == '.') { str++; get_microseconds(&l_time->second_part, status, &number_of_fields, &str, end); } not_zero_date = l_time->year || l_time->month || l_time->day || l_time->hour || l_time->minute || l_time->second || l_time->second_part; if (year_length == 2 && not_zero_date) l_time->year+= (l_time->year < YY_PART_YEAR ? 2000 : 1900); if (l_time->year > 9999 || l_time->month > 12 || l_time->day > 31 || l_time->hour > 23 || l_time->minute > 59 || l_time->second > 59) { status->warnings|= MYSQL_TIME_WARN_TRUNCATED; goto err; } if (check_date(l_time, not_zero_date, flags, &status->warnings)) goto err; l_time->time_type= (number_of_fields <= 3 ? MYSQL_TIMESTAMP_DATE : MYSQL_TIMESTAMP_DATETIME); for (; str != end ; str++) { if (!my_isspace(&my_charset_latin1,*str)) { status->warnings= MYSQL_TIME_WARN_TRUNCATED; break; } } DBUG_RETURN(FALSE); err: bzero((char*) l_time, sizeof(*l_time)); l_time->time_type= MYSQL_TIMESTAMP_ERROR; DBUG_RETURN(TRUE); }
unsigned int CL_System::get_time() { return (unsigned int) (get_microseconds() / 1000); }
/** Creates n client connects to address */ void* client_thread(void *data) { const struct client_request * const req = data; const struct client_request_details * details = req->details; // Make a copy of the global settings const struct settings settings = *req->settings; // The time in microseconds to wait between each send (to limit our bandwidth) const unsigned long long time_between_sends = settings.rate> 0 ? 1000000 / settings.rate : 0; unsigned long long next_send_time = 0; // Array of client sockets SOCKET *client = NULL; unsigned int clients = 0; // The number of clients unsigned int clients_temp = 0; // The number of clients SOCKET *c = NULL; char *buffer= NULL; #ifdef USE_EPOLL int readFD_epoll = -1; struct epoll_event *events = NULL; #else int nfds; fd_set readFD; fd_set writeFD; #endif assert ( req != NULL ); assert ( details != NULL ); // Malloc the client array after we find out how many clients there are while (details != NULL) { clients += details->n; details = details->next; } if (clients == 0) { fprintf(stderr, "%s:%d Must have more than zero clients!\n", __FILE__, __LINE__ ); goto cleanup; } #ifndef USE_EPOLL if ( clients> FD_SETSIZE ) { fprintf(stderr, "%s:%d Client thread can have no more than %d connections\n", __FILE__, __LINE__, FD_SETSIZE ); goto cleanup; } #endif client = calloc(clients, sizeof(*client)); if ( client == NULL ) { fprintf(stderr, "%s:%d calloc error\n", __FILE__, __LINE__ ); goto cleanup; } // Blank client before we start for ( c = client; c < &client[ clients ]; c++) *c = INVALID_SOCKET; if ( settings.verbose ) printf("Core %d: Started client thread\n", req->cores); if ( connect_connections(&settings, req, client, &clients_temp) ) { goto cleanup; } if ( clients != clients_temp ) { fprintf(stderr, "%s:%d Requested number of clients does not match actual clients (%d != %d)\n", __FILE__, __LINE__, clients, clients_temp ); goto cleanup; } buffer = malloc( settings.message_size ); if ( buffer == NULL ) { fprintf(stderr, "%s:%d malloc error\n", __FILE__, __LINE__ ); goto cleanup; } memset( buffer, BUFFER_FILL, settings.message_size ); #ifdef USE_EPOLL readFD_epoll = epoll_create(clients); if(readFD_epoll == -1) { fprintf(stderr, "%s:%d epoll_create() error (%d) %s\n", __FILE__, __LINE__, ERRNO, strerror(ERRNO) ); goto cleanup; } events = calloc( clients, sizeof(*events) ); if ( events == NULL ) { fprintf(stderr, "%s:%d calloc error\n", __FILE__, __LINE__ ); goto cleanup; } #else nfds = (int)*client; FD_ZERO ( &readFD ); FD_ZERO ( &writeFD ); #endif // Loop all client sockets for (c = client; c < &client [ clients ]; c++) { SOCKET s = *c; #ifdef USE_EPOLL struct epoll_event event = {0}; assert ( s != INVALID_SOCKET ); event.events = EPOLLIN | EPOLLOUT; event.data.fd = s; if (epoll_ctl(readFD_epoll, EPOLL_CTL_ADD, s, &event) == -1) { fprintf(stderr, "%s:%d epoll() error adding client (%d) %s\n", __FILE__, __LINE__, ERRNO, strerror(ERRNO) ); goto cleanup; } #else assert ( s != INVALID_SOCKET ); // Add them to FD sets FD_SET( s, &readFD); FD_SET( s, &writeFD); if ( (int)s >= nfds ) nfds = (int)s + 1; assert ( FD_ISSET(s, &readFD ) ); assert ( FD_ISSET(s, &writeFD ) ); #endif } // Signal we are ready threads_signal_parent ( SIGNAL_READY_TO_GO, settings.threaded_model ); // Wait for the go wait_for_nonzero( &go_mutex, &go_cond, &bGo ); next_send_time = get_microseconds(); // Now start the main loop while ( bRunning ) { #ifdef USE_EPOLL int i; //This has been changed to re-try the epoll if we fail. int ready = epoll_wait_ign_signal(readFD_epoll, events, clients, TRANSFER_TIMEOUT); for ( i = 0; i < ready; i++ ) { SOCKET s = events[i].data.fd; assert ( s != INVALID_SOCKET ); if (events[i].events & (EPOLLHUP | EPOLLERR)) { //fprintf(stderr, "%s:%d epoll() error (%d) %s on socket %d\n", __FILE__, __LINE__, ERRNO, strerror(ERRNO) , s); closesocket( s ); continue; } if( events[i].events & EPOLLIN) { #else struct timeval waittime = {TRANSFER_TIMEOUT / 1000, 0}; // 1 second int ret = select_ign_signal(nfds, &readFD, &writeFD, NULL, &waittime); if ( ret == 0 ) fprintf(stderr, "%s:%d select() timeout occured\n", __FILE__, __LINE__ ); else if ( ret == SOCKET_ERROR ) { fprintf(stderr, "%s:%d select() error (%d) %s\n", __FILE__, __LINE__, ERRNO, strerror(ERRNO) ); goto cleanup; } // Figure out which sockets have fired for (c = client; c < &client [ clients ]; c++ ) { SOCKET s = *c; assert ( s != INVALID_SOCKET ); // Speed hack if ( ret == 0 ) { FD_SET( s, &readFD); FD_SET( s, &writeFD); continue; } // Check for reads if ( FD_ISSET( s, &readFD) ) { #endif int len = recv_ign_signal( s, buffer, settings.message_size, 0); if ( len == SOCKET_ERROR ) { if ( ERRNO != ECONNRESET ) { fprintf(stderr, "%s:%d recv(%d) error (%d) %s\n", __FILE__, __LINE__, s, ERRNO, strerror(ERRNO) ); goto cleanup; } } #ifndef USE_EPOLL ret--; #endif // The socket has closed if ( len <= 0 ) { if ( settings.verbose ) printf(" Client: %d Removed client (%d/%d)\n", req->cores, (int)((c - client) / sizeof(*c)) + 1, clients ); #ifndef USE_EPOLL // Quickly check if this client was in the write set if ( FD_ISSET( s, &writeFD) ) { FD_CLR( s, &writeFD ); ret--; } // Unset me from the set FD_CLR( s, &readFD ); // Move this back move_down ( c, &client[ clients ] ); c--; // Update the nfds nfds = (int)highest_socket(client, clients - 1) + 1; #endif // Invalid this client closesocket_ign_signal( s ); clients--; // If this is the last client then just give up! if ( clients == 0 ) goto cleanup; // This socket is now closed, so lets go back up to the loop continue; } #ifndef USE_EPOLL } else { // Set the socket on this FD, to save us doing it at the beginning of each loop FD_SET( s, &readFD); } // Check if we are ready to write if ( FD_ISSET( s, &writeFD) ) { ret--; #else } if( events[i].events & EPOLLOUT) { #endif // Rate limiting code if ( time_between_sends> 0 ) { const unsigned long long now = get_microseconds(); if ( next_send_time > now ) continue; next_send_time += time_between_sends; } if ( send_ign_signal( s, buffer, settings.message_size, 0 ) == SOCKET_ERROR ) { if ( ERRNO != EWOULDBLOCK && ERRNO != EPIPE ) { fprintf(stderr, "%s:%d send() error (%d) %s\n", __FILE__, __LINE__, ERRNO, strerror(ERRNO) ); goto cleanup; } } #ifdef USE_EPOLL } #endif #ifndef USE_EPOLL } else { // Set the socket on this FD, to save us doing it at the beginning of each loop FD_SET( s, &writeFD); } } // We have now looped over each socket, If we are here ret MUST be zero assert(ret == 0); } #else }