summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/yuzu/startup_checks.cpp82
-rw-r--r--src/yuzu/startup_checks.h4
2 files changed, 64 insertions, 22 deletions
diff --git a/src/yuzu/startup_checks.cpp b/src/yuzu/startup_checks.cpp
index 6a91212e2..ccdcf10fa 100644
--- a/src/yuzu/startup_checks.cpp
+++ b/src/yuzu/startup_checks.cpp
@@ -4,16 +4,19 @@
4#include "video_core/vulkan_common/vulkan_wrapper.h" 4#include "video_core/vulkan_common/vulkan_wrapper.h"
5 5
6#ifdef _WIN32 6#ifdef _WIN32
7#include <cstring> // for memset, strncpy 7#include <cstring>
8#include <processthreadsapi.h> 8#include <processthreadsapi.h>
9#include <windows.h> 9#include <windows.h>
10#elif defined(YUZU_UNIX) 10#elif defined(YUZU_UNIX)
11#include <cstring>
11#include <errno.h> 12#include <errno.h>
13#include <spawn.h>
14#include <sys/types.h>
12#include <sys/wait.h> 15#include <sys/wait.h>
13#include <unistd.h> 16#include <unistd.h>
14#endif 17#endif
15 18
16#include <cstdio> 19#include <fmt/core.h>
17#include "video_core/vulkan_common/vulkan_instance.h" 20#include "video_core/vulkan_common/vulkan_instance.h"
18#include "video_core/vulkan_common/vulkan_library.h" 21#include "video_core/vulkan_common/vulkan_library.h"
19#include "yuzu/startup_checks.h" 22#include "yuzu/startup_checks.h"
@@ -27,7 +30,7 @@ void CheckVulkan() {
27 Vulkan::CreateInstance(library, dld, VK_API_VERSION_1_0); 30 Vulkan::CreateInstance(library, dld, VK_API_VERSION_1_0);
28 31
29 } catch (const Vulkan::vk::Exception& exception) { 32 } catch (const Vulkan::vk::Exception& exception) {
30 std::fprintf(stderr, "Failed to initialize Vulkan: %s\n", exception.what()); 33 fmt::print(stderr, "Failed to initialize Vulkan: {}\n", exception.what());
31 } 34 }
32} 35}
33 36
@@ -49,8 +52,15 @@ bool CheckEnvVars(bool* is_child) {
49 *is_child = true; 52 *is_child = true;
50 return false; 53 return false;
51 } else if (!SetEnvironmentVariableA(IS_CHILD_ENV_VAR, ENV_VAR_ENABLED_TEXT)) { 54 } else if (!SetEnvironmentVariableA(IS_CHILD_ENV_VAR, ENV_VAR_ENABLED_TEXT)) {
52 std::fprintf(stderr, "SetEnvironmentVariableA failed to set %s with error %lu\n", 55 fmt::print(stderr, "SetEnvironmentVariableA failed to set {} with error {}\n",
53 IS_CHILD_ENV_VAR, GetLastError()); 56 IS_CHILD_ENV_VAR, GetLastError());
57 return true;
58 }
59#elif defined(YUZU_UNIX)
60 const char* startup_check_var = getenv(STARTUP_CHECK_ENV_VAR);
61 if (startup_check_var != nullptr &&
62 std::strncmp(startup_check_var, ENV_VAR_ENABLED_TEXT, 8) == 0) {
63 CheckVulkan();
54 return true; 64 return true;
55 } 65 }
56#endif 66#endif
@@ -62,8 +72,8 @@ bool StartupChecks(const char* arg0, bool* has_broken_vulkan, bool perform_vulka
62 // Set the startup variable for child processes 72 // Set the startup variable for child processes
63 const bool env_var_set = SetEnvironmentVariableA(STARTUP_CHECK_ENV_VAR, ENV_VAR_ENABLED_TEXT); 73 const bool env_var_set = SetEnvironmentVariableA(STARTUP_CHECK_ENV_VAR, ENV_VAR_ENABLED_TEXT);
64 if (!env_var_set) { 74 if (!env_var_set) {
65 std::fprintf(stderr, "SetEnvironmentVariableA failed to set %s with error %lu\n", 75 fmt::print(stderr, "SetEnvironmentVariableA failed to set {} with error {}\n",
66 STARTUP_CHECK_ENV_VAR, GetLastError()); 76 STARTUP_CHECK_ENV_VAR, GetLastError());
67 return false; 77 return false;
68 } 78 }
69 79
@@ -81,48 +91,57 @@ bool StartupChecks(const char* arg0, bool* has_broken_vulkan, bool perform_vulka
81 DWORD exit_code = STILL_ACTIVE; 91 DWORD exit_code = STILL_ACTIVE;
82 const int err = GetExitCodeProcess(process_info.hProcess, &exit_code); 92 const int err = GetExitCodeProcess(process_info.hProcess, &exit_code);
83 if (err == 0) { 93 if (err == 0) {
84 std::fprintf(stderr, "GetExitCodeProcess failed with error %lu\n", GetLastError()); 94 fmt::print(stderr, "GetExitCodeProcess failed with error {}\n", GetLastError());
85 } 95 }
86 96
87 // Vulkan is broken if the child crashed (return value is not zero) 97 // Vulkan is broken if the child crashed (return value is not zero)
88 *has_broken_vulkan = (exit_code != 0); 98 *has_broken_vulkan = (exit_code != 0);
89 99
90 if (CloseHandle(process_info.hProcess) == 0) { 100 if (CloseHandle(process_info.hProcess) == 0) {
91 std::fprintf(stderr, "CloseHandle failed with error %lu\n", GetLastError()); 101 fmt::print(stderr, "CloseHandle failed with error {}\n", GetLastError());
92 } 102 }
93 if (CloseHandle(process_info.hThread) == 0) { 103 if (CloseHandle(process_info.hThread) == 0) {
94 std::fprintf(stderr, "CloseHandle failed with error %lu\n", GetLastError()); 104 fmt::print(stderr, "CloseHandle failed with error {}\n", GetLastError());
95 } 105 }
96 } 106 }
97 107
98 if (!SetEnvironmentVariableA(STARTUP_CHECK_ENV_VAR, nullptr)) { 108 if (!SetEnvironmentVariableA(STARTUP_CHECK_ENV_VAR, nullptr)) {
99 std::fprintf(stderr, "SetEnvironmentVariableA failed to clear %s with error %lu\n", 109 fmt::print(stderr, "SetEnvironmentVariableA failed to clear {} with error {}\n",
100 STARTUP_CHECK_ENV_VAR, GetLastError()); 110 STARTUP_CHECK_ENV_VAR, GetLastError());
101 } 111 }
102 112
103#elif defined(YUZU_UNIX) 113#elif defined(YUZU_UNIX)
114 const int env_var_set = setenv(STARTUP_CHECK_ENV_VAR, ENV_VAR_ENABLED_TEXT, 1);
115 if (env_var_set == -1) {
116 const int err = errno;
117 fmt::print(stderr, "setenv failed to set {} with error {}\n", STARTUP_CHECK_ENV_VAR, err);
118 return false;
119 }
120
104 if (perform_vulkan_check) { 121 if (perform_vulkan_check) {
105 const pid_t pid = fork(); 122 const pid_t pid = SpawnChild(arg0);
106 if (pid == 0) { 123 if (pid == -1) {
107 CheckVulkan();
108 return true;
109 } else if (pid == -1) {
110 const int err = errno;
111 std::fprintf(stderr, "fork failed with error %d\n", err);
112 return false; 124 return false;
113 } 125 }
114 126
115 // Get exit code from child process 127 // Get exit code from child process
116 int status; 128 int status;
117 const int r_val = wait(&status); 129 const int r_val = waitpid(pid, &status, 0);
118 if (r_val == -1) { 130 if (r_val == -1) {
119 const int err = errno; 131 const int err = errno;
120 std::fprintf(stderr, "wait failed with error %d\n", err); 132 fmt::print(stderr, "wait failed with error {}\n", err);
121 return false; 133 return false;
122 } 134 }
123 // Vulkan is broken if the child crashed (return value is not zero) 135 // Vulkan is broken if the child crashed (return value is not zero)
124 *has_broken_vulkan = (status != 0); 136 *has_broken_vulkan = (status != 0);
125 } 137 }
138
139 const int env_var_cleared = unsetenv(STARTUP_CHECK_ENV_VAR);
140 if (env_var_cleared == -1) {
141 const int err = errno;
142 fmt::print(stderr, "unsetenv failed to clear {} with error {}\n", STARTUP_CHECK_ENV_VAR,
143 err);
144 }
126#endif 145#endif
127 return false; 146 return false;
128} 147}
@@ -150,10 +169,29 @@ bool SpawnChild(const char* arg0, PROCESS_INFORMATION* pi, int flags) {
150 pi // lpProcessInformation 169 pi // lpProcessInformation
151 ); 170 );
152 if (!process_created) { 171 if (!process_created) {
153 std::fprintf(stderr, "CreateProcessA failed with error %lu\n", GetLastError()); 172 fmt::print(stderr, "CreateProcessA failed with error {}\n", GetLastError());
154 return false; 173 return false;
155 } 174 }
156 175
157 return true; 176 return true;
158} 177}
178#elif defined(YUZU_UNIX)
179pid_t SpawnChild(const char* arg0) {
180 const pid_t pid = fork();
181
182 if (pid == -1) {
183 // error
184 const int err = errno;
185 fmt::print(stderr, "fork failed with error {}\n", err);
186 return pid;
187 } else if (pid == 0) {
188 // child
189 execl(arg0, arg0, nullptr);
190 const int err = errno;
191 fmt::print(stderr, "execl failed with error {}\n", err);
192 _exit(0);
193 }
194
195 return pid;
196}
159#endif 197#endif
diff --git a/src/yuzu/startup_checks.h b/src/yuzu/startup_checks.h
index d8e563be6..2f86fb843 100644
--- a/src/yuzu/startup_checks.h
+++ b/src/yuzu/startup_checks.h
@@ -5,6 +5,8 @@
5 5
6#ifdef _WIN32 6#ifdef _WIN32
7#include <windows.h> 7#include <windows.h>
8#elif defined(YUZU_UNIX)
9#include <sys/types.h>
8#endif 10#endif
9 11
10constexpr char IS_CHILD_ENV_VAR[] = "YUZU_IS_CHILD"; 12constexpr char IS_CHILD_ENV_VAR[] = "YUZU_IS_CHILD";
@@ -17,4 +19,6 @@ bool StartupChecks(const char* arg0, bool* has_broken_vulkan, bool perform_vulka
17 19
18#ifdef _WIN32 20#ifdef _WIN32
19bool SpawnChild(const char* arg0, PROCESS_INFORMATION* pi, int flags); 21bool SpawnChild(const char* arg0, PROCESS_INFORMATION* pi, int flags);
22#elif defined(YUZU_UNIX)
23pid_t SpawnChild(const char* arg0);
20#endif 24#endif