diff options
| author | 2018-09-09 13:08:57 +0200 | |
|---|---|---|
| committer | 2019-02-15 22:12:54 +0100 | |
| commit | 41549365680f0aae3f82e5812f3470305e939f7d (patch) | |
| tree | 027ec302d0119e4ded6cc4627c6fa3a94c8699ec /src | |
| parent | Merge pull request #2112 from lioncash/shadowing (diff) | |
| download | yuzu-41549365680f0aae3f82e5812f3470305e939f7d.tar.gz yuzu-41549365680f0aae3f82e5812f3470305e939f7d.tar.xz yuzu-41549365680f0aae3f82e5812f3470305e939f7d.zip | |
threadsafe_queue: Add WaitIfEmpty and use it in logging
Diffstat (limited to 'src')
| -rw-r--r-- | src/common/logging/backend.cpp | 20 | ||||
| -rw-r--r-- | src/common/logging/backend.h | 1 | ||||
| -rw-r--r-- | src/common/threadsafe_queue.h | 19 |
3 files changed, 26 insertions, 14 deletions
diff --git a/src/common/logging/backend.cpp b/src/common/logging/backend.cpp index a5e031189..276e49f86 100644 --- a/src/common/logging/backend.cpp +++ b/src/common/logging/backend.cpp | |||
| @@ -40,9 +40,7 @@ public: | |||
| 40 | const Impl& operator=(Impl const&) = delete; | 40 | const Impl& operator=(Impl const&) = delete; |
| 41 | 41 | ||
| 42 | void PushEntry(Entry e) { | 42 | void PushEntry(Entry e) { |
| 43 | std::lock_guard<std::mutex> lock(message_mutex); | ||
| 44 | message_queue.Push(std::move(e)); | 43 | message_queue.Push(std::move(e)); |
| 45 | message_cv.notify_one(); | ||
| 46 | } | 44 | } |
| 47 | 45 | ||
| 48 | void AddBackend(std::unique_ptr<Backend> backend) { | 46 | void AddBackend(std::unique_ptr<Backend> backend) { |
| @@ -85,16 +83,13 @@ private: | |||
| 85 | backend->Write(e); | 83 | backend->Write(e); |
| 86 | } | 84 | } |
| 87 | }; | 85 | }; |
| 88 | while (true) { | 86 | while (message_queue.PopWait(entry)) { |
| 89 | { | 87 | if (entry.final_entry) { |
| 90 | std::unique_lock<std::mutex> lock(message_mutex); | ||
| 91 | message_cv.wait(lock, [&] { return !running || message_queue.Pop(entry); }); | ||
| 92 | } | ||
| 93 | if (!running) { | ||
| 94 | break; | 88 | break; |
| 95 | } | 89 | } |
| 96 | write_logs(entry); | 90 | write_logs(entry); |
| 97 | } | 91 | } |
| 92 | |||
| 98 | // Drain the logging queue. Only writes out up to MAX_LOGS_TO_WRITE to prevent a case | 93 | // Drain the logging queue. Only writes out up to MAX_LOGS_TO_WRITE to prevent a case |
| 99 | // where a system is repeatedly spamming logs even on close. | 94 | // where a system is repeatedly spamming logs even on close. |
| 100 | const int MAX_LOGS_TO_WRITE = filter.IsDebug() ? INT_MAX : 100; | 95 | const int MAX_LOGS_TO_WRITE = filter.IsDebug() ? INT_MAX : 100; |
| @@ -106,14 +101,13 @@ private: | |||
| 106 | } | 101 | } |
| 107 | 102 | ||
| 108 | ~Impl() { | 103 | ~Impl() { |
| 109 | running = false; | 104 | Entry entry; |
| 110 | message_cv.notify_one(); | 105 | entry.final_entry = true; |
| 106 | message_queue.Push(entry); | ||
| 111 | backend_thread.join(); | 107 | backend_thread.join(); |
| 112 | } | 108 | } |
| 113 | 109 | ||
| 114 | std::atomic_bool running{true}; | 110 | std::mutex writing_mutex; |
| 115 | std::mutex message_mutex, writing_mutex; | ||
| 116 | std::condition_variable message_cv; | ||
| 117 | std::thread backend_thread; | 111 | std::thread backend_thread; |
| 118 | std::vector<std::unique_ptr<Backend>> backends; | 112 | std::vector<std::unique_ptr<Backend>> backends; |
| 119 | Common::MPSCQueue<Log::Entry> message_queue; | 113 | Common::MPSCQueue<Log::Entry> message_queue; |
diff --git a/src/common/logging/backend.h b/src/common/logging/backend.h index 91bb0c309..a31ee6968 100644 --- a/src/common/logging/backend.h +++ b/src/common/logging/backend.h | |||
| @@ -27,6 +27,7 @@ struct Entry { | |||
| 27 | unsigned int line_num; | 27 | unsigned int line_num; |
| 28 | std::string function; | 28 | std::string function; |
| 29 | std::string message; | 29 | std::string message; |
| 30 | bool final_entry = false; | ||
| 30 | 31 | ||
| 31 | Entry() = default; | 32 | Entry() = default; |
| 32 | Entry(Entry&& o) = default; | 33 | Entry(Entry&& o) = default; |
diff --git a/src/common/threadsafe_queue.h b/src/common/threadsafe_queue.h index f553efdc9..4fdcecca0 100644 --- a/src/common/threadsafe_queue.h +++ b/src/common/threadsafe_queue.h | |||
| @@ -8,6 +8,7 @@ | |||
| 8 | // single reader, single writer queue | 8 | // single reader, single writer queue |
| 9 | 9 | ||
| 10 | #include <atomic> | 10 | #include <atomic> |
| 11 | #include <condition_variable> | ||
| 11 | #include <cstddef> | 12 | #include <cstddef> |
| 12 | #include <mutex> | 13 | #include <mutex> |
| 13 | #include <utility> | 14 | #include <utility> |
| @@ -39,12 +40,13 @@ public: | |||
| 39 | template <typename Arg> | 40 | template <typename Arg> |
| 40 | void Push(Arg&& t) { | 41 | void Push(Arg&& t) { |
| 41 | // create the element, add it to the queue | 42 | // create the element, add it to the queue |
| 42 | write_ptr->current = std::forward<Arg>(t); | 43 | write_ptr->current = std::move(t); |
| 43 | // set the next pointer to a new element ptr | 44 | // set the next pointer to a new element ptr |
| 44 | // then advance the write pointer | 45 | // then advance the write pointer |
| 45 | ElementPtr* new_ptr = new ElementPtr(); | 46 | ElementPtr* new_ptr = new ElementPtr(); |
| 46 | write_ptr->next.store(new_ptr, std::memory_order_release); | 47 | write_ptr->next.store(new_ptr, std::memory_order_release); |
| 47 | write_ptr = new_ptr; | 48 | write_ptr = new_ptr; |
| 49 | cv.notify_one(); | ||
| 48 | 50 | ||
| 49 | ++size; | 51 | ++size; |
| 50 | } | 52 | } |
| @@ -67,6 +69,7 @@ public: | |||
| 67 | --size; | 69 | --size; |
| 68 | 70 | ||
| 69 | ElementPtr* tmpptr = read_ptr; | 71 | ElementPtr* tmpptr = read_ptr; |
| 72 | |||
| 70 | read_ptr = tmpptr->next.load(std::memory_order_acquire); | 73 | read_ptr = tmpptr->next.load(std::memory_order_acquire); |
| 71 | t = std::move(tmpptr->current); | 74 | t = std::move(tmpptr->current); |
| 72 | tmpptr->next.store(nullptr); | 75 | tmpptr->next.store(nullptr); |
| @@ -74,6 +77,14 @@ public: | |||
| 74 | return true; | 77 | return true; |
| 75 | } | 78 | } |
| 76 | 79 | ||
| 80 | bool PopWait(T& t) { | ||
| 81 | if (Empty()) { | ||
| 82 | std::unique_lock<std::mutex> lock(cv_mutex); | ||
| 83 | cv.wait(lock, [this]() { return !Empty(); }); | ||
| 84 | } | ||
| 85 | return Pop(t); | ||
| 86 | } | ||
| 87 | |||
| 77 | // not thread-safe | 88 | // not thread-safe |
| 78 | void Clear() { | 89 | void Clear() { |
| 79 | size.store(0); | 90 | size.store(0); |
| @@ -101,6 +112,8 @@ private: | |||
| 101 | ElementPtr* write_ptr; | 112 | ElementPtr* write_ptr; |
| 102 | ElementPtr* read_ptr; | 113 | ElementPtr* read_ptr; |
| 103 | std::atomic_size_t size{0}; | 114 | std::atomic_size_t size{0}; |
| 115 | std::mutex cv_mutex; | ||
| 116 | std::condition_variable cv; | ||
| 104 | }; | 117 | }; |
| 105 | 118 | ||
| 106 | // a simple thread-safe, | 119 | // a simple thread-safe, |
| @@ -135,6 +148,10 @@ public: | |||
| 135 | return spsc_queue.Pop(t); | 148 | return spsc_queue.Pop(t); |
| 136 | } | 149 | } |
| 137 | 150 | ||
| 151 | bool PopWait(T& t) { | ||
| 152 | return spsc_queue.PopWait(t); | ||
| 153 | } | ||
| 154 | |||
| 138 | // not thread-safe | 155 | // not thread-safe |
| 139 | void Clear() { | 156 | void Clear() { |
| 140 | spsc_queue.Clear(); | 157 | spsc_queue.Clear(); |