Daniele Bartolini пре 6 година
родитељ
комит
de7e7b0809

+ 1 - 61
src/core/os.cpp

@@ -22,7 +22,7 @@
 	#include <string.h>   // memset
 	#include <sys/wait.h> // wait
 	#include <time.h>     // clock_gettime
-	#include <unistd.h>   // unlink, rmdir, getcwd, fork, execv, access
+	#include <unistd.h>   // unlink, rmdir, getcwd, access
 #elif CROWN_PLATFORM_WINDOWS
 	#include <io.h>       // _access
 	#include <stdio.h>
@@ -238,66 +238,6 @@ namespace os
 #endif
 	}
 
-	int execute_process(const char* const* argv, StringStream& output)
-	{
-		TempAllocator512 ta;
-		StringStream path(ta);
-
-		path << argv[0];
-		path << ' ';
-#if CROWN_PLATFORM_POSIX
-		path << "2>&1 ";
-#endif
-		for (s32 i = 1; argv[i] != NULL; ++i)
-		{
-			const char* arg = argv[i];
-			for (; *arg; ++arg)
-			{
-				if (*arg == ' ')
-					path << '\\';
-				path << *arg;
-			}
-			path << ' ';
-		}
-#if CROWN_PLATFORM_POSIX
-		FILE* file = popen(string_stream::c_str(path), "r");
-
-		char buf[1024];
-		while (fgets(buf, sizeof(buf), file) != NULL)
-			output << buf;
-
-		return pclose(file);
-#elif CROWN_PLATFORM_WINDOWS
-		STARTUPINFO info;
-		memset(&info, 0, sizeof(info));
-		info.cb = sizeof(info);
-
-		PROCESS_INFORMATION process;
-		memset(&process, 0, sizeof(process));
-
-		int err = CreateProcess(argv[0]
-			, (LPSTR)string_stream::c_str(path)
-			, NULL
-			, NULL
-			, FALSE
-			, CREATE_NO_WINDOW
-			, NULL
-			, NULL
-			, &info
-			, &process
-			);
-		CE_ASSERT(err != 0, "CreateProcess: GetLastError = %d", GetLastError());
-		CE_UNUSED(err);
-
-		DWORD exitcode = 1;
-		::WaitForSingleObject(process.hProcess, INFINITE);
-		GetExitCodeProcess(process.hProcess, &exitcode);
-		CloseHandle(process.hProcess);
-		CloseHandle(process.hThread);
-		return (int)exitcode;
-#endif
-	}
-
 } // namespace os
 
 } // namespace crown

+ 0 - 4
src/core/os.h

@@ -86,10 +86,6 @@ namespace os
 	///
 	s32 access(const char* path, u32 flags);
 
-	/// Executes the process described by @a argv and returns its exit code.
-	/// It fills @a output with stdout and stderr.
-	int execute_process(const char* const* argv, StringStream& output);
-
 } // namespace os
 
 } // namespace crown

+ 132 - 0
src/core/process.cpp

@@ -0,0 +1,132 @@
+/*
+ * Copyright (c) 2012-2018 Daniele Bartolini and individual contributors.
+ * License: https://github.com/dbartolini/crown/blob/master/LICENSE
+ */
+
+#include "core/memory/temp_allocator.h"
+#include "core/process.h"
+#include "core/strings/string_stream.h"
+
+#if CROWN_PLATFORM_POSIX
+	#include <unistd.h>   // fork, execv
+#elif CROWN_PLATFORM_WINDOWS
+	#include <windows.h>
+#endif
+
+namespace crown
+{
+struct Private
+{
+#if CROWN_PLATFORM_POSIX
+	FILE* file;
+#elif CROWN_PLATFORM_WINDOWS
+	PROCESS_INFORMATION process;
+#endif
+};
+
+namespace process_internal
+{
+	bool is_open(Private* priv)
+	{
+#if CROWN_PLATFORM_POSIX
+		return priv->file != NULL;
+#elif CROWN_PLATFORM_WINDOWS
+		return priv->process.hProcess != 0;
+#endif
+	}
+}
+
+Process::Process()
+{
+	CE_STATIC_ASSERT(sizeof(_data) >= sizeof(Private));
+	Private* priv = (Private*)_data;
+
+#if CROWN_PLATFORM_POSIX
+	priv->file = NULL;
+#elif CROWN_PLATFORM_WINDOWS
+	memset(&priv->process, 0, sizeof(priv->process));
+#endif
+}
+
+Process::~Process()
+{
+	Private* priv = (Private*)_data;
+	CE_ENSURE(process_internal::is_open(priv) == false);
+}
+
+s32 Process::spawn(const char* const* argv)
+{
+	Private* priv = (Private*)_data;
+	CE_ENSURE(process_internal::is_open(priv) == false);
+
+	TempAllocator512 ta;
+	StringStream path(ta);
+
+	path << argv[0];
+	path << ' ';
+#if CROWN_PLATFORM_POSIX
+	path << "2>&1 ";
+#endif
+	for (s32 i = 1; argv[i] != NULL; ++i)
+	{
+		const char* arg = argv[i];
+		for (; *arg; ++arg)
+		{
+			if (*arg == ' ')
+				path << '\\';
+			path << *arg;
+		}
+		path << ' ';
+	}
+#if CROWN_PLATFORM_POSIX
+	priv->file = popen(string_stream::c_str(path), "r");
+
+	return priv->file != NULL ? 0 : -1;
+#elif CROWN_PLATFORM_WINDOWS
+	STARTUPINFO info;
+	memset(&info, 0, sizeof(info));
+	info.cb = sizeof(info);
+
+	int err = CreateProcess(argv[0]
+		, (LPSTR)string_stream::c_str(path)
+		, NULL
+		, NULL
+		, FALSE
+		, CREATE_NO_WINDOW
+		, NULL
+		, NULL
+		, &info
+		, &priv->process
+		);
+	return (s32)err;
+#endif
+}
+
+s32 Process::wait(StringStream* output)
+{
+	Private* priv = (Private*)_data;
+	CE_ENSURE(process_internal::is_open(priv) == true);
+
+#if CROWN_PLATFORM_POSIX
+	if (output != NULL)
+	{
+		char buf[1024];
+		while (fgets(buf, sizeof(buf), priv->file) != NULL)
+			*output << buf;
+	}
+
+	s32 exitcode = pclose(priv->file);
+	priv->file = NULL;
+	return exitcode;
+#elif CROWN_PLATFORM_WINDOWS
+	DWORD exitcode = 1;
+	::WaitForSingleObject(priv->process.hProcess, INFINITE);
+	GetExitCodeProcess(priv->process.hProcess, &exitcode);
+	CloseHandle(priv->process.hProcess);
+	CloseHandle(priv->process.hThread);
+	memset(priv->process, 0, sizeof(priv->process));
+	return (s32)exitcode;
+#endif
+}
+
+} // namespace crown

+ 35 - 0
src/core/process.h

@@ -0,0 +1,35 @@
+/*
+ * Copyright (c) 2012-2018 Daniele Bartolini and individual contributors.
+ * License: https://github.com/dbartolini/crown/blob/master/LICENSE
+ */
+
+#pragma once
+
+#include "core/strings/types.h"
+
+namespace crown
+{
+/// Process.
+///
+/// @ingroup Core
+struct Process
+{
+	CE_ALIGN_DECL(16, u8 _data[32]);
+
+	///
+	Process();
+
+	///
+	~Process();
+
+	/// Spawns the process described by @a argv.
+	/// Returns 0 on success, non-zero otherwise.
+	s32 spawn(const char* const* argv);
+
+	/// Waits for the process to terminate and returns its exit code.
+	/// If @a output is not NULL it reads stdout and stderr into
+	/// the StringStream.
+	s32 wait(StringStream* output);
+};
+
+} // namespace crown

+ 1 - 5
src/resource/compile_options.cpp

@@ -12,6 +12,7 @@
 #include "core/guid.h"
 #include "core/memory/temp_allocator.h"
 #include "core/os.h"
+#include "core/process.h"
 #include "core/strings/dynamic_string.h"
 #include "core/strings/string_stream.h"
 #include "device/log.h"
@@ -189,9 +190,4 @@ const char* CompileOptions::exe_path(const char* const* paths, u32 num)
 	return NULL;
 }
 
-int CompileOptions::run_external_compiler(const char* const* argv, StringStream& output)
-{
-	return os::execute_process(argv, output);
-}
-
 } // namespace crown

+ 0 - 3
src/resource/compile_options.h

@@ -129,9 +129,6 @@ struct CompileOptions
 
 	/// Returns the first path with executable permissions or NULL if none found.
 	const char* exe_path(const char* const* paths, u32 num);
-
-	///
-	int run_external_compiler(const char* const* argv, StringStream& output);
 };
 
 } // namespace crown

+ 10 - 2
src/resource/lua_resource.cpp

@@ -7,6 +7,7 @@
 #include "core/containers/array.h"
 #include "core/filesystem/file.h"
 #include "core/memory/temp_allocator.h"
+#include "core/process.h"
 #include "core/strings/dynamic_string.h"
 #include "core/strings/string_stream.h"
 #include "resource/compile_options.h"
@@ -30,7 +31,6 @@ namespace lua_resource_internal
 		opts.get_absolute_path(opts.source_path(), luasrc);
 		opts.get_temporary_path("lua", luabin);
 
-		StringStream output(ta);
 		const char* argv[] =
 		{
 			EXE_PATH("luajit"),
@@ -39,7 +39,15 @@ namespace lua_resource_internal
 			luabin.c_str(),
 			NULL
 		};
-		int ec = opts.run_external_compiler(argv, output);
+		Process pr;
+		s32 sc = pr.spawn(argv);
+		DATA_COMPILER_ASSERT(sc == 0
+			, opts
+			, "Failed to spawn `%s`"
+			, argv[0]
+			);
+		StringStream output(ta);
+		s32 ec = pr.wait(&output);
 		DATA_COMPILER_ASSERT(ec == 0
 			, opts
 			, "Failed to compile lua:\n%s"

+ 2 - 0
src/resource/resource_manager.h

@@ -11,6 +11,8 @@
 #include "core/strings/string_id.h"
 #include "core/types.h"
 #include "resource/types.h"
+#include "core/json/types.h"
+#include "device/console_server.h"
 
 namespace crown
 {

+ 55 - 16
src/resource/shader_resource.cpp

@@ -10,6 +10,7 @@
 #include "core/json/json_object.h"
 #include "core/json/sjson.h"
 #include "core/memory/temp_allocator.h"
+#include "core/process.h"
 #include "core/strings/string_stream.h"
 #include "device/device.h"
 #include "resource/compile_options.h"
@@ -422,7 +423,14 @@ namespace shader_resource_internal
 		return SamplerWrap::COUNT;
 	}
 
-	static int run_external_compiler(CompileOptions& opts, const char* shaderc, const char* infile, const char* outfile, const char* varying, const char* type, const char* platform, StringStream& output)
+	static s32 run_external_compiler(Process& pr
+		, const char* shaderc
+		, const char* infile
+		, const char* outfile
+		, const char* varying
+		, const char* type
+		, const char* platform
+		)
 	{
 		const char* argv[] =
 		{
@@ -448,7 +456,7 @@ namespace shader_resource_internal
 			argv[12] = ((strcmp(type, "vertex") == 0) ? "vs_4_0" : "ps_4_0");
 		}
 
-		return opts.run_external_compiler(argv, output);
+		return pr.spawn(argv);
 	}
 
 	struct RenderState
@@ -1174,47 +1182,78 @@ namespace shader_resource_internal
 			_opts.write_temporary(_fs_source_path.c_str(), fs_code);
 			_opts.write_temporary(_varying_path.c_str(), shader._varying.c_str(), shader._varying.length());
 
-			TempAllocator4096 ta;
-			StringStream output(ta);
-
 			const char* shaderc = _opts.exe_path(shaderc_paths, countof(shaderc_paths));
 			DATA_COMPILER_ASSERT(shaderc != NULL
 				, _opts
 				, "shaderc not found"
 				);
 
-			int ec = run_external_compiler(_opts, shaderc, _vs_source_path.c_str()
+			// Invoke shaderc
+			Process pr_vert;
+			Process pr_frag;
+			s32 sc;
+
+			sc = run_external_compiler(pr_vert
+				, shaderc
+				, _vs_source_path.c_str()
 				, _vs_compiled_path.c_str()
 				, _varying_path.c_str()
 				, "vertex"
 				, _opts.platform()
-				, output
 				);
-			if (ec)
+			if (sc != 0)
 			{
 				delete_temp_files();
-				DATA_COMPILER_ASSERT(false
+				DATA_COMPILER_ASSERT(sc == 0
 					, _opts
-					, "Failed to compile vertex shader:\n%s"
-					, string_stream::c_str(output)
+					, "Failed to spawn `%s`"
+					, shaderc
 					);
 			}
 
-			array::clear(output);
-			ec = run_external_compiler(_opts, shaderc, _fs_source_path.c_str()
+			sc = run_external_compiler(pr_frag
+				, shaderc
+				, _fs_source_path.c_str()
 				, _fs_compiled_path.c_str()
 				, _varying_path.c_str()
 				, "fragment"
 				, _opts.platform()
-				, output
 				);
-			if (ec)
+			if (sc != 0)
+			{
+				delete_temp_files();
+				DATA_COMPILER_ASSERT(sc == 0
+					, _opts
+					, "Failed to spawn `%s`"
+					, shaderc
+					);
+			}
+
+			// Check shaderc exit code
+			s32 ec;
+			TempAllocator4096 ta;
+			StringStream output_vert(ta);
+			StringStream output_frag(ta);
+
+			ec = pr_vert.wait(&output_vert);
+			if (ec != 0)
+			{
+				delete_temp_files();
+				DATA_COMPILER_ASSERT(false
+					, _opts
+					, "Failed to compile vertex shader:\n%s"
+					, string_stream::c_str(output_vert)
+					);
+			}
+
+			ec = pr_frag.wait(&output_frag);
+			if (ec != 0)
 			{
 				delete_temp_files();
 				DATA_COMPILER_ASSERT(false
 					, _opts
 					, "Failed to compile fragment shader:\n%s"
-					, string_stream::c_str(output)
+					, string_stream::c_str(output_frag)
 					);
 			}
 

+ 9 - 2
src/resource/texture_resource.cpp

@@ -8,6 +8,7 @@
 #include "core/json/json_object.h"
 #include "core/json/sjson.h"
 #include "core/memory/temp_allocator.h"
+#include "core/process.h"
 #include "core/strings/dynamic_string.h"
 #include "core/strings/string_stream.h"
 #include "resource/compile_options.h"
@@ -67,9 +68,15 @@ namespace texture_resource_internal
 			(normal_map    ? "-n" : ""),
 			NULL
 		};
-
+		Process pr;
+		s32 sc = pr.spawn(argv);
+		DATA_COMPILER_ASSERT(sc == 0
+			, opts
+			, "Failed to spawn `%s`"
+			, argv[0]
+			);
 		StringStream output(ta);
-		int ec = opts.run_external_compiler(argv, output);
+		s32 ec = pr.wait(&output);
 		DATA_COMPILER_ASSERT(ec == 0
 			, opts
 			, "Failed to compile texture:\n%s"