src/util/ring-fifo.c (view raw)
1/* Copyright (c) 2013-2014 Jeffrey Pfau
2 *
3 * This Source Code Form is subject to the terms of the Mozilla Public
4 * License, v. 2.0. If a copy of the MPL was not distributed with this
5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
6#include <mgba-util/ring-fifo.h>
7
8#include <mgba-util/memory.h>
9
10void RingFIFOInit(struct RingFIFO* buffer, size_t capacity) {
11 buffer->data = anonymousMemoryMap(capacity);
12 buffer->capacity = capacity;
13 RingFIFOClear(buffer);
14}
15
16void RingFIFODeinit(struct RingFIFO* buffer) {
17 mappedMemoryFree(buffer->data, buffer->capacity);
18 buffer->data = 0;
19}
20
21size_t RingFIFOCapacity(const struct RingFIFO* buffer) {
22 return buffer->capacity;
23}
24
25void RingFIFOClear(struct RingFIFO* buffer) {
26 ATOMIC_STORE(buffer->readPtr, buffer->data);
27 ATOMIC_STORE(buffer->writePtr, buffer->data);
28}
29
30size_t RingFIFOWrite(struct RingFIFO* buffer, const void* value, size_t length) {
31 void* data = buffer->writePtr;
32 void* end;
33 ATOMIC_LOAD(end, buffer->readPtr);
34
35 // Wrap around if we can't fit enough in here
36 if ((intptr_t) data - (intptr_t) buffer->data + length >= buffer->capacity) {
37 if (end == buffer->data) {
38 // Oops! If we wrap now, it'll appear empty
39 return 0;
40 }
41 data = buffer->data;
42 }
43
44 size_t remaining;
45 if (data >= end) {
46 uintptr_t bufferEnd = (uintptr_t) buffer->data + buffer->capacity;
47 remaining = bufferEnd - (uintptr_t) data;
48 } else {
49 remaining = (uintptr_t) end - (uintptr_t) data;
50 }
51 // Note that we can't hit the end pointer
52 if (remaining <= length) {
53 return 0;
54 }
55 if (value) {
56 memcpy(data, value, length);
57 }
58 ATOMIC_STORE(buffer->writePtr, (void*) ((intptr_t) data + length));
59 return length;
60}
61
62size_t RingFIFORead(struct RingFIFO* buffer, void* output, size_t length) {
63 void* data = buffer->readPtr;
64 void* end;
65 ATOMIC_LOAD(end, buffer->writePtr);
66
67 // Wrap around if we can't fit enough in here
68 if ((intptr_t) data - (intptr_t) buffer->data + length >= buffer->capacity) {
69 if (end == data) {
70 // Oops! If we wrap now, it'll appear full
71 return 0;
72 }
73 data = buffer->data;
74 }
75
76 size_t remaining;
77 if (data > end) {
78 uintptr_t bufferEnd = (uintptr_t) buffer->data + buffer->capacity;
79 remaining = bufferEnd - (uintptr_t) data;
80 } else {
81 remaining = (intptr_t) end - (intptr_t) data;
82 }
83 // If the pointers touch, it's empty
84 if (remaining < length) {
85 return 0;
86 }
87 if (output) {
88 memcpy(output, data, length);
89 }
90 ATOMIC_STORE(buffer->readPtr, (void*) ((intptr_t) data + length));
91 return length;
92}