Browse Source

Add the new mingw-std-threads files

Signed-off-by: falkTX <falktx@falktx.com>
pull/128/head
falkTX 1 year ago
parent
commit
b740231ed8
Signed by: falkTX <falktx@falktx.com> GPG Key ID: CDBAA37ABC74FBA0
3 changed files with 1264 additions and 0 deletions
  1. +9
    -0
      libs/mingw-std-threads/latch
  2. +1133
    -0
      libs/mingw-std-threads/mingw.future.h
  3. +122
    -0
      libs/mingw-std-threads/mingw.latch.h

+ 9
- 0
libs/mingw-std-threads/latch View File

@@ -0,0 +1,9 @@
// Copyright 2023 Filipe Coelho <falktx@falktx.com>
// SPDX-License-Identifier: 0BSD OR ISC

#pragma once
#include_next <latch>

#if __GNUC__ < 12
#include "mingw.latch.h"
#endif

+ 1133
- 0
libs/mingw-std-threads/mingw.future.h
File diff suppressed because it is too large
View File


+ 122
- 0
libs/mingw-std-threads/mingw.latch.h View File

@@ -0,0 +1,122 @@
/// \file mingw.latch.h
/// \brief std::latch implementation for MinGW.
///
/// (c) 2023 by Mega Limited, Auckland, New Zealand
/// \author Edoardo Sanguineti
///
/// \copyright Simplified (2-clause) BSD License.
///
/// \note This file may become part of the mingw-w64 runtime package. If/when
/// this happens, the appropriate license will be added, i.e. this code will
/// become dual-licensed, and the current BSD 2-clause license will stay.

// Notes on the namespaces:
// - The implementation can be accessed directly in the namespace
// mingw_stdthread.
// - Objects will be brought into namespace std by a using directive. This
// will cause objects declared in std (such as MinGW's implementation) to
// hide this implementation's definitions.
// The end result is that if MinGW supplies an object, it is automatically
// used. If MinGW does not supply an object, this implementation's version will
// instead be used.

#ifndef MINGW_LATCH_H_
#define MINGW_LATCH_H_

#if !defined(__cplusplus) || (__cplusplus < 202002L)
#error The contents of <latch> require a C++20 compiler!
#endif

#include <atomic>
#include <cassert> // for descriptive errors
#include <cstddef> // for std::ptrdiff_t
#include <limits> // for std::numeric_limits

namespace mingw_stdthread
{
class latch
{
public:
[[nodiscard]] static constexpr std::ptrdiff_t max() noexcept
{
return std::numeric_limits<std::ptrdiff_t>::max();
}

constexpr explicit latch(std::ptrdiff_t expected) noexcept : mCounter{expected}
{
assert(expected >= 0);
}

~latch()=default;
latch(const latch&)=delete;
latch& operator=(const latch&)=delete;

void count_down(std::ptrdiff_t update = 1)
{
assert(update >= 0);

const auto current = mCounter.fetch_sub(update, std::memory_order_release);

assert(update <= current);

if (current <= update)
{
mCounter.notify_all();
}
}

[[nodiscard]] bool try_wait() const noexcept
{
return mCounter.load(std::memory_order_acquire) <= 0;
}

/**
* The call to atomic::wait() may unblock with a non-zero counter in some edge cases (see GH-91 for an in-depth explanation)
* To address the edge cases this loop will continue to wait until the counter has been verified to have reached 0 (or less)
*/
void wait() const
{
while (true)
{
const auto current = mCounter.load(std::memory_order_acquire);
if (current <= 0)
{
return;
}

mCounter.wait(current, std::memory_order_relaxed);
}
}

void arrive_and_wait(const std::ptrdiff_t update = 1) noexcept
{
assert(update >= 0);

const auto current = mCounter.fetch_sub(update, std::memory_order_acq_rel);

assert(current <= update);

if (current == update)
{
mCounter.notify_all();
}
else
{
assert(current > 0);

mCounter.wait(current - update, std::memory_order_relaxed);
wait();
}
}

private:
std::atomic<std::ptrdiff_t> mCounter;
};
} // Namespace mingw_stdthread

namespace std
{
using mingw_stdthread::latch;
} // Namespace std

#endif // MINGW_LATCH_H_

Loading…
Cancel
Save