openGauss-server/src/gausskernel/cbb/bbox/bbox_threads.cpp

774 lines
24 KiB
C++

/*
* Copyright (c) 2020 Huawei Technologies Co.,Ltd.
*
* openGauss is licensed under Mulan PSL v2.
* You can use this software according to the terms and conditions of the Mulan PSL v2.
* You may obtain a copy of Mulan PSL v2 at:
*
* http://license.coscl.org.cn/MulanPSL2
*
* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
* EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
* MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
* See the Mulan PSL v2 for more details.
* -------------------------------------------------------------------------
*
* bbox_threads.cpp
*
* IDENTIFICATION
* src/gausskernel/cbb/bbox/bbox_threads.cpp
*
* -------------------------------------------------------------------------
*/
#include "bbox_syscall_support.h"
#include "bbox_threads.h"
#include "bbox_print.h"
#include "bbox_atomic.h"
#include "../../src/include/securec.h"
#include "../../src/include/securec_check.h"
static const u32 iSyncSignals[] = {
SIGABRT,
SIGILL,
SIGFPE,
SIGSEGV,
SIGBUS,
SIGXCPU,
SIGXFSZ,
};
struct TASK_ATTACH_INFO {
pid_t pid; /* pid */
u8 cIsAttached; /* Whether the thread is ptraced */
};
struct TASK_CHECK_RESUME_ARGS {
struct TASK_ATTACH_INFO* pstTaskInfo; /* recover process information */
s32 iThreadCount; /* thread count */
GET_THREAD_TYPE enType; /* get thread type */
};
struct BBOX_ListParams {
s32 iResult; /* result */
s32 iError; /* error code */
u8* pAltStackMem; /* Execution stack information */
BBOX_GetAllThreadsCallBack pCallBack; /* Executes the callback function exported by the thread */
BBOX_GetAllThreadDone pDoneCallback; /* call back function after exporting the thread information */
void* pDoneArgs; /* parameter of call back function pDoneCallback */
GET_THREAD_TYPE enGetType; /* get data type */
va_list ap; /* parameter list of function pCallBack */
};
u8 g_szAltStackMem[BBOX_ALT_STACKSIZE]; /* independent thread stack memory */
BBOX_ATOMIC_STRU g_isBusy = BBOX_ATOMIC_INIT(0); /* whether deal with core file. */
/*
function name: BBOX_ReserveZeroStack
description: The function creat a empty stack, and its size depend on argument count.
arguments: An integer of type s32, namely int, it destines the storage of stack.
return value: void
note: The stack this function creats is actually a character array.
date: 2022/8/3
contact tel: 18720816902
*/
void BBOX_ReserveZeroStack(s32 count)
{
char buff[count];
errno_t rc = memset_s(buff, count, 0, count);
securec_check_c(rc, "\0", "\0");
(void)sys_read(-1, buff, count);
}
/*
* clone the current process and runs the specified function
* return 0 if seccess else err code
*/
s32 BBOX_CloneRun(u32 uFlags, s32 (*pFn)(void*), void* pArg, ...)
{
/* reserve 4K when calling and running a function to protect waitpid can exit correct. */
/* CLONE_UNTRACED flag is must or gdb will debug new process which is cloned. */
pid_t pid;
if (pArg == NULL || pFn == NULL) {
return -1;
}
pid = sys__clone(pFn, (((char*)(pArg)) - 4096), uFlags | CLONE_UNTRACED, pArg, 0, 0, 0);
return pid;
}
/*
function name: BBOX_GetTaskNumber
description: When get a path to specific process, this function will return count of threads below it.
arguments: A pointer of type char*, including a path to specific process.
return value: An integer that indicates the count of threads below specific process.
note: none
date: 2022/8/3
contact tel: 18720816902
*/
s32 BBOX_GetTaskNumber(char* szTaskPath)
{
struct kernel_stat stProcSB = {0};
s32 iProc = -1;
if (szTaskPath == NULL) {
bbox_print(PRINT_ERR, "parameter szTaskPath is null.\n");
return -1;
}
/* open /proc */
iProc = sys_open(szTaskPath, O_RDONLY | O_DIRECTORY, 0);
if (iProc < 0) {
bbox_print(PRINT_ERR, "open file %s failed, errno = %d\n", szTaskPath, errno);
return -1;
}
/* get the number of first file nodes in the directory */
if (sys_fstat(iProc, &stProcSB)) {
bbox_print(PRINT_ERR, "Get file %s fstat, errno = %d, iProc = %d\n", szTaskPath, errno, iProc);
sys_close(iProc);
return -1;
}
sys_close(iProc);
return stProcSB.st_nlink;
}
/*
function name: BBOX_GetTaskId
description: When get a path to specific process, this function will return count of threads below it.
arguments: The first argument is a structure pointer named pstTaskInfo,its type is struct TASK_ATTACH_INFO*,
we use it as a structure array to store requisite thread infomation, the next argument destines
the max size of the array that the first argument destines. The last argument is a pointer of type
char*, including a path to specific process.
return value: An integer that indicates the count of threads stored in structure array.
note: none
date: 2022/8/3
contact tel: 18720816902
*/
s32 BBOX_GetTaskId(struct TASK_ATTACH_INFO* pstTaskInfo, s32 iSize, char* szTaskPath)
{
s32 iProc = -1;
pid_t pid = 0;
struct linux_dirent* pstEntry = NULL;
char szBuff[PAGE_SIZE];
ssize_t nBytes;
const char* pszPtr = NULL;
s32 iThreadCount = 0;
if (pstTaskInfo == NULL || szTaskPath == NULL) {
bbox_print(PRINT_ERR,
"parameter is invalid, pstTaskInfo or szTaskPath is NULL, iSize = %d \n",
iSize);
return -1;
}
iProc = sys_open(szTaskPath, O_RDONLY | O_DIRECTORY, 0);
if (iProc < 0) {
bbox_print(PRINT_ERR, "open '%s' failed, errno = %d\n", szTaskPath, errno);
return -1;
}
/* traverse /proc/[pid]/task, get count of thread and pid. */
for (; iThreadCount < iSize;) {
/* get pointer to the directory structure */
nBytes = sys_getdents(iProc, (struct linux_dirent*)szBuff, sizeof(szBuff));
if (nBytes < 0) {
bbox_print(PRINT_ERR, "Get dents '%s' failed, errno = %d\n", szTaskPath, errno);
goto errout;
} else if (0 == nBytes) {
sys_lseek(iProc, 0, SEEK_SET);
break;
}
/* recursively traversing the directory */
for (pstEntry = (struct linux_dirent*)szBuff;
(pstEntry < (struct linux_dirent*)&szBuff[nBytes]) && (iThreadCount < iSize);
pstEntry = (struct linux_dirent*)((char*)pstEntry + pstEntry->d_reclen)) {
if (pstEntry->d_ino == 0) {
continue;
}
pszPtr = pstEntry->d_name;
bbox_print(PRINT_DBG, "dir: %s/%s\n", szTaskPath, pszPtr);
if (*pszPtr == '.') {
pszPtr++;
}
/* ignore directory that is not a proc. */
if (*pszPtr < '0' || *pszPtr > '9') {
continue;
}
/* get pid information */
pid = bbox_atoi(pszPtr);
if (!pid || pid == sys_gettid()) {
bbox_print(PRINT_ERR, "pid is invalid , pid = %d\n", pid);
continue;
}
/* add thread information into a array. */
pstTaskInfo[iThreadCount].pid = pid;
pstTaskInfo[iThreadCount].cIsAttached = 0;
iThreadCount++;
}
}
sys_close(iProc);
return iThreadCount;
errout:
sys_close(iProc);
return -1;
}
/*
function name: BBOX_PtraceAttachPid
description: The function is used to check the process whose id stored in structure array pstTaskInfo work normally.
arguments: The first argument is a structure pointer named pstTaskInfo,its type is struct TASK_ATTACH_INFO*,
it is used as a structure array that has stored requisite thread infomation, the next argument destines
the size of the array that the first argument destines, namely how many elements the array has.
The last argument is an integer to decide if need to check if the trace to destined process
work normally, if normal, corresponding element of array pstTaskInfo's member variable cIsAttached
will change from 0 to 1.
return value: An integer, if function work normally, the value is RET_OK, else is RET_ERR.
note: none
date: 2022/8/3
contact tel: 18720816902
*/
s32 BBOX_PtraceAttachPid(struct TASK_ATTACH_INFO* pstTaskInfo, s32 iPidCount, s32 iDoPtraceCheck)
{
u32 i;
pid_t pid;
unsigned long m = 0;
unsigned long n = 0;
if (pstTaskInfo == NULL || iPidCount <= 0) {
return RET_ERR;
}
for (i = 0; i < (u32)iPidCount; i++) {
/* walk through all the threads and debug the trace. */
pid = pstTaskInfo[i].pid;
if (sys_ptrace(PTRACE_ATTACH, pid, (void*)0, (void*)0) < 0) {
bbox_print(PRINT_ERR, "ptrace failed, pid = %d, errno = %d\n", pid, errno);
continue;
}
/* check that if the thread state is normal. */
while (sys_waitpid(pid, (int*)0, __WALL) < 0) {
if (errno != EINTR) {
bbox_print(PRINT_ERR, "wait for %d failed, errno = %d\n", pid, errno);
sys_ptrace(PTRACE_DETACH, pid, 0, 0);
break;
}
}
if (iDoPtraceCheck) {
int ret = 0;
ret = sys_ptrace(PTRACE_PEEKDATA, pid, &m, &n);
/* check that if the trace is valid */
if (ret || (m != n)) {
bbox_print(PRINT_ERR,
"ptrace peek data failed, pid = %d, ret = %d,m = %lu, n = %lu, errno = %d\n",
pid, ret, m, n, errno);
sys_ptrace(PTRACE_DETACH, pid, 0, 0);
continue;
}
}
bbox_print(PRINT_LOG, "ptrace attach %d\n", pid);
pstTaskInfo[i].cIsAttached = 1;
}
return RET_OK;
}
/*
function name: BBOX_DetachAllThread
description: The function is used to cancel checking the process whose id stored in structure array pstTaskInfo
work normally, "work normally" means in array pstTaskInfo corresponding element's member
variable cIsAttached's value is 1.
arguments: The first argument is a structure pointer named pstTaskInfo,its type is struct TASK_ATTACH_INFO*,
it is used as a structure array that has stored requisite thread infomation, the next argument destines
the size of the array that the first argument destines, namely how many elements the array has.
return value: void
note: none
date: 2022/8/3
contact tel: 18720816902
*/
void BBOX_DetachAllThread(struct TASK_ATTACH_INFO* pstTaskInfo, s32 iPidCount)
{
u32 i;
pid_t pid;
if (pstTaskInfo == NULL || iPidCount <= 0) {
return;
}
for (i = 0; i < (u32)iPidCount; i++) {
pid = pstTaskInfo[i].pid;
if (!pstTaskInfo[i].cIsAttached) {
continue;
}
bbox_print(PRINT_LOG, "ptrace detach %d\n", pid);
/* cancel track. */
sys_sched_yield();
sys_ptrace(PTRACE_DETACH, pid, 0, 0);
sys_kill(pid, SIGCONT);
}
return;
}
/*
* notification function after dump module have got all data, to recover a thread.
*/
void BBOX_CheckResumeThread(void* pArgs)
{
struct TASK_CHECK_RESUME_ARGS* pstTaskCheck = NULL;
if (pArgs == NULL) {
return;
}
pstTaskCheck = (struct TASK_CHECK_RESUME_ARGS*)pArgs;
if (GET_TYPE_SNAP == pstTaskCheck->enType) {
BBOX_DetachAllThread(pstTaskCheck->pstTaskInfo, pstTaskCheck->iThreadCount);
}
}
/*
function name: BBOX_PtraceAndRun
description: When get a path to specific process, this function will trace the threads below it, and get the
information for example how many threads work normally then store it in pstArgs.
arguments: The first argument is a structure pointer named pstArgs, its type is struct BBOX_ListParams*,
what matters is its member variable callback function pointer, the next argument destines
the max count of the thread. The last argument is a pointer of type char*, including a path
to specific process.
return value: An integer, if function work normally, the value is RET_OK, else is RET_ERR.
note: none
date: 2022/8/3
contact tel: 18720816902
*/
s32 BBOX_PtraceAndRun(struct BBOX_ListParams* pstArgs, s32 iMaxThreadCount, char* pszProcSelfTask)
{
struct TASK_ATTACH_INFO stTaskInfo[iMaxThreadCount];
pid_t thread_pids[iMaxThreadCount];
struct TASK_CHECK_RESUME_ARGS stTaskCheck;
s32 iThreadCount = 0;
s32 iAttachCount = 0;
s32 iRet = 0;
s32 iDoPtraceCheck = 1;
s32 i;
if (pstArgs == NULL || pszProcSelfTask == NULL || iMaxThreadCount <= 0) {
bbox_print(PRINT_ERR,
"Parameter is invald, pstArgs or pszProcSelfTask is NULL, iMaxThreadCount = %d \n",
iMaxThreadCount);
return RET_ERR;
}
errno_t rc = memset_s(stTaskInfo, sizeof(stTaskInfo), 0, sizeof(stTaskInfo));
securec_check_c(rc, "\0", "\0");
rc = memset_s(thread_pids, sizeof(thread_pids), 0, sizeof(thread_pids));
securec_check_c(rc, "\0", "\0");
rc = memset_s(&stTaskCheck, sizeof(stTaskCheck), 0, sizeof(stTaskCheck));
securec_check_c(rc, "\0", "\0");
iThreadCount = BBOX_GetTaskId(stTaskInfo, iMaxThreadCount, pszProcSelfTask);
if (iThreadCount <= 0) {
bbox_print(PRINT_ERR, "Get task id failed.\n");
goto errout;
}
if (GET_TYPE_DUMP != pstArgs->enGetType) {
iDoPtraceCheck = 0;
} else {
iDoPtraceCheck = 1;
}
iRet = BBOX_PtraceAttachPid(stTaskInfo, iThreadCount, iDoPtraceCheck);
if (iRet != RET_OK) {
bbox_print(PRINT_ERR, "Ptrace attache failed.\n");
goto errout;
}
/* copy information of thread that have been attaching. */
for (i = 0; i < iThreadCount; i++) {
if (!stTaskInfo[i].cIsAttached) {
continue;
}
thread_pids[iAttachCount] = stTaskInfo[i].pid;
iAttachCount++;
}
stTaskCheck.pstTaskInfo = stTaskInfo;
stTaskCheck.enType = pstArgs->enGetType;
stTaskCheck.iThreadCount = iThreadCount;
/* run call back function. */
bbox_print(PRINT_TIP, "Thread count :%d\n", iThreadCount);
bbox_print(PRINT_TIP, "Ptraced thread count :%d\n", iAttachCount);
bbox_print(PRINT_LOG, "Run callback: thread count = %d\n", iThreadCount);
/* Callback to the thread information handler. */
pstArgs->iResult = pstArgs->pCallBack(BBOX_CheckResumeThread, &stTaskCheck, iAttachCount, thread_pids, pstArgs->ap);
pstArgs->iError = errno;
BBOX_DetachAllThread(stTaskInfo, iThreadCount);
return RET_OK;
errout:
BBOX_DetachAllThread(stTaskInfo, iThreadCount);
return RET_ERR;
}
/*
function name: BBOX_PrintFailedLog
description: Write log infomation into specific file, if errors arise, print the infomation about errors.
arguments: The only argument is a pointer of type const char* to a filename string, if this file doesn't
exist, we will creat a new file named it.
return value: An integer, if function work normally, the value is RET_OK, else is RET_ERR.
note: none
date: 2022/8/3
contact tel: 18720816902
*/
void BBOX_PrintFailedLog(const char* pFileName)
{
ssize_t iRet = 0;
s32 iWriteSize = 0;
s32 iBboxLogFd = -1;
iBboxLogFd = sys_open(pFileName, O_RDWR | O_CREAT | O_TRUNC, 0600);
if (iBboxLogFd < 0) {
bbox_print(PRINT_ERR, "open failed, errno = %d\n", errno);
return;
}
iWriteSize = bbox_strnlen(g_acBBoxLog, BBOX_LOG_SIZE) + 1;
iWriteSize = (iWriteSize > BBOX_LOG_SIZE) ? BBOX_LOG_SIZE : iWriteSize;
iRet = sys_write(iBboxLogFd, g_acBBoxLog, iWriteSize);
if (iRet < 0) {
bbox_print(PRINT_ERR, "write failed, errno = %d\n", errno);
sys_close(iBboxLogFd);
return;
}
sys_close(iBboxLogFd);
}
/*
function name: BBOX_ListThread
description: Export thread information.
arguments: The only argument is a structure pointer named pstArgs, its type is struct BBOX_ListParams*,
what matters is its member variable callback function pointer and thread infomation.
return value: void
note: none
date: 2022/8/3
contact tel: 18720816902
*/
void BBOX_ListThread(struct BBOX_ListParams* pstArgs)
{
pid_t ppid = 0;
s32 iMaker = -1;
s32 iMaxThreadCount = 0;
s32 iRet = 0;
struct kernel_stat stMarkerSB;
char szProcSelfTask[BBOX_PROC_PATH_LEN];
char pszMarkPath[BBOX_PROC_PATH_LEN];
stack_t altstack;
errno_t rc = EOK;
if (pstArgs == NULL) {
bbox_print(PRINT_ERR, "pstArgs is NULL.\n");
return;
}
ppid = sys_getppid();
iMaker = sys_socket(PF_LOCAL, SOCK_DGRAM, 0);
if (iMaker < 0) {
bbox_print(PRINT_ERR, "sys_socket error, errno = %d\n", errno);
goto errout;
}
if (sys_fcntl(iMaker, F_SETFD, FD_CLOEXEC) < 0) {
bbox_print(PRINT_ERR, "sys_fcntl error, errno = %d\n", errno);
goto errout;
}
if (bbox_snprintf(szProcSelfTask, BBOX_PROC_PATH_LEN, "/proc/%d/task", ppid) <= 0) {
bbox_print(PRINT_ERR, "bbox_snprintf is failed, errno = %d.\n", errno);
goto errout;
}
if (bbox_snprintf(pszMarkPath, BBOX_PROC_PATH_LEN, "/proc/%d/fd/%d", ppid, iMaker) <= 0) {
bbox_print(PRINT_ERR, "bbox_snprintf is failed, errno = %d.\n", errno);
goto errout;
}
bbox_print(PRINT_TIP, "Get information for pid %d:\n", ppid);
rc = memset_s(&stMarkerSB, sizeof(stMarkerSB), 0, sizeof(stMarkerSB));
securec_check_c(rc, "\0", "\0");
if (sys_stat(pszMarkPath, &stMarkerSB) < 0) {
bbox_print(PRINT_ERR, "sys_stat error, errno = %d, path = %s\n", errno, pszMarkPath);
goto errout;
}
/* switch stack pointer */
rc = memset_s(&altstack, sizeof(altstack), 0, sizeof(altstack));
securec_check_c(rc, "\0", "\0");
altstack.ss_sp = pstArgs->pAltStackMem;
altstack.ss_flags = 0;
altstack.ss_size = BBOX_ALT_STACKSIZE;
sys_sigaltstack(&altstack, (const stack_t*)NULL);
/* get max count of task. */
iMaxThreadCount = BBOX_GetTaskNumber(szProcSelfTask);
if (iMaxThreadCount <= 0) {
bbox_print(PRINT_ERR, "Get task number failed.\n");
goto errout;
}
/* ptrace and run thread. */
iRet = BBOX_PtraceAndRun(pstArgs, iMaxThreadCount, szProcSelfTask);
if (iRet != RET_OK) {
bbox_print(PRINT_ERR, "ptrace task and run failed.\n");
goto errout;
}
bbox_print(PRINT_TIP, "Get information success.\n");
sys_close(iMaker);
if (RET_OK != pstArgs->iResult) {
BBOX_PrintFailedLog((char*)(((struct BBOX_ListDirParam*)(pstArgs->pDoneArgs))->pArg2));
}
if (pstArgs->pDoneCallback != NULL) {
pstArgs->pDoneCallback(pstArgs->pDoneArgs);
}
sys_exit(0);
errout:
if (iMaker > 0) {
sys_close(iMaker);
}
bbox_print(PRINT_ERR, "Get information failed.\n");
pstArgs->iResult = -1;
pstArgs->iError = errno;
BBOX_PrintFailedLog((char*)(((struct BBOX_ListDirParam*)(pstArgs->pDoneArgs))->pArg2));
if (pstArgs->pDoneCallback != NULL) {
pstArgs->pDoneCallback(pstArgs->pDoneArgs);
}
sys_exit(1);
}
/*
function name: BBOX_GetClonePidResult
description: The function get the status of child process at first, then according to it assign pstArgs's
member variables iError and iResult appropriate values.
arguments: The first argument is a integer named iClonePid, it represents the pid of child process.
The second argument is a structure pointer named pstArgs, its type is struct BBOX_ListParams*,
what matters is its member variable callback function pointer and thread infomation.
The third argument is a integer indicating error code.
return value: An integer, if function work normally, the value is RET_OK, else is RET_ERR.
note: none
date: 2022/8/3
contact tel: 18720816902
*/
s32 BBOX_GetClonePidResult(pid_t iClonePid, struct BBOX_ListParams* pstArgs, s32 iCloneErrno)
{
s32 iStatus = 0;
s32 iRet = 0;
if (iClonePid < 0) {
bbox_print(PRINT_ERR, "Clone failed, can't create child process, errno = %d.\n", iCloneErrno);
BBOX_PrintFailedLog((char*)(((struct BBOX_ListDirParam*)(pstArgs->pDoneArgs))->pArg2));
if (pstArgs->pDoneCallback != NULL) {
pstArgs->pDoneCallback(pstArgs->pDoneArgs);
}
return RET_ERR;
}
/* wait child process exit. */
while ((iRet = sys_waitpid(iClonePid, &iStatus, __WALL)) < 0 && errno == EINTR) {
continue;
}
bbox_print(PRINT_LOG, "clone pid %d ret is %x, status = %x\n", iClonePid, iRet, WIFEXITED(iStatus));
if (iRet < 0) {
pstArgs->iError = errno;
pstArgs->iResult = -1;
} else if (WIFEXITED(iStatus)) {
switch (WEXITSTATUS(iStatus)) {
case 0:
break;
case 2:
pstArgs->iError = EFAULT;
pstArgs->iResult = -1;
break;
case 3:
pstArgs->iError = EPERM;
pstArgs->iResult = 1;
break;
default:
pstArgs->iError = ECHILD;
pstArgs->iResult = -1;
break;
}
} else if (!WIFEXITED(iStatus)) {
pstArgs->iError = EFAULT;
pstArgs->iResult = -1;
bbox_print(PRINT_ERR, "WIFEXITED status failed");
} else {
pstArgs->iError = iCloneErrno;
pstArgs->iResult = -1;
bbox_print(PRINT_ERR, "WIFEXITED error, errno = %d\n", iCloneErrno);
}
return RET_OK;
}
/*
* get all threads and run specify function
*/
s32 BBOX_GetAllThreads(
GET_THREAD_TYPE enType, BBOX_GetAllThreadDone pDone, void* pDoneArgs, BBOX_GetAllThreadsCallBack pCallback, ...)
{
struct BBOX_ListParams stArgs;
struct kernel_sigset_t stSigBlocked;
struct kernel_sigset_t stSigOld;
s32 iDumpable = 1;
s32 iSigNo;
s32 iCloneErrno;
pid_t ClonePid;
errno = 0;
if (BBOX_AtomicIncReturn(&g_isBusy) > 1) {
BBOX_AtomicDec(&g_isBusy);
bbox_print(PRINT_ERR, "Dump task is running.\n");
errno = EALREADY;
return -1;
}
if (enType >= GET_TYPE_BUTT || pCallback == NULL) {
bbox_print(PRINT_ERR, "Parameter is invalid, enType = %d, and maybe pCallback is NULL", enType);
BBOX_AtomicDec(&g_isBusy);
return -1;
}
errno_t rc = memset_s(&stArgs, sizeof(stArgs), 0, sizeof(stArgs));
securec_check_c(rc, "\0", "\0");
rc = memset_s(&stSigBlocked, sizeof(stSigBlocked), 0, sizeof(stSigBlocked));
securec_check_c(rc, "\0", "\0");
rc = memset_s(&stSigOld, sizeof(stSigOld), 0, sizeof(stSigOld));
securec_check_c(rc, "\0", "\0");
va_start(stArgs.ap, pCallback);
/* clear new stack */
rc = memset_s(g_szAltStackMem, BBOX_ALT_STACKSIZE, 0, BBOX_ALT_STACKSIZE);
securec_check_c(rc, "\0", "\0");
/* reserve 32K */
BBOX_ReserveZeroStack(1024 * 32);
/* check and set dump flag. */
iDumpable = sys_prctl(PR_GET_DUMPABLE, 0, 0, 0, 0);
if (!iDumpable) {
sys_prctl(PR_SET_DUMPABLE, 1, 0, 0, 0);
}
/* set start parameter of dump thread. */
stArgs.iResult = -1;
stArgs.iError = 0;
stArgs.pAltStackMem = g_szAltStackMem;
stArgs.pCallBack = pCallback;
stArgs.pDoneCallback = pDone;
stArgs.pDoneArgs = pDoneArgs;
stArgs.enGetType = enType;
/* suspend all signals */
sys_sigfillset(&stSigBlocked);
for (iSigNo = 0; iSigNo < (s32)(sizeof(iSyncSignals) / sizeof(*iSyncSignals)); iSigNo++) {
sys_sigdelset(&stSigBlocked, iSyncSignals[iSigNo]);
}
/* block all signals */
if (sys_sigprocmask(SIG_BLOCK, &stSigBlocked, &stSigOld)) {
stArgs.iError = errno;
stArgs.iResult = -1;
bbox_print(PRINT_ERR, "sys_sigprocmask error, errno = %d\n", errno);
goto errout;
}
/* create child process and run function to export thread information. */
if (GET_TYPE_DUMP == enType) {
ClonePid = BBOX_CloneRun(CLONE_VM | CLONE_FS | CLONE_FILES, (s32(*)(void*))BBOX_ListThread, &stArgs);
} else {
/* copy VMA if type is snapshoot. */
ClonePid = BBOX_CloneRun(CLONE_FS | CLONE_FILES, (s32(*)(void*))BBOX_ListThread, &stArgs);
}
iCloneErrno = errno;
/* restoring signal */
sys_sigprocmask(SIG_SETMASK, &stSigOld, &stSigOld);
if (BBOX_GetClonePidResult(ClonePid, &stArgs, iCloneErrno) != RET_OK) {
bbox_print(PRINT_ERR, "BBOX_GetClonePidResult error\n");
}
errout:
BBOX_AtomicDec(&g_isBusy);
if (!iDumpable) {
sys_prctl(PR_SET_DUMPABLE, iDumpable, 0, 0, 0);
}
va_end(stArgs.ap);
errno = stArgs.iError;
return stArgs.iResult;
}