Skip to content

Commit

Permalink
Merge pull request #62 from guzba/master
Browse files Browse the repository at this point in the history
1.5.3 lower nim req + nim version github actions
  • Loading branch information
treeform authored Jan 29, 2022
2 parents 7d9590a + dac5f09 commit 4cf63e0
Show file tree
Hide file tree
Showing 5 changed files with 228 additions and 217 deletions.
8 changes: 8 additions & 0 deletions .github/workflows/build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -6,12 +6,20 @@ jobs:
fail-fast: false
matrix:
os: [ubuntu-latest, windows-latest, macos-latest]
nim-version: ['1.2.2', '1.2.x', '1.4.x', 'stable']
include:
- nim-version: '1.4.x'
gc_orc: true
- nim-version: 'stable'
gc_orc: true

runs-on: ${{ matrix.os }}

steps:
- uses: actions/checkout@v2
- uses: jiro4989/setup-nim-action@v1
with:
nim-version: ${{ matrix.nim-version }}

- run: nimble install -y libcurl
- run: nimble install -y zippy
Expand Down
4 changes: 2 additions & 2 deletions puppy.nimble
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
version = "1.5.2"
version = "1.5.3"
author = "Andre von Houck"
description = "Puppy fetches HTML pages for Nim."
license = "MIT"

srcDir = "src"

requires "nim >= 1.4.4"
requires "nim >= 1.2.2"
requires "urlly >= 0.2.0"
requires "libcurl >= 1.0.0"
requires "zippy >= 0.7.3"
245 changes: 123 additions & 122 deletions src/puppy/requestpools.nim
Original file line number Diff line number Diff line change
@@ -1,144 +1,145 @@
import puppy, std/locks, std/deques

when not defined(gcArc):
{.error: "Please use --gc:arc when using Puppy request pools.".}

type
RequestPoolObj = object
lock: Lock
cond: Cond
threads: seq[Thread[ptr RequestPoolObj]]
queue: Deque[ResponseHandle]
closed: bool
requestsCompleted: bool

RequestPool* = ref RequestPoolObj

ResponseHandleInternal = object
lock: Lock
request: Request
response: Response
error: ref PuppyError
refCount: int

ResponseHandle* = object
internal: ptr ResponseHandleInternal

proc free(internal: ptr ResponseHandleInternal) =
deinitLock(internal.lock)
internal.request = nil
internal.response = nil
internal.error = nil
dealloc(internal)

proc `=destroy`*(handle: var ResponseHandle) =
if handle.internal != nil:
acquire(handle.internal.lock)
if handle.internal.refCount == 0:
release(handle.internal.lock)
free handle.internal
else:
dec handle.internal.refCount
release(handle.internal.lock)
when (NimMajor, NimMinor, NimPatch) >= (1, 6, 0):
import puppy, std/locks, std/deques

when not defined(gcArc):
{.error: "Please use --gc:arc when using Puppy request pools.".}

type
RequestPoolObj = object
lock: Lock
cond: Cond
threads: seq[Thread[ptr RequestPoolObj]]
queue: Deque[ResponseHandle]
closed: bool
requestsCompleted: bool

RequestPool* = ref RequestPoolObj

ResponseHandleInternal = object
lock: Lock
request: Request
response: Response
error: ref PuppyError
refCount: int

ResponseHandle* = object
internal: ptr ResponseHandleInternal

proc free(internal: ptr ResponseHandleInternal) =
deinitLock(internal.lock)
internal.request = nil
internal.response = nil
internal.error = nil
dealloc(internal)

proc `=destroy`*(handle: var ResponseHandle) =
if handle.internal != nil:
acquire(handle.internal.lock)
if handle.internal.refCount == 0:
release(handle.internal.lock)
free handle.internal
else:
dec handle.internal.refCount
release(handle.internal.lock)

proc `=`*(dst: var ResponseHandle, src: ResponseHandle) =
if src.internal != nil:
acquire(src.internal.lock)
inc src.internal.refCount
release(src.internal.lock)

if dst.internal != nil:
`=destroy`(dst)

dst.internal = src.internal

proc `=destroy`*(pool: var RequestPoolObj) =
acquire(pool.lock)
pool.closed = true
release(pool.lock)

proc `=`*(dst: var ResponseHandle, src: ResponseHandle) =
if src.internal != nil:
acquire(src.internal.lock)
inc src.internal.refCount
release(src.internal.lock)
broadcast(pool.cond)

if dst.internal != nil:
`=destroy`(dst)
joinThreads(pool.threads)

dst.internal = src.internal
deinitLock(pool.lock)
deinitCond(pool.cond)
`=destroy`(pool.threads)
`=destroy`(pool.queue)

proc `=destroy`*(pool: var RequestPoolObj) =
acquire(pool.lock)
pool.closed = true
release(pool.lock)
proc ready*(handle: ResponseHandle): bool =
acquire(handle.internal.lock)
result = handle.internal.response != nil
release(handle.internal.lock)

broadcast(pool.cond)
proc response*(handle: ResponseHandle): Response =
var error: ref PuppyError

joinThreads(pool.threads)
acquire(handle.internal.lock)
result = handle.internal.response
error = handle.internal.error
release(handle.internal.lock)

deinitLock(pool.lock)
deinitCond(pool.cond)
`=destroy`(pool.threads)
`=destroy`(pool.queue)
if error != nil:
raise error

proc ready*(handle: ResponseHandle): bool =
acquire(handle.internal.lock)
result = handle.internal.response != nil
release(handle.internal.lock)
proc workerProc(pool: ptr RequestPoolObj) {.raises: [].} =
while true:
acquire(pool.lock)

proc response*(handle: ResponseHandle): Response =
var error: ref PuppyError
while pool.queue.len == 0 and not pool.closed:
wait(pool.cond, pool.lock)

acquire(handle.internal.lock)
result = handle.internal.response
error = handle.internal.error
release(handle.internal.lock)
if pool.closed:
release(pool.lock)
break

if error != nil:
raise error
let handle = pool.queue.popFirst()

proc workerProc(pool: ptr RequestPoolObj) {.raises: [].} =
while true:
acquire(pool.lock)
release(pool.lock)

while pool.queue.len == 0 and not pool.closed:
wait(pool.cond, pool.lock)
var
response: Response
error: ref PuppyError
try:
response = fetch(handle.internal.request)
except PuppyError as e:
error = e

acquire(handle.internal.lock)
handle.internal.response = response
handle.internal.error = error
release(handle.internal.lock)

if pool.closed:
acquire(pool.lock)
pool.requestsCompleted = true
release(pool.lock)
break

let handle = pool.queue.popFirst()
proc newRequestPool*(maxInFlight: int): RequestPool =
result = RequestPool()
initLock(result.lock)
initCond(result.cond)
result.threads.setLen(maxInFlight)
for thread in result.threads.mitems:
createThread(thread, workerProc, cast[ptr RequestPoolObj](result))

proc fetch*(pool: RequestPool, request: Request): ResponseHandle =
result.internal = cast[ptr ResponseHandleInternal](
alloc0(sizeof(ResponseHandleInternal))
)
initLock(result.internal.lock)
result.internal.request = request

acquire(pool.lock)
pool.queue.addLast(result)
release(pool.lock)

var
response: Response
error: ref PuppyError
try:
response = fetch(handle.internal.request)
except PuppyError as e:
error = e

acquire(handle.internal.lock)
handle.internal.response = response
handle.internal.error = error
release(handle.internal.lock)
signal(pool.cond)

proc requestsCompleted*(pool: RequestPool): bool =
## Returns whether or not at least one request has completed since the last
## time this proc was called.
acquire(pool.lock)
pool.requestsCompleted = true
result = pool.requestsCompleted
pool.requestsCompleted = false
release(pool.lock)

proc newRequestPool*(maxInFlight: int): RequestPool =
result = RequestPool()
initLock(result.lock)
initCond(result.cond)
result.threads.setLen(maxInFlight)
for thread in result.threads.mitems:
createThread(thread, workerProc, cast[ptr RequestPoolObj](result))

proc fetch*(pool: RequestPool, request: Request): ResponseHandle =
result.internal = cast[ptr ResponseHandleInternal](
alloc0(sizeof(ResponseHandleInternal))
)
initLock(result.internal.lock)
result.internal.request = request

acquire(pool.lock)
pool.queue.addLast(result)
release(pool.lock)

signal(pool.cond)

proc requestsCompleted*(pool: RequestPool): bool =
## Returns whether or not at least one request has completed since the last
## time this proc was called.
acquire(pool.lock)
result = pool.requestsCompleted
pool.requestsCompleted = false
release(pool.lock)
Loading

0 comments on commit 4cf63e0

Please sign in to comment.