         } else {
             print("disgarding action reply \(actionId)")
         }
+        objc_sync_exit(self.eventSemaphores)
     }
     
     @objc(registerAction:)

        // clear semaphore and reply cache
        self.replyCache[actionId] = nil
        self.eventSemaphores[actionId] = nil
        
        return reply
    }

    @objc(replyToAction:response:error:)
    func replyToAction(actionId: NSInteger, response: NSDictionary, error: String) {
        // lookup the semaphore for this action
        objc_sync_enter(self.eventSemaphores)
        if let sem = self.eventSemaphores[actionId] {
            // place response in cache and signal on this semaphore
            self.replyCache[actionId] = ["result": response, "error": error]
