Add threading support to LoadableResource
.
This commit is contained in:
parent
e748831f3a
commit
78cafe6566
|
@ -58,12 +58,14 @@ type LoadableResource* = ref object of RootObj
|
||||||
done_func: proc()
|
done_func: proc()
|
||||||
cancel_func: proc()
|
cancel_func: proc()
|
||||||
str*: proc(): string
|
str*: proc(): string
|
||||||
|
use_threads: bool
|
||||||
result: ref Result # only to be used with loadAll
|
result: ref Result # only to be used with loadAll
|
||||||
|
|
||||||
proc newLoadableResource*[T: LoadableResource](
|
proc newLoadableResource*[T: LoadableResource](
|
||||||
start: proc(self: LoadableResource),
|
start: proc(self: LoadableResource),
|
||||||
done: proc() = nil,
|
done: proc() = nil,
|
||||||
str: proc(): string = nil,
|
str: proc(): string = nil,
|
||||||
|
use_threads = false,
|
||||||
): T =
|
): T =
|
||||||
new(result)
|
new(result)
|
||||||
result.start_func = start
|
result.start_func = start
|
||||||
|
@ -71,10 +73,28 @@ proc newLoadableResource*[T: LoadableResource](
|
||||||
result.str = str
|
result.str = str
|
||||||
if str == nil:
|
if str == nil:
|
||||||
result.str = proc(): string = ""
|
result.str = proc(): string = ""
|
||||||
|
result.use_threads = use_threads
|
||||||
|
|
||||||
|
# main -> thread channels
|
||||||
|
var to_start: Channel[LoadableResource]
|
||||||
|
# main <- thread channels
|
||||||
|
var to_return: Channel[(LoadableResource, bool, string, pointer, int)]
|
||||||
|
var to_done: Channel[LoadableResource]
|
||||||
|
|
||||||
proc start*[T: LoadableResource](self: T) =
|
proc start*[T: LoadableResource](self: T) =
|
||||||
self.status = Started
|
self.status = Started
|
||||||
self.start_func(self)
|
if self.use_threads:
|
||||||
|
to_start.send self
|
||||||
|
else:
|
||||||
|
self.start_func(self)
|
||||||
|
|
||||||
|
proc doneImpl*[T: LoadableResource](self: T) =
|
||||||
|
if self.status == Started:
|
||||||
|
self.cancel()
|
||||||
|
else:
|
||||||
|
self.status = NotStarted
|
||||||
|
if self.done_func != nil:
|
||||||
|
self.done_func()
|
||||||
|
|
||||||
proc `onload=`*[T: LoadableResource](self: T, onload_func: proc(ok: bool, err: string, p: pointer, len: int)) =
|
proc `onload=`*[T: LoadableResource](self: T, onload_func: proc(ok: bool, err: string, p: pointer, len: int)) =
|
||||||
self.onload_func = onload_func
|
self.onload_func = onload_func
|
||||||
|
@ -85,25 +105,24 @@ proc onload*[T: LoadableResource](self: T, ok: bool, err: string, p: pointer, le
|
||||||
if self.result != nil:
|
if self.result != nil:
|
||||||
self.result[] = (ok, err, p, len)
|
self.result[] = (ok, err, p, len)
|
||||||
if self.onload_func != nil:
|
if self.onload_func != nil:
|
||||||
self.onload_func(ok, err, p, len)
|
if self.use_threads:
|
||||||
|
to_return.send((self.LoadableResource, ok, err, p, len))
|
||||||
|
else:
|
||||||
|
self.onload_func(ok, err, p, len)
|
||||||
else: # cancelled
|
else: # cancelled
|
||||||
self.status = NotStarted
|
self.doneImpl()
|
||||||
if self.done_func != nil:
|
|
||||||
self.done_func()
|
|
||||||
|
|
||||||
# TODO: check if we can always use destructors instead of calling this
|
# TODO: check if we can always use destructors instead of calling this
|
||||||
proc done*[T: LoadableResource](self: T) =
|
proc done*[T: LoadableResource](self: T) =
|
||||||
if self.status == Started:
|
if self.use_threads:
|
||||||
self.cancel()
|
to_done.send self
|
||||||
else:
|
else:
|
||||||
self.status = NotStarted
|
self.doneImpl()
|
||||||
if self.done_func != nil:
|
|
||||||
self.done_func()
|
|
||||||
|
|
||||||
proc cancel*[T: LoadableResource](self: T) =
|
proc cancel*[T: LoadableResource](self: T) =
|
||||||
if self.status != Started:
|
if self.status != Started:
|
||||||
return
|
return
|
||||||
if self.cancel_func != nil:
|
if self.cancel_func == nil:
|
||||||
# self.`onload=`(proc(ok, err, p, len: auto) =
|
# self.`onload=`(proc(ok, err, p, len: auto) =
|
||||||
# self.done())
|
# self.done())
|
||||||
self.onload_func = proc(ok: bool, err: string, p: pointer, len: int) =
|
self.onload_func = proc(ok: bool, err: string, p: pointer, len: int) =
|
||||||
|
@ -128,6 +147,31 @@ proc cancel*[T: LoadableResource](self: T) =
|
||||||
# results.add res.result[]
|
# results.add res.result[]
|
||||||
# res.result = nil
|
# res.result = nil
|
||||||
|
|
||||||
|
var worker: Thread[void]
|
||||||
|
proc workerThreadProc() {.thread.} =
|
||||||
|
while true:
|
||||||
|
let res = to_start.recv()
|
||||||
|
if res == nil:
|
||||||
|
break
|
||||||
|
cast[proc(self: LoadableResource) {.gcsafe.}](res.start_func)(res)
|
||||||
|
|
||||||
|
worker.createThread(workerThreadProc)
|
||||||
|
to_start.open()
|
||||||
|
to_return.open()
|
||||||
|
to_done.open()
|
||||||
|
|
||||||
|
proc updateLoadableWorkerThreads*() =
|
||||||
|
while true:
|
||||||
|
let tried = to_return.tryRecv()
|
||||||
|
if not tried.dataAvailable:
|
||||||
|
break
|
||||||
|
let (res, ok, err, p, len) = tried.msg
|
||||||
|
res.onload_func(ok, err, p, len)
|
||||||
|
while true:
|
||||||
|
let tried = to_done.tryRecv()
|
||||||
|
if not tried.dataAvailable:
|
||||||
|
break
|
||||||
|
tried.msg.done_func()
|
||||||
|
|
||||||
type Fetch* = ref object of LoadableResource
|
type Fetch* = ref object of LoadableResource
|
||||||
custom: pointer
|
custom: pointer
|
||||||
|
@ -226,6 +270,7 @@ proc loadUri*(
|
||||||
var done_func: proc()
|
var done_func: proc()
|
||||||
var self: Fetch
|
var self: Fetch
|
||||||
var uri = uri
|
var uri = uri
|
||||||
|
var use_threads = false
|
||||||
when not defined(onlyLocalFiles):
|
when not defined(onlyLocalFiles):
|
||||||
when defined(emscripten):
|
when defined(emscripten):
|
||||||
const is_remote = true
|
const is_remote = true
|
||||||
|
@ -261,6 +306,7 @@ proc loadUri*(
|
||||||
discard emscripten_fetch_close(cast[ptr emscripten_fetch_t](self.custom))
|
discard emscripten_fetch_close(cast[ptr emscripten_fetch_t](self.custom))
|
||||||
self.custom = nil
|
self.custom = nil
|
||||||
else:
|
else:
|
||||||
|
use_threads = true
|
||||||
var client = newHttpClient()
|
var client = newHttpClient()
|
||||||
var response: string
|
var response: string
|
||||||
start_func = proc(self: LoadableResource) =
|
start_func = proc(self: LoadableResource) =
|
||||||
|
@ -298,7 +344,7 @@ proc loadUri*(
|
||||||
if cast[Fetch](self).auto_done:
|
if cast[Fetch](self).auto_done:
|
||||||
self.done()
|
self.done()
|
||||||
proc str(): string = uri
|
proc str(): string = uri
|
||||||
self = newLoadableResource[Fetch](start_func, done_func, str)
|
self = newLoadableResource[Fetch](start_func, done_func, str, use_threads=use_threads)
|
||||||
self.onload_func = onload_func
|
self.onload_func = onload_func
|
||||||
self.auto_done = auto_done
|
self.auto_done = auto_done
|
||||||
if auto_start:
|
if auto_start:
|
||||||
|
|
|
@ -77,6 +77,7 @@ import ./screen
|
||||||
import ./platform/platform
|
import ./platform/platform
|
||||||
import ./loaders/blend
|
import ./loaders/blend
|
||||||
import ./util
|
import ./util
|
||||||
|
from loadable import updateLoadableWorkerThreads
|
||||||
import arr_ref
|
import arr_ref
|
||||||
|
|
||||||
export arr_ref
|
export arr_ref
|
||||||
|
@ -165,6 +166,7 @@ proc myou_main_loop*(self: MyouEngine) =
|
||||||
##
|
##
|
||||||
## You usually don't need to call this. Use `run <#run,MyouEngine>`_
|
## You usually don't need to call this. Use `run <#run,MyouEngine>`_
|
||||||
## instead.
|
## instead.
|
||||||
|
updateLoadableWorkerThreads()
|
||||||
# TODO: make a table object that can be iterated while changing, e.g. with a
|
# TODO: make a table object that can be iterated while changing, e.g. with a
|
||||||
# seq and a dirty flag to update the seq
|
# seq and a dirty flag to update the seq
|
||||||
if self.new_scenes.len != 0:
|
if self.new_scenes.len != 0:
|
||||||
|
|
Loading…
Reference in a new issue