/** * @param buffer can be NULL, in case when user want to just buffer it or skip some data. * * Global options that have efffect on this function are following * 1) ccx_options.live_stream * 2) ccx_options.buffer_input * 3) ccx_options.input_source * 4) ccx_options.binary_concat * * TODO instead of using global ccx_options move them to ccx_demuxer */ size_t buffered_read_opt (struct ccx_demuxer *ctx, unsigned char *buffer, size_t bytes) { size_t origin_buffer_size = bytes; size_t copied = 0; time_t seconds = 0; position_sanity_check(ctx); if (ccx_options.live_stream > 0) time (&seconds); if (ccx_options.buffer_input || ctx->filebuffer_pos < ctx->bytesinbuffer) { // Needs to return data from filebuffer_start+pos to filebuffer_start+pos+bytes-1; int eof = (ctx->infd == -1); while ((!eof || ccx_options.live_stream) && bytes) { if (terminate_asap) break; if (eof) { // No more data available inmediately, we sleep a while to give time // for the data to come up sleepandchecktimeout (seconds); } size_t ready = ctx->bytesinbuffer - ctx->filebuffer_pos; if (ready == 0) // We really need to read more { if (!ccx_options.buffer_input) { // We got in the buffering code because of the initial buffer for // detection stuff. However we don't want more buffering so // we do the rest directly on the final buffer. int i; do { // No code for network support here, because network is always // buffered - if here, then it must be files. if (buffer != NULL) // Read { i = read (ctx->infd, buffer, bytes); if( i == -1) fatal (EXIT_READ_ERROR, "Error reading input file!\n"); buffer += i; } else // Seek { LLONG op, np; op = LSEEK (ctx->infd, 0, SEEK_CUR); // Get current pos if (op + bytes < 0) // Would mean moving beyond start of file: Not supported return 0; np = LSEEK (ctx->infd, bytes, SEEK_CUR); // Pos after moving i = (int) (np - op); } // if both above lseek returned -1 (error); i would be 0 here and // in case when its not live stream copied would decrease and bytes would... if (i == 0 && ccx_options.live_stream) { if (ccx_options.input_source == CCX_DS_STDIN) { ccx_options.live_stream = 0; break; } else { sleepandchecktimeout (seconds); } } else { copied += i; bytes -= i; } } while ((i || ccx_options.live_stream || (ccx_options.binary_concat && switch_to_next_file(ctx->parent, copied))) && bytes); return copied; } // Keep the last 8 bytes, so we have a guaranteed // working seek (-8) - needed by mythtv. int keep = ctx->bytesinbuffer > 8 ? 8 : ctx->bytesinbuffer; memmove (ctx->filebuffer, ctx->filebuffer+(FILEBUFFERSIZE-keep),keep); int i; if (ccx_options.input_source == CCX_DS_FILE || ccx_options.input_source == CCX_DS_STDIN) i = read (ctx->infd, ctx->filebuffer + keep, FILEBUFFERSIZE-keep); else if (ccx_options.input_source == CCX_DS_TCP) i = net_tcp_read(ctx->infd, (char *) ctx->filebuffer + keep, FILEBUFFERSIZE - keep); else i = recvfrom(ctx->infd,(char *) ctx->filebuffer + keep, FILEBUFFERSIZE - keep, 0, NULL, NULL); if (terminate_asap) /* Looks like receiving a signal here will trigger a -1, so check that first */ break; if (i == -1) fatal (EXIT_READ_ERROR, "Error reading input stream!\n"); if (i == 0) { /* If live stream, don't try to switch - acknowledge eof here as it won't cause a loop end */ if (ccx_options.live_stream || ((struct lib_ccx_ctx *)ctx->parent)->inputsize <= origin_buffer_size || !(ccx_options.binary_concat && switch_to_next_file(ctx->parent, copied))) eof = 1; } ctx->filebuffer_pos = keep; ctx->bytesinbuffer = (int) i + keep; ready = i; } int copy = (int) (ready>=bytes ? bytes:ready); if (copy) { if (buffer != NULL) { memcpy (buffer, ctx->filebuffer + ctx->filebuffer_pos, copy); buffer += copy; } ctx->filebuffer_pos += copy; bytes -= copy; copied += copy; } } } else // Read without buffering { if (buffer != NULL) { int i; while (bytes > 0 && ctx->infd != -1 && ((i = read(ctx->infd, buffer, bytes)) != 0 || ccx_options.live_stream || (ccx_options.binary_concat && switch_to_next_file(ctx->parent, copied)))) { if (terminate_asap) break; if( i == -1) fatal (EXIT_READ_ERROR, "Error reading input file!\n"); else if (i == 0) sleepandchecktimeout (seconds); else { copied += i; bytes -= i; buffer += i; } } return copied; } while (bytes != 0 && ctx->infd != -1) { LLONG op, np; if (terminate_asap) break; op = LSEEK (ctx->infd, 0, SEEK_CUR); // Get current pos if (op + bytes < 0) // Would mean moving beyond start of file: Not supported return 0; np = LSEEK (ctx->infd, bytes, SEEK_CUR); // Pos after moving if (op == -1 && np == -1) // Possibly a pipe that doesn't like "skipping" { char c; for (size_t i = 0; i<bytes; i++) read(ctx->infd, &c, 1); copied = bytes; } else copied = copied + (np - op); bytes = bytes- (unsigned int) copied; if (copied == 0) { if (ccx_options.live_stream) sleepandchecktimeout (seconds); else { if (ccx_options.binary_concat) switch_to_next_file(ctx->parent, 0); else break; } } } } return copied; }
static void* __net_slice_worker(void* arg) { net_slice_ctx_t* slice_ctx = (net_slice_ctx_t*)arg; int slice_num = slice_ctx->slice_num; int slice_id = slice_ctx->slice_id; int cpu_base = slice_ctx->cpu_base; assert(slice_ctx->fd > 0); if (cpu_base > 0) { cpu_base += (slice_id%4); spk_worker_set_affinity(cpu_base); } zlog_info(net_zc, "slice> spawned: id=%d, cpu=%d", slice_id, cpu_base); while (!slice_ctx->quit_req) { pthread_mutex_lock(&slice_ctx->lock); if(slice_ctx->wptr == slice_ctx->rptr) { struct timeval now; struct timespec outtime; gettimeofday(&now, NULL); outtime.tv_sec = now.tv_sec + 1; outtime.tv_nsec = now.tv_usec * 1000; pthread_cond_timedwait(&slice_ctx->not_empty, &slice_ctx->lock, &outtime); } if (slice_ctx->wptr == slice_ctx->rptr) { pthread_mutex_unlock(&slice_ctx->lock); continue; } assert(slice_ctx->data_chunk.flag == CHUNK_DATA_FLAG__REQ); size_t chunk_size = slice_ctx->data_chunk.size; size_t slice_sz = chunk_size / slice_num; ssize_t access = 0; // check chunk_size and slice_sz if ((chunk_size % slice_num) || (slice_sz & (0x4000-1))) { // 16k alignment zlog_error(net_zc, "illegal chunk_sz: chunk_sz=%zu, slice_num=%d", chunk_size, slice_num); access = SPKERR_PARAM; goto done; } if (slice_sz != slice_ctx->slice_sz) { zlog_warn(net_zc, "unexpected slice size : slice_sz=%zu, expect=%zu",slice_sz, slice_ctx->slice_sz); // this chunk may the last in file } if (slice_ctx->dir == SPK_DIR_WRITE) { // write if (slice_ctx->type == net_intf_tcp) { access = net_tcp_write(slice_ctx->fd, slice_ctx->data_chunk.buf + slice_id * slice_sz,slice_sz); } else if (slice_ctx->type == net_intf_udp) { access = net_udp_write(slice_ctx->fd, slice_ctx->data_chunk.buf + slice_id * slice_sz,slice_sz,((struct sockaddr*)&slice_ctx->svr_addr)); } } else { // read if (slice_ctx->type == net_intf_tcp) { access = net_tcp_read(slice_ctx->fd, slice_ctx->data_chunk.buf + slice_id * slice_sz,slice_sz); } else if (slice_ctx->type == net_intf_udp) { access = net_udp_read(slice_ctx->fd, slice_ctx->data_chunk.buf + slice_id * slice_sz,slice_sz,((struct sockaddr*)&slice_ctx->svr_addr)); } } if (access != slice_sz) { zlog_error(net_zc, "failed to access file: dir=%d, " "sock_fd:%d slice_sz=%zu, offset=%ld, ret=%ld, errmsg=\'%s\'", slice_ctx->dir, slice_ctx->fd,slice_sz, slice_id * slice_sz, access, strerror(errno)); access = SPKERR_EACCESS; goto done; } done: if (access == slice_sz) { slice_ctx->data_chunk.flag = CHUNK_DATA_FLAG__DONE; } else { slice_ctx->data_chunk.flag = access; } slice_ctx->rptr++; pthread_cond_signal(&slice_ctx->not_full); pthread_mutex_unlock(&slice_ctx->lock); } zlog_info(net_zc, "slice> terminated: id=%d", slice_id); return(NULL); }