-
Notifications
You must be signed in to change notification settings - Fork 8
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Store window events instead of handling them. (#43)
- Loading branch information
1 parent
267d216
commit d6b3ff3
Showing
3 changed files
with
165 additions
and
12 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,125 @@ | ||
/* | ||
* Copyright (C) Nemirtingas | ||
* This file is part of the ingame overlay project | ||
* | ||
* The ingame overlay project is free software; you can redistribute it | ||
* and/or modify it under the terms of the GNU Lesser General Public | ||
* License as published by the Free Software Foundation; either | ||
* version 3 of the License, or (at your option) any later version. | ||
* | ||
* The ingame overlay project is distributed in the hope that it will be | ||
* useful, but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
* Lesser General Public License for more details. | ||
* | ||
* You should have received a copy of the GNU Lesser General Public | ||
* License along with the ingame overlay project; if not, see | ||
* <http://www.gnu.org/licenses/>. | ||
*/ | ||
|
||
#pragma once | ||
|
||
#include <atomic> | ||
#include <cassert> | ||
|
||
template<typename T> | ||
class mpmc_bounded_queue | ||
{ | ||
public: | ||
mpmc_bounded_queue(size_t buffer_size) | ||
: buffer_(new cell_t[buffer_size]) | ||
, buffer_mask_(buffer_size - 1) | ||
{ | ||
assert((buffer_size >= 2) && ((buffer_size & (buffer_size - 1)) == 0)); | ||
for (size_t i = 0; i != buffer_size; i += 1) | ||
buffer_[i].sequence_.store(i, std::memory_order_relaxed); | ||
enqueue_pos_.store(0, std::memory_order_relaxed); | ||
dequeue_pos_.store(0, std::memory_order_relaxed); | ||
item_count_.store(0, std::memory_order_relaxed); | ||
} | ||
|
||
~mpmc_bounded_queue() | ||
{ | ||
delete[] buffer_; | ||
} | ||
|
||
bool enqueue(T const& data) | ||
{ | ||
cell_t* cell; | ||
size_t pos = enqueue_pos_.load(std::memory_order_relaxed); | ||
|
||
for (;;) | ||
{ | ||
cell = &buffer_[pos & buffer_mask_]; | ||
size_t seq = cell->sequence_.load(std::memory_order_acquire); | ||
intptr_t dif = (intptr_t)seq - (intptr_t)pos; | ||
if (dif == 0) | ||
{ | ||
if (enqueue_pos_.compare_exchange_weak(pos, pos + 1, std::memory_order_relaxed)) | ||
break; | ||
} | ||
else if (dif < 0) | ||
return false; | ||
else | ||
pos = enqueue_pos_.load(std::memory_order_relaxed); | ||
} | ||
cell->data_ = data; | ||
item_count_.fetch_sub(1, std::memory_order_relaxed); | ||
cell->sequence_.store(pos + 1, std::memory_order_release); | ||
return true; | ||
} | ||
|
||
bool dequeue(T& data) | ||
{ | ||
cell_t* cell; | ||
size_t pos = dequeue_pos_.load(std::memory_order_relaxed); | ||
|
||
for (;;) | ||
{ | ||
cell = &buffer_[pos & buffer_mask_]; | ||
size_t seq = cell->sequence_.load(std::memory_order_acquire); | ||
intptr_t dif = (intptr_t)seq - (intptr_t)(pos + 1); | ||
if (dif == 0) | ||
{ | ||
if (dequeue_pos_.compare_exchange_weak(pos, pos + 1, std::memory_order_relaxed)) | ||
break; | ||
} | ||
else if (dif < 0) | ||
return false; | ||
else | ||
pos = dequeue_pos_.load(std::memory_order_relaxed); | ||
} | ||
data = cell->data_; | ||
item_count_.fetch_sub(1, std::memory_order_relaxed); | ||
cell->sequence_.store(pos + buffer_mask_ + 1, std::memory_order_release); | ||
return true; | ||
} | ||
|
||
size_t queue_size() const | ||
{ | ||
return item_count_.load(std::memory_order_relaxed); | ||
} | ||
|
||
private: | ||
struct cell_t | ||
{ | ||
std::atomic<size_t> sequence_; | ||
T data_; | ||
}; | ||
|
||
static size_t const cacheline_size = 64; | ||
typedef char cacheline_pad_t[cacheline_size]; | ||
cacheline_pad_t pad0_; | ||
cell_t* const buffer_; | ||
size_t const buffer_mask_; | ||
cacheline_pad_t pad1_; | ||
std::atomic<size_t> enqueue_pos_; | ||
cacheline_pad_t pad2_; | ||
std::atomic<size_t> dequeue_pos_; | ||
cacheline_pad_t pad3_; | ||
std::atomic<size_t> item_count_; | ||
cacheline_pad_t pad4_; | ||
|
||
mpmc_bounded_queue(mpmc_bounded_queue const&) = delete; | ||
void operator=(mpmc_bounded_queue const&) = delete; | ||
}; |