Skip to content

Commit 8c8c476

Browse files
committed
port the windows_thread_pool from libunifex
1 parent 3a65e6a commit 8c8c476

9 files changed

Lines changed: 1269 additions & 16 deletions

CMakeLists.txt

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -524,6 +524,12 @@ if (CMAKE_SYSTEM_NAME STREQUAL "Darwin")
524524
target_compile_definitions(stdexec INTERFACE STDEXEC_ENABLE_LIBDISPATCH)
525525
endif()
526526

527+
if (CMAKE_SYSTEM_NAME STREQUAL "Windows")
528+
CHECK_INCLUDE_FILE_CXX("windows.h" STDEXEC_FOUND_WINDOWS_HEADER)
529+
option(STDEXEC_ENABLE_WINDOWS_THREAD_POOL "Enable use of the Windows Thread Pool scheduler" ${STDEXEC_FOUND_WINDOWS_HEADER})
530+
target_compile_definitions(stdexec INTERFACE STDEXEC_ENABLE_WINDOWS_THREAD_POOL)
531+
endif()
532+
527533
option (STDEXEC_ENABLE_NUMA "Enable NUMA affinity for static_thread_pool" OFF)
528534
if (STDEXEC_ENABLE_NUMA)
529535
find_package(numa REQUIRED)

include/exec/__detail/__system_context_default_impl.hpp

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,8 @@
2222
# include "../libdispatch_queue.hpp" // IWYU pragma: keep
2323
#elif STDEXEC_ENABLE_IO_URING
2424
# include "../linux/io_uring_context.hpp" // IWYU pragma: keep
25+
#elif STDEXEC_ENABLE_WINDOWS_THREAD_POOL
26+
# include "../windows/windows_thread_pool.hpp" // IWYU pragma: keep
2527
#else
2628
# include "../static_thread_pool.hpp" // IWYU pragma: keep
2729
#endif
@@ -201,7 +203,7 @@ namespace exec::__system_context_default_impl {
201203
}
202204

203205
uint32_t __end(uint32_t __chunk_index) const noexcept {
204-
return std::min(__begin(__chunk_index + 1), __max_size_);
206+
return (std::min)(__begin(__chunk_index + 1), __max_size_);
205207
}
206208
};
207209

@@ -370,6 +372,8 @@ namespace exec::__system_context_default_impl {
370372
using __parallel_scheduler_backend_impl = __generic_impl<exec::libdispatch_queue>;
371373
#elif STDEXEC_ENABLE_IO_URING
372374
using __parallel_scheduler_backend_impl = __generic_impl<exec::io_uring_context>;
375+
#elif STDEXEC_ENABLE_WINDOWS_THREAD_POOL
376+
using __parallel_scheduler_backend_impl = __generic_impl<exec::windows_thread_pool>;
373377
#else
374378
using __parallel_scheduler_backend_impl = __generic_impl<exec::static_thread_pool>;
375379
#endif

include/exec/repeat_effect_until.hpp

Lines changed: 40 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -24,12 +24,11 @@
2424
#include "trampoline_scheduler.hpp"
2525

2626
#include <atomic>
27-
#include <concepts>
2827
#include <exception>
2928
#include <type_traits>
3029

3130
namespace exec {
32-
namespace __repeat_effect_until {
31+
namespace __repeat_effect {
3332
using namespace stdexec;
3433

3534
template <class _Sender, class _Receiver>
@@ -66,7 +65,6 @@ namespace exec {
6665
};
6766

6867
STDEXEC_PRAGMA_PUSH()
69-
7068
STDEXEC_PRAGMA_IGNORE_GNU("-Wtsan")
7169

7270
template <class _Sender, class _Receiver>
@@ -173,6 +171,7 @@ namespace exec {
173171
__error_t
174172
>;
175173

174+
struct __repeat_effect_tag { };
176175
struct __repeat_effect_until_tag { };
177176

178177
struct __repeat_effect_until_impl : __sexpr_defaults {
@@ -214,22 +213,55 @@ namespace exec {
214213
});
215214
}
216215
};
217-
} // namespace __repeat_effect_until
218216

219-
using __repeat_effect_until::repeat_effect_until_t;
217+
struct repeat_effect_t {
218+
struct _never {
219+
template <class... _Args>
220+
STDEXEC_ATTRIBUTE(host, device, always_inline)
221+
constexpr auto operator()(_Args &&...) const noexcept -> bool{
222+
return false;
223+
}
224+
};
225+
226+
template <sender _Sender>
227+
auto operator()(_Sender &&__sndr) const {
228+
auto __domain = __get_early_domain(__sndr);
229+
return stdexec::transform_sender(
230+
__domain, __make_sexpr<repeat_effect_t>({}, static_cast<_Sender &&>(__sndr)));
231+
}
232+
233+
STDEXEC_ATTRIBUTE(always_inline)
234+
constexpr auto operator()() const -> __binder_back<repeat_effect_t> {
235+
return {{}, {}, {}};
236+
}
237+
238+
template <class _Sender>
239+
auto transform_sender(_Sender &&__sndr, __ignore) {
240+
return __sexpr_apply(
241+
static_cast<_Sender &&>(__sndr), []<class _Child>(__ignore, __ignore, _Child __child) {
242+
return repeat_effect_until_t{}(stdexec::then(std::move(__child)), _never{});
243+
});
244+
}
245+
};
246+
} // namespace __repeat_effect
247+
248+
using __repeat_effect::repeat_effect_until_t;
220249
inline constexpr repeat_effect_until_t repeat_effect_until{};
250+
251+
using __repeat_effect::repeat_effect_t;
252+
inline constexpr repeat_effect_t repeat_effect{};
221253
} // namespace exec
222254

223255
namespace stdexec {
224256
template <>
225-
struct __sexpr_impl<exec::__repeat_effect_until::__repeat_effect_until_tag>
226-
: exec::__repeat_effect_until::__repeat_effect_until_impl { }; // namespace stdexec
257+
struct __sexpr_impl<exec::__repeat_effect::__repeat_effect_until_tag>
258+
: exec::__repeat_effect::__repeat_effect_until_impl { }; // namespace stdexec
227259

228260
template <>
229261
struct __sexpr_impl<exec::repeat_effect_until_t> : __sexpr_defaults {
230262
static constexpr auto get_completion_signatures =
231263
[]<class _Sender>(
232-
_Sender &&) noexcept -> exec::__repeat_effect_until::__completions_t<__data_of<_Sender>> {
264+
_Sender &&) noexcept -> exec::__repeat_effect::__completions_t<__data_of<_Sender>> {
233265
return {};
234266
};
235267
};

include/exec/system_context.hpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -378,7 +378,7 @@ namespace exec {
378378
// If we are not parallelizing, we need to run all the iterations sequentially.
379379
uint32_t __increments = 1;
380380
if constexpr (!_BulkState::__parallelize) {
381-
__increments = __state->__size_;
381+
__increments = static_cast<uint32_t>(__state->__size_);
382382
}
383383
for (uint32_t __i = __begin; __i < __begin + __increments; __i++) {
384384
std::apply(
@@ -389,7 +389,7 @@ namespace exec {
389389
// If we are not parallelizing, we need to pass the entire range to the functor.
390390
if constexpr (!_BulkState::__parallelize) {
391391
__begin = 0;
392-
__end = __state->__size_;
392+
__end = static_cast<uint32_t>(__state->__size_);
393393
}
394394
std::apply(
395395
[&](auto&&... __args) { __state->__fun_(__begin, __end, __args...); },
Lines changed: 144 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,144 @@
1+
/*
2+
* Copyright (c) Facebook, Inc. and its affiliates.
3+
*
4+
* Licensed under the Apache License Version 2.0 with LLVM Exceptions
5+
* (the "License"); you may not use this file except in compliance with
6+
* the License. You may obtain a copy of the License at
7+
*
8+
* https://llvm.org/LICENSE.txt
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
#pragma once
17+
18+
#include <chrono>
19+
#include <cstdint>
20+
21+
#include <windows.h>
22+
23+
namespace exec::__win32 {
24+
25+
class filetime_clock {
26+
public:
27+
using rep = std::int64_t;
28+
using ratio = std::ratio<1, 10'000'000>; // 100ns
29+
using duration = std::chrono::duration<rep, ratio>;
30+
31+
static constexpr bool is_steady = false;
32+
33+
class time_point {
34+
public:
35+
using duration = filetime_clock::duration;
36+
37+
constexpr time_point() noexcept = default;
38+
39+
constexpr time_point(const time_point &) noexcept = default;
40+
41+
auto operator=(const time_point &) noexcept -> time_point & = default;
42+
43+
[[nodiscard]] auto get_ticks() const noexcept -> std::uint64_t {
44+
return ticks_;
45+
}
46+
47+
static constexpr auto(max)() noexcept -> time_point {
48+
time_point tp;
49+
tp.ticks_ = (std::numeric_limits<std::int64_t>::max)();
50+
return tp;
51+
}
52+
53+
static constexpr auto(min)() noexcept -> time_point { return time_point{}; }
54+
55+
static auto from_ticks(std::uint64_t ticks) noexcept -> time_point {
56+
time_point tp;
57+
tp.ticks_ = ticks;
58+
return tp;
59+
}
60+
61+
template <typename Rep, typename Ratio>
62+
auto operator+=(const std::chrono::duration<Rep, Ratio> &d) noexcept
63+
-> time_point & {
64+
ticks_ += std::chrono::duration_cast<duration>(d).count();
65+
return *this;
66+
}
67+
68+
template <typename Rep, typename Ratio>
69+
auto operator-=(const std::chrono::duration<Rep, Ratio> &d) noexcept
70+
-> time_point & {
71+
ticks_ -= std::chrono::duration_cast<duration>(d).count();
72+
return *this;
73+
}
74+
75+
friend auto operator-(time_point a, time_point b) noexcept -> duration {
76+
return duration{a.ticks_} - duration{b.ticks_};
77+
}
78+
79+
template <typename Rep, typename Ratio>
80+
friend auto operator-(time_point t,
81+
std::chrono::duration<Rep, Ratio> d) noexcept
82+
-> time_point {
83+
time_point tp = t;
84+
tp -= d;
85+
return tp;
86+
}
87+
88+
template <typename Rep, typename Ratio>
89+
friend auto operator+(time_point t,
90+
std::chrono::duration<Rep, Ratio> d) noexcept
91+
-> time_point {
92+
time_point tp = t;
93+
tp += d;
94+
return tp;
95+
}
96+
97+
template <typename Rep, typename Ratio>
98+
friend auto operator+(std::chrono::duration<Rep, Ratio> d, time_point t) noexcept
99+
-> time_point {
100+
return t + d;
101+
}
102+
103+
friend auto operator==(time_point a, time_point b) noexcept -> bool {
104+
return a.ticks_ == b.ticks_;
105+
}
106+
107+
friend auto operator!=(time_point a, time_point b) noexcept -> bool {
108+
return a.ticks_ != b.ticks_;
109+
}
110+
111+
friend auto operator<(time_point a, time_point b) noexcept -> bool {
112+
return a.ticks_ < b.ticks_;
113+
}
114+
115+
friend auto operator>(time_point a, time_point b) noexcept -> bool {
116+
return a.ticks_ > b.ticks_;
117+
}
118+
119+
friend auto operator<=(time_point a, time_point b) noexcept -> bool {
120+
return a.ticks_ <= b.ticks_;
121+
}
122+
123+
friend auto operator>=(time_point a, time_point b) noexcept -> bool {
124+
return a.ticks_ >= b.ticks_;
125+
}
126+
127+
private:
128+
// Ticks since Jan 1, 1601 (UTC)
129+
std::uint64_t ticks_{};
130+
};
131+
132+
static auto now() noexcept -> time_point {
133+
FILETIME filetime;
134+
::GetSystemTimeAsFileTime(&filetime);
135+
136+
ULARGE_INTEGER ticks;
137+
ticks.HighPart = filetime.dwHighDateTime;
138+
ticks.LowPart = filetime.dwLowDateTime;
139+
140+
return time_point::from_ticks(ticks.QuadPart);
141+
}
142+
};
143+
144+
} // namespace exec::__win32

0 commit comments

Comments
 (0)