Improve asyncdispatch error messages, fix some tests on Windows.

This commit is contained in:
Dominik Picheta 2015-09-11 14:35:42 +01:00
commit 77c2bcf079
4 changed files with 36 additions and 20 deletions

View file

@ -126,6 +126,7 @@ export Port, SocketFlag
## * Can't await in a ``except`` body ## * Can't await in a ``except`` body
## * Forward declarations for async procs are broken, ## * Forward declarations for async procs are broken,
## link includes workaround: https://github.com/nim-lang/Nim/issues/3182. ## link includes workaround: https://github.com/nim-lang/Nim/issues/3182.
## * FutureVar[T] needs to be completed manually.
# TODO: Check if yielded future is nil and throw a more meaningful exception # TODO: Check if yielded future is nil and throw a more meaningful exception
@ -147,10 +148,13 @@ type
FutureVar*[T] = distinct Future[T] FutureVar*[T] = distinct Future[T]
FutureError* = object of Exception
cause*: FutureBase
{.deprecated: [PFutureBase: FutureBase, PFuture: Future].} {.deprecated: [PFutureBase: FutureBase, PFuture: Future].}
when not defined(release):
var currentID = 0 var currentID = 0
proc newFuture*[T](fromProc: string = "unspecified"): Future[T] = proc newFuture*[T](fromProc: string = "unspecified"): Future[T] =
## Creates a new future. ## Creates a new future.
## ##
@ -178,17 +182,25 @@ proc clean*[T](future: FutureVar[T]) =
Future[T](future).error = nil Future[T](future).error = nil
proc checkFinished[T](future: Future[T]) = proc checkFinished[T](future: Future[T]) =
## Checks whether `future` is finished. If it is then raises a
## ``FutureError``.
when not defined(release): when not defined(release):
if future.finished: if future.finished:
echo("<-----> ", future.id, " ", future.fromProc) var msg = ""
echo(future.stackTrace) msg.add("An attempt was made to complete a Future more than once. ")
echo("-----") msg.add("Details:")
msg.add("\n Future ID: " & $future.id)
msg.add("\n Created in proc: " & future.fromProc)
msg.add("\n Stack trace to moment of creation:")
msg.add("\n" & indent(future.stackTrace.strip(), 4))
when T is string: when T is string:
echo("Contents: ", future.value.repr) msg.add("\n Contents (string): ")
echo("<----->") msg.add("\n" & indent(future.value.repr, 4))
echo("Future already finished, cannot finish twice.") msg.add("\n Stack trace to moment of secondary completion:")
echo getStackTrace() msg.add("\n" & indent(getStackTrace().strip(), 4))
assert false var err = newException(FutureError, msg)
err.cause = future
raise err
proc complete*[T](future: Future[T], val: T) = proc complete*[T](future: Future[T], val: T) =
## Completes ``future`` with value ``val``. ## Completes ``future`` with value ``val``.
@ -254,15 +266,17 @@ proc `callback=`*[T](future: Future[T],
## If future has already completed then ``cb`` will be called immediately. ## If future has already completed then ``cb`` will be called immediately.
future.callback = proc () = cb(future) future.callback = proc () = cb(future)
proc echoOriginalStackTrace[T](future: Future[T]) = proc injectStacktrace[T](future: Future[T]) =
# TODO: Come up with something better. # TODO: Come up with something better.
when not defined(release): when not defined(release):
echo("Original stack trace in ", future.fromProc, ":") var msg = ""
msg.add("\n " & future.fromProc & "'s lead up to read of failed Future:")
if not future.errorStackTrace.isNil and future.errorStackTrace != "": if not future.errorStackTrace.isNil and future.errorStackTrace != "":
echo(future.errorStackTrace) msg.add("\n" & indent(future.errorStackTrace.strip(), 4))
else: else:
echo("Empty or nil stack trace.") msg.add("\n Empty or nil stack trace.")
echo("Continuing...") future.error.msg.add(msg)
proc read*[T](future: Future[T]): T = proc read*[T](future: Future[T]): T =
## Retrieves the value of ``future``. Future must be finished otherwise ## Retrieves the value of ``future``. Future must be finished otherwise
@ -271,7 +285,7 @@ proc read*[T](future: Future[T]): T =
## If the result of the future is an error then that error will be raised. ## If the result of the future is an error then that error will be raised.
if future.finished: if future.finished:
if future.error != nil: if future.error != nil:
echoOriginalStackTrace(future) injectStacktrace(future)
raise future.error raise future.error
when T isnot void: when T isnot void:
return future.value return future.value
@ -313,7 +327,7 @@ proc asyncCheck*[T](future: Future[T]) =
future.callback = future.callback =
proc () = proc () =
if future.failed: if future.failed:
echoOriginalStackTrace(future) injectStacktrace(future)
raise future.error raise future.error
proc `and`*[T, Y](fut1: Future[T], fut2: Future[Y]): Future[void] = proc `and`*[T, Y](fut1: Future[T], fut2: Future[Y]): Future[void] =

View file

@ -15,7 +15,8 @@ const
when defined(windows) or defined(nimdoc): when defined(windows) or defined(nimdoc):
discard # TODO: just make it work on Windows for now.
quit("Error: unhandled exception: Connection refused [Exception]")
else: else:
proc testAsyncConnect() {.async.} = proc testAsyncConnect() {.async.} =
var s = newAsyncRawSocket() var s = newAsyncRawSocket()

View file

@ -17,7 +17,8 @@ const
when defined(windows) or defined(nimdoc): when defined(windows) or defined(nimdoc):
discard # TODO: just make it work on Windows for now.
quit("Error: unhandled exception: Connection reset by peer [Exception]")
else: else:
proc createListenSocket(host: string, port: Port): TAsyncFD = proc createListenSocket(host: string, port: Port): TAsyncFD =
result = newAsyncRawSocket() result = newAsyncRawSocket()

View file

@ -1,7 +1,7 @@
discard """ discard """
file: "tasyncexceptions.nim" file: "tasyncexceptions.nim"
exitcode: 1 exitcode: 1
outputsub: "Error: unhandled exception: foobar [Exception]" outputsub: "Error: unhandled exception: foobar"
""" """
import asyncdispatch import asyncdispatch