From 022c82ccbcf9d738498d195c3201727410ae4c8b Mon Sep 17 00:00:00 2001 From: Andrey Tolstoy Date: Thu, 15 Feb 2024 22:16:34 +0700 Subject: [PATCH] test debug --- lib/device.js | 20 +++++++++++++++++ lib/index.js | 60 +++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 80 insertions(+) diff --git a/lib/device.js b/lib/device.js index 7fd719b..1bbb25a 100644 --- a/lib/device.js +++ b/lib/device.js @@ -224,6 +224,10 @@ class Device extends EventEmitter { } else { break; } + if (mboxMessages.length > 1000) { + this._log.error('mbox over 1000 messages !?'); + break; + } } catch (err) { break; } @@ -480,9 +484,11 @@ class Device extends EventEmitter { } async _close() { + let timeoutAt = Date.now() + DEVICE_OPEN_TIMEOUT; const canClose = () => (!this._opening && !this._closing); while (!canClose()) { const p = new Promise(resolve => { + let timer = null; const onChange = () => { if (canClose()) { this.off('_opening', onChange); @@ -490,8 +496,22 @@ class Device extends EventEmitter { resolve(); } }; + const onTimeout = async () => { + this._log.error('Timeout while _closing_ the device, attempt to force close'); + this.off('_opening', onChange); + this.off('_closing', onChange); + if (this._usbDev) { + try { + await this._usbDev.close({ processPendingRequests: false }); + } catch (e) { + this._log.error('Failed to force-close the device', e); + } + } + reject(new Error('Timeout while _closing_ the device')); + }; this.on('_opening', onChange); this.on('_closing', onChange); + timer = setTimeout(onTimeout, Math.max(0, timeoutAt - Date.now())); }); await p; } diff --git a/lib/index.js b/lib/index.js index 2f921a7..8bdc542 100755 --- a/lib/index.js +++ b/lib/index.js @@ -5,8 +5,68 @@ const { Logger } = require('./logger'); const { RunMode, initConfig, showUsage, config } = require('./config'); const { isInternalError } = require('./error'); const { version: PACKAGE_VERSION } = require('../package.json'); +const async_hooks = require('async_hooks'); + +let hook = null; +let hookMap = new Map(); async function run() { + hook = async_hooks.createHook({ + init: (asyncId, type, triggerAsyncId, resource) => { + if (resource && resource._timerArgs && resource._timerArgs[0] == 'notrack') { + return; + } + const error = {}; + Error.captureStackTrace(error); + const stack = error.stack.split("\n").map(line => line.trim()).slice(1); + hookMap.set(asyncId, { + type, + triggerAsyncId, + resource, + stack, + count: 0, + timer: type == 'PROMISE' ? setInterval(() => { + console.log('================================================================'); + const m = hookMap.get(asyncId); + m.count++; + console.log(`async op=${asyncId} stalled for over ${10 * m.count} mins`); + console.log(type); + console.log(resource); + console.log('stack:'); + console.log(stack); + let parentId = triggerAsyncId; + while (parentId) { + const parent = hookMap.get(parentId); + if (!parent) { + break; + } + parentId = parent.triggerAsyncId; + console.log(`Parent ${parentId}`); + console.log(type); + console.log(resource); + console.log('stack:'); + console.log(parent.stack); + } + console.log('done=============================================================\r\n\r\n'); + }, 10 * 60 * 1000, 'notrack') : null + }); + }, + destroy: (asyncId) => { + const task = hookMap.get(asyncId); + if (task && task.timer) { + clearInterval(task.timer); + } + hookMap.delete(asyncId); + }, + promiseResolve: (asyncId) => { + const task = hookMap.get(asyncId); + if (task && task.timer) { + clearInterval(task.timer); + } + hookMap.delete(asyncId); + }, + }); + hook.enable(); let ok = true; let runner = null; try {