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 if (end == data) {
79 // Oops! If we wrap now, it'll appear full
80 return 0;
81 }
82 data = buffer->data;
83 }
84
85 size_t remaining;
86 if (data > end) {
87 uintptr_t bufferEnd = (uintptr_t) buffer->data + buffer->capacity;
88 remaining = bufferEnd - (uintptr_t) data;
89 } else {
90 remaining = (intptr_t) end - (intptr_t) data;
91 }
92 // If the pointers touch, it's empty
93 if (remaining < length) {
94 return 0;
95 }
96 if (output) {
97 memcpy(output, data, length);
98 }
99 ATOMIC_STORE(buffer->readPtr, (void*) ((intptr_t) data + length));
100 return length;
101}