diff options
Diffstat (limited to 'iono/iono.swift')
-rw-r--r-- | iono/iono.swift | 148 |
1 files changed, 114 insertions, 34 deletions
diff --git a/iono/iono.swift b/iono/iono.swift index 23e0104..1f07140 100644 --- a/iono/iono.swift +++ b/iono/iono.swift @@ -27,48 +27,127 @@ func notification_callback(payload: Optional<UnsafePointer<Int8>>, native.internalOnNotify(payload: string) } +struct Queue<T> { + var contents: [T] + + init() { + self.contents = [] + } + + mutating func push(_ element: T) { + contents.append(element) + } + + mutating func pop() -> T? { + if (contents.isEmpty) { + return nil + } else { + return contents.remove(at: 0) + } + } +} + +class NodeThread: Thread { + var iono: Iono! + var workQueue: Queue<() -> ()> + var initialized: Bool + var initCondition: NSCondition + + override init() { + self.workQueue = Queue<() -> ()>() + self.initialized = false + self.initCondition = NSCondition() + super.init() + } + + override func main() { + iono.instance = __initNative() + __setNotifyHandler(iono.instance, notification_callback, Unmanaged.passUnretained(iono).toOpaque()) + self.initialized = true + initCondition.broadcast() + while true { + __runNode(iono.instance) + while let workItem = workQueue.pop() { + workItem() + } + if iono.stopped { + break + } + } + } + + func waitUntilInitialized(block: @escaping () -> ()) { + if (self.initialized) { + block() + return + } + + initCondition.lock() + while (!self.initialized) { + initCondition.wait() + } + + block() + + initCondition.unlock() + } +} + public class Iono { + var stopped: Bool + var thread: NodeThread + var instance: OpaquePointer! - var work_queue: DispatchQueue - var initialization_group: DispatchGroup - var messageHandler: IonoMessageHandler? - - public init() { - work_queue = DispatchQueue(label: "NodeQueue", qos: .userInitiated) - initialization_group = DispatchGroup() - initialization_group.notify(queue: work_queue) { - self.instance = __initNative() - __setNotifyHandler(self.instance, notification_callback, Unmanaged.passUnretained(self).toOpaque()) - } + public var messageHandler: IonoMessageHandler? + + public init() { // We need to be calling runNode! + self.stopped = false + self.thread = NodeThread() + self.thread.iono = self + + self.thread.start() } - + deinit { __destroyNative(instance) } - - private func scheduleNodeThreadAsync(block: @escaping () -> Void) { - initialization_group.wait() - work_queue.async(execute: block) - notifyNative() + + private func scheduleNodeThreadAsync(block: @escaping () -> ()) { + thread.waitUntilInitialized { + self.thread.workQueue.push(block) + self.notifyNative() + } } - + private func scheduleNodeThreadSync(block: @escaping () -> Void) { - initialization_group.wait() - work_queue.sync(execute: block) - notifyNative() + var hasExecuted = false + let executeCondition = NSCondition() + + executeCondition.lock() + thread.waitUntilInitialized { + self.thread.workQueue.push { + block() + hasExecuted = true + executeCondition.broadcast() + } + self.notifyNative() + } + while (!hasExecuted) { + executeCondition.wait() + } + executeCondition.unlock() } - + public func internalOnNotify(payload: String) { if let handler = messageHandler { handler.handleMessage(message: payload) } } - + public func notifyNative() { - initialization_group.wait() __notifyNative(instance) } - + public func evalSimpleJs(source: String) -> String { var result: String? scheduleNodeThreadSync { @@ -80,13 +159,13 @@ public class Iono { } return result! } - + public func evalNodeCode(source: String) { scheduleNodeThreadAsync { __makeCallbackNative(self.instance, source.cString(using: .utf8)) } } - + public func sendMessage(message: String) { let encoded = message.data(using: .utf8)!.base64EncodedString() let source = """ @@ -99,15 +178,16 @@ public class Iono { """ evalNodeCode(source: source) } - + public func waitStopped() { - - } - - public func putModuleCode(modName: String, code: String) { scheduleNodeThreadSync { - __putModuleCodeNative(self.instance, modName.cString(using: .utf8), - code.cString(using: .utf8)) + self.stopped = true } + thread.cancel() + } + + public func putModuleCode(modName: String, code: String) { + __putModuleCodeNative(self.instance, modName.cString(using: .utf8), + code.cString(using: .utf8)) } } |