Skip to content

Commit 09e93c4

Browse files
AlexGutenievmisccostrega-nil-ms
authored andcommitted
Atomic wait: zero-initialize wait list head (microsoft#2781)
Co-authored-by: Michael Schellenberger Costa <[email protected]> Co-authored-by: nicole mazzuca <[email protected]>
1 parent 8fe945a commit 09e93c4

File tree

1 file changed

+22
-2
lines changed

1 file changed

+22
-2
lines changed

stl/src/atomic_wait.cpp

Lines changed: 22 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -62,8 +62,12 @@ namespace {
6262
#pragma warning(push)
6363
#pragma warning(disable : 4324) // structure was padded due to alignment specifier
6464
struct alignas(_STD hardware_destructive_interference_size) _Wait_table_entry {
65-
SRWLOCK _Lock = SRWLOCK_INIT;
66-
_Wait_context _Wait_list_head = {nullptr, &_Wait_list_head, &_Wait_list_head, CONDITION_VARIABLE_INIT};
65+
SRWLOCK _Lock = SRWLOCK_INIT;
66+
// Initialize to all zeros, self-link lazily to optimize for space.
67+
// Since _Wait_table_entry is initialized to all zero bytes,
68+
// _Atomic_wait_table_entry::wait_table will also be all zero bytes.
69+
// It can thus can be stored in the .bss section, and not in the actual binary.
70+
_Wait_context _Wait_list_head = {nullptr, nullptr, nullptr, CONDITION_VARIABLE_INIT};
6771

6872
constexpr _Wait_table_entry() noexcept = default;
6973
};
@@ -263,6 +267,11 @@ void __stdcall __std_atomic_notify_one_indirect(const void* const _Storage) noex
263267
auto& _Entry = _Atomic_wait_table_entry(_Storage);
264268
_SrwLock_guard _Guard(_Entry._Lock);
265269
_Wait_context* _Context = _Entry._Wait_list_head._Next;
270+
271+
if (_Context == nullptr) {
272+
return;
273+
}
274+
266275
for (; _Context != &_Entry._Wait_list_head; _Context = _Context->_Next) {
267276
if (_Context->_Storage == _Storage) {
268277
// Can't move wake outside SRWLOCKed section: SRWLOCK also protects the _Context itself
@@ -276,6 +285,11 @@ void __stdcall __std_atomic_notify_all_indirect(const void* const _Storage) noex
276285
auto& _Entry = _Atomic_wait_table_entry(_Storage);
277286
_SrwLock_guard _Guard(_Entry._Lock);
278287
_Wait_context* _Context = _Entry._Wait_list_head._Next;
288+
289+
if (_Context == nullptr) {
290+
return;
291+
}
292+
279293
for (; _Context != &_Entry._Wait_list_head; _Context = _Context->_Next) {
280294
if (_Context->_Storage == _Storage) {
281295
// Can't move wake outside SRWLOCKed section: SRWLOCK also protects the _Context itself
@@ -289,6 +303,12 @@ int __stdcall __std_atomic_wait_indirect(const void* _Storage, void* _Comparand,
289303
auto& _Entry = _Atomic_wait_table_entry(_Storage);
290304

291305
_SrwLock_guard _Guard(_Entry._Lock);
306+
307+
if (_Entry._Wait_list_head._Next == nullptr) {
308+
_Entry._Wait_list_head._Next = &_Entry._Wait_list_head;
309+
_Entry._Wait_list_head._Prev = &_Entry._Wait_list_head;
310+
}
311+
292312
_Guarded_wait_context _Context{_Storage, &_Entry._Wait_list_head};
293313
for (;;) {
294314
if (!_Are_equal(_Storage, _Comparand, _Size, _Param)) { // note: under lock to prevent lost wakes

0 commit comments

Comments
 (0)