-
-
Notifications
You must be signed in to change notification settings - Fork 1.5k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
[Backport] Fixes callbacks being dropped on Linux/macOS/BSD.
Fixes #15003. This is a serious bug which occurs when data cannot be read/sent immediately and there are a bunch of other read/write events pending. What happens is that the new events are dropped which results in the case of the reported bug resulted in some data not being sent (!).
- Loading branch information
Showing
2 changed files
with
73 additions
and
1 deletion.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,67 @@ | ||
discard """ | ||
disabled: "windows" | ||
exitcode: 0 | ||
""" | ||
# AsyncSocketBug.nim | ||
# Jens Alfke (@snej) -- 16 July 2020 | ||
# Demonstrates data loss by Nim's AsyncSocket. | ||
# Just run it, and it will raise an assertion failure within a minute. | ||
|
||
import asyncdispatch, asyncnet, strformat, strutils, sugar | ||
|
||
const FrameSize = 9999 # Exact size not important, but larger sizes fail quicker | ||
|
||
proc runServer() {.async.} = | ||
# Server side: | ||
var server = newAsyncSocket() | ||
server.bindAddr(Port(9001)) | ||
server.listen() | ||
let client = await server.accept() | ||
echo "Server got client connection" | ||
var lastN = 0 | ||
while true: | ||
let frame = await client.recv(FrameSize) | ||
assert frame.len == FrameSize | ||
let n = frame[0..<6].parseInt() | ||
echo "RCVD #", n, ": ", frame[0..80], "..." | ||
if n != lastN + 1: | ||
echo &"******** ERROR: Server received #{n}, but last was #{lastN}!" | ||
assert n == lastN + 1 | ||
lastN = n | ||
await sleepAsync 100 | ||
|
||
|
||
proc main() {.async.} = | ||
asyncCheck runServer() | ||
|
||
# Client side: | ||
let socket = newAsyncSocket(buffered = false) | ||
await socket.connect("localhost", Port(9001)) | ||
echo "Client socket connected" | ||
|
||
var sentCount = 0 | ||
var completedCount = 0 | ||
|
||
while sentCount < 2000: | ||
sentCount += 1 | ||
let n = sentCount | ||
|
||
var message = &"{n:06} This is message #{n} of ∞. Please stay tuned for more. " | ||
#echo ">>> ", message | ||
while message.len < FrameSize: | ||
message = message & message | ||
let frame = message[0..<FrameSize] | ||
|
||
capture n: | ||
socket.send(frame).addCallback proc(f: Future[void]) = | ||
# Callback when the send completes: | ||
assert not f.failed | ||
echo "SENT #", n | ||
if n != completedCount + 1: | ||
echo &"******** ERROR: Client completed #{n}, but last completed was #{completedCount}!" | ||
# If this assert is enabled, it will trigger earlier than the server-side assert above: | ||
assert n == completedCount + 1 | ||
completedCount = n | ||
await sleepAsync 1 | ||
|
||
waitFor main() |