// private function to assign a new element pointer to a given 'slot' static void ringbuffer_set(ringbuffer_t *rb, size_t index, void *element) { if (index >= rb->capacity) index -= rb->capacity; ringbuffer_free(rb, index); rb->entries[index] = element; }
void * mread_pull(struct mread_pool * self , int size) { if (self->active == -1) { return NULL; } struct socket *s = &self->sockets[self->active]; int rd_size = size; char * buffer = _ringbuffer_read(self, &rd_size); if (buffer) { self->skip += size; return buffer; } if (s->status == SOCKET_CLOSED) { ringbuffer_free(self->rb , s->node); s->node = NULL; return NULL; } if (s->status == SOCKET_READ) { s->status = SOCKET_SUSPEND; return NULL; } assert(s->status == SOCKET_POLLIN); int sz = size - rd_size; int rd = READBLOCKSIZE; if (rd < sz) { rd = sz; } int id = self->active; struct ringbuffer * rb = self->rb; struct ringbuffer_block * blk = ringbuffer_alloc(rb , rd); while (blk == NULL) { int collect_id = ringbuffer_collect(rb); _close_client(self , collect_id); if (id == collect_id) { return NULL; } blk = ringbuffer_alloc(rb , rd); } buffer = (char *)(blk + 1); for (;;) { int bytes = recv(s->fd, buffer, rd, MSG_DONTWAIT); if (bytes > 0) { ringbuffer_resize(rb, blk , bytes); if (bytes < sz) { _link_node(rb, self->active, s , blk); s->status = SOCKET_SUSPEND; return NULL; } s->status = SOCKET_READ; break; } if (bytes == 0) { _close_active(self); return NULL; } if (bytes == -1) { switch(errno) { case EWOULDBLOCK: return NULL; case EINTR: continue; default: _close_active(self); return NULL; } } } _link_node(rb, self->active , s , blk); void * ret; int real_rd = ringbuffer_data(rb, s->node , size , self->skip, &ret); if (ret) { self->skip += size; return ret; } assert(real_rd == size); struct ringbuffer_block * temp = ringbuffer_alloc(rb, size); while (temp == NULL) { int collect_id = ringbuffer_collect(rb); if (id == collect_id) { return NULL; } temp = ringbuffer_alloc(rb , size); } temp->id = id; if (s->temp) { ringbuffer_link(rb, temp, s->temp); } s->temp = temp; ret = ringbuffer_copy(rb, s->node, self->skip, temp); assert(ret); self->skip += size; return ret; }
void * DMXThread(void * v_arg) { pthread_t file_thread; struct filenames_t filename_data; char filename_extension[3]; ringbuffer_data_t vec[2]; ssize_t written; ssize_t todo = 0; ssize_t todo2; unsigned char buf[TS_SIZE]; int offset = 0; ssize_t r = 0; struct pollfd pfd = {*(int*)v_arg, POLLIN|POLLERR,0 }; int pres; ringbuffer_t * ringbuf = ringbuffer_create(ringbuffersize); if (!ringbuf) { exit_flag = STREAM2FILE_STATUS_RECORDING_THREADS_FAILED; puts("[stream2file]: error allocating ringbuffer! (out of memory?)"); } else fprintf(stderr, "[stream2file] allocated ringbuffer size: %ld\n", ringbuffer_write_space(ringbuf)); filename_data.ringbuffer = ringbuf; if (v_arg == &dvrfd) { filename_data.extension = "ts"; } else { for (int i = 0; i < MAXPIDS; i++) if (v_arg == (&(demuxfd[i]))) sprintf(filename_extension, "%u", i); filename_data.extension = filename_extension; } if (pthread_create(&file_thread, 0, FileThread, &filename_data) != 0) { exit_flag = STREAM2FILE_STATUS_RECORDING_THREADS_FAILED; puts("[stream2file]: error creating file_thread! (out of memory?)"); } if (v_arg == &dvrfd) while (exit_flag == STREAM2FILE_STATUS_RUNNING) { if ((pres=poll (&pfd, 1, 15000))>0) { if (!(pfd.revents&POLLIN)) { printf ("[stream2file]: PANIC: error reading from demux, bailing out\n"); exit_flag = STREAM2FILE_STATUS_READ_FAILURE; } r = read(*(int *)v_arg, &(buf[0]), TS_SIZE); #ifdef HAVE_TRIPLEDRAGON if (r < 0) { perror("stream2file read DMX"); exit_flag = STREAM2FILE_STATUS_READ_FAILURE; break; } #endif if (r > 0) { offset = sync_byte_offset(&(buf[0]), r); if (offset != -1) break; } } else if (!pres) { printf ("[stream2file]: timeout from demux\n"); } } else offset = 0; if (exit_flag == STREAM2FILE_STATUS_RUNNING) { written = ringbuffer_write(ringbuf, (char *)&(buf[offset]), r - offset); // TODO: Retry if (written != r - offset) { printf("PANIC: wrote less than requested to ringbuffer, written %d, requested %d\n", written, r - offset); exit_flag = STREAM2FILE_STATUS_BUFFER_OVERFLOW; } todo = IN_SIZE - (r - offset); } /* IN_SIZE > TS_SIZE => todo > 0 */ while (exit_flag == STREAM2FILE_STATUS_RUNNING) { ringbuffer_get_write_vector(ringbuf, &(vec[0])); todo2 = todo - vec[0].len; if (todo2 < 0) { todo2 = 0; } else { if (((size_t)todo2) > vec[1].len) { printf("PANIC: not enough space in ringbuffer, available %d, needed %d\n", vec[0].len + vec[1].len, todo + todo2); exit_flag = STREAM2FILE_STATUS_BUFFER_OVERFLOW; } todo = vec[0].len; } while (exit_flag == STREAM2FILE_STATUS_RUNNING) { if ((pres=poll (&pfd, 1, 5000))>0) { if (!(pfd.revents&POLLIN)) { printf ("PANIC: error reading from demux, bailing out\n"); exit_flag = STREAM2FILE_STATUS_READ_FAILURE; } r = read(*(int *)v_arg, vec[0].buf, todo); if (r > 0) { ringbuffer_write_advance(ringbuf, r); if (todo == r) { if (todo2 == 0) goto next; todo = todo2; todo2 = 0; vec[0].buf = vec[1].buf; } else { vec[0].buf += r; todo -= r; } } #ifdef HAVE_TRIPLEDRAGON if (r < 0 && errno != EAGAIN) { perror("[stream2file] read DMX"); exit_flag = STREAM2FILE_STATUS_READ_FAILURE; break; } #endif } else if (!pres){ printf ("[stream2file]: timeout reading from demux\n"); exit_flag = STREAM2FILE_STATUS_READ_FAILURE; } } next: todo = IN_SIZE; } if (v_arg == &dvrfd) close(*(int *)v_arg); else unsetPesFilter(*(int *)v_arg); pthread_join(file_thread, NULL); if (ringbuf) ringbuffer_free(ringbuf); if (v_arg == &dvrfd) while (demuxfd_count > 0) unsetPesFilter(demuxfd[--demuxfd_count]); DEC_BUSY_COUNT; if ((v_arg == &dvrfd) || (v_arg == (&(demuxfd[0])))) { CEventServer eventServer; eventServer.registerEvent2(NeutrinoMessages::EVT_RECORDING_ENDED, CEventServer::INITID_NEUTRINO, "/tmp/neutrino.sock"); stream2file_status2_t s; s.status = exit_flag; strncpy(s.filename,basename(myfilename),512); s.filename[511] = '\0'; strncpy(s.dir,dirname(myfilename),100); s.dir[99] = '\0'; eventServer.sendEvent(NeutrinoMessages::EVT_RECORDING_ENDED, CEventServer::INITID_NEUTRINO, &s, sizeof(s)); printf("[stream2file]: pthreads exit code: %i, dir: '%s', filename: '%s' myfilename: '%s'\n", exit_flag, s.dir, s.filename, myfilename); } pthread_exit(NULL); }