YSTest: YCommon.cpp 源文件

YSTest PreAlpha_b900_20201012 The YSLib Test Project

YCommon.cpp
浏览该文件的文档.
1 /*
2 © 2009-2016, 2018-2019 FrankHB.
3
4 This file is part of the YSLib project, and may only be used,
5 modified, and distributed under the terms of the YSLib project
6 license, LICENSE.TXT. By continuing to use, modify, or distribute
7 this file you indicate that you have read the license and
8 understand and accept it fully.
9 */
10
28 #include "YCLib/YModules.h"
29 #include YFM_YCLib_Debug
30 #include <cstdlib> // for std::abort, std::system;
31 #include YFM_YCLib_NativeAPI // for ::swiWaitForVBlank, ::sysconf,
32 // _SC_PAGESIZE, _SC_SEM_NSEMS_MAX, _SC_SEM_VALUE_MAX, _SC_SYMLOOP_MAX,
33 // ::fifoSendValue32, ::SYSTEM_INFO, ::GetSystemInfo;
34 #include <limits> // for std::numeric_limits;
35 #include <limits.h> // for _POSIX_SEM_NSEMS_MAX, _POSIX_SYMLOOP_MAX,
36 // _POSIX_SEM_VALUE_MAX;
37 #if YCL_Win32
38 # include YFM_Win32_YCLib_NLS // for platform_ex::UTF8ToWCS, ::STARTUPINFOW,
39 // ::PROCESS_INFORMATION, ::CreateProcessW, CREATE_UNICODE_ENVIRONMENT,
40 // platform_ex::WaitUnique, ::GetExitCodeProcess;
41 #endif
42 #include <stdlib.h> // for ::_wsystem, ::_putenv, ::setenv;
43
44 namespace platform
45 {
46
47 void
48 terminate() ynothrow
49 {
50 #if YCL_DS
51 while(true)
52 ::swiWaitForVBlank();
53 #else
54 std::abort();
55 #endif
56 }
57
58 int
59 uspawn(const char* cmd)
60 {
61 #if YCL_Win32
62 auto wcmd(platform_ex::UTF8ToWCS(cmd));
63 // NOTE: See https://blogs.msdn.microsoft.com/oldnewthing/20031210-00/?p=41553/.
64 // XXX: With inspection of UCRT source (SDK version 10.0.17134.0), some MSDN
65 // documents seems to be wrong of the limit, e.g. https://docs.microsoft.com/en-us/cpp/c-runtime-library/reference/spawnvpe-wspawnvpe?view=vs-2017.
66 // The actual limit should be same to %::_wexecvp and %::CreateProcessW in
67 // current versions of Windows, i.e. 32767.
68 ::STARTUPINFOW startup_info{};
69 ::PROCESS_INFORMATION process_info{};
70
71 startup_info.cb = sizeof(::STARTUPINFOW);
72 if(::CreateProcessW(nullptr, &wcmd[0], {}, {}, true,
73 CREATE_UNICODE_ENVIRONMENT, {}, {}, &startup_info, &process_info))
74 {
75 platform_ex::WaitUnique(process_info.hProcess);
76
77 unsigned long exit_code(0);
78
79 if(::GetExitCodeProcess(process_info.hProcess, &exit_code))
80 // XXX: Cast expexted.
81 return int(exit_code);
82 YCL_Raise_Win32E("GetExitCodeProcess", yfsig);
83 }
84 YCL_Raise_Win32E("CreateProcessW", yfsig);
85 #else
86 return std::system(cmd);
87 #endif
88 }
89
90 int
91 usystem(const char* cmd)
92 {
93 #if YCL_Win32
94 return ::_wsystem(platform_ex::UTF8ToWCS(cmd).c_str());
95 #else
96 return std::system(cmd);
97 #endif
98 }
99
100
101 void
102 SetEnvironmentVariable(const char* envname, const char* envval)
103 {
104 #if YCL_DS
105 yunused(envname), yunused(envval);
106 ystdex::throw_error(std::errc::function_not_supported, yfsig);
107 #elif YCL_Win32
108 // TODO: Use %::_wputenv_s when available.
109 // NOTE: Only narrow enviornment is used.
110 // XXX: Though not documented, %::putenv actually copies the argument.
111 // Confirmed in ucrt source. See also https://patchwork.ozlabs.org/patch/127453/.
112 YCL_CallF_CAPI(, ::_putenv,
113 (string(Nonnull(envname)) + '=' + Nonnull(envval)).c_str());
114 #else
115 YCL_CallF_CAPI(, ::setenv, Nonnull(envname), Nonnull(envval), 1);
116 #endif
117 }
118
119
120 size_t
121 FetchLimit(SystemOption opt) ynothrow
122 {
123 // NOTE: For constant expression value that is always less than max value
124 // of %size_t, there is no check needed.
125 // XXX: Values greater than maximum value of %size_t would be truncated.
126 const auto conf_conv([](long n){
127 using res_t = ystdex::common_type_t<long, size_t>;
128 return n >= 0 && res_t(n) < res_t(std::numeric_limits<size_t>::max())
129 ? size_t(n) : size_t(-1);
130 });
131
132 // NOTE: For POSIX-defined minimum values, if the macro is undefined,
133 // use the value specified in POSIX.1-2013 instead. See http://pubs.opengroup.org/onlinepubs/9699919799/basedefs/limits.h.html.
134 switch(opt)
135 {
136 case SystemOption::PageSize:
137 // NOTE: Value of 0 indicates the target system does not support paging.
138 // Though POSIX requires 1 as minimum acceptable value, it is intended
139 // here. For platforms without an appropriate page size, it should be
140 // specified here explicitly, rather than relying on the system library
141 // with POSIX compliance. For example, RTEMS: https://devel.rtems.org/ticket/1216.
142 #if YCL_DS
143 return 0;
144 #elif YCL_Win32
145 ::SYSTEM_INFO info;
146 ::GetSystemInfo(&info);
147
148 return size_t(info.dwPageSize);
149 #elif defined(_SC_PAGESIZE)
150 return conf_conv(::sysconf(_SC_PAGESIZE));
151 #else
152 // XXX: %::getpagesize is not used. Fallback to POSIX allowed minimum
153 // value.
154 return 1;
155 #endif
156 case SystemOption::MaxSemaphoreNumber:
157 #if YCL_DS
158 return 0;
159 #elif YCL_Win32
160 return size_t(-1);
161 #elif defined(_SC_SEM_NSEMS_MAX)
162 return conf_conv(::sysconf(_SC_SEM_NSEMS_MAX));
163 #elif defined(_POSIX_SEM_NSEMS_MAX)
164 static_assert(size_t(_POSIX_SEM_NSEMS_MAX) == _POSIX_SEM_NSEMS_MAX,
165 "Invalid value found.");
166
167 return _POSIX_SEM_NSEMS_MAX;
168 #else
169 return 256;
170 #endif
171 case SystemOption::MaxSemaphoreValue:
172 #if YCL_Win32
173 static_assert(long(size_t(std::numeric_limits<long>::max()))
174 == std::numeric_limits<long>::max(), "Invalid value found.");
175
176 return size_t(std::numeric_limits<long>::max());
177 #elif defined(_SC_SEM_VALUE_MAX)
178 return conf_conv(::sysconf(_SC_SEM_VALUE_MAX));
179 #elif defined(_POSIX_SEM_VALUE_MAX)
180 static_assert(size_t(_POSIX_SEM_VALUE_MAX) == _POSIX_SEM_VALUE_MAX,
181 "Invalid value found.");
182
183 return _POSIX_SEM_VALUE_MAX;
184 #else
185 return 256;
186 #endif
187 case SystemOption::MaxSymlinkLoop:
188 #if YCL_DS
189 return 0;
190 #elif defined(_SC_SYMLOOP_MAX)
191 return conf_conv(::sysconf(_SC_SYMLOOP_MAX));
192 #elif defined(_POSIX_SYMLOOP_MAX)
193 static_assert(size_t(_POSIX_SYMLOOP_MAX) == _POSIX_SYMLOOP_MAX,
194 "Invalid value found.");
195
196 return _POSIX_SYMLOOP_MAX;
197 #else
198 // NOTE: Windows has nothing about this concept. Win32 error
199 // %ERROR_CANT_RESOLVE_FILENAME maps to Windows NT error
200 // %STATUS_REPARSE_POINT_NOT_RESOLVED, which seems to be not
201 // necessarily related to a fixed loop limit. To keep POSIX compliant
202 // and better performance of loop detection, minimum allowed value is
203 // used. See also https://cygwin.com/ml/cygwin/2009-03/msg00335.html.
204 // TODO: Make it configurable for Windows?
205 return 8;
206 #endif
207 default:
208 break;
209 }
210 #if !YCL_DS
211 YTraceDe(Descriptions::Warning,
212 "Configuration option '%zu' is not handled.", size_t(opt));
213 errno = EINVAL;
214 #endif
215 return size_t(-1);
216 }
217
218 } // namespace platform;
219
220 namespace platform_ex
221 {
222
223 #if YCL_DS
224 bool
225 AllowSleep(bool b)
226 {
227 // NOTE: Synchronized with ARM7 power management.
228 static bool b_sleep_enabled(true);
229 const bool b_old(b_sleep_enabled);
230
231 if(b != b_sleep_enabled)
232 {
233 b_sleep_enabled = b;
234 ::fifoSendValue32(FIFO_PM,
235 b ? PM_REQ_SLEEP_ENABLE : PM_REQ_SLEEP_DISABLE);
236 }
237 return b_old;
238 }
239 #elif YCL_Win32
240
241 #endif
242
243 }
244
platform::Nonnull
YB_PURE _type && Nonnull(_type &&p) ynothrowv
断言并返回非空参数。
Definition: Debug.h:518
platform::SystemOption::PageSize
@ PageSize
内存页面字节数。
platform::usystem
YF_API int usystem(const char *)
执行 UTF-8 字符串的环境命令。
Definition: YCommon.cpp:91
platform_ex
平台扩展命名空间。
Definition: Android.h:46
platform::SystemOption::MaxSemaphoreValue
@ MaxSemaphoreValue
可具有的信号量的最大值。
yfsig
#define yfsig
展开为表示函数签名的预定义变量的宏。
Definition: ydef.h:1133
platform::size_t
YB_ATTR_nodiscard YF_API size_t
Definition: FileIO.h:1345
YSLib::IO::int
YF_API int
Definition: File.h:51
YCL_Raise_Win32E
#define YCL_Raise_Win32E(...)
取转换为 errno 的 Win32 错误。
Definition: Win32/include/YCLib/MinGW32.h:147
ystdex::cpp2014::max
const _type & max(const _type &a, const _type &b, _fComp comp=less< _type >())
取较大的元素。
Definition: algorithm.hpp:635
platform::FetchLimit
YF_API size_t FetchLimit(SystemOption) ynothrow
取限制配置。
Definition: YCommon.cpp:121
platform::SetEnvironmentVariable
void SetEnvironmentVariable(const char *envname, const char *envval)
Definition: YCommon.cpp:102
platform::terminate
YB_NORETURN YF_API void terminate() ynothrow
终止函数。
Definition: YCommon.cpp:48
platform_ex::Windows::UTF8ToWCS
UTF8ToWCS
Definition: NLS.h:72
platform::ynothrow
const _tString &path ynothrow
Definition: YCLib/FileSystem.h:453
platform_ex::Windows::WaitUnique
YF_API void WaitUnique(UniqueHandle::pointer, unsigned long=INFINITE)
以指定的时间间隔上限等待句柄指定的同步对象。
platform::SystemOption
SystemOption
系统配置选项。
Definition: YCommon.h:421
ystdex::throw_error
void throw_error(std::error_code ec, _tParams &&... args)
抛出错误： std::system_error 或允许相同构造函数参数的异常。
Definition: ystdex/exception.h:241
YTraceDe
#define YTraceDe(...)
YCLib 默认调试跟踪。
Definition: Debug.h:407
platform::Descriptions::Warning
@ Warning
Definition: YCommon.h:183
platform
默认平台命名空间。
Definition: Container.h:56
YModules.h
YCLib 库模块配置文件。
NPL::c_str
YF_API const char src c_str())) YF_API void InstallDirectory(const string &
安装目录：复制目录树。
Definition: Dependency.h:140
platform::SystemOption::MaxSemaphoreNumber
@ MaxSemaphoreNumber
一个进程中可具有的信号量的最大数量。
YCL_CallF_CAPI
#define YCL_CallF_CAPI(_t, _fn,...)
Definition: YCommon.h:260
platform::uspawn
YF_API int uspawn(const char *)
执行 UTF-8 字符串的环境命令。
Definition: YCommon.cpp:59
ystdex::cpp2014::common_type_t
typename common_type< _types... >::type common_type_t
Definition: meta.hpp:205
yunused
#define yunused(...)
标记未使用的表达式。
Definition: ydef.h:1458
platform::SystemOption::MaxSymlinkLoop
@ MaxSymlinkLoop
在路径解析中符号链接可被可靠遍历的最大次数。