!3 合并修复已知bug

Merge pull request !3 from mcy-kylin/changtao
This commit is contained in:
mcy-kylin 2024-02-29 08:56:32 +00:00 committed by Gitee
commit cc7ec9f435
No known key found for this signature in database
GPG Key ID: 173E9B9CA92EEF8F
7 changed files with 4205 additions and 425 deletions

View File

@ -9,20 +9,16 @@ deadlock-detect 用于C/C++/Java进程的死锁检测分析帮助开发者在
## 功能
- 进程死锁检测
- 远程环境进程死锁检测
## 使用方法
#### 检查依赖
依赖binutils、libc-bin、sshpass、libc6-dbg软件包
安装方式```sudo apt install binutils libc-bin gdb sshpass libc6-dbg -y```
依赖binutils、libc-bin、libc6-dbg软件包
安装方式```sudo apt install binutils libc-bin gdb libc6-dbg -y```
或 通过插件依赖管理器extension-dependency进行依赖检测与安装
#### 进程死锁检测
执行ctrl+shift+p启动命令面板或者在编辑区域点击鼠标右键选择'C/C++/Java进程死锁检测',选择`C/C++/Java进程死锁检测`,默认会打开一个页面,按要求选择死锁类型、添加`进程Pid`、`用户密码`即可。
#### 远程环境死锁检测
执行ctrl+shift+p启动命令面板或者在编辑区域点击鼠标右键选择'C/C++/Java进程死锁检测',选择`C/C++/Java进程死锁检测`,默认会打开一个页面,点击“远程检测”,按要求添加`进程Pid`、`远程用户`、`远程IP地址`、`远程登录密码`即可。
# C/C++/Java Process deadlock analysis
## Introduction
@ -31,7 +27,6 @@ deadlock-detect is a tool for deadlock detection and analysis in C/C++/Java proc
## Features
- Process deadlock detection
- Remote environment process deadlock detection
## Usage
#### Check dependencies
@ -40,6 +35,4 @@ deadlock-detect is a tool for deadlock detection and analysis in C/C++/Java proc
#### Process deadlock detection
Open the command palette with ctrl+shift+p or right-click in the editor area and select C/C++/Java Process Deadlock Detection. Select C/C++/Java Process Deadlock Detection, and a page will open. Choose the type of deadlock, add the process PID, and >user password as required.
#### Remote environment deadlock detection
Open the command palette with ctrl+shift+p or right-click in the editor area and select C/C++/Java Process Deadlock Detection. Select C/C++/Java Process Deadlock Detection, and a page will open. Click "Remote Detection" and add the process PID, remote user, remote IP address, and remote login password as required.

View File

@ -0,0 +1,67 @@
#!/usr/bin/sh
DEADLOCK_BEGIN_FLAG='^Found .* Java-level deadlock'
DEADLOCK_END_FLAG='^Java stack information for the threads .*'
SEM_WAIT_FLAG='parking to wait for.*Semaphore$.*'
STACK_INFO=`jstack $1`
MUTEXLOCK=`echo "$STACK_INFO" | grep "java.util.concurrent.locks.ReentrantLock.*"`
RWLOCK=`echo "$STACK_INFO" | grep "java.util.concurrent.locks.ReentrantReadWriteLock.*"`
SEMLOCK=`echo "$STACK_INFO" | grep "java.util.concurrent.Semaphore.*"`
if [ $2 -eq 1 ];then
# 信号量
[ -z "$SEMLOCK" ] && exit 0
fi
if [ $2 -eq 2 ];then
# 互斥锁
[ -z "$MUTEXLOCK" ] && exit 0
fi
if [ $2 -eq 3 ];then
# 读写锁
[ -z "$RWLOCK" ] && exit 0
fi
BEGIN=`echo "$STACK_INFO" | grep -n -E "${DEADLOCK_BEGIN_FLAG}"`
END=`echo "$STACK_INFO" | grep -n -E "${DEADLOCK_END_FLAG}"`
DEADLOCK_STATUS=0
[ -n "$BEGIN" ] && [ -n "$END" ] && DEADLOCK_STATUS=1
DETAIL_INFO=''
# mythread1 waiting for ownable synchronizer 0x0000000717159f08 which is held by mythread2
getAThreadHoldInfo(){
[ ! $# -eq 3 ] && return
echo "$1|$2|$3"
}
if [ $DEADLOCK_STATUS -eq 1 ];then
# 死锁
DEADLOCK_BEGIN_LINE_NUM=`echo "$BEGIN" | awk -F ':' '{print $1}' | head -n 1`
DEADLOCK_END_LINE_NUM=`echo "$END" | awk -F ':' '{print $1}' | head -n 1`
BEGIN_NUM=$(expr $DEADLOCK_BEGIN_LINE_NUM + 1)
END_NUM=$(expr $DEADLOCK_END_LINE_NUM - 1)
DETAIL_INFO=$(echo "${STACK_INFO}" | sed -n "${BEGIN_NUM},${END_NUM}p" | grep -v -E "^==" | sed -e 's/(.*)\|[,:"]//g' | grep -v '^$' 2>/dev/null)
if [ -n "$DETAIL_INFO" ];then
num=1
echo "$DETAIL_INFO" | while IFS= read -r line; do
[ $(expr $num % 3) -eq 1 ] && threadID=$line
[ $(expr $num % 3) -eq 2 ] && mutexID=`echo $line | grep -o '0x[0-9a-fA-F]*'`
[ $(expr $num % 3) -eq 0 ] && heldThreadID=`echo $line | sed -e 's/which is held by//g'` && getAThreadHoldInfo $threadID $mutexID $heldThreadID
num=$(expr $num + 1)
done
fi
exit 0
fi
# 信号量死锁
SEM_INFOS=`echo "${STACK_INFO}" | grep -n "$SEM_WAIT_FLAG"`
echo "$SEM_INFOS" | while IFS= read -r line; do
lnum=`echo $line | awk -F ':' '{print $1}'`
mutexid=`echo $line | grep -o '0x[0-9a-fA-F]*'`
threadinfo=`echo "${STACK_INFO}" | sed -n "$(expr $lnum - 3)p"`
[ -n "${threadinfo}" ] && echo "${threadinfo} ${mutexid}" | awk '{print $1"|"$NF}' | sed -e 's/"//g'
done

View File

@ -0,0 +1,43 @@
#!/bin/sh
if test $# -ne 1; then
echo "Usage: `basename $0 .sh` <process-id>" 1>&2
exit 1
fi
if test ! -r /proc/$1; then
echo "Process $1 not found." 1>&2
exit 1
fi
# GDB doesn't allow "thread apply all bt" when the process isn't
# threaded; need to peek at the process to determine if that or the
# simpler "bt" should be used.
backtrace="bt"
if test -d /proc/$1/task ; then
# Newer kernel; has a task/ directory.
if test `/bin/ls /proc/$1/task | /usr/bin/wc -l` -gt 1 2>/dev/null ; then
backtrace="thread apply all bt"
fi
elif test -f /proc/$1/maps ; then
# Older kernel; go by it loading libpthread.
if /bin/grep -e libpthread /proc/$1/maps > /dev/null 2>&1 ; then
backtrace="thread apply all bt"
fi
fi
GDB=${GDB:-/usr/bin/gdb}
# Run GDB, strip out unwanted noise.
# --readnever is no longer used since .gdb_index is now in use.
$GDB --quiet -nx $GDBARGS /proc/$1/exe $1 <<EOF 2>&1 |
set width 0
set height 0
set pagination no
$backtrace
EOF
/bin/sed -n \
-e 's/^\((gdb) \)*//' \
-e '/^#/p' \
-e '/^Thread/p'

View File

@ -3,7 +3,7 @@
"displayName": "deadlock-detect",
"description": "Deadlock detect for C/C++/Java program.",
"publisher": "KylinIDETeam",
"version": "0.2.7",
"version": "0.2.8",
"engines": {
"vscode": "^1.54.0"
},

View File

@ -153,7 +153,14 @@ export function activate(context: vscode.ExtensionContext) {
function gdb_cmdof_info_thread(pwd:string,pid:string):string[]{
//let temcmd = `cat ${__dirname}/../detect-tools/.user.pwd | sudo -S gdb -q -p ${pid} -ex "info threads" -ex "q" `;
let temcmd = `echo "${pwd}" | sudo -S gdb -q -p ${pid} -ex "info threads" -ex "q" `;
let cmdout = execSync(temcmd).toString();
let cmdout = "".toString()
try{
cmdout = execSync(temcmd).toString();
}catch(error){
return [];
}
//console.log("BBBB:",cmdout)
let infothreads = cmdout.trim().split('\n')
//console.log("CCCC:",infothreads)
@ -205,6 +212,9 @@ export function activate(context: vscode.ExtensionContext) {
lwp = key;
thread_id = lwp_to_thread_id[key];
let bt_output = gdb_cmdof_thread_n_and_bt(pwd,pid,thread_id);
if(bt_output.length === 0){
return [];
}
for(let j=0;j<bt_output.length;j++){
if(bt_output[j].startsWith("#") && bt_output[j].includes(armRpmMutexlock))
{
@ -263,7 +273,8 @@ export function activate(context: vscode.ExtensionContext) {
if(lockID !="unknown"){
lockowner = gdb_cmdof_p_mutex_owner_for_loongarchServer(pwd,pid,thread_id,lockID);
}else{
lockowner = "unknown"
lockowner = "unknown";
return [];
}
const mutexlock_info_temp:rwlock_infomation={
@ -351,6 +362,7 @@ export function activate(context: vscode.ExtensionContext) {
};
thread_RWlock_info.push(mutexlock_info_temp)
}else{
return [];
console.log('No rwlock address found for armserver');
}
}
@ -382,6 +394,7 @@ export function activate(context: vscode.ExtensionContext) {
};
thread_RWlock_info.push(mutexlock_info_temp)
}else{
return [];
console.log('No rwlock address found for armserver');
}
}
@ -414,6 +427,7 @@ export function activate(context: vscode.ExtensionContext) {
thread_RWlock_info.push(mutexlock_info_temp)
}else{
console.log('No rwlock address found for armserver');
return [];
}
}
}
@ -454,7 +468,12 @@ export function activate(context: vscode.ExtensionContext) {
function gdb_cmdof_thread_n_and_bt(pwd:string,pid:string,thread_id:string):string[]{
//let temcmd = `cat ${__dirname}/../detect-tools/.user.pwd | sudo -S gdb -q -p ${pid} -ex "info threads" -ex "thread ${thread_id}" -ex "bt" -ex "q"`;
let temcmd = `echo "${pwd}" | sudo -S gdb -q -p ${pid} -ex "info threads" -ex "thread ${thread_id}" -ex "bt" -ex "q"`;
let cmdout = execSync(temcmd).toString();
let cmdout = "".toString();
try{
cmdout = execSync(temcmd).toString();
}catch(error){
return [];
}
let bt_output = cmdout.trim().split('\n');
return bt_output;
@ -463,7 +482,13 @@ export function activate(context: vscode.ExtensionContext) {
//let temcmd = `cat ${__dirname}/../detect-tools/.user.pwd | sudo -S gdb -q -p ${pid} -ex "thread ${thread_id}" -ex "p/x \\$x6" -ex "q"`;
let temcmd = `echo "${pwd}" | sudo -S gdb -q -p ${pid} -ex "thread ${thread_id}" -ex "p/x \\$x6" -ex "q"`;
//console.log("execcmd is:",temcmd)
let cmdout = execSync(temcmd).toString();
let cmdout = "".toString();
try{
cmdout = execSync(temcmd).toString();
}catch(error){
return "unknown"
}
//arm服务器锁地址存放在寄存器x6
let x6_output = cmdout.trim().split('\n');
//console.log("x6_output is:",x6_output)
@ -484,7 +509,13 @@ export function activate(context: vscode.ExtensionContext) {
//let temcmd = `cat ${__dirname}/../detect-tools/.user.pwd | sudo -S gdb -q -p ${pid} -ex "thread ${thread_id}" -ex "p/x \\$rbx" -ex "q"`;
let temcmd = ` echo "${pwd}" | sudo -S gdb -q -p ${pid} -ex "thread ${thread_id}" -ex "p/x \\$rbx" -ex "q"`;
//console.log("execcmd is:",temcmd)
let cmdout = execSync(temcmd).toString();
let cmdout = "".toString();
try{
cmdout = execSync(temcmd).toString();
}catch(error){
return "unknown"
}
//x86服务器锁地址存放在寄存器rbx
let x6_output = cmdout.trim().split('\n');
//console.log("x6_output is:",x6_output)
@ -506,7 +537,13 @@ export function activate(context: vscode.ExtensionContext) {
//let temcmd = `cat ${__dirname}/../detect-tools/.user.pwd | sudo -S gdb -q -p ${pid} -ex "thread ${thread_id}" -ex "p/x \\$a6" -ex "q"`;
let temcmd = `echo "${pwd}" | sudo -S gdb -q -p ${pid} -ex "thread ${thread_id}" -ex "p/x \\$a6" -ex "q"`;
//console.log("execcmd is:",temcmd)
let cmdout = execSync(temcmd).toString();
let cmdout = "".toString();
try{
cmdout = execSync(temcmd).toString();
}catch(error){
return "unknown"
}
//x86服务器锁地址存放在寄存器rbx
let x6_output = cmdout.trim().split('\n');
//console.log("x6_output is:",x6_output)
@ -528,7 +565,13 @@ export function activate(context: vscode.ExtensionContext) {
//let temcmd = `cat ${__dirname}/../detect-tools/.user.pwd | sudo -S gdb -q -p ${pid} -ex "thread ${thread_id}" -ex "p/x \\$s0" -ex "q"`;
let temcmd = `echo "${pwd}" | sudo -S gdb -q -p ${pid} -ex "thread ${thread_id}" -ex "p/x \\$s0" -ex "q"`;
//console.log("execcmd is:",temcmd)
let cmdout = execSync(temcmd).toString();
let cmdout = "".toString();
try{
cmdout = execSync(temcmd).toString();
}catch(error){
return "unknown"
}
//loongarch服务器锁地址存放在寄存器s0
let s0_output = cmdout.trim().split('\n');
//console.log("s0_output is:",s0_output)
@ -553,7 +596,13 @@ export function activate(context: vscode.ExtensionContext) {
//let temcmd = `cat ${__dirname}/../detect-tools/.user.pwd | sudo -S gdb -q -p ${pid} -ex "thread ${thread_id}" -ex "p ${printName}" -ex "q"`;
let temcmd = `echo "${pwd}" | sudo -S gdb -q -p ${pid} -ex "thread ${thread_id}" -ex "p ${printName}" -ex "q"`;
let cmdout = execSync(temcmd).toString();
let cmdout = "".toString();
try{
cmdout = execSync(temcmd).toString();
}catch(error){
return "unknown"
}
//arm服务器锁owner
let owner_output = cmdout.trim().split('\n');
@ -579,7 +628,13 @@ export function activate(context: vscode.ExtensionContext) {
//let temcmd = `cat ${__dirname}/../detect-tools/.user.pwd | sudo -S gdb -q -p ${pid} -ex "thread ${thread_id}" -ex "p ${printName}" -ex "q"`;
let temcmd = `echo "${pwd}" | sudo -S gdb -q -p ${pid} -ex "thread ${thread_id}" -ex "p ${printName}" -ex "q"`;
let cmdout = execSync(temcmd).toString();
let cmdout = "".toString();
try{
cmdout = execSync(temcmd).toString();
}catch(error){
return "unknown"
}
//arm服务器锁owner
let owner_output = cmdout.trim().split('\n');
@ -601,7 +656,13 @@ export function activate(context: vscode.ExtensionContext) {
let mutex_owner= lockname +"._M_mutex.__data.__owner"
//let temcmd = `cat ${__dirname}/../detect-tools/.user.pwd | sudo -S gdb -q -p ${pid} -ex "info threads" -ex "thread ${thread_id}" -ex "p ${mutex_owner}" -ex "q"`;
let temcmd = `echo "${pwd}" | sudo -S gdb -q -p ${pid} -ex "info threads" -ex "thread ${thread_id}" -ex "p ${mutex_owner}" -ex "q"`;
let cmdout = execSync(temcmd).toString()
let cmdout = "".toString();
try{
cmdout = execSync(temcmd).toString()
}catch(error){
return "unknow";
}
let mutex_info = cmdout.trim().split('\n');
for(let j=mutex_info.length-1;j>=0;j--){
if(mutex_info[j].startsWith("$1")){
@ -618,7 +679,13 @@ export function activate(context: vscode.ExtensionContext) {
let mutex_owner= lockname +".__data.__cur_writer"
//let temcmd = `cat ${__dirname}/../detect-tools/.user.pwd | sudo -S gdb -q -p ${pid} -ex "info threads" -ex "thread ${thread_id}" -ex "p ${mutex_owner}" -ex "q"`;
let temcmd = `echo "${pwd}" | sudo -S gdb -q -p ${pid} -ex "info threads" -ex "thread ${thread_id}" -ex "p ${mutex_owner}" -ex "q"`;
let cmdout = execSync(temcmd).toString()
let cmdout = "".toString();
try{
cmdout = execSync(temcmd).toString()
}catch(error){
return "unknow";
}
let mutex_info = cmdout.trim().split('\n');
for(let j=mutex_info.length-1;j>=0;j--){
if(mutex_info[j].startsWith("$1")){
@ -768,6 +835,14 @@ export function activate(context: vscode.ExtensionContext) {
//ARM x86 loongarch64 服务器
let mutex_info:rwlock_infomation[] = [];
let info_threads = gdb_cmdof_info_thread(form.pwd,form.pid);
//gdb error 进程终止
if(info_threads.length === 0){
form.mutexflag = false;
form.errflag = "gdberror";
panel.webview.postMessage({
res: form});
return;
}
let lwp_to_thread_id = get_threadid_lwp_relation_for_armServer(info_threads);
if(form.dead_type == 1){
if(arch == "loongarch64" || arch == "loong64" || arch =="la64"){
@ -775,6 +850,14 @@ export function activate(context: vscode.ExtensionContext) {
}else{
//arm服务器系统互斥锁寄存器为x4(或者x19),但是不需要安装glibc-debugutilsgdb调试包含锁信息
mutex_info = judge_mutex(form.pwd,form.pid,lwp_to_thread_id,"__gthread_mutex_lock");
//gdberror导致获取mutex_info为空
if(mutex_info.length === 0){
form.mutexflag = false;
form.errflag = "gdberror";
panel.webview.postMessage({
res: form});
return;
}
}
console.log("mutex_info is:",mutex_info)
if(mutex_info.length != 0){
@ -859,9 +942,27 @@ export function activate(context: vscode.ExtensionContext) {
}else if(form.dead_type == 1 && isOpenkylin == true && arch =="x86_64"){
//openkylin && x86
let info_threads = gdb_cmdof_info_thread(form.pwd,form.pid);
//gdb error 进程终止
if(info_threads.length === 0){
form.openkylin = true;
form.mutexflag = false;
form.errflag = "gdberror";
panel.webview.postMessage({
res: form});
return;
}
let lwp_to_thread_id = get_threadid_lwp_relation(info_threads);
//let mutex_info = judge_mutex(form.pid,lwp_to_thread_id,"__GI___lll_lock_wait");
let mutex_info = judge_mutex(form.pwd,form.pid,lwp_to_thread_id,"___pthread_mutex_lock");
//gdberror导致获取mutex_info为空
if(mutex_info.length === 0){
form.mutexflag = false;
form.openkylin = true;
form.errflag = "gdberror";
panel.webview.postMessage({
res: form});
return;
}
if(mutex_info.length !=0){
form.openkylin = true;
form.mutexflag = true;
@ -881,6 +982,14 @@ export function activate(context: vscode.ExtensionContext) {
}else if((form.dead_type == 2 || form.dead_type == 3) && sys_flag == "deb" ){
//x86 arm loongarch桌面系统读写锁和信号量
let info_threads = gdb_cmdof_info_thread(form.pwd,form.pid);
//gdb error 进程终止
if(info_threads.length === 0){
form.rwflag = false;
form.errflag = "gdberror";
panel.webview.postMessage({
res: form});
return;
}
let lwp_to_thread_id = get_threadid_lwp_relation(info_threads);
if(form.dead_type == 2){
//loongarch桌面系统读写锁寄存器和服务器系统一致a6用读寄存器方式实现不需要安装libc6-dbg
@ -890,8 +999,10 @@ export function activate(context: vscode.ExtensionContext) {
rwlock_info = judge_rwlock_for_armServer(form.pwd,form.pid,lwp_to_thread_id,"pthread_rwlock_");
}else if(arch == "loongarch64" || arch == "loong64" || arch =="la64"){
rwlock_info = judge_rwlock_for_loongarchServer(form.pwd,form.pid,lwp_to_thread_id,"pthread_rwlock_");
}else{
rwlock_info = judge_rwlock_for_x86Server(form.pwd,form.pid,lwp_to_thread_id,"pthread_rwlock_");
}
if(rwlock_info.length != 0){
form.rwflag = true;
form.arch = "loong64-arm64";
@ -1087,7 +1198,7 @@ export function activate(context: vscode.ExtensionContext) {
//执行死锁检测程序
let isJava = isJavaProcess(form.pid)
if(isJava){
child.exec(`jstack ${form.pid}`, (e1, x, c2) => {
child.exec(`${__dirname}/../detect-tools/detect_java.sh ${form.pid} ${form.deadType}`, (e1, x, c2) => {
console.log("output is:",x)
form.arch=os.arch();
form.data =x;

3886
view-ui/package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@ -47,34 +47,6 @@
</div>
</div>
<!--el-tab-pane label="C/C++远程检测" name="second" >
<div style="width: 60%;margin:auto">
<br />
<el-input v-model="remote_pid_input" placeholder="请输入被检测进程PID"></el-input>
<br />
<el-input v-model="remote_addr_input" placeholder="请输入远程IP地址"></el-input>
<el-input v-model="remote_account_input" placeholder="请输入远程用户账号"></el-input>
<el-input placeholder="请输入远程用户密码" v-model="remote_passwd_input" show-password></el-input>
<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>
<div class="loading-overlay" v-if="this.loading2">
<div class="loading-spinner">
<div class="text1">检测中<span class="dots">...</span></div>
</div>
</div-->
<el-tab-pane label="Java进程死锁检测" name="third" >
<div style="width: 60%;margin:auto">
<br />
@ -118,14 +90,6 @@
</div>
</div>
</el-tabs>
<!--div class="loading-overlay" v-if="this.loading1">
<div class="loading-spinner">
<div class="text1">检测中<span class="dots">...</span></div>
</div>
</div-->
</template>
</div>
</template>
@ -309,6 +273,8 @@ export default {
message:'待检测进程不是C/C++类型,请重新输入!',
});
}else{
this.local_thread_data = ''
this.thread_info = []
if(this.c_dead_type == 3){
this.loading1 = false;
if(event.data.res.wrongpasswd == true){
@ -401,7 +367,16 @@ export default {
let temp_array_copy2 = []
let flag = true;
console.log("发现读写锁死锁:",event.data.res.thread_rwlock_info)
console.log("发现读写锁死锁:",event.data.res.thread_rwlock_info);
let tmpArr = [];
let tmpObjArr = [];
event.data.res.thread_rwlock_info.forEach((item)=>{
if(!tmpArr.includes(item.threadID)){
tmpArr.push(item.threadID);
tmpObjArr.push(item);
}
})
event.data.res.thread_rwlock_info = tmpObjArr;
for(let i=0;i<event.data.res.thread_rwlock_info.length;i++){
let obj = {};
let threadLwp = event.data.res.thread_rwlock_info[i]
@ -533,7 +508,7 @@ export default {
/* */
if(cirle_deadlock){
this.$message({
message: "发现互斥锁死锁(严格意义的环路死锁)!",
message: "2发现互斥锁死锁(严格意义的环路死锁)!",
})
}else{
this.$message({
@ -563,7 +538,7 @@ export default {
if(cirle_deadlock){
this.$message({
message: "发现互斥锁死锁(严格意义的环路死锁)!",
message: "1发现互斥锁死锁(严格意义的环路死锁)!",
})
}else{
this.$message({
@ -716,6 +691,7 @@ export default {
this.javapid = this.java_pid_input;
java_form.pwd = this.java_passwd_input;
java_form.CmdType = cmd_type.JAVA_PID;
java_form.deadType = this.java_dead_type;
this.$vscode.postMessage({form: java_form});
},
//C
@ -1120,381 +1096,89 @@ export default {
根据jstack输出信息提取锁信息
*/
javalockInfoInit(data,arch){
const common_func = function (data, lock_type) {
let res_str = "";
const hadHeldMutexMap = new Map(); // 线 < 线ID>
const willHeldMutexMap = new Map(); // 线 <线ID >
data.split('\n').forEach((Info)=>{
if(Info && Info.length){
let count = 0;
let tmp = Info.split('|');
if(tmp && tmp.length >= 3){
res_str += '线程' + tmp[0] +`申请${lock_type}`+ tmp[1] +"被线程"+ tmp[2]+"持有; ";
hadHeldMutexMap.set(tmp[1], tmp[2]); //< 线ID>
willHeldMutexMap.set(tmp[0], tmp[1]); //<线ID >
}
}
});
let nodeItem = [];
willHeldMutexMap.forEach(function(value, key) {
hadHeldMutexMap.forEach(function (v1, k1) {
if(v1 === key){
nodeItem.push({
threadID: key,
lockID: value,
ownID: k1
})
}
})
});
return {
"res_str": res_str,
"nodeItem": nodeItem
}
}
/*
判断信号量死锁 this.java_dead_type == 1
判断read write死锁 this.java_dead_type == 3
*/
if(this.java_dead_type == 1 ){
this.local_java_data = "";
console.log("QQQQQQQQQQ:",this.java_dead_type)
this.semlockflag = false;
let processIndex = 0;
let tempsting = data;
//
let split1=tempsting.replace(/\t/g, " ").replace(/^\s\s*/, "").replace(/\s\s*$/, "").split(/\n\n/);
let semdataInfo=[];
let htmlInfo=[];
split1.forEach((item)=>{
console.log("00000 item is:",item)
if(item&&(item.indexOf('a java.util.concurrent.Semaphore$NonfairSync')!=-1)){
this.semlockflag = true
let infoObj={};
let htmlInfoStr='';
processIndex+=1;
console.log("111111:",item)
// item
let splitItemArr=item.replace(/^\s\s*/, "").replace(/\s\s*$/, "").split(/\n/);
console.log("222222:",splitItemArr)
splitItemArr.forEach((item1,index)=>{
console.log("origin info item1 is:",item1);
let lineReg=/a java.util.concurrent.Semaphore\$NonfairSync/;
if(index==0){
let match = item1.match(/"([^"]+)"/);
if(match){
infoObj.threadName = match[1];
}
let threadName=item1.split('nid=')[1].split(' ')[0];
threadName=parseInt(threadName,16)
infoObj.threadName = threadName;
//infoObj.threadNum = threadName;
}
if(index==splitItemArr.length-1){
let line=item1.replace(/^\s\s*/, "").replace(/\s\s*$/, "").split('(')[1];
line=line.replace(')','').split(':')
infoObj.line=line[1];
infoObj.fileName=line[0];
}
if(lineReg.test(item1)){
let lock=item1.replace(/^\s\s*/, "").replace(/\s\s*$/, "").split('<')[1];
lock=lock.replace(')','').replace(/>/,'').split('(')
infoObj.lockName='<'+lock[0].replace(/^\s\s*|\s\s*$/, "")+'>';
infoObj.lockType=lock[1].replace(/^\s\s*|\s\s*$/, "");
}
infoObj.threadNum=Number(this.java_pid_input)+processIndex;
});
htmlInfoStr='线程 '+infoObj.threadName+' 等待 信号量'+infoObj.lockName;
semdataInfo.push(infoObj);
htmlInfo.push(htmlInfoStr);
console.log("AAAA infoObj:",infoObj);
console.log("BBBB htmlInfoStr",htmlInfoStr)
}else{
if(item&&item.indexOf("java.lang.Thread.State: WAITING")!=-1){
/*将字符串 item 两端的空白字符删除,然后按照换行符将字符串分割成多个子串*/
this.semlockflag = true
let infoObj={};
let htmlInfoStr='';
let splitItemArr=item.replace(/^\s\s*/, "").replace(/\s\s*$/, "").split(/\n/);
console.log("222222:",splitItemArr)
splitItemArr.forEach((item1,index)=>{
console.log("origin info item1 is:",item1)
let lineReg=/a java.util.concurrent.Semaphore\$NonfairSync/;
/*线程号或线程名*/
if(index==0){
let match = item1.match(/"([^"]+)"/);
if(match){
infoObj.threadName = match[1];
}
let threadName=item1.split('nid=')[1].split(' ')[0];
threadName=parseInt(threadName,16)
infoObj.threadName = threadName;
}
//
if(item1.includes('<') && item1.includes('>')){
const start = item1.indexOf('<') + 1; // "<"
const end = item1.indexOf('>'); // ">"
const objStr = item1.slice(start, end); // "<" ">"
infoObj.lockName = objStr;
}
//
if (item1.includes('$')) {
const idx = item1.indexOf('$');
if (idx < item1.length - 1 && /^\d$/.test(item1.charAt(idx + 1))) {
const matched = item1.match(/\(([^)]+)\)/);
if (matched) {
console.log(matched[1]);
infoObj.fileName = matched[1].split(":")[0];
infoObj.line = matched[1].split(":")[1];
}
}
}
});
htmlInfoStr='线程 '+infoObj.threadName+' 等待 信号量'+infoObj.lockName;
semdataInfo.push(infoObj);
htmlInfo.push(htmlInfoStr);
console.log("AAAA infoObj:",infoObj);
console.log("BBBB htmlInfoStr",htmlInfoStr)
}
}
});
this.loading3 = false;
if(htmlInfo.length==0){
this.$message({
message: "未发现信号量死锁!",
});
this.java_thread_info = [];
this.echartsInit(this.java_thread_info);
}else{
console.log("semdataInfo is:",semdataInfo)
this.local_java_data += htmlInfo
this.java_thread_info = [];
this.echartsInit(this.java_thread_info);
//let echartsData=this.javasemgetEchartsData(semdataInfo);
//this.javasemechartsInit(echartsData)
}
}else if(this.java_dead_type == 2){
// this.java_dead_type == 2
this.local_java_data = '';
this.java_thread_info = [];
if(data.includes("Found.*?deadlock")){
let a=data.split(/Found.*?deadlock:/g)[1];
a=a.replace(/\t+/g,'\n');
let b=a.split(/.*?\n=+?\n+/g);
let b1=b[1].replace('Java stack information for the threads listed above:','').replace(/^\s\s*/, "").replace(/\s\s*$/, "");
let deadTable=this.deadTableData(b1,arch);
console.log("AAAAA:",b1)
let b2=b[2].split(/Found.*?deadlock./g);
let c1=b2[0].replace(/"/g, "");
let d2=c1.split(/Thread-/g);
console.log("BBBBB:",d2)
if(d2&&d2.length>0){
d2.forEach(item=>{
if(item){
let arrData=item.split(/:\n/g);
let theardItem={};
let arrData2=arrData[1].replace(/^\s\s*/, "").replace(/\s\s*$/, "").split(/\n+/g);
let val=arrData2[0].replace(/^\s\s*/, "").replace(/\s\s*$/, "").split(/\(/)[1].split(/\)/)[0];
let obj2={};
theardItem.sourceStr=arrData2;
//arrData2[1],arrData2[2]
let index1 = arrData2[1].indexOf('<')
let index2 = arrData2[1].indexOf('>')
let waitlock = arrData2[1].substring(index1+1,index2)
console.log("等待锁:",waitlock)
index1 = arrData2[2].indexOf('<')
index2 = arrData2[2].indexOf('>')
let ownlock = arrData2[2].substring(index1+1,index2)
console.log("拥有锁:",ownlock)
console.log("code line is:",theardItem.sourceStr)
theardItem.sourceLine=val;
//theardItem.sourceLine线
console.log("code line2 is:",theardItem.sourceLine)
//obj2['Thread-'+arrData[0]]=theardItem;
let lockrelation = 'Thread-'+arrData[0] +'('+ theardItem.sourceLine +')' + "等待锁" + waitlock + "拥有锁" + ownlock + ';' +'\n'
console.log("result info is :",lockrelation)
this.local_java_data += lockrelation
obj2.threadID = 'Thread-'+arrData[0];
obj2.ownID = ownlock;
obj2.lockID = waitlock;
this.java_thread_info.push(obj2);
}
})
}
let d1=[];
deadTable.lockTableInfo.forEach(item => {
let obj={};
if(item){
obj.lock=item.key0;
obj.val=item.key4;
d1.push(obj);
}
});
this.javaLockInfo=deadTable.lockInfo;//
this.javaLockTableInfo=deadTable.lockTableInfo;//
}
//this.echartsInit(d1,obj2);
if(this.java_thread_info.length==0){
this.loading3=false;
this.$message({
message: "未发现互斥锁死锁!",
});
}else{
this.echartsInit(this.java_thread_info);
}
}else if(this.java_dead_type == 3){
//java
this.local_java_data = '';
this.java_thread_info = [];
let tempstring = data;
//
if(tempstring.includes('Found one Java-level deadlock:')){
//start to modify for eduction version
const pattern = /"(Thread-\d+)":\s*waiting for ownable synchronizer\s*(0x[0-9a-f]+),\s*\(a java\.util\.concurrent\.locks\.ReentrantReadWriteLock\$NonfairSync\),\s*which is held by\s*"(Thread-\d+)"/g;
let match;
this.java_thread_info = [];
let temp_arry = [];
while ((match = pattern.exec(data)) !== null) {
const threadWaiting = match[1];
const address = match[2];
const threadHolding = match[3];
let obj4= {};
obj4.waitthread = threadWaiting;
obj4.lockID = address;
obj4.holdthread = threadHolding;
temp_arry.push(obj4);
console.log("Thread waiting:", threadWaiting);
console.log("Address:", address);
console.log("Thread holding:", threadHolding);
console.log();
}
//
//
const temp_arry_copy = JSON.parse(JSON.stringify(temp_arry));
console.log("temp_arry is:",temp_arry)
temp_arry.forEach((t) => {
const holdingThread = temp_arry_copy.find((h) => h.holdthread === t.waitthread);
if (holdingThread) {
t.holdthread = holdingThread.lockID;
console.log("t.holdthread(ownID):",t.holdthread)
}
});
console.log("temp_array is:",temp_arry)
console.log("temp_arry_copy is:",temp_arry_copy)
//,:threadID lockID ownID
temp_arry.forEach((t) => {
let obj4 = {};
obj4.threadID = t.waitthread;
obj4.lockID = t.lockID;
obj4.ownID = t.holdthread;
this.local_java_data += "线程"+ obj4.threadID + "等待读写锁"+ obj4.lockID + ",拥有读写锁"+obj4.ownID+";"
this.java_thread_info.push(obj4);
})
this.echartsInit(this.java_thread_info);
console.log("this.java_thread_info is :",this.java_thread_info);
//end modify for eduction version
//,
// this.java_thread_info = [];
// let temp_arry = [];
// let split1=tempstring.replace(/\t/g, " ").replace(/^\s\s*/, "").replace(/\s\s*$/, "").split(/\n\n/);
/* split1.forEach((item)=>{
if((item.indexOf("Found one Java-level deadlock:")!=-1)&&(item.indexOf("=============")!=-1)){
// item
const pattern = /"(.*)":\s+waiting for ownable synchronizer (\S+), \(a java\.util\.concurrent\.locks\.ReentrantReadWriteLock\$NonfairSync\),\s+which is held by "(.*)"/g;
let matches;
while ((matches = pattern.exec(item)) !== null) {
const waitingThread = matches[1];
const objectId = matches[2];
const holdingThread = matches[3];
let obj3 = {};
obj3.waitthread = waitingThread;
obj3.lockID = objectId;
obj3.holdthread = holdingThread;
temp_arry.push(obj3);
console.log(`Waiting thread: ${waitingThread}`);
console.log(`Holding thread: ${holdingThread}`);
console.log(`Object ID: ${objectId}`);
if(data && data.length) {
let sem_res_str = "";
data.split('\n').forEach((semInfo)=>{
if(semInfo && semInfo.length){
sem_res_str += "线程" + semInfo.replace('|', "等待信号量") + '; ';
}
//
//
const temp_arry_copy = JSON.parse(JSON.stringify(temp_arry));
console.log("temp_arry is:",temp_arry)
temp_arry.forEach((t) => {
const holdingThread = temp_arry_copy.find((h) => h.holdthread === t.waitthread);
if (holdingThread) {
t.holdthread = holdingThread.lockID;
console.log("t.holdthread(ownID):",t.holdthread)
}
});
console.log("temp_array is:",temp_arry)
console.log("temp_arry_copy is:",temp_arry_copy)
//,:threadID lockID ownID
temp_arry.forEach((t) => {
let obj4 = {};
obj4.threadID = t.waitthread;
obj4.lockID = t.lockID;
obj4.ownID = t.holdthread;
this.local_java_data += "线程"+ obj4.threadID + "等待读写锁"+ obj4.lockID + ",拥有读写锁"+obj4.ownID+";"
this.java_thread_info.push(obj4);
})
this.echartsInit(this.java_thread_info);
console.log("this.java_thread_info is :",this.java_thread_info);
}
})*/
}else{
//
this.loading3=false;
this.$message({
message: "未发现读写锁死锁!",
});
if(sem_res_str.length) this.local_java_data = sem_res_str;
this.java_thread_info = [];
this.echartsInit(this.java_thread_info);
return;
}
this.local_java_data = "";
this.$message({
message: "未发现信号量死锁!",
});
this.java_thread_info = [];
this.echartsInit(this.java_thread_info);
}else if(this.java_dead_type == 2 || this.java_dead_type == 3){
//java
this.loading3 = false;
if(data && data.length){
const obj = common_func(data, this.java_dead_type == 3 ? "读写锁":"互斥锁");
this.java_thread_info = obj.nodeItem;
if(obj.res_str.length) this.local_java_data = obj.res_str;
this.echartsInit(this.java_thread_info);
return;
}
this.local_java_data = "";
this.$message({
message: `未发现死锁!`,
});
this.java_thread_info = [];
this.echartsInit(this.java_thread_info);
}else{
this.$message({
message: "请选择死锁类型!",
});
message: "请选择死锁类型!",
});
}
},
/*
java 互斥锁信息格式化
*/
deadTableData(b1,arch){
let c='';
if(arch&&(arch=='loong64'||arch=='loongarch64'||arch=='la64'||arch=='arm64'||arch=='sw_64'||arch=='mips64el')){//longxin5000FT2000/4LS3A4000
c=b1.replace(/^\s\s*/, "").replace(/\s\s*$/, "").split(/\"\n\"/g);
}else{
c=b1.replace(/\"\n\n\"/g,'\t')
c=c.replace(/\n\n/g,'\n');
c=c.split(/\t/g);
if(c.length>2){
c.pop();
}
}
let d=[];
let d1=[];
let processIndex=0;
console.log("ccccccc:",c)
c.forEach(item=>{
processIndex+=1;
let o=item;
console.log("1111111:",o)
o=o.replace(/:/, "")
o=o.replace(/waiting to lock monitor/, "等待互斥锁").replace(/which is held by/, "被线程");
console.log("2222222:",o)
o='线程'+o+'占用';
d.push(o);
item=item.split(/:/);
let str1=item[1].replace(/^\s\s*/, "").replace(/\s\s*$/, "").split(/waiting to lock monitor/)[1];
str1=str1.replace(/^\s\s*/, "").replace(/\s\s*$/, "").split(/\(/);
let str2=str1[1];
str1=str1[0].replace(/^\s\s*/, "").replace(/\s\s*$/, "");
str2=str2.split(/\)/);
let str4=str2[1].split(/which is held by/)[1].replace(/"/g,"").replace(/^\s\s*/, "").replace(/\s\s*$/, "");
let str3=str2[0].split(/,/)[1].replace(/^\s\s*/, "").replace(/\s\s*$/, "").split(/a\s+/)[1];
str2=str2[0].split(/,/)[0].split(/\s+/)[1];
console.log("str1 is:",str1)
console.log("str1 is:",str2)
console.log("str1 is:",str3)
console.log("str1 is:",str4)
let obj={};
obj.key0=item[0].replace(/"/g, "");
obj.key1=str1
obj.key2=str2
obj.key3=str3
obj.key4=str4
obj.key5=Number(this.javapid)+processIndex
d1.push(obj);
});
return {
'lockInfo':d,
"lockTableInfo":d1
}
},
/*
c/c++死锁关系图节点数据格式化
*/
/*
c/c++死锁关系图节点数据格式化
*/
echartsInit(lockInfo) {
console.log(`lockInfo -> ${JSON.stringify(lockInfo)}`);
let data=[];
let createdNodeArr=[];
let threadPos={};