Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

exception tracking #166

Merged
merged 5 commits into from
Mar 24, 2021
Merged
Show file tree
Hide file tree
Changes from 4 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
43 changes: 39 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ Chronos is an efficient [async/await](https://en.wikipedia.org/wiki/Async/await)
* Cancellation support
* Synchronization primitivies like queues, events and locks
* FIFO processing order of dispatch queue
* Minimal exception effect support (see [exception effects](#exception-effects))

## Installation

Expand Down Expand Up @@ -198,15 +199,49 @@ proc p3() {.async.} =
fut2 = p2()
try:
await fut1
except:
except CachableError:
echo "p1() failed: ", fut1.error.name, ": ", fut1.error.msg
echo "reachable code here"
await fut2
```

Exceptions inheriting from `Defect` are treated differently, being raised
directly. Don't try to catch them coming out of `poll()`, because this would
leave behind some zombie futures.
Chronos does not allow that future continuations and other callbacks raise
`CatchableError` - as such, calls to `poll` will never raise exceptions caused
originating from tasks on the dispatcher queue. It is however possible that
`Defect` that happen in tasks bubble up through `poll` as these are not caught
by the transformation.

### Platform independence

Several functions in `chronos` are backed by the operating system, such as
waiting for network events, creating files and sockets etc. The specific
exceptions that are raised by the OS is platform-dependent, thus such functions
are declared as raising `CatchableError` but will in general raise something
more specific. In particular, it's possible that some functions that are
annotated as raising `CatchableError` only raise on _some_ platforms - in order
to work on all platforms, calling code must assume that they will raise even
when they don't seem to do so on one platform.

### Exception effects

`chronos` currently offers minimal support for exception effects and `raises`
annotations. In general, during the `async` transformation, a generic
`except CatchableError` handler is added around the entire function being
transformed, in order to catch any exceptions and transfer them to the `Future`.
Because of this, the effect system thinks no exceptions are "leaking" because in
fact, exception _handling_ is deferred to when the future is being read.

Effectively, this means that while code can be compiled with
`{.push raises: [Defect]}`, the intended effect propagation and checking is
**disabled** for `async` functions.

To enable checking exception effects in `async` code, enable strict mode with
`-d:chronosStrictException`.

In the strict mode, `async` functions are checked such that they only raise
`CatchableError` and thus must make sure to explicitly specify exception
effects on forward declarations, callbacks and methods using
`{.raises: [CatchableError].}` (or more strict) annotations.

## TODO
* Pipe/Subprocess Transports.
Expand Down
7 changes: 4 additions & 3 deletions chronos.nimble
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
packageName = "chronos"
version = "2.6.1"
version = "3.0.0"
author = "Status Research & Development GmbH"
description = "Chronos"
license = "Apache License 2.0 or MIT"
Expand All @@ -10,12 +10,13 @@ skipDirs = @["tests"]
requires "nim > 1.2.0",
"stew",
"bearssl",
"httputils"
"httputils",
"https://github.com/status-im/nim-unittest2.git#head"

task test, "Run all tests":
var commands = @[
"nim c -r -d:useSysAssert -d:useGcAssert tests/",
"nim c -r -d:chronosStackTrace tests/",
"nim c -r -d:chronosStackTrace -d:chronosStrictException tests/",
"nim c -r -d:release tests/",
"nim c -r -d:release -d:chronosFutureTracking tests/"
]
Expand Down
2 changes: 1 addition & 1 deletion chronos/apps.nim
Original file line number Diff line number Diff line change
Expand Up @@ -6,5 +6,5 @@
# Licensed under either of
# Apache License, version 2.0, (LICENSE-APACHEv2)
# MIT license (LICENSE-MIT)
import apps/http/httpserver, apps/http/shttpserver
import ./apps/http/[httpserver, shttpserver]
export httpserver, shttpserver
5 changes: 3 additions & 2 deletions chronos/apps/http/httpserver.nim
Original file line number Diff line number Diff line change
Expand Up @@ -44,11 +44,12 @@ type
Empty, Prepared, Sending, Finished, Failed, Cancelled, Dumb

HttpProcessCallback* =
proc(req: RequestFence): Future[HttpResponseRef] {.gcsafe.}
proc(req: RequestFence): Future[HttpResponseRef] {.
gcsafe, raises: [Defect, CatchableError].}

HttpConnectionCallback* =
proc(server: HttpServerRef,
transp: StreamTransport): Future[HttpConnectionRef] {.gcsafe.}
transp: StreamTransport): Future[HttpConnectionRef] {.gcsafe, raises: [Defect].}

HttpServer* = object of RootObj
instance*: StreamServer
Expand Down
Loading