Process.h implementations for unix and windows
This commit is contained in:
parent
1b5efdb146
commit
91b5eef3dc
@ -1,7 +1,7 @@
|
||||
#include <unistd.h>
|
||||
#include "CompilationScenario.h"
|
||||
#include "../kerep/src/Filesystem/filesystem.h"
|
||||
#include "Process.h"
|
||||
#include "process/process.h"
|
||||
|
||||
kt_define(Language, NULL, NULL);
|
||||
kt_define(Tool, NULL, NULL);
|
||||
@ -314,15 +314,16 @@ Maybe Tool_exec(Tool* tool){
|
||||
Autoarr_add(args_ar, arg));
|
||||
|
||||
const char** args = (const char**)Autoarr_toArray(args_ar);
|
||||
i32 argc = Autoarr_length(args_ar);
|
||||
Autoarr_freeWithoutMembers(args_ar, true);
|
||||
|
||||
Process* tool_proc = NULL;
|
||||
try(process_start(tool->exe_file, args, true), _mtp,
|
||||
tool_proc = _mtp.value.VoidPtr);
|
||||
Process tool_proc;
|
||||
try(process_start(&tool_proc, tool->exe_file, args, argc, true), _m5512, Autoarr_freeWithoutMembers(sources, true))
|
||||
|
||||
// TODO wrap tool_proc->io
|
||||
process_waitForExit(tool_proc);
|
||||
process_waitForExit(&tool_proc);
|
||||
|
||||
Autoarr_freeWithoutMembers(sources, true);
|
||||
return MaybeNull;
|
||||
}
|
||||
|
||||
|
||||
@ -1,69 +0,0 @@
|
||||
#include "Process.h"
|
||||
#ifdef __MINGW32__
|
||||
#include <fcntl.h>
|
||||
#define pipe(fds) _pipe(fds, 1024, _O_BINARY)
|
||||
int fork(void); // idk where is it's header, different compilers use their own implementations
|
||||
#endif
|
||||
|
||||
void Process_close(Process* p){
|
||||
p->id=0;
|
||||
close(p->io.input);
|
||||
close(p->io.output);
|
||||
close(p->io.error);
|
||||
}
|
||||
|
||||
kt_define(Process, (freeMembers_t)Process_close, NULL)
|
||||
|
||||
#define throw_if_negative(expr) if(expr == -1) throw(#expr " error");
|
||||
#define safethrow_if_negative(expr) if(expr == -1) safethrow(#expr " error",;);
|
||||
|
||||
Maybe process_start(const char* file_path, const char** args, bool use_PATH){
|
||||
int input_pipe[2];
|
||||
int output_pipe[2];
|
||||
int error_pipe[2];
|
||||
safethrow_if_negative(pipe(input_pipe));
|
||||
safethrow_if_negative(pipe(output_pipe));
|
||||
safethrow_if_negative(pipe(error_pipe));
|
||||
|
||||
int pid = fork();
|
||||
if(pid == -1)
|
||||
safethrow("fork() error", ;);
|
||||
|
||||
// child process
|
||||
if(pid == 0){
|
||||
throw_if_negative(close(input_pipe[1])); // close writing
|
||||
throw_if_negative(close(output_pipe[0])); // close reading
|
||||
throw_if_negative(close(error_pipe[0])); // close reading
|
||||
|
||||
// redirect io streams to pipes
|
||||
throw_if_negative(dup2(input_pipe[0], STDIN_FILENO));
|
||||
throw_if_negative(dup2(output_pipe[1], STDOUT_FILENO));
|
||||
throw_if_negative(dup2(error_pipe[1], STDERR_FILENO));
|
||||
|
||||
// start new process
|
||||
int rzlt = use_PATH ? execvp(file_path, (char* const*)args) : execv (file_path, (char* const*)args);
|
||||
if(rzlt != 0)
|
||||
|
||||
// end child process
|
||||
exit(rzlt);
|
||||
return MaybeNull;
|
||||
}
|
||||
|
||||
// parent process
|
||||
safethrow_if_negative(close(input_pipe[0])); // close reading
|
||||
safethrow_if_negative(close(output_pipe[1])); // close writing
|
||||
safethrow_if_negative(close(error_pipe[1])); // close writing
|
||||
|
||||
Process* p = malloc(sizeof(Process));
|
||||
p->file_path = file_path;
|
||||
p->args = args;
|
||||
p->id=pid;
|
||||
p->io.input=input_pipe[1];
|
||||
p->io.output=output_pipe[0];
|
||||
p->io.error=error_pipe[0];
|
||||
return SUCCESS(UniHeapPtr(Process, p));
|
||||
}
|
||||
|
||||
Maybe process_waitForExit(Process* p){
|
||||
safethrow(ERR_NOTIMPLEMENTED, ;);
|
||||
}
|
||||
@ -1,22 +0,0 @@
|
||||
#include "../kerep/src/base/base.h"
|
||||
#include <unistd.h>
|
||||
|
||||
typedef struct {
|
||||
int input;
|
||||
int output;
|
||||
int error;
|
||||
} io;
|
||||
|
||||
typedef struct {
|
||||
int id;
|
||||
const char* file_path;
|
||||
const char** args;
|
||||
io io;
|
||||
} Process;
|
||||
kt_declare(Process);
|
||||
|
||||
///@return Maybe<Process*>
|
||||
Maybe process_start(const char* file_path, const char** args, bool use_PATH);
|
||||
|
||||
///@return Maybe<void>
|
||||
Maybe process_waitForExit(Process* p);
|
||||
@ -2,6 +2,7 @@
|
||||
#include "../kerep/src/Filesystem/filesystem.h"
|
||||
#include "../kerep/src/DtsodParser/DtsodV24.h"
|
||||
#include "CompilationScenario.h"
|
||||
#include "process/process.h"
|
||||
|
||||
#ifndef OS
|
||||
#error undefined OS
|
||||
@ -42,6 +43,7 @@ int main(const int argc, const char** argv){
|
||||
kt_register(CompilationScenario);
|
||||
kt_register(Language);
|
||||
kt_register(Tool);
|
||||
kt_register(Process);
|
||||
kt_endInit();
|
||||
|
||||
tasks = Autoarr_create(Pointer, 16, 32);
|
||||
|
||||
33
src/process/Process.h
Normal file
33
src/process/Process.h
Normal file
@ -0,0 +1,33 @@
|
||||
#include "../../kerep/src/base/base.h"
|
||||
|
||||
#ifdef _WIN32
|
||||
#define USE_WINDOWS_PROCESS_API
|
||||
typedef void* PipeHandle;
|
||||
#else
|
||||
typedef int PipeHandle;
|
||||
#endif
|
||||
|
||||
typedef struct Process {
|
||||
int id;
|
||||
const char* file_path;
|
||||
const char** args;
|
||||
PipeHandle input;
|
||||
PipeHandle output;
|
||||
PipeHandle error;
|
||||
#ifdef USE_WINDOWS_PROCESS_API
|
||||
void* _winProcHandle;
|
||||
#endif
|
||||
} Process;
|
||||
kt_declare(Process);
|
||||
|
||||
///@param search_in_PATH if true and file_path doesn't contain path separator characters, will search in PATH for the file_path
|
||||
///@return Maybe<void>
|
||||
Maybe process_start(Process* ptr, const char* file_path, const char** args, int argc, bool search_in_PATH);
|
||||
|
||||
///@return Maybe<void>
|
||||
Maybe process_waitForExit(Process* p);
|
||||
|
||||
///@return Maybe<void>
|
||||
Maybe Process_stop(Process* p);
|
||||
|
||||
i32 PipeHandle_read(PipeHandle pipe, char* buf, i32 bufsize);
|
||||
99
src/process/Process_posix.c
Normal file
99
src/process/Process_posix.c
Normal file
@ -0,0 +1,99 @@
|
||||
#include "process.h"
|
||||
|
||||
#ifndef USE_WINDOWS_PROCESS_API
|
||||
|
||||
#include <fcntl.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/wait.h>
|
||||
#include <errno.h>
|
||||
extern int kill (__pid_t __pid, int __sig) __THROW;
|
||||
extern void * memset(void * __dst, int __val, size_t __n);
|
||||
|
||||
#define throw_if_negative(expr) if(expr < 0) throw(cptr_concat(#expr " exited with error ", toString_i64(errno)));
|
||||
#define safethrow_if_negative(expr) if(expr < 0) safethrow(cptr_concat(#expr " exited with error ", toString_i64(errno)), ;);
|
||||
|
||||
Maybe process_start(Process* p, const char* file_path, const char** args, int argc, bool search_in_PATH){
|
||||
memset(p, 0, sizeof(Process));
|
||||
int input_pipe[2];
|
||||
int output_pipe[2];
|
||||
int error_pipe[2];
|
||||
safethrow_if_negative(pipe(input_pipe));
|
||||
safethrow_if_negative(pipe(output_pipe));
|
||||
safethrow_if_negative(pipe(error_pipe));
|
||||
|
||||
int pid = fork();
|
||||
if(pid == -1)
|
||||
safethrow("fork() error", ;);
|
||||
|
||||
// child process
|
||||
if(pid == 0){
|
||||
printf("child");
|
||||
throw_if_negative(close(input_pipe[1])); // close writing
|
||||
throw_if_negative(close(output_pipe[0])); // close reading
|
||||
throw_if_negative(close(error_pipe[0])); // close reading
|
||||
|
||||
// redirect io streams to pipes
|
||||
throw_if_negative(dup2(input_pipe[0], STDIN_FILENO));
|
||||
throw_if_negative(dup2(output_pipe[1], STDOUT_FILENO));
|
||||
throw_if_negative(dup2(error_pipe[1], STDERR_FILENO));
|
||||
|
||||
//
|
||||
const char** argv = malloc(sizeof(char*) * (argc+2));
|
||||
argv[0] = file_path;
|
||||
for(int i=0; i<argc; i++){
|
||||
argv[i+1] = args[i];
|
||||
}
|
||||
argv[argc+1] = NULL;
|
||||
// start new process
|
||||
int rzlt = search_in_PATH ? execvp(file_path, (char* const*)argv) : execv (file_path, (char* const*)argv);
|
||||
exit(rzlt);
|
||||
}
|
||||
|
||||
// parent process
|
||||
safethrow_if_negative(close(input_pipe[0])); // close reading
|
||||
safethrow_if_negative(close(output_pipe[1])); // close writing
|
||||
safethrow_if_negative(close(error_pipe[1])); // close writing
|
||||
|
||||
p->file_path = file_path;
|
||||
p->args = args;
|
||||
p->id=pid;
|
||||
p->input=input_pipe[1];
|
||||
p->output=output_pipe[0];
|
||||
p->error=error_pipe[0];
|
||||
return MaybeNull;
|
||||
}
|
||||
|
||||
Maybe Process_closeHandles(Process* p){
|
||||
safethrow_if_negative(close(p->input));
|
||||
safethrow_if_negative(close(p->output));
|
||||
safethrow_if_negative(close(p->error));
|
||||
p->id=0;
|
||||
return MaybeNull;
|
||||
}
|
||||
|
||||
Maybe process_waitForExit(Process* p){
|
||||
int wstatus=0;
|
||||
if(waitpid(p->id, &wstatus, 0) == -1)
|
||||
safethrow("waitpid() error", ;);
|
||||
if(!WIFEXITED(wstatus))
|
||||
safethrow(ERR_NOTIMPLEMENTED, ;)
|
||||
int exitCode = WEXITSTATUS(wstatus);
|
||||
if(exitCode != 0)
|
||||
safethrow(cptr_concat("process ", toString_i64(p->id), " exited with code ", toString_i64(exitCode)), ;)
|
||||
Process_closeHandles(p);
|
||||
return MaybeNull;
|
||||
}
|
||||
|
||||
Maybe Process_stop(Process* p){
|
||||
safethrow_if_negative(kill(p->id, SIGINT));
|
||||
try(Process_closeHandles(p), _m864, ;);
|
||||
return MaybeNull;
|
||||
}
|
||||
|
||||
kt_define(Process, (freeMembers_t)(void*)Process_stop, NULL)
|
||||
|
||||
i32 PipeHandle_read(PipeHandle pipe, char* buf, i32 bufsize){
|
||||
return read(pipe, buf, bufsize);
|
||||
}
|
||||
|
||||
#endif
|
||||
141
src/process/Process_windows.c
Normal file
141
src/process/Process_windows.c
Normal file
@ -0,0 +1,141 @@
|
||||
#include "process.h"
|
||||
|
||||
#ifdef USE_WINDOWS_PROCESS_API
|
||||
#include <windows.h>
|
||||
#include "../../kerep/src/String/StringBuilder.h"
|
||||
|
||||
#define safethrow_if_false(expr) if(!expr) safethrow(cptr_concat(#expr " exited with error ", toString_i64(GetLastError())), ;);
|
||||
|
||||
Maybe process_start(Process* p, const char* file_path, const char** args, int argc, bool search_in_PATH){
|
||||
memset(p, 0, sizeof(Process));
|
||||
if(search_in_PATH && !cptr_contains(file_path, "\\")){
|
||||
LPSTR lpFilePart;
|
||||
char search_rezult[MAX_PATH];
|
||||
safethrow_if_false(SearchPath( NULL, file_path, NULL, MAX_PATH, search_rezult, &lpFilePart))
|
||||
file_path = cptr_copy(search_rezult);
|
||||
}
|
||||
|
||||
SECURITY_ATTRIBUTES saAttr;
|
||||
saAttr.nLength = sizeof(SECURITY_ATTRIBUTES);
|
||||
// Set the bInheritHandle flag so pipe handles are inherited
|
||||
saAttr.bInheritHandle = TRUE;
|
||||
saAttr.lpSecurityDescriptor = NULL;
|
||||
|
||||
HANDLE in_pipe_r = NULL;
|
||||
HANDLE in_pipe_w = NULL;
|
||||
HANDLE out_pipe_r = NULL;
|
||||
HANDLE out_pipe_w = NULL;
|
||||
HANDLE err_pipe_r = NULL;
|
||||
HANDLE err_pipe_w = NULL;
|
||||
|
||||
// Create a pipe for the child process's STDIN.
|
||||
safethrow_if_false( CreatePipe(&in_pipe_r, &in_pipe_w, &saAttr, 0));
|
||||
// Ensure the write handle to the pipe for STDIN is not inherited.
|
||||
safethrow_if_false( SetHandleInformation(in_pipe_w, HANDLE_FLAG_INHERIT, 0) );
|
||||
|
||||
// Create a pipe for the child process's STDOUT.
|
||||
safethrow_if_false( CreatePipe(&out_pipe_r, &out_pipe_w, &saAttr, 0) )
|
||||
// Ensure the read handle to the pipe for STDOUT is not inherited.
|
||||
safethrow_if_false( SetHandleInformation(out_pipe_r, HANDLE_FLAG_INHERIT, 0) );
|
||||
|
||||
// Create a pipe for the child process's STDERR.
|
||||
safethrow_if_false( CreatePipe(&err_pipe_r, &err_pipe_w, &saAttr, 0) );
|
||||
// Ensure the read handle to the pipe for STDERR is not inherited.
|
||||
safethrow_if_false( SetHandleInformation(err_pipe_r, HANDLE_FLAG_INHERIT, 0) )
|
||||
|
||||
STARTUPINFO si;
|
||||
memset(&si, 0, sizeof(si));
|
||||
si.cb = sizeof(si);
|
||||
si.hStdInput = in_pipe_r;
|
||||
si.hStdOutput = out_pipe_w;
|
||||
si.hStdError = err_pipe_w;
|
||||
si.dwFlags |= STARTF_USESTDHANDLES;
|
||||
|
||||
PROCESS_INFORMATION pi;
|
||||
memset(&pi, 0, sizeof(pi));
|
||||
|
||||
StringBuilder* b = StringBuilder_create();
|
||||
|
||||
StringBuilder_append_char(b, '"');
|
||||
StringBuilder_append_cptr(b, file_path);
|
||||
StringBuilder_append_char(b, '"');
|
||||
StringBuilder_append_char(b, ' ');
|
||||
for(int i = 0; i < argc; i++) {
|
||||
StringBuilder_append_char(b, '"');
|
||||
StringBuilder_append_cptr(b, args[i]);
|
||||
StringBuilder_append_char(b, '"');
|
||||
StringBuilder_append_char(b, ' ');
|
||||
}
|
||||
string args_str = StringBuilder_build(b);
|
||||
|
||||
// Start the child process.
|
||||
if( !CreateProcess(
|
||||
file_path, // Program executable path (optional)
|
||||
args_str.ptr, // Command line args
|
||||
NULL, // Process handle not inheritable
|
||||
NULL, // Thread handle not inheritable
|
||||
TRUE, // Inherit IO handles
|
||||
0, // No creation flags
|
||||
NULL, // Use parent's environment block
|
||||
NULL, // Use parent's starting directory
|
||||
&si, // Pointer to STARTUPINFO structure
|
||||
&pi) // Pointer to PROCESS_INFORMATION structure
|
||||
) {
|
||||
safethrow(cptr_concat("process_start(", file_path, ", ", args_str, ", ", search_in_PATH ? "true" : "false",
|
||||
") error: CreateProcess() failed with error code ", toString_i64(GetLastError())), ;)
|
||||
}
|
||||
|
||||
|
||||
// Close thread handle and child process pipe ends
|
||||
safethrow_if_false(CloseHandle(in_pipe_r));
|
||||
safethrow_if_false(CloseHandle(out_pipe_w));
|
||||
safethrow_if_false(CloseHandle(err_pipe_w));
|
||||
safethrow_if_false(CloseHandle(pi.hThread));
|
||||
|
||||
p->file_path = file_path;
|
||||
p->args = args;
|
||||
p->id=pi.dwProcessId;
|
||||
p->_winProcHandle = pi.hProcess;
|
||||
|
||||
p->input = in_pipe_w;
|
||||
p->output= out_pipe_r;
|
||||
p->error = err_pipe_r;
|
||||
return MaybeNull;
|
||||
}
|
||||
|
||||
Maybe Process_closeHandles(Process* p){
|
||||
safethrow_if_false(CloseHandle(p->_winProcHandle));
|
||||
safethrow_if_false(CloseHandle(p->input));
|
||||
safethrow_if_false(CloseHandle(p->output));
|
||||
safethrow_if_false(CloseHandle(p->error));
|
||||
p->id=0;
|
||||
return MaybeNull;
|
||||
}
|
||||
|
||||
Maybe process_waitForExit(Process* p){
|
||||
if(WaitForSingleObject(p->_winProcHandle, INFINITE) != 0)
|
||||
safethrow("WaitForSingleObject() failed", ;);
|
||||
DWORD exitCode = 0;
|
||||
safethrow_if_false(GetExitCodeProcess(p->_winProcHandle, &exitCode));
|
||||
if(exitCode != 0)
|
||||
safethrow(cptr_concat("process ", toString_i64(p->id), " exited with code ", toString_i64(exitCode)), ;)
|
||||
Process_closeHandles(p);
|
||||
return MaybeNull;
|
||||
}
|
||||
|
||||
Maybe Process_stop(Process* p){
|
||||
safethrow_if_false(TerminateProcess(p->_winProcHandle, 1));
|
||||
try(Process_closeHandles(p), _m864, ;);
|
||||
return MaybeNull;
|
||||
}
|
||||
|
||||
kt_define(Process, (freeMembers_t)(void*)Process_stop, NULL)
|
||||
|
||||
i32 PipeHandle_read(PipeHandle pipe, char* buf, i32 bufsize){
|
||||
DWORD bytesRead = 0;
|
||||
if(!ReadFile(pipe, buf, bufsize, &bytesRead, NULL))
|
||||
return -1;
|
||||
return bytesRead;
|
||||
}
|
||||
|
||||
#endif
|
||||
Loading…
Reference in New Issue
Block a user