all repos — mgba @ ac115422264c242439c19aaf383b6b743a309c69

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 "ring-fifo.h"
 7
 8#include "util/memory.h"
 9
10#ifndef _MSC_VER
11#define ATOMIC_STORE(DST, SRC) __atomic_store_n(&DST, SRC, __ATOMIC_RELEASE)
12#define ATOMIC_LOAD(DST, SRC) DST = __atomic_load_n(&SRC, __ATOMIC_ACQUIRE)
13#else
14// TODO
15#define ATOMIC_STORE(DST, SRC) DST = SRC
16#define ATOMIC_LOAD(DST, SRC) DST = SRC
17#endif
18
19void RingFIFOInit(struct RingFIFO* buffer, size_t capacity) {
20	buffer->data = anonymousMemoryMap(capacity);
21	buffer->capacity = capacity;
22	RingFIFOClear(buffer);
23}
24
25void RingFIFODeinit(struct RingFIFO* buffer) {
26	mappedMemoryFree(buffer->data, buffer->capacity);
27	buffer->data = 0;
28}
29
30size_t RingFIFOCapacity(const struct RingFIFO* buffer) {
31	return buffer->capacity;
32}
33
34void RingFIFOClear(struct RingFIFO* buffer) {
35	ATOMIC_STORE(buffer->readPtr, buffer->data);
36	ATOMIC_STORE(buffer->writePtr, buffer->data);
37}
38
39size_t RingFIFOWrite(struct RingFIFO* buffer, const void* value, size_t length) {
40	void* data = buffer->writePtr;
41	void* end;
42	ATOMIC_LOAD(end, buffer->readPtr);
43
44	// Wrap around if we can't fit enough in here
45	if ((intptr_t) data - (intptr_t) buffer->data + length >= buffer->capacity) {
46		if (end == buffer->data) {
47			// Oops! If we wrap now, it'll appear empty
48			return 0;
49		}
50		data = buffer->data;
51	}
52
53	size_t remaining;
54	if (data >= end) {
55		uintptr_t bufferEnd = (uintptr_t) buffer->data + buffer->capacity;
56		remaining = bufferEnd - (uintptr_t) data;
57	} else {
58		remaining = (uintptr_t) end - (uintptr_t) data;
59	}
60	// Note that we can't hit the end pointer
61	if (remaining <= length) {
62		return 0;
63	}
64	if (value) {
65		memcpy(data, value, length);
66	}
67	ATOMIC_STORE(buffer->writePtr, (void*) ((intptr_t) data + length));
68	return length;
69}
70
71size_t RingFIFORead(struct RingFIFO* buffer, void* output, size_t length) {
72	void* data = buffer->readPtr;
73	void* end;
74	ATOMIC_LOAD(end, buffer->writePtr);
75
76	// Wrap around if we can't fit enough in here
77	if ((intptr_t) data - (intptr_t) buffer->data + length >= buffer->capacity) {
78		data = buffer->data;
79	}
80
81	size_t remaining;
82	if (data > end) {
83		uintptr_t bufferEnd = (uintptr_t) buffer->data + buffer->capacity;
84		remaining = bufferEnd - (uintptr_t) data;
85	} else {
86		remaining = (intptr_t) end - (intptr_t) data;
87	}
88	// If the pointers touch, it's empty
89	if (remaining < length) {
90		return 0;
91	}
92	if (output) {
93		memcpy(output, data, length);
94	}
95	ATOMIC_STORE(buffer->readPtr, (void*) ((intptr_t) data + length));
96	return length;
97}