33#include < iostream>
44#include < sstream>
55#include < string>
6+
67namespace python_engine {
78namespace {
89constexpr const int k200OK = 200 ;
@@ -61,33 +62,6 @@ static size_t WriteCallback(char* ptr, size_t size, size_t nmemb,
6162 return size * nmemb;
6263}
6364
64- std::string ConstructWindowsCommandLine (const std::vector<std::string>& args) {
65- std::string cmd_line;
66- for (const auto & arg : args) {
67- // Simple escaping for Windows command line
68- std::string escaped_arg = arg;
69- if (escaped_arg.find (' ' ) != std::string::npos) {
70- // Wrap in quotes and escape existing quotes
71- for (char & c : escaped_arg) {
72- if (c == ' "' )
73- c = ' \\ ' ;
74- }
75- escaped_arg = " \" " + escaped_arg + " \" " ;
76- }
77- cmd_line += escaped_arg + " " ;
78- }
79- return cmd_line;
80- }
81-
82- std::vector<char *> ConvertToArgv (const std::vector<std::string>& args) {
83- std::vector<char *> argv;
84- for (const auto & arg : args) {
85- argv.push_back (const_cast <char *>(arg.c_str ()));
86- }
87- argv.push_back (nullptr );
88- return argv;
89- }
90-
9165} // namespace
9266
9367PythonEngine::PythonEngine () : q_(4 /* n_parallel*/ , " python_engine" ) {}
@@ -106,80 +80,6 @@ config::PythonModelConfig* PythonEngine::GetModelConfig(
10680 return nullptr ;
10781}
10882
109- // TODO(sang) move to utils to re-use
110- pid_t PythonEngine::SpawnProcess (const std::string& model,
111- const std::vector<std::string>& command) {
112- try {
113- #if defined(_WIN32)
114- // Windows process creation
115- STARTUPINFOA si = {0 };
116- PROCESS_INFORMATION pi = {0 };
117- si.cb = sizeof (si);
118-
119- // Construct command line
120- std::string cmd_line = ConstructWindowsCommandLine (command);
121-
122- // Convert string to char* for Windows API
123- char command_buffer[4096 ];
124- strncpy_s (command_buffer, cmd_line.c_str (), sizeof (command_buffer));
125-
126- if (!CreateProcessA (NULL , // lpApplicationName
127- command_buffer, // lpCommandLine
128- NULL , // lpProcessAttributes
129- NULL , // lpThreadAttributes
130- FALSE , // bInheritHandles
131- 0 , // dwCreationFlags
132- NULL , // lpEnvironment
133- NULL , // lpCurrentDirectory
134- &si, // lpStartupInfo
135- &pi // lpProcessInformation
136- )) {
137- throw std::runtime_error (" Failed to create process on Windows" );
138- }
139-
140- // Store the process ID
141- pid_t pid = pi.dwProcessId ;
142- process_map_[model] = pid;
143-
144- // Close handles to avoid resource leaks
145- CloseHandle (pi.hProcess );
146- CloseHandle (pi.hThread );
147-
148- return pid;
149-
150- #elif defined(__APPLE__) || defined(__linux__)
151- // POSIX process creation
152- pid_t pid;
153-
154- // Convert command vector to char*[]
155- auto argv = ConvertToArgv (command);
156-
157- // Use posix_spawn for cross-platform compatibility
158- auto spawn_result = posix_spawn (&pid, // pid output
159- command[0 ].c_str (), // executable path
160- NULL , // file actions
161- NULL , // spawn attributes
162- argv.data (), // argument vector
163- NULL // environment (inherit)
164- );
165-
166- if (spawn_result != 0 ) {
167- throw std::runtime_error (" Failed to spawn process" );
168- }
169-
170- // Store the process ID
171- process_map_[model] = pid;
172- return pid;
173-
174- #else
175- #error Unsupported platform
176- #endif
177- } catch (const std::exception& e) {
178- LOG_ERROR << " Process spawning error: " << e.what ();
179- return -1 ;
180- }
181- }
182-
18383bool PythonEngine::TerminateModelProcess (const std::string& model) {
18484 auto it = process_map_.find (model);
18585 if (it == process_map_.end ()) {
@@ -405,7 +305,8 @@ void PythonEngine::LoadModel(
405305
406306 // Add the parsed arguments to the command
407307 command.insert (command.end (), args.begin (), args.end ());
408- pid = SpawnProcess (model, command);
308+ pid = cortex::process::SpawnProcess (command);
309+ process_map_[model] = pid;
409310 if (pid == -1 ) {
410311 std::unique_lock lock (models_mutex_);
411312 if (models_.find (model) != models_.end ()) {
@@ -467,7 +368,7 @@ void PythonEngine::UnloadModel(
467368
468369 auto model = (*json_body)[" model" ].asString ();
469370
470- {
371+ {
471372 if (TerminateModelProcess (model)) {
472373 std::unique_lock lock (models_mutex_);
473374 models_.erase (model);
0 commit comments