static int cache_fill_buffer(struct stream *cache, char *buffer, int max_len) { struct priv *s = cache->priv; assert(s->cache_thread_running); pthread_mutex_lock(&s->mutex); if (cache->pos != s->read_filepos) MP_ERR(s, "!!! read_filepos differs !!! report this bug...\n"); int readb = 0; if (max_len > 0) { double retry_time = 0; int64_t retry = s->reads - 1; // try at least 1 read on EOF while (1) { readb = read_buffer(s, buffer, max_len, s->read_filepos); s->read_filepos += readb; if (readb > 0) break; if (s->eof && s->read_filepos >= s->max_filepos && s->reads >= retry) break; s->idle = false; if (mp_cancel_test(s->cache->cancel)) break; cache_wakeup_and_wait(s, &retry_time); } } // wakeup the cache thread, possibly make it read more data ahead pthread_cond_signal(&s->wakeup); pthread_mutex_unlock(&s->mutex); return readb; }
// Runs in the main thread // mutex must be held, but is sometimes temporarily dropped static int cache_read(struct priv *s, unsigned char *buf, int size) { if (size <= 0) return 0; double retry = 0; while (s->read_filepos >= s->max_filepos || s->read_filepos < s->min_filepos) { if (s->eof && s->read_filepos >= s->max_filepos) return 0; if (cache_wakeup_and_wait(s, &retry) == CACHE_INTERRUPTED) return 0; } int64_t newb = s->max_filepos - s->read_filepos; // new bytes in the buffer int64_t pos = s->read_filepos - s->offset; // file pos to buffer memory pos if (pos < 0) pos += s->buffer_size; else if (pos >= s->buffer_size) pos -= s->buffer_size; if (newb > s->buffer_size - pos) newb = s->buffer_size - pos; // handle wrap... newb = FFMIN(newb, size); memcpy(buf, &s->buffer[pos], newb); s->read_filepos += newb; return newb; }
static int cache_control(stream_t *cache, int cmd, void *arg) { struct priv *s = cache->priv; int r = STREAM_ERROR; assert(cmd > 0); pthread_mutex_lock(&s->mutex); r = cache_get_cached_control(cache, cmd, arg); if (r != STREAM_ERROR) goto done; MP_VERBOSE(s, "blocking for STREAM_CTRL %d\n", cmd); s->control = cmd; s->control_arg = arg; double retry = 0; while (s->control != CACHE_CTRL_NONE) { if (mp_cancel_test(s->cache->cancel)) { s->eof = 1; r = STREAM_UNSUPPORTED; goto done; } cache_wakeup_and_wait(s, &retry); } r = s->control_res; if (s->control_flush) { stream_drop_buffers(cache); cache->pos = s->read_filepos; } done: pthread_mutex_unlock(&s->mutex); return r; }
static int cache_control(stream_t *cache, int cmd, void *arg) { struct priv *s = cache->priv; int r = STREAM_ERROR; assert(cmd > 0); pthread_mutex_lock(&s->mutex); r = cache_get_cached_control(cache, cmd, arg); if (r != STREAM_ERROR) goto done; mp_msg(MSGT_CACHE, MSGL_V, "[cache] blocking for STREAM_CTRL %d\n", cmd); s->control = cmd; s->control_arg = arg; double retry = 0; while (s->control != CACHE_CTRL_NONE) { if (cache_wakeup_and_wait(s, &retry) == CACHE_INTERRUPTED) { s->eof = 1; r = STREAM_UNSUPPORTED; goto done; } } r = s->control_res; if (s->control_flush) { cache->pos = s->read_filepos; cache->eof = 0; cache->buf_pos = cache->buf_len = 0; } done: pthread_mutex_unlock(&s->mutex); return r; }