koffi 2.6.3 → 2.6.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +9 -0
- package/build/koffi/darwin_arm64/koffi.node +0 -0
- package/build/koffi/darwin_x64/koffi.node +0 -0
- package/build/koffi/freebsd_arm64/koffi.node +0 -0
- package/build/koffi/freebsd_ia32/koffi.node +0 -0
- package/build/koffi/freebsd_x64/koffi.node +0 -0
- package/build/koffi/linux_arm32hf/koffi.node +0 -0
- package/build/koffi/linux_arm64/koffi.node +0 -0
- package/build/koffi/linux_ia32/koffi.node +0 -0
- package/build/koffi/linux_riscv64hf64/koffi.node +0 -0
- package/build/koffi/linux_x64/koffi.node +0 -0
- package/build/koffi/openbsd_ia32/koffi.node +0 -0
- package/build/koffi/openbsd_x64/koffi.node +0 -0
- package/build/koffi/win32_arm64/koffi.node +0 -0
- package/build/koffi/win32_ia32/koffi.node +0 -0
- package/build/koffi/win32_x64/koffi.node +0 -0
- package/doc/benchmarks.md +26 -33
- package/doc/benchmarks.xlsx +0 -0
- package/doc/contribute.md +1 -1
- package/doc/packaging.md +4 -2
- package/doc/static/perf_linux_20231028.png +0 -0
- package/doc/static/perf_windows_20231028.png +0 -0
- package/index.js +3 -4
- package/indirect.js +3 -4
- package/package.json +2 -2
- package/src/cnoke/src/builder.js +2 -2
- package/src/core/libcc/libcc.cc +263 -177
- package/src/core/libcc/libcc.hh +31 -19
- package/src/koffi/CMakeLists.txt +9 -9
- package/src/koffi/cmake/raylib.cmake +98 -0
- package/src/koffi/cmake/sqlite.cmake +27 -0
- package/src/koffi/src/ffi.cc +50 -28
- package/src/koffi/src/ffi.hh +3 -2
- package/src/koffi/src/util.cc +8 -1
- package/src/koffi/src/win32.cc +1 -1
package/src/core/libcc/libcc.cc
CHANGED
|
@@ -1426,7 +1426,7 @@ static inline void ProcessArg(const FmtArg &arg, AppendFunc append)
|
|
|
1426
1426
|
RG_ASSERT(arg.u.random.len <= RG_SIZE(out_buf.data));
|
|
1427
1427
|
|
|
1428
1428
|
for (Size j = 0; j < arg.u.random.len; j++) {
|
|
1429
|
-
int rnd =
|
|
1429
|
+
int rnd = GetRandomIntFast(0, (int)chars.len);
|
|
1430
1430
|
out_buf.Append(chars[rnd]);
|
|
1431
1431
|
}
|
|
1432
1432
|
|
|
@@ -2146,37 +2146,6 @@ fail:
|
|
|
2146
2146
|
return str_buf;
|
|
2147
2147
|
}
|
|
2148
2148
|
|
|
2149
|
-
void SetEnvironmentVar(const char *name, const char *value)
|
|
2150
|
-
{
|
|
2151
|
-
RG_ASSERT(name && name[0] && !strchr(name, '='));
|
|
2152
|
-
RG_ASSERT(value);
|
|
2153
|
-
|
|
2154
|
-
if (win32_utf8) {
|
|
2155
|
-
RG_CRITICAL(SetEnvironmentVariableA(name, value), "Failed to set environment variable '%1' to '%2': %3", name, value, GetWin32ErrorString());
|
|
2156
|
-
} else {
|
|
2157
|
-
wchar_t name_w[256];
|
|
2158
|
-
wchar_t value_w[4096];
|
|
2159
|
-
|
|
2160
|
-
RG_CRITICAL(ConvertUtf8ToWin32Wide(name, name_w) >= 0, "Failed to set environment variable '%1' to '%2'", name, value);
|
|
2161
|
-
RG_CRITICAL(ConvertUtf8ToWin32Wide(value, value_w) >= 0, "Failed to set environment variable '%1' to '%2'", name, value);
|
|
2162
|
-
RG_CRITICAL(SetEnvironmentVariableW(name_w, value_w), "Failed to set environment variable '%1' to '%2': %3", name, value, GetWin32ErrorString());
|
|
2163
|
-
}
|
|
2164
|
-
}
|
|
2165
|
-
|
|
2166
|
-
void DeleteEnvironmentVar(const char *name)
|
|
2167
|
-
{
|
|
2168
|
-
RG_ASSERT(name && name[0] && !strchr(name, '='));
|
|
2169
|
-
|
|
2170
|
-
if (win32_utf8) {
|
|
2171
|
-
RG_CRITICAL(SetEnvironmentVariableA(name, nullptr), "Failed to clear environment variable '%1': %2", name, GetWin32ErrorString());
|
|
2172
|
-
} else {
|
|
2173
|
-
wchar_t name_w[256];
|
|
2174
|
-
|
|
2175
|
-
RG_CRITICAL(ConvertUtf8ToWin32Wide(name, name_w) >= 0, "Failed to clear environment variable '%1'", name);
|
|
2176
|
-
RG_CRITICAL(SetEnvironmentVariableW(name_w, nullptr), "Failed to clear environment variable '%1': %2", name, GetWin32ErrorString());
|
|
2177
|
-
}
|
|
2178
|
-
}
|
|
2179
|
-
|
|
2180
2149
|
static FileType FileAttributesToType(uint32_t attr)
|
|
2181
2150
|
{
|
|
2182
2151
|
if (attr & FILE_ATTRIBUTE_DIRECTORY) {
|
|
@@ -2360,20 +2329,6 @@ EnumResult EnumerateDirectory(const char *dirname, const char *filter, Size max_
|
|
|
2360
2329
|
|
|
2361
2330
|
#else
|
|
2362
2331
|
|
|
2363
|
-
void SetEnvironmentVar(const char *name, const char *value)
|
|
2364
|
-
{
|
|
2365
|
-
RG_ASSERT(name && name[0] && !strchr(name, '='));
|
|
2366
|
-
RG_ASSERT(value);
|
|
2367
|
-
|
|
2368
|
-
RG_CRITICAL(!setenv(name, value, 1), "Failed to set environment variable '%1' to '%2': %3", name, value, strerror(errno));
|
|
2369
|
-
}
|
|
2370
|
-
|
|
2371
|
-
void DeleteEnvironmentVar(const char *name)
|
|
2372
|
-
{
|
|
2373
|
-
RG_ASSERT(name && name[0] && !strchr(name, '='));
|
|
2374
|
-
RG_CRITICAL(!unsetenv(name), "Failed to clear environment variable '%1': %2", name, strerror(errno));
|
|
2375
|
-
}
|
|
2376
|
-
|
|
2377
2332
|
static FileType FileModeToType(mode_t mode)
|
|
2378
2333
|
{
|
|
2379
2334
|
if (S_ISDIR(mode)) {
|
|
@@ -2473,11 +2428,15 @@ StatResult StatFile(const char *filename, unsigned int flags, FileInfo *out_info
|
|
|
2473
2428
|
(int64_t)sb.st_mtim.tv_nsec / 1000000;
|
|
2474
2429
|
out_info->btime = (int64_t)sb.__st_birthtim.tv_sec * 1000 +
|
|
2475
2430
|
(int64_t)sb.__st_birthtim.tv_nsec / 1000000;
|
|
2476
|
-
#
|
|
2431
|
+
#elif defined(__FreeBSD__)
|
|
2477
2432
|
out_info->mtime = (int64_t)sb.st_mtim.tv_sec * 1000 +
|
|
2478
2433
|
(int64_t)sb.st_mtim.tv_nsec / 1000000;
|
|
2479
2434
|
out_info->btime = (int64_t)sb.st_birthtim.tv_sec * 1000 +
|
|
2480
2435
|
(int64_t)sb.st_birthtim.tv_nsec / 1000000;
|
|
2436
|
+
#else
|
|
2437
|
+
out_info->mtime = (int64_t)sb.st_mtim.tv_sec * 1000 +
|
|
2438
|
+
(int64_t)sb.st_mtim.tv_nsec / 1000000;
|
|
2439
|
+
out_info->btime = out_info->mtime;
|
|
2481
2440
|
#endif
|
|
2482
2441
|
out_info->mode = (unsigned int)sb.st_mode;
|
|
2483
2442
|
out_info->uid = (uint32_t)sb.st_uid;
|
|
@@ -3919,7 +3878,7 @@ struct PendingIO {
|
|
|
3919
3878
|
}
|
|
3920
3879
|
};
|
|
3921
3880
|
|
|
3922
|
-
bool ExecuteCommandLine(const char *cmd_line, const
|
|
3881
|
+
bool ExecuteCommandLine(const char *cmd_line, const ExecuteInfo &info,
|
|
3923
3882
|
FunctionRef<Span<const uint8_t>()> in_func,
|
|
3924
3883
|
FunctionRef<void(Span<uint8_t> buf)> out_func, int *out_code)
|
|
3925
3884
|
{
|
|
@@ -3934,9 +3893,9 @@ bool ExecuteCommandLine(const char *cmd_line, const char *work_dir,
|
|
|
3934
3893
|
|
|
3935
3894
|
// Convert work directory
|
|
3936
3895
|
Span<wchar_t> work_dir_w;
|
|
3937
|
-
if (work_dir) {
|
|
3938
|
-
work_dir_w = AllocateSpan<wchar_t>(&temp_alloc, 2 * strlen(work_dir) + 1);
|
|
3939
|
-
if (ConvertUtf8ToWin32Wide(work_dir, work_dir_w) < 0)
|
|
3896
|
+
if (info.work_dir) {
|
|
3897
|
+
work_dir_w = AllocateSpan<wchar_t>(&temp_alloc, 2 * strlen(info.work_dir) + 1);
|
|
3898
|
+
if (ConvertUtf8ToWin32Wide(info.work_dir, work_dir_w) < 0)
|
|
3940
3899
|
return false;
|
|
3941
3900
|
} else {
|
|
3942
3901
|
work_dir_w = {};
|
|
@@ -3988,6 +3947,45 @@ bool ExecuteCommandLine(const char *cmd_line, const char *work_dir,
|
|
|
3988
3947
|
if (out_func.IsValid() && !CreateOverlappedPipe(true, false, PipeMode::Byte, out_pipe))
|
|
3989
3948
|
return false;
|
|
3990
3949
|
|
|
3950
|
+
// Prepare environment (if needed)
|
|
3951
|
+
HeapArray<wchar_t> new_env_w;
|
|
3952
|
+
if (info.reset_env || info.env_variables.len) {
|
|
3953
|
+
if (!info.reset_env) {
|
|
3954
|
+
Span<wchar_t> current_env = MakeSpan(GetEnvironmentStringsW(), 0);
|
|
3955
|
+
|
|
3956
|
+
do {
|
|
3957
|
+
Size len = (Size)wcslen(current_env.end());
|
|
3958
|
+
current_env.len += len + 1;
|
|
3959
|
+
} while (current_env.ptr[current_env.len]);
|
|
3960
|
+
|
|
3961
|
+
new_env_w.Append(current_env);
|
|
3962
|
+
}
|
|
3963
|
+
|
|
3964
|
+
for (const ExecuteInfo::KeyValue &kv: info.env_variables) {
|
|
3965
|
+
Span<const char> key = kv.key;
|
|
3966
|
+
Span<const char> value = kv.value;
|
|
3967
|
+
|
|
3968
|
+
Size len = 2 * (key.len + value.len + 1) + 1;
|
|
3969
|
+
new_env_w.Reserve(len);
|
|
3970
|
+
|
|
3971
|
+
len = ConvertUtf8ToWin32Wide(key, new_env_w.TakeAvailable());
|
|
3972
|
+
if (len < 0) [[unlikely]]
|
|
3973
|
+
return false;
|
|
3974
|
+
new_env_w.len += len;
|
|
3975
|
+
|
|
3976
|
+
new_env_w.Append(L'=');
|
|
3977
|
+
|
|
3978
|
+
len = ConvertUtf8ToWin32Wide(value, new_env_w.TakeAvailable());
|
|
3979
|
+
if (len < 0) [[unlikely]]
|
|
3980
|
+
return false;
|
|
3981
|
+
new_env_w.len += len;
|
|
3982
|
+
|
|
3983
|
+
new_env_w.Append(0);
|
|
3984
|
+
}
|
|
3985
|
+
|
|
3986
|
+
new_env_w.Append(0);
|
|
3987
|
+
}
|
|
3988
|
+
|
|
3991
3989
|
// Start process
|
|
3992
3990
|
HANDLE process_handle;
|
|
3993
3991
|
{
|
|
@@ -4012,9 +4010,11 @@ bool ExecuteCommandLine(const char *cmd_line, const char *work_dir,
|
|
|
4012
4010
|
si.dwFlags |= STARTF_USESTDHANDLES;
|
|
4013
4011
|
}
|
|
4014
4012
|
|
|
4013
|
+
int flags = CREATE_NEW_PROCESS_GROUP | CREATE_UNICODE_ENVIRONMENT;
|
|
4014
|
+
|
|
4015
4015
|
PROCESS_INFORMATION pi = {};
|
|
4016
|
-
if (!CreateProcessW(nullptr, cmd_line_w.ptr, nullptr, nullptr, TRUE,
|
|
4017
|
-
|
|
4016
|
+
if (!CreateProcessW(nullptr, cmd_line_w.ptr, nullptr, nullptr, TRUE, flags,
|
|
4017
|
+
new_env_w.ptr, work_dir_w.ptr, &si, &pi)) {
|
|
4018
4018
|
LogError("Failed to start process: %1", GetWin32ErrorString());
|
|
4019
4019
|
return false;
|
|
4020
4020
|
}
|
|
@@ -4223,10 +4223,12 @@ void CloseDescriptorSafe(int *fd_ptr)
|
|
|
4223
4223
|
*fd_ptr = -1;
|
|
4224
4224
|
}
|
|
4225
4225
|
|
|
4226
|
-
bool ExecuteCommandLine(const char *cmd_line, const
|
|
4226
|
+
bool ExecuteCommandLine(const char *cmd_line, const ExecuteInfo &info,
|
|
4227
4227
|
FunctionRef<Span<const uint8_t>()> in_func,
|
|
4228
4228
|
FunctionRef<void(Span<uint8_t> buf)> out_func, int *out_code)
|
|
4229
4229
|
{
|
|
4230
|
+
BlockAllocator temp_alloc;
|
|
4231
|
+
|
|
4230
4232
|
// Create read pipes
|
|
4231
4233
|
int in_pfd[2] = {-1, -1};
|
|
4232
4234
|
RG_DEFER {
|
|
@@ -4277,6 +4279,26 @@ bool ExecuteCommandLine(const char *cmd_line, const char *work_dir,
|
|
|
4277
4279
|
}
|
|
4278
4280
|
}
|
|
4279
4281
|
|
|
4282
|
+
// Prepare new environment (if needed)
|
|
4283
|
+
HeapArray<char *> new_env;
|
|
4284
|
+
if (info.reset_env || info.env_variables.len) {
|
|
4285
|
+
if (!info.reset_env) {
|
|
4286
|
+
char **ptr = environ;
|
|
4287
|
+
|
|
4288
|
+
while (*ptr) {
|
|
4289
|
+
new_env.Append(*ptr);
|
|
4290
|
+
ptr++;
|
|
4291
|
+
}
|
|
4292
|
+
}
|
|
4293
|
+
|
|
4294
|
+
for (const ExecuteInfo::KeyValue &kv: info.env_variables) {
|
|
4295
|
+
const char *var = Fmt(&temp_alloc, "%1=%2", kv.key, kv.value).ptr;
|
|
4296
|
+
new_env.Append((char *)var);
|
|
4297
|
+
}
|
|
4298
|
+
|
|
4299
|
+
new_env.Append(nullptr);
|
|
4300
|
+
}
|
|
4301
|
+
|
|
4280
4302
|
// Start process
|
|
4281
4303
|
pid_t pid;
|
|
4282
4304
|
{
|
|
@@ -4297,12 +4319,12 @@ bool ExecuteCommandLine(const char *cmd_line, const char *work_dir,
|
|
|
4297
4319
|
return false;
|
|
4298
4320
|
}
|
|
4299
4321
|
|
|
4300
|
-
if (work_dir) {
|
|
4301
|
-
const char *argv[] = {"env", "-C", work_dir, "sh", "-c", cmd_line, nullptr };
|
|
4302
|
-
errno = posix_spawn(&pid, "/bin/env", &file_actions, nullptr, const_cast<char **>(argv), environ);
|
|
4322
|
+
if (info.work_dir) {
|
|
4323
|
+
const char *argv[] = {"env", "-C", info.work_dir, "sh", "-c", cmd_line, nullptr };
|
|
4324
|
+
errno = posix_spawn(&pid, "/bin/env", &file_actions, nullptr, const_cast<char **>(argv), new_env.ptr ? new_env.ptr : environ);
|
|
4303
4325
|
} else {
|
|
4304
4326
|
const char *argv[] = {"sh", "-c", cmd_line, nullptr};
|
|
4305
|
-
errno = posix_spawn(&pid, "/bin/sh", &file_actions, nullptr, const_cast<char **>(argv), environ);
|
|
4327
|
+
errno = posix_spawn(&pid, "/bin/sh", &file_actions, nullptr, const_cast<char **>(argv), new_env.ptr ? new_env.ptr : environ);
|
|
4306
4328
|
}
|
|
4307
4329
|
if (errno) {
|
|
4308
4330
|
LogError("Failed to start process: %1", strerror(errno));
|
|
@@ -4444,7 +4466,7 @@ bool ExecuteCommandLine(const char *cmd_line, const char *work_dir,
|
|
|
4444
4466
|
|
|
4445
4467
|
#endif
|
|
4446
4468
|
|
|
4447
|
-
bool ExecuteCommandLine(const char *cmd_line, const
|
|
4469
|
+
bool ExecuteCommandLine(const char *cmd_line, const ExecuteInfo &info,
|
|
4448
4470
|
Span<const uint8_t> in_buf, Size max_len,
|
|
4449
4471
|
HeapArray<uint8_t> *out_buf, int *out_code)
|
|
4450
4472
|
{
|
|
@@ -4467,8 +4489,8 @@ bool ExecuteCommandLine(const char *cmd_line, const char *work_dir,
|
|
|
4467
4489
|
// Don't f*ck up the log
|
|
4468
4490
|
bool warned = false;
|
|
4469
4491
|
|
|
4470
|
-
bool success = ExecuteCommandLine(cmd_line,
|
|
4471
|
-
|
|
4492
|
+
bool success = ExecuteCommandLine(cmd_line, info, [&]() { return in_buf; },
|
|
4493
|
+
[&](Span<uint8_t> buf) {
|
|
4472
4494
|
if (out_buf->len - start_len <= max_len - buf.len) {
|
|
4473
4495
|
out_buf->Append(buf);
|
|
4474
4496
|
} else if (!warned) {
|
|
@@ -4494,7 +4516,7 @@ Size ReadCommandOutput(const char *cmd_line, Span<char> out_output)
|
|
|
4494
4516
|
};
|
|
4495
4517
|
|
|
4496
4518
|
int exit_code;
|
|
4497
|
-
if (!ExecuteCommandLine(cmd_line,
|
|
4519
|
+
if (!ExecuteCommandLine(cmd_line, {}, MakeSpan((const uint8_t *)nullptr, 0), write, &exit_code))
|
|
4498
4520
|
return -1;
|
|
4499
4521
|
if (exit_code) {
|
|
4500
4522
|
LogDebug("Command '%1 failed (exit code: %2)", cmd_line, exit_code);
|
|
@@ -4507,7 +4529,7 @@ Size ReadCommandOutput(const char *cmd_line, Span<char> out_output)
|
|
|
4507
4529
|
bool ReadCommandOutput(const char *cmd_line, HeapArray<char> *out_output)
|
|
4508
4530
|
{
|
|
4509
4531
|
int exit_code;
|
|
4510
|
-
if (!ExecuteCommandLine(cmd_line,
|
|
4532
|
+
if (!ExecuteCommandLine(cmd_line, {}, {}, Mebibytes(1), out_output, &exit_code))
|
|
4511
4533
|
return false;
|
|
4512
4534
|
if (exit_code) {
|
|
4513
4535
|
LogDebug("Command '%1 failed (exit code: %2)", cmd_line, exit_code);
|
|
@@ -4759,7 +4781,7 @@ bool NotifySystemd()
|
|
|
4759
4781
|
return false;
|
|
4760
4782
|
}
|
|
4761
4783
|
|
|
4762
|
-
|
|
4784
|
+
unsetenv("NOTIFY_SOCKET");
|
|
4763
4785
|
return true;
|
|
4764
4786
|
}
|
|
4765
4787
|
#endif
|
|
@@ -5063,79 +5085,6 @@ const char *CreateUniqueDirectory(Span<const char> directory, const char *prefix
|
|
|
5063
5085
|
// Random
|
|
5064
5086
|
// ------------------------------------------------------------------------
|
|
5065
5087
|
|
|
5066
|
-
static inline uint32_t ROTL32(uint32_t v, int n)
|
|
5067
|
-
{
|
|
5068
|
-
return (v << n) | (v >> (32 - n));
|
|
5069
|
-
}
|
|
5070
|
-
|
|
5071
|
-
static inline uint64_t ROTL64(uint64_t v, int n) {
|
|
5072
|
-
return (v << n) | (v >> (64 - n));
|
|
5073
|
-
}
|
|
5074
|
-
|
|
5075
|
-
FastRandom::FastRandom()
|
|
5076
|
-
{
|
|
5077
|
-
do {
|
|
5078
|
-
FillRandomSafe(state, RG_SIZE(state));
|
|
5079
|
-
} while (std::all_of(std::begin(state), std::end(state), [](uint64_t v) { return !v; }));
|
|
5080
|
-
}
|
|
5081
|
-
|
|
5082
|
-
FastRandom::FastRandom(uint64_t seed)
|
|
5083
|
-
{
|
|
5084
|
-
// splitmix64 generator to seed xoshiro256++, as recommended
|
|
5085
|
-
|
|
5086
|
-
seed += 0x9e3779b97f4a7c15;
|
|
5087
|
-
|
|
5088
|
-
for (int i = 0; i < 4; i++) {
|
|
5089
|
-
seed = (seed ^ (seed >> 30)) * 0xbf58476d1ce4e5b9;
|
|
5090
|
-
seed = (seed ^ (seed >> 27)) * 0x94d049bb133111eb;
|
|
5091
|
-
state[i] = seed ^ (seed >> 31);
|
|
5092
|
-
}
|
|
5093
|
-
}
|
|
5094
|
-
|
|
5095
|
-
void FastRandom::Fill(void *out_buf, Size len)
|
|
5096
|
-
{
|
|
5097
|
-
for (Size i = 0; i < len; i += 8) {
|
|
5098
|
-
uint64_t rnd = Next();
|
|
5099
|
-
|
|
5100
|
-
Size copy_len = std::min(RG_SIZE(rnd), len - i);
|
|
5101
|
-
memcpy((uint8_t *)out_buf + i, &rnd, copy_len);
|
|
5102
|
-
}
|
|
5103
|
-
}
|
|
5104
|
-
|
|
5105
|
-
int FastRandom::GetInt(int min, int max)
|
|
5106
|
-
{
|
|
5107
|
-
int range = max - min;
|
|
5108
|
-
RG_ASSERT(range >= 2);
|
|
5109
|
-
|
|
5110
|
-
unsigned int treshold = (UINT_MAX - UINT_MAX % range);
|
|
5111
|
-
|
|
5112
|
-
unsigned int x;
|
|
5113
|
-
do {
|
|
5114
|
-
Fill(&x, RG_SIZE(x));
|
|
5115
|
-
} while (x >= treshold);
|
|
5116
|
-
x %= range;
|
|
5117
|
-
|
|
5118
|
-
return min + (int)x;
|
|
5119
|
-
}
|
|
5120
|
-
|
|
5121
|
-
uint64_t FastRandom::Next()
|
|
5122
|
-
{
|
|
5123
|
-
// xoshiro256++ by David Blackman and Sebastiano Vigna (vigna@acm.org)
|
|
5124
|
-
// Hopefully I did not screw it up :)
|
|
5125
|
-
|
|
5126
|
-
uint64_t result = ROTL64(state[0] + state[3], 23) + state[0];
|
|
5127
|
-
uint64_t t = state[1] << 17;
|
|
5128
|
-
|
|
5129
|
-
state[2] ^= state[0];
|
|
5130
|
-
state[3] ^= state[1];
|
|
5131
|
-
state[1] ^= state[2];
|
|
5132
|
-
state[0] ^= state[3];
|
|
5133
|
-
state[2] ^= t;
|
|
5134
|
-
state[3] = ROTL64(state[3], 45);
|
|
5135
|
-
|
|
5136
|
-
return result;
|
|
5137
|
-
}
|
|
5138
|
-
|
|
5139
5088
|
static RG_THREAD_LOCAL Size rnd_remain;
|
|
5140
5089
|
static RG_THREAD_LOCAL int64_t rnd_time;
|
|
5141
5090
|
#ifndef _WIN32
|
|
@@ -5145,6 +5094,17 @@ static RG_THREAD_LOCAL uint32_t rnd_state[16];
|
|
|
5145
5094
|
static RG_THREAD_LOCAL uint8_t rnd_buf[64];
|
|
5146
5095
|
static RG_THREAD_LOCAL Size rnd_offset;
|
|
5147
5096
|
|
|
5097
|
+
static thread_local FastRandom rng_fast;
|
|
5098
|
+
|
|
5099
|
+
static inline uint32_t ROTL32(uint32_t v, int n)
|
|
5100
|
+
{
|
|
5101
|
+
return (v << n) | (v >> (32 - n));
|
|
5102
|
+
}
|
|
5103
|
+
|
|
5104
|
+
static inline uint64_t ROTL64(uint64_t v, int n) {
|
|
5105
|
+
return (v << n) | (v >> (64 - n));
|
|
5106
|
+
}
|
|
5107
|
+
|
|
5148
5108
|
static void InitChaCha20(uint32_t state[16], uint32_t key[8], uint32_t iv[2])
|
|
5149
5109
|
{
|
|
5150
5110
|
alignas(uint32_t) static char str[] = "expand 32-byte k";
|
|
@@ -5251,18 +5211,18 @@ void FillRandomSafe(void *out_buf, Size len)
|
|
|
5251
5211
|
|
|
5252
5212
|
memset(rnd_state, 0, RG_SIZE(rnd_state));
|
|
5253
5213
|
#if defined(_WIN32)
|
|
5254
|
-
RG_CRITICAL(RtlGenRandom(&buf, RG_SIZE(buf)), "RtlGenRandom() failed: %
|
|
5214
|
+
RG_CRITICAL(RtlGenRandom(&buf, RG_SIZE(buf)), "RtlGenRandom() failed: %1", GetWin32ErrorString());
|
|
5255
5215
|
#elif defined(__linux__)
|
|
5256
5216
|
{
|
|
5257
5217
|
restart:
|
|
5258
5218
|
int ret = syscall(SYS_getrandom, &buf, RG_SIZE(buf), 0);
|
|
5259
|
-
RG_CRITICAL(ret >= 0, "getentropy() failed: %
|
|
5219
|
+
RG_CRITICAL(ret >= 0, "getentropy() failed: %1", strerror(errno));
|
|
5260
5220
|
|
|
5261
5221
|
if (ret < RG_SIZE(buf))
|
|
5262
5222
|
goto restart;
|
|
5263
5223
|
}
|
|
5264
5224
|
#else
|
|
5265
|
-
RG_CRITICAL(getentropy(&buf, RG_SIZE(buf)) == 0, "getentropy() failed: %
|
|
5225
|
+
RG_CRITICAL(getentropy(&buf, RG_SIZE(buf)) == 0, "getentropy() failed: %1", strerror(errno));
|
|
5266
5226
|
#endif
|
|
5267
5227
|
|
|
5268
5228
|
InitChaCha20(rnd_state, buf.key, buf.iv);
|
|
@@ -5312,6 +5272,75 @@ int GetRandomIntSafe(int min, int max)
|
|
|
5312
5272
|
return min + (int)x;
|
|
5313
5273
|
}
|
|
5314
5274
|
|
|
5275
|
+
FastRandom::FastRandom()
|
|
5276
|
+
{
|
|
5277
|
+
do {
|
|
5278
|
+
FillRandomSafe(state, RG_SIZE(state));
|
|
5279
|
+
} while (std::all_of(std::begin(state), std::end(state), [](uint64_t v) { return !v; }));
|
|
5280
|
+
}
|
|
5281
|
+
|
|
5282
|
+
FastRandom::FastRandom(uint64_t seed)
|
|
5283
|
+
{
|
|
5284
|
+
// splitmix64 generator to seed xoshiro256++, as recommended
|
|
5285
|
+
|
|
5286
|
+
seed += 0x9e3779b97f4a7c15;
|
|
5287
|
+
|
|
5288
|
+
for (int i = 0; i < 4; i++) {
|
|
5289
|
+
seed = (seed ^ (seed >> 30)) * 0xbf58476d1ce4e5b9;
|
|
5290
|
+
seed = (seed ^ (seed >> 27)) * 0x94d049bb133111eb;
|
|
5291
|
+
state[i] = seed ^ (seed >> 31);
|
|
5292
|
+
}
|
|
5293
|
+
}
|
|
5294
|
+
|
|
5295
|
+
void FastRandom::Fill(void *out_buf, Size len)
|
|
5296
|
+
{
|
|
5297
|
+
for (Size i = 0; i < len; i += 8) {
|
|
5298
|
+
uint64_t rnd = Next();
|
|
5299
|
+
|
|
5300
|
+
Size copy_len = std::min(RG_SIZE(rnd), len - i);
|
|
5301
|
+
memcpy((uint8_t *)out_buf + i, &rnd, copy_len);
|
|
5302
|
+
}
|
|
5303
|
+
}
|
|
5304
|
+
|
|
5305
|
+
int FastRandom::GetInt(int min, int max)
|
|
5306
|
+
{
|
|
5307
|
+
int range = max - min;
|
|
5308
|
+
RG_ASSERT(range >= 2);
|
|
5309
|
+
|
|
5310
|
+
unsigned int treshold = (UINT_MAX - UINT_MAX % range);
|
|
5311
|
+
|
|
5312
|
+
unsigned int x;
|
|
5313
|
+
do {
|
|
5314
|
+
x = (unsigned int)Next();
|
|
5315
|
+
} while (x >= treshold);
|
|
5316
|
+
x %= range;
|
|
5317
|
+
|
|
5318
|
+
return min + (int)x;
|
|
5319
|
+
}
|
|
5320
|
+
|
|
5321
|
+
uint64_t FastRandom::Next()
|
|
5322
|
+
{
|
|
5323
|
+
// xoshiro256++ by David Blackman and Sebastiano Vigna (vigna@acm.org)
|
|
5324
|
+
// Hopefully I did not screw it up :)
|
|
5325
|
+
|
|
5326
|
+
uint64_t result = ROTL64(state[0] + state[3], 23) + state[0];
|
|
5327
|
+
uint64_t t = state[1] << 17;
|
|
5328
|
+
|
|
5329
|
+
state[2] ^= state[0];
|
|
5330
|
+
state[3] ^= state[1];
|
|
5331
|
+
state[1] ^= state[2];
|
|
5332
|
+
state[0] ^= state[3];
|
|
5333
|
+
state[2] ^= t;
|
|
5334
|
+
state[3] = ROTL64(state[3], 45);
|
|
5335
|
+
|
|
5336
|
+
return result;
|
|
5337
|
+
}
|
|
5338
|
+
|
|
5339
|
+
int GetRandomIntFast(int min, int max)
|
|
5340
|
+
{
|
|
5341
|
+
return rng_fast.GetInt(min, max);
|
|
5342
|
+
}
|
|
5343
|
+
|
|
5315
5344
|
// ------------------------------------------------------------------------
|
|
5316
5345
|
// Sockets
|
|
5317
5346
|
// ------------------------------------------------------------------------
|
|
@@ -5517,7 +5546,10 @@ struct Task {
|
|
|
5517
5546
|
std::function<bool()> func;
|
|
5518
5547
|
};
|
|
5519
5548
|
|
|
5520
|
-
struct
|
|
5549
|
+
struct WorkerData {
|
|
5550
|
+
AsyncPool *pool = nullptr;
|
|
5551
|
+
int idx;
|
|
5552
|
+
|
|
5521
5553
|
std::mutex queue_mutex;
|
|
5522
5554
|
BucketArray<Task> tasks;
|
|
5523
5555
|
};
|
|
@@ -5533,15 +5565,13 @@ class AsyncPool {
|
|
|
5533
5565
|
int refcount = 0;
|
|
5534
5566
|
|
|
5535
5567
|
int async_count = 0;
|
|
5536
|
-
HeapArray<
|
|
5537
|
-
|
|
5538
|
-
HeapArray<TaskQueue> queues;
|
|
5568
|
+
HeapArray<WorkerData> workers;
|
|
5539
5569
|
std::atomic_int pending_tasks { 0 };
|
|
5540
5570
|
|
|
5541
5571
|
public:
|
|
5542
5572
|
AsyncPool(int threads, bool leak);
|
|
5543
5573
|
|
|
5544
|
-
int GetWorkerCount() const { return (int)
|
|
5574
|
+
int GetWorkerCount() const { return (int)workers.len; }
|
|
5545
5575
|
int CountPendingTasks() const { return pending_tasks; }
|
|
5546
5576
|
|
|
5547
5577
|
void RegisterAsync();
|
|
@@ -5552,7 +5582,7 @@ public:
|
|
|
5552
5582
|
void RunWorker(int worker_idx);
|
|
5553
5583
|
void SyncOn(Async *async);
|
|
5554
5584
|
|
|
5555
|
-
void RunTasks(int
|
|
5585
|
+
void RunTasks(int worker_idx);
|
|
5556
5586
|
void RunTask(Task *task);
|
|
5557
5587
|
};
|
|
5558
5588
|
|
|
@@ -5643,25 +5673,72 @@ AsyncPool::AsyncPool(int threads, bool leak)
|
|
|
5643
5673
|
threads = RG_ASYNC_MAX_THREADS;
|
|
5644
5674
|
}
|
|
5645
5675
|
|
|
5646
|
-
// The first queue is for the main thread
|
|
5647
|
-
|
|
5648
|
-
workers_state.AppendDefault(threads);
|
|
5649
|
-
queues.AppendDefault(threads);
|
|
5676
|
+
// The first queue is for the main thread
|
|
5677
|
+
workers.AppendDefault(threads);
|
|
5650
5678
|
|
|
5651
5679
|
refcount = leak;
|
|
5652
5680
|
}
|
|
5653
5681
|
|
|
5682
|
+
#ifdef _WIN32
|
|
5683
|
+
|
|
5684
|
+
static DWORD WINAPI RunWorkerWin32(void *udata)
|
|
5685
|
+
{
|
|
5686
|
+
WorkerData *worker = (WorkerData *)udata;
|
|
5687
|
+
worker->pool->RunWorker(worker->idx);
|
|
5688
|
+
return 0;
|
|
5689
|
+
}
|
|
5690
|
+
|
|
5691
|
+
#else
|
|
5692
|
+
|
|
5693
|
+
static void *RunWorkerPthread(void *udata)
|
|
5694
|
+
{
|
|
5695
|
+
WorkerData *worker = (WorkerData *)udata;
|
|
5696
|
+
worker->pool->RunWorker(worker->idx);
|
|
5697
|
+
return nullptr;
|
|
5698
|
+
}
|
|
5699
|
+
|
|
5700
|
+
#endif
|
|
5701
|
+
|
|
5654
5702
|
void AsyncPool::RegisterAsync()
|
|
5655
5703
|
{
|
|
5656
5704
|
std::lock_guard<std::mutex> lock_pool(pool_mutex);
|
|
5657
5705
|
|
|
5658
5706
|
if (!async_count++) {
|
|
5659
|
-
for (int i = 1; i <
|
|
5660
|
-
|
|
5661
|
-
|
|
5707
|
+
for (int i = 1; i < workers.len; i++) {
|
|
5708
|
+
WorkerData *worker = &workers[i];
|
|
5709
|
+
|
|
5710
|
+
if (!worker->pool) {
|
|
5711
|
+
worker->pool = this;
|
|
5712
|
+
worker->idx = i;
|
|
5713
|
+
|
|
5714
|
+
#ifdef _WIN32
|
|
5715
|
+
// Our worker threads may exit after main() has returned (or exit has been called),
|
|
5716
|
+
// which can trigger crashes in _Cnd_do_broadcast_at_thread_exit() because it
|
|
5717
|
+
// tries to dereference destroyed stuff. It turns out that std::thread calls this
|
|
5718
|
+
// function, and we don't want that, so avoid std::thread on Windows.
|
|
5719
|
+
HANDLE h = CreateThread(nullptr, 0, RunWorkerWin32, worker, 0, nullptr);
|
|
5720
|
+
if (!h) [[unlikely]] {
|
|
5721
|
+
LogError("Failed to create worker thread: %1", GetWin32ErrorString());
|
|
5722
|
+
|
|
5723
|
+
worker->pool = nullptr;
|
|
5724
|
+
return;
|
|
5725
|
+
}
|
|
5726
|
+
|
|
5727
|
+
CloseHandle(h);
|
|
5728
|
+
#else
|
|
5729
|
+
pthread_t thread;
|
|
5730
|
+
int ret = pthread_create(&thread, nullptr, RunWorkerPthread, worker);
|
|
5731
|
+
if (ret) [[unlikely]] {
|
|
5732
|
+
LogError("Failed to create worker thread: %1", strerror(ret));
|
|
5733
|
+
|
|
5734
|
+
worker->pool = nullptr;
|
|
5735
|
+
return;
|
|
5736
|
+
}
|
|
5737
|
+
|
|
5738
|
+
pthread_detach(thread);
|
|
5739
|
+
#endif
|
|
5662
5740
|
|
|
5663
5741
|
refcount++;
|
|
5664
|
-
workers_state[i] = true;
|
|
5665
5742
|
}
|
|
5666
5743
|
}
|
|
5667
5744
|
}
|
|
@@ -5677,20 +5754,20 @@ void AsyncPool::AddTask(Async *async, const std::function<bool()> &func)
|
|
|
5677
5754
|
{
|
|
5678
5755
|
if (async_running_pool != async->pool) {
|
|
5679
5756
|
for (;;) {
|
|
5680
|
-
int idx =
|
|
5681
|
-
|
|
5757
|
+
int idx = GetRandomIntFast(0, (int)workers.len);
|
|
5758
|
+
WorkerData *worker = &workers[idx];
|
|
5682
5759
|
|
|
5683
|
-
std::unique_lock<std::mutex> lock_queue(
|
|
5760
|
+
std::unique_lock<std::mutex> lock_queue(worker->queue_mutex, std::try_to_lock);
|
|
5684
5761
|
if (lock_queue.owns_lock()) {
|
|
5685
|
-
|
|
5762
|
+
worker->tasks.Append({ async, func });
|
|
5686
5763
|
break;
|
|
5687
5764
|
}
|
|
5688
5765
|
}
|
|
5689
5766
|
} else {
|
|
5690
|
-
|
|
5767
|
+
WorkerData *worker = &workers[async_running_worker_idx];
|
|
5691
5768
|
|
|
5692
|
-
std::lock_guard<std::mutex> lock_queue(
|
|
5693
|
-
|
|
5769
|
+
std::lock_guard<std::mutex> lock_queue(worker->queue_mutex);
|
|
5770
|
+
worker->tasks.Append({ async, func });
|
|
5694
5771
|
}
|
|
5695
5772
|
|
|
5696
5773
|
async->remaining_tasks++;
|
|
@@ -5720,7 +5797,8 @@ void AsyncPool::RunWorker(int worker_idx)
|
|
|
5720
5797
|
pending_cv.wait_for(lock_pool, duration, [&]() { return !!pending_tasks; });
|
|
5721
5798
|
}
|
|
5722
5799
|
|
|
5723
|
-
|
|
5800
|
+
workers[worker_idx].pool = nullptr;
|
|
5801
|
+
|
|
5724
5802
|
if (!--refcount) {
|
|
5725
5803
|
lock_pool.unlock();
|
|
5726
5804
|
delete this;
|
|
@@ -5739,31 +5817,31 @@ void AsyncPool::SyncOn(Async *async)
|
|
|
5739
5817
|
async_running_worker_idx = 0;
|
|
5740
5818
|
|
|
5741
5819
|
while (async->remaining_tasks) {
|
|
5742
|
-
RunTasks(
|
|
5820
|
+
RunTasks(0);
|
|
5743
5821
|
|
|
5744
5822
|
std::unique_lock<std::mutex> lock_sync(pool_mutex);
|
|
5745
5823
|
sync_cv.wait(lock_sync, [&]() { return pending_tasks || !async->remaining_tasks; });
|
|
5746
5824
|
}
|
|
5747
5825
|
}
|
|
5748
5826
|
|
|
5749
|
-
void AsyncPool::RunTasks(int
|
|
5827
|
+
void AsyncPool::RunTasks(int worker_idx)
|
|
5750
5828
|
{
|
|
5751
5829
|
// The '12' factor is pretty arbitrary, don't try to find meaning there
|
|
5752
|
-
for (int i = 0; i <
|
|
5753
|
-
|
|
5754
|
-
std::unique_lock<std::mutex> lock_queue(
|
|
5830
|
+
for (int i = 0; i < workers.len * 12; i++) {
|
|
5831
|
+
WorkerData *worker = &workers[worker_idx];
|
|
5832
|
+
std::unique_lock<std::mutex> lock_queue(worker->queue_mutex, std::try_to_lock);
|
|
5755
5833
|
|
|
5756
|
-
if (lock_queue.owns_lock() &&
|
|
5757
|
-
Task task = std::move(
|
|
5834
|
+
if (lock_queue.owns_lock() && worker->tasks.len) {
|
|
5835
|
+
Task task = std::move(worker->tasks[0]);
|
|
5758
5836
|
|
|
5759
|
-
|
|
5760
|
-
|
|
5837
|
+
worker->tasks.RemoveFirst();
|
|
5838
|
+
worker->tasks.Trim();
|
|
5761
5839
|
|
|
5762
5840
|
lock_queue.unlock();
|
|
5763
5841
|
|
|
5764
5842
|
RunTask(&task);
|
|
5765
5843
|
} else {
|
|
5766
|
-
|
|
5844
|
+
worker_idx = (++worker_idx < workers.len) ? worker_idx : 0;
|
|
5767
5845
|
}
|
|
5768
5846
|
}
|
|
5769
5847
|
}
|
|
@@ -5982,10 +6060,16 @@ void Fiber::FiberCallback(unsigned int high, unsigned int low)
|
|
|
5982
6060
|
static RG_THREAD_LOCAL std::unique_lock<std::mutex> *fib_lock;
|
|
5983
6061
|
static RG_THREAD_LOCAL Fiber *fib_self;
|
|
5984
6062
|
|
|
5985
|
-
Fiber::Fiber(const std::function<bool()> &f, Size
|
|
6063
|
+
Fiber::Fiber(const std::function<bool()> &f, Size)
|
|
5986
6064
|
: f(f)
|
|
5987
6065
|
{
|
|
5988
|
-
|
|
6066
|
+
int ret = pthread_create(&thread, nullptr, ThreadCallback, this);
|
|
6067
|
+
if (ret) {
|
|
6068
|
+
LogError("Failed to create thread: %1", strerror(ret));
|
|
6069
|
+
return;
|
|
6070
|
+
}
|
|
6071
|
+
joinable = true;
|
|
6072
|
+
|
|
5989
6073
|
done = false;
|
|
5990
6074
|
|
|
5991
6075
|
while (toggle == 1) {
|
|
@@ -5998,8 +6082,8 @@ Fiber::~Fiber()
|
|
|
5998
6082
|
// We are forced to execute it until the end
|
|
5999
6083
|
Finalize();
|
|
6000
6084
|
|
|
6001
|
-
if (
|
|
6002
|
-
thread
|
|
6085
|
+
if (joinable) {
|
|
6086
|
+
pthread_join(thread, nullptr);
|
|
6003
6087
|
}
|
|
6004
6088
|
}
|
|
6005
6089
|
|
|
@@ -6030,7 +6114,7 @@ bool Fiber::SwitchBack()
|
|
|
6030
6114
|
}
|
|
6031
6115
|
}
|
|
6032
6116
|
|
|
6033
|
-
void Fiber::ThreadCallback(void *udata)
|
|
6117
|
+
void *Fiber::ThreadCallback(void *udata)
|
|
6034
6118
|
{
|
|
6035
6119
|
Fiber *self = (Fiber *)udata;
|
|
6036
6120
|
|
|
@@ -6047,6 +6131,8 @@ void Fiber::ThreadCallback(void *udata)
|
|
|
6047
6131
|
|
|
6048
6132
|
self->toggle = 0;
|
|
6049
6133
|
self->cv.notify_one();
|
|
6134
|
+
|
|
6135
|
+
return nullptr;
|
|
6050
6136
|
}
|
|
6051
6137
|
|
|
6052
6138
|
void Fiber::Toggle(int to, std::unique_lock<std::mutex> *lock)
|