basic thread support; still broken on Windows; untested on Mac OS X

This commit is contained in:
Araq
2011-01-18 02:22:01 +01:00
parent 0f743e0183
commit 66cfc851a1
17 changed files with 521 additions and 127 deletions

View File

@@ -51,6 +51,8 @@ ECHO %CC% %COMP_FLAGS% -Ibuild -c build/1_1/idents.c -o build/1_1/idents.o
%CC% %COMP_FLAGS% -Ibuild -c build/1_1/idents.c -o build/1_1/idents.o
ECHO %CC% %COMP_FLAGS% -Ibuild -c build/1_1/astalgo.c -o build/1_1/astalgo.o
%CC% %COMP_FLAGS% -Ibuild -c build/1_1/astalgo.c -o build/1_1/astalgo.o
ECHO %CC% %COMP_FLAGS% -Ibuild -c build/1_1/rodutils.c -o build/1_1/rodutils.o
%CC% %COMP_FLAGS% -Ibuild -c build/1_1/rodutils.c -o build/1_1/rodutils.o
ECHO %CC% %COMP_FLAGS% -Ibuild -c build/1_1/extccomp.c -o build/1_1/extccomp.o
%CC% %COMP_FLAGS% -Ibuild -c build/1_1/extccomp.c -o build/1_1/extccomp.o
ECHO %CC% %COMP_FLAGS% -Ibuild -c build/1_1/osproc.c -o build/1_1/osproc.o
@@ -146,8 +148,8 @@ ECHO %CC% %COMP_FLAGS% -Ibuild -c build/1_1/transf.c -o build/1_1/transf.o
ECHO %CC% %COMP_FLAGS% -Ibuild -c build/1_1/parseopt.c -o build/1_1/parseopt.o
%CC% %COMP_FLAGS% -Ibuild -c build/1_1/parseopt.c -o build/1_1/parseopt.o
ECHO %LINKER% %LINK_FLAGS% -o bin\nimrod.exe build/1_1/nim__dat.o build/1_1/system.o build/1_1/nimrod.o build/1_1/times.o build/1_1/strutils.o build/1_1/parseutils.o build/1_1/winlean.o build/1_1/commands.o build/1_1/os.o build/1_1/msgs.o build/1_1/options.o build/1_1/lists.o build/1_1/nstrtabs.o build/1_1/nhashes.o build/1_1/nversion.o build/1_1/condsyms.o build/1_1/ast.o build/1_1/crc.o build/1_1/ropes.o build/1_1/platform.o build/1_1/idents.o build/1_1/astalgo.o build/1_1/extccomp.o build/1_1/osproc.o build/1_1/strtabs.o build/1_1/hashes.o build/1_1/streams.o build/1_1/wordrecg.o build/1_1/scanner.o build/1_1/lexbase.o build/1_1/llstream.o build/1_1/nimconf.o build/1_1/main.o build/1_1/syntaxes.o build/1_1/pnimsyn.o build/1_1/pbraces.o build/1_1/ptmplsyn.o build/1_1/rnimsyn.o build/1_1/filters.o build/1_1/rodread.o build/1_1/rodwrite.o build/1_1/passes.o build/1_1/types.o build/1_1/trees.o build/1_1/math.o build/1_1/magicsys.o build/1_1/nimsets.o build/1_1/bitsets.o build/1_1/importer.o build/1_1/lookups.o build/1_1/semdata.o build/1_1/treetab.o build/1_1/sem.o build/1_1/evals.o build/1_1/semfold.o build/1_1/procfind.o build/1_1/pragmas.o build/1_1/docgen.o build/1_1/rst.o build/1_1/highlite.o build/1_1/cgen.o build/1_1/ccgutils.o build/1_1/cgmeth.o build/1_1/ecmasgen.o build/1_1/interact.o build/1_1/passaux.o build/1_1/depends.o build/1_1/transf.o build/1_1/parseopt.o
%LINKER% %LINK_FLAGS% -o bin\nimrod.exe build/1_1/nim__dat.o build/1_1/system.o build/1_1/nimrod.o build/1_1/times.o build/1_1/strutils.o build/1_1/parseutils.o build/1_1/winlean.o build/1_1/commands.o build/1_1/os.o build/1_1/msgs.o build/1_1/options.o build/1_1/lists.o build/1_1/nstrtabs.o build/1_1/nhashes.o build/1_1/nversion.o build/1_1/condsyms.o build/1_1/ast.o build/1_1/crc.o build/1_1/ropes.o build/1_1/platform.o build/1_1/idents.o build/1_1/astalgo.o build/1_1/extccomp.o build/1_1/osproc.o build/1_1/strtabs.o build/1_1/hashes.o build/1_1/streams.o build/1_1/wordrecg.o build/1_1/scanner.o build/1_1/lexbase.o build/1_1/llstream.o build/1_1/nimconf.o build/1_1/main.o build/1_1/syntaxes.o build/1_1/pnimsyn.o build/1_1/pbraces.o build/1_1/ptmplsyn.o build/1_1/rnimsyn.o build/1_1/filters.o build/1_1/rodread.o build/1_1/rodwrite.o build/1_1/passes.o build/1_1/types.o build/1_1/trees.o build/1_1/math.o build/1_1/magicsys.o build/1_1/nimsets.o build/1_1/bitsets.o build/1_1/importer.o build/1_1/lookups.o build/1_1/semdata.o build/1_1/treetab.o build/1_1/sem.o build/1_1/evals.o build/1_1/semfold.o build/1_1/procfind.o build/1_1/pragmas.o build/1_1/docgen.o build/1_1/rst.o build/1_1/highlite.o build/1_1/cgen.o build/1_1/ccgutils.o build/1_1/cgmeth.o build/1_1/ecmasgen.o build/1_1/interact.o build/1_1/passaux.o build/1_1/depends.o build/1_1/transf.o build/1_1/parseopt.o
ECHO %LINKER% %LINK_FLAGS% -o bin\nimrod.exe build/1_1/nim__dat.o build/1_1/system.o build/1_1/nimrod.o build/1_1/times.o build/1_1/strutils.o build/1_1/parseutils.o build/1_1/winlean.o build/1_1/commands.o build/1_1/os.o build/1_1/msgs.o build/1_1/options.o build/1_1/lists.o build/1_1/nstrtabs.o build/1_1/nhashes.o build/1_1/nversion.o build/1_1/condsyms.o build/1_1/ast.o build/1_1/crc.o build/1_1/ropes.o build/1_1/platform.o build/1_1/idents.o build/1_1/astalgo.o build/1_1/rodutils.o build/1_1/extccomp.o build/1_1/osproc.o build/1_1/strtabs.o build/1_1/hashes.o build/1_1/streams.o build/1_1/wordrecg.o build/1_1/scanner.o build/1_1/lexbase.o build/1_1/llstream.o build/1_1/nimconf.o build/1_1/main.o build/1_1/syntaxes.o build/1_1/pnimsyn.o build/1_1/pbraces.o build/1_1/ptmplsyn.o build/1_1/rnimsyn.o build/1_1/filters.o build/1_1/rodread.o build/1_1/rodwrite.o build/1_1/passes.o build/1_1/types.o build/1_1/trees.o build/1_1/math.o build/1_1/magicsys.o build/1_1/nimsets.o build/1_1/bitsets.o build/1_1/importer.o build/1_1/lookups.o build/1_1/semdata.o build/1_1/treetab.o build/1_1/sem.o build/1_1/evals.o build/1_1/semfold.o build/1_1/procfind.o build/1_1/pragmas.o build/1_1/docgen.o build/1_1/rst.o build/1_1/highlite.o build/1_1/cgen.o build/1_1/ccgutils.o build/1_1/cgmeth.o build/1_1/ecmasgen.o build/1_1/interact.o build/1_1/passaux.o build/1_1/depends.o build/1_1/transf.o build/1_1/parseopt.o
%LINKER% %LINK_FLAGS% -o bin\nimrod.exe build/1_1/nim__dat.o build/1_1/system.o build/1_1/nimrod.o build/1_1/times.o build/1_1/strutils.o build/1_1/parseutils.o build/1_1/winlean.o build/1_1/commands.o build/1_1/os.o build/1_1/msgs.o build/1_1/options.o build/1_1/lists.o build/1_1/nstrtabs.o build/1_1/nhashes.o build/1_1/nversion.o build/1_1/condsyms.o build/1_1/ast.o build/1_1/crc.o build/1_1/ropes.o build/1_1/platform.o build/1_1/idents.o build/1_1/astalgo.o build/1_1/rodutils.o build/1_1/extccomp.o build/1_1/osproc.o build/1_1/strtabs.o build/1_1/hashes.o build/1_1/streams.o build/1_1/wordrecg.o build/1_1/scanner.o build/1_1/lexbase.o build/1_1/llstream.o build/1_1/nimconf.o build/1_1/main.o build/1_1/syntaxes.o build/1_1/pnimsyn.o build/1_1/pbraces.o build/1_1/ptmplsyn.o build/1_1/rnimsyn.o build/1_1/filters.o build/1_1/rodread.o build/1_1/rodwrite.o build/1_1/passes.o build/1_1/types.o build/1_1/trees.o build/1_1/math.o build/1_1/magicsys.o build/1_1/nimsets.o build/1_1/bitsets.o build/1_1/importer.o build/1_1/lookups.o build/1_1/semdata.o build/1_1/treetab.o build/1_1/sem.o build/1_1/evals.o build/1_1/semfold.o build/1_1/procfind.o build/1_1/pragmas.o build/1_1/docgen.o build/1_1/rst.o build/1_1/highlite.o build/1_1/cgen.o build/1_1/ccgutils.o build/1_1/cgmeth.o build/1_1/ecmasgen.o build/1_1/interact.o build/1_1/passaux.o build/1_1/depends.o build/1_1/transf.o build/1_1/parseopt.o
ECHO SUCCESS

View File

@@ -1,5 +1,5 @@
# Configuration file for the Nimrod Compiler.
# (c) 2010 Andreas Rumpf
# (c) 2011 Andreas Rumpf
# Feel free to edit the default values as you need.
@@ -14,6 +14,7 @@ cc = gcc
lib = "nimlib"
@end
path="$lib/core"
path="$lib/pure"
path="$lib/impure"
path="$lib/wrappers"

View File

@@ -31,6 +31,9 @@ Core
implicitly by the compiler. Do not import it directly. It relies on compiler
magic to work.
* `threads <threads.html>`_
Nimrod thread support.
* `macros <macros.html>`_
Contains the AST API and documentation of Nimrod for writing macros.

View File

@@ -321,6 +321,8 @@ if [ $# -eq 1 ] ; then
chmod 644 $libdir/system/sysstr.nim
cp lib/system/systhread.nim $libdir/system/systhread.nim
chmod 644 $libdir/system/systhread.nim
cp lib/pure/base64.nim $libdir/pure/base64.nim
chmod 644 $libdir/pure/base64.nim
cp lib/pure/browsers.nim $libdir/pure/browsers.nim
chmod 644 $libdir/pure/browsers.nim
cp lib/pure/cgi.nim $libdir/pure/cgi.nim
@@ -329,12 +331,12 @@ if [ $# -eq 1 ] ; then
chmod 644 $libdir/pure/colors.nim
cp lib/pure/complex.nim $libdir/pure/complex.nim
chmod 644 $libdir/pure/complex.nim
cp lib/pure/cookies.nim $libdir/pure/cookies.nim
chmod 644 $libdir/pure/cookies.nim
cp lib/pure/dynlib.nim $libdir/pure/dynlib.nim
chmod 644 $libdir/pure/dynlib.nim
cp lib/pure/hashes.nim $libdir/pure/hashes.nim
chmod 644 $libdir/pure/hashes.nim
cp lib/pure/hashtabs.nim $libdir/pure/hashtabs.nim
chmod 644 $libdir/pure/hashtabs.nim
cp lib/pure/htmlparser.nim $libdir/pure/htmlparser.nim
chmod 644 $libdir/pure/htmlparser.nim
cp lib/pure/httpclient.nim $libdir/pure/httpclient.nim
@@ -347,8 +349,6 @@ if [ $# -eq 1 ] ; then
chmod 644 $libdir/pure/lexbase.nim
cp lib/pure/logging.nim $libdir/pure/logging.nim
chmod 644 $libdir/pure/logging.nim
cp lib/pure/macros.nim $libdir/pure/macros.nim
chmod 644 $libdir/pure/macros.nim
cp lib/pure/math.nim $libdir/pure/math.nim
chmod 644 $libdir/pure/math.nim
cp lib/pure/md5.nim $libdir/pure/md5.nim
@@ -377,6 +377,10 @@ if [ $# -eq 1 ] ; then
chmod 644 $libdir/pure/regexprs.nim
cp lib/pure/ropes.nim $libdir/pure/ropes.nim
chmod 644 $libdir/pure/ropes.nim
cp lib/pure/scgi.nim $libdir/pure/scgi.nim
chmod 644 $libdir/pure/scgi.nim
cp lib/pure/smtp.nim $libdir/pure/smtp.nim
chmod 644 $libdir/pure/smtp.nim
cp lib/pure/sockets.nim $libdir/pure/sockets.nim
chmod 644 $libdir/pure/sockets.nim
cp lib/pure/streams.nim $libdir/pure/streams.nim
@@ -391,8 +395,6 @@ if [ $# -eq 1 ] ; then
chmod 644 $libdir/pure/times.nim
cp lib/pure/unicode.nim $libdir/pure/unicode.nim
chmod 644 $libdir/pure/unicode.nim
cp lib/pure/variants.nim $libdir/pure/variants.nim
chmod 644 $libdir/pure/variants.nim
cp lib/pure/xmldom.nim $libdir/pure/xmldom.nim
chmod 644 $libdir/pure/xmldom.nim
cp lib/pure/xmldomparser.nim $libdir/pure/xmldomparser.nim
@@ -421,10 +423,14 @@ if [ $# -eq 1 ] ; then
chmod 644 $libdir/impure/osinfo_win.nim
cp lib/impure/re.nim $libdir/impure/re.nim
chmod 644 $libdir/impure/re.nim
cp lib/impure/ssl.nim $libdir/impure/ssl.nim
chmod 644 $libdir/impure/ssl.nim
cp lib/impure/web.nim $libdir/impure/web.nim
chmod 644 $libdir/impure/web.nim
cp lib/impure/zipfiles.nim $libdir/impure/zipfiles.nim
chmod 644 $libdir/impure/zipfiles.nim
cp lib/wrappers/claro.nim $libdir/wrappers/claro.nim
chmod 644 $libdir/wrappers/claro.nim
cp lib/wrappers/expat.nim $libdir/wrappers/expat.nim
chmod 644 $libdir/wrappers/expat.nim
cp lib/wrappers/iup.nim $libdir/wrappers/iup.nim
@@ -435,6 +441,8 @@ if [ $# -eq 1 ] ; then
chmod 644 $libdir/wrappers/mysql.nim
cp lib/wrappers/odbcsql.nim $libdir/wrappers/odbcsql.nim
chmod 644 $libdir/wrappers/odbcsql.nim
cp lib/wrappers/openssl.nim $libdir/wrappers/openssl.nim
chmod 644 $libdir/wrappers/openssl.nim
cp lib/wrappers/pcre.nim $libdir/wrappers/pcre.nim
chmod 644 $libdir/wrappers/pcre.nim
cp lib/wrappers/postgres.nim $libdir/wrappers/postgres.nim

259
lib/core/marshal.nim Normal file
View File

@@ -0,0 +1,259 @@
#
#
# Nimrod's Runtime Library
# (c) Copyright 2011 Andreas Rumpf
#
# See the file "copying.txt", included in this
# distribution, for details about the copyright.
#
## This module contains procs for serialization and deseralization of
## arbitrary Nimrod data structures. XXX This is not implemented yet!
import streams
proc load*[T](s: PStream, data: var T) {.magic: "Load".}
## loads `data` from the stream `s`. Raises `EIO` in case of an error.
proc store*[T](s: PStream, data: T) {.magic: "Store".}
## stores `data` into the stream `s`. Raises `EIO` in case of an error.
proc reprInt(x: int64): string {.compilerproc.} = return $x
proc reprFloat(x: float): string {.compilerproc.} = return $x
proc reprPointer(x: pointer): string {.compilerproc.} =
var buf: array [0..59, char]
c_sprintf(buf, "%p", x)
return $buf
proc reprStrAux(result: var string, s: string) =
if cast[pointer](s) == nil:
add result, "nil"
return
add result, reprPointer(cast[pointer](s)) & "\""
for c in items(s):
case c
of '"': add result, "\\\""
of '\\': add result, "\\\\" # BUGFIX: forgotten
of '\10': add result, "\\10\"\n\"" # " \n " # better readability
of '\128' .. '\255', '\0'..'\9', '\11'..'\31':
add result, "\\" & reprInt(ord(c))
else: result.add(c)
add result, "\""
proc reprStr(s: string): string {.compilerRtl.} =
result = ""
reprStrAux(result, s)
proc reprBool(x: bool): string {.compilerRtl.} =
if x: result = "true"
else: result = "false"
proc reprChar(x: char): string {.compilerRtl.} =
result = "\'"
case x
of '"': add result, "\\\""
of '\\': add result, "\\\\"
of '\128' .. '\255', '\0'..'\31': add result, "\\" & reprInt(ord(x))
else: add result, x
add result, "\'"
proc reprEnum(e: int, typ: PNimType): string {.compilerRtl.} =
if e <% typ.node.len: # BUGFIX
result = $typ.node.sons[e].name
else:
result = $e & " (invalid data!)"
type
pbyteArray = ptr array[0.. 0xffff, byte]
proc addSetElem(result: var string, elem: int, typ: PNimType) =
case typ.kind
of tyEnum: add result, reprEnum(elem, typ)
of tyBool: add result, reprBool(bool(elem))
of tyChar: add result, reprChar(chr(elem))
of tyRange: addSetElem(result, elem, typ.base)
of tyInt..tyInt64: add result, reprInt(elem)
else: # data corrupt --> inform the user
add result, " (invalid data!)"
proc reprSetAux(result: var string, p: pointer, typ: PNimType) =
# "typ.slots.len" field is for sets the "first" field
var elemCounter = 0 # we need this flag for adding the comma at
# the right places
add result, "{"
var u: int64
case typ.size
of 1: u = ze64(cast[ptr int8](p)^)
of 2: u = ze64(cast[ptr int16](p)^)
of 4: u = ze64(cast[ptr int32](p)^)
of 8: u = cast[ptr int64](p)^
else:
var a = cast[pbyteArray](p)
for i in 0 .. typ.size*8-1:
if (ze(a[i div 8]) and (1 shl (i mod 8))) != 0:
if elemCounter > 0: add result, ", "
addSetElem(result, i+typ.node.len, typ.base)
inc(elemCounter)
if typ.size <= 8:
for i in 0..sizeof(int64)*8-1:
if (u and (1 shl i)) != 0:
if elemCounter > 0: add result, ", "
addSetElem(result, i+typ.node.len, typ.base)
inc(elemCounter)
add result, "}"
proc reprSet(p: pointer, typ: PNimType): string {.compilerRtl.} =
result = ""
reprSetAux(result, p, typ)
type
TReprClosure {.final.} = object # we cannot use a global variable here
# as this wouldn't be thread-safe
marked: TCellSet
recdepth: int # do not recurse endless
indent: int # indentation
when not defined(useNimRtl):
proc initReprClosure(cl: var TReprClosure) =
Init(cl.marked)
cl.recdepth = -1 # default is to display everything!
cl.indent = 0
proc deinitReprClosure(cl: var TReprClosure) =
Deinit(cl.marked)
proc reprBreak(result: var string, cl: TReprClosure) =
add result, "\n"
for i in 0..cl.indent-1: add result, ' '
proc reprAux(result: var string, p: pointer, typ: PNimType,
cl: var TReprClosure)
proc reprArray(result: var string, p: pointer, typ: PNimType,
cl: var TReprClosure) =
add result, "["
var bs = typ.base.size
for i in 0..typ.size div bs - 1:
if i > 0: add result, ", "
reprAux(result, cast[pointer](cast[TAddress](p) + i*bs), typ.base, cl)
add result, "]"
proc reprSequence(result: var string, p: pointer, typ: PNimType,
cl: var TReprClosure) =
if p == nil:
add result, "nil"
return
result.add(reprPointer(p) & "[")
var bs = typ.base.size
for i in 0..cast[PGenericSeq](p).len-1:
if i > 0: add result, ", "
reprAux(result, cast[pointer](cast[TAddress](p) + GenericSeqSize + i*bs),
typ.Base, cl)
add result, "]"
proc reprRecordAux(result: var string, p: pointer, n: ptr TNimNode,
cl: var TReprClosure) =
case n.kind
of nkNone: assert(false)
of nkSlot:
add result, $n.name
add result, " = "
reprAux(result, cast[pointer](cast[TAddress](p) + n.offset), n.typ, cl)
of nkList:
for i in 0..n.len-1:
if i > 0: add result, ",\n"
reprRecordAux(result, p, n.sons[i], cl)
of nkCase:
var m = selectBranch(p, n)
reprAux(result, cast[pointer](cast[TAddress](p) + n.offset), n.typ, cl)
if m != nil: reprRecordAux(result, p, m, cl)
proc reprRecord(result: var string, p: pointer, typ: PNimType,
cl: var TReprClosure) =
add result, "["
reprRecordAux(result, p, typ.node, cl)
add result, "]"
proc reprRef(result: var string, p: pointer, typ: PNimType,
cl: var TReprClosure) =
# we know that p is not nil here:
when defined(boehmGC) or defined(nogc):
var cell = cast[PCell](p)
else:
var cell = usrToCell(p)
add result, "ref " & reprPointer(p)
if cell notin cl.marked:
# only the address is shown:
incl(cl.marked, cell)
add result, " --> "
reprAux(result, p, typ.base, cl)
proc reprAux(result: var string, p: pointer, typ: PNimType,
cl: var TReprClosure) =
if cl.recdepth == 0:
add result, "..."
return
dec(cl.recdepth)
case typ.kind
of tySet: reprSetAux(result, p, typ)
of tyArray: reprArray(result, p, typ, cl)
of tyTuple, tyPureObject: reprRecord(result, p, typ, cl)
of tyObject:
var t = cast[ptr PNimType](p)^
reprRecord(result, p, t, cl)
of tyRef, tyPtr:
assert(p != nil)
if cast[ppointer](p)^ == nil: add result, "nil"
else: reprRef(result, cast[ppointer](p)^, typ, cl)
of tySequence:
reprSequence(result, cast[ppointer](p)^, typ, cl)
of tyInt: add result, $(cast[ptr int](p)^)
of tyInt8: add result, $int(cast[ptr Int8](p)^)
of tyInt16: add result, $int(cast[ptr Int16](p)^)
of tyInt32: add result, $int(cast[ptr Int32](p)^)
of tyInt64: add result, $(cast[ptr Int64](p)^)
of tyFloat: add result, $(cast[ptr float](p)^)
of tyFloat32: add result, $(cast[ptr float32](p)^)
of tyFloat64: add result, $(cast[ptr float64](p)^)
of tyEnum: add result, reprEnum(cast[ptr int](p)^, typ)
of tyBool: add result, reprBool(cast[ptr bool](p)^)
of tyChar: add result, reprChar(cast[ptr char](p)^)
of tyString: reprStrAux(result, cast[ptr string](p)^)
of tyCString: reprStrAux(result, $(cast[ptr cstring](p)^))
of tyRange: reprAux(result, p, typ.base, cl)
of tyProc, tyPointer:
if cast[ppointer](p)^ == nil: add result, "nil"
else: add result, reprPointer(cast[ppointer](p)^)
else:
add result, "(invalid data!)"
inc(cl.recdepth)
proc reprOpenArray(p: pointer, length: int, elemtyp: PNimType): string {.
compilerRtl.} =
var
cl: TReprClosure
initReprClosure(cl)
result = "["
var bs = elemtyp.size
for i in 0..length - 1:
if i > 0: add result, ", "
reprAux(result, cast[pointer](cast[TAddress](p) + i*bs), elemtyp, cl)
add result, "]"
deinitReprClosure(cl)
when not defined(useNimRtl):
proc reprAny(p: pointer, typ: PNimType): string =
var
cl: TReprClosure
initReprClosure(cl)
result = ""
if typ.kind in {tyObject, tyPureObject, tyTuple, tyArray, tySet}:
reprAux(result, p, typ, cl)
else:
var p = p
reprAux(result, addr(p), typ, cl)
add result, "\n"
deinitReprClosure(cl)

174
lib/core/threads.nim Normal file
View File

@@ -0,0 +1,174 @@
#
#
# Nimrod's Runtime Library
# (c) Copyright 2011 Andreas Rumpf
#
# See the file "copying.txt", included in this
# distribution, for details about the copyright.
#
## Basic thread support for Nimrod. Note that Nimrod's default GC is still
## single-threaded. This means that either your threads should not allocate
## GC'ed memory, or you should compile with ``--gc:none`` or ``--gc:boehm``.
##
## Example:
##
## .. code-block:: nimrod
##
## var
## thr: array [0..4, TThread]
## L: TLock
##
## proc threadFunc(c: pointer) {.procvar.} =
## for i in 0..9:
## Aquire(L) # lock stdout
## echo i
## Release(L)
##
## InitLock(L)
##
## for i in 0..high(thr):
## createThread(thr[i], threadFunc)
## for i in 0..high(thr):
## joinThread(thr[i])
# We jump through some hops here to ensure that Nimrod thread procs can have
# the Nimrod calling convention. This is needed because thread procs are
# ``stdcall`` on Windows and ``noconv`` on UNIX. Alternative would be to just
# use ``stdcall`` since it is mapped to ``noconv`` on UNIX anyway. However,
# the current approach will likely result in less problems later when we have
# GC'ed closures in Nimrod.
type
TThreadProc* = proc (closure: pointer) ## Standard Nimrod thread proc.
TThreadProcClosure {.pure, final.} = object
fn: TThreadProc
data: pointer
when defined(Windows):
type
THandle = int
TSysThread = THandle
TSysLock {.final, pure.} = object # CRITICAL_SECTION in WinApi
DebugInfo: pointer
LockCount: int32
RecursionCount: int32
OwningThread: int
LockSemaphore: int
Reserved: int32
TWinThreadProc = proc (x: pointer): int32 {.stdcall.}
TLock* = TSysLock ## Standard Nimrod Lock type.
proc InitLock*(L: var TLock) {.stdcall,
dynlib: "kernel32", importc: "InitializeCriticalSection".}
## Initializes the lock `L`.
proc Aquire*(L: var TLock) {.stdcall,
dynlib: "kernel32", importc: "EnterCriticalSection".}
## Aquires the lock `L`.
proc Release*(L: var TLock) {.stdcall,
dynlib: "kernel32", importc: "LeaveCriticalSection".}
## Releases the lock `L`.
proc CreateThread(lpThreadAttributes: Pointer, dwStackSize: int32,
lpStartAddress: TWinThreadProc,
lpParameter: Pointer,
dwCreationFlags: int32, lpThreadId: var int32): THandle {.
stdcall, dynlib: "kernel32", importc: "CreateThread".}
when false:
proc winSuspendThread(hThread: TSysThread): int32 {.
stdcall, dynlib: "kernel32", importc: "SuspendThread".}
proc winResumeThread(hThread: TSysThread): int32 {.
stdcall, dynlib: "kernel32", importc: "ResumeThread".}
proc WaitForMultipleObjects(nCount: int32,
lpHandles: ptr array[0..10, THandle],
bWaitAll: int32,
dwMilliseconds: int32): int32 {.
stdcall, dynlib: "kernel32", importc: "WaitForMultipleObjects".}
proc WaitForSingleObject(hHandle: THANDLE, dwMilliseconds: int32): int32 {.
stdcall, dynlib: "kernel32", importc: "WaitForSingleObject".}
proc TerminateThread(hThread: THandle, dwExitCode: int32): int32 {.
stdcall, dynlib: "kernel32", importc: "TerminateThread".}
proc threadProcWrapper(closure: pointer): int32 {.stdcall.} =
var c = cast[ptr TThreadProcClosure](closure)
c.fn(c.data)
# implicitely return 0
else:
type
TSysLock {.importc: "pthread_mutex_t", header: "<sys/types.h>".} = int
TSysThread {.importc: "pthread_t", header: "<sys/types.h>".} = int
TLock* = TSysLock
proc InitLockAux(L: var TSysLock, attr: pointer = nil) {.
importc: "pthread_mutex_init", header: "<pthread.h>".}
proc InitLock*(L: var TLock) {.inline.} =
InitLockAux(L)
proc Aquire*(L: var TLock) {.
importc: "pthread_mutex_lock", header: "<pthread.h>".}
proc Release*(L: var TLock) {.
importc: "pthread_mutex_unlock", header: "<pthread.h>".}
proc pthread_create(a1: var TSysThread, a2: ptr int,
a3: proc (x: pointer) {.noconv.},
a4: pointer): cint {.importc: "pthread_create",
header: "<pthread.h>".}
proc pthread_join(a1: TSysThread, a2: ptr pointer): cint {.
importc, header: "<pthread.h>".}
proc pthread_cancel(a1: TSysThread): cint {.
importc: "pthread_cancel", header: "<pthread.h>".}
proc threadProcWrapper(closure: pointer) {.noconv.} =
var c = cast[ptr TThreadProcClosure](closure)
c.fn(c.data)
{.passL: "-pthread".}
{.passC: "-pthread".}
type
TThread* = object of TObject ## Nimrod thread.
sys: TSysThread
c: TThreadProcClosure
proc createThread*(t: var TThread, tp: TThreadProc,
closure: pointer = nil) =
## creates a new thread `t` and starts its execution. Entry point is the
## proc `tp`. `closure` is passed to `tp`.
t.c.data = closure
t.c.fn = tp
when defined(windows):
var dummyThreadId: int32
t.sys = CreateThread(nil, 0'i32, threadProcWrapper, addr(t.c), 0'i32,
dummyThreadId)
else:
discard pthread_create(t.sys, nil, threadProcWrapper, addr(t.c))
proc joinThread*(t: TThread) =
## waits for the thread `t` until it has terminated.
when defined(windows):
discard WaitForSingleObject(t.sys, -1'i32)
else:
discard pthread_join(t.sys, nil)
proc destroyThread*(t: var TThread) =
## forces the thread `t` to terminate. This is potentially dangerous if
## you don't have full control over `t` and its aquired ressources.
when defined(windows):
discard TerminateThread(t.sys, 1'i32)
else:
discard pthread_cancel(t.sys)

View File

@@ -71,7 +71,11 @@ __TINYC__
# define NIM_CONST const
#endif
#define NIM_THREADVAR __thread
#if (defined(WIN32) || defined(_WIN32) || defined(__WIN32__))
# define NIM_THREADVAR __declspec(thread)
#else
# define NIM_THREADVAR __thread
#endif
/* --------------- how int64 constants should be declared: ----------- */
#if defined(__GNUC__) || defined(__LCC__) || \
@@ -415,8 +419,9 @@ struct TFrame {
NI len;
};
/*
extern TFrame* framePtr;
/*extern TSafePoint* excHandler; */
extern TSafePoint* excHandler; */
#if defined(__cplusplus)
struct NimException {

View File

@@ -1259,6 +1259,18 @@ var
## each executed instruction. This should only be used by debuggers!
## Only code compiled with the ``debugger:on`` switch calls this hook.
type
PFrame = ptr TFrame
TFrame {.importc, nodecl, final.} = object
prev: PFrame
procname: CString
line: int # current line number
filename: CString
len: int # length of slots (when not debugging always zero)
var
framePtr {.threadvar, compilerproc.}: PFrame
when not defined(ECMAScript):
{.push overflow_checks:off}
proc add* (x: var string, y: cstring) =

View File

@@ -1,7 +1,7 @@
#
#
# Nimrod's Runtime Library
# (c) Copyright 2010 Andreas Rumpf
# (c) Copyright 2011 Andreas Rumpf
#
# See the file "copying.txt", included in this
# distribution, for details about the copyright.
@@ -40,10 +40,10 @@ type
context: C_JmpBuf
var
excHandler {.compilerproc.}: PSafePoint = nil
excHandler {.threadvar, compilerproc.}: PSafePoint = nil
# list of exception handlers
# a global variable for the root of all try blocks
currException: ref E_Base
currException {.threadvar.}: ref E_Base
proc pushSafePoint(s: PSafePoint) {.compilerRtl, inl.} =
s.prev = excHandler
@@ -107,23 +107,11 @@ when nativeStacktrace:
# interested in
enabled = true
type
PFrame = ptr TFrame
TFrame {.importc, nodecl, final.} = object
prev: PFrame
procname: CString
line: int # current line number
filename: CString
len: int # length of slots (when not debugging always zero)
var
buf: string # cannot be allocated on the stack!
assertBuf: string # we need a different buffer for
# assert, as it raises an exception and
# exception handler needs the buffer too
framePtr {.exportc.}: PFrame
tempFrames: array [0..127, PFrame] # cannot be allocated on the stack!
proc auxWriteStackTrace(f: PFrame, s: var string) =

View File

@@ -61,8 +61,9 @@ type
decStack: TCellSeq # cells in the stack that are to decref again
cycleRoots: TCellSet
tempStack: TCellSeq # temporary stack for recursion elimination
cycleRootsLock: TSysLock
zctLock: TSysLock
when hasThreadSupport:
cycleRootsLock: TSysLock
zctLock: TSysLock
stat: TGcStat
var
@@ -281,8 +282,9 @@ proc initGC() =
init(gch.tempStack)
Init(gch.cycleRoots)
Init(gch.decStack)
InitLock(gch.cycleRootsLock)
InitLock(gch.zctLock)
when hasThreadSupport:
InitLock(gch.cycleRootsLock)
InitLock(gch.zctLock)
new(gOutOfMem) # reserve space for the EOutOfMemory exception here!
proc forAllSlotsAux(dest: pointer, n: ptr TNimNode, op: TWalkOp) =

View File

@@ -44,83 +44,4 @@ proc atomicDec(memLoc: var int, x: int): int =
else:
dec(memLoc, x)
result = memLoc
when defined(Windows):
type
THandle = int
TSysThread = THandle
TSysLock {.final, pure.} = object # CRITICAL_SECTION in WinApi
DebugInfo: pointer
LockCount: int32
RecursionCount: int32
OwningThread: int
LockSemaphore: int
Reserved: int32
proc InitLock(L: var TSysLock) {.stdcall,
dynlib: "kernel32", importc: "InitializeCriticalSection".}
proc Aquire(L: var TSysLock) {.stdcall,
dynlib: "kernel32", importc: "EnterCriticalSection".}
proc Release(L: var TSysLock) {.stdcall,
dynlib: "kernel32", importc: "LeaveCriticalSection".}
proc CreateThread(lpThreadAttributes: Pointer, dwStackSize: int32,
lpStartAddress: pointer, lpParameter: Pointer,
dwCreationFlags: int32, lpThreadId: var int32): THandle {.
stdcall, dynlib: "kernel32", importc: "CreateThread".}
proc winSuspendThread(hThread: TSysThread): int32 {.
stdcall, dynlib: "kernel32", importc: "SuspendThread".}
proc winResumeThread(hThread: TSysThread): int32 {.
stdcall, dynlib: "kernel32", importc: "ResumeThread".}
proc WaitForMultipleObjects(nCount: int32,
lpHandles: ptr array[0..10, THandle],
bWaitAll: int32,
dwMilliseconds: int32): int32 {.
stdcall, dynlib: "kernel32", importc: "WaitForMultipleObjects".}
proc WaitForSingleObject(hHandle: THANDLE, dwMilliseconds: int32): int32 {.
stdcall, dynlib: "kernel32", importc: "WaitForSingleObject".}
else:
type
TSysLock {.importc: "pthread_mutex_t", header: "<sys/types.h>".} = int
TSysThread {.importc: "pthread_t", header: "<sys/types.h>".} = int
proc InitLock(L: var TSysLock, attr: pointer = nil) {.
importc: "pthread_mutex_init", header: "<pthread.h>".}
proc Aquire(L: var TSysLock) {.
importc: "pthread_mutex_lock", header: "<pthread.h>".}
proc Release(L: var TSysLock) {.
importc: "pthread_mutex_unlock", header: "<pthread.h>".}
proc pthread_create(a1: ptr TSysThread, a2: ptr int,
a3: proc (x: pointer): pointer {.noconv.},
a4: pointer): cint {.importc: "pthread_create",
header: "<pthread.h>".}
proc pthread_join(a1: TSysThread, a2: ptr pointer): cint {.
importc, header: "<pthread.h>".}
type
TThread* = TSysThread
TLock* = TSysLock
TThreadFunc* = proc (closure: pointer) {.cdecl.}
proc createThread*(t: var TThread, fn: TThreadFunc, closure: pointer) =
when defined(windows):
nil
else:
nil
#pthread_create(
proc joinThread*(t: TThread) =
nil
#proc pthread_exit(void *value_ptr)
proc destroyThread*(t: var TThread) =
nil

View File

@@ -477,7 +477,7 @@ proc genTryStmtCpp(p: BProc, t: PNode) =
rethrowFlag = getTempName()
appf(p.s[cpsLocals], "volatile NIM_BOOL $1 = NIM_FALSE;$n", [rethrowFlag])
if optStackTrace in p.Options:
app(p.s[cpsStmts], "framePtr = (TFrame*)&F;" & tnl)
appcg(p, cpsStmts, "#framePtr = (TFrame*)&F;" & tnl)
app(p.s[cpsStmts], "try {" & tnl)
add(p.nestedTryStmts, t)
genStmts(p, t.sons[0])
@@ -542,7 +542,7 @@ proc genTryStmt(p: BProc, t: PNode) =
appcg(p, cpsStmts, "#pushSafePoint(&$1);$n" &
"$1.status = setjmp($1.context);$n", [safePoint])
if optStackTrace in p.Options:
app(p.s[cpsStmts], "framePtr = (TFrame*)&F;" & tnl)
appcg(p, cpsStmts, "#framePtr = (TFrame*)&F;" & tnl)
appf(p.s[cpsStmts], "if ($1.status == 0) {$n", [safePoint])
var length = sonsLen(t)
add(p.nestedTryStmts, t)

View File

@@ -386,10 +386,10 @@ proc assignGlobalVar(p: BProc, s: PSym) =
useHeader(p.module, s)
if lfNoDecl in s.loc.flags: return
if sfImportc in s.flags: app(p.module.s[cfsVars], "extern ")
if sfThreadVar in s.flags: app(p.module.s[cfsVars], "NIM_THREADVAR ")
app(p.module.s[cfsVars], getTypeDesc(p.module, s.loc.t))
if sfRegister in s.flags: app(p.module.s[cfsVars], " register")
if sfVolatile in s.flags: app(p.module.s[cfsVars], " volatile")
if sfThreadVar in s.flags: app(p.module.s[cfsVars], " NIM_THREADVAR")
appf(p.module.s[cfsVars], " $1;$n", [s.loc.r])
if {optStackTrace, optEndb} * p.module.module.options ==
{optStackTrace, optEndb}:
@@ -550,19 +550,12 @@ proc retIsNotVoid(s: PSym): bool =
result = (s.typ.sons[0] != nil) and not isInvalidReturnType(s.typ.sons[0])
proc initFrame(p: BProc, procname, filename: PRope): PRope =
inc(p.labels, 5)
result = ropeff("F.procname = $1;$n" & "F.prev = framePtr;$n" &
"F.filename = $2;$n" & "F.line = 0;$n" & "framePtr = (TFrame*)&F;$n",
"%LOC$3 = getelementptr %TF %F, %NI 1$n" &
"%LOC$4 = getelementptr %TF %F, %NI 0$n" &
"%LOC$5 = getelementptr %TF %F, %NI 3$n" &
"%LOC$6 = getelementptr %TF %F, %NI 2$n" & "store i8* $1, i8** %LOC$3$n" &
"store %TFrame* @framePtr, %TFrame** %LOC$4$n" &
"store i8* $2, i8** %LOC$5$n" & "store %NI 0, %NI* %LOC$6$n" &
"%LOC$7 = bitcast %TF* %F to %TFrame*$n" &
"store %TFrame* %LOC$7, %TFrame** @framePtr$n", [procname, filename,
toRope(p.labels), toRope(p.labels - 1), toRope(p.labels - 2),
toRope(p.labels - 3), toRope(p.labels - 4)])
result = ropecg(p.module,
"F.procname = $1;$n" &
"F.prev = #framePtr;$n" &
"F.filename = $2;$n" &
"F.line = 0;$n" &
"framePtr = (TFrame*)&F;$n", [procname, filename])
proc deinitFrame(p: BProc): PRope =
inc(p.labels, 3)
@@ -693,10 +686,10 @@ proc genVarPrototype(m: BModule, sym: PSym) =
[sym.loc.r, getTypeDesc(m, sym.loc.t)])
else:
app(m.s[cfsVars], "extern ")
if sfThreadVar in sym.flags: app(m.s[cfsVars], "NIM_THREADVAR ")
app(m.s[cfsVars], getTypeDesc(m, sym.loc.t))
if sfRegister in sym.flags: app(m.s[cfsVars], " register")
if sfVolatile in sym.flags: app(m.s[cfsVars], " volatile")
if sfThreadVar in sym.flags: app(m.s[cfsVars], " NIM_THREADVAR")
appf(m.s[cfsVars], " $1;$n", [sym.loc.r])
proc genConstPrototype(m: BModule, sym: PSym) =

21
tests/gc/tthreads.nim Normal file
View File

@@ -0,0 +1,21 @@
import threads
var
thr: array [0..4, TThread]
L: TLock
proc threadFunc(c: pointer) {.procvar.} =
for i in 0..9:
Aquire(L)
echo i
Release(L)
InitLock(L)
for i in 0..high(thr):
createThread(thr[i], threadFunc)
for i in 0..high(thr):
joinThread(thr[i])

View File

@@ -1,10 +1,14 @@
- thread support: threadvar on Windows seems broken;
add --deadlock_prevention:on|off switch
- we need a way to disable tests
- deprecate ^ and make it available as operator
- test branch coverage
- checked exceptions
- built-in serialization
- do not ambiguity error for methods if amibiguity only affects the same
- do not ambiguity error for methods if ambiguity only affects the same
dispatcher anyway
- slicing
High priority (version 0.9.0)

View File

@@ -49,6 +49,7 @@ Additions
``array[TMyEnum, string]`` mapping.
- Indices in array literals may be explicitly given, enhancing readability:
``[enumValueA: "a", enumValueB: "b"]``.
- Added basic thread support via the ``threads`` core module.