all repos — mgba @ fa884d071ecaa3e05ff20b45a67bf9500dd3d6b6

mGBA Game Boy Advance Emulator

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}