summaryrefslogtreecommitdiff
path: root/src/common/threadsafe_queue.h
diff options
context:
space:
mode:
authorGravatar B3n302017-11-25 14:56:57 +0100
committerGravatar bunnei2018-01-08 19:10:25 -0500
commit82151d407d8021fa8865cf8dd51c4d5cf0a4b702 (patch)
tree739df280fddbecb50e1a2fa690abe8749486ea2d /src/common/threadsafe_queue.h
parentIPC: Make DuplicateSession return the Domain instead of the Session if the re... (diff)
downloadyuzu-82151d407d8021fa8865cf8dd51c4d5cf0a4b702.tar.gz
yuzu-82151d407d8021fa8865cf8dd51c4d5cf0a4b702.tar.xz
yuzu-82151d407d8021fa8865cf8dd51c4d5cf0a4b702.zip
CoreTiming: Reworked CoreTiming (cherry-picked from Citra #3119)
* CoreTiming: New CoreTiming; Add Test for CoreTiming
Diffstat (limited to 'src/common/threadsafe_queue.h')
-rw-r--r--src/common/threadsafe_queue.h122
1 files changed, 122 insertions, 0 deletions
diff --git a/src/common/threadsafe_queue.h b/src/common/threadsafe_queue.h
new file mode 100644
index 000000000..a0c731e8c
--- /dev/null
+++ b/src/common/threadsafe_queue.h
@@ -0,0 +1,122 @@
1// Copyright 2010 Dolphin Emulator Project
2// Licensed under GPLv2+
3// Refer to the license.txt file included.
4
5#pragma once
6
7// a simple lockless thread-safe,
8// single reader, single writer queue
9
10#include <algorithm>
11#include <atomic>
12#include <cstddef>
13#include <mutex>
14#include "common/common_types.h"
15
16namespace Common {
17template <typename T, bool NeedSize = true>
18class SPSCQueue {
19public:
20 SPSCQueue() : size(0) {
21 write_ptr = read_ptr = new ElementPtr();
22 }
23 ~SPSCQueue() {
24 // this will empty out the whole queue
25 delete read_ptr;
26 }
27
28 u32 Size() const {
29 static_assert(NeedSize, "using Size() on FifoQueue without NeedSize");
30 return size.load();
31 }
32
33 bool Empty() const {
34 return !read_ptr->next.load();
35 }
36 T& Front() const {
37 return read_ptr->current;
38 }
39 template <typename Arg>
40 void Push(Arg&& t) {
41 // create the element, add it to the queue
42 write_ptr->current = std::forward<Arg>(t);
43 // set the next pointer to a new element ptr
44 // then advance the write pointer
45 ElementPtr* new_ptr = new ElementPtr();
46 write_ptr->next.store(new_ptr, std::memory_order_release);
47 write_ptr = new_ptr;
48 if (NeedSize)
49 size++;
50 }
51
52 void Pop() {
53 if (NeedSize)
54 size--;
55 ElementPtr* tmpptr = read_ptr;
56 // advance the read pointer
57 read_ptr = tmpptr->next.load();
58 // set the next element to nullptr to stop the recursive deletion
59 tmpptr->next.store(nullptr);
60 delete tmpptr; // this also deletes the element
61 }
62
63 bool Pop(T& t) {
64 if (Empty())
65 return false;
66
67 if (NeedSize)
68 size--;
69
70 ElementPtr* tmpptr = read_ptr;
71 read_ptr = tmpptr->next.load(std::memory_order_acquire);
72 t = std::move(tmpptr->current);
73 tmpptr->next.store(nullptr);
74 delete tmpptr;
75 return true;
76 }
77
78 // not thread-safe
79 void Clear() {
80 size.store(0);
81 delete read_ptr;
82 write_ptr = read_ptr = new ElementPtr();
83 }
84
85private:
86 // stores a pointer to element
87 // and a pointer to the next ElementPtr
88 class ElementPtr {
89 public:
90 ElementPtr() : next(nullptr) {}
91 ~ElementPtr() {
92 ElementPtr* next_ptr = next.load();
93
94 if (next_ptr)
95 delete next_ptr;
96 }
97
98 T current;
99 std::atomic<ElementPtr*> next;
100 };
101
102 ElementPtr* write_ptr;
103 ElementPtr* read_ptr;
104 std::atomic<u32> size;
105};
106
107// a simple thread-safe,
108// single reader, multiple writer queue
109
110template <typename T, bool NeedSize = true>
111class MPSCQueue : public SPSCQueue<T, NeedSize> {
112public:
113 template <typename Arg>
114 void Push(Arg&& t) {
115 std::lock_guard<std::mutex> lock(write_lock);
116 SPSCQueue<T, NeedSize>::Push(t);
117 }
118
119private:
120 std::mutex write_lock;
121};
122} // namespace Common