make ref object work in threads

This commit is contained in:
Dmitriy Ryajov 2025-05-19 11:12:54 -06:00
parent f1433ffbd8
commit f0ffaf4663
No known key found for this signature in database
GPG Key ID: DA8C680CE7C657A4

View File

@ -40,16 +40,20 @@ type PortMapping* = object
internalUdpPort*: Port internalUdpPort*: Port
description*: string description*: string
type NatManager* = ref object type
portMappings: seq[PortMapping] NatManagerObj* = object
thread: Thread[ptr NatManager] portMappings: seq[PortMapping]
config: NatConfig thread: Thread[NatManagerPtr]
lock: Lock config: NatConfig
upnp {.guard: lock.}: Miniupnp lock: Lock
npmp {.guard: lock.}: NatPmp upnp {.guard: lock.}: Miniupnp
strategy: NatStrategy npmp {.guard: lock.}: NatPmp
threadStarted: bool strategy: NatStrategy
natClosed: Atomic[bool] threadStarted: bool
natClosed: Atomic[bool]
NatManager* = ref NatManagerObj
NatManagerPtr* = ptr NatManagerObj
export natutils export natutils
@ -233,9 +237,10 @@ proc doPortMapping(
extUdpPort = extPort extUdpPort = extPort
return some((extTcpPort, extUdpPort)) return some((extTcpPort, extUdpPort))
proc repeatPortMapping(self: ptr NatManager) {.thread, raises: [ValueError].} = proc repeatPortMapping(self: NatManagerPtr) {.thread, raises: [ValueError].} =
ignoreSignalsInThread() ignoreSignalsInThread()
var self = cast[NatManager](self)
let let
interval = initDuration(seconds = PORT_MAPPING_INTERVAL) interval = initDuration(seconds = PORT_MAPPING_INTERVAL)
sleepDuration = 1_000 # in ms, also the maximum delay after pressing Ctrl-C sleepDuration = 1_000 # in ms, also the maximum delay after pressing Ctrl-C
@ -251,10 +256,10 @@ proc repeatPortMapping(self: ptr NatManager) {.thread, raises: [ValueError].} =
# select on Nim channels like on Go ones # select on Nim channels like on Go ones
let currTime = now() let currTime = now()
if currTime >= (lastUpdate + interval): if currTime >= (lastUpdate + interval):
for entry in self[].portMappings: for entry in self.portMappings:
discard doPortMapping( discard doPortMapping(
self[], self,
self[].strategy, self.strategy,
entry.externalTcpPort, entry.externalTcpPort,
entry.externalUdpPort, entry.externalUdpPort,
entry.description, entry.description,
@ -275,6 +280,8 @@ proc stop*(self: NatManager) {.async.} =
self.thread.joinThread() self.thread.joinThread()
except Exception as exc: except Exception as exc:
warn "Failed to stop NAT port mapping renewal thread", exc = exc.msg warn "Failed to stop NAT port mapping renewal thread", exc = exc.msg
finally:
GC_unref(self)
# delete our port mappings # delete our port mappings
@ -401,7 +408,9 @@ proc startPortMappingThread*(self: NatManager) =
if self.portMappings.len > 0: if self.portMappings.len > 0:
self.natClosed.store(false) self.natClosed.store(false)
try: try:
self.thread.createThread(repeatPortMapping, (self.addr)) let mngrPtr = cast[NatManagerPtr](self)
GC_ref(self)
self.thread.createThread(repeatPortMapping, mngrPtr)
self.threadStarted = true self.threadStarted = true
except Exception as exc: except Exception as exc:
warn "Failed to create NAT port mapping renewal thread", exc = exc.msg warn "Failed to create NAT port mapping renewal thread", exc = exc.msg