添加检测任务模块及死锁检测bug修改

This commit is contained in:
machunyu 2022-10-12 15:12:11 +08:00
parent b93dfd7244
commit 1111d8d11b
22 changed files with 2233 additions and 160 deletions

5
.vscode/extensions.json vendored Normal file
View File

@ -0,0 +1,5 @@
{
// See http://go.microsoft.com/fwlink/?LinkId=827846
// for the documentation about the extensions.json format
"recommendations": ["dbaeumer.vscode-eslint", "amodio.tsl-problem-matcher"]
}

35
.vscode/launch.json vendored Normal file
View File

@ -0,0 +1,35 @@
// A launch configuration that compiles the extension and then opens it inside a new window
// Use IntelliSense to learn about possible attributes.
// Hover to view descriptions of existing attributes.
// For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
{
"version": "0.2.0",
"configurations": [
{
"name": "Run Extension",
"type": "extensionHost",
"request": "launch",
"args": [
"--extensionDevelopmentPath=${workspaceFolder}"
],
"outFiles": [
"${workspaceFolder}/dist/**/*.js"
],
"preLaunchTask": "${defaultBuildTask}"
},
{
"name": "Extension Tests",
"type": "extensionHost",
"request": "launch",
"args": [
"--extensionDevelopmentPath=${workspaceFolder}",
"--extensionTestsPath=${workspaceFolder}/out/test/suite/index"
],
"outFiles": [
"${workspaceFolder}/out/**/*.js",
"${workspaceFolder}/dist/**/*.js"
],
"preLaunchTask": "tasks: watch-tests"
}
]
}

13
.vscode/settings.json vendored Normal file
View File

@ -0,0 +1,13 @@
// Place your settings in this file to overwrite default and user settings.
{
"files.exclude": {
"out": false, // set this to true to hide the "out" folder with the compiled JS files
"dist": false // set this to true to hide the "dist" folder with the compiled JS files
},
"search.exclude": {
"out": true, // set this to false to include "out" folder in search results
"dist": true // set this to false to include "dist" folder in search results
},
// Turn off tsc task auto detection since we have the necessary tasks as npm scripts
"typescript.tsc.autoDetect": "off"
}

40
.vscode/tasks.json vendored Normal file
View File

@ -0,0 +1,40 @@
// See https://go.microsoft.com/fwlink/?LinkId=733558
// for the documentation about the tasks.json format
{
"version": "2.0.0",
"tasks": [
{
"type": "npm",
"script": "watch",
"problemMatcher": "$ts-webpack-watch",
"isBackground": true,
"presentation": {
"reveal": "never",
"group": "watchers"
},
"group": {
"kind": "build",
"isDefault": true
}
},
{
"type": "npm",
"script": "watch-tests",
"problemMatcher": "$tsc-watch",
"isBackground": true,
"presentation": {
"reveal": "never",
"group": "watchers"
},
"group": "build"
},
{
"label": "tasks: watch-tests",
"dependsOn": [
"npm: watch",
"npm: watch-tests"
],
"problemMatcher": []
}
]
}

11
build.sh Executable file
View File

@ -0,0 +1,11 @@
#!/bin/bash
# sudo apt install sshpass
cd view-ui
npm install
npm run build
rm -rf ../detect-plugin/dist/
cp dist/ ../detect-plugin/ -r
cd ../detect-plugin
yarn
vsce package

26
detect-plugin/README.md Normal file
View File

@ -0,0 +1,26 @@
# C/C++ 程序锁分析
#### [仓库](https://gitee.com/openkylin/deadlock-detect)
## 介绍
deadlock-detect 是一款基于OpenKylin社区kylin-code的拓展插件用于C/C++程序的死锁检测及锁状态分析帮助开发者在Linux系统下识别多线程死锁状态、互斥锁自旋锁等状态异常问题并对程序加锁位置分析。
---
## 功能
- C/C++ 多线程序锁分析
- 可视化观察临界区进入次数、耗时、条件变量等待时长
- 线程退出未释放锁异常
- 可执行程序死锁检测
- 进程死锁检测
- 远程环境进程死锁检测
## 使用方法
1. C/C++ 多线程序锁分析
2. 进程死锁检测
3. 远程进程死锁检测

View File

@ -0,0 +1,29 @@
#!/usr/bin/bash
ARCH=`arch`
DIR=`dirname $0`
BINLOADER=$DIR/${ARCH}/binloader
if [ $# -lt 1 ];then
# echo "Error params"
exit 101
fi
BINPATH=$1
if [ ! -e ${BINPATH} ] || [ "a" == "a${BINPATH}" ];then
# echo "No File"
exit 102
fi
if [ -z "`file ${BINPATH} | grep ELF`" ];then
# echo "Not ELF"
exit 103
fi
LIBPTHREAD_PATH=`ldd ${BINPATH} | grep pthread | awk '{print $3}'`
if [ -z "${LIBPTHREAD_PATH}" ];then
# echo "No pthread"
exit 104
fi
${BINLOADER} $@

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@ -16,15 +16,50 @@
"Other"
],
"activationEvents": [
"onCommand:deadlock-detect.detect"
"onCommand:deadlock-detect.open",
"onLanguage:c",
"onLanguage:cpp",
"onCommand:workbench.action.tasks.runTask"
],
"main": "./out/extension.js",
"contributes": {
"commands": [
{
"command": "deadlock-detect.detect",
"command": "deadlock-detect.open",
"title": "C/C++程序死锁检测"
}
],
"taskDefinitions": [
{
"type": "deadlockdetect",
"required": [
"command"
],
"properties": {
"command": {
"type": "string",
"description": "%deadlockdetect.taskDefinitions.command.description%"
},
"args": {
"type": "array",
"description": "%deadlockdetect.taskDefinitions.args.description%"
},
"options": {
"type": "object",
"description": "%deadlockdetect.taskDefinitions.options.description%",
"properties": {
"cwd": {
"type": "string",
"description": "%deadlockdetect.taskDefinitions.options.cwd.description%"
},
"env": {
"type": "array",
"description": "%deadlockdetect.taskDefinitions.options.env.description%"
}
}
}
}
}
]
},
"scripts": {
@ -39,19 +74,22 @@
"test": "node ./out/test/runTest.js"
},
"devDependencies": {
"@types/vscode": "^1.54.0",
"@types/glob": "^7.2.0",
"@types/mocha": "^9.1.1",
"@types/node": "16.x",
"@types/vscode": "^1.54.0",
"@typescript-eslint/eslint-plugin": "^5.31.0",
"@typescript-eslint/parser": "^5.31.0",
"@vscode/test-electron": "^2.1.5",
"eslint": "^8.20.0",
"glob": "^8.0.3",
"mocha": "^10.0.0",
"typescript": "^4.7.4",
"ts-loader": "^9.3.1",
"typescript": "^4.7.4",
"webpack": "^5.74.0",
"webpack-cli": "^4.10.0",
"@vscode/test-electron": "^2.1.5"
"webpack-cli": "^4.10.0"
},
"dependencies": {
"yaml": "^2.1.3"
}
}

View File

@ -0,0 +1,7 @@
{
"deadlockdetect.taskDefinitions.command.description": "这里是要检测的可执行程序(必选) 相对路径或绝对路径",
"deadlockdetect.taskDefinitions.args.description": "这里是可执行程序的参数(可选)",
"deadlockdetect.taskDefinitions.options.description": "这里是一些可选型",
"deadlockdetect.taskDefinitions.options.cwd.description": "程序的运行目录",
"deadlockdetect.taskDefinitions.options.env.description": "程序的环境变量"
}

View File

@ -0,0 +1,238 @@
import * as vscode from 'vscode';
import * as child from 'child_process';
import {execDetect, testPwd, prase_yaml2html} from './utils';
import { dirname, join } from 'path';
import { kill } from 'process';
import * as fs from 'fs';
type Options = {
cwd?: string;
env?: string[];
};
const binLoader: string = join(dirname(__dirname), "detect-tools/bincheck_loader.sh");
interface DetectTaskDefinition extends vscode.TaskDefinition {
command: string;
args?: string[];
options?: Options;
}
export class DetectTaskProvider implements vscode.TaskProvider {
static customBuildScriptType = 'deadlockdetect';
private tasks: vscode.Task[] | undefined;
private sharedState: string | undefined;
private cmd: child.ChildProcessWithoutNullStreams | undefined;
constructor(private workspaceRoot: string, private context: vscode.ExtensionContext) { }
public async provideTasks(): Promise<vscode.Task[]> {
return this.getTasks();
}
public resolveTask(_task: vscode.Task): vscode.Task | undefined {
const command: string = _task.definition.command;
if (command) {
const definition: DetectTaskDefinition = <any>_task.definition;
return this.getTask(definition.command, definition.args ? definition.args : [], definition.options ? definition.options : {}, definition);
}
return undefined;
}
private getTasks(): vscode.Task[] {
if (this.tasks !== undefined) {
return this.tasks;
}
this.tasks = [];
var option: Options = {
env: ["程序执行所需额外环境变量:如 DISPALY=1"],
};
this.tasks!.push(this.getTask("被检测可执行程序", ["可执行程序参数(可选)"], option));
return this.tasks;
}
private getTask(command: string, args: string[], option: Options, definition?: DetectTaskDefinition): vscode.Task {
if (definition === undefined) {
definition = {
type: DetectTaskProvider.customBuildScriptType,
command: command,
args: args,
options: option,
};
}
return new vscode.Task(definition, vscode.TaskScope.Workspace, "可执行程序锁检测",
DetectTaskProvider.customBuildScriptType, new vscode.CustomExecution(async (): Promise<vscode.Pseudoterminal> => {
// When the task is executed, this callback will run. Here, we setup for running the task.
return new CustomBuildTaskTerminal(this.cmd, this.context, command, args, option, () => this.sharedState, (state: string) => this.sharedState = state);
}));
}
}
class CustomBuildTaskTerminal implements vscode.Pseudoterminal {
private writeEmitter = new vscode.EventEmitter<string>();
onDidWrite: vscode.Event<string> = this.writeEmitter.event;
private closeEmitter = new vscode.EventEmitter<number>();
onDidClose?: vscode.Event<number> = this.closeEmitter.event;
private passwd: string | undefined;
private checkedPid: number = 0;
constructor(private cmd: child.ChildProcessWithoutNullStreams | undefined, private context: vscode.ExtensionContext, private command: string, private args: string[], private option: Options, private getSharedState: () => string | undefined, private setSharedState: (state: string) => void) {
}
open(initialDimensions: vscode.TerminalDimensions | undefined): void {
// At this point we can start using the terminal.
if (this.command.length) {
let found = false;
vscode.workspace.workspaceFolders?.forEach((value)=>{
// value.uri.fsPath
if(this.command[0] == '/' && !found){
this.option.cwd = value.uri.fsPath;
found = true;
}
if(!found){
let absPath = join(value.uri.fsPath, this.command);
if(fs.existsSync(absPath)){
this.option.cwd = value.uri.fsPath;
this.command = absPath;
found = true;
}
}
});
if(!found || !fs.existsSync(this.command)){
vscode.window.showWarningMessage("未找到被检测二进制文件, 请输入相对路径或绝对路径");
this.closeEmitter.fire(0);
return;
}
// vscode.workspace.workspaceFolders
vscode.window.showInputBox({
password:true, // 输入内容是否是密码
ignoreFocusOut:true, // 默认false设置为true时鼠标点击别的地方输入框不会消失
placeHolder:'请输入用户密码', // 在输入框内的提示信息
prompt:'请输入当前用户的密码',
}).then((pwd)=>{
if(pwd === undefined || pwd?.length === 0)
{
this.closeEmitter.fire(0);
return;
}
testPwd(pwd, (ok)=>{
if(ok){
this.passwd = pwd;
this.doExec();
return;
}
vscode.window.showErrorMessage("用户密码不匹配");
this.closeEmitter.fire(0);
});
});
}else{
vscode.window.showWarningMessage("未发现被检测二进制文件");
this.closeEmitter.fire(0);
}
}
close(): void {
if(this.cmd){
kill(this.checkedPid, 9);
vscode.window.showWarningMessage("检测任务已退出");
}
}
// 开始执行待检测程序
private async doExec(): Promise<void> {
return new Promise<void>((resolve) => {
this.writeEmitter.fire('正在检测 ...\r\n');
this.option.env?.forEach(e =>{
let kv = e.split('=', 2);
if(kv.length === 2){
process.env[kv[0]] = kv[1];
}
});
let hadPid = false;
let coption: child.SpawnOptionsWithoutStdio = {
env: process.env
};
if(this.option.cwd?.length){
coption.cwd = this.option.cwd;
}
this.cmd = child.spawn(binLoader, [this.command, ...this.args], coption);
this.cmd.on('error', (err)=>{
this.writeEmitter.fire('执行失败 ... ' + err.message);
});
this.cmd.on('exit', (code) =>{
let errmsg = "";
switch (code) {
case 101:
errmsg = "待检测可执行程序不能为空 !";
break;
case 102:
errmsg = "待检测可执行程序未找到,请确认可执行程序路径是否存在 !";
break;
case 103:
errmsg = "待检测可执行程序不是二进制文件 !";
break;
case 104:
errmsg = "待检测可执行程序未引用pthread动态库 !";
break;
default:
break;
}
if(errmsg.length){
vscode.window.showErrorMessage(errmsg);
}
this.writeEmitter.fire('被检测程序已终止 ... \r\n');
const date = new Date();
this.setSharedState(date.toTimeString() + ' ' + date.toDateString());
this.closeEmitter.fire(0);
resolve();
});
this.cmd.stdout.on('data', (data) =>{
// childPid: 17558
let buff: Buffer = data;
let str: string = buff.toString('utf8');
let arrStr = str.split(/\r?\n/);
arrStr.forEach((s)=>{
this.writeEmitter.fire(s+'\r\n');
});
});
this.cmd.stderr.on('data', (data) =>{
let buff: Buffer = data;
let str: string = buff.toString('utf8');
if(!hadPid){
let result = str.split("|");
if(result.length >= 4){
hadPid = true;
this.checkedPid = parseInt(result[3].trim());
execDetect(this.passwd, result[1].trim(), this.checkedPid, (detectResult)=>{
if(detectResult.match(/fatal/)?.length){
vscode.window.showWarningMessage("被检测程序存在严重问题!")
}else if(detectResult.match(/deadlock/)?.length){
vscode.window.showWarningMessage("被检测程序存在死锁!");
}
if(detectResult.match(/normal|fatal|deadlock/)?.length){
const webPanel = vscode.window.createWebviewPanel(
'detectResultWebview',
"检测结果",
vscode.ViewColumn.One,
{
enableScripts: true,
retainContextWhenHidden: true,
}
)
webPanel.webview.html = prase_yaml2html(this.command, this.context.extensionPath, webPanel.webview, detectResult);
}else{
vscode.window.showInformationMessage("程序已退出,但未检测到相关锁信息");
}
});
}
return;
}
let arrStr = str.split(/\r?\n/);
arrStr.forEach((s)=>{
this.writeEmitter.fire(s+'\r\n');
});
});
});
}
}

View File

@ -3,9 +3,17 @@
import * as vscode from 'vscode';
import path = require('path');
import fs = require("fs");
import {DetectTaskProvider} from './detectTaskProvider';
import { homedir } from 'os';
// linux命令操作模块
var child = require('child_process');
const { pid } = require('process');
let detectTaskProvider: vscode.Disposable | undefined;
function getWebViewContent(context: vscode.ExtensionContext, templatePath: string) {
const resourcePath = path.join(context.extensionPath, templatePath);
const resourcePath = path.join(path.dirname(__dirname), templatePath);
const dirPath = path.dirname(resourcePath);
let html = fs.readFileSync(resourcePath, 'utf-8');
// vscode不支持直接加载本地资源需要替换成其专有路径格式这里只是简单的将样式和JS的路径替换
@ -18,6 +26,23 @@ function getWebViewContent(context: vscode.ExtensionContext, templatePath: strin
return html;
}
function is_pid_exist(pid: string) {
return new Promise(function(resolve, reject) {
child.exec(`ps -ef`, (e: any, x: string, c: any) => {
if(e){
reject('ps命令执行错误!')
}else{
let search=new RegExp("\\s+"+pid+"\\s+");
let exist=search.test(x);
if(exist){
resolve('1');
}else{
resolve('-1');
}
}
})
});
}
// this method is called when your extension is activated
// your extension is activated the very first time the command is executed
export function activate(context: vscode.ExtensionContext) {
@ -26,10 +51,155 @@ export function activate(context: vscode.ExtensionContext) {
// This line of code will only be executed once when your extension is activated
console.log('Congratulations, your extension "deadlock-detect" is now active!');
let newFn={
local_detect_deadlock:function (message: any ,panel: vscode.WebviewPanel){
let form=message.form;
if(form.CmdType==1){
child.exec(`echo '${form.pwd}' | sudo -S ps`, (e: any, x: string, c: any) => {
if(e){
form.success='error-pwd';
form.msg='您输入的密码错误!';
if(e.message.indexOf('sudoers')!=-1){
form.msg='当前用户无sudo权限请在拥有sudo权限后重试!';
}
panel.webview.postMessage({
res: form
})
return;
}
})
let pid_exist = is_pid_exist(form.pid);
pid_exist.then((result)=>{
console.log(result);
if(result=='-1'){
form.success='error-pid';
form.msg='进程号不存在,请重新输入';
panel.webview.postMessage({
res: form
})
return
}else if(result=='1'){
child.exec(`echo '${form.pwd}' | sudo -S ${__dirname}/../detect-tools/x86_64/detect_deadlock ${form.pid}`, (e: any, x: string, c: any) => {
// console.log(`echo '${form.pwd}' | sudo ${__dirname}/../detect-tools/x86_64/detect_deadlock ${form.pid}`);
if(!e){
form.data =x;
form.success='success';
panel.webview.postMessage({
res: form});
}
else{
form.success='error';
panel.webview.postMessage({
res: form});
}
});
}
})
}
},
remote_detect_deadlock:function (message: any ,panel: vscode.WebviewPanel){
let form=message.form;
if(form.CmdType==3){
// sudo apt install sshpass
child.exec(`sshpass -p '${form.pwd}' ssh -o StrictHostKeyChecking=no ${form.user}@${form.ip}`, (e: any, x: string, c: any) => {
if(e){
form.success='error-ssh-login';
form.msg='无法登录您指定的远端系统请确保具有ssh登录权限!';
panel.webview.postMessage({
res: form
})
return;
}
})
child.exec(`sshpass -p '${form.pwd}' ssh -o StrictHostKeyChecking=no ${form.user}@${form.ip} 'echo "${form.pwd}" | sudo -S ps'`, (e: any, x: string, c: any) => {
if(e){
form.success='error-not-sudoer';
form.msg='user is not sudoer!';
if(e.message.indexOf('sudoers')!=-1){
form.msg='当前用户无sudo权限请在拥有sudo权限后重试!';
}
panel.webview.postMessage({
res: form
})
return;
}
})
let pid_exist = new Promise(function(resolve, reject) {
child.exec(`sshpass -p '${form.pwd}' ssh -o StrictHostKeyChecking=no ${form.user}@${form.ip} 'echo "${form.pwd}" | sudo -S ps -ef'`, (e: any, x: string, c: any) => {
if(e){
reject('ps命令执行错误!')
}else{
let search=new RegExp("\\s+"+form.pid+"\\s+");
let exist=search.test(x);
if(exist){
resolve('1');
}else{
resolve('-1');
}
}
})
});
pid_exist.then((result)=>{
console.log(result);
if(result=='-1'){
form.success='error-pid';
form.msg='进程号不存在,请重新输入';
panel.webview.postMessage({
res: form
})
return;
}else if(result=='1'){
child.exec(`sshpass -p '${form.pwd}' ssh -o StrictHostKeyChecking=no ${form.user}@${form.ip} '[ ! -d .deadlock-detect ] && mkdir .deadlock-detect || ls .deadlock-detect'`, (e: any, x: string, c: any) => {
// console.log(`echo '${form.pwd}' | sudo ${__dirname}/../detect-tools/x86_64/detect_deadlock ${form.pid}`);
if(e){
form.success='error-mkdir';
form.msg='创建目录.deadlock-detect失败!';
panel.webview.postMessage({
res: form});
return;
}
});
child.exec(`sshpass -p '${form.pwd}' scp -o StrictHostKeyChecking=no ${__dirname}/../detect-tools/x86_64/detect_deadlock ${form.user}@${form.ip}:./.deadlock-detect`, (e: any, x: string, c: any) => {
// console.log(`echo '${form.pwd}' | sudo ${__dirname}/../detect-tools/x86_64/detect_deadlock ${form.pid}`);
if(e){
form.success='error-scp';
form.msg='scp EXE failed!';
panel.webview.postMessage({
res: form});
return;
}
});
child.exec(`sshpass -p '${form.pwd}' ssh -o StrictHostKeyChecking=no ${form.user}@${form.ip} 'echo "${form.pwd}" | sudo -S ./.deadlock-detect/detect_deadlock ${form.pid}'`, (e: any, x: string, c: any) => {
// console.log(`echo '${form.pwd}' | sudo ${__dirname}/../detect-tools/x86_64/detect_deadlock ${form.pid}`);
if(!e){
form.data =x;
console.log(x);
form.success='success';
panel.webview.postMessage({
res: form});
}
else{
form.success='error';
panel.webview.postMessage({
res: form});
}
});
}
})
}
},
}
// The command has been defined in the package.json file
// Now provide the implementation of the command with registerCommand
// The commandId parameter must match the command field in package.json
let disposable = vscode.commands.registerCommand('deadlock-detect.detect', () => {
let disposable = vscode.commands.registerCommand('deadlock-detect.open', () => {
// The code you place here will be executed every time your command is executed
// Display a message box to the user
const panel = vscode.window.createWebviewPanel(
@ -38,14 +208,31 @@ export function activate(context: vscode.ExtensionContext) {
vscode.ViewColumn.One,
{
enableScripts: true,
retainContextWhenHidden: false,
retainContextWhenHidden: true,
}
);
panel.webview.html = getWebViewContent(context, "./dist/index.html");
panel.webview.onDidReceiveMessage(message => {
switch(message.form.CmdType) {
case 1://local pid dead-detect
newFn.local_detect_deadlock(message,panel);
break;
case 3://remote pid dead-detect
newFn.remote_detect_deadlock(message,panel);
break;
}
});
panel.webview.html = getWebViewContent(context, 'dist/index.html');
});
const workspaceRoot = (vscode.workspace.workspaceFolders && (vscode.workspace.workspaceFolders.length > 0)) ? vscode.workspace.workspaceFolders[0].uri.fsPath : homedir();
detectTaskProvider = vscode.tasks.registerTaskProvider(DetectTaskProvider.customBuildScriptType, new DetectTaskProvider(workspaceRoot, context));
context.subscriptions.push(disposable);
}
// this method is called when your extension is deactivated
export function deactivate() {}
export function deactivate() {
if(detectTaskProvider){
detectTaskProvider.dispose();
}
}

421
detect-plugin/src/utils.ts Normal file
View File

@ -0,0 +1,421 @@
import * as child from 'child_process';
import * as vscode from 'vscode';
import { dirname, join } from 'path';
import * as YAML from 'yaml';
const archs = new Map([
["x86_64", "x86_64"],
["x64", "x86_64"],
["arm64", "arm64"]
]);
const myArch = archs.get(process.arch);
const detectTool: string = join(dirname(__dirname), "detect-tools", myArch ? myArch: "x86_64", "deadlockcheck");
export function execDetect(pwd: string | undefined, libPthreadPath: string, checkedPid: number, cb: (da:string)=> void) {
var task = child.exec(`echo ${pwd} | sudo -S ${detectTool} --threadlib ${libPthreadPath} --pid ${checkedPid}`, (err, out, e)=>{
if(err?.message){
vscode.window.showErrorMessage('附加到被检测程序失败, '+err.message);
return;
}
if(out.length){
cb(out);
}
child.exec(`sudo -k`);
});
}
export function testPwd(pwd:string, cb: (ok: boolean)=>void): void {
if(pwd?.length){
child.exec(`echo ${pwd} | sudo -S echo okok`, (err, stdout, stderr)=>{
if(stdout.includes('okok')){
child.exec(`sudo -k`, (e1, stdout1, stderr3)=>{
cb(true);
});
return;
}
cb(false);
});
}
}
function circledNodesPosition(x:number, y: number, index: number, nodesLen: number) {
const avd = 360 / nodesLen;
const ahd = avd * Math.PI / 180;
return {
x: Math.sin((ahd * index)) * 15 + x,
y: Math.cos((ahd * index)) * 15 + y
}
}
// warn: "process exit"
// normalInfo:
// mutex:
// - pid: 12619
// details:
// 0x7f6a92f4c990: 5-7673-0
// 0x7f6a92f4c968: 1-3764-0
// 0x7ffc74e6ab98: 1-7411-0
// totalTime: 18848
// condWaitTime: 0
// - pid: 12618
// details:
// 0x7f6a92f4c990: 6-10005-0
// 0x7f6a92f4c968: 1-95491-0
// 0x7ffc74e6ab98: 2-43556-8000086897
// totalTime: 149052
// condWaitTime: 8000086897
// - pid: 12560
// details:
// 0x7f6a92f4c968: 2-36323-0
// totalTime: 36323
// condWaitTime: 0
// 输出死锁时的信息
function product_deadlockinfo_to_html(cmd: string, echartsPath: string, deadlockDesc: string, nodesInfo: object[], linksInfo: object[]) {
let _nodesInfo = JSON.stringify(nodesInfo);
let _linksInfo = JSON.stringify(linksInfo);
return `
<!DOCTYPE html>
<html lang="zh-CN" style="height: 100%">
<head>
<meta charset="utf-8">
</head>
<body style="height: 100%; margin: 0">
<div id="deadlockinfo" style="width:60%;margin:auto">
<h3>
</h3>
<p>${cmd}</p>
<h3>
</h3>
<ul>
${deadlockDesc}
</ul>
</div>
<br><br>
<div id="container" style="height: 70%;width:60%;margin:auto"></div>
<script type="text/javascript" src="${echartsPath}"></script>
<script type="text/javascript">
var dom = document.getElementById('container');
var myChart = echarts.init(dom, null, {
renderer: 'canvas',
useDirtyRect: false
});
var app = {};
var option;
option = {
title: {
text: '死锁关系图'
},
tooltip: {},
animationDurationUpdate: 1500,
animationEasingUpdate: 'quinticInOut',
series: [
{
type: 'graph',
layout: 'none',
roam: true,
symbolSize: 80,
label: {
show: true
},
edgeSymbol: ['none', 'arrow'],
edgeSymbolSize: [4, 10],
edgeLabel: {
normal: {
show: true,
textStyle: {
fontSize: 8
},
formatter: "{c}"
}
},
data: ${_nodesInfo},
links: ${_linksInfo},
lineStyle: {
opacity: 0.9,
width: 2,
curveness: -0.1
}
}
]
};
if (option && typeof option === 'object') {
myChart.setOption(option);
}
window.addEventListener('resize', myChart.resize);
</script>
</body>
</html>
`
}
// 输入正常锁信息的html
function product_normalinfo_to_html(cmd: string, echartsPath: string, mutexInfo:string, dimensionsList: string[], sourceList: object[], seriesList: object[]) {
let _dimensionsList = JSON.stringify(dimensionsList);
let _sourceList = JSON.stringify(sourceList);
let _seriesList = JSON.stringify(seriesList);
return `
<!DOCTYPE html>
<html lang="zh-CN" style="height: 55%">
<head>
<meta charset="utf-8">
</head>
<body style="height: 100%; margin: 0">
<br><br>
<div style="width:60%;margin:auto">
<h3>
</h3>
<p>${cmd}</p>
<h3>线</h3>
<ul>
${mutexInfo}
</ul>
</div>
<br><br><br>
<div id="container" style="height: 100%;width:60%;margin:auto"></div>
<script type="text/javascript" src="${echartsPath}"></script>
<script type="text/javascript">
var dom = document.getElementById('container');
var myChart = echarts.init(dom, null, {
renderer: 'canvas',
useDirtyRect: false
});
var app = {};
var option;
option = {
title: {
text: '临界区耗时'
},
legend: {},
tooltip: {},
dataset: {
dimensions: ${_dimensionsList},
source: ${_sourceList}
},
xAxis: { type: 'category' },
yAxis: {},
// Declare several bar series, each will be mapped
// to a column of dataset.source by default.
series: ${_seriesList}
};
if (option && typeof option === 'object') {
myChart.setOption(option);
}
window.addEventListener('resize', myChart.resize);
</script>
</body>
</html>
`
}
// 线程退出但是未释放锁
// fatal:
// - pid: 23773
// mutexes:
// - 0x7ffd08d622d8
// 输出线程退出但是未释放锁的html
function product_fatalinfo_to_html(cmd: string, fatalInfo:string) {
return `
<!DOCTYPE html>
<html lang="zh-CN" style="height: 55%">
<head>
<meta charset="utf-8">
</head>
<body style="height: 100%; margin: 0">
<br><br>
<div style="height: 100%;width:60%;margin:auto">
<h3>
</h3>
<p>${cmd}</p>
<h3></h3>
<ul>
${fatalInfo}
</ul>
</div>
</body>
</html>
`
}
// 发生死锁
// deadlock:
// cycle:
// - 0x7ffdd4f33b50
// - 0x7ffdd4f33b28
// threadid:
// - 23446
// - 23445
interface DetailInfo {
[key:string]: string
}
interface MutexInfo{
pid: number,
details: DetailInfo,
totalTime: number,
condWaitTime: number
}
interface DeadlockInfo{
cycle: number [],
threadid: number[]
}
interface FatalInfo{
pid: number,
mutexes: number[]
}
interface SourceInfo {
[key:string]: any
};
function parse_mutexInfo(mutexObj:MutexInfo[], sinfoList:SourceInfo[], dimensionsList:string[], seriesList: object[]):string {
let miStr: string = ``;
let mutexSet = new Set<string>();
mutexObj.forEach(obj =>{
let sinfo:SourceInfo = {};
sinfo['product'] = `线程 ${obj.pid}`;
if(obj.condWaitTime){
miStr += `
<li>线 ${obj.pid} ${obj.totalTime} ${obj.condWaitTime} .
<ul>
`;
}else{
miStr += `
<li>线 ${obj.pid} ${obj.totalTime} .
<ul>
`;
}
for (const key1 in obj.details) {
let info = obj.details[key1].split('-');
if(info.length >= 3){
let key = '互斥量 0x'+Number(key1).toString(16);
sinfo[key] = Number(info[1]);
mutexSet.add(key);
if(Number(info[2])){
miStr += `
<li>
(${key}) ${info[0]} , ${info[1]} , ${info[2]} .
</li>
`
}else{
miStr += `
<li>
(${key}) ${info[0]} , ${info[1]} .
</li>
`
}
}
}
miStr += `
</ul>
</li>
`
sinfoList.push(sinfo);
});
dimensionsList.push('product');
mutexSet.forEach((mutex)=>{
dimensionsList.push(mutex);
});
for (let index = 0; index < sinfoList.length; index++) {
seriesList.push({type:'bar'});
}
return miStr;
}
function parse_fatalInfo(fatalInfoList:FatalInfo[]) {
let fatalStr =``;
fatalInfoList.forEach(fatal=>{
fatalStr += `
<li> 线 ${fatal.pid} 退,
<ul>
`;
let tmp = '';
fatal.mutexes.forEach(m=>{
tmp = '0x' + m.toString(16);
fatalStr += `<li> ${tmp} </li>`;
})
fatalStr += `
</ul>
</li>
`;
})
return fatalStr;
}
// <li>
// 线程 1005 已经拥有互斥量(0x2342fff), 继续申请互斥量(0x2342fffff)
// </li>
// <li>
// 线程 1002 已经拥有互斥量(0x2342fff), 继续申请互斥量(0x2342fffff)
// </li>
// <li>
// 线程 1001 已经拥有互斥量(0x2342fff), 继续申请互斥量(0x2342fffff)
// </li>
function parse_deadlockInfo(dlInfo:DeadlockInfo, dataList: object[], linksList: object[]) {
let miStr = ``;
if(dlInfo.cycle.length != dlInfo.threadid.length)
{
return miStr;
}
dlInfo.threadid.forEach((value, index)=>{
if(dlInfo.cycle[index]){
let tmp1 = '0x'+dlInfo.cycle[index].toString(16);
let tmp2 = '0x'+dlInfo.cycle[(index+1)%dlInfo.cycle.length].toString(16);
let val = `线程 ${value} 已经拥有互斥量(${tmp1}), 继续申请互斥量(${tmp2})`;
miStr += `
<li>
${val}.
</li>`;
let pos = circledNodesPosition(300, 300, index, dlInfo.cycle.length);
dataList.push({
name: `互斥量 \n(${tmp1})`,
x: pos.x,
y: pos.y,
});
linksList.push({
source: index,
target: (index+1)%dlInfo.cycle.length,
value: `线程 ${value}`,
lineStyle: {
curveness: 0.2
}
});
}
});
return miStr;
}
export function prase_yaml2html(cmd: string, uri: string, webView: vscode.Webview, str: string) {
let ymlObj = YAML.parse(str);
const diskPath = vscode.Uri.file(join(uri, 'static', 'echarts.min.js'));
const scriptUri = diskPath.with({ scheme: 'vscode-resource' }).toString();
if(ymlObj.warn){
if(ymlObj.normalInfo?.mutex){
let sinfoList:SourceInfo[] = [];
let dimensionsList:string[] = [];
let seriesList: object[] = [];
let miStr = parse_mutexInfo(ymlObj.normalInfo.mutex, sinfoList, dimensionsList, seriesList);
return product_normalinfo_to_html(cmd, scriptUri, miStr, dimensionsList, sinfoList, seriesList);
}
}
if(ymlObj.fatal){
return product_fatalinfo_to_html(cmd, parse_fatalInfo(ymlObj.fatal));
}
if(ymlObj.deadlock){
let dataList: object[] = [];
let linksList: object[] = [];
let dlStr = parse_deadlockInfo(ymlObj.deadlock, dataList, linksList);
return product_deadlockinfo_to_html(cmd, scriptUri, dlStr, dataList, linksList);
}
return ``;
}

45
detect-plugin/static/echarts.min.js vendored Normal file

File diff suppressed because one or more lines are too long

View File

@ -2024,6 +2024,11 @@ yallist@^4.0.0:
resolved "https://registry.npmmirror.com/yallist/-/yallist-4.0.0.tgz#9bb92790d9c0effec63be73519e11a35019a3a72"
integrity sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==
yaml@^2.1.3:
version "2.1.3"
resolved "https://registry.npmmirror.com/yaml/-/yaml-2.1.3.tgz#9b3a4c8aff9821b696275c79a8bee8399d945207"
integrity sha512-AacA8nRULjKMX2DvWvOAdBZMOfQlypSFkjcOcu9FalllIDJ1kvlREzcdIZmidQUqqeMv7jorHjq2HlLv/+c2lg==
yargs-parser@20.2.4:
version "20.2.4"
resolved "https://registry.npmmirror.com/yargs-parser/-/yargs-parser-20.2.4.tgz#b42890f14566796f85ae8e3a25290d205f154a54"

View File

@ -12,10 +12,12 @@
"echart": "^0.1.3",
"echarts": "^5.3.3",
"element-ui": "^2.15.9",
"vscode": "^1.1.37",
"vue": "2.6.14"
},
"devDependencies": {
"@types/node": "^16.11.25",
"@types/vscode-webview": "^1.57.0",
"@vitejs/plugin-legacy": "^1.7.1",
"@vue/runtime-dom": "^3.2.31",
"typescript": "~4.7.3",
@ -802,6 +804,14 @@
"node": ">= 8.0.0"
}
},
"node_modules/@tootallnate/once": {
"version": "1.1.2",
"resolved": "https://registry.npmmirror.com/@tootallnate/once/-/once-1.1.2.tgz",
"integrity": "sha512-RbzJvlNzmRq5c3O09UipeuXno4tA1FE6ikOjxZK0tuxVv3412l64l5t1W5pj4+rJq9vpkm/kwiR07aZXnsKPxw==",
"engines": {
"node": ">= 6"
}
},
"node_modules/@types/node": {
"version": "16.11.56",
"resolved": "https://registry.npmmirror.com/@types/node/-/node-16.11.56.tgz",
@ -814,6 +824,12 @@
"integrity": "sha512-5eQEtSCoESnh2FsiLTxE121IiE60hnMqcb435fShf4bpLRjEu1Eoekht23y6zXS9Ts3l+Szu3TARnTsA0GkOkQ==",
"dev": true
},
"node_modules/@types/vscode-webview": {
"version": "1.57.0",
"resolved": "https://registry.npmmirror.com/@types/vscode-webview/-/vscode-webview-1.57.0.tgz",
"integrity": "sha512-x3Cb/SMa1IwRHfSvKaZDZOTh4cNoG505c3NjTqGlMC082m++x/ETUmtYniDsw6SSmYzZXO8KBNhYxR0+VqymqA==",
"dev": true
},
"node_modules/@vitejs/plugin-legacy": {
"version": "1.8.2",
"resolved": "https://registry.npmmirror.com/@vitejs/plugin-legacy/-/plugin-legacy-1.8.2.tgz",
@ -1194,6 +1210,17 @@
"node": ">= 0.6"
}
},
"node_modules/agent-base": {
"version": "6.0.2",
"resolved": "https://registry.npmmirror.com/agent-base/-/agent-base-6.0.2.tgz",
"integrity": "sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==",
"dependencies": {
"debug": "4"
},
"engines": {
"node": ">= 6.0.0"
}
},
"node_modules/ansi-styles": {
"version": "3.2.1",
"resolved": "https://registry.npmmirror.com/ansi-styles/-/ansi-styles-3.2.1.tgz",
@ -1254,12 +1281,31 @@
"resolved": "https://registry.npmmirror.com/regenerator-runtime/-/regenerator-runtime-0.11.1.tgz",
"integrity": "sha512-MguG95oij0fC3QV3URf4V2SDYGJhJnJGqvIIgdECeODCT98wSWDAJ94SSuVpYQUoTcGUIL6L4yNB7j1DFFHSBg=="
},
"node_modules/balanced-match": {
"version": "1.0.2",
"resolved": "https://registry.npmmirror.com/balanced-match/-/balanced-match-1.0.2.tgz",
"integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw=="
},
"node_modules/bluebird": {
"version": "3.7.2",
"resolved": "https://registry.npmmirror.com/bluebird/-/bluebird-3.7.2.tgz",
"integrity": "sha512-XpNj6GDQzdfW+r2Wnn7xiSAd7TM3jzkxGXBGTtWKuSXv1xUV+azxAm8jdWZN06QTQk+2N2XB9jRDkvbmQmcRtg==",
"dev": true
},
"node_modules/brace-expansion": {
"version": "1.1.11",
"resolved": "https://registry.npmmirror.com/brace-expansion/-/brace-expansion-1.1.11.tgz",
"integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==",
"dependencies": {
"balanced-match": "^1.0.0",
"concat-map": "0.0.1"
}
},
"node_modules/browser-stdout": {
"version": "1.3.1",
"resolved": "https://registry.npmmirror.com/browser-stdout/-/browser-stdout-1.3.1.tgz",
"integrity": "sha512-qhAVI1+Av2X7qelOfAIYwXONood6XlZE/fXaBSmW/T5SzLAmCgzi+eiWE7fUvbHaeNBQH13UftjpXxsfLkMpgw=="
},
"node_modules/browserslist": {
"version": "4.21.3",
"resolved": "https://registry.npmmirror.com/browserslist/-/browserslist-4.21.3.tgz",
@ -1278,6 +1324,11 @@
"node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7"
}
},
"node_modules/buffer-from": {
"version": "1.1.2",
"resolved": "https://registry.npmmirror.com/buffer-from/-/buffer-from-1.1.2.tgz",
"integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ=="
},
"node_modules/cache-content-type": {
"version": "1.0.1",
"resolved": "https://registry.npmmirror.com/cache-content-type/-/cache-content-type-1.0.1.tgz",
@ -1343,6 +1394,16 @@
"integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==",
"dev": true
},
"node_modules/commander": {
"version": "2.15.1",
"resolved": "https://registry.npmmirror.com/commander/-/commander-2.15.1.tgz",
"integrity": "sha512-VlfT9F3V0v+jr4yxPc5gg9s62/fIVWsd2Bk2iD435um1NlGMYdVCq+MjcXnhYq2icNOizHr1kK+5TI6H0Hy0ag=="
},
"node_modules/concat-map": {
"version": "0.0.1",
"resolved": "https://registry.npmmirror.com/concat-map/-/concat-map-0.0.1.tgz",
"integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg=="
},
"node_modules/consolidate": {
"version": "0.16.0",
"resolved": "https://registry.npmmirror.com/consolidate/-/consolidate-0.16.0.tgz",
@ -1489,6 +1550,14 @@
"npm": "1.2.8000 || >= 1.4.16"
}
},
"node_modules/diff": {
"version": "3.5.0",
"resolved": "https://registry.npmmirror.com/diff/-/diff-3.5.0.tgz",
"integrity": "sha512-A46qtFgd+g7pDZinpnwiRJtxbC1hpgf0uzP3iG89scHk0AUC7A1TGxf5OiiOUv/JMZR8GOt8hL900hV0bOy5xA==",
"engines": {
"node": ">=0.3.1"
}
},
"node_modules/dom-serializer": {
"version": "1.4.1",
"resolved": "https://registry.npmmirror.com/dom-serializer/-/dom-serializer-1.4.1.tgz",
@ -1628,6 +1697,19 @@
"integrity": "sha512-p92if5Nz619I0w+akJrLZH0MX0Pb5DX39XOwQTtXSdQQOaYH03S1uIQp4mhOZtAXrxq4ViO67YTiLBo2638o9A==",
"dev": true
},
"node_modules/es6-promise": {
"version": "4.2.8",
"resolved": "https://registry.npmmirror.com/es6-promise/-/es6-promise-4.2.8.tgz",
"integrity": "sha512-HJDGx5daxeIvxdBxvG2cb9g4tEvwIk3i8+nhX0yGrYmZUzbkdg8QbDevheDB8gd0//uPj4c1EQua8Q+MViT0/w=="
},
"node_modules/es6-promisify": {
"version": "5.0.0",
"resolved": "https://registry.npmmirror.com/es6-promisify/-/es6-promisify-5.0.0.tgz",
"integrity": "sha512-C+d6UdsYDk0lMebHNR4S2NybQMMngAOnOwYBQjTOiv0MkoJMP0Myw2mgpDLBcpfCmRLxyFqYhS/CfOENq4SJhQ==",
"dependencies": {
"es6-promise": "^4.0.3"
}
},
"node_modules/esbuild": {
"version": "0.14.54",
"resolved": "https://registry.npmmirror.com/esbuild/-/esbuild-0.14.54.tgz",
@ -2002,7 +2084,6 @@
"version": "1.0.5",
"resolved": "https://registry.npmmirror.com/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz",
"integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==",
"dev": true,
"engines": {
"node": ">=0.8.0"
}
@ -2036,6 +2117,11 @@
"node": ">=10"
}
},
"node_modules/fs.realpath": {
"version": "1.0.0",
"resolved": "https://registry.npmmirror.com/fs.realpath/-/fs.realpath-1.0.0.tgz",
"integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw=="
},
"node_modules/fsevents": {
"version": "2.3.2",
"resolved": "https://registry.npmmirror.com/fsevents/-/fsevents-2.3.2.tgz",
@ -2065,6 +2151,22 @@
"node": ">=6.9.0"
}
},
"node_modules/glob": {
"version": "7.2.3",
"resolved": "https://registry.npmmirror.com/glob/-/glob-7.2.3.tgz",
"integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==",
"dependencies": {
"fs.realpath": "^1.0.0",
"inflight": "^1.0.4",
"inherits": "2",
"minimatch": "^3.1.1",
"once": "^1.3.0",
"path-is-absolute": "^1.0.0"
},
"engines": {
"node": "*"
}
},
"node_modules/globals": {
"version": "11.12.0",
"resolved": "https://registry.npmmirror.com/globals/-/globals-11.12.0.tgz",
@ -2080,6 +2182,14 @@
"integrity": "sha512-9ByhssR2fPVsNZj478qUUbKfmL0+t5BDVyjShtyZZLiK7ZDAArFFfopyOTj0M05wE2tJPisA4iTnnXl2YoPvOA==",
"dev": true
},
"node_modules/growl": {
"version": "1.10.5",
"resolved": "https://registry.npmmirror.com/growl/-/growl-1.10.5.tgz",
"integrity": "sha512-qBr4OuELkhPenW6goKVXiv47US3clb3/IbuWF9KNKEijAy9oeHxU9IgzjvJhHkUzhaj7rOUD7+YGWqUjLp5oSA==",
"engines": {
"node": ">=4.x"
}
},
"node_modules/has": {
"version": "1.0.3",
"resolved": "https://registry.npmmirror.com/has/-/has-1.0.3.tgz",
@ -2096,7 +2206,6 @@
"version": "3.0.0",
"resolved": "https://registry.npmmirror.com/has-flag/-/has-flag-3.0.0.tgz",
"integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==",
"dev": true,
"engines": {
"node": ">=4"
}
@ -2191,6 +2300,40 @@
"node": ">= 0.6"
}
},
"node_modules/http-proxy-agent": {
"version": "4.0.1",
"resolved": "https://registry.npmmirror.com/http-proxy-agent/-/http-proxy-agent-4.0.1.tgz",
"integrity": "sha512-k0zdNgqWTGA6aeIRVpvfVob4fL52dTfaehylg0Y4UvSySvOq/Y+BOyPrgpUrA7HylqvU8vIZGsRuXmspskV0Tg==",
"dependencies": {
"@tootallnate/once": "1",
"agent-base": "6",
"debug": "4"
},
"engines": {
"node": ">= 6"
}
},
"node_modules/https-proxy-agent": {
"version": "5.0.1",
"resolved": "https://registry.npmmirror.com/https-proxy-agent/-/https-proxy-agent-5.0.1.tgz",
"integrity": "sha512-dFcAjpTQFgoLMzC2VwU+C/CbS7uRL0lWmxDITmqm7C+7F0Odmj6s9l6alZc6AELXhrnggM2CeWSXHGOdX2YtwA==",
"dependencies": {
"agent-base": "6",
"debug": "4"
},
"engines": {
"node": ">= 6"
}
},
"node_modules/inflight": {
"version": "1.0.6",
"resolved": "https://registry.npmmirror.com/inflight/-/inflight-1.0.6.tgz",
"integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==",
"dependencies": {
"once": "^1.3.0",
"wrappy": "1"
}
},
"node_modules/inherits": {
"version": "2.0.4",
"resolved": "https://registry.npmmirror.com/inherits/-/inherits-2.0.4.tgz",
@ -2428,6 +2571,118 @@
"node": ">= 0.6"
}
},
"node_modules/minimatch": {
"version": "3.1.2",
"resolved": "https://registry.npmmirror.com/minimatch/-/minimatch-3.1.2.tgz",
"integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==",
"dependencies": {
"brace-expansion": "^1.1.7"
},
"engines": {
"node": "*"
}
},
"node_modules/minimist": {
"version": "0.0.8",
"resolved": "https://registry.npmmirror.com/minimist/-/minimist-0.0.8.tgz",
"integrity": "sha512-miQKw5Hv4NS1Psg2517mV4e4dYNaO3++hjAvLOAzKqZ61rH8NS1SK+vbfBWZ5PY/Me/bEWhUwqMghEW5Fb9T7Q=="
},
"node_modules/mkdirp": {
"version": "0.5.1",
"resolved": "https://registry.npmmirror.com/mkdirp/-/mkdirp-0.5.1.tgz",
"integrity": "sha512-SknJC52obPfGQPnjIkXbmA6+5H15E+fR+E4iR2oQ3zzCLbd7/ONua69R/Gw7AgkTLsRG+r5fzksYwWe1AgTyWA==",
"deprecated": "Legacy versions of mkdirp are no longer supported. Please update to mkdirp 1.x. (Note that the API surface has changed to use Promises in 1.x.)",
"dependencies": {
"minimist": "0.0.8"
},
"bin": {
"mkdirp": "bin/cmd.js"
}
},
"node_modules/mocha": {
"version": "5.2.0",
"resolved": "https://registry.npmmirror.com/mocha/-/mocha-5.2.0.tgz",
"integrity": "sha512-2IUgKDhc3J7Uug+FxMXuqIyYzH7gJjXECKe/w43IGgQHTSj3InJi+yAA7T24L9bQMRKiUEHxEX37G5JpVUGLcQ==",
"dependencies": {
"browser-stdout": "1.3.1",
"commander": "2.15.1",
"debug": "3.1.0",
"diff": "3.5.0",
"escape-string-regexp": "1.0.5",
"glob": "7.1.2",
"growl": "1.10.5",
"he": "1.1.1",
"minimatch": "3.0.4",
"mkdirp": "0.5.1",
"supports-color": "5.4.0"
},
"bin": {
"_mocha": "bin/_mocha",
"mocha": "bin/mocha"
},
"engines": {
"node": ">= 4.0.0"
}
},
"node_modules/mocha/node_modules/debug": {
"version": "3.1.0",
"resolved": "https://registry.npmmirror.com/debug/-/debug-3.1.0.tgz",
"integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==",
"dependencies": {
"ms": "2.0.0"
}
},
"node_modules/mocha/node_modules/glob": {
"version": "7.1.2",
"resolved": "https://registry.npmmirror.com/glob/-/glob-7.1.2.tgz",
"integrity": "sha512-MJTUg1kjuLeQCJ+ccE4Vpa6kKVXkPYJ2mOCQyUuKLcLQsdrMCpBPUi8qVE6+YuaJkozeA9NusTAw3hLr8Xe5EQ==",
"dependencies": {
"fs.realpath": "^1.0.0",
"inflight": "^1.0.4",
"inherits": "2",
"minimatch": "^3.0.4",
"once": "^1.3.0",
"path-is-absolute": "^1.0.0"
},
"engines": {
"node": "*"
}
},
"node_modules/mocha/node_modules/he": {
"version": "1.1.1",
"resolved": "https://registry.npmmirror.com/he/-/he-1.1.1.tgz",
"integrity": "sha512-z/GDPjlRMNOa2XJiB4em8wJpuuBfrFOlYKTZxtpkdr1uPdibHI8rYA3MY0KDObpVyaes0e/aunid/t88ZI2EKA==",
"bin": {
"he": "bin/he"
}
},
"node_modules/mocha/node_modules/minimatch": {
"version": "3.0.4",
"resolved": "https://registry.npmmirror.com/minimatch/-/minimatch-3.0.4.tgz",
"integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==",
"dependencies": {
"brace-expansion": "^1.1.7"
},
"engines": {
"node": "*"
}
},
"node_modules/mocha/node_modules/ms": {
"version": "2.0.0",
"resolved": "https://registry.npmmirror.com/ms/-/ms-2.0.0.tgz",
"integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A=="
},
"node_modules/mocha/node_modules/supports-color": {
"version": "5.4.0",
"resolved": "https://registry.npmmirror.com/supports-color/-/supports-color-5.4.0.tgz",
"integrity": "sha512-zjaXglF5nnWpsq470jSv6P9DwPvgLkuapYmfDm3JWOm0vkNTVF2tI4UrN2r6jH1qM/uc/WtxYY1hYoA2dOKj5w==",
"dependencies": {
"has-flag": "^3.0.0"
},
"engines": {
"node": ">=4"
}
},
"node_modules/ms": {
"version": "2.1.2",
"resolved": "https://registry.npmmirror.com/ms/-/ms-2.1.2.tgz",
@ -2475,6 +2730,14 @@
"node": ">= 0.8"
}
},
"node_modules/once": {
"version": "1.4.0",
"resolved": "https://registry.npmmirror.com/once/-/once-1.4.0.tgz",
"integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==",
"dependencies": {
"wrappy": "1"
}
},
"node_modules/only": {
"version": "0.0.2",
"resolved": "https://registry.npmmirror.com/only/-/only-0.0.2.tgz",
@ -2488,6 +2751,14 @@
"node": ">= 0.8"
}
},
"node_modules/path-is-absolute": {
"version": "1.0.1",
"resolved": "https://registry.npmmirror.com/path-is-absolute/-/path-is-absolute-1.0.1.tgz",
"integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==",
"engines": {
"node": ">=0.10.0"
}
},
"node_modules/path-parse": {
"version": "1.0.7",
"resolved": "https://registry.npmmirror.com/path-parse/-/path-parse-1.0.7.tgz",
@ -2645,7 +2916,6 @@
"version": "0.6.1",
"resolved": "https://registry.npmmirror.com/source-map/-/source-map-0.6.1.tgz",
"integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==",
"dev": true,
"engines": {
"node": ">=0.10.0"
}
@ -2659,6 +2929,15 @@
"node": ">=0.10.0"
}
},
"node_modules/source-map-support": {
"version": "0.5.21",
"resolved": "https://registry.npmmirror.com/source-map-support/-/source-map-support-0.5.21.tgz",
"integrity": "sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==",
"dependencies": {
"buffer-from": "^1.0.0",
"source-map": "^0.6.0"
}
},
"node_modules/sourcemap-codec": {
"version": "1.4.8",
"resolved": "https://registry.npmmirror.com/sourcemap-codec/-/sourcemap-codec-1.4.8.tgz",
@ -2973,6 +3252,96 @@
"node": ">= 8"
}
},
"node_modules/vscode": {
"version": "1.1.37",
"resolved": "https://registry.npmmirror.com/vscode/-/vscode-1.1.37.tgz",
"integrity": "sha512-vJNj6IlN7IJPdMavlQa1KoFB3Ihn06q1AiN3ZFI/HfzPNzbKZWPPuiU+XkpNOfGU5k15m4r80nxNPlM7wcc0wg==",
"deprecated": "This package is deprecated in favor of @types/vscode and vscode-test. For more information please read: https://code.visualstudio.com/updates/v1_36#_splitting-vscode-package-into-typesvscode-and-vscodetest",
"dependencies": {
"glob": "^7.1.2",
"http-proxy-agent": "^4.0.1",
"https-proxy-agent": "^5.0.0",
"mocha": "^5.2.0",
"semver": "^5.4.1",
"source-map-support": "^0.5.0",
"vscode-test": "^0.4.1"
},
"bin": {
"vscode-install": "bin/install"
},
"engines": {
"node": ">=8.9.3"
}
},
"node_modules/vscode-test": {
"version": "0.4.3",
"resolved": "https://registry.npmmirror.com/vscode-test/-/vscode-test-0.4.3.tgz",
"integrity": "sha512-EkMGqBSefZH2MgW65nY05rdRSko15uvzq4VAPM5jVmwYuFQKE7eikKXNJDRxL+OITXHB6pI+a3XqqD32Y3KC5w==",
"deprecated": "This package has been renamed to @vscode/test-electron, please update to the new name",
"dependencies": {
"http-proxy-agent": "^2.1.0",
"https-proxy-agent": "^2.2.1"
},
"engines": {
"node": ">=8.9.3"
}
},
"node_modules/vscode-test/node_modules/agent-base": {
"version": "4.3.0",
"resolved": "https://registry.npmmirror.com/agent-base/-/agent-base-4.3.0.tgz",
"integrity": "sha512-salcGninV0nPrwpGNn4VTXBb1SOuXQBiqbrNXoeizJsHrsL6ERFM2Ne3JUSBWRE6aeNJI2ROP/WEEIDUiDe3cg==",
"dependencies": {
"es6-promisify": "^5.0.0"
},
"engines": {
"node": ">= 4.0.0"
}
},
"node_modules/vscode-test/node_modules/debug": {
"version": "3.1.0",
"resolved": "https://registry.npmmirror.com/debug/-/debug-3.1.0.tgz",
"integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==",
"dependencies": {
"ms": "2.0.0"
}
},
"node_modules/vscode-test/node_modules/http-proxy-agent": {
"version": "2.1.0",
"resolved": "https://registry.npmmirror.com/http-proxy-agent/-/http-proxy-agent-2.1.0.tgz",
"integrity": "sha512-qwHbBLV7WviBl0rQsOzH6o5lwyOIvwp/BdFnvVxXORldu5TmjFfjzBcWUWS5kWAZhmv+JtiDhSuQCp4sBfbIgg==",
"dependencies": {
"agent-base": "4",
"debug": "3.1.0"
},
"engines": {
"node": ">= 4.5.0"
}
},
"node_modules/vscode-test/node_modules/https-proxy-agent": {
"version": "2.2.4",
"resolved": "https://registry.npmmirror.com/https-proxy-agent/-/https-proxy-agent-2.2.4.tgz",
"integrity": "sha512-OmvfoQ53WLjtA9HeYP9RNrWMJzzAz1JGaSFr1nijg0PVR1JaD/xbJq1mdEIIlxGpXp9eSe/O2LgU9DJmTPd0Eg==",
"dependencies": {
"agent-base": "^4.3.0",
"debug": "^3.1.0"
},
"engines": {
"node": ">= 4.5.0"
}
},
"node_modules/vscode-test/node_modules/ms": {
"version": "2.0.0",
"resolved": "https://registry.npmmirror.com/ms/-/ms-2.0.0.tgz",
"integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A=="
},
"node_modules/vscode/node_modules/semver": {
"version": "5.7.1",
"resolved": "https://registry.npmmirror.com/semver/-/semver-5.7.1.tgz",
"integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==",
"bin": {
"semver": "bin/semver"
}
},
"node_modules/vue": {
"version": "2.6.14",
"resolved": "https://registry.npmmirror.com/vue/-/vue-2.6.14.tgz",
@ -3041,6 +3410,11 @@
"integrity": "sha512-h9atBP/bsZohWpHnr+2sic8Iecb60GxftXsWNLLLSqewgIsGzByd2gcIID4nXcG+3tNe4GQG3dLcff3kXupdRA==",
"dev": true
},
"node_modules/wrappy": {
"version": "1.0.2",
"resolved": "https://registry.npmmirror.com/wrappy/-/wrappy-1.0.2.tgz",
"integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ=="
},
"node_modules/yallist": {
"version": "2.1.2",
"resolved": "https://registry.npmmirror.com/yallist/-/yallist-2.1.2.tgz",
@ -3625,6 +3999,11 @@
"picomatch": "^2.2.2"
}
},
"@tootallnate/once": {
"version": "1.1.2",
"resolved": "https://registry.npmmirror.com/@tootallnate/once/-/once-1.1.2.tgz",
"integrity": "sha512-RbzJvlNzmRq5c3O09UipeuXno4tA1FE6ikOjxZK0tuxVv3412l64l5t1W5pj4+rJq9vpkm/kwiR07aZXnsKPxw=="
},
"@types/node": {
"version": "16.11.56",
"resolved": "https://registry.npmmirror.com/@types/node/-/node-16.11.56.tgz",
@ -3637,6 +4016,12 @@
"integrity": "sha512-5eQEtSCoESnh2FsiLTxE121IiE60hnMqcb435fShf4bpLRjEu1Eoekht23y6zXS9Ts3l+Szu3TARnTsA0GkOkQ==",
"dev": true
},
"@types/vscode-webview": {
"version": "1.57.0",
"resolved": "https://registry.npmmirror.com/@types/vscode-webview/-/vscode-webview-1.57.0.tgz",
"integrity": "sha512-x3Cb/SMa1IwRHfSvKaZDZOTh4cNoG505c3NjTqGlMC082m++x/ETUmtYniDsw6SSmYzZXO8KBNhYxR0+VqymqA==",
"dev": true
},
"@vitejs/plugin-legacy": {
"version": "1.8.2",
"resolved": "https://registry.npmmirror.com/@vitejs/plugin-legacy/-/plugin-legacy-1.8.2.tgz",
@ -3974,6 +4359,14 @@
"negotiator": "0.6.3"
}
},
"agent-base": {
"version": "6.0.2",
"resolved": "https://registry.npmmirror.com/agent-base/-/agent-base-6.0.2.tgz",
"integrity": "sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==",
"requires": {
"debug": "4"
}
},
"ansi-styles": {
"version": "3.2.1",
"resolved": "https://registry.npmmirror.com/ansi-styles/-/ansi-styles-3.2.1.tgz",
@ -4028,12 +4421,31 @@
}
}
},
"balanced-match": {
"version": "1.0.2",
"resolved": "https://registry.npmmirror.com/balanced-match/-/balanced-match-1.0.2.tgz",
"integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw=="
},
"bluebird": {
"version": "3.7.2",
"resolved": "https://registry.npmmirror.com/bluebird/-/bluebird-3.7.2.tgz",
"integrity": "sha512-XpNj6GDQzdfW+r2Wnn7xiSAd7TM3jzkxGXBGTtWKuSXv1xUV+azxAm8jdWZN06QTQk+2N2XB9jRDkvbmQmcRtg==",
"dev": true
},
"brace-expansion": {
"version": "1.1.11",
"resolved": "https://registry.npmmirror.com/brace-expansion/-/brace-expansion-1.1.11.tgz",
"integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==",
"requires": {
"balanced-match": "^1.0.0",
"concat-map": "0.0.1"
}
},
"browser-stdout": {
"version": "1.3.1",
"resolved": "https://registry.npmmirror.com/browser-stdout/-/browser-stdout-1.3.1.tgz",
"integrity": "sha512-qhAVI1+Av2X7qelOfAIYwXONood6XlZE/fXaBSmW/T5SzLAmCgzi+eiWE7fUvbHaeNBQH13UftjpXxsfLkMpgw=="
},
"browserslist": {
"version": "4.21.3",
"resolved": "https://registry.npmmirror.com/browserslist/-/browserslist-4.21.3.tgz",
@ -4046,6 +4458,11 @@
"update-browserslist-db": "^1.0.5"
}
},
"buffer-from": {
"version": "1.1.2",
"resolved": "https://registry.npmmirror.com/buffer-from/-/buffer-from-1.1.2.tgz",
"integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ=="
},
"cache-content-type": {
"version": "1.0.1",
"resolved": "https://registry.npmmirror.com/cache-content-type/-/cache-content-type-1.0.1.tgz",
@ -4098,6 +4515,16 @@
"integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==",
"dev": true
},
"commander": {
"version": "2.15.1",
"resolved": "https://registry.npmmirror.com/commander/-/commander-2.15.1.tgz",
"integrity": "sha512-VlfT9F3V0v+jr4yxPc5gg9s62/fIVWsd2Bk2iD435um1NlGMYdVCq+MjcXnhYq2icNOizHr1kK+5TI6H0Hy0ag=="
},
"concat-map": {
"version": "0.0.1",
"resolved": "https://registry.npmmirror.com/concat-map/-/concat-map-0.0.1.tgz",
"integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg=="
},
"consolidate": {
"version": "0.16.0",
"resolved": "https://registry.npmmirror.com/consolidate/-/consolidate-0.16.0.tgz",
@ -4209,6 +4636,11 @@
"resolved": "https://registry.npmmirror.com/destroy/-/destroy-1.2.0.tgz",
"integrity": "sha512-2sJGJTaXIIaR1w4iJSNoN0hnMY7Gpc/n8D4qSCJw8QqFWXf7cuAgnEHxBpweaVcPevC2l3KpjYCx3NypQQgaJg=="
},
"diff": {
"version": "3.5.0",
"resolved": "https://registry.npmmirror.com/diff/-/diff-3.5.0.tgz",
"integrity": "sha512-A46qtFgd+g7pDZinpnwiRJtxbC1hpgf0uzP3iG89scHk0AUC7A1TGxf5OiiOUv/JMZR8GOt8hL900hV0bOy5xA=="
},
"dom-serializer": {
"version": "1.4.1",
"resolved": "https://registry.npmmirror.com/dom-serializer/-/dom-serializer-1.4.1.tgz",
@ -4335,6 +4767,19 @@
"integrity": "sha512-p92if5Nz619I0w+akJrLZH0MX0Pb5DX39XOwQTtXSdQQOaYH03S1uIQp4mhOZtAXrxq4ViO67YTiLBo2638o9A==",
"dev": true
},
"es6-promise": {
"version": "4.2.8",
"resolved": "https://registry.npmmirror.com/es6-promise/-/es6-promise-4.2.8.tgz",
"integrity": "sha512-HJDGx5daxeIvxdBxvG2cb9g4tEvwIk3i8+nhX0yGrYmZUzbkdg8QbDevheDB8gd0//uPj4c1EQua8Q+MViT0/w=="
},
"es6-promisify": {
"version": "5.0.0",
"resolved": "https://registry.npmmirror.com/es6-promisify/-/es6-promisify-5.0.0.tgz",
"integrity": "sha512-C+d6UdsYDk0lMebHNR4S2NybQMMngAOnOwYBQjTOiv0MkoJMP0Myw2mgpDLBcpfCmRLxyFqYhS/CfOENq4SJhQ==",
"requires": {
"es6-promise": "^4.0.3"
}
},
"esbuild": {
"version": "0.14.54",
"resolved": "https://registry.npmmirror.com/esbuild/-/esbuild-0.14.54.tgz",
@ -4518,8 +4963,7 @@
"escape-string-regexp": {
"version": "1.0.5",
"resolved": "https://registry.npmmirror.com/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz",
"integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==",
"dev": true
"integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg=="
},
"estree-walker": {
"version": "2.0.2",
@ -4544,6 +4988,11 @@
"universalify": "^2.0.0"
}
},
"fs.realpath": {
"version": "1.0.0",
"resolved": "https://registry.npmmirror.com/fs.realpath/-/fs.realpath-1.0.0.tgz",
"integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw=="
},
"fsevents": {
"version": "2.3.2",
"resolved": "https://registry.npmmirror.com/fsevents/-/fsevents-2.3.2.tgz",
@ -4563,6 +5012,19 @@
"integrity": "sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==",
"dev": true
},
"glob": {
"version": "7.2.3",
"resolved": "https://registry.npmmirror.com/glob/-/glob-7.2.3.tgz",
"integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==",
"requires": {
"fs.realpath": "^1.0.0",
"inflight": "^1.0.4",
"inherits": "2",
"minimatch": "^3.1.1",
"once": "^1.3.0",
"path-is-absolute": "^1.0.0"
}
},
"globals": {
"version": "11.12.0",
"resolved": "https://registry.npmmirror.com/globals/-/globals-11.12.0.tgz",
@ -4575,6 +5037,11 @@
"integrity": "sha512-9ByhssR2fPVsNZj478qUUbKfmL0+t5BDVyjShtyZZLiK7ZDAArFFfopyOTj0M05wE2tJPisA4iTnnXl2YoPvOA==",
"dev": true
},
"growl": {
"version": "1.10.5",
"resolved": "https://registry.npmmirror.com/growl/-/growl-1.10.5.tgz",
"integrity": "sha512-qBr4OuELkhPenW6goKVXiv47US3clb3/IbuWF9KNKEijAy9oeHxU9IgzjvJhHkUzhaj7rOUD7+YGWqUjLp5oSA=="
},
"has": {
"version": "1.0.3",
"resolved": "https://registry.npmmirror.com/has/-/has-1.0.3.tgz",
@ -4587,8 +5054,7 @@
"has-flag": {
"version": "3.0.0",
"resolved": "https://registry.npmmirror.com/has-flag/-/has-flag-3.0.0.tgz",
"integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==",
"dev": true
"integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw=="
},
"has-symbols": {
"version": "1.0.3",
@ -4661,6 +5127,34 @@
}
}
},
"http-proxy-agent": {
"version": "4.0.1",
"resolved": "https://registry.npmmirror.com/http-proxy-agent/-/http-proxy-agent-4.0.1.tgz",
"integrity": "sha512-k0zdNgqWTGA6aeIRVpvfVob4fL52dTfaehylg0Y4UvSySvOq/Y+BOyPrgpUrA7HylqvU8vIZGsRuXmspskV0Tg==",
"requires": {
"@tootallnate/once": "1",
"agent-base": "6",
"debug": "4"
}
},
"https-proxy-agent": {
"version": "5.0.1",
"resolved": "https://registry.npmmirror.com/https-proxy-agent/-/https-proxy-agent-5.0.1.tgz",
"integrity": "sha512-dFcAjpTQFgoLMzC2VwU+C/CbS7uRL0lWmxDITmqm7C+7F0Odmj6s9l6alZc6AELXhrnggM2CeWSXHGOdX2YtwA==",
"requires": {
"agent-base": "6",
"debug": "4"
}
},
"inflight": {
"version": "1.0.6",
"resolved": "https://registry.npmmirror.com/inflight/-/inflight-1.0.6.tgz",
"integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==",
"requires": {
"once": "^1.3.0",
"wrappy": "1"
}
},
"inherits": {
"version": "2.0.4",
"resolved": "https://registry.npmmirror.com/inherits/-/inherits-2.0.4.tgz",
@ -4856,6 +5350,94 @@
"mime-db": "1.52.0"
}
},
"minimatch": {
"version": "3.1.2",
"resolved": "https://registry.npmmirror.com/minimatch/-/minimatch-3.1.2.tgz",
"integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==",
"requires": {
"brace-expansion": "^1.1.7"
}
},
"minimist": {
"version": "0.0.8",
"resolved": "https://registry.npmmirror.com/minimist/-/minimist-0.0.8.tgz",
"integrity": "sha512-miQKw5Hv4NS1Psg2517mV4e4dYNaO3++hjAvLOAzKqZ61rH8NS1SK+vbfBWZ5PY/Me/bEWhUwqMghEW5Fb9T7Q=="
},
"mkdirp": {
"version": "0.5.1",
"resolved": "https://registry.npmmirror.com/mkdirp/-/mkdirp-0.5.1.tgz",
"integrity": "sha512-SknJC52obPfGQPnjIkXbmA6+5H15E+fR+E4iR2oQ3zzCLbd7/ONua69R/Gw7AgkTLsRG+r5fzksYwWe1AgTyWA==",
"requires": {
"minimist": "0.0.8"
}
},
"mocha": {
"version": "5.2.0",
"resolved": "https://registry.npmmirror.com/mocha/-/mocha-5.2.0.tgz",
"integrity": "sha512-2IUgKDhc3J7Uug+FxMXuqIyYzH7gJjXECKe/w43IGgQHTSj3InJi+yAA7T24L9bQMRKiUEHxEX37G5JpVUGLcQ==",
"requires": {
"browser-stdout": "1.3.1",
"commander": "2.15.1",
"debug": "3.1.0",
"diff": "3.5.0",
"escape-string-regexp": "1.0.5",
"glob": "7.1.2",
"growl": "1.10.5",
"he": "1.1.1",
"minimatch": "3.0.4",
"mkdirp": "0.5.1",
"supports-color": "5.4.0"
},
"dependencies": {
"debug": {
"version": "3.1.0",
"resolved": "https://registry.npmmirror.com/debug/-/debug-3.1.0.tgz",
"integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==",
"requires": {
"ms": "2.0.0"
}
},
"glob": {
"version": "7.1.2",
"resolved": "https://registry.npmmirror.com/glob/-/glob-7.1.2.tgz",
"integrity": "sha512-MJTUg1kjuLeQCJ+ccE4Vpa6kKVXkPYJ2mOCQyUuKLcLQsdrMCpBPUi8qVE6+YuaJkozeA9NusTAw3hLr8Xe5EQ==",
"requires": {
"fs.realpath": "^1.0.0",
"inflight": "^1.0.4",
"inherits": "2",
"minimatch": "^3.0.4",
"once": "^1.3.0",
"path-is-absolute": "^1.0.0"
}
},
"he": {
"version": "1.1.1",
"resolved": "https://registry.npmmirror.com/he/-/he-1.1.1.tgz",
"integrity": "sha512-z/GDPjlRMNOa2XJiB4em8wJpuuBfrFOlYKTZxtpkdr1uPdibHI8rYA3MY0KDObpVyaes0e/aunid/t88ZI2EKA=="
},
"minimatch": {
"version": "3.0.4",
"resolved": "https://registry.npmmirror.com/minimatch/-/minimatch-3.0.4.tgz",
"integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==",
"requires": {
"brace-expansion": "^1.1.7"
}
},
"ms": {
"version": "2.0.0",
"resolved": "https://registry.npmmirror.com/ms/-/ms-2.0.0.tgz",
"integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A=="
},
"supports-color": {
"version": "5.4.0",
"resolved": "https://registry.npmmirror.com/supports-color/-/supports-color-5.4.0.tgz",
"integrity": "sha512-zjaXglF5nnWpsq470jSv6P9DwPvgLkuapYmfDm3JWOm0vkNTVF2tI4UrN2r6jH1qM/uc/WtxYY1hYoA2dOKj5w==",
"requires": {
"has-flag": "^3.0.0"
}
}
}
},
"ms": {
"version": "2.1.2",
"resolved": "https://registry.npmmirror.com/ms/-/ms-2.1.2.tgz",
@ -4891,6 +5473,14 @@
"ee-first": "1.1.1"
}
},
"once": {
"version": "1.4.0",
"resolved": "https://registry.npmmirror.com/once/-/once-1.4.0.tgz",
"integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==",
"requires": {
"wrappy": "1"
}
},
"only": {
"version": "0.0.2",
"resolved": "https://registry.npmmirror.com/only/-/only-0.0.2.tgz",
@ -4901,6 +5491,11 @@
"resolved": "https://registry.npmmirror.com/parseurl/-/parseurl-1.3.3.tgz",
"integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ=="
},
"path-is-absolute": {
"version": "1.0.1",
"resolved": "https://registry.npmmirror.com/path-is-absolute/-/path-is-absolute-1.0.1.tgz",
"integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg=="
},
"path-parse": {
"version": "1.0.7",
"resolved": "https://registry.npmmirror.com/path-parse/-/path-parse-1.0.7.tgz",
@ -5023,8 +5618,7 @@
"source-map": {
"version": "0.6.1",
"resolved": "https://registry.npmmirror.com/source-map/-/source-map-0.6.1.tgz",
"integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==",
"dev": true
"integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g=="
},
"source-map-js": {
"version": "1.0.2",
@ -5032,6 +5626,15 @@
"integrity": "sha512-R0XvVJ9WusLiqTCEiGCmICCMplcCkIwwR11mOSD9CR5u+IXYdiseeEuXCVAjS54zqwkLcPNnmU4OeJ6tUrWhDw==",
"dev": true
},
"source-map-support": {
"version": "0.5.21",
"resolved": "https://registry.npmmirror.com/source-map-support/-/source-map-support-0.5.21.tgz",
"integrity": "sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==",
"requires": {
"buffer-from": "^1.0.0",
"source-map": "^0.6.0"
}
},
"sourcemap-codec": {
"version": "1.4.8",
"resolved": "https://registry.npmmirror.com/sourcemap-codec/-/sourcemap-codec-1.4.8.tgz",
@ -5246,6 +5849,77 @@
}
}
},
"vscode": {
"version": "1.1.37",
"resolved": "https://registry.npmmirror.com/vscode/-/vscode-1.1.37.tgz",
"integrity": "sha512-vJNj6IlN7IJPdMavlQa1KoFB3Ihn06q1AiN3ZFI/HfzPNzbKZWPPuiU+XkpNOfGU5k15m4r80nxNPlM7wcc0wg==",
"requires": {
"glob": "^7.1.2",
"http-proxy-agent": "^4.0.1",
"https-proxy-agent": "^5.0.0",
"mocha": "^5.2.0",
"semver": "^5.4.1",
"source-map-support": "^0.5.0",
"vscode-test": "^0.4.1"
},
"dependencies": {
"semver": {
"version": "5.7.1",
"resolved": "https://registry.npmmirror.com/semver/-/semver-5.7.1.tgz",
"integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ=="
}
}
},
"vscode-test": {
"version": "0.4.3",
"resolved": "https://registry.npmmirror.com/vscode-test/-/vscode-test-0.4.3.tgz",
"integrity": "sha512-EkMGqBSefZH2MgW65nY05rdRSko15uvzq4VAPM5jVmwYuFQKE7eikKXNJDRxL+OITXHB6pI+a3XqqD32Y3KC5w==",
"requires": {
"http-proxy-agent": "^2.1.0",
"https-proxy-agent": "^2.2.1"
},
"dependencies": {
"agent-base": {
"version": "4.3.0",
"resolved": "https://registry.npmmirror.com/agent-base/-/agent-base-4.3.0.tgz",
"integrity": "sha512-salcGninV0nPrwpGNn4VTXBb1SOuXQBiqbrNXoeizJsHrsL6ERFM2Ne3JUSBWRE6aeNJI2ROP/WEEIDUiDe3cg==",
"requires": {
"es6-promisify": "^5.0.0"
}
},
"debug": {
"version": "3.1.0",
"resolved": "https://registry.npmmirror.com/debug/-/debug-3.1.0.tgz",
"integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==",
"requires": {
"ms": "2.0.0"
}
},
"http-proxy-agent": {
"version": "2.1.0",
"resolved": "https://registry.npmmirror.com/http-proxy-agent/-/http-proxy-agent-2.1.0.tgz",
"integrity": "sha512-qwHbBLV7WviBl0rQsOzH6o5lwyOIvwp/BdFnvVxXORldu5TmjFfjzBcWUWS5kWAZhmv+JtiDhSuQCp4sBfbIgg==",
"requires": {
"agent-base": "4",
"debug": "3.1.0"
}
},
"https-proxy-agent": {
"version": "2.2.4",
"resolved": "https://registry.npmmirror.com/https-proxy-agent/-/https-proxy-agent-2.2.4.tgz",
"integrity": "sha512-OmvfoQ53WLjtA9HeYP9RNrWMJzzAz1JGaSFr1nijg0PVR1JaD/xbJq1mdEIIlxGpXp9eSe/O2LgU9DJmTPd0Eg==",
"requires": {
"agent-base": "^4.3.0",
"debug": "^3.1.0"
}
},
"ms": {
"version": "2.0.0",
"resolved": "https://registry.npmmirror.com/ms/-/ms-2.0.0.tgz",
"integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A=="
}
}
},
"vue": {
"version": "2.6.14",
"resolved": "https://registry.npmmirror.com/vue/-/vue-2.6.14.tgz",
@ -5302,6 +5976,11 @@
"integrity": "sha512-h9atBP/bsZohWpHnr+2sic8Iecb60GxftXsWNLLLSqewgIsGzByd2gcIID4nXcG+3tNe4GQG3dLcff3kXupdRA==",
"dev": true
},
"wrappy": {
"version": "1.0.2",
"resolved": "https://registry.npmmirror.com/wrappy/-/wrappy-1.0.2.tgz",
"integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ=="
},
"yallist": {
"version": "2.1.2",
"resolved": "https://registry.npmmirror.com/yallist/-/yallist-2.1.2.tgz",

View File

@ -12,6 +12,7 @@
"echart": "^0.1.3",
"echarts": "^5.3.3",
"element-ui": "^2.15.9",
"vscode": "^1.1.37",
"vue": "2.6.14"
},
"devDependencies": {
@ -24,6 +25,7 @@
"vite-plugin-vue2": "^1.9.3",
"vue-template-babel-compiler": "^1.2.0",
"vue-template-compiler": "2.6.14",
"vue-tsc": "^0.37.3"
"vue-tsc": "^0.37.3",
"@types/vscode-webview": "^1.57.0"
}
}

View File

@ -1,28 +1,29 @@
<template>
<div id="app">
<template>
<el-tabs v-model="activeName" @tab-click="handleClick" style="width: 80%;margin: auto;">
<el-tabs v-model="activeName" @tab-click="handleClick" type="border-card" style="width: 80%;margin: auto;">
<el-tab-pane label="本地检测" name="first">
<div style="width: 60%;margin:auto">
<br />
<el-radio v-model="radio" label="1">检测指定进程</el-radio>
<el-radio v-model="radio" label="2">检测可执行程序</el-radio>
<div id="pid" v-if="radio == '1'">
<div id="pid">
<br />
<el-input v-model="local_pid_input" placeholder="请输入被检测进程PID"></el-input>
</div>
<div id="comm" v-if="radio == '2'">
<br />
<el-input v-model="local_cmd_input" placeholder="请输入被检测程序命令行"></el-input>
<br /><br />
<el-input v-model="local_env_input" placeholder="请输入被检测程序环境变量"></el-input>
</div>
<br />
<el-input placeholder="请输入管理员密码" v-model="local_passwd_input" show-password></el-input>
<el-input placeholder="请输入用户密码" v-model="local_passwd_input" show-password></el-input>
<br /> <br />
<el-button type="primary" v-on:click="begin_local_check(1,radio)">开始检测</el-button>
<el-button type="primary" v-on:click="begin_local_check()">开始检测</el-button>
</div>
<br />
<el-card v-loading="loading" element-loading-text="正在检测..." class="box-card" style="width: 80%;margin: auto;">
<div slot="header" class="clearfix" v-if="loading == false">
<span>{{ local_thread_data }}</span>
</div>
<div v-if="loading == false && pid == false" v-for="o in 4" :key="o" class="text item">
{{'线程信息: ' + o }}
</div>
</el-card>
<el-card id="main_local" style="width: 80%; height: 400px; margin: auto;"></el-card >
</el-tab-pane>
<el-tab-pane label="远程检测" name="second">
@ -36,20 +37,17 @@
<br /> <br />
<el-button type="primary" @click="begin_remote_check()">开始检测</el-button>
</div>
<br />
<el-card class="box-card" style="width: 80%;margin: auto;">
<div>
<span>线程死锁关系</span>
<br>
<span>{{ remote_thread_data }}</span>
</div>
</el-card>
<el-card id="main_remote" style="width: 80%; height: 400px; margin: auto;"></el-card>
</el-tab-pane>
</el-tabs>
<el-card v-loading="loading" element-loading-text="正在检测..." class="box-card" style="width: 80%;margin: auto;">
<div slot="header" class="clearfix" v-if="loading == false">
<span>检测结果</span>
</div>
<div v-if="loading== false" v-for="o in 4" :key="o" class="text item">
{{'线程信息: ' + o }}
</div>
</el-card>
<el-card id="main" style="width: 80%; height: 400px; margin: auto;">
</el-card >
</template>
</div>
</template>
@ -101,137 +99,429 @@ function TableData () {
export default {
data() {
return {
local_pid_input: -1,
local_pid_input: '',
local_passwd_input: '',
local_cmd_input: '',
local_env_input: '',
remote_account_input: '',
remote_passwd_input: '',
remote_addr_input: '',
remote_pid_input: -1,
radio: '1',
remote_pid_input: '',
loading: true,
pid: false,
afterchecked: false,
deadlockgraph: {},
deadlockinfo: [],
lockinfo:[]
lockinfo:[],
activeName: "first",
local_thread_data: '',
remote_thread_data: '',
thread_info: []
};
},
mounted() {
this.chartDraw();
this.listener();
this.messageListen();
},
methods:{
begin_local_check(isLocal, isPid){
let td = new TableData();
if(isLocal){
}else if(!isLocal){
td.CmdType = cmd_type.REMOTE_PID;
td.Pid = remote_pid_input;
td.Addr = remote_addr_input;
td.User = remote_
}
this.$vscode.postMessage(data);
messageListen() {
window.addEventListener("message", (event) => {
if (event.data.res.CmdType == 1) {
if(event.data.res.success=='success') {
this.drawDeadGraph(event.data.res.data);
}
// else if (event.data.res.success=='error') {
// this.$message({
// showClose: true,
// message:"local-deadlock-detect command exec failed!",
// type: event.data.res.success=='success'?'success':'error'
// });
// }
// else {
// this.$message({
// showClose: true,
// message: event.data.res.msg,
// type: event.data.res.success=='success'?'success':'error'
// });
// }
}
else if (event.data.res.CmdType == 3) {
if(event.data.res.success=='success'){
this.drawDeadGraph(event.data.res.data);
}
// else if (event.data.res.success=='error') {
// this.$message({
// showClose: true,
// message:"local-deadlock-detect command exec failed!",
// type: event.data.res.success=='success'?'success':'error'
// });
// }
// else {
// this.$message({
// showClose: true,
// message: event.data.res.msg,
// type: event.data.res.success=='success'?'success':'error'
// });
// }
}
})
},
chartDraw() {
var myChart = echarts.init(document.getElementById('main'));
var option;
option = {
title: {
text: '死锁关系图'
},
tooltip: {},
animationDurationUpdate: 1500,
animationEasingUpdate: 'quinticInOut',
series: [
{
type: 'graph',
layout: 'none',
symbolSize: 50,
roam: false,
label: {
show: true
},
edgeSymbol: ['circle', 'arrow'],
edgeSymbolSize: [4, 10],
edgeLabel: {
fontSize: 20
},
data: [
{
name: 'Node 1',
x: 300,
y: 300
},
{
name: 'Node 2',
x: 800,
y: 300
},
{
name: 'Node 3',
x: 550,
y: 100
},
{
name: 'Node 4',
x: 550,
y: 500
}
],
// links: [],
links: [
{
source: 0,
target: 1,
symbolSize: [5, 20],
label: {
show: true
},
lineStyle: {
width: 5,
curveness: 0.2
}
},
{
source: 'Node 2',
target: 'Node 1',
label: {
show: true
},
lineStyle: {
curveness: 0.2
}
},
{
source: 'Node 1',
target: 'Node 3'
},
{
source: 'Node 2',
target: 'Node 3'
},
{
source: 'Node 2',
target: 'Node 4'
},
{
source: 'Node 1',
target: 'Node 4'
}
],
lineStyle: {
opacity: 0.9,
width: 2,
curveness: 0
begin_local_check(){
let td = new TableData();
let local_form = {};
let re = this.local_info_verify(this.local_pid_input, this.local_passwd_input);
if(re == '-1')
return;
local_form.pid = this.local_pid_input;
local_form.pwd = this.local_passwd_input;
local_form.CmdType = cmd_type.LOCAL_PID;
this.$vscode.postMessage({form: local_form});
},
begin_remote_check(){
let remote_form = {};
let re = this.remote_info_verify(this.remote_pid_input, this.remote_passwd_input, this.remote_account_input, this.remote_addr_input);
if(re == '-1')
return;
remote_form.pid = this.remote_pid_input;
remote_form.pwd = this.remote_passwd_input;
remote_form.CmdType = cmd_type.REMOTE_PID;
remote_form.user = this.remote_account_input;
remote_form.ip = this.remote_addr_input;
this.$vscode.postMessage({form: remote_form});
},
local_info_verify(pid, pwd) {
if(!pid){
this.$message({
showClose: true,
message:'请输入pid',
type:'warning',
});
return '-1';
}
if(!pwd){
this.$message({
showClose: true,
message:'请输入用户密码',
type:'warning',
});
return '-1';
}
return '0';
},
remote_info_verify(pid, pwd, user, ip) {
if(!pid){
this.$message({
showClose: true,
message:'请输入pid',
type:'warning',
});
return '-1';
}
if(!pwd){
this.$message({
showClose: true,
message:'请输入用户密码',
type:'warning',
});
return '-1';
}
if(!user){
this.$message({
showClose: true,
message:'请输入远程用户账号!',
type:'warning',
});
return '-1';
}
if(!ip){
this.$message({
showClose: true,
message:'请输入远程IP地址!',
type:'warning',
});
return '-1';
}
return '0';
},
lockInfoInit(data){
if (this.activeName == "first")
this.local_thread_data = '';
if (this.activeName == "second")
this.remote_thread_data = '';
this.thread_info = [];
let sub=data.split(/\n/);
console.log(sub);
this.pid = true;
this.loading = false;
sub.forEach(item=>{
if(/LWP/g.test(item)){
let obj={};
obj.threadID=item.split(/LWP /)[1].split(/\)/)[0];
obj.lockID=item.split(/\{/)[1].split(/\}/)[0];
obj.ownID=item.split(/LWP /)[2].split(/\)/)[0];
this.thread_info.push(obj);
if (this.activeName == "first") {
this.local_thread_data = `${this.local_thread_data}线程${obj.threadID}等待锁${obj.lockID},锁${obj.lockID}被线程${obj.ownID}拥有;\n`;
console.log(this.local_thread_data);
} else {
this.remote_thread_data = `${this.remote_thread_data}线程${obj.threadID}等待锁${obj.lockID},锁${obj.lockID}被线程${obj.ownID}拥有;`;
console.log(this.remote_thread_data);
}
}
]
};
option && myChart.setOption(option);
}
});
},
drawDeadGraph(data){
if(/没有发现死锁/g.test(data)){
let myChart = echarts.init(document.getElementById(this.activeName == "first" ? "main_local" : "main_remote"));
myChart.setOption({}, true);
myChart.clear();
if (this.activeName == "first") {
this.local_thread_data = '';
} else {
this.remote_thread_data = '';
}
this.$message({
showClose: true,
message:'没有发现死锁!',
type:'warning',
});
return '-1';
}
this.lockInfoInit(data);
let echartsData=this.getdeadgraphData(this.thread_info);
this.deadgraph(echartsData);
},
getdeadgraphData(lockInfo){
let data=[];
let createdNodeArr=[];
let threadPos={};
let lockPos={};
let thPosX=0;
let thPosY=0
let linkDataArr=[];
lockInfo.forEach((item,index)=>{
thPosX+=50;
let obj={
name: item.threadID,
// x: threadPos[item.threadID],
x: thPosX,
y: thPosY,
symbol:'rect',
};
data.push(obj);
createdNodeArr.push(item.threadID);
if(index==lockInfo.length-1){
thPosY=0;
}else{
thPosY+=50;
}
if(!lockPos[item.ownID]){
lockPos[item.ownID]=thPosY;
}else{
lockPos[item.ownID]+=50;
lockPos[item.ownID]+=thPosY;
}
obj={
name: '锁'+item.lockID,
// x: threadPos[item.threadID],
x:thPosX,
// y: lockPos[item.ownID],
y:thPosY,
symbol:'circle',
};
data.push(obj);
createdNodeArr.push('锁'+item.lockID);
let linkObj={
source: item.threadID,
target: '锁'+item.lockID,
label: {
show: true,
formatter:'等待'
},
lineStyle: {
curveness: 0.2
}
}
let linkObj1={
source: item.ownID,
target: '锁'+item.lockID,
label: {
show: true,
formatter:'拥有'
},
lineStyle: {
curveness: 0.2
}
}
linkDataArr.push(linkObj,linkObj1);
})
let returnData={
data:data,
linkDataArr:linkDataArr
};
return returnData;
}
,
deadgraph(echartsData) {
// var myChart = echarts.init(document.getElementById(this.activeName == "first" ? "main_local" : "main_remote"));
// var myChart = echarts.init(document.getElementById("main_local"));
// myChart.setOption({}, true);
// myChart = echarts.init(document.getElementById("main_remote"));
// myChart.setOption({}, true);
let myChart = echarts.init(document.getElementById(this.activeName == "first" ? "main_local" : "main_remote"));
// var op = myChart.getOption();
// console.log(op);
let option = {
title: {
text: '死锁关系图'
},
tooltip: {},
animationDurationUpdate: 1500,
animationEasingUpdate: 'quinticInOut',
series: [
{
type: 'graph',
layout: 'none',
symbolSize: 50,
roam: true,
label: {
show: true
},
edgeSymbol: ['circle', 'arrow'],
edgeSymbolSize: [4, 10],
itemStyle: {
color: '#bbb',
show: true
},
edgeLabel: {
fontSize: 20
},
data: echartsData.data,
links: echartsData.linkDataArr,
lineStyle: {
opacity: 0.9,
width: 1,
curveness: 0.2
}
}
]
};
console.log("打印option数据");
myChart.setOption(option, true);
},
// chartDraw() {
// var myChart = echarts.init(document.getElementById('main'));
// var option;
// option = {
// title: {
// text: ''
// },
// tooltip: {},
// animationDurationUpdate: 1500,
// animationEasingUpdate: 'quinticInOut',
// series: [
// {
// type: 'graph',
// layout: 'none',
// symbolSize: 50,
// roam: false,
// label: {
// show: true
// },
// edgeSymbol: ['circle', 'arrow'],
// edgeSymbolSize: [4, 10],
// edgeLabel: {
// fontSize: 20
// },
// data: [
// {
// name: 'Node 1',
// x: 300,
// y: 300
// },
// {
// name: 'Node 2',
// x: 800,
// y: 300
// },
// {
// name: 'Node 3',
// x: 550,
// y: 100
// },
// {
// name: 'Node 4',
// x: 550,
// y: 500
// }
// ],
// // links: [],
// links: [
// {
// source: 0,
// target: 1,
// symbolSize: [5, 20],
// label: {
// show: true
// },
// lineStyle: {
// width: 5,
// curveness: 0.2
// }
// },
// {
// source: 'Node 2',
// target: 'Node 1',
// label: {
// show: true
// },
// lineStyle: {
// curveness: 0.2
// }
// },
// {
// source: 'Node 1',
// target: 'Node 3'
// },
// {
// source: 'Node 2',
// target: 'Node 3'
// },
// {
// source: 'Node 2',
// target: 'Node 4'
// },
// {
// source: 'Node 1',
// target: 'Node 4'
// }
// ],
// lineStyle: {
// opacity: 0.9,
// width: 2,
// curveness: 0
// }
// }
// ]
// };
// option && myChart.setOption(option);
// }
}
};
</script>
</script>

View File

@ -4,9 +4,11 @@ import 'element-ui/lib/theme-chalk/index.css';
import App from './App.vue';
Vue.use(ElementUI);
const vscode = acquireVsCodeApi()
Vue.prototype.$vscode = vscode
new Vue({
el: '#app',
render: h => h(App)