7#if BLI_SUBPROCESS_SUPPORT
18static bool check_arguments_are_valid(Span<StringRefNull> args)
20 for (StringRefNull arg : args) {
21 for (
const char c : arg) {
22 if (!std::isalnum(c) && !
ELEM(c,
'_',
'-')) {
35# define WIN32_LEAN_AND_MEAN
41static void print_last_error(
const char *function,
const char *msg)
43 DWORD error_code = GetLastError();
44 std::cerr <<
"ERROR (" << error_code <<
"): " << function <<
" : " << msg << std::endl;
47static void check(
bool result,
const char *function,
const char *msg)
50 print_last_error(function, msg);
55# define CHECK(result) check((result), __func__, #result)
57# define ERROR(msg) check(false, __func__, msg)
68 handle_ = CreateJobObject(
nullptr,
nullptr);
70 JOBOBJECT_EXTENDED_LIMIT_INFORMATION info = {0};
71 info.BasicLimitInformation.LimitFlags = JOB_OBJECT_LIMIT_KILL_ON_JOB_CLOSE;
73 SetInformationJobObject(handle_, JobObjectExtendedLimitInformation, &info,
sizeof(info)));
78 CHECK(CloseHandle(handle_));
81 void assign_subprocess(HANDLE subprocess)
83 CHECK(AssignProcessToJobObject(handle_, subprocess));
87bool BlenderSubprocess::create(Span<StringRefNull> args)
91 if (!check_arguments_are_valid(args)) {
97 if (!GetModuleFileNameW(
nullptr, path,
FILE_MAX)) {
98 ERROR(
"GetModuleFileNameW");
102 std::string args_str;
103 for (StringRefNull arg : args) {
104 args_str += arg +
" ";
107 const int length_wc = MultiByteToWideChar(
108 CP_UTF8, 0, args_str.c_str(), args_str.length(),
nullptr, 0);
109 std::wstring w_args(length_wc, 0);
110 CHECK(MultiByteToWideChar(
111 CP_UTF8, 0, args_str.c_str(), args_str.length(), w_args.data(), length_wc));
113 STARTUPINFOW startup_info = {0};
114 startup_info.cb =
sizeof(startup_info);
115 PROCESS_INFORMATION process_info = {0};
116 if (!CreateProcessW(path,
122 CREATE_BREAKAWAY_FROM_JOB,
128 ERROR(
"CreateProcessW");
132 handle_ = process_info.hProcess;
133 CHECK(CloseHandle(process_info.hThread));
135 static ProcessGroup group;
137 group.assign_subprocess(handle_);
142BlenderSubprocess::~BlenderSubprocess()
145 CHECK(CloseHandle(handle_));
149bool BlenderSubprocess::is_running()
156 if (GetExitCodeProcess(handle_, &exit_code)) {
157 return exit_code == STILL_ACTIVE;
160 ERROR(
"GetExitCodeProcess");
165SharedMemory::SharedMemory(std::string name,
size_t size,
bool is_owner)
166 : name_(name), is_owner_(is_owner)
169 handle_ = CreateFileMappingA(
170 INVALID_HANDLE_VALUE,
nullptr, PAGE_READWRITE, 0, size, name.c_str());
174 handle_ = OpenFileMappingA(FILE_MAP_ALL_ACCESS,
FALSE, name.c_str());
179 data_ = MapViewOfFile(handle_, FILE_MAP_ALL_ACCESS, 0, 0, size);
186 data_size_ = data_ ?
size : 0;
189SharedMemory::~SharedMemory()
192 CHECK(UnmapViewOfFile(data_));
195 CHECK(CloseHandle(handle_));
199SharedSemaphore::SharedSemaphore(std::string name,
bool is_owner)
200 : name_(name), is_owner_(is_owner)
202 handle_ = CreateSemaphoreA(
nullptr, 0, 1, name.c_str());
206SharedSemaphore::~SharedSemaphore()
209 CHECK(CloseHandle(handle_));
213void SharedSemaphore::increment()
215 CHECK(ReleaseSemaphore(handle_, 1,
nullptr));
218void SharedSemaphore::decrement()
220 CHECK(WaitForSingleObject(handle_, INFINITE) != WAIT_FAILED);
223bool SharedSemaphore::try_decrement(
int wait_ms)
225 DWORD result = WaitForSingleObject(handle_, wait_ms);
226 CHECK(result != WAIT_FAILED);
227 return result == WAIT_OBJECT_0;
232# elif defined(__linux__)
237# include <linux/limits.h>
239# include <sys/mman.h>
240# include <sys/stat.h>
246static void print_last_error(
const char *function,
const char *msg)
248 int error_code = errno;
249 std::string error_msg =
"ERROR (" + std::to_string(error_code) +
"): " + function +
" : " + msg;
250 perror(error_msg.c_str());
253static void check(
int result,
const char *function,
const char *msg)
256 print_last_error(function, msg);
261# define CHECK(result) check((result), __func__, #result)
262# define ERROR(msg) check(-1, __func__, msg)
264bool BlenderSubprocess::create(Span<StringRefNull> args)
266 if (!check_arguments_are_valid(args)) {
272 const size_t len = readlink(
"/proc/self/exe", path,
PATH_MAX);
273 if (
len ==
size_t(-1)) {
280 Vector<char *> char_args;
281 for (StringRefNull arg : args) {
282 char_args.append((
char *)arg.data());
284 char_args.append(
nullptr);
297 execv(path, char_args.data());
312BlenderSubprocess::~BlenderSubprocess() {}
314bool BlenderSubprocess::is_running()
320 pid_t result = waitpid(pid_,
nullptr, WNOHANG);
323 if (result == pid_) {
331SharedMemory::SharedMemory(std::string name,
size_t size,
bool is_owner)
332 : name_(name), is_owner_(is_owner)
334 constexpr mode_t user_mode = S_IRUSR | S_IWUSR;
336 handle_ = shm_open(name.c_str(), O_CREAT | O_EXCL | O_RDWR, user_mode);
339 if (ftruncate(handle_, size) == -1) {
341 CHECK(close(handle_));
347 handle_ = shm_open(name.c_str(), O_RDWR, user_mode);
352 data_ = mmap(
nullptr, size, PROT_READ | PROT_WRITE, MAP_SHARED, handle_, 0);
353 if (data_ == MAP_FAILED) {
358 CHECK(close(handle_));
364 data_size_ = data_ ?
size : 0;
367SharedMemory::~SharedMemory()
370 CHECK(munmap(data_, data_size_));
372 CHECK(shm_unlink(name_.c_str()));
377SharedSemaphore::SharedSemaphore(std::string name,
bool is_owner)
378 : name_(name), is_owner_(is_owner)
380 constexpr mode_t user_mode = S_IRUSR | S_IWUSR;
381 handle_ = sem_open(name.c_str(), O_CREAT, user_mode, 0);
387SharedSemaphore::~SharedSemaphore()
390 CHECK(sem_close(handle_));
392 CHECK(sem_unlink(name_.c_str()));
397void SharedSemaphore::increment()
399 CHECK(sem_post(handle_));
402void SharedSemaphore::decrement()
405 int result = sem_wait(handle_);
409 else if (errno != EINTR) {
417bool SharedSemaphore::try_decrement(
int wait_ms)
420 int result = sem_trywait(handle_);
424 else if (errno == EINVAL) {
425 ERROR(
"sem_trywait");
431 if (clock_gettime(CLOCK_REALTIME, &time) == -1) {
432 ERROR(
"clock_gettime");
434 return try_decrement(0);
437 time.tv_sec += wait_ms / 1000;
438 time.tv_nsec += (wait_ms % 1000) * 10e6;
441 int result = sem_timedwait(handle_, &time);
445 else if (errno != EINTR) {
446 if (errno != ETIMEDOUT) {
447 ERROR(
"sem_timedwait");
#define BLI_assert_unreachable()
Platform independent time functions.
void BLI_time_sleep_ms(int ms)
static DBVT_INLINE btScalar size(const btDbvtVolume &a)
#define CHECK(test_value, str, ofs, msg)