Skip to content

Commit c2b58ba

Browse files
committed
Refactor thread implementation in nt.h and impl.h for clarity and consistency
- Simplified the namespace structure for `fast_io::win32::nt`, improving organization. - Updated thread-related functions and constructors to use `inline constexpr` for better performance and clarity. - Enhanced error handling in sleep functions to ensure proper validation of input parameters. - Streamlined the usage of `nt_thread` and `this_thread` to improve readability and maintainability across the codebase.
1 parent 9ee1807 commit c2b58ba

File tree

2 files changed

+148
-69
lines changed

2 files changed

+148
-69
lines changed

include/fast_io_hosted/threads/thread/impl.h

Lines changed: 1 addition & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -1,41 +1,9 @@
11
#pragma once
22

33
#if (defined(_WIN32) && !defined(__WINE__)) && !defined(__CYGWIN__)
4-
#ifdef _WIN32_WINDOWS
54
#include "win32.h"
6-
7-
namespace fast_io
8-
{
9-
using thread = ::fast_io::win32::win32_thread;
10-
11-
namespace this_thread
12-
{
13-
14-
using ::fast_io::win32::this_thread::get_id;
15-
using ::fast_io::win32::this_thread::sleep_for;
16-
using ::fast_io::win32::this_thread::sleep_until;
17-
18-
} // namespace this_thread
19-
20-
} // namespace fast_io
21-
#else
5+
#ifndef _WIN32_WINDOWS
226
#include "nt.h"
23-
24-
namespace fast_io
25-
{
26-
template <bool zw = false>
27-
using thread = ::fast_io::win32::nt::nt_thread<zw>;
28-
29-
namespace this_thread
30-
{
31-
32-
using ::fast_io::win32::nt::this_thread::get_id;
33-
using ::fast_io::win32::nt::this_thread::sleep_for;
34-
using ::fast_io::win32::nt::this_thread::sleep_until;
35-
36-
} // namespace this_thread
37-
38-
} // namespace fast_io
397
#endif
408
#elif defined (__linux__)
419

include/fast_io_hosted/threads/thread/nt.h

Lines changed: 147 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -9,45 +9,50 @@
99
#include "../../../fast_io_dsal/tuple.h"
1010
#include "../../../fast_io_core_impl/allocation/common.h"
1111

12-
namespace fast_io::win32::nt
12+
namespace fast_io
13+
{
14+
namespace win32::nt
1315
{
1416

1517
namespace details
1618
{
1719

20+
template <typename Tuple>
1821
class nt_thread_start_routine_tuple_allocate_guard
1922
{
2023
public:
2124
void *ptr_{nullptr};
2225

23-
constexpr nt_thread_start_routine_tuple_allocate_guard() = default;
26+
inline constexpr nt_thread_start_routine_tuple_allocate_guard() = default;
2427

25-
constexpr nt_thread_start_routine_tuple_allocate_guard(void *ptr) : ptr_{ptr}
28+
inline constexpr nt_thread_start_routine_tuple_allocate_guard(void *ptr)
29+
: ptr_{ptr}
2630
{}
2731

28-
constexpr nt_thread_start_routine_tuple_allocate_guard(nt_thread_start_routine_tuple_allocate_guard const &) noexcept = delete;
29-
constexpr nt_thread_start_routine_tuple_allocate_guard(nt_thread_start_routine_tuple_allocate_guard &&other) noexcept = default;
32+
inline constexpr nt_thread_start_routine_tuple_allocate_guard(nt_thread_start_routine_tuple_allocate_guard const &) noexcept = delete;
33+
inline constexpr nt_thread_start_routine_tuple_allocate_guard(nt_thread_start_routine_tuple_allocate_guard &&other) noexcept = default;
3034

31-
constexpr ~nt_thread_start_routine_tuple_allocate_guard()
35+
inline constexpr ~nt_thread_start_routine_tuple_allocate_guard()
3236
{
3337
if (ptr_ != nullptr)
3438
{
39+
::std::ranges::destroy_at(reinterpret_cast<Tuple *>(this->ptr_));
3540
::fast_io::generic_allocator_adapter<::fast_io::nt_rtlallocateheap_allocator>::deallocate(this->ptr_);
3641
}
3742
}
3843
};
3944

4045
template <typename Tuple, ::std::size_t... Is>
41-
constexpr ::std::uint_least32_t FAST_IO_WINSTDCALL thread_start_routine(void *args) noexcept(noexcept(
46+
inline constexpr ::std::uint_least32_t FAST_IO_WINSTDCALL thread_start_routine(void *args) noexcept(noexcept(
4247
::std::invoke(::fast_io::get<Is>(*reinterpret_cast<Tuple *>(args))...)))
4348
{
44-
[[maybe_unused]] ::fast_io::win32::nt::details::nt_thread_start_routine_tuple_allocate_guard _(args);
49+
[[maybe_unused]] ::fast_io::win32::nt::details::nt_thread_start_routine_tuple_allocate_guard<Tuple> _(args);
4550
::std::invoke(::fast_io::get<Is>(*reinterpret_cast<Tuple *>(args))...);
4651
return 0;
4752
}
4853

4954
template <typename Tuple, ::std::size_t... Is>
50-
constexpr auto get_thread_start_routine(::std::index_sequence<Is...>) noexcept
55+
inline constexpr auto get_thread_start_routine(::std::index_sequence<Is...>) noexcept
5156
{
5257
return ::fast_io::win32::nt::details::thread_start_routine<Tuple, Is...>;
5358
}
@@ -66,13 +71,13 @@ class nt_thread
6671
native_handle_type handle_{nullptr};
6772

6873
public:
69-
constexpr nt_thread() noexcept = default;
74+
inline constexpr nt_thread() noexcept = default;
7075

7176
template <typename Func, typename... Args>
7277
requires(::std::invocable<Func, Args...>)
73-
constexpr nt_thread(Func &&func, Args &&...args)
78+
inline constexpr nt_thread(Func &&func, Args &&...args)
7479
{
75-
using start_routine_tuple_type = ::fast_io::tuple<decltype(func), decltype(args)...>;
80+
using start_routine_tuple_type = ::fast_io::tuple<::std::decay_t<Func>, ::std::decay_t<Args>...>;
7681
#if __has_cpp_attribute(indeterminate)
7782
::fast_io::win32::nt::client_id cid [[indeterminate]];
7883
#else
@@ -107,11 +112,11 @@ class nt_thread
107112
this->id_ = cid.UniqueThread;
108113
}
109114

110-
constexpr nt_thread(nt_thread const &) noexcept = delete;
115+
inline constexpr nt_thread(nt_thread const &) noexcept = delete;
111116

112-
constexpr nt_thread(nt_thread &&other) noexcept = default;
117+
inline constexpr nt_thread(nt_thread &&other) noexcept = default;
113118

114-
constexpr ~nt_thread() noexcept
119+
inline constexpr ~nt_thread() noexcept
115120
{
116121
if (handle_ != nullptr)
117122
{
@@ -127,9 +132,9 @@ class nt_thread
127132
}
128133
}
129134

130-
constexpr nt_thread &operator=(nt_thread const &) noexcept = delete;
135+
inline constexpr nt_thread &operator=(nt_thread const &) noexcept = delete;
131136

132-
constexpr nt_thread &operator=(nt_thread &&other) noexcept
137+
inline constexpr nt_thread &operator=(nt_thread &&other) noexcept
133138
{
134139
if (this == __builtin_addressof(other)) [[unlikely]]
135140
{
@@ -138,26 +143,26 @@ class nt_thread
138143
this->swap(other);
139144
return *this;
140145
}
141-
constexpr bool joinable() const noexcept
146+
inline constexpr bool joinable() const noexcept
142147
{
143148
return this->id_ != nullptr;
144149
}
145150

146-
constexpr void join()
151+
inline constexpr void join()
147152
{
148153
if (!this->joinable()) [[unlikely]]
149154
{
150155
::fast_io::fast_terminate();
151156
}
152-
auto status{::fast_io::win32::nt::nt_wait_for_single_object<zw>(this->handle_, /* INFINITE = */ int(0xffffffff), nullptr)};
157+
auto status{::fast_io::win32::nt::nt_wait_for_single_object<zw>(this->handle_, false, nullptr)};
153158
if (status) [[unlikely]]
154159
{
155160
::fast_io::throw_nt_error(status);
156161
}
157162
this->id_ = nullptr;
158163
}
159164

160-
constexpr void detach()
165+
inline constexpr void detach()
161166
{
162167
if (!this->joinable()) [[unlikely]]
163168
{
@@ -172,20 +177,20 @@ class nt_thread
172177
this->id_ = nullptr;
173178
}
174179

175-
constexpr void swap(nt_thread &other) noexcept
180+
inline constexpr void swap(nt_thread &other) noexcept
176181
{
177182
::std::ranges::swap(handle_, other.handle_);
178183
::std::ranges::swap(id_, other.id_);
179184
}
180185

181186
[[nodiscard]]
182-
constexpr auto get_id() const noexcept
187+
inline constexpr auto get_id() const noexcept
183188
{
184189
return this->id_;
185190
}
186191

187192
[[nodiscard]]
188-
constexpr auto native_handle() const noexcept
193+
inline constexpr auto native_handle() const noexcept
189194
{
190195
return this->handle_;
191196
}
@@ -194,13 +199,22 @@ class nt_thread
194199
* @brief Get the win32 id of the thread.
195200
* @note same as win32 GetCurrentThreadId
196201
*/
197-
constexpr ::std::uint_least32_t get_win32_id() const noexcept
202+
inline constexpr ::std::uint_least32_t get_win32_id() const noexcept
198203
{
199-
auto peb = ::fast_io::win32::nt::nt_current_teb();
200-
return static_cast<::std::uint_least32_t>(reinterpret_cast<::std::size_t>(peb->ClientId.UniqueThread));
204+
::fast_io::win32::nt::thread_basic_information tbi; // no init
205+
206+
auto status{::fast_io::win32::nt::nt_query_information_thread<zw>(
207+
this->handle_, ::fast_io::win32::nt::thread_information_class::ThreadBasicInformation, __builtin_addressof(tbi), sizeof(tbi), nullptr)};
208+
209+
if (status) [[unlikely]]
210+
{
211+
::fast_io::throw_nt_error(status);
212+
}
213+
214+
return reinterpret_cast<::std::uint_least32_t>(tbi.ClientId.UniqueThread);
201215
}
202216

203-
static constexpr ::std::uint_least32_t hardware_concurrency()
217+
inline static constexpr ::std::uint_least32_t hardware_concurrency()
204218
{
205219
::fast_io::win32::nt::system_basic_information sb{};
206220
auto status{::fast_io::win32::nt::nt_query_system_information<zw>(::fast_io::win32::nt::system_information_class::SystemBasicInformation,
@@ -217,7 +231,7 @@ namespace this_thread
217231
{
218232

219233
template <bool zw = false>
220-
constexpr auto get_id() -> ::fast_io::win32::nt::nt_thread<zw>::id
234+
inline constexpr ::fast_io::win32::nt::nt_thread<zw>::id get_id()
221235
{
222236
::fast_io::win32::nt::thread_basic_information tbi;
223237
::std::uint_least32_t status{::fast_io::win32::nt::nt_query_information_thread<zw>(
@@ -233,10 +247,48 @@ constexpr auto get_id() -> ::fast_io::win32::nt::nt_thread<zw>::id
233247
return tbi.ClientId.UniqueThread;
234248
}
235249

250+
inline ::std::uint_least32_t get_win32_id() noexcept
251+
{
252+
auto teb{::fast_io::win32::nt::nt_current_teb()};
253+
return static_cast<::std::uint_least32_t>(reinterpret_cast<::std::size_t>(teb->ClientId.UniqueThread));
254+
}
255+
236256
template <bool zw = false, typename Rep, typename Period>
237-
constexpr void sleep_for(::std::chrono::duration<Rep, Period> const &sleep_duration)
257+
inline constexpr void sleep_for(::std::chrono::duration<Rep, Period> const &sleep_duration)
238258
{
239-
auto val = -static_cast<::std::int_least64_t>(::std::chrono::duration_cast<::std::chrono::microseconds>(sleep_duration).count() * 10);
259+
auto const count{
260+
::std::chrono::duration_cast<::std::chrono::microseconds>(sleep_duration).count() * 10u +
261+
::std::chrono::duration_cast<::std::chrono::nanoseconds>(sleep_duration).count() / 100u % 10u};
262+
263+
if (count > static_cast<::std::uint_least64_t>(::std::numeric_limits<::std::int_least64_t>::max()))
264+
{
265+
::fast_io::throw_nt_error(0xC000000D);
266+
}
267+
268+
auto val{-static_cast<::std::int_least64_t>(count)};
269+
::std::uint_least32_t status{::fast_io::win32::nt::nt_delay_execution<zw>(false, __builtin_addressof(val))};
270+
if (status) [[unlikely]]
271+
{
272+
::fast_io::throw_nt_error(status);
273+
}
274+
}
275+
276+
template <bool zw = false, ::std::int_least64_t off_to_epoch>
277+
inline constexpr void sleep_for(::fast_io::basic_timestamp<off_to_epoch> const &sleep_duration)
278+
{
279+
if (sleep_duration.seconds < 0) [[unlikely]]
280+
{
281+
::fast_io::throw_nt_error(0xC000000D);
282+
}
283+
284+
auto const win_100ns_seconds{static_cast<::std::uint_least64_t>(static_cast<::std::uint_least64_t>(sleep_duration.seconds) * 10'000'000u + sleep_duration.subseconds / 100u)};
285+
286+
if (win_100ns_seconds > static_cast<::std::uint_least64_t>(::std::numeric_limits<::std::int_least64_t>::max())) [[unlikely]]
287+
{
288+
::fast_io::throw_nt_error(0xC000000D);
289+
}
290+
291+
auto val = -static_cast<::std::int_least64_t>(win_100ns_seconds);
240292
::std::uint_least32_t status{::fast_io::win32::nt::nt_delay_execution<zw>(false, __builtin_addressof(val))};
241293
if (status) [[unlikely]]
242294
{
@@ -245,19 +297,78 @@ constexpr void sleep_for(::std::chrono::duration<Rep, Period> const &sleep_durat
245297
}
246298

247299
template <bool zw = false, typename Clock, typename Duration>
248-
constexpr void sleep_until(::std::chrono::time_point<Clock, Duration> const &expect_time)
300+
inline constexpr void sleep_until(::std::chrono::time_point<Clock, Duration> const &expect_time)
249301
{
250302
auto const unix_ts = ::std::chrono::duration_cast<std::chrono::seconds>(
251-
expect_time.time_since_epoch())
252-
.count();
253-
auto nt_ts = (unix_ts + 11644473600) * 10000000;
303+
expect_time.time_since_epoch())
304+
.count();
305+
auto const unix_subsec_ts = ::std::chrono::duration_cast<std::chrono::nanoseconds>(
306+
expect_time.time_since_epoch())
307+
.count() /
308+
100u % 10000000u;
309+
310+
auto const unix_to_nt_secs{static_cast<::std::int_least64_t>(unix_ts) + 11644473600};
311+
if (unix_to_nt_secs < 0) [[unlikely]]
312+
{
313+
::fast_io::throw_nt_error(0xC000000D);
314+
}
315+
316+
auto const count{static_cast<::std::uint_least64_t>(unix_to_nt_secs) * 10000000u + static_cast<::std::uint_least64_t>(unix_subsec_ts)};
317+
318+
if (count > static_cast<::std::uint_least64_t>(::std::numeric_limits<::std::int_least64_t>::max()))
319+
{
320+
::fast_io::throw_nt_error(0xC000000D);
321+
}
322+
323+
auto nt_ts{static_cast<::std::int_least64_t>(count)};
254324
::std::uint_least32_t status{::fast_io::win32::nt::nt_delay_execution<zw>(false, __builtin_addressof(nt_ts))};
255325
if (status) [[unlikely]]
256326
{
257327
::fast_io::throw_nt_error(status);
258328
}
259329
}
260330

331+
template <bool zw = false, ::std::int_least64_t off_to_epoch>
332+
inline constexpr void sleep_until(::fast_io::basic_timestamp<off_to_epoch> const &expect_time)
333+
{
334+
if (expect_time.seconds < 0) [[unlikely]]
335+
{
336+
::fast_io::throw_nt_error(0xC000000D);
337+
}
338+
339+
auto const win32_ts{static_cast<::fast_io::win32_timestamp>(expect_time)};
340+
341+
auto const win_100ns_seconds = static_cast<::std::uint_least64_t>(win32_ts.seconds) * 10'000'000u + win32_ts.subseconds / 100u;
342+
343+
if (win_100ns_seconds > static_cast<::std::uint_least64_t>(::std::numeric_limits<::std::int_least64_t>::max())) [[unlikely]]
344+
{
345+
::fast_io::throw_nt_error(0xC000000D);
346+
}
347+
348+
auto val = static_cast<::std::int_least64_t>(win_100ns_seconds);
349+
::std::uint_least32_t status{::fast_io::win32::nt::nt_delay_execution<zw>(false, __builtin_addressof(val))};
350+
if (status) [[unlikely]]
351+
{
352+
::fast_io::throw_nt_error(status);
353+
}
354+
}
355+
261356
} // namespace this_thread
262357

263-
} // namespace fast_io::win32::nt
358+
} // namespace win32::nt
359+
360+
using nt_thread = win32::nt::nt_thread<false>;
361+
using zw_thread = win32::nt::nt_thread<true>;
362+
363+
#if defined(_WIN32) && !defined(_WIN32_WINDOWS)
364+
using native_thread = nt_thread;
365+
366+
namespace this_thread
367+
{
368+
using ::fast_io::win32::nt::this_thread::get_id;
369+
using ::fast_io::win32::nt::this_thread::sleep_for;
370+
using ::fast_io::win32::nt::this_thread::sleep_until;
371+
} // namespace this_thread
372+
#endif
373+
374+
} // namespace fast_io

0 commit comments

Comments
 (0)