11#if BLI_SUBPROCESS_SUPPORT
25 for (
const char c : arg) {
26 if (!std::isalnum(c) && !
ELEM(c,
'_',
'-')) {
39# define WIN32_LEAN_AND_MEAN
45static void print_last_error(
const char *function,
const char *msg)
47 DWORD error_code = GetLastError();
48 std::cerr <<
"ERROR (" << error_code <<
"): " << function <<
" : " << msg << std::endl;
51static void check(
bool result,
const char *function,
const char *msg)
54 print_last_error(function, msg);
59# define CHECK(result) check((result), __func__, #result)
61# define ERROR(msg) check(false, __func__, msg)
72 handle_ = CreateJobObject(
nullptr,
nullptr);
74 JOBOBJECT_EXTENDED_LIMIT_INFORMATION info = {0};
75 info.BasicLimitInformation.LimitFlags = JOB_OBJECT_LIMIT_KILL_ON_JOB_CLOSE;
77 SetInformationJobObject(handle_, JobObjectExtendedLimitInformation, &info,
sizeof(info)));
82 CHECK(CloseHandle(handle_));
85 void assign_subprocess(HANDLE subprocess)
87 CHECK(AssignProcessToJobObject(handle_, subprocess));
95 if (!check_arguments_are_valid(args)) {
101 if (!GetModuleFileNameW(
nullptr, path,
FILE_MAX)) {
102 ERROR(
"GetModuleFileNameW");
106 std::string args_str;
108 args_str += arg +
" ";
111 const int length_wc = MultiByteToWideChar(
112 CP_UTF8, 0, args_str.c_str(), args_str.length(),
nullptr, 0);
113 std::wstring w_args(length_wc, 0);
114 CHECK(MultiByteToWideChar(
115 CP_UTF8, 0, args_str.c_str(), args_str.length(), w_args.data(), length_wc));
117 STARTUPINFOW startup_info = {0};
118 startup_info.cb =
sizeof(startup_info);
119 PROCESS_INFORMATION process_info = {0};
120 if (!CreateProcessW(path,
126 CREATE_BREAKAWAY_FROM_JOB,
132 ERROR(
"CreateProcessW");
136 handle_ = process_info.hProcess;
137 CHECK(CloseHandle(process_info.hThread));
139 static ProcessGroup group;
141 group.assign_subprocess(handle_);
146BlenderSubprocess::~BlenderSubprocess()
149 CHECK(CloseHandle(handle_));
153bool BlenderSubprocess::is_running()
160 if (GetExitCodeProcess(handle_, &exit_code)) {
161 return exit_code == STILL_ACTIVE;
164 ERROR(
"GetExitCodeProcess");
169SharedMemory::SharedMemory(std::string
name,
size_t size,
bool is_owner)
170 : name_(
name), is_owner_(is_owner)
173 handle_ = CreateFileMappingA(
174 INVALID_HANDLE_VALUE,
nullptr, PAGE_READWRITE, 0,
size,
name.c_str());
178 handle_ = OpenFileMappingA(FILE_MAP_ALL_ACCESS,
FALSE,
name.c_str());
183 data_ = MapViewOfFile(handle_, FILE_MAP_ALL_ACCESS, 0, 0,
size);
190 data_size_ = data_ ?
size : 0;
193SharedMemory::~SharedMemory()
196 CHECK(UnmapViewOfFile(data_));
199 CHECK(CloseHandle(handle_));
203SharedSemaphore::SharedSemaphore(std::string
name,
bool is_owner)
204 : name_(
name), is_owner_(is_owner)
206 handle_ = CreateSemaphoreA(
nullptr, 0, 1,
name.c_str());
210SharedSemaphore::~SharedSemaphore()
213 CHECK(CloseHandle(handle_));
217void SharedSemaphore::increment()
219 CHECK(ReleaseSemaphore(handle_, 1,
nullptr));
222void SharedSemaphore::decrement()
224 CHECK(WaitForSingleObject(handle_, INFINITE) != WAIT_FAILED);
227bool SharedSemaphore::try_decrement(
int wait_ms)
229 DWORD
result = WaitForSingleObject(handle_, wait_ms);
231 return result == WAIT_OBJECT_0;
236# elif defined(__linux__)
241# include <linux/limits.h>
243# include <sys/mman.h>
244# include <sys/stat.h>
250static void print_last_error(
const char *function,
const char *msg)
252 int error_code = errno;
253 std::string error_msg =
"ERROR (" + std::to_string(error_code) +
"): " + function +
" : " + msg;
254 perror(error_msg.c_str());
257static void check(
int result,
const char *function,
const char *msg)
260 print_last_error(function, msg);
265# define CHECK(result) check((result), __func__, #result)
266# define ERROR(msg) check(-1, __func__, msg)
270 if (!check_arguments_are_valid(args)) {
276 const size_t len = readlink(
"/proc/self/exe", path,
PATH_MAX);
277 if (
len ==
size_t(-1)) {
286 char_args.
append((
char *)arg.data());
288 char_args.
append(
nullptr);
301 execv(path, char_args.
data());
316BlenderSubprocess::~BlenderSubprocess() {}
318bool BlenderSubprocess::is_running()
324 pid_t
result = waitpid(pid_,
nullptr, WNOHANG);
335SharedMemory::SharedMemory(std::string
name,
size_t size,
bool is_owner)
336 : name_(
name), is_owner_(is_owner)
338 constexpr mode_t user_mode = S_IRUSR | S_IWUSR;
340 handle_ = shm_open(
name.c_str(), O_CREAT | O_EXCL | O_RDWR, user_mode);
343 if (ftruncate(handle_,
size) == -1) {
345 CHECK(close(handle_));
351 handle_ = shm_open(
name.c_str(), O_RDWR, user_mode);
356 data_ = mmap(
nullptr,
size, PROT_READ | PROT_WRITE, MAP_SHARED, handle_, 0);
357 if (data_ == MAP_FAILED) {
362 CHECK(close(handle_));
368 data_size_ = data_ ?
size : 0;
371SharedMemory::~SharedMemory()
374 CHECK(munmap(data_, data_size_));
376 CHECK(shm_unlink(name_.c_str()));
381SharedSemaphore::SharedSemaphore(std::string
name,
bool is_owner)
382 : name_(
name), is_owner_(is_owner)
384 constexpr mode_t user_mode = S_IRUSR | S_IWUSR;
385 handle_ = sem_open(
name.c_str(), O_CREAT, user_mode, 0);
391SharedSemaphore::~SharedSemaphore()
394 CHECK(sem_close(handle_));
396 CHECK(sem_unlink(name_.c_str()));
401void SharedSemaphore::increment()
403 CHECK(sem_post(handle_));
406void SharedSemaphore::decrement()
409 int result = sem_wait(handle_);
413 if (errno != EINTR) {
421bool SharedSemaphore::try_decrement(
int wait_ms)
424 int result = sem_trywait(handle_);
428 if (errno == EINVAL) {
429 ERROR(
"sem_trywait");
435 if (clock_gettime(CLOCK_REALTIME, &time) == -1) {
436 ERROR(
"clock_gettime");
438 return try_decrement(0);
441 time.tv_sec += wait_ms / 1000;
442 time.tv_nsec += (wait_ms % 1000) * 10e6;
445 int result = sem_timedwait(handle_, &time);
449 if (errno != EINTR) {
450 if (errno != ETIMEDOUT) {
451 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)
void append(const T &value)
#define CHECK(expression)