diff options
-rw-r--r-- | butl/buildfile | 9 | ||||
-rw-r--r-- | butl/process.cxx | 55 |
2 files changed, 59 insertions, 5 deletions
diff --git a/butl/buildfile b/butl/buildfile index 25354c8..53fa588 100644 --- a/butl/buildfile +++ b/butl/buildfile @@ -77,7 +77,14 @@ lib{butl}: cxx.export.poptions = "-I$out_root" "-I$src_root" liba{butl}: cxx.export.poptions += -DLIBBUTL_STATIC libs{butl}: cxx.export.poptions += -DLIBBUTL_SHARED -if ($cxx.target.class != "windows") +if ($cxx.target.class == "windows") +{ + if ($cxx.target.system == "mingw32") + cxx.libs += -lpsapi + else + cxx.libs += psapi.lib +} +else cxx.libs += -lpthread # Install into the butl/ subdirectory of, say, /usr/include/. diff --git a/butl/process.cxx b/butl/process.cxx index db529a6..940560c 100644 --- a/butl/process.cxx +++ b/butl/process.cxx @@ -12,6 +12,8 @@ #else # include <butl/win32-utility> +# include <psapi.h> // EnumProcessModules(), etc + # include <io.h> // _get_osfhandle(), _close() # include <stdlib.h> // _MAX_PATH # include <sys/types.h> // stat @@ -43,6 +45,8 @@ #include <butl/fdstream> // fdnull() #include <butl/process-details> +#include <iostream> + using namespace std; #ifdef _WIN32 @@ -1166,7 +1170,9 @@ namespace butl // be in the returned list if it has failed to initialize). With this // improvement we could then wait longer and try harder. // - for (size_t ret (0); ret != 20; ++ret) + optional<bool> msys; // Absent if we don't know. + + for (size_t ret (0); ret != 5; ++ret) { if (!CreateProcess ( batch != nullptr ? batch : pp.effect_string (), @@ -1183,13 +1189,54 @@ namespace butl auto_handle (pi.hThread).reset (); // Close. - // Wait a bit (50ms) and check if the process has terminated. If it is + // Detect if this is an MSYS2 process by checking if the process has + // loaded msys-2.0.dll. + // + size_t wait (200); + + if (!msys) + { + // Wait a bit for the process to load its DLLs. + // + if (WaitForSingleObject (pi.hProcess, 50) == WAIT_TIMEOUT) + { + wait -= 50; + + DWORD mn; + HMODULE ms[32]; // Normally it is one of the first. + + if (EnumProcessModules (pi.hProcess, ms, sizeof (ms), &mn)) + { + for (DWORD i (0); !msys && i != mn / sizeof (HMODULE); ++i) + { + char p[_MAX_PATH + 1]; + if (GetModuleFileNameExA (pi.hProcess, ms[i], p, sizeof (p))) + { + size_t n (strlen (p)); + if (n >= 12 && casecmp (p + n - 12, "msys-2.0.dll") == 0) + msys = true; + } + } + + if (!msys) + msys = false; + } + // EnumProcessModules() failed (presumably because the process has + // already exited), fall through. + } + // Process exited, fall through. + } + + if (msys && !*msys) + break; + + // Wait a bit longer and check if the process has terminated. If it is // still running then we assume all is good. Otherwise, retry if this // is the DLL initialization error. // DWORD s; - if (WaitForSingleObject (pi.hProcess, 50) != WAIT_OBJECT_0 || - !GetExitCodeProcess (pi.hProcess, &s) || + if (WaitForSingleObject (pi.hProcess, wait) != WAIT_OBJECT_0 || + !GetExitCodeProcess (pi.hProcess, &s) || s != STATUS_DLL_INIT_FAILED) break; } |