all repos — mgba @ 812d063b73cf9231123e9600160d4f4d0eb7a8cf

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, size_t maxalloc) {
20	buffer->data = anonymousMemoryMap(capacity);
21	buffer->capacity = capacity;
22	buffer->maxalloc = maxalloc;
23	RingFIFOClear(buffer);
24}
25
26void RingFIFODeinit(struct RingFIFO* buffer) {
27	mappedMemoryFree(buffer->data, buffer->capacity);
28	buffer->data = 0;
29}
30
31size_t RingFIFOCapacity(const struct RingFIFO* buffer) {
32	return buffer->capacity;
33}
34
35void RingFIFOClear(struct RingFIFO* buffer) {
36	ATOMIC_STORE(buffer->readPtr, buffer->data);
37	ATOMIC_STORE(buffer->writePtr, buffer->data);
38}
39
40size_t RingFIFOWrite(struct RingFIFO* buffer, const void* value, size_t length) {
41	void* data = buffer->writePtr;
42	void* end;
43	ATOMIC_LOAD(end, buffer->readPtr);
44	size_t remaining;
45	if ((intptr_t) data - (intptr_t) buffer->data + buffer->maxalloc >= buffer->capacity) {
46		data = buffer->data;
47	}
48	if (data >= end) {
49		remaining = (intptr_t) buffer->data + buffer->capacity - (intptr_t) data;
50	} else {
51		remaining = (intptr_t) end - (intptr_t) data;
52	}
53	if (remaining <= length) {
54		return 0;
55	}
56	if (value) {
57		memcpy(data, value, length);
58	}
59	ATOMIC_STORE(buffer->writePtr, (void*) ((intptr_t) data + length));
60	return length;
61}
62
63size_t RingFIFORead(struct RingFIFO* buffer, void* output, size_t length) {
64	void* data = buffer->readPtr;
65	void* end;
66	ATOMIC_LOAD(end, buffer->writePtr);
67	size_t remaining;
68	if ((intptr_t) data - (intptr_t) buffer->data + buffer->maxalloc >= buffer->capacity) {
69		data = buffer->data;
70	}
71	if (data > end) {
72		remaining = (intptr_t) buffer->data + buffer->capacity - (intptr_t) data;
73	} else {
74		remaining = (intptr_t) end - (intptr_t) data;
75	}
76	if (remaining <= length) {
77		return 0;
78	}
79	if (output) {
80		memcpy(output, data, length);
81	}
82	ATOMIC_STORE(buffer->readPtr, (void*) ((intptr_t) data + length));
83	return length;
84}