os: add Process (#6786)
parent
8e473181ed
commit
d633261a99
|
@ -0,0 +1,81 @@
|
||||||
|
module main
|
||||||
|
|
||||||
|
import os
|
||||||
|
import time
|
||||||
|
import os.cmdline
|
||||||
|
|
||||||
|
enum Target {
|
||||||
|
both
|
||||||
|
stderr
|
||||||
|
stdout
|
||||||
|
alternate
|
||||||
|
}
|
||||||
|
|
||||||
|
fn s2target(s string) Target {
|
||||||
|
return match s {
|
||||||
|
'both' { Target.both }
|
||||||
|
'stderr' { Target.stderr }
|
||||||
|
'alternate' { Target.alternate }
|
||||||
|
else { Target.stdout }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
struct Context {
|
||||||
|
mut:
|
||||||
|
timeout_ms int
|
||||||
|
period_ms int
|
||||||
|
exitcode int
|
||||||
|
target Target
|
||||||
|
omode Target
|
||||||
|
is_verbose bool
|
||||||
|
}
|
||||||
|
|
||||||
|
fn (mut ctx Context) println(s string) {
|
||||||
|
if ctx.target == .alternate {
|
||||||
|
ctx.omode = if ctx.omode == .stderr { Target.stdout } else { Target.stderr }
|
||||||
|
}
|
||||||
|
if ctx.target in [.both, .stdout] || ctx.omode == .stdout {
|
||||||
|
println('stdout, $s')
|
||||||
|
}
|
||||||
|
if ctx.target in [.both, .stderr] || ctx.omode == .stderr {
|
||||||
|
eprintln('stderr, $s')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn do_timeout(c &Context) {
|
||||||
|
mut ctx := c
|
||||||
|
time.sleep_ms(ctx.timeout_ms)
|
||||||
|
exit(ctx.exitcode)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
mut ctx := Context{}
|
||||||
|
args := os.args[1..]
|
||||||
|
if '-h' in args || '--help' in args {
|
||||||
|
println("Usage:
|
||||||
|
test_os_process [-v] [-h] [-target stderr/stdout/both/alternate] [-exitcode 0] [-timeout_ms 1000] [-period_ms 100]
|
||||||
|
Prints lines periodically (-period_ms), to stdout/stderr (-target).
|
||||||
|
After a while (-timeout_ms), exit with (-exitcode).
|
||||||
|
This program is useful for platform independent testing
|
||||||
|
of child process/standart input/output control.
|
||||||
|
It is used in V\'s `os` module tests.
|
||||||
|
")
|
||||||
|
}
|
||||||
|
ctx.is_verbose = '-v' in args
|
||||||
|
ctx.target = s2target(cmdline.option(args, '-target', 'both'))
|
||||||
|
ctx.exitcode = cmdline.option(args, '-exitcode', '0').int()
|
||||||
|
ctx.timeout_ms = cmdline.option(args, '-timeout_ms', '1000').int()
|
||||||
|
ctx.period_ms = cmdline.option(args, '-period_ms', '100').int()
|
||||||
|
if ctx.target == .alternate {
|
||||||
|
ctx.omode = .stdout
|
||||||
|
}
|
||||||
|
if ctx.is_verbose {
|
||||||
|
eprintln('> args: $args | context: $ctx')
|
||||||
|
}
|
||||||
|
go do_timeout(&ctx)
|
||||||
|
for i := 1; true; i++ {
|
||||||
|
ctx.println('$i')
|
||||||
|
time.sleep_ms(ctx.period_ms)
|
||||||
|
}
|
||||||
|
time.sleep(100000)
|
||||||
|
}
|
|
@ -4,388 +4,307 @@ module builtin
|
||||||
fn C.memcpy(byteptr, byteptr, int) voidptr
|
fn C.memcpy(byteptr, byteptr, int) voidptr
|
||||||
|
|
||||||
fn C.memcmp(byteptr, byteptr, int) int
|
fn C.memcmp(byteptr, byteptr, int) int
|
||||||
fn C.memmove(byteptr, byteptr, int) voidptr
|
|
||||||
fn C.calloc(int) byteptr
|
|
||||||
fn C.malloc(int) byteptr
|
|
||||||
fn C.realloc(a byteptr, b int) byteptr
|
|
||||||
fn C.free(ptr voidptr)
|
|
||||||
fn C.exit(code int)
|
|
||||||
|
|
||||||
|
fn C.memmove(byteptr, byteptr, int) voidptr
|
||||||
|
|
||||||
|
fn C.calloc(int) byteptr
|
||||||
|
|
||||||
|
fn C.malloc(int) byteptr
|
||||||
|
|
||||||
|
fn C.realloc(a byteptr, b int) byteptr
|
||||||
|
|
||||||
|
fn C.free(ptr voidptr)
|
||||||
|
|
||||||
|
fn C.exit(code int)
|
||||||
|
|
||||||
fn C.qsort(voidptr, int, int, qsort_callback_func)
|
fn C.qsort(voidptr, int, int, qsort_callback_func)
|
||||||
|
|
||||||
|
|
||||||
fn C.sprintf(a ...voidptr) int
|
fn C.sprintf(a ...voidptr) int
|
||||||
|
|
||||||
|
|
||||||
fn C.strlen(s charptr) int
|
fn C.strlen(s charptr) int
|
||||||
|
|
||||||
fn C.sscanf(byteptr, byteptr,...byteptr) int
|
fn C.sscanf(byteptr, byteptr, ...byteptr) int
|
||||||
|
|
||||||
fn C.isdigit(s byteptr) bool
|
fn C.isdigit(s byteptr) bool
|
||||||
|
|
||||||
// stdio.h
|
// stdio.h
|
||||||
fn C.popen(c charptr, t charptr) voidptr
|
fn C.popen(c charptr, t charptr) voidptr
|
||||||
|
|
||||||
// <execinfo.h>
|
// <execinfo.h>
|
||||||
fn C.backtrace(a &voidptr, size int) int
|
fn C.backtrace(a &voidptr, size int) int
|
||||||
fn C.backtrace_symbols(a &voidptr, size int) &charptr
|
|
||||||
|
fn C.backtrace_symbols(a &voidptr, size int) &charptr
|
||||||
|
|
||||||
fn C.backtrace_symbols_fd(a &voidptr, size int, fd int)
|
fn C.backtrace_symbols_fd(a &voidptr, size int, fd int)
|
||||||
|
|
||||||
// <libproc.h>
|
// <libproc.h>
|
||||||
pub fn proc_pidpath(int, voidptr, int) int
|
pub fn proc_pidpath(int, voidptr, int) int
|
||||||
|
|
||||||
|
|
||||||
fn C.realpath(charptr, charptr) &char
|
fn C.realpath(charptr, charptr) &char
|
||||||
|
|
||||||
|
|
||||||
fn C.chmod(byteptr, int) int
|
fn C.chmod(byteptr, int) int
|
||||||
|
|
||||||
|
|
||||||
fn C.printf(byteptr, ...byteptr) int
|
fn C.printf(byteptr, ...byteptr) int
|
||||||
|
|
||||||
fn C.puts(byteptr) int
|
fn C.puts(byteptr) int
|
||||||
|
|
||||||
fn C.fputs(byteptr) int
|
fn C.fputs(byteptr) int
|
||||||
|
|
||||||
|
|
||||||
fn C.fflush(byteptr) int
|
fn C.fflush(byteptr) int
|
||||||
|
|
||||||
// TODO define args in these functions
|
// TODO define args in these functions
|
||||||
fn C.fseek() int
|
fn C.fseek() int
|
||||||
|
|
||||||
|
|
||||||
fn C.fopen() voidptr
|
fn C.fopen() voidptr
|
||||||
|
|
||||||
|
|
||||||
fn C.fileno(voidptr) int
|
fn C.fileno(voidptr) int
|
||||||
|
|
||||||
|
|
||||||
fn C.fwrite() int
|
fn C.fwrite() int
|
||||||
|
|
||||||
|
|
||||||
fn C.fclose() int
|
fn C.fclose() int
|
||||||
|
|
||||||
|
|
||||||
fn C.pclose() int
|
fn C.pclose() int
|
||||||
|
|
||||||
|
// process execution, os.process:
|
||||||
|
fn C.getpid() int
|
||||||
|
|
||||||
fn C.system() int
|
fn C.system() int
|
||||||
fn C.posix_spawn(&int, charptr, voidptr, voidptr, &charptr, voidptr) int
|
|
||||||
fn C.waitpid(int, voidptr, int) int
|
fn C.posix_spawn(child_pid &int, path charptr, file_actions voidptr, attrp voidptr, argv &charptr, envp &charptr) int
|
||||||
|
|
||||||
|
fn C.posix_spawnp(child_pid &int, exefile charptr, file_actions voidptr, attrp voidptr, argv &charptr, envp &charptr) int
|
||||||
|
|
||||||
|
fn C.execve(cmd_path charptr, args voidptr, envs voidptr) int
|
||||||
|
|
||||||
|
fn C.fork() int
|
||||||
|
|
||||||
|
fn C.wait(status &int) int
|
||||||
|
|
||||||
|
fn C.waitpid(pid int, status &int, options int) int
|
||||||
|
|
||||||
|
fn C.kill(pid int, sig int) int
|
||||||
|
|
||||||
fn C.setenv(charptr) int
|
fn C.setenv(charptr) int
|
||||||
|
|
||||||
|
|
||||||
fn C.unsetenv(charptr) int
|
fn C.unsetenv(charptr) int
|
||||||
|
|
||||||
|
|
||||||
fn C.access() int
|
fn C.access() int
|
||||||
|
|
||||||
|
|
||||||
fn C.remove() int
|
fn C.remove() int
|
||||||
|
|
||||||
|
|
||||||
fn C.rmdir() int
|
fn C.rmdir() int
|
||||||
|
|
||||||
|
|
||||||
fn C.chdir() int
|
fn C.chdir() int
|
||||||
|
|
||||||
|
|
||||||
fn C.fread() int
|
fn C.fread() int
|
||||||
|
|
||||||
|
|
||||||
fn C.rewind() int
|
fn C.rewind() int
|
||||||
|
|
||||||
|
|
||||||
fn C.stat(charptr) int
|
fn C.stat(charptr) int
|
||||||
|
|
||||||
|
|
||||||
fn C.lstat() int
|
fn C.lstat() int
|
||||||
|
|
||||||
|
|
||||||
fn C.rename() int
|
fn C.rename() int
|
||||||
|
|
||||||
|
|
||||||
fn C.fgets() int
|
fn C.fgets() int
|
||||||
|
|
||||||
|
|
||||||
fn C.memset() int
|
fn C.memset() int
|
||||||
|
|
||||||
|
|
||||||
fn C.sigemptyset() int
|
fn C.sigemptyset() int
|
||||||
|
|
||||||
|
|
||||||
fn C.getcwd() int
|
fn C.getcwd() int
|
||||||
|
|
||||||
|
fn C.signal(signal int, handlercb voidptr) voidptr
|
||||||
fn C.signal() int
|
|
||||||
|
|
||||||
|
|
||||||
fn C.mktime() int
|
fn C.mktime() int
|
||||||
|
|
||||||
|
|
||||||
fn C.gettimeofday() int
|
fn C.gettimeofday() int
|
||||||
|
|
||||||
|
|
||||||
[trusted]
|
[trusted]
|
||||||
fn C.sleep(int) int
|
fn C.sleep(int) int
|
||||||
|
|
||||||
|
|
||||||
fn C.usleep() int
|
fn C.usleep() int
|
||||||
|
|
||||||
|
|
||||||
fn C.opendir() voidptr
|
fn C.opendir() voidptr
|
||||||
|
|
||||||
|
|
||||||
fn C.closedir() int
|
fn C.closedir() int
|
||||||
|
|
||||||
|
|
||||||
fn C.mkdir() int
|
fn C.mkdir() int
|
||||||
|
|
||||||
|
|
||||||
fn C.srand() int
|
fn C.srand() int
|
||||||
|
|
||||||
|
|
||||||
fn C.atof() int
|
fn C.atof() int
|
||||||
|
|
||||||
|
|
||||||
fn C.tolower() int
|
fn C.tolower() int
|
||||||
|
|
||||||
|
|
||||||
fn C.toupper() int
|
fn C.toupper() int
|
||||||
|
|
||||||
|
|
||||||
[trusted]
|
[trusted]
|
||||||
fn C.getchar() int
|
fn C.getchar() int
|
||||||
|
|
||||||
|
|
||||||
[trusted]
|
[trusted]
|
||||||
fn C.strerror(int) charptr
|
fn C.strerror(int) charptr
|
||||||
|
|
||||||
|
|
||||||
fn C.snprintf() int
|
fn C.snprintf() int
|
||||||
|
|
||||||
|
|
||||||
fn C.fprintf(byteptr, ...byteptr)
|
fn C.fprintf(byteptr, ...byteptr)
|
||||||
|
|
||||||
|
|
||||||
fn C.WIFEXITED() bool
|
fn C.WIFEXITED() bool
|
||||||
|
|
||||||
|
|
||||||
fn C.WEXITSTATUS() int
|
fn C.WEXITSTATUS() int
|
||||||
|
|
||||||
|
|
||||||
fn C.WIFSIGNALED() bool
|
fn C.WIFSIGNALED() bool
|
||||||
|
|
||||||
|
|
||||||
fn C.WTERMSIG() int
|
fn C.WTERMSIG() int
|
||||||
|
|
||||||
|
|
||||||
fn C.isatty() int
|
fn C.isatty() int
|
||||||
|
|
||||||
|
|
||||||
fn C.syscall() int
|
fn C.syscall() int
|
||||||
|
|
||||||
|
|
||||||
fn C.sysctl() int
|
fn C.sysctl() int
|
||||||
|
|
||||||
|
|
||||||
fn C._fileno(int) int
|
fn C._fileno(int) int
|
||||||
|
|
||||||
|
|
||||||
fn C._get_osfhandle(fd int) C.intptr_t
|
fn C._get_osfhandle(fd int) C.intptr_t
|
||||||
|
|
||||||
|
|
||||||
fn C.GetModuleFileName() int
|
fn C.GetModuleFileName() int
|
||||||
|
|
||||||
fn C.GetModuleFileNameW(hModule voidptr, lpFilename &u16, nSize u32) u32
|
fn C.GetModuleFileNameW(hModule voidptr, lpFilename &u16, nSize u32) u32
|
||||||
|
|
||||||
|
|
||||||
fn C.CreateFile() voidptr
|
fn C.CreateFile() voidptr
|
||||||
fn C.CreateFileW(lpFilename &u16, dwDesiredAccess u32, dwShareMode u32, lpSecurityAttributes &u16, dwCreationDisposition u32, dwFlagsAndAttributes u32, hTemplateFile voidptr) u32
|
|
||||||
|
|
||||||
|
fn C.CreateFileW(lpFilename &u16, dwDesiredAccess u32, dwShareMode u32, lpSecurityAttributes &u16, dwCreationDisposition u32, dwFlagsAndAttributes u32, hTemplateFile voidptr) u32
|
||||||
|
|
||||||
fn C.GetFinalPathNameByHandleW(hFile voidptr, lpFilePath &u16, nSize u32, dwFlags u32) int
|
fn C.GetFinalPathNameByHandleW(hFile voidptr, lpFilePath &u16, nSize u32, dwFlags u32) int
|
||||||
|
|
||||||
|
|
||||||
fn C.CreatePipe(hReadPipe &voidptr, hWritePipe &voidptr, lpPipeAttributes voidptr, nSize u32) bool
|
fn C.CreatePipe(hReadPipe &voidptr, hWritePipe &voidptr, lpPipeAttributes voidptr, nSize u32) bool
|
||||||
|
|
||||||
|
|
||||||
fn C.SetHandleInformation(hObject voidptr, dwMask u32, dw_flags u32) bool
|
fn C.SetHandleInformation(hObject voidptr, dwMask u32, dw_flags u32) bool
|
||||||
|
|
||||||
|
|
||||||
fn C.ExpandEnvironmentStringsW(lpSrc &u16, lpDst &u16, nSize u32) u32
|
fn C.ExpandEnvironmentStringsW(lpSrc &u16, lpDst &u16, nSize u32) u32
|
||||||
|
|
||||||
|
|
||||||
fn C.SendMessageTimeout() u32
|
fn C.SendMessageTimeout() u32
|
||||||
fn C.SendMessageTimeoutW(hWnd voidptr, Msg u32, wParam &u16, lParam &u32, fuFlags u32, uTimeout u32, lpdwResult &u64) u32
|
|
||||||
|
|
||||||
|
fn C.SendMessageTimeoutW(hWnd voidptr, Msg u32, wParam &u16, lParam &u32, fuFlags u32, uTimeout u32, lpdwResult &u64) u32
|
||||||
|
|
||||||
fn C.CreateProcessW(lpApplicationName &u16, lpCommandLine &u16, lpProcessAttributes voidptr, lpThreadAttributes voidptr, bInheritHandles bool, dwCreationFlags u32, lpEnvironment voidptr, lpCurrentDirectory &u16, lpStartupInfo voidptr, lpProcessInformation voidptr) bool
|
fn C.CreateProcessW(lpApplicationName &u16, lpCommandLine &u16, lpProcessAttributes voidptr, lpThreadAttributes voidptr, bInheritHandles bool, dwCreationFlags u32, lpEnvironment voidptr, lpCurrentDirectory &u16, lpStartupInfo voidptr, lpProcessInformation voidptr) bool
|
||||||
|
|
||||||
|
|
||||||
fn C.ReadFile(hFile voidptr, lpBuffer voidptr, nNumberOfBytesToRead u32, lpNumberOfBytesRead C.LPDWORD, lpOverlapped voidptr) bool
|
fn C.ReadFile(hFile voidptr, lpBuffer voidptr, nNumberOfBytesToRead u32, lpNumberOfBytesRead C.LPDWORD, lpOverlapped voidptr) bool
|
||||||
|
|
||||||
|
|
||||||
fn C.GetFileAttributesW(lpFileName byteptr) u32
|
fn C.GetFileAttributesW(lpFileName byteptr) u32
|
||||||
|
|
||||||
|
|
||||||
fn C.RegQueryValueEx() voidptr
|
fn C.RegQueryValueEx() voidptr
|
||||||
|
|
||||||
fn C.RegQueryValueExW(hKey voidptr, lpValueName &u16, lp_reserved &u32, lpType &u32, lpData byteptr, lpcbData &u32) int
|
fn C.RegQueryValueExW(hKey voidptr, lpValueName &u16, lp_reserved &u32, lpType &u32, lpData byteptr, lpcbData &u32) int
|
||||||
|
|
||||||
|
|
||||||
fn C.RegOpenKeyEx() voidptr
|
fn C.RegOpenKeyEx() voidptr
|
||||||
|
|
||||||
fn C.RegOpenKeyExW(hKey voidptr, lpSubKey &u16, ulOptions u32, samDesired u32, phkResult voidptr) int
|
fn C.RegOpenKeyExW(hKey voidptr, lpSubKey &u16, ulOptions u32, samDesired u32, phkResult voidptr) int
|
||||||
|
|
||||||
|
|
||||||
fn C.RegSetValueEx() voidptr
|
fn C.RegSetValueEx() voidptr
|
||||||
fn C.RegSetValueExW(hKey voidptr, lpValueName &u16, Reserved u32, dwType u32, lpData byteptr, lpcbData u32) int
|
|
||||||
|
|
||||||
|
fn C.RegSetValueExW(hKey voidptr, lpValueName &u16, Reserved u32, dwType u32, lpData byteptr, lpcbData u32) int
|
||||||
|
|
||||||
fn C.RegCloseKey()
|
fn C.RegCloseKey()
|
||||||
|
|
||||||
|
|
||||||
fn C.RemoveDirectory() int
|
fn C.RemoveDirectory() int
|
||||||
|
|
||||||
|
// fn C.GetStdHandle() voidptr
|
||||||
//fn C.GetStdHandle() voidptr
|
|
||||||
fn C.GetStdHandle(u32) voidptr
|
fn C.GetStdHandle(u32) voidptr
|
||||||
|
|
||||||
|
// fn C.SetConsoleMode()
|
||||||
//fn C.SetConsoleMode()
|
|
||||||
fn C.SetConsoleMode(voidptr, u32)
|
fn C.SetConsoleMode(voidptr, u32)
|
||||||
|
|
||||||
|
// fn C.GetConsoleMode() int
|
||||||
//fn C.GetConsoleMode() int
|
|
||||||
fn C.GetConsoleMode(voidptr, &u32) int
|
fn C.GetConsoleMode(voidptr, &u32) int
|
||||||
|
|
||||||
|
fn C.GetCurrentProcessId() int
|
||||||
|
|
||||||
fn C.wprintf()
|
fn C.wprintf()
|
||||||
|
|
||||||
|
// fn C.setbuf()
|
||||||
//fn C.setbuf()
|
|
||||||
fn C.setbuf(voidptr, charptr)
|
fn C.setbuf(voidptr, charptr)
|
||||||
|
|
||||||
|
|
||||||
fn C.SymCleanup()
|
fn C.SymCleanup()
|
||||||
|
|
||||||
|
|
||||||
fn C.MultiByteToWideChar() int
|
fn C.MultiByteToWideChar() int
|
||||||
|
|
||||||
|
|
||||||
fn C.wcslen() int
|
fn C.wcslen() int
|
||||||
|
|
||||||
|
|
||||||
fn C.WideCharToMultiByte() int
|
fn C.WideCharToMultiByte() int
|
||||||
|
|
||||||
|
|
||||||
fn C._wstat()
|
fn C._wstat()
|
||||||
|
|
||||||
|
|
||||||
fn C._wrename()
|
fn C._wrename()
|
||||||
|
|
||||||
|
|
||||||
fn C._wfopen() voidptr
|
fn C._wfopen() voidptr
|
||||||
|
|
||||||
|
|
||||||
fn C._wpopen() voidptr
|
fn C._wpopen() voidptr
|
||||||
|
|
||||||
|
|
||||||
fn C._pclose() int
|
fn C._pclose() int
|
||||||
|
|
||||||
|
|
||||||
fn C._wsystem() int
|
fn C._wsystem() int
|
||||||
|
|
||||||
|
|
||||||
fn C._wgetenv() voidptr
|
fn C._wgetenv() voidptr
|
||||||
|
|
||||||
|
|
||||||
fn C._putenv() int
|
fn C._putenv() int
|
||||||
|
|
||||||
|
|
||||||
fn C._waccess() int
|
fn C._waccess() int
|
||||||
|
|
||||||
|
|
||||||
fn C._wremove() int
|
fn C._wremove() int
|
||||||
|
|
||||||
|
|
||||||
fn C.ReadConsole() voidptr
|
fn C.ReadConsole() voidptr
|
||||||
|
|
||||||
|
|
||||||
fn C.WriteConsole() voidptr
|
fn C.WriteConsole() voidptr
|
||||||
|
|
||||||
|
|
||||||
fn C.WriteFile() voidptr
|
fn C.WriteFile() voidptr
|
||||||
|
|
||||||
|
|
||||||
fn C._wchdir()
|
fn C._wchdir()
|
||||||
|
|
||||||
|
|
||||||
fn C._wgetcwd() int
|
fn C._wgetcwd() int
|
||||||
|
|
||||||
|
|
||||||
fn C._fullpath() int
|
fn C._fullpath() int
|
||||||
|
|
||||||
|
|
||||||
fn C.GetCommandLine() voidptr
|
fn C.GetCommandLine() voidptr
|
||||||
|
|
||||||
|
|
||||||
fn C.LocalFree()
|
fn C.LocalFree()
|
||||||
|
|
||||||
|
|
||||||
fn C.FindFirstFileW() voidptr
|
fn C.FindFirstFileW() voidptr
|
||||||
|
|
||||||
|
|
||||||
fn C.FindFirstFile() voidptr
|
fn C.FindFirstFile() voidptr
|
||||||
|
|
||||||
|
|
||||||
fn C.FindNextFile() int
|
fn C.FindNextFile() int
|
||||||
|
|
||||||
|
|
||||||
fn C.FindClose()
|
fn C.FindClose()
|
||||||
|
|
||||||
|
|
||||||
fn C.MAKELANGID() int
|
fn C.MAKELANGID() int
|
||||||
|
|
||||||
|
|
||||||
fn C.FormatMessage() voidptr
|
fn C.FormatMessage() voidptr
|
||||||
|
|
||||||
|
|
||||||
fn C.CloseHandle(voidptr) int
|
fn C.CloseHandle(voidptr) int
|
||||||
|
|
||||||
|
|
||||||
fn C.GetExitCodeProcess()
|
fn C.GetExitCodeProcess()
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
fn C.GetTickCount() i64
|
fn C.GetTickCount() i64
|
||||||
|
|
||||||
|
|
||||||
fn C.Sleep()
|
fn C.Sleep()
|
||||||
|
|
||||||
|
|
||||||
fn C.WSAStartup(u16, &voidptr) int
|
fn C.WSAStartup(u16, &voidptr) int
|
||||||
|
|
||||||
|
|
||||||
fn C.WSAGetLastError() int
|
fn C.WSAGetLastError() int
|
||||||
|
|
||||||
|
|
||||||
fn C.closesocket(int) int
|
fn C.closesocket(int) int
|
||||||
|
|
||||||
|
|
||||||
fn C.vschannel_init(&C.TlsContext)
|
fn C.vschannel_init(&C.TlsContext)
|
||||||
|
|
||||||
|
|
||||||
fn C.request(&C.TlsContext, int, &u16, byteptr, &byteptr)
|
fn C.request(&C.TlsContext, int, &u16, byteptr, &byteptr)
|
||||||
|
|
||||||
|
|
||||||
fn C.vschannel_cleanup(&C.TlsContext)
|
fn C.vschannel_cleanup(&C.TlsContext)
|
||||||
|
|
||||||
|
|
||||||
fn C.URLDownloadToFile(int, &u16, &u16, int, int)
|
fn C.URLDownloadToFile(int, &u16, &u16, int, int)
|
||||||
|
|
||||||
|
|
||||||
fn C.GetLastError() u32
|
fn C.GetLastError() u32
|
||||||
|
|
||||||
|
|
||||||
fn C.CreateDirectory(byteptr, int) bool
|
fn C.CreateDirectory(byteptr, int) bool
|
||||||
|
|
||||||
// win crypto
|
// win crypto
|
||||||
|
@ -393,60 +312,102 @@ fn C.BCryptGenRandom(int, voidptr, int, int) int
|
||||||
|
|
||||||
// win synchronization
|
// win synchronization
|
||||||
fn C.CreateMutex(int, bool, byteptr) voidptr
|
fn C.CreateMutex(int, bool, byteptr) voidptr
|
||||||
|
|
||||||
fn C.WaitForSingleObject(voidptr, int) int
|
fn C.WaitForSingleObject(voidptr, int) int
|
||||||
|
|
||||||
fn C.ReleaseMutex(voidptr) bool
|
fn C.ReleaseMutex(voidptr) bool
|
||||||
|
|
||||||
fn C.CreateEvent(int, bool, bool, byteptr) voidptr
|
fn C.CreateEvent(int, bool, bool, byteptr) voidptr
|
||||||
|
|
||||||
fn C.SetEvent(voidptr) int
|
fn C.SetEvent(voidptr) int
|
||||||
|
|
||||||
fn C.CreateSemaphore(voidptr, int, int, voidptr) voidptr
|
fn C.CreateSemaphore(voidptr, int, int, voidptr) voidptr
|
||||||
|
|
||||||
fn C.ReleaseSemaphore(voidptr, int, voidptr) voidptr
|
fn C.ReleaseSemaphore(voidptr, int, voidptr) voidptr
|
||||||
|
|
||||||
fn C.InitializeSRWLock(voidptr)
|
fn C.InitializeSRWLock(voidptr)
|
||||||
|
|
||||||
fn C.AcquireSRWLockShared(voidptr)
|
fn C.AcquireSRWLockShared(voidptr)
|
||||||
|
|
||||||
fn C.AcquireSRWLockExclusive(voidptr)
|
fn C.AcquireSRWLockExclusive(voidptr)
|
||||||
|
|
||||||
fn C.ReleaseSRWLockShared(voidptr)
|
fn C.ReleaseSRWLockShared(voidptr)
|
||||||
|
|
||||||
fn C.ReleaseSRWLockExclusive(voidptr)
|
fn C.ReleaseSRWLockExclusive(voidptr)
|
||||||
|
|
||||||
// pthread.h
|
// pthread.h
|
||||||
fn C.pthread_mutex_init(voidptr, voidptr) int
|
fn C.pthread_mutex_init(voidptr, voidptr) int
|
||||||
|
|
||||||
fn C.pthread_mutex_lock(voidptr) int
|
fn C.pthread_mutex_lock(voidptr) int
|
||||||
|
|
||||||
fn C.pthread_mutex_unlock(voidptr) int
|
fn C.pthread_mutex_unlock(voidptr) int
|
||||||
|
|
||||||
fn C.pthread_mutex_destroy(voidptr) int
|
fn C.pthread_mutex_destroy(voidptr) int
|
||||||
|
|
||||||
fn C.pthread_rwlockattr_init(voidptr) int
|
fn C.pthread_rwlockattr_init(voidptr) int
|
||||||
|
|
||||||
fn C.pthread_rwlockattr_setkind_np(voidptr, int) int
|
fn C.pthread_rwlockattr_setkind_np(voidptr, int) int
|
||||||
|
|
||||||
fn C.pthread_rwlockattr_setpshared(voidptr, int) int
|
fn C.pthread_rwlockattr_setpshared(voidptr, int) int
|
||||||
|
|
||||||
fn C.pthread_rwlock_init(voidptr, voidptr) int
|
fn C.pthread_rwlock_init(voidptr, voidptr) int
|
||||||
|
|
||||||
fn C.pthread_rwlock_rdlock(voidptr) int
|
fn C.pthread_rwlock_rdlock(voidptr) int
|
||||||
|
|
||||||
fn C.pthread_rwlock_wrlock(voidptr) int
|
fn C.pthread_rwlock_wrlock(voidptr) int
|
||||||
|
|
||||||
fn C.pthread_rwlock_unlock(voidptr) int
|
fn C.pthread_rwlock_unlock(voidptr) int
|
||||||
|
|
||||||
fn C.pthread_condattr_init(voidptr) int
|
fn C.pthread_condattr_init(voidptr) int
|
||||||
|
|
||||||
fn C.pthread_condattr_setpshared(voidptr, int) int
|
fn C.pthread_condattr_setpshared(voidptr, int) int
|
||||||
|
|
||||||
fn C.pthread_condattr_destroy(voidptr) int
|
fn C.pthread_condattr_destroy(voidptr) int
|
||||||
|
|
||||||
fn C.pthread_cond_init(voidptr, voidptr) int
|
fn C.pthread_cond_init(voidptr, voidptr) int
|
||||||
|
|
||||||
fn C.pthread_cond_signal(voidptr) int
|
fn C.pthread_cond_signal(voidptr) int
|
||||||
|
|
||||||
fn C.pthread_cond_wait(voidptr, voidptr) int
|
fn C.pthread_cond_wait(voidptr, voidptr) int
|
||||||
|
|
||||||
fn C.pthread_cond_timedwait(voidptr, voidptr, voidptr) int
|
fn C.pthread_cond_timedwait(voidptr, voidptr, voidptr) int
|
||||||
|
|
||||||
fn C.pthread_cond_destroy(voidptr) int
|
fn C.pthread_cond_destroy(voidptr) int
|
||||||
|
|
||||||
fn C.sem_init(voidptr, int, u32) int
|
fn C.sem_init(voidptr, int, u32) int
|
||||||
|
|
||||||
fn C.sem_post(voidptr) int
|
fn C.sem_post(voidptr) int
|
||||||
|
|
||||||
fn C.sem_wait(voidptr) int
|
fn C.sem_wait(voidptr) int
|
||||||
|
|
||||||
fn C.sem_trywait(voidptr) int
|
fn C.sem_trywait(voidptr) int
|
||||||
|
|
||||||
fn C.sem_timedwait(voidptr, voidptr) int
|
fn C.sem_timedwait(voidptr, voidptr) int
|
||||||
|
|
||||||
fn C.sem_destroy(voidptr) int
|
fn C.sem_destroy(voidptr) int
|
||||||
|
|
||||||
// MacOS semaphore functions
|
// MacOS semaphore functions
|
||||||
fn C.dispatch_semaphore_create(i64) voidptr
|
fn C.dispatch_semaphore_create(i64) voidptr
|
||||||
|
|
||||||
fn C.dispatch_semaphore_signal(voidptr) i64
|
fn C.dispatch_semaphore_signal(voidptr) i64
|
||||||
|
|
||||||
fn C.dispatch_semaphore_wait(voidptr, u64) i64
|
fn C.dispatch_semaphore_wait(voidptr, u64) i64
|
||||||
|
|
||||||
fn C.dispatch_time(u64, i64) u64
|
fn C.dispatch_time(u64, i64) u64
|
||||||
|
|
||||||
fn C.dispatch_release(voidptr)
|
fn C.dispatch_release(voidptr)
|
||||||
|
|
||||||
|
// file descriptor based reading/writing
|
||||||
fn C.read(fd int, buf voidptr, count size_t) int
|
fn C.read(fd int, buf voidptr, count size_t) int
|
||||||
|
|
||||||
fn C.write(fd int, buf voidptr, count size_t) int
|
fn C.write(fd int, buf voidptr, count size_t) int
|
||||||
|
|
||||||
fn C.close(fd int) int
|
fn C.close(fd int) int
|
||||||
|
|
||||||
|
// pipes
|
||||||
|
fn C.pipe(pipefds &int) int
|
||||||
|
|
||||||
|
fn C.dup2(oldfd int, newfd int) int
|
||||||
|
|
||||||
// used by gl, stbi, freetype
|
// used by gl, stbi, freetype
|
||||||
fn C.glTexImage2D()
|
fn C.glTexImage2D()
|
||||||
|
|
|
@ -0,0 +1,44 @@
|
||||||
|
module os
|
||||||
|
|
||||||
|
// file descriptor based operations:
|
||||||
|
pub fn fd_close(fd int) int {
|
||||||
|
return C.close(fd)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn fd_write(fd int, s string) {
|
||||||
|
mut sp := s.str
|
||||||
|
mut remaining := s.len
|
||||||
|
for remaining > 0 {
|
||||||
|
written := C.write(fd, sp, remaining)
|
||||||
|
if written < 0 {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
remaining = remaining - written
|
||||||
|
sp = unsafe {sp + written}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn fd_slurp(fd int) []string {
|
||||||
|
mut res := []string{}
|
||||||
|
for {
|
||||||
|
s, b := fd_read(fd, 4096)
|
||||||
|
if b <= 0 {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
res << s
|
||||||
|
}
|
||||||
|
return res
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn fd_read(fd int, maxbytes int) (string, int) {
|
||||||
|
mut buf := malloc(maxbytes)
|
||||||
|
nbytes := C.read(fd, buf, maxbytes)
|
||||||
|
if nbytes < 0 {
|
||||||
|
free(buf)
|
||||||
|
return '', nbytes
|
||||||
|
}
|
||||||
|
unsafe {
|
||||||
|
buf[nbytes] = 0
|
||||||
|
}
|
||||||
|
return tos(buf, nbytes), nbytes
|
||||||
|
}
|
|
@ -8,8 +8,6 @@ struct C.dirent {
|
||||||
|
|
||||||
fn C.readdir(voidptr) &C.dirent
|
fn C.readdir(voidptr) &C.dirent
|
||||||
|
|
||||||
fn C.getpid() int
|
|
||||||
|
|
||||||
fn C.readlink() int
|
fn C.readlink() int
|
||||||
|
|
||||||
fn C.getline(voidptr, voidptr, voidptr) int
|
fn C.getline(voidptr, voidptr, voidptr) int
|
||||||
|
@ -24,10 +22,6 @@ fn C.fdopen(int, string) voidptr
|
||||||
|
|
||||||
fn C.CopyFile(&u32, &u32, int) int
|
fn C.CopyFile(&u32, &u32, int) int
|
||||||
|
|
||||||
fn C.fork() int
|
|
||||||
|
|
||||||
fn C.wait() int
|
|
||||||
|
|
||||||
// fn C.proc_pidpath(int, byteptr, int) int
|
// fn C.proc_pidpath(int, byteptr, int) int
|
||||||
struct C.stat {
|
struct C.stat {
|
||||||
st_size int
|
st_size int
|
||||||
|
|
|
@ -0,0 +1,240 @@
|
||||||
|
module os
|
||||||
|
|
||||||
|
// ProcessState.not_started - the process has not yet started
|
||||||
|
// ProcessState.running - the process is currently running
|
||||||
|
// ProcessState.stopped - the process was running, but was stopped temporarily
|
||||||
|
// ProcessState.exited - the process has finished/exited
|
||||||
|
// ProcessState.aborted - the process was terminated by a signal
|
||||||
|
pub enum ProcessState {
|
||||||
|
not_started
|
||||||
|
running
|
||||||
|
stopped
|
||||||
|
exited
|
||||||
|
aborted
|
||||||
|
}
|
||||||
|
|
||||||
|
[ref_only]
|
||||||
|
pub struct Process {
|
||||||
|
pub:
|
||||||
|
filename string // the process's command file path
|
||||||
|
pub mut:
|
||||||
|
pid int // the PID of the process
|
||||||
|
code int = -1
|
||||||
|
// the exit code of the process, != -1 *only* when status is .exited *and* the process was not aborted
|
||||||
|
status ProcessState = .not_started
|
||||||
|
// the current status of the process
|
||||||
|
err string // if the process fails, contains the reason why
|
||||||
|
args []string // the arguments that the command takes
|
||||||
|
env_is_custom bool // true, when the environment was customized with .set_environment
|
||||||
|
env []string // the environment with which the process was started
|
||||||
|
use_stdio_ctl bool // when true, then you can use p.stdin_write(), p.stdout_slurp() and p.stderr_slurp()
|
||||||
|
stdio_fd [3]int
|
||||||
|
}
|
||||||
|
|
||||||
|
// new_process - create a new process descriptor
|
||||||
|
// NB: new does NOT start the new process.
|
||||||
|
// That is done because you may want to customize it first,
|
||||||
|
// by calling different set_ methods on it.
|
||||||
|
// In order to start it, call p.run() or p.wait()
|
||||||
|
pub fn new_process(filename string) &Process {
|
||||||
|
return &Process{
|
||||||
|
filename: filename
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// set_args - set the arguments for the new process
|
||||||
|
pub fn (mut p Process) set_args(pargs []string) &Process {
|
||||||
|
if p.status != .not_started {
|
||||||
|
return p
|
||||||
|
}
|
||||||
|
p.args = pargs
|
||||||
|
return p
|
||||||
|
}
|
||||||
|
|
||||||
|
// set_environment - set a custom environment variable mapping for the new process
|
||||||
|
pub fn (mut p Process) set_environment(envs map[string]string) &Process {
|
||||||
|
if p.status != .not_started {
|
||||||
|
return p
|
||||||
|
}
|
||||||
|
p.env_is_custom = true
|
||||||
|
p.env = []string{}
|
||||||
|
for k, v in envs {
|
||||||
|
p.env << '$k=$v'
|
||||||
|
}
|
||||||
|
return p
|
||||||
|
}
|
||||||
|
|
||||||
|
// run - starts the new process
|
||||||
|
pub fn (mut p Process) run() &Process {
|
||||||
|
if p.status != .not_started {
|
||||||
|
return p
|
||||||
|
}
|
||||||
|
p._spawn()
|
||||||
|
return p
|
||||||
|
}
|
||||||
|
|
||||||
|
// signal_kill - kills the process, after that it is no longer running
|
||||||
|
pub fn (mut p Process) signal_kill() &Process {
|
||||||
|
if p.status !in [.running, .stopped] {
|
||||||
|
return p
|
||||||
|
}
|
||||||
|
p._signal_kill()
|
||||||
|
p.status = .aborted
|
||||||
|
return p
|
||||||
|
}
|
||||||
|
|
||||||
|
// signal_stop - stops the process, you can resume it with p.signal_continue()
|
||||||
|
pub fn (mut p Process) signal_stop() &Process {
|
||||||
|
if p.status != .running {
|
||||||
|
return p
|
||||||
|
}
|
||||||
|
p._signal_stop()
|
||||||
|
p.status = .stopped
|
||||||
|
return p
|
||||||
|
}
|
||||||
|
|
||||||
|
// signal_continue - tell a stopped process to continue/resume its work
|
||||||
|
pub fn (mut p Process) signal_continue() &Process {
|
||||||
|
if p.status != .stopped {
|
||||||
|
return p
|
||||||
|
}
|
||||||
|
p._signal_continue()
|
||||||
|
p.status = .running
|
||||||
|
return p
|
||||||
|
}
|
||||||
|
|
||||||
|
// wait - wait for a process to finish.
|
||||||
|
// NB: You have to call p.wait(), otherwise a finished process
|
||||||
|
// would get to a zombie state, and its resources will not get
|
||||||
|
// released fully, until its parent process exits.
|
||||||
|
// NB: This call will block the calling process until the child
|
||||||
|
// process is finished.
|
||||||
|
pub fn (mut p Process) wait() &Process {
|
||||||
|
if p.status == .not_started {
|
||||||
|
p._spawn()
|
||||||
|
}
|
||||||
|
if p.status !in [.running, .stopped] {
|
||||||
|
return p
|
||||||
|
}
|
||||||
|
p._wait()
|
||||||
|
return p
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// _spawn - should not be called directly, but only by p.run()/p.wait() .
|
||||||
|
// It encapsulates the fork/execve mechanism that allows the
|
||||||
|
// asynchronous starting of the new child process.
|
||||||
|
fn (mut p Process) _spawn() int {
|
||||||
|
if !p.env_is_custom {
|
||||||
|
p.env = []string{}
|
||||||
|
current_environment := environ()
|
||||||
|
for k, v in current_environment {
|
||||||
|
p.env << '$k=$v'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
mut pid := 0
|
||||||
|
$if windows {
|
||||||
|
pid = p.win_spawn_process()
|
||||||
|
} $else {
|
||||||
|
pid = p.unix_spawn_process()
|
||||||
|
}
|
||||||
|
p.pid = pid
|
||||||
|
p.status = .running
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
// is_alive - query whether the process p.pid is still alive
|
||||||
|
pub fn (mut p Process) is_alive() bool {
|
||||||
|
if p.status in [.running, .stopped] {
|
||||||
|
return p._is_alive()
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
pub fn (mut p Process) set_redirect_stdio() &Process {
|
||||||
|
p.use_stdio_ctl = true
|
||||||
|
return p
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn (mut p Process) stdin_write(s string) {
|
||||||
|
p._check_redirection_call('stdin_write')
|
||||||
|
fd_write(p.stdio_fd[0], s)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn (mut p Process) stdout_slurp() string {
|
||||||
|
p._check_redirection_call('stdout_slurp')
|
||||||
|
return fd_slurp(p.stdio_fd[1]).join('')
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn (mut p Process) stderr_slurp() string {
|
||||||
|
p._check_redirection_call('stderr_slurp')
|
||||||
|
return fd_slurp(p.stdio_fd[2]).join('')
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn (mut p Process) stdout_read() string {
|
||||||
|
p._check_redirection_call('stdout_read')
|
||||||
|
s, _ := fd_read(p.stdio_fd[1], 4096)
|
||||||
|
return s
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn (mut p Process) stderr_read() string {
|
||||||
|
p._check_redirection_call('stderr_read')
|
||||||
|
s, _ := fd_read(p.stdio_fd[2], 4096)
|
||||||
|
return s
|
||||||
|
}
|
||||||
|
|
||||||
|
// _check_redirection_call - should be called just by stdxxx methods
|
||||||
|
fn (mut p Process) _check_redirection_call(fn_name string) {
|
||||||
|
if !p.use_stdio_ctl {
|
||||||
|
panic('Call p.set_redirect_stdio() before calling p.$fn_name')
|
||||||
|
}
|
||||||
|
if p.status == .not_started {
|
||||||
|
panic('Call p.${fn_name}() after you have called p.run()')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// _signal_stop - should not be called directly, except by p.signal_stop
|
||||||
|
fn (mut p Process) _signal_stop() {
|
||||||
|
$if windows {
|
||||||
|
p.win_stop_process()
|
||||||
|
} $else {
|
||||||
|
p.unix_stop_process()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// _signal_continue - should not be called directly, just by p.signal_continue
|
||||||
|
fn (mut p Process) _signal_continue() {
|
||||||
|
$if windows {
|
||||||
|
p.win_resume_process()
|
||||||
|
} $else {
|
||||||
|
p.unix_resume_process()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// _signal_kill - should not be called directly, except by p.signal_kill
|
||||||
|
fn (mut p Process) _signal_kill() {
|
||||||
|
$if windows {
|
||||||
|
p.win_kill_process()
|
||||||
|
} $else {
|
||||||
|
p.unix_kill_process()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// _wait - should not be called directly, except by p.wait()
|
||||||
|
fn (mut p Process) _wait() {
|
||||||
|
$if windows {
|
||||||
|
p.win_wait()
|
||||||
|
} $else {
|
||||||
|
p.unix_wait()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// _is_alive - should not be called directly, except by p.is_alive()
|
||||||
|
fn (mut p Process) _is_alive() bool {
|
||||||
|
$if windows {
|
||||||
|
return p.win_is_alive()
|
||||||
|
} $else {
|
||||||
|
return p.unix_is_alive()
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,134 @@
|
||||||
|
module os
|
||||||
|
|
||||||
|
fn (mut p Process) unix_spawn_process() int {
|
||||||
|
mut pipeset := [6]int{}
|
||||||
|
if p.use_stdio_ctl {
|
||||||
|
C.pipe(&pipeset[0]) // pipe read end 0 <- 1 pipe write end
|
||||||
|
C.pipe(&pipeset[2]) // pipe read end 2 <- 3 pipe write end
|
||||||
|
C.pipe(&pipeset[4]) // pipe read end 4 <- 5 pipe write end
|
||||||
|
}
|
||||||
|
pid := fork()
|
||||||
|
if pid != 0 {
|
||||||
|
// This is the parent process after the fork.
|
||||||
|
// NB: pid contains the process ID of the child process
|
||||||
|
if p.use_stdio_ctl {
|
||||||
|
p.stdio_fd[0] = pipeset[1] // store the write end of child's in
|
||||||
|
p.stdio_fd[1] = pipeset[2] // store the read end of child's out
|
||||||
|
p.stdio_fd[2] = pipeset[4] // store the read end of child's err
|
||||||
|
// close the rest of the pipe fds, the parent does not need them
|
||||||
|
fd_close(pipeset[0])
|
||||||
|
fd_close(pipeset[3])
|
||||||
|
fd_close(pipeset[5])
|
||||||
|
}
|
||||||
|
return pid
|
||||||
|
}
|
||||||
|
//
|
||||||
|
// Here, we are in the child process.
|
||||||
|
// It still shares file descriptors with the parent process,
|
||||||
|
// but it is otherwise independant and can do stuff *without*
|
||||||
|
// affecting the parent process.
|
||||||
|
if p.use_stdio_ctl {
|
||||||
|
// Redirect the child standart in/out/err to the pipes that
|
||||||
|
// were created in the parent.
|
||||||
|
// Close the parent's pipe fds, the child do not need them:
|
||||||
|
fd_close(pipeset[1])
|
||||||
|
fd_close(pipeset[2])
|
||||||
|
fd_close(pipeset[4])
|
||||||
|
// redirect the pipe fds to the child's in/out/err fds:
|
||||||
|
C.dup2(pipeset[0], 0)
|
||||||
|
C.dup2(pipeset[3], 1)
|
||||||
|
C.dup2(pipeset[5], 2)
|
||||||
|
// close the pipe fdsx after the redirection
|
||||||
|
fd_close(pipeset[0])
|
||||||
|
fd_close(pipeset[3])
|
||||||
|
fd_close(pipeset[5])
|
||||||
|
}
|
||||||
|
mut cargv := []charptr{}
|
||||||
|
mut cenvs := []charptr{}
|
||||||
|
cargv << p.filename.str
|
||||||
|
for i in 0 .. p.args.len {
|
||||||
|
cargv << p.args[i].str
|
||||||
|
}
|
||||||
|
for i in 0 .. p.env.len {
|
||||||
|
cenvs << p.env[i].str
|
||||||
|
}
|
||||||
|
cargv << charptr(0)
|
||||||
|
cenvs << charptr(0)
|
||||||
|
C.execve(p.filename.str, cargv.data, cenvs.data)
|
||||||
|
// NB: normally execve does not return at all.
|
||||||
|
// If it returns, then something went wrong...
|
||||||
|
eprintln(posix_get_error_msg(C.errno))
|
||||||
|
exit(1)
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
fn (mut p Process) unix_stop_process() {
|
||||||
|
C.kill(p.pid, C.SIGSTOP)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn (mut p Process) unix_resume_process() {
|
||||||
|
C.kill(p.pid, C.SIGCONT)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn (mut p Process) unix_kill_process() {
|
||||||
|
C.kill(p.pid, C.SIGKILL)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn (mut p Process) unix_wait() {
|
||||||
|
cstatus := 0
|
||||||
|
ret := C.waitpid(p.pid, &cstatus, 0)
|
||||||
|
if ret == -1 {
|
||||||
|
p.err = posix_get_error_msg(C.errno)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
pret, is_signaled := posix_wait4_to_exit_status(cstatus)
|
||||||
|
if is_signaled {
|
||||||
|
p.status = .aborted
|
||||||
|
p.err = 'Terminated by signal ${ret:2d} (${sigint_to_signal_name(pret)})'
|
||||||
|
} else {
|
||||||
|
p.status = .exited
|
||||||
|
}
|
||||||
|
p.code = pret
|
||||||
|
}
|
||||||
|
|
||||||
|
fn (mut p Process) unix_is_alive() bool {
|
||||||
|
cstatus := 0
|
||||||
|
ret := C.waitpid(p.pid, &cstatus, C.WNOHANG)
|
||||||
|
if ret == -1 {
|
||||||
|
p.err = posix_get_error_msg(C.errno)
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
if ret == 0 {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
pret, is_signaled := posix_wait4_to_exit_status(cstatus)
|
||||||
|
if is_signaled {
|
||||||
|
p.status = .aborted
|
||||||
|
p.err = 'Terminated by signal ${ret:2d} (${sigint_to_signal_name(pret)})'
|
||||||
|
} else {
|
||||||
|
p.status = .exited
|
||||||
|
}
|
||||||
|
p.code = pret
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
// these are here to make v_win.c/v.c generation work in all cases:
|
||||||
|
fn (mut p Process) win_spawn_process() int {
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
fn (mut p Process) win_stop_process() {
|
||||||
|
}
|
||||||
|
|
||||||
|
fn (mut p Process) win_resume_process() {
|
||||||
|
}
|
||||||
|
|
||||||
|
fn (mut p Process) win_kill_process() {
|
||||||
|
}
|
||||||
|
|
||||||
|
fn (mut p Process) win_wait() {
|
||||||
|
}
|
||||||
|
|
||||||
|
fn (mut p Process) win_is_alive() bool {
|
||||||
|
return false
|
||||||
|
}
|
|
@ -0,0 +1,63 @@
|
||||||
|
import os
|
||||||
|
import time
|
||||||
|
|
||||||
|
fn test_getpid() {
|
||||||
|
pid := os.getpid()
|
||||||
|
eprintln('current pid: $pid')
|
||||||
|
assert pid != 0
|
||||||
|
}
|
||||||
|
|
||||||
|
fn test_run() {
|
||||||
|
if os.user_os() == 'windows' {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
//
|
||||||
|
mut p := os.new_process('/bin/sleep')
|
||||||
|
p.set_args(['0.2'])
|
||||||
|
p.run()
|
||||||
|
assert p.status == .running
|
||||||
|
assert p.pid > 0
|
||||||
|
assert p.pid != os.getpid()
|
||||||
|
mut i := 0
|
||||||
|
for {
|
||||||
|
if !p.is_alive() {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
os.system('ps -opid= -oppid= -ouser= -onice= -of= -ovsz= -orss= -otime= -oargs= -p $p.pid')
|
||||||
|
time.sleep_ms(50)
|
||||||
|
i++
|
||||||
|
}
|
||||||
|
p.wait()
|
||||||
|
assert p.code == 0
|
||||||
|
assert p.status == .exited
|
||||||
|
//
|
||||||
|
eprintln('polling iterations: $i')
|
||||||
|
assert i > 1
|
||||||
|
assert i < 20
|
||||||
|
}
|
||||||
|
|
||||||
|
fn test_wait() {
|
||||||
|
if os.user_os() == 'windows' {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
mut p := os.new_process('/bin/date')
|
||||||
|
p.wait()
|
||||||
|
assert p.pid != os.getpid()
|
||||||
|
assert p.code == 0
|
||||||
|
assert p.status == .exited
|
||||||
|
}
|
||||||
|
|
||||||
|
fn test_slurping_output() {
|
||||||
|
if os.user_os() == 'windows' {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
mut p := os.new_process('/bin/date')
|
||||||
|
p.set_redirect_stdio()
|
||||||
|
p.wait()
|
||||||
|
assert p.code == 0
|
||||||
|
assert p.status == .exited
|
||||||
|
output := p.stdout_slurp().trim_space()
|
||||||
|
errors := p.stderr_slurp().trim_space()
|
||||||
|
eprintln('p output: "$output"')
|
||||||
|
eprintln('p errors: "$errors"')
|
||||||
|
}
|
|
@ -0,0 +1,51 @@
|
||||||
|
module os
|
||||||
|
|
||||||
|
fn (mut p Process) win_spawn_process() int {
|
||||||
|
eprintln('TODO implement waiting for a process on windows')
|
||||||
|
return 12345
|
||||||
|
}
|
||||||
|
|
||||||
|
fn (mut p Process) win_stop_process() {
|
||||||
|
eprintln('TODO implement stopping a process on windows')
|
||||||
|
}
|
||||||
|
|
||||||
|
fn (mut p Process) win_resume_process() {
|
||||||
|
eprintln('TODO implement resuming a process on windows')
|
||||||
|
}
|
||||||
|
|
||||||
|
fn (mut p Process) win_kill_process() {
|
||||||
|
eprintln('TODO implement killing a process on windows')
|
||||||
|
}
|
||||||
|
|
||||||
|
fn (mut p Process) win_wait() {
|
||||||
|
eprintln('TODO implement waiting for a process on windows')
|
||||||
|
p.status = .exited
|
||||||
|
p.code = 0
|
||||||
|
}
|
||||||
|
|
||||||
|
fn (mut p Process) win_is_alive() bool {
|
||||||
|
eprintln('TODO implement checking whether the process is still alive on windows')
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// these are here to make v_win.c/v.c generation work in all cases:
|
||||||
|
fn (mut p Process) unix_spawn_process() int {
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
fn (mut p Process) unix_stop_process() {
|
||||||
|
}
|
||||||
|
|
||||||
|
fn (mut p Process) unix_resume_process() {
|
||||||
|
}
|
||||||
|
|
||||||
|
fn (mut p Process) unix_kill_process() {
|
||||||
|
}
|
||||||
|
|
||||||
|
fn (mut p Process) unix_wait() {
|
||||||
|
}
|
||||||
|
|
||||||
|
fn (mut p Process) unix_is_alive() bool {
|
||||||
|
return false
|
||||||
|
}
|
|
@ -38,8 +38,6 @@ fn C.tcsetattr() int
|
||||||
|
|
||||||
fn C.raise()
|
fn C.raise()
|
||||||
|
|
||||||
fn C.kill(int, int) int
|
|
||||||
|
|
||||||
fn C.getppid() int
|
fn C.getppid() int
|
||||||
|
|
||||||
// Enable the raw mode of the terminal
|
// Enable the raw mode of the terminal
|
||||||
|
|
Loading…
Reference in New Issue