remove Nim 1.2 and Nim 1.4 support (#32)

* remove Nim 1.2 and Nim 1.4 support

* re-add std/tasks shims

* remove shim again
This commit is contained in:
tersec 2023-06-27 09:45:06 +00:00 committed by GitHub
parent 7929634fad
commit 5551f10490
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
10 changed files with 9 additions and 434 deletions

View File

@ -27,11 +27,11 @@ jobs:
cpu: amd64
#- os: windows
#cpu: i386
branch: [version-1-2, version-1-4, version-1-6, devel]
branch: [version-1-6, version-2-0, devel]
include:
- target:
os: linux
builder: ubuntu-18.04
builder: ubuntu-20.04
shell: bash
- target:
os: macos

View File

@ -7,16 +7,15 @@ description = "lightweight, energy-efficient, easily auditable threadpool"
license = "MIT"
skipDirs = @["tests"]
requires "nim >= 1.2.12"
requires "nim >= 1.6.0"
let nimc = getEnv("NIMC", "nim") # Which nim compiler to use
let lang = getEnv("NIMLANG", "c") # Which backend (c/cpp/js)
let flags = getEnv("NIMFLAGS", "") # Extra flags for the compiler
let verbose = getEnv("V", "") notin ["", "0"]
let styleCheckStyle = if (NimMajor, NimMinor) < (1, 6): "hint" else: "error"
let cfg =
" --styleCheck:usages --styleCheck:" & styleCheckStyle &
" --styleCheck:usages --styleCheck:error" &
(if verbose: "" else: " --verbosity:0 --hints:off") &
" --skipParentCfg --skipUserCfg --outdir:build --nimcache:build/nimcache -f" &
" --stacktrace:on --linetrace:on" &

View File

@ -28,9 +28,6 @@ type
itemSize*: uint8
buffer*{.align: 8.}: UncheckedArray[byte]
when (NimMajor,NimMinor,NimPatch) <= (1,4,0):
type AssertionDefect = AssertionError
{.push raises: [AssertionDefect].} # Ensure no exceptions can happen
proc `=`(

View File

@ -65,9 +65,6 @@ type
buf: Atomic[ptr Buf[T]]
garbage: ptr Buf[T]
when (NimMajor,NimMinor,NimPatch) <= (1,4,0):
type AssertionDefect = AssertionError
{.push raises: [AssertionDefect].} # Ensure no exceptions can happen
{.push overflowChecks: off.} # We don't want exceptions (for Defect) in a multithreaded context
# but we don't to deal with underflow of unsigned int either

View File

@ -1,5 +1,5 @@
# Nim-Taskpools
# Copyright (c) 2021 Status Research & Development GmbH
# Copyright (c) 2021-2023 Status Research & Development GmbH
# Licensed and distributed under either of
# * MIT license (license terms in the root directory or at http://opensource.org/licenses/MIT).
# * Apache v2 license (license terms in the root directory or at http://www.apache.org/licenses/LICENSE-2.0).
@ -36,9 +36,6 @@ type
parked: int
signals: int
when (NimMajor,NimMinor,NimPatch) <= (1,4,0):
type AssertionDefect = AssertionError
{.push raises: [AssertionDefect].} # Ensure no exceptions can happen
{.push overflowChecks: off.} # We don't want exceptions (for Defect) in a multithreaded context
# but we don't to deal with underflow of unsigned int either

View File

@ -1,12 +0,0 @@
# Versions
## std/tasks
- https://github.com/nim-lang/Nim/blob/3619a5a2aa1c7387ec7df01b195bc683943654ff/lib/std/tasks.nim
We don't support aborting if there is a closure as this requires [#17501](https://github.com/nim-lang/Nim/pull/17501/files)
## std/isolation
- https://github.com/nim-lang/Nim/blob/603af22b7ca46ac566f8c7c15402028f3f976a4e/lib/std/isolation.nim
## std/effecttraits
- https://github.com/nim-lang/Nim/blob/603af22b7ca46ac566f8c7c15402028f3f976a4e/lib/std/effecttraits.nim

View File

@ -1,54 +0,0 @@
#
#
# Nim's Runtime Library
# (c) Copyright 2020 Nim contributors
#
# See the file "copying.txt", included in this
# distribution, for details about the copyright.
#
## This module provides access to the inferred .raises effects
## for Nim's macro system.
## **Since**: Version 1.4.
##
## One can test for the existance of this standard module
## via `defined(nimHasEffectTraitsModule)`.
import macros
proc getRaisesListImpl(n: NimNode): NimNode = discard "see compiler/vmops.nim"
proc getTagsListImpl(n: NimNode): NimNode = discard "see compiler/vmops.nim"
proc isGcSafeImpl(n: NimNode): bool = discard "see compiler/vmops.nim"
proc hasNoSideEffectsImpl(n: NimNode): bool = discard "see compiler/vmops.nim"
proc getRaisesList*(fn: NimNode): NimNode =
## Extracts the `.raises` list of the func/proc/etc `fn`.
## `fn` has to be a resolved symbol of kind `nnkSym`. This
## implies that the macro that calls this proc should accept `typed`
## arguments and not `untyped` arguments.
expectKind fn, nnkSym
result = getRaisesListImpl(fn)
proc getTagsList*(fn: NimNode): NimNode =
## Extracts the `.tags` list of the func/proc/etc `fn`.
## `fn` has to be a resolved symbol of kind `nnkSym`. This
## implies that the macro that calls this proc should accept `typed`
## arguments and not `untyped` arguments.
expectKind fn, nnkSym
result = getTagsListImpl(fn)
proc isGcSafe*(fn: NimNode): bool =
## Return true if the func/proc/etc `fn` is `gcsafe`.
## `fn` has to be a resolved symbol of kind `nnkSym`. This
## implies that the macro that calls this proc should accept `typed`
## arguments and not `untyped` arguments.
expectKind fn, nnkSym
result = isGcSafeImpl(fn)
proc hasNoSideEffects*(fn: NimNode): bool =
## Return true if the func/proc/etc `fn` has `noSideEffect`.
## `fn` has to be a resolved symbol of kind `nnkSym`. This
## implies that the macro that calls this proc should accept `typed`
## arguments and not `untyped` arguments.
expectKind fn, nnkSym
result = hasNoSideEffectsImpl(fn)

View File

@ -1,50 +0,0 @@
#
#
# Nim's Runtime Library
# (c) Copyright 2020 Nim contributors
#
# See the file "copying.txt", included in this
# distribution, for details about the copyright.
#
## This module implements the `Isolated[T]` type for
## safe construction of isolated subgraphs that can be
## passed efficiently to different channels and threads.
##
## .. warning:: This module is experimental and its interface may change.
##
type
Isolated*[T] = object ## Isolated data can only be moved, not copied.
value: T
proc `=copy`*[T](dest: var Isolated[T]; src: Isolated[T]) {.error.}
proc `=sink`*[T](dest: var Isolated[T]; src: Isolated[T]) {.inline.} =
# delegate to value's sink operation
`=sink`(dest.value, src.value)
proc `=destroy`*[T](dest: var Isolated[T]) {.inline.} =
# delegate to value's destroy operation
`=destroy`(dest.value)
# XXX: removed the {.magic: "Isolate".}
func isolate*[T](value: sink T): Isolated[T] =
## Creates an isolated subgraph from the expression `value`.
## Isolation is checked at compile time.
##
## Please read https://github.com/nim-lang/RFCs/issues/244
## for more details.
Isolated[T](value: value)
func unsafeIsolate*[T](value: sink T): Isolated[T] =
## Creates an isolated subgraph from the expression `value`.
##
## .. warning:: The proc doesn't check whether `value` is isolated.
##
Isolated[T](value: value)
func extract*[T](src: var Isolated[T]): T =
## Returns the internal value of `src`.
## The value is moved from `src`.
result = move(src.value)

View File

@ -1,290 +0,0 @@
#
#
# Nim's Runtime Library
# (c) Copyright 2021 Nim contributors
#
# See the file "copying.txt", included in this
# distribution, for details about the copyright.
#
## This module provides basic primitives for creating parallel programs.
## A `Task` should be only owned by a single Thread, it cannot be shared by threads.
import std/[macros, typetraits]
import system/ansi_c
import ./isolation
export isolation
when compileOption("threads"):
from ./effecttraits import isGcSafe
#
# proc hello(a: int, b: string) =
# echo $a & b
#
# let literal = "Nim"
# let t = toTask(hello(521, literal))
#
#
# is roughly converted to
#
# type
# ScratchObj_369098780 = object
# a: int
# b: string
#
# let scratch_369098762 = cast[ptr ScratchObj_369098780](c_calloc(csize_t 1,
# csize_t sizeof(ScratchObj_369098780)))
# if scratch_369098762.isNil:
# raise newException(OutOfMemDefect, "Could not allocate memory")
# block:
# var isolate_369098776 = isolate(521)
# scratch_369098762.a = extract(isolate_369098776)
# var isolate_369098778 = isolate(literal)
# scratch_369098762.b = extract(isolate_369098778)
# proc hello_369098781(args`gensym3: pointer) {.nimcall.} =
# let objTemp_369098775 = cast[ptr ScratchObj_369098780](args`gensym3)
# let :tmp_369098777 = objTemp_369098775.a
# let :tmp_369098779 = objTemp_369098775.b
# hello(a = :tmp_369098777, b = :tmp_369098779)
#
# proc destroyScratch_369098782(args`gensym3: pointer) {.nimcall.} =
# let obj_369098783 = cast[ptr ScratchObj_369098780](args`gensym3)
# =destroy(obj_369098783[])
# let t = Task(callback: hello_369098781, args: scratch_369098762, destroy: destroyScratch_369098782)
#
type
Task* = object ## `Task` contains the callback and its arguments.
callback: proc (args: pointer) {.nimcall, gcsafe.}
args: pointer
destroy: proc (args: pointer) {.nimcall, gcsafe.}
# XXX: ⚠️ No destructors for 1.2 due to unreliable codegen
# proc `=copy`*(x: var Task, y: Task) {.error.}
proc shim_destroy*(t: var Task) {.inline, gcsafe.} =
## Frees the resources allocated for a `Task`.
if t.args != nil:
if t.destroy != nil:
t.destroy(t.args)
c_free(t.args)
proc invoke*(task: Task) {.inline, gcsafe.} =
## Invokes the `task`.
assert task.callback != nil
task.callback(task.args)
template checkIsolate(scratchAssignList: seq[NimNode], procParam, scratchDotExpr: NimNode) =
# block:
# var isoTempA = isolate(521)
# scratch.a = extract(isolateA)
# var isoTempB = isolate(literal)
# scratch.b = extract(isolateB)
let isolatedTemp = genSym(nskTemp, "isoTemp")
# XXX: Fix sym bindings
# scratchAssignList.add newVarStmt(isolatedTemp, newCall(newidentNode("isolate"), procParam))
# scratchAssignList.add newAssignment(scratchDotExpr,
# newCall(newIdentNode("extract"), isolatedTemp))
scratchAssignList.add newVarStmt(isolatedTemp, newCall(bindSym("isolate"), procParam))
scratchAssignList.add newAssignment(scratchDotExpr,
newCall(bindSym("extract"), isolatedTemp))
template addAllNode(assignParam: NimNode, procParam: NimNode) =
let scratchDotExpr = newDotExpr(scratchIdent, formalParams[i][0])
checkIsolate(scratchAssignList, procParam, scratchDotExpr)
let tempNode = genSym(kind = nskTemp, ident = formalParams[i][0].strVal)
callNode.add nnkExprEqExpr.newTree(formalParams[i][0], tempNode)
tempAssignList.add newLetStmt(tempNode, newDotExpr(objTemp, formalParams[i][0]))
scratchRecList.add newIdentDefs(newIdentNode(formalParams[i][0].strVal), assignParam)
macro toTask*(e: typed{nkCall | nkInfix | nkPrefix | nkPostfix | nkCommand | nkCallStrLit}): Task =
## Converts the call and its arguments to `Task`.
runnableExamples("--gc:orc"):
proc hello(a: int) = echo a
let b = toTask hello(13)
assert b is Task
doAssert getTypeInst(e).typeKind == ntyVoid
# requires 1.6
# when compileOption("threads"):
# if not isGcSafe(e[0]):
# error("'toTask' takes a GC safe call expression")
# TODO
# https://github.com/nim-lang/Nim/pull/17501/files
#
# if hasClosure(e[0]):
# error("closure call is not allowed")
if e.len > 1:
let scratchIdent = genSym(kind = nskTemp, ident = "scratch")
let impl = e[0].getTypeInst
when defined(nimTasksDebug):
echo impl.treeRepr
echo e.treeRepr
let formalParams = impl[0]
var
scratchRecList = newNimNode(nnkRecList)
scratchAssignList: seq[NimNode]
tempAssignList: seq[NimNode]
callNode: seq[NimNode]
let
objTemp = genSym(nskTemp, ident = "objTemp")
for i in 1 ..< formalParams.len:
var param = formalParams[i][1]
if param.kind == nnkBracketExpr and param[0].eqIdent("sink"):
param = param[0]
if param.typeKind in {ntyExpr, ntyStmt}:
error("'toTask'ed function cannot have a 'typed' or 'untyped' parameter")
case param.kind
of nnkVarTy:
error("'toTask'ed function cannot have a 'var' parameter")
of nnkBracketExpr:
if param[0].typeKind == ntyTypeDesc:
callNode.add nnkExprEqExpr.newTree(formalParams[i][0], e[i])
elif param[0].typeKind in {ntyVarargs, ntyOpenArray}:
if param[1].typeKind in {ntyExpr, ntyStmt}:
error("'toTask'ed function cannot have a 'typed' or 'untyped' parameter")
let
seqType = nnkBracketExpr.newTree(newIdentNode("seq"), param[1])
seqCallNode = newCall("@", e[i])
addAllNode(seqType, seqCallNode)
else:
addAllNode(param, e[i])
of nnkBracket, nnkObjConstr:
# passing by static parameters
# so we pass them directly instead of passing by scratchObj
callNode.add nnkExprEqExpr.newTree(formalParams[i][0], e[i])
of nnkSym, nnkPtrTy:
addAllNode(param, e[i])
of nnkCharLit..nnkNilLit:
callNode.add nnkExprEqExpr.newTree(formalParams[i][0], e[i])
else:
error("not supported type kinds")
let scratchObjType = genSym(kind = nskType, ident = "ScratchObj")
let scratchObj = nnkTypeSection.newTree(
nnkTypeDef.newTree(
scratchObjType,
newEmptyNode(),
nnkObjectTy.newTree(
newEmptyNode(),
newEmptyNode(),
scratchRecList
)
)
)
let scratchObjPtrType = quote do:
cast[ptr `scratchObjType`](c_calloc(csize_t 1, csize_t sizeof(`scratchObjType`)))
let scratchLetSection = newLetStmt(
scratchIdent,
scratchObjPtrType
)
let scratchCheck = quote do:
if `scratchIdent`.isNil:
# Renamed in 1.4
# raise newException(OutOfMemDefect, "Could not allocate memory")
raise newException(OutOfMemError, "Could not allocate memory")
var stmtList = newStmtList()
stmtList.add(scratchObj)
stmtList.add(scratchLetSection)
stmtList.add(scratchCheck)
stmtList.add(nnkBlockStmt.newTree(newEmptyNode(), newStmtList(scratchAssignList)))
var functionStmtList = newStmtList()
let funcCall = newCall(e[0], callNode)
functionStmtList.add tempAssignList
functionStmtList.add funcCall
let funcName = genSym(nskProc, e[0].strVal)
let destroyName = genSym(nskProc, "destroyScratch")
let objTemp2 = genSym(ident = "obj")
let tempNode = quote("@") do:
# XXX:
# We avoid destructors for Nim 1.2 due to bad codegen
# For taskpool there are no destructor to run.
# We ensure that by checking that we only operate on plain old data
static: doAssert supportsCopyMem(@scratchObjType)
# `=destroy`(@objTemp2[])
result = quote do:
`stmtList`
proc `funcName`(args: pointer) {.gcsafe, nimcall.} =
let `objTemp` = cast[ptr `scratchObjType`](args)
`functionStmtList`
proc `destroyName`(args: pointer) {.nimcall.} =
let `objTemp2` = cast[ptr `scratchObjType`](args)
`tempNode`
Task(callback: `funcName`, args: `scratchIdent`, destroy: `destroyName`)
else:
let funcCall = newCall(e[0])
let funcName = genSym(nskProc, e[0].strVal)
result = quote do:
proc `funcName`(args: pointer) {.gcsafe, nimcall.} =
`funcCall`
Task(callback: `funcName`, args: nil)
when defined(nimTasksDebug):
echo result.repr
runnableExamples("--gc:orc"):
block:
var num = 0
proc hello(a: int) = inc num, a
let b = toTask hello(13)
b.invoke()
assert num == 13
# A task can be invoked multiple times
b.invoke()
assert num == 26
block:
type
Runnable = ref object
data: int
var data: int
proc hello(a: Runnable) {.nimcall.} =
a.data += 2
data = a.data
when false:
# the parameters of call must be isolated.
let x = Runnable(data: 12)
let b = toTask hello(x) # error ----> expression cannot be isolated: x
b.invoke()
let b = toTask(hello(Runnable(data: 12)))
b.invoke()
assert data == 14
b.invoke()
assert data == 16

View File

@ -35,9 +35,6 @@
# In case a thread is blocked for IO, other threads can steal pending tasks in that thread.
# If all threads are pending for IO, the threadpool will not make any progress and be soft-locked.
when (NimMajor,NimMinor,NimPatch) <= (1,4,0):
type AssertionDefect = AssertionError
{.push raises: [AssertionDefect].} # Ensure no exceptions can happen
import
@ -56,11 +53,8 @@ export
# flowvars
Flowvar, isSpawned, isReady, sync
when (NimMajor,NimMinor,NimPatch) >= (1,6,0):
import std/[isolation, tasks]
export isolation
else:
import ./shims_pre_1_6/tasks
import std/[isolation, tasks]
export isolation
type
WorkerID = int32
@ -191,11 +185,8 @@ proc new(T: type TaskNode, parent: TaskNode, task: sink Task): T =
proc runTask(tn: var TaskNode) {.raises:[Exception], inline.} =
## Run a task and consumes the taskNode
tn.task.invoke()
when (NimMajor,NimMinor,NimPatch) >= (1,6,0):
{.gcsafe.}: # Upstream missing tagging `=destroy` as gcsafe
tn.task.`=destroy`()
else:
tn.task.shim_destroy()
{.gcsafe.}: # Upstream missing tagging `=destroy` as gcsafe
tn.task.`=destroy`()
tn.c_free()
proc schedule(ctx: WorkerContext, tn: sink TaskNode) {.inline.} =