Skip to content

Commit 491ddff

Browse files
committed
Add AsyncSemaphore tests.
1 parent 3f06465 commit 491ddff

File tree

2 files changed

+109
-26
lines changed

2 files changed

+109
-26
lines changed

chronos/asyncsync.nim

Lines changed: 16 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -207,21 +207,27 @@ proc isSet*(event: AsyncEvent): bool =
207207
## Return `true` if and only if the internal flag of ``event`` is `true`.
208208
event.flag
209209

210+
proc wakeupNext(waiters: var seq[Future[void]]) {.inline.} =
211+
var i = 0
212+
while i < len(waiters):
213+
var waiter = waiters[i]
214+
inc(i)
215+
216+
if not(waiter.finished()):
217+
waiter.complete()
218+
break
219+
220+
if i > 0:
221+
waiters.delete(0, i - 1)
222+
210223
proc newAsyncSemaphore*(value: int = 1): AsyncSemaphore =
211224
## Creates a new asynchronous bounded semaphore ``AsyncSemaphore`` with
212225
## internal counter set to ``value``.
213-
doAssert(value < 0, "AsyncSemaphore initial value must be bigger or equal 0")
226+
doAssert(value >= 0, "AsyncSemaphore initial value must be bigger or equal 0")
214227
discard getThreadDispatcher()
215228
AsyncSemaphore(waiters: newSeq[Future[void]](), counter: value,
216229
maxcounter: value)
217230

218-
proc wakeupNext(asem: AsyncSemaphore) {.inline.} =
219-
while len(asem.waiters) > 0:
220-
let waiter = asem.waiters.pop()
221-
if not(waiter.finished()):
222-
waiter.complete()
223-
return
224-
225231
proc locked*(asem: AsyncSemaphore): bool =
226232
## Returns ``true`` if semaphore can not be acquired immediately
227233
(asem.counter == 0)
@@ -239,7 +245,7 @@ proc acquire*(asem: AsyncSemaphore) {.async.} =
239245
await waiter
240246
except CatchableError as exc:
241247
if asem.counter > 0 and not(waiter.cancelled()):
242-
asem.wakeupNext()
248+
asem.waiters.wakeupNext()
243249
raise exc
244250
dec(asem.counter)
245251

@@ -248,7 +254,7 @@ proc release*(asem: AsyncSemaphore) =
248254
if asem.counter >= asem.maxcounter:
249255
raiseAssert("AsyncSemaphore released too many times")
250256
inc(asem.counter)
251-
asem.wakeupNext()
257+
asem.waiters.wakeupNext()
252258

253259
proc newAsyncQueue*[T](maxsize: int = 0): AsyncQueue[T] =
254260
## Creates a new asynchronous queue ``AsyncQueue``.
@@ -279,19 +285,6 @@ proc newAsyncPriorityQueue*[T](maxsize: int = 0): AsyncPriorityQueue[T] =
279285
maxsize: maxsize
280286
)
281287

282-
proc wakeupNext(waiters: var seq[Future[void]]) {.inline.} =
283-
var i = 0
284-
while i < len(waiters):
285-
var waiter = waiters[i]
286-
inc(i)
287-
288-
if not(waiter.finished()):
289-
waiter.complete()
290-
break
291-
292-
if i > 0:
293-
waiters.delete(0, i - 1)
294-
295288
proc full*[T](aq: AsyncQueue[T] | AsyncPriorityQueue[T]): bool {.inline.} =
296289
## Return ``true`` if there are ``maxsize`` items in the queue.
297290
##

tests/testsync.nim

Lines changed: 93 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@ suite "Asynchronous sync primitives test suite":
3737
discard testLock(9, lock)
3838
lock.release()
3939
## There must be exactly 20 poll() calls
40-
for i in 0..<20:
40+
for i in 0 ..< 20:
4141
poll()
4242
result = testLockResult
4343

@@ -344,13 +344,97 @@ suite "Asynchronous sync primitives test suite":
344344
var queue1 = newAsyncPriorityQueue[int](10)
345345
var queue2 = newAsyncPriorityQueue[int](1)
346346

347-
var fut1 = task2(queue1)
347+
discard task2(queue1)
348348
let r1 = waitFor task1(queue1)
349-
var fut2 = task2(queue2)
349+
discard task2(queue2)
350350
let r2 = waitFor task1(queue2)
351351

352352
return r1 == "0123456789" and r2 == "6593482107"
353353

354+
proc testAsyncSemaphoreBehavior(): bool =
355+
var res = ""
356+
357+
proc testSemaphore(n: int, sem: AsyncSemaphore) {.async.} =
358+
await sem.acquire()
359+
res = res & $n
360+
sem.release()
361+
362+
proc test(): Future[string] {.async.} =
363+
var sem = newAsyncSemaphore()
364+
await sem.acquire()
365+
discard testSemaphore(0, sem)
366+
discard testSemaphore(1, sem)
367+
discard testSemaphore(2, sem)
368+
discard testSemaphore(3, sem)
369+
discard testSemaphore(4, sem)
370+
discard testSemaphore(5, sem)
371+
discard testSemaphore(6, sem)
372+
discard testSemaphore(7, sem)
373+
discard testSemaphore(8, sem)
374+
discard testSemaphore(9, sem)
375+
sem.release()
376+
for i in 0 ..< 20:
377+
poll()
378+
return res
379+
380+
return waitFor(test()) == "0123456789"
381+
382+
proc testAsyncSemaphoreDoubleRelease(): bool =
383+
var res = ""
384+
385+
proc testSemaphore(n: int, sem: AsyncSemaphore) {.async.} =
386+
await sem.acquire()
387+
res = res & $n
388+
sem.release()
389+
390+
proc test(): Future[bool] {.async.} =
391+
var sem = newAsyncSemaphore()
392+
await sem.acquire()
393+
var fut1 = testSemaphore(0, sem)
394+
sem.release()
395+
await sem.acquire()
396+
await sleepAsync(50.milliseconds)
397+
if fut1.finished() == true:
398+
return false
399+
sem.release()
400+
await sleepAsync(50.milliseconds)
401+
if fut1.finished() == false:
402+
return false
403+
return res == "0"
404+
405+
return waitFor(test())
406+
407+
proc testAsyncSemaphoreCounter(): bool =
408+
var res = ""
409+
410+
proc testSemaphore(n: int, sem: AsyncSemaphore) {.async.} =
411+
await sem.acquire()
412+
res = res & $n
413+
414+
proc test(): Future[bool] {.async.} =
415+
var sem = newAsyncSemaphore(3)
416+
discard testSemaphore(0, sem)
417+
discard testSemaphore(1, sem)
418+
discard testSemaphore(2, sem)
419+
discard testSemaphore(3, sem)
420+
discard testSemaphore(4, sem)
421+
discard testSemaphore(5, sem)
422+
await sleepAsync(50.milliseconds)
423+
if res != "012":
424+
return false
425+
sem.release()
426+
await sleepAsync(50.milliseconds)
427+
if res != "0123":
428+
return false
429+
sem.release()
430+
sem.release()
431+
await sleepAsync(50.milliseconds)
432+
if res != "012345":
433+
return false
434+
return true
435+
436+
return waitFor(test())
437+
354438
test "AsyncLock() behavior test":
355439
check:
356440
test1() == "0123456789"
@@ -392,3 +476,9 @@ suite "Asynchronous sync primitives test suite":
392476
check testPriorityBehavior() == 3000
393477
test "AsyncPriorityQueue() priority test":
394478
check testPriorityQueue() == true
479+
test "AsyncSemaphore() behavior test":
480+
check testAsyncSemaphoreBehavior() == true
481+
test "AsyncSemaphore() double release test":
482+
check testAsyncSemaphoreDoubleRelease() == true
483+
test "AsyncSemaphore() counter test":
484+
check testAsyncSemaphoreCounter() == true

0 commit comments

Comments
 (0)