cgen: no type canon for integral types; osproc use posix_spawn instead of fork&exec

This commit is contained in:
Araq
2011-11-18 00:29:56 +01:00
parent b05418a431
commit 61792dc7d6
9 changed files with 149 additions and 54 deletions

View File

@@ -574,7 +574,8 @@ const
tyPointer,
tyOpenArray, tyString, tyCString, tyInt..tyInt64, tyFloat..tyFloat128,
tyUInt..tyUInt64}
IntegralTypes* = {tyBool, tyChar, tyEnum, tyInt..tyInt64,
tyFloat..tyFloat128, tyUInt..tyUInt64}
ConstantDataTypes*: TTypeKinds = {tyArrayConstr, tyArray, tySet,
tyTuple, tySequence}
ExportableSymKinds* = {skVar, skConst, skProc, skMethod, skType, skIterator,

View File

@@ -265,7 +265,7 @@ proc getSimpleTypeDesc(m: BModule, typ: PType): PRope =
of tyBool: result = typeNameOrLiteral(typ, "NIM_BOOL")
of tyChar: result = typeNameOrLiteral(typ, "NIM_CHAR")
of tyNil: result = typeNameOrLiteral(typ, "0")
of tyInt..tyFloat128:
of tyInt..tyFloat128, tyUInt..tyUInt64:
result = typeNameOrLiteral(typ, NumericalTypeToStr[typ.Kind])
of tyRange: result = getSimpleTypeDesc(m, typ.sons[0])
else: result = nil

View File

@@ -73,11 +73,15 @@ proc GetUniqueType*(key: PType): PType =
if key == nil: return
var k = key.kind
case k
of tyNone, tyBool, tyChar, tyEmpty,
tyNil, tyExpr, tyStmt, tyTypeDesc, tyPointer, tyString, tyCString,
of tyBool, tyChar,
tyInt, tyInt8, tyInt16, tyInt32, tyInt64,
tyFloat, tyFloat32, tyFloat64, tyFloat128,
tyUInt, tyUInt8, tyUInt16, tyUInt32, tyUInt64, tyBigNum:
tyUInt, tyUInt8, tyUInt16, tyUInt32, tyUInt64:
# no canonicalization for integral types, so that e.g. ``pid_t`` is
# produced instead of ``NI``.
result = key
of tyEmpty, tyNil, tyExpr, tyStmt, tyTypeDesc, tyPointer, tyString,
tyCString, tyNone, tyBigNum:
result = gCanonicalTypes[k]
if result == nil:
gCanonicalTypes[k] = key

View File

@@ -427,6 +427,11 @@ __declspec(naked) int __fastcall NimXadd(volatile int* pNum, int val) {
#ifdef __GNUC__
# define likely(x) __builtin_expect(x, 1)
# define unlikely(x) __builtin_expect(x, 0)
/* We need the following for the posix wrapper. In particular it will give us
POSIX_SPAWN_USEVFORK: */
# ifndef _GNU_SOURCE
# define _GNU_SOURCE
# endif
#else
# define likely(x) (x)
# define unlikely(x) (x)

View File

@@ -24,13 +24,13 @@
## the \`identifier\` notation is used.
##
## This library relies on the header files of your C compiler. The
## resulting C code will just include <XYZ.h> and *not* define the
## resulting C code will just ``#include <XYZ.h>`` and *not* define the
## symbols declared here.
from times import TTime
const
hasSpawnH = defined(linux)
hasSpawnH = true # should exist for every Posix system really nowadays
hasAioH = defined(linux)
when false:
@@ -401,9 +401,9 @@ when hasAioH:
when hasSpawnH:
type
Tposix_spawnattr* {.importc: "posix_spawnattr_t",
header: "<spawn.h>".} = cint
header: "<spawn.h>", final, pure.} = object
Tposix_spawn_file_actions* {.importc: "posix_spawn_file_actions_t",
header: "<spawn.h>".} = cint
header: "<spawn.h>", final, pure.} = object
type
TSocklen* {.importc: "socklen_t", header: "<sys/socket.h>".} = cint
@@ -1720,7 +1720,8 @@ when hasSpawnh:
POSIX_SPAWN_SETSCHEDULER* {.importc, header: "<spawn.h>".}: cint
POSIX_SPAWN_SETSIGDEF* {.importc, header: "<spawn.h>".}: cint
POSIX_SPAWN_SETSIGMASK* {.importc, header: "<spawn.h>".}: cint
POSIX_SPAWN_USEVFORK* {.importc, header: "<spawn.h>".}: cint
when hasAioH:
proc aio_cancel*(a1: cint, a2: ptr Taiocb): cint {.importc, header: "<aio.h>".}
proc aio_error*(a1: ptr Taiocb): cint {.importc, header: "<aio.h>".}
@@ -2369,7 +2370,7 @@ when hasSpawnH:
importc, header: "<spawn.h>".}
proc posix_spawnattr_setsigdefault*(a1: var tposix_spawnattr,
a2: var tsigset): cint {.importc, header: "<spawn.h>".}
proc posix_spawnattr_setflags*(a1: var tposix_spawnattr, a2: cshort): cint {.
proc posix_spawnattr_setflags*(a1: var tposix_spawnattr, a2: cint): cint {.
importc, header: "<spawn.h>".}
proc posix_spawnattr_setpgroup*(a1: var tposix_spawnattr, a2: tpid): cint {.
importc, header: "<spawn.h>".}

View File

@@ -1,6 +1,3 @@
discard """
cmd: "nimrod cc --hints:on --threads:on $# $#"
"""
#
#
# Nimrod's Runtime Library

View File

@@ -25,9 +25,10 @@ type
when defined(windows):
FProcessHandle: Thandle
inputHandle, outputHandle, errorHandle: TFileHandle
id: THandle
else:
inputHandle, outputHandle, errorHandle: TFileHandle
id: cint
id: TPid
exitCode: cint
PProcess* = ref TProcess ## represents an operating system process
@@ -158,6 +159,10 @@ proc execProcesses*(cmds: openArray[string],
## executes the commands `cmds` in parallel. Creates `n` processes
## that execute in parallel. The highest return value of all processes
## is returned.
when defined(posix):
# poParentStreams causes problems on Posix, so we disable it simply:
var options = options - {poParentStreams}
assert n > 0
if n > 1:
var q: seq[PProcess]
@@ -475,6 +480,17 @@ elif not defined(useNimRtl):
copyMem(result[i], addr(x[0]), x.len+1)
inc(i)
proc EnvToCStringArray(): cstringArray =
var counter = 0
for key, val in envPairs(): inc counter
result = cast[cstringArray](alloc0((counter + 1) * sizeof(cstring)))
var i = 0
for key, val in envPairs():
var x = key & "=" & val
result[i] = cast[cstring](alloc(x.len+1))
copyMem(result[i], addr(x[0]), x.len+1)
inc(i)
proc startProcess(command: string,
workingDir: string = "",
args: openarray[string] = [],
@@ -484,58 +500,122 @@ elif not defined(useNimRtl):
p_stdin, p_stdout, p_stderr: array [0..1, cint]
new(result)
result.exitCode = -3 # for ``waitForExit``
if pipe(p_stdin) != 0'i32 or pipe(p_stdout) != 0'i32 or
pipe(p_stderr) != 0'i32:
OSError()
var Pid = fork()
if Pid < 0: OSError()
if poParentStreams notin options:
if pipe(p_stdin) != 0'i32 or pipe(p_stdout) != 0'i32 or
pipe(p_stderr) != 0'i32:
OSError()
var pid: TPid
when defined(posix_spawn) and not defined(useFork):
var attr: Tposix_spawnattr
var fops: Tposix_spawn_file_actions
if pid == 0:
## child process:
discard close(p_stdin[writeIdx])
if dup2(p_stdin[readIdx], readIdx) < 0: OSError()
discard close(p_stdout[readIdx])
if dup2(p_stdout[writeIdx], writeIdx) < 0: OSError()
discard close(p_stderr[readIdx])
if poStdErrToStdOut in options:
if dup2(p_stdout[writeIdx], 2) < 0: OSError()
else:
if dup2(p_stderr[writeIdx], 2) < 0: OSError()
template chck(e: expr) =
if e != 0'i32: OSError()
# Create a new process group
if setpgid(0, 0) == -1: quit("setpgid call failed: " & $strerror(errno))
chck posix_spawn_file_actions_init(fops)
chck posix_spawnattr_init(attr)
var mask: Tsigset
chck sigemptyset(mask)
chck posix_spawnattr_setsigmask(attr, mask)
chck posix_spawnattr_setpgroup(attr, 0'i32)
chck posix_spawnattr_setflags(attr, POSIX_SPAWN_USEVFORK or
POSIX_SPAWN_SETSIGMASK or
POSIX_SPAWN_SETPGROUP)
if poParentStreams notin options:
chck posix_spawn_file_actions_addclose(fops, p_stdin[writeIdx])
chck posix_spawn_file_actions_adddup2(fops, p_stdin[readIdx], readIdx)
chck posix_spawn_file_actions_addclose(fops, p_stdout[readIdx])
chck posix_spawn_file_actions_adddup2(fops, p_stdout[writeIdx], writeIdx)
chck posix_spawn_file_actions_addclose(fops, p_stderr[readIdx])
if poStdErrToStdOut in options:
chck posix_spawn_file_actions_adddup2(fops, p_stdout[writeIdx], 2)
else:
chck posix_spawn_file_actions_adddup2(fops, p_stderr[writeIdx], 2)
var e = if env == nil: EnvToCStringArray() else: ToCStringArray(env)
if workingDir.len > 0: os.setCurrentDir(workingDir)
if poUseShell notin options:
var a = toCStringArray([extractFilename(command)], args)
if env == nil:
discard execv(command, a)
else:
discard execve(command, a, ToCStringArray(env))
chck posix_spawn(pid, command, fops, attr, a, e)
else:
var x = addCmdArgs(command, args)
var a = toCStringArray(["sh", "-c"], [x])
if env == nil:
discard execv("/bin/sh", a)
chck posix_spawn(pid, "/bin/sh", fops, attr, a, e)
if {poEchoCmd, poUseShell} * options == {poEchoCmd}:
# shell echos already, so ...
echo(command, " ", join(args, " "))
chck posix_spawn_file_actions_destroy(fops)
chck posix_spawnattr_destroy(attr)
else:
Pid = fork()
if Pid < 0: OSError()
if pid == 0:
## child process:
if poParentStreams notin options:
discard close(p_stdin[writeIdx])
if dup2(p_stdin[readIdx], readIdx) < 0: OSError()
discard close(p_stdout[readIdx])
if dup2(p_stdout[writeIdx], writeIdx) < 0: OSError()
discard close(p_stderr[readIdx])
if poStdErrToStdOut in options:
if dup2(p_stdout[writeIdx], 2) < 0: OSError()
else:
if dup2(p_stderr[writeIdx], 2) < 0: OSError()
# Create a new process group
if setpgid(0, 0) == -1: quit("setpgid call failed: " & $strerror(errno))
if workingDir.len > 0: os.setCurrentDir(workingDir)
if poUseShell notin options:
var a = toCStringArray([extractFilename(command)], args)
if env == nil:
discard execv(command, a)
else:
discard execve(command, a, ToCStringArray(env))
else:
discard execve("/bin/sh", a, ToCStringArray(env))
# too risky to raise an exception here:
quit("execve call failed: " & $strerror(errno))
var x = addCmdArgs(command, args)
var a = toCStringArray(["sh", "-c"], [x])
if env == nil:
discard execv("/bin/sh", a)
else:
discard execve("/bin/sh", a, ToCStringArray(env))
# too risky to raise an exception here:
quit("execve call failed: " & $strerror(errno))
# Parent process. Copy process information.
if poEchoCmd in options:
# shell with no redirects echos already, so ...
echo(command, " ", join(args, " "))
result.id = pid
result.inputHandle = p_stdin[writeIdx]
result.outputHandle = p_stdout[readIdx]
if poStdErrToStdOut in options:
result.errorHandle = result.outputHandle
discard close(p_stderr[readIdx])
if poParentStreams in options:
# does not make much sense, but better than nothing:
result.inputHandle = 0
result.outputHandle = 1
if poStdErrToStdOut in options:
result.errorHandle = result.outputHandle
else:
result.errorHandle = 2
else:
result.errorHandle = p_stderr[readIdx]
discard close(p_stderr[writeIdx])
discard close(p_stdin[readIdx])
discard close(p_stdout[writeIdx])
result.inputHandle = p_stdin[writeIdx]
result.outputHandle = p_stdout[readIdx]
if poStdErrToStdOut in options:
result.errorHandle = result.outputHandle
discard close(p_stderr[readIdx])
else:
result.errorHandle = p_stderr[readIdx]
discard close(p_stderr[writeIdx])
discard close(p_stdin[readIdx])
discard close(p_stdout[writeIdx])
proc close(p: PProcess) =
discard close(p.inputHandle)

View File

@@ -27,7 +27,8 @@ type
when defined(posix):
type
TTime* = distinct int ## distinct type that represents a time
TTimeImpl {.importc: "time_t", header: "<sys/time.h>".} = int
TTime* = distinct TTimeImpl ## distinct type that represents a time
Ttimeval {.importc: "struct timeval", header: "<sys/select.h>",
final, pure.} = object ## struct timeval
@@ -46,9 +47,12 @@ elif defined(windows):
when defined(vcc):
# newest version of Visual C++ defines time_t to be of 64 bits
type TTime* = distinct int64
type TTimeImpl {.importc: "time_t", header: "<sys/time.h>".} = int64
else:
type TTime* = distinct int32
type TTimeImpl {.importc: "time_t", header: "<sys/time.h>".} = int32
type
TTime* = distinct TTimeImpl
elif defined(ECMAScript):
type

View File

@@ -117,6 +117,9 @@ Library Additions
- Added ``ftpclient`` module.
- Added ``memfiles`` module.
- Added ``osproc.startCmd``, ``osproc.execCmdEx``.
- The ``osproc`` module now uses ``posix_spawn`` instead of ``fork``
and ``exec`` on Posix systems. Define the symbol ``useFork`` to revert to
the old implementation.
2011-07-10 Version 0.8.12 released