diff --git a/apps/buffering.c b/apps/buffering.c index 0fd0c4c..5afb560 100644 --- a/apps/buffering.c +++ b/apps/buffering.c @@ -116,6 +116,7 @@ struct memory_handle { size_t filerem; /* Remaining bytes of file NOT in buffer */ volatile size_t available; /* Available bytes to read from buffer */ size_t offset; /* Offset at which we started reading the file */ + struct mutex mutex; struct memory_handle *next; }; /* invariant: filesize == offset + available + filerem */ @@ -272,6 +273,7 @@ static struct memory_handle *add_handle(size_t data_size, const bool can_wrap, /* only advance the buffer write index of the size of the struct */ buf_widx = RINGBUF_ADD(buf_widx, sizeof(struct memory_handle)); + mutex_init(&new_handle->mutex); new_handle->id = cur_handle_id; /* Use += 2 instead of ++ to guarantee that the low bit is always high and * prevent the assignment of a zero id when wrapping. */ @@ -601,6 +603,8 @@ static void reset_handle(int handle_id) if (!h) return; + mutex_lock(&h->mutex); + h->widx = h->data; if (h == cur_handle) buf_widx = h->widx; @@ -610,6 +614,8 @@ static void reset_handle(int handle_id) if (h->fd >= 0) { lseek(h->fd, h->offset, SEEK_SET); } + + mutex_unlock(&h->mutex); } /* Seek to a nonbuffered part of a handle by rebuffering the data. */ @@ -619,7 +625,11 @@ static void rebuffer_handle(int handle_id, size_t newpos) if (!h) return; + DEBUGF("rebuffer_handle\n"); + + mutex_lock(&h->mutex); h->offset = newpos; + mutex_unlock(&h->mutex); LOGFQUEUE("? >| buffering Q_RESET_HANDLE"); queue_send(&buffering_queue, Q_RESET_HANDLE, handle_id); @@ -627,7 +637,9 @@ static void rebuffer_handle(int handle_id, size_t newpos) LOGFQUEUE("? >| buffering Q_BUFFER_HANDLE"); queue_send(&buffering_queue, Q_BUFFER_HANDLE, handle_id); + mutex_lock(&h->mutex); h->ridx = h->data; + mutex_unlock(&h->mutex); } static bool close_handle(int handle_id) @@ -636,11 +648,15 @@ static bool close_handle(int handle_id) if (!h) return false; + mutex_lock(&h->mutex); + if (h->fd >= 0) { close(h->fd); h->fd = -1; } + mutex_unlock(&h->mutex); + rm_handle(h); return true; } @@ -651,22 +667,27 @@ static void shrink_handle(int handle_id) { size_t delta; struct memory_handle *h = find_handle(handle_id); - if (!h) return; + mutex_lock(&h->mutex); + if (h->next && (h->type == TYPE_ID3 || h->type == TYPE_CUESHEET || h->type == TYPE_IMAGE) && h->filerem == 0 ) { /* metadata handle: we can move all of it */ - size_t handle_distance = + size_t handle_distance = RINGBUF_SUB((unsigned)((void *)h->next - (void*)buffer), h->data); delta = handle_distance - h->available; + mutex_unlock(&h->mutex); + /* The value of delta might change for alignment reasons */ h = move_handle(h, &delta, h->available); if (!h) return; + mutex_lock(&h->mutex); + size_t olddata = h->data; h->data = RINGBUF_ADD(h->data, delta); h->ridx = RINGBUF_ADD(h->ridx, delta); @@ -683,13 +704,17 @@ static void shrink_handle(int handle_id) { /* only move the handle struct */ delta = RINGBUF_SUB(h->ridx, h->data); + mutex_unlock(&h->mutex); h = move_handle(h, &delta, 0); if (!h) return; + mutex_lock(&h->mutex); h->data = RINGBUF_ADD(h->data, delta); h->available -= delta; h->offset += delta; } + + mutex_unlock(&h->mutex); } /* Fill the buffer by buffering as much data as possible for handles that still @@ -744,6 +769,7 @@ void update_data_counters(void) m = first_handle; while (m) { + mutex_lock(&m->mutex); data_counters.buffered += m->available; data_counters.wasted += RINGBUF_SUB(m->ridx, m->data); data_counters.remaining += m->filerem; @@ -751,6 +777,7 @@ void update_data_counters(void) if (m->id >= base_handle_id) data_counters.useful += RINGBUF_SUB(m->widx, m->ridx); + mutex_unlock(&m->mutex); m = m->next; } } @@ -800,6 +827,8 @@ int bufopen(const char *file, size_t offset, enum data_type type) return BUFFER_FULL; } + mutex_lock(&h->mutex); + strncpy(h->path, file, MAX_PATH); h->filesize = size; h->filerem = size - offset; @@ -822,6 +851,8 @@ int bufopen(const char *file, size_t offset, enum data_type type) } logf("bufopen: new hdl %d", h->id); + + mutex_unlock(&h->mutex); return h->id; } @@ -842,6 +873,8 @@ int bufalloc(const void *src, size_t size, enum data_type type) if (!h) return BUFFER_FULL; + mutex_lock(&h->mutex); + if (src) { if (type == TYPE_ID3 && size == sizeof(struct mp3entry)) { /* specially take care of struct mp3entry */ @@ -866,6 +899,8 @@ int bufalloc(const void *src, size_t size, enum data_type type) buf_widx += size; /* safe too */ logf("bufalloc: new hdl %d", h->id); + + mutex_unlock(&h->mutex); return h->id; } @@ -890,8 +925,11 @@ int bufseek(int handle_id, size_t newpos) if (!h) return HANDLE_NOT_FOUND; + mutex_lock(&h->mutex); + if (newpos > h->filesize) { /* access beyond the end of the file */ + mutex_unlock(&h->mutex); return INVALID_VALUE; } else if (newpos < h->offset || h->offset + h->available < newpos) { @@ -901,6 +939,8 @@ int bufseek(int handle_id, size_t newpos) else { h->ridx = RINGBUF_ADD(h->data, newpos - h->offset); } + + mutex_unlock(&h->mutex); return 0; } @@ -908,36 +948,51 @@ int bufseek(int handle_id, size_t newpos) Return 0 for success and < 0 for failure */ int bufadvance(int handle_id, off_t offset) { - const struct memory_handle *h = find_handle(handle_id); + int ret; + struct memory_handle *h = find_handle(handle_id); if (!h) return HANDLE_NOT_FOUND; + mutex_lock(&h->mutex); size_t newpos = h->offset + RINGBUF_SUB(h->ridx, h->data) + offset; - return bufseek(handle_id, newpos); + ret = bufseek(handle_id, newpos); + mutex_unlock(&h->mutex); + return ret; } /* Copy data from the given handle to the dest buffer. Return the number of bytes copied or < 0 for failure. */ ssize_t bufread(int handle_id, size_t size, void *dest) { - const struct memory_handle *h = find_handle(handle_id); + struct memory_handle *h = find_handle(handle_id); if (!h) return HANDLE_NOT_FOUND; + mutex_lock(&h->mutex); + size_t ret; size_t copy_n = RINGBUF_SUB(h->widx, h->ridx); if (size == 0 && h->filerem > 0 && copy_n == 0) + { /* Data isn't ready */ + mutex_unlock(&h->mutex); return DATA_NOT_READY; + } if (copy_n < size && h->filerem > 0) + { /* Data isn't ready */ + mutex_unlock(&h->mutex); return DATA_NOT_READY; + } if (copy_n == 0 && h->filerem == 0) + { /* File is finished reading */ + mutex_unlock(&h->mutex); return 0; + } ret = MIN(size, copy_n); @@ -953,6 +1008,7 @@ ssize_t bufread(int handle_id, size_t size, void *dest) memcpy(dest, &buffer[h->ridx], ret); } + mutex_unlock(&h->mutex); return ret; } @@ -963,24 +1019,35 @@ ssize_t bufread(int handle_id, size_t size, void *dest) The guard buffer may be used to provide the requested size */ ssize_t bufgetdata(int handle_id, size_t size, void **data) { - const struct memory_handle *h = find_handle(handle_id); + struct memory_handle *h = find_handle(handle_id); if (!h) return HANDLE_NOT_FOUND; + mutex_lock(&h->mutex); + ssize_t ret; size_t copy_n = RINGBUF_SUB(h->widx, h->ridx); if (size == 0 && h->filerem > 0 && copy_n == 0) + { /* Data isn't ready */ + mutex_unlock(&h->mutex); return DATA_NOT_READY; + } if (copy_n < size && h->filerem > 0) + { /* Data isn't ready */ + mutex_unlock(&h->mutex); return DATA_NOT_READY; + } if (copy_n == 0 && h->filerem == 0) + { /* File is finished reading */ + mutex_unlock(&h->mutex); return 0; + } if (h->ridx + size > buffer_len && copy_n >= size) { @@ -996,6 +1063,7 @@ ssize_t bufgetdata(int handle_id, size_t size, void **data) } *data = &buffer[h->ridx]; + mutex_unlock(&h->mutex); return ret; } @@ -1019,19 +1087,28 @@ management functions for all the actual handle management work. /* Get a handle offset from a pointer */ ssize_t buf_get_offset(int handle_id, void *ptr) { - const struct memory_handle *h = find_handle(handle_id); + ssize_t ret; + struct memory_handle *h = find_handle(handle_id); if (!h) return HANDLE_NOT_FOUND; - return (size_t)ptr - (size_t)&buffer[h->ridx]; + mutex_lock(&h->mutex); + ret = (size_t)ptr - (size_t)&buffer[h->ridx]; + mutex_unlock(&h->mutex); + return ret; } ssize_t buf_handle_offset(int handle_id) { - const struct memory_handle *h = find_handle(handle_id); + ssize_t ret; + struct memory_handle *h = find_handle(handle_id); if (!h) return HANDLE_NOT_FOUND; - return h->offset; + + mutex_lock(&h->mutex); + ret = h->offset; + mutex_unlock(&h->mutex); + return ret; } void buf_request_buffer_handle(int handle_id)