往前冲队-合并请求 #37

Open
makqmlwy5 wants to merge 56 commits from makqmlwy5/openGauss-server:master into master
29 changed files with 11894 additions and 9060 deletions

View File

@ -142,72 +142,72 @@ int SYS_NAME(sysconf)(int name)
{
switch (name) {
case _SC_PAGESIZE:
return getpagesize();
return getpagesize(); // 返回系统页面大小
case _SC_OPEN_MAX: {
struct kernel_rlimit limit = {0};
if (sys_getrlimit(RLIMIT_NOFILE, &limit) >= 0) {
return limit.rlim_cur;
struct kernel_rlimit limit = {0}; // 创建一个kernel_rlimit结构体并初始化为0
if (sys_getrlimit(RLIMIT_NOFILE, &limit) >= 0) { // 调用sys_getrlimit函数将RLIMIT_NOFILE资源限制信息存储在limit中
return limit.rlim_cur; // 返回当前进程的最大打开文件数
} else {
/* Default maximum open files for per process */
return 8192;
return 8192; // 返回默认的最大打开文件数为8192
}
}
default:
errno = ENOSYS;
errno = ENOSYS; // 如果name不匹配_SC_PAGESIZE和_SC_OPEN_MAX则设置errno为ENOSYS表示函数未实现
return -1;
}
}
int SYS_NAME(sigemptyset)(struct kernel_sigset_t* set)
{
errno_t rc = memset_s(set->sig, sizeof(set->sig), 0, sizeof(set->sig));
errno_t rc = memset_s(set->sig, sizeof(set->sig), 0, sizeof(set->sig)); // 使用memset_s函数将set->sig的值设置为0
securec_check_c(rc, "\0", "\0");
return 0;
}
int SYS_NAME(sigfillset)(struct kernel_sigset_t* set)
{
errno_t rc = memset_s(set->sig, sizeof(set->sig), 0xFF, sizeof(set->sig));
errno_t rc = memset_s(set->sig, sizeof(set->sig), 0xFF, sizeof(set->sig)); // 使用memset_s函数将set->sig的值设置为0xFF
securec_check_c(rc, "\0", "\0");
return 0;
}
int SYS_NAME(sigaddset)(struct kernel_sigset_t* set, int __signum)
{
int signo = (int)(8 * sizeof(set->sig));
int signo = (int)(8 * sizeof(set->sig)); // 计算消息信号集的位数
if (__signum < 1 || __signum > signo) {
errno = EINVAL;
errno = EINVAL; // 如果__signum小于1或大于signo设置errno为EINVAL表示无效参数
return -1;
} else {
set->sig[(__signum - 1) / (8 * sizeof(set->sig[0]))] |= 1UL << ((__signum - 1) % (8 * sizeof(set->sig[0])));
set->sig[(__signum - 1) / (8 * sizeof(set->sig[0]))] |= 1UL << ((__signum - 1) % (8 * sizeof(set->sig[0]))); // 将__signum对应的位设置为1
return 0;
}
}
int SYS_NAME(sigdelset)(struct kernel_sigset_t* set, int __signum)
{
int signo = (int)(8 * sizeof(set->sig));
int signo = (int)(8 * sizeof(set->sig)); // 计算消息信号集的位数
if (__signum < 1 || __signum > signo) {
errno = EINVAL;
errno = EINVAL; // 如果__signum小于1或大于signo设置errno为EINVAL表示无效参数
return -1;
} else {
set->sig[(__signum - 1) / (8 * sizeof(set->sig[0]))] &= ~(1UL << ((__signum - 1) % (8 * sizeof(set->sig[0]))));
set->sig[(__signum - 1) / (8 * sizeof(set->sig[0]))] &= ~(1UL << ((__signum - 1) % (8 * sizeof(set->sig[0])))); // 将__signum对应的位设置为0
return 0;
}
}
int SYS_NAME(sigismember)(struct kernel_sigset_t* set, int __signum)
{
int signo = (int)(8 * sizeof(set->sig));
int signo = (int)(8 * sizeof(set->sig)); // 计算消息信号集的位数
if (__signum < 1 || __signum > signo) {
errno = EINVAL;
errno = EINVAL; // 如果__signum小于1或大于signo设置errno为EINVAL表示无效参数
return -1;
} else {
return !!(set->sig[(__signum - 1) / (8 * sizeof(set->sig[0]))] &
(1UL << ((__signum - 1) % (8 * sizeof(set->sig[0])))));
(1UL << ((__signum - 1) % (8 * sizeof(set->sig[0]))))); // 检查__signum对应的位是否为1返回结果
}
}
@ -215,7 +215,7 @@ long SYS_NAME(sigprocmask)(int how, struct kernel_sigset_t* set, struct kernel_s
{
long ret = 0;
ret = SYS_NAME(rt_sigprocmask)(how, set, oldset, (KERNEL_NSIG + 7) / 8);
ret = SYS_NAME(rt_sigprocmask)(how, set, oldset, (KERNEL_NSIG + 7) / 8); // 调用SYS_NAME(rt_sigprocmask)函数设置信号屏蔽字
return ret;
}
@ -428,7 +428,7 @@ __syscall5(
long SYS_NAME(waitpid)(pid_t pid, int* status, int options)
{
return SYS_NAME(wait4)(pid, status, options, 0);
return SYS_NAME(wait4)(pid, status, options, 0); // 调用SYS_NAME(wait4)函数等待子进程结束
}
long SYS_NAME(signal)(int __signum, void (*handler)(int))
@ -436,22 +436,23 @@ long SYS_NAME(signal)(int __signum, void (*handler)(int))
struct kernel_sigaction _sa;
struct kernel_sigaction old;
errno_t rc = memset_s(&_sa, sizeof(_sa), 0, sizeof(_sa));
errno_t rc = memset_s(&_sa, sizeof(_sa), 0, sizeof(_sa)); // 使用memset_s函数将_sa的值设置为0
securec_check_c(rc, "\0", "\0");
sys_sigfillset(&_sa.sa_mask);
_sa.sa_flags |= SA_RESTORER | SA_RESTART;
_sa.handle.sa_handler_ = handler;
sys_sigfillset(&_sa.sa_mask); // 将_sa.sa_mask的所有位都设置为1
_sa.sa_flags |= SA_RESTORER | SA_RESTART; // 设置_sa.sa_flags的标志位
_sa.handle.sa_handler_ = handler; // 设置_sa.handle.sa_handler_为传入的handler函数
return SYS_NAME(rt_sigaction)(__signum, &_sa, &old, (KERNEL_NSIG + 7) / 8);
return SYS_NAME(rt_sigaction)(__signum, &_sa, &old, (KERNEL_NSIG + 7) / 8); // 调用SYS_NAME(rt_sigaction)函数设置信号处理动作
}
long SYS_NAME(_clone)(
int (*fn)(void*), void* child_stack, int flags, void* arg, int* parent_tidptr, void* newtls, int* child_tidptr)
/*
long SYS_NAME(_clone)(int (fn)(void), void* child_stack, int flags, void* arg, int* parent_tidptr, void* newtls, int* child_tidptr)
*/
long SYS_NAME(_clone)(int (*fn)(void*), void* child_stack, int flags, void* arg, int* parent_tidptr, void* newtls, int* child_tidptr)
{
register long ___res __asm__("r5");
{
if (fn == NULL || child_stack == NULL) {
if (fn == NULL || child_stack == NULL) { // 如果传入的函数指针为NULL或者子进程栈指针为NULL则返回EINVAL错误码
___res = -EINVAL;
goto _clone_exit;
}
@ -459,24 +460,25 @@ long SYS_NAME(_clone)(
/* stash first 4 arguments on stack first because we can only load
* them after all function calls.
*/
int tmp_flags = flags;
int* tmp_stack = (int*)child_stack;
void* tmp_ptid = parent_tidptr;
void* tmp_tls = newtls;
int tmp_flags = flags; // 复制flags的值 `tmp_flags`变量用于保存`flags`的值。
register int* ___ctid __asm__("r4") = child_tidptr;
int* tmp_stack = (int*)child_stack; // 将子进程栈指针转换为int类型指针并保存为tmp_stack
void* tmp_ptid = parent_tidptr; // 保存parent_tidptr的值
void* tmp_tls = newtls; // 保存newtls的值
register int* ___ctid __asm__("r4") = child_tidptr; // 将child_tidptr保存到___ctid寄存器变量中
/* Push "arg" and "fn" onto the stack that will be
* used by the child.
*/
*(--tmp_stack) = (int)arg;
*(--tmp_stack) = (int)fn;
*(--tmp_stack) = (int)arg; // 将arg的值存入子进程栈中
*(--tmp_stack) = (int)fn; // 将fn的值存入子进程栈中
/* We must load r0..r3 last after all possible function calls. */
register int ___flags __asm__("r0") = tmp_flags;
register void* ___stack __asm__("r1") = tmp_stack;
register void* ___ptid __asm__("r2") = tmp_ptid;
register void* ___tls __asm__("r3") = tmp_tls;
register int ___flags __asm__("r0") = tmp_flags; // 将tmp_flags保存到___flags寄存器变量中
register void* ___stack __asm__("r1") = tmp_stack; // 将tmp_stack保存到___stack寄存器变量中
register void* ___ptid __asm__("r2") = tmp_ptid; // 将tmp_ptid保存到___ptid寄存器变量中
register void* ___tls __asm__("r3") = tmp_tls; // 将tmp_tls保存到___tls寄存器变量中
/* example: %r0 = syscall(%r0 = flags,
* %r1 = child_stack,
@ -484,28 +486,29 @@ long SYS_NAME(_clone)(
* %r3 = newtls,
* %r4 = child_tidptr)
*/
__SYS_REG(clone)
__SYS_REG(clone) // 定义宏__SYS_REG(clone)
__asm__ __volatile__(
"push {r7}\n"
"mov r7,%1\n" __syscall(clone) "\n"
"push {r7}\n" // 将r7寄存器的值保存到栈中
"mov r7,%1\n" __syscall(clone) "\n" // 调用系统调用clone
"movs %0,r0\n"
"bne 1f\n"
"movs %0,r0\n" // 将r0的值保存到___res中并设置条件码
"bne 1f\n" // 如果条件码不等于0则跳转到标号1处
"ldr r0,[sp, #4]\n"
"mov lr,pc\n"
"ldr pc,[sp]\n"
"ldr r0,[sp, #4]\n" // 将sp加上4得到地址然后将该地址处的内容保存到r0寄存器中
"mov lr,pc\n" // 将pc的值保存到lr寄存器中
"ldr pc,[sp]\n" // 将sp的值保存到pc寄存器中
"mov r7,%2\n" __syscall(exit) "\n"
"mov r7,%2\n" __syscall(exit) "\n" // 调用系统调用exit
"1: pop {r7}\n"
: "=r"(___res)
: "r"(__sysreg), "i"(__NR_exit), "r"(___stack), "r"(___flags), "r"(___ptid), "r"(___tls), "r"(___ctid)
: "cc", "lr", "memory");
"1: pop {r7}\n" // 将栈中的值保存到r7寄存器中
: "=r"(___res) // 输出结果保存到___res寄存器变量中
: "r"(__sysreg), "i"(__NR_exit), "r"(___stack), "r"(___flags), "r"(___ptid), "r"(___tls), "r"(___ctid) // 输入参数
: "cc", "lr", "memory"); // 修改了条件码lr寄存器内容以及内存
}
_clone_exit:
___syscall_return(int, ___res);
___syscall_return(int, ___res); // 调用___syscall_return函数返回结果
}
#elif (defined(__aarch64__))

1137
bootstrap.cpp Normal file

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -1,22 +1,21 @@
/*
* Copyright (c) 2019 Huawei Technologies Co.,Ltd.
* (c) 2019
*
* 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:
* openGauss在Mulan PSL v2下获得许可
* Mulan PSL v2的条款和条件使用此软件
* Mulan PSL v2的副本
*
* 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.
* "按原样"
*
* Mulan PSL v2
* -------------------------------------------------------------------------
*
* cgexcp.cpp
* Cgroup exceptional data process
* Cgroup异常数据处理
*
* IDENTIFICATION
*
* src/bin/gs_cgroup/cgexcp.cpp
*
* -------------------------------------------------------------------------
@ -47,11 +46,11 @@
} \
}
/*
* function name: cgexcp_skewpercent_is_invalid
* description : check skew percent whether is invalid
* return value : 0: valid, 1: invalid
*/
/*
* cgexcp_skewpercent_is_invalid
*
* 01
*/
static int cgexcp_skewpercent_is_invalid(const except_data_t* except)
{
if ((except->skewpercent > 0 && except->qualitime > 0) || (except->skewpercent <= 0 && except->qualitime <= 0))
@ -59,38 +58,36 @@ static int cgexcp_skewpercent_is_invalid(const except_data_t* except)
return 1;
}
/**
* cgexcp_exception_save
*
*
* -1
* 0
*/
static int cgexcp_exception_save(gscgroup_grp_t* grp) {
char* p = NULL; // 保存解析字符串的指针
char* q = NULL; // 保存','字符的指针
char eflag; // 异常标志
unsigned long val; // 异常值
int err = 0; // 错误码
/*
* function name: cgexcp_exception_save
* description : save the exceptional data into the config file
* return value :
* -1: abnormal
* 0: normal
*
*/
static int cgexcp_exception_save(gscgroup_grp_t* grp)
{
char *p = NULL;
char *q = NULL;
char eflag;
unsigned long val;
int err = 0;
p = cgutil_opt.edata;
eflag = cgutil_opt.eflag;
p = cgutil_opt.edata; // 获取解析字符串
eflag = cgutil_opt.eflag; // 获取异常标志
do {
while (*p == ' ') {
while (*p == ' ') { // 跳过空格字符
p++;
}
q = strchr(p, ',');
q = strchr(p, ','); // 查找','字符
if (q != NULL) {
*q++ = '\0';
*q++ = '\0'; // 将','字符置为字符串结束符
}
if (strncasecmp("BlockTime=", p, sizeof("BlockTime=") - 1) == 0) {
EXCP_PARSE_KEY(p, val);
if (strncasecmp("BlockTime=", p, sizeof("BlockTime=") - 1) == 0) { // 判断是否为"BlockTime="字符串
EXCP_PARSE_KEY(p, val); // 解析异常值
if (val > UINT_MAX) {
if (val > UINT_MAX) { // 判断异常值是否超出范围
fprintf(stderr,
"ERROR: threshold \'BlockTime\', "
"value limit exceeded, it should be 0~%u!\n",
@ -99,7 +96,7 @@ static int cgexcp_exception_save(gscgroup_grp_t* grp)
break;
}
if (IS_EXCEPT_FLAG(eflag, EXCEPT_PENALTY)) {
if (IS_EXCEPT_FLAG(eflag, EXCEPT_PENALTY)) { // 判断异常标志位是否为"penalty"
fprintf(stderr,
"ERROR: threshold \'BlockTime\' "
"for \"penalty\" is invalid!\n");
@ -107,137 +104,84 @@ static int cgexcp_exception_save(gscgroup_grp_t* grp)
break;
}
grp->except[eflag - 1].blocktime = (unsigned int)val;
} else if (strncasecmp("ElapsedTime=", p, sizeof("ElapsedTime=") - 1) == 0) {
EXCP_PARSE_KEY(p, val);
if (val > UINT_MAX) {
fprintf(stderr,
"ERROR: threshold \'ElapsedTime\', "
"value limit exceeded, it should be 0~%u!\n",
UINT_MAX);
err = -1;
break;
}
if (IS_EXCEPT_FLAG(eflag, EXCEPT_PENALTY)) {
fprintf(stderr,
"ERROR: threshold \'ElapsedTime\', "
"for \"penalty\" is invalid!\n");
err = -1;
break;
}
grp->except[eflag - 1].elapsedtime = (unsigned int)val;
} else if (strncasecmp("SpillSize=", p, sizeof("SpillSize=") - 1) == 0) {
EXCP_PARSE_KEY(p, val);
if (val > UINT_MAX) {
fprintf(stderr,
"ERROR: threshold \'SpillSize\', "
"value limit exceeded, it should be 0~%u!\n",
UINT_MAX);
err = -1;
break;
}
if (IS_EXCEPT_FLAG(eflag, EXCEPT_PENALTY)) {
fprintf(stderr,
"ERROR: threshold \'SpillSize\', "
"for \"penalty\" is invalid!\n");
err = -1;
break;
}
grp->except[eflag - 1].spoolsize = (int64)val;
} else if (strncasecmp("BroadcastSize=", p, sizeof("BroadcastSize=") - 1) == 0) {
EXCP_PARSE_KEY(p, val);
if (val > UINT_MAX) {
fprintf(stderr,
"ERROR: threshold \'BroadcastSize\', "
"value limit exceeded, it should be 0~%u!\n",
UINT_MAX);
err = -1;
break;
}
if (IS_EXCEPT_FLAG(eflag, EXCEPT_PENALTY)) {
fprintf(stderr,
"ERROR: threshold \'BroadcastSize\', "
"for \"penalty\" is invalid!\n");
err = -1;
break;
}
grp->except[eflag - 1].broadcastsize = (int64)val;
} else if (strncasecmp("AllCpuTime=", p, sizeof("AllCpuTime=") - 1) == 0) {
EXCP_PARSE_KEY(p, val);
if (val > UINT_MAX) {
fprintf(stderr,
"ERROR: threshold \'AllCpuTime\', "
"value limit exceeded, it should be 0~%u!\n",
UINT_MAX);
err = -1;
break;
}
grp->except[eflag - 1].allcputime = (unsigned int)val;
} else if (strncasecmp("QualificationTime=", p, sizeof("QualificationTime=") - 1) == 0) {
EXCP_PARSE_KEY(p, val);
if (val > UINT_MAX) {
fprintf(stderr,
"ERROR: threshold \'QualificationTime\', "
"value limit exceeded, it should be 0~%u!\n",
UINT_MAX);
err = -1;
break;
}
grp->except[eflag - 1].qualitime = (unsigned int)val;
} else if (strncasecmp("CPUSkewPercent=", p, sizeof("CPUSkewPercent=") - 1) == 0) {
EXCP_PARSE_KEY(p, val);
if (val > 100) {
fprintf(stderr,
"ERROR: threshold \'CPUSkewPercent\', "
"value '%u' is invalid, it must be 0~100!\n",
(unsigned int)val);
err = -1;
break;
}
grp->except[eflag - 1].skewpercent = (unsigned int)val;
} else {
fprintf(stderr, "ERROR: exception key string '%s' doesn't be supported!\n", p);
err = -1;
break;
grp->except[eflag - 1].blocktime = (unsigned int)val; // 将异常值保存到对应的异常数据结构中
}
p = q;
} while ((q != NULL) && *q);
else if (strncasecmp("ElapsedTime=", p, sizeof("ElapsedTime=") - 1) == 0) { // 判断是否为"ElapsedTime="字符串
EXCP_PARSE_KEY(p, val); // 解析异常值
if (cgexcp_skewpercent_is_invalid(&grp->except[eflag - 1])) {
grp->except[eflag - 1].skewpercent = 0;
grp->except[eflag - 1].qualitime = 0;
fprintf(stderr,
"ERROR: exception key string '%s' is invalid, "
"\'CPUSkewPercent\' must be specified together with \'QualificationTime\'!\n",
cgutil_opt.edata);
if (val > UINT_MAX) { // 判断异常值是否超出范围
fprintf(stderr,
"ERROR: threshold \'ElapsedTime\', "
"value limit exceeded, it should be 0~%u!\n",
UINT_MAX);
err = -1;
break;
}
return -1;
}
if (IS_EXCEPT_FLAG(eflag, EXCEPT_PENALTY)) { // 判断异常标志位是否为"penalty"
fprintf(stderr,
"ERROR: threshold \'ElapsedTime\', "
"for \"penalty\" is invalid!\n");
err = -1;
break;
}
return err;
grp->except[eflag - 1].elapsedtime = (unsigned int)val; // 将异常值保存到对应的异常数据结构中
}
else if (strncasecmp("SpillSize=", p, sizeof("SpillSize=") - 1) == 0) { // 判断是否为"SpillSize="字符串
EXCP_PARSE_KEY(p, val); // 解析异常值
if (val > UINT_MAX) { // 判断异常值是否超出范围
fprintf(stderr,
"ERROR: threshold \'SpillSize\', "
"value limit exceeded, it should be 0~%u!\n",
UINT_MAX);
err = -1;
break;
}
if (IS_EXCEPT_FLAG(eflag, EXCEPT_PENALTY)) { // 判断异常标志位是否为"penalty"
fprintf(stderr,
"ERROR: threshold \'SpillSize\', "
"for \"penalty\" is invalid!\n");
err = -1;
break;
}
grp->except[eflag - 1].spoolsize = (int64)val; // 将异常值保存到对应的异常数据结构中
}
else if (strncasecmp("BroadcastSize=", p, sizeof("BroadcastSize=") - 1) == 0) { // 判断是否为"BroadcastSize="字符串
EXCP_PARSE_KEY(p, val); // 解析异常值
if (val > UINT_MAX) { // 判断异常值是否超出范围
fprintf(stderr,
"ERROR: threshold \'BroadcastSize\', "
"value limit exceeded, it should be 0~%u!\n",
UINT_MAX);
err = -1;
break;
}
if (IS_EXCEPT_FLAG(eflag, EXCEPT_PENALTY)) { // 判断异常标志位是否为"penalty"
fprintf(stderr,
"ERROR: threshold \'BroadcastSize\', "
"for \"penalty\" is invalid!\n");
err = -1;
break;
}
grp->except[eflag - 1].broadcastsize = (int64)val; // 将异常值保存到对应的异常数据结构中
}
} while (q != NULL);
return err; // 返回错误码
}
/*
* function name: cgexcp_class_exception
* description : deal with the class exception
* return value :
* -1: abnormal
* 0: normal
* cgexcp_class_exception
*
*
* -1
* 0
*
*/
int cgexcp_class_exception(void)
@ -249,7 +193,7 @@ int cgexcp_class_exception(void)
char* tmpstr = NULL;
size_t wdname_len;
/* check if the class exists */
/* 检查类是否存在 */
for (i = CLASSCG_START_ID; i <= CLASSCG_END_ID; i++) {
if (cgutil_vaddr[i]->used == 0)
continue;
@ -260,7 +204,7 @@ int cgexcp_class_exception(void)
}
}
/* back up the config file */
/* 备份配置文件 */
if (-1 == cgconf_backup_config_file()) {
return -1;
}
@ -274,7 +218,7 @@ int cgexcp_class_exception(void)
if (cgutil_vaddr[i]->used == 0 || cgutil_vaddr[i]->ginfo.wd.cgid != cls)
continue;
/* workload name with level or no level */
/* 判断工作负载名称是否有级别或者没有级别 */
if (tmpstr != NULL)
cmp = strcmp(cgutil_vaddr[i]->grpname, cgutil_opt.wdname);
else {
@ -293,22 +237,37 @@ int cgexcp_class_exception(void)
cgconf_remove_backup_conffile();
return -1;
}
} else {
fprintf(stderr, "ERROR: the specified workload %s doesn't exist!\n", cgutil_opt.wdname);
}
else {
fprintf(stderr, "错误:指定的工作负载 %s 不存在!\n", cgutil_opt.wdname);
cgconf_remove_backup_conffile();
return -1;
}
} else {
}
else {
if (-1 == cgexcp_exception_save(cgutil_vaddr[cls])) {
cgconf_remove_backup_conffile();
return -1;
}
}
} else {
fprintf(stderr, "ERROR: the specified class %s doesn't exist!\n", cgutil_opt.clsname);
}
else {
fprintf(stderr, "错误:指定的类 %s 不存在!\n", cgutil_opt.clsname);
cgconf_remove_backup_conffile();
return -1;
}
return 0;
}
// 示例说明:
// 该函数用于处理类异常,首先检查指定的类是否存在,然后备份配置文件,接着根据不同的条件判断是否需要处理工作负载的异常。
// 如果指定了异常中止标志位并且指定了工作负载名称,那么根据工作负载名称和类的关联关系找到对应的工作负载,并将其异常信息保存。
// 如果没有指定工作负载名称,直接根据类的信息保存异常信息。
// 如果指定的类不存在,则输出错误信息并返回异常。
// 语言块功能解析:
// 1. 备份配置文件cgconf_backup_config_file()函数用于备份配置文件。
// 2. 判断工作负载名称是否有级别或者没有级别根据工作负载名称判断是否有级别如果有则使用strcmp()函数进行比较如果没有则使用strncmp()函数进行比较。
// 3. 异常信息保存cgexcp_exception_save()函数用于保存异常信息。
// 4. 移除备份的配置文件cgconf_remove_backup_conffile()函数用于移除备份的配置文件。

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

134
src/gausskernel/bootstrap/bootstrap.cpp Executable file → Normal file
View File

@ -188,6 +188,21 @@ typedef struct _IndexList {
*
* This code is here just because of historical reasons.
*/
//这是一个主要的引导启动进程。它包含以下主要步骤:
//初始化全局变量设置进程IDPostmasterPid和启动时间MyStartTime
//使用进程ID和启动时间作为种子初始化随机数。
//初始化错误和内存管理子系统。
//初始化全局配置选项。
//处理命令行参数。根据参数设置相应的配置选项。
//验证并设置数据目录。
//创建数据目录的锁文件。
//设置处理模式为BootstrapProcessing。
//初始化基本的后台进程。
//初始化统计信息收集。
//根据进程类型执行相应的操作。
//如果进程类型是CheckerProcess则执行CheckerModeMain()函数,并退出进程。
//如果进程类型是BootstrapProcess则设置信号处理函数执行BootStrapXLOG()函数然后执行BootstrapModeMain()函数,并退出进程。
//如果进程类型未被识别则触发PANIC错误并退出进程。
void BootStrapProcessMain(int argc, char* argv[])
{
char* progName = argv[0];
@ -388,44 +403,45 @@ static void CheckerModeMain(void)
* The bootstrap backend doesn't speak SQL, but instead expects
* commands in a special bootstrap language.
*/
static void BootstrapModeMain(void)
static void BootstrapModeMain(void)//BootstrapModeMain函数用于完成系统引导模式即系统启动阶段执行的函数
{
int i;
Assert(!IsUnderPostmaster);
Assert(!IsUnderPostmaster);// 断言,确认不是在后台进程中执行
SetProcessingMode(BootstrapProcessing);
SetProcessingMode(BootstrapProcessing);// 设置处理模式为引导模式
/*
* Do backend-like initialization for bootstrap mode
*/
InitProcess();
InitProcess();//为引导模式做类似后台进程的初始化
// 设置参数PostInit字段为NULL
t_thrd.proc_cxt.PostInit->SetDatabaseAndUser(NULL, InvalidOid, NULL);
// 初始化引导模式
t_thrd.proc_cxt.PostInit->InitBootstrap();
/* Initialize stuff for bootstrap-file processing */
/* 初始化bootstrap文件处理的相关内容 */
for (i = 0; i < MAXATTR; i++) {
t_thrd.bootstrap_cxt.attrtypes[i] = NULL;
Nulls[i] = false;
t_thrd.bootstrap_cxt.attrtypes[i] = NULL;// 每个属性的类型初始化为NULL
Nulls[i] = false; // 每个属性的是否为空初始化为false
}
/*
* Process bootstrap input.
*/
boot_yyparse();
boot_yyparse();//处理bootstrap输入
/*
* We should now know about all mapped relations, so it's okay to write
* out the initial relation mapping files.
*/
RelationMapFinishBootstrap();
RelationMapFinishBootstrap();// 调用boot_yyparse函数进行解析
/* Clean up and exit */
cleanup();
proc_exit(0);
cleanup();// 调用cleanup函数进行清理操作
proc_exit(0);// 调用proc_exit函数结束进程
}
/* ----------------------------------------------------------------
* misc functions
* ----------------------------------------------------------------
@ -433,6 +449,22 @@ static void BootstrapModeMain(void)
/*
* Set up signal handling for a bootstrap process
*/
/*
IsUnderPostmaster为真
- SIGHUP信号被设置为忽略
- SIGINT信号
- SIGTERM信号被设置为调用die()
- SIGQUIT信号被设置为调用quickdie()
- SIGALRMSIGPIPESIGUSR1和SIGUSR2信号被设置为忽略
- SIGCHLDSIGTTINSIGTTOUSIGCONT和SIGWINCH信号被设置为默认处理
-
die()SIGUSR2信号
*/
static void bootstrap_signals(void)
{
if (IsUnderPostmaster) {
@ -481,6 +513,20 @@ static void bootstrap_signals(void)
* boot_openrel
* ----------------
*/
/*
relation
NAMEDATALEN'\0'NAMEDATALEN
t_thrd.bootstrap_cxt.Typ是否为NULLNULLpg_type数据
pg_type数据的过程是从pg_type表中获取所有的行i中app
i次typmap结构的空间app中NULL
pg_type表tup中
typmap结构的am_oid成员设置为tup的OID属性值am_typ成员设置为tup的实际数据app递增1
pg_type表t_thrd.bootstrap_cxt.boot_reldesc设置为新打开的关系
pg_type表中的数据t_thrd.bootstrap_cxt.Typ中
*/
void boot_openrel(char* relname)
{
int i;
@ -553,25 +599,41 @@ void boot_openrel(char* relname)
* closerel
* ----------------
*/
closerel添加注释
/**
* @brief
*
* @param name
*/
void closerel(char* name)
{
// 检查是否传入了正确的参数
if (name != NULL) {
// 检查是否存在已打开的关系
if (t_thrd.bootstrap_cxt.boot_reldesc) {
// 检查要关闭的关系名是否与当前已打开的关系名不同
if (strcmp(RelationGetRelationName(t_thrd.bootstrap_cxt.boot_reldesc), name) != 0)
// 如果不同,报错,提示预期的关系名和实际的关系名
ereport(ERROR,
(errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
errmsg("close of %s when %s was expected",
name,
RelationGetRelationName(t_thrd.bootstrap_cxt.boot_reldesc))));
} else
} else {
// 如果不存在已打开的关系,报错,提示关闭关系前未打开任何关系
ereport(ERROR,
(errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
errmsg("close of %s before any relation was opened", name)));
}
}
// 检查是否存在已打开的关系
if (t_thrd.bootstrap_cxt.boot_reldesc == NULL)
// 如果不存在已打开的关系,报错,提示没有可关闭的关系
ereport(ERROR, (errcode(ERRCODE_UNEXPECTED_NULL_VALUE), errmsg("no open relation to close")));
else {
// 输出调试信息关闭关系将已打开的关系指针设置为NULL
ereport(DEBUG4, (errmsg("close relation %s", RelationGetRelationName(t_thrd.bootstrap_cxt.boot_reldesc))));
heap_close(t_thrd.bootstrap_cxt.boot_reldesc, NoLock);
t_thrd.bootstrap_cxt.boot_reldesc = NULL;
@ -606,6 +668,16 @@ static void fix_attr_notnull(const char* name, int attnum)
* will be called n times
* ----------------
*/
/*
nametypeattnum
Attribute结构体给t_thrd.bootstrap_cxt.attrtypes[attnum]0
Attribute结构体中attnum + 1OID值
C结构体声明访问"not null"
"partkey""intervaltablespace""intspnum""roluseft""rolmonitoradmin""roloperatoradmin""rolpolicyadmin"
"not null"
*/
void DefineAttr(const char* name, char* type, int attnum)
{
Oid typeoid;
@ -694,6 +766,15 @@ void DefineAttr(const char* name, char* type, int attnum)
* Otherwise, an OID will be assigned (if necessary) by heap_insert.
* ----------------
*/
/*这个函数用于向表中插入一条元组。函数的参数是一个对象IDobjectid表示要插入的元组的ID。函数通过`t_thrd.bootstrap_cxt.boot_reldesc`访问引导过程中的关系(表)描述符。
ID和列数pg_proc表的描述符pg_proc表中
`CreateTupleDesc`tupDescOid
`tableam_tops_form_tuple`HeapTuple结构体HeapTuple时使用了`tupDesc``values``Nulls`NULL的标记
0IDobjectid使`HeapTupleSetOid`HeapTuple的对象ID
`simple_heap_insert`HeapTuple插入到关系中
`tableam_tops_free_tuple`HeapTuple
`Nulls`false便使
HeapTupleHeapTuple使*/
void InsertOneTuple(Oid objectid)
{
HeapTuple tuple;
@ -847,6 +928,16 @@ static Oid gettype(char* type)
* can be made to work during early bootstrap.
* ----------------
*/
/*
typid/typid查找对应的类型信息
`t_thrd.bootstrap_cxt.Typ``pg_type``t_thrd.bootstrap_cxt.Typ`typid对应的类型信息`ap`
typid对应的信息OID未在Typ列表中找到
`ap`typlentypbyvaltypaligntypdelimtypioparamtypinputtypoutput
`t_thrd.bootstrap_cxt.Typ``pg_type`使`TypInfo``TypInfo`typid对应的类型信息`typeindex`
typid对应的类型信息OID在TypInfo中未找到
`TypInfo`typlentypbyvaltypaligntypdelimtypioparamtypinputtypoutput
/`pg_type`使`pg_type`使`TypInfo`
*/
void boot_get_type_io_data(Oid typid, int16* typlen, bool* typbyval, char* typalign, char* typdelim, Oid* typioparam,
Oid* typinput, Oid* typoutput)
{
@ -967,6 +1058,15 @@ const char* MapArrayTypeName(const char* s)
* indexes on those catalogs. Doing it in two phases is the simplest
* way of making sure the indexes have the right contents at the end.
*/
/*这个函数用于在引导过程中注册索引。函数接收三个参数heap堆表的对象ID、ind索引的对象ID和indexInfoIndexInfo结构体的指针包含了索引的详细信息
IndexList结构体的实例newindNULL
t_thrd.bootstrap_cxt.nogc上下文"BootstrapNoGC"
t_thrd.bootstrap_cxt.nogc上下文
IndexList结构体的内存heapind和indexInfo的值分别赋给新分配的结构体的相应成员变量
memcpy_s函数将indexInfo结构体的内容复制到newind->il_info中使copyObject函数分别复制indexInfo->ii_Expressions和indexInfo->ii_Predicatenewind->il_info->ii_Expressions和newind->il_info->ii_Predicate
newind添加到t_thrd.bootstrap_cxt.ILHead链表中便使
IndexList结构体对象使*/
void index_register(Oid heap, Oid ind, IndexInfo* indexInfo)
{
IndexList* newind = NULL;
@ -1011,6 +1111,14 @@ void index_register(Oid heap, Oid ind, IndexInfo* indexInfo)
/*
* build_indices -- fill in all the indexes registered earlier
*/
/*
t_thrd.bootstrap_cxt.ILHead链表中的每个索引来逐个构建索引
t_thrd.bootstrap_cxt.ILHead不为空Relation对象heap和ind
使heap_open和index_open函数打开堆表和索引表ID和锁的模式NoLock表示不获取锁Relation对象分别赋给heap和ind变量
index_build函数来构建索引t_thrd.bootstrap_cxt.ILHead链表的当前节点使
使index_close和heap_close函数关闭索引表和堆表NoLock
t_thrd.bootstrap_cxt.ILHead链表中的每个索引index_build函数进行索引构建
*/
void build_indices(void)
{
for (; t_thrd.bootstrap_cxt.ILHead != NULL; t_thrd.bootstrap_cxt.ILHead = t_thrd.bootstrap_cxt.ILHead->il_next) {

View File

@ -49,13 +49,14 @@ int BBOX_GetSysDateTime(void)
int iCommandFD = -1;
int iReadSize = 0;
// 打开一个管道,并执行指定的日期时间命令
BBOX_NOINTR(iCommandFD = sys_popen(BBOX_DATE_TIME_CMD, "r"));
if (iCommandFD < 0) {
bbox_print(PRINT_ERR, "sys_popen is failed, errno = %d.\n", errno);
return RET_ERR;
}
/* read the result of sys_read command */
// 读取sys_read命令的结果
BBOX_NOINTR(iReadSize = sys_read(iCommandFD, g_acDateTime, BBOX_TINE_LEN));
if (iReadSize <= 0) {
(void)sys_pclose(iCommandFD);
@ -66,7 +67,7 @@ int BBOX_GetSysDateTime(void)
(void)sys_pclose(iCommandFD);
if (iReadSize > 0) {
g_acDateTime[iReadSize - 1] = '\0'; /* remove '\n' */
g_acDateTime[iReadSize - 1] = '\0'; /* 移除'\n'字符 */
}
bbox_print(PRINT_LOG, "Get system time %s.\n", g_acDateTime);
@ -179,6 +180,7 @@ s32 BBOX_GetBBoxOldiestName(const char* pszPath, const char* pszName, void* pArg
struct kernel_stat stCurrState = {0};
char szFileName[BBOX_NAME_PATH_LEN];
// 检查参数
pstArgs = (struct BBOX_ListDirParam*)pArgs;
if (pstArgs == NULL) {
bbox_print(PRINT_ERR, "Invalid argument pstArgs\n");
@ -188,35 +190,37 @@ s32 BBOX_GetBBoxOldiestName(const char* pszPath, const char* pszName, void* pArg
pstOldiestState = (struct kernel_stat*)pstArgs->pArg1;
pszOldName = (char*)pstArgs->pArg2;
/* ignore path "." and ".." */
// 忽略路径"."和".."
if ((0 == bbox_strcmp(pszName, ".")) || (0 == bbox_strcmp(pszName, ".."))) {
return RET_OK;
}
/* ignore the file which not belong to bbox */
// 忽略不属于bbox的文件
if ((0 == bbox_strstr(pszName, BBOX_SNAP_FILE_ADD_NAME ".lz4")) &&
(0 == bbox_strstr(pszName, BBOX_CORE_FILE_ADD_NAME ".lz4"))) {
return RET_OK;
}
/* ignore the file which not created by this process. */
// 忽略不是由该进程创建的文件
if (bbox_strstr(pszName, progname) == 0) {
return RET_OK;
}
// 拼接文件路径
if (bbox_snprintf(szFileName, sizeof(szFileName), "%s/%s", pszPath, pszName) <= 0) {
bbox_print(PRINT_ERR, "bbox_snprintf is failed, errno = %d.\n", errno);
return RET_ERR;
}
// 获取文件信息
if (sys_stat(szFileName, &stCurrState) < 0) {
bbox_print(PRINT_ERR, "Get stat of '%s' failed, errno = %d\n", szFileName, errno);
return RET_ERR;
}
/* compare and judge if it is the oldiest time */
// 比较并判断是否为最早创建的文件
if (stCurrState.st_mtime_ < pstOldiestState->st_mtime_) {
/* record the oldiest file information */
// 记录最早的文件信息
*pstOldiestState = stCurrState;
if (bbox_snprintf(pszOldName, BBOX_NAME_PATH_LEN, "%s/%s", pszPath, pszName) <= 0) {
bbox_print(PRINT_ERR, "bbox_snprintf is failed, errno = %d.\n", errno);
@ -349,42 +353,48 @@ void BBOX_RemoveTempBBoxFile(void)
*/
void BBOX_FinishDumpFile(void* args)
{
// 声明所需的变量
char* pszNewName = NULL;
char* pszOldName = NULL;
struct kernel_timeval stProgramCoreDumpTime = {0};
struct BBOX_ListDirParam* pstArgs = (struct BBOX_ListDirParam*)args;
// 检查参数是否为NULL
if (args == NULL) {
bbox_print(PRINT_ERR, "BBOX_FinishDumpFile args is null.\n");
return;
}
// 获取程序核心转储完成的时间
sys_gettimeofday(&stProgramCoreDumpTime, NULL);
// 将程序核心转储完成的时间赋值给全局变量
g_iCoreDumpEndTime = stProgramCoreDumpTime.tv_sec;
bbox_print(PRINT_TIP, "coredump End at %ld\n", stProgramCoreDumpTime.tv_sec);
// 打印程序核心转储所用的时间
bbox_print(PRINT_TIP, "coredump used time: %ld sec\n", g_iCoreDumpEndTime - g_iCoreDumpBeginTime);
/* remove oldiest file */
// 移除最旧的文件
BBOX_RemoveOldBBoxFile();
// 获取新文件名和旧文件名
pszNewName = (char*)pstArgs->pArg1;
pszOldName = (char*)pstArgs->pArg2;
/* change file mode to 0600 */
// 将旧文件的访问权限设置为0600
if (sys_chmod(pszOldName, 0600)) {
bbox_print(PRINT_ERR, "set %s mode to 0600 failed, errno = %d\n", pszOldName, errno);
}
/* rename file */
// 重命名文件
if (pszNewName != NULL && pszOldName != NULL) {
if (sys_rename(pszOldName, pszNewName) < 0) {
bbox_print(PRINT_ERR, "rename file %s to %s failed, errno = %d.\n", pszOldName, pszNewName, errno);
}
}
/* remove temp bbox file. */
// 移除临时核心转储文件
BBOX_RemoveTempBBoxFile();
}
@ -403,19 +413,22 @@ s32 BBOX_CreateCoredump(char* file_name)
bbox_initlog(0);
// 打印日志头
bbox_print(PRINT_TIP, "\nBBOX LOG\n-------------------------------\n");
// 获取系统当前时间
iRet = BBOX_GetSysDateTime();
if (iRet != RET_OK) {
return RET_ERR;
}
// 创建核心文件保存路径
if (bbox_mkdir(g_szBboxCorePath) < 0) {
bbox_print(PRINT_ERR, "bbox_mkdir is failed, errno = %d.\n", errno);
return RET_ERR;
}
/* if file_name is NULL, create it using default name. */
// 若file_name为NULL则使用默认名称创建核心文件
if (file_name == NULL) {
if (BBOX_GetDefaultCoreName(szFileName, BBOX_NAME_PATH_LEN, BBOX_CORE_FILE_ADD_NAME) == RET_OK) {
file_name = szFileName;
@ -425,8 +438,10 @@ s32 BBOX_CreateCoredump(char* file_name)
}
}
// 打印核心文件路径
bbox_print(PRINT_TIP, "core file path is %s\n", file_name);
// 获取临时核心文件名
if (BBOX_GetTmpCoreName(szTmpName, BBOX_NAME_PATH_LEN) == RET_OK) {
file_tmp = szTmpName;
} else {
@ -434,6 +449,7 @@ s32 BBOX_CreateCoredump(char* file_name)
return RET_ERR;
}
// 设置参数并调用相关函数
stArgs.pArg1 = file_name;
stArgs.pArg2 = file_tmp;

View File

@ -52,59 +52,59 @@ char g_acBboxStrTabInfo[BBOX_SH_STR_TAB_SIZE]; /* record string symbol tab
* return : iGetChar - current character of the file being read
* RET_ERR - failed
*/
static int BBOX_SkipDeviceAndNodeField(struct BBOX_READ_FILE_IO* pstReadIO)
{
int iCount = -1;
int iGetChar = -1;
if (NULL == pstReadIO) {
// 检查参数的有效性
if (NULL == pstReadIO) {
bbox_print(PRINT_ERR, "BBOX_SkipDeviceAndNodeField参数无效pstReadIO为NULL。\n");
return RET_ERR;
}
bbox_print(PRINT_ERR, "BBOX_SkipDeviceAndNodeField parameters is invalid: pstReadIO is NULL.\n");
// 从文件中获取一个字符
iGetChar = BBOX_GetCharFromFile(pstReadIO);
if (RET_ERR == iGetChar) {
bbox_print(PRINT_ERR, "BBOX_GetCharFromFile调用失败iGetChar= %d。\n", iGetChar);
return RET_ERR;
}
return RET_ERR;
}
iGetChar = BBOX_GetCharFromFile(pstReadIO);
if (RET_ERR == iGetChar) {
bbox_print(PRINT_ERR, "BBOX_GetCharFromFile is failed, iGetChar= %d.\n", iGetChar);
return RET_ERR;
}
for (iCount = 0; iCount < DEVICE_AND_NODE_FIELD_NUM; iCount++) {
while (iGetChar == ' ') {
iGetChar = BBOX_GetCharFromFile(pstReadIO);
if (RET_ERR == iGetChar) {
bbox_print(PRINT_ERR, "BBOX_GetCharFromFile is failed, iGetChar= %d.\n", iGetChar);
return RET_ERR;
}
}
while (iGetChar != ' ' && iGetChar != '\n') {
if (RET_ERR == iGetChar) {
bbox_print(PRINT_ERR, "BBOX_GetCharFromFile is failed, iGetChar= %d.\n", iGetChar);
return RET_ERR;
}
iGetChar = BBOX_GetCharFromFile(pstReadIO);
}
while (iGetChar == ' ') {
iGetChar = BBOX_GetCharFromFile(pstReadIO);
if (RET_ERR == iGetChar) {
bbox_print(PRINT_ERR, "BBOX_GetCharFromFile is failed, iGetChar= %d.\n", iGetChar);
return RET_ERR;
}
// 进入循环,跳过设备和节点字段
for (iCount = 0; iCount < DEVICE_AND_NODE_FIELD_NUM; iCount++) {
// 跳过空格字符
while (iGetChar == ' ') {
// 继续从文件中获取下一个字符
iGetChar = BBOX_GetCharFromFile(pstReadIO);
if (RET_ERR == iGetChar) {
bbox_print(PRINT_ERR, "BBOX_GetCharFromFile调用失败iGetChar= %d。\n", iGetChar);
return RET_ERR;
}
}
return iGetChar;
// 跳过非空格和换行符的字符
while (iGetChar != ' ' && iGetChar != '\n') {
if (RET_ERR == iGetChar) {
bbox_print(PRINT_ERR, "BBOX_GetCharFromFile调用失败iGetChar= %d。\n", iGetChar);
return RET_ERR;
}
// 继续从文件中获取下一个字符
iGetChar = BBOX_GetCharFromFile(pstReadIO);
}
// 跳过空格字符
while (iGetChar == ' ') {
// 继续从文件中获取下一个字符
iGetChar = BBOX_GetCharFromFile(pstReadIO);
if (RET_ERR == iGetChar) {
bbox_print(PRINT_ERR, "BBOX_GetCharFromFile调用失败iGetChar= %d。\n", iGetChar);
return RET_ERR;
}
}
}
return iGetChar; // 返回读取的下一个字符
}
/*
@ -155,79 +155,82 @@ static int BBOX_SetMappingDeviceFlag(
return RET_OK;
}
/*
* set whether the mapping is labeled as PF_VDSO, means that, whether or not it's a VDSO mapping.
* in : int *piGetChar - pointer to the character read
* struct BBOX_READ_FILE_IO *pstReadIO - pointer to struct of file read
* struct BBOX_VM_MAPS *pstVmMappingSegment - pointer to discription of mapping segment structure.
* return RET_OK or RET_ERR
*/
static int BBOX_SetMappingVDSOFlag(
int* piGetChar, struct BBOX_READ_FILE_IO* pstReadIO, struct BBOX_VM_MAPS* pstSegmentMapping)
/*
BBOX_SetMappingVDSOFlag的静态函数
VDSO标志以及VVAR标志
:
piGetChar:
pstReadIO: BBOX_READ_FILE_IO结构的指针
pstSegmentMapping: BBOX_VM_MAPS结构的指针
:
RET_OK
RET_ERR */
static int BBOX_SetMappingVDSOFlag(int* piGetChar, struct BBOX_READ_FILE_IO* pstReadIO, struct BBOX_VM_MAPS* pstSegmentMapping)
{
int iIsMappingVdsoFlag = BBOX_FALSE;
int iIsMappingVvarFlag = BBOX_TRUE;
const char* pszVdso = VDSO_NAME_STRING;
const char* pszVvar = VVAR_NAME_STRING;
if (NULL == piGetChar || NULL == pstReadIO || NULL == pstSegmentMapping) {
bbox_print(PRINT_ERR,
"BBOX_FillMappingFlagsAndOffset parameters is invalid: piGetChar," \
"pstReadIO or pstSegmentMapping is NULL.\n");
int iIsMappingVdsoFlag = BBOX_FALSE; // 表示是否映射了VDSO的标志初始为假
int iIsMappingVvarFlag = BBOX_TRUE; // 表示是否映射了VVAR的标志初始为真
const char* pszVdso = VDSO_NAME_STRING; // VDSO名称字符串
const char* pszVvar = VVAR_NAME_STRING; // VVAR名称字符串
// 检查参数的有效性
if (NULL == piGetChar || NULL == pstReadIO || NULL == pstSegmentMapping) {
bbox_print(PRINT_ERR,
"BBOX_SetMappingVDSOFlag参数无效piGetCharpstReadIO或pstSegmentMapping为NULL。\n");
return RET_ERR;
}
// 当VDSO名称字符串和从文件中获取的字符相等时进行以下操作
while (*pszVdso && *piGetChar == *pszVdso) {
// 如果映射了VVAR并且从文件中获取的字符与VVAR名称字符串相等
if (iIsMappingVvarFlag == BBOX_TRUE) {
iIsMappingVvarFlag = (*piGetChar == *pszVvar) ? BBOX_TRUE : BBOX_FALSE;
pszVvar++;
}
// 继续从文件中获取下一个字符
*piGetChar = BBOX_GetCharFromFile(pstReadIO);
if (RET_ERR == *piGetChar) {
bbox_print(PRINT_ERR, "BBOX_GetCharFromFile调用失败*piGetChar= %d。\n", *piGetChar);
return RET_ERR;
}
while (*pszVdso && *piGetChar == *pszVdso) {
if (iIsMappingVvarFlag == BBOX_TRUE) {
iIsMappingVvarFlag = (*piGetChar == *pszVvar) ? BBOX_TRUE : BBOX_FALSE;
pszVvar++;
}
pszVdso++;
}
// 如果VDSO名称字符串为空且从文件中获取的字符为换行符、空格或空字符
if (*pszVdso == '\0' && (*piGetChar == '\n' || *piGetChar == ' ' || *piGetChar == '\0')) {
pstSegmentMapping->iFlags |= PF_VDSO; // 设置VDSO标志
bbox_print(PRINT_DBG,
"获取VDSO的起始地址 = %zu结束地址 = %zu。\n",
pstSegmentMapping->uiStartAddress,
pstSegmentMapping->uiEndAddress);
}
// 如果映射了VVAR并且从文件中获取的字符与VVAR名称字符串相等时进行以下操作
if (iIsMappingVvarFlag == BBOX_TRUE) {
while (*pszVdso && *piGetChar == *pszVvar) {
// 继续从文件中获取下一个字符
*piGetChar = BBOX_GetCharFromFile(pstReadIO);
if (RET_ERR == *piGetChar) {
bbox_print(PRINT_ERR, "BBOX_GetCharFromFile is failed, *piGetChar= %d.\n", *piGetChar);
bbox_print(PRINT_ERR, "BBOX_GetCharFromFile调用失败*piGetChar= %d。\n", *piGetChar);
return RET_ERR;
}
pszVdso++;
pszVvar++;
}
iIsMappingVdsoFlag = (*pszVdso == '\0' && (*piGetChar == '\n' || *piGetChar == ' ' || *piGetChar == '\0'));
if (BBOX_TRUE == iIsMappingVdsoFlag) {
pstSegmentMapping->iFlags |= PF_VDSO; /* set VDSO flag. */
// 如果VVAR名称字符串为空且从文件中获取的字符为换行符、空格或空字符
if (*pszVvar == '\0' && (*piGetChar == '\n' || *piGetChar == ' ' || *piGetChar == '\0')) {
pstSegmentMapping->iFlags |= PF_VVAR; // 设置VVAR标志
bbox_print(PRINT_DBG,
" Get VDSO StartAddr = %zu, EndAddr = %zu.\n",
pstSegmentMapping->uiStartAddress,
pstSegmentMapping->uiEndAddress);
"获取VVAR的起始地址 = %zu结束地址 = %zu。\n",
pstSegmentMapping->uiStartAddress, pstSegmentMapping->uiEndAddress);
}
if (iIsMappingVvarFlag == BBOX_TRUE) {
while (*pszVdso && *piGetChar == *pszVvar) {
*piGetChar = BBOX_GetCharFromFile(pstReadIO);
if (RET_ERR == *piGetChar) {
bbox_print(PRINT_ERR, "BBOX_GetCharFromFile is failed, *piGetChar= %d.\n", *piGetChar);
return RET_ERR;
}
pszVvar++;
}
if (*pszVvar == '\0' && (*piGetChar == '\n' || *piGetChar == ' ' || *piGetChar == '\0')) {
pstSegmentMapping->iFlags |= PF_VVAR; /* set VVAR flag */
bbox_print(PRINT_DBG,
" Get VVAR StartAddr = %zu, EndAddr = %zu.\n",
pstSegmentMapping->uiStartAddress, pstSegmentMapping->uiEndAddress);
}
}
return RET_OK;
}
return RET_OK;
}
/*
* check if the file is a dynamic library file.
* in : char* pszFilePath - path
@ -344,6 +347,28 @@ static int BBOX_SettingFileFlags(
* return : int iGetChar - current character of file reading
* RET_ERR - read failed
*/
/*
BBOX_FillMappingFlagsAndOffset
:
- pstReadIO: BBOX_READ_FILE_IO结构的指针
- pstSegmentMapping: BBOX_VM_MAPS结构的指针
:
- :
- : RET_ERR
1. RET_ERR
2. '-'0pstSegmentMapping->iFlags中
3. pstSegmentMapping->iFlags进行处理PF_MASK进行与运算
4. BBOX_StringSwitchInt函数读取偏移量pstSegmentMapping->uiOffset中
5.
6. '['
7. PF_ANONYMOUS标志BBOX_SetMappingVDSOFlag函数判断是否是VDSO段VDSO并返回获取的字符
8. BBOX_SetMappingDeviceFlag函数判断是否是描述某个设备的字段
9. BBOX_SettingFileFlags函数设置文件标志
10.
*/
static int BBOX_FillMappingFlagsAndOffset(struct BBOX_READ_FILE_IO* pstReadIO, struct BBOX_VM_MAPS* pstSegmentMapping)
{
int iRessult = 0;
@ -510,6 +535,28 @@ static char BBOX_FillMappingAddress(struct BBOX_READ_FILE_IO* pstReadIO, struct
* struct BBOX_WRITE_FDS *pstWriteFds : segment to be written into core file
* return RET_OK if success else RET_ERR.
*/
/*
BBOX_VmExecludeBlackList
:
- pstVmMappingSegment: BBOX_VM_MAPS结构的指针
:
- : RET_OK
1.
2. _BBOX_FindAddrInBlackList函数在黑名单中查找起始地址和结束地址
3.
4.
5.
6.
7.
8.
9.
10.
11. RET_OK
*/
static int BBOX_VmExecludeBlackList(struct BBOX_VM_MAPS *pstVmMappingSegment)
{
void *pStartAddress = (void *)(uintptr_t)pstVmMappingSegment->uiStartAddress;
@ -2742,6 +2789,29 @@ static int BBOX_CloseCoreFile(struct BBOX_WRITE_FDS* pstFileWriteFd)
* va_list ap - Multiparameter list
* return RET_OK or RET_ERR
*/
/*
core文件线ID数组以及可变参数列表
RET_ERR
使11
退线BBOX_THREAD_NOTE_INFO结构体数组NULLRET_ERR
BBOX_VM_VDSOBBOX_ELF_NOTE_INFO和BBOX_WRITE_FDSID和线程信息数
BBOX_GetVmMapsNum函数获取/proc/self/maps文件的行数0RET_ERR
BBOX_VM_MAPS结构体数组BBOX_FillAllInfoOfCoreFile函数来填充生成core文件所需的所有信息RET_OKRET_ERR
线core文件名并检查其有效性RET_ERR
BBOX_OpenCoreFile函数创建core文件RET_OKERR标签
ERR标签处BBOX_CloseCoreFile函数RET_OK
BBOX_CloseCoreFile函数的结果RET_ERR
*/
int BBOX_DoDumpElfCore(BBOX_GetAllThreadDone pDone, void* pDoneHandle, int iNumThreads, pid_t* ptPids, va_list ap)
{
int iSegmentNum = -1;

View File

@ -60,18 +60,25 @@ noteThe way that this function judge the mode that PC uses to store data is t
date: 2022/8/2
contact tel: 18720816902
*/
// 用于确定系统的字节序的函数
int BBOX_DetermineMsb(void)
{
// 定义一个联合体用于存储一个short整数并将其拆分为单个字节
union INT_PROBE {
short sShortInt;
char cSplit[sizeof(short)];
short sShortInt; // 短整数
char cSplit[sizeof(short)]; // 字符数组(字节数组),用于拆分整数
} unProbe;
// 将联合体中的整数值设置为已知值
unProbe.sShortInt = BBOX_MSB_LSB_INT;
// 检查short整数的第一个字节是否与MSB的预期值匹配
// 并且检查第二个字节是否与LSB的预期值匹配
if ((BBOX_LITTER_BITS == unProbe.cSplit[0]) && (BBOX_HIGH_BITS == unProbe.cSplit[1])) {
// 如果字节序为LSB则返回LSB的值
return ELFDATA2LSB;
} else {
// 如果字节序为MSB则返回MSB的值
return ELFDATA2MSB;
}
}
@ -111,25 +118,31 @@ int BBOX_StringToTime(const char* pSwitch, struct BBOX_ELF_TIMEVAL* pstElfTimeva
* return : the character read in file - success
* RET_ERR - failed
*/
// 从文件中获取一个字符的函数
int BBOX_GetCharFromFile(struct BBOX_READ_FILE_IO* pstIO)
{
ssize_t iReadSize = -1;
// 检查pstIO是否为NULL
if (NULL == pstIO) {
bbox_print(PRINT_ERR, "BBOX_GetCharFromFile parameters is invalid: pstIO is NULL.\n");
bbox_print(PRINT_ERR, "BBOX_GetCharFromFile参数无效pstIO为NULL。\n");
return RET_ERR;
}
unsigned char* pTempIO = pstIO->pData;
// 检查缓冲区是否为空
if (pTempIO == pstIO->pEnd) {
/* read character from file when the buffer is empty, and push it into buffer */
/* 当缓冲区为空时,从文件中读取字符并将其放入缓冲区 */
BBOX_NOINTR(iReadSize = sys_read(pstIO->iFd, pstIO->szBuff, sizeof(pstIO->szBuff)));
// 检查读取的大小
if (iReadSize <= 0) {
if (0 == iReadSize) {
errno = 0;
errno = 0; // 清除错误标记
}
return RET_ERR;
return RET_ERR; // 读取出错
}
pTempIO = &(pstIO->szBuff[0]);
@ -148,52 +161,57 @@ int BBOX_GetCharFromFile(struct BBOX_READ_FILE_IO* pstIO)
* return : the result num - success
* RET_ERR - failed
*/
// 字符串转换为整数的函数, 从文件中读取字符并将其转换为整数
int BBOX_StringSwitchInt(struct BBOX_READ_FILE_IO* pstIO, size_t* pAddress)
{
int iMappingTextChar = 0;
// 检查pstIO和pAddress是否为NULL
if (NULL == pstIO || NULL == pAddress) {
bbox_print(
PRINT_ERR, "BBOX_StringSwitchInt parameters is invalid: pstIO or pAddress is NULL.\n");
PRINT_ERR, "BBOX_StringSwitchInt参数无效pstIO或pAddress为NULL。\n");
return RET_ERR;
}
*pAddress = 0;
iMappingTextChar = BBOX_GetCharFromFile(pstIO);
while (
(iMappingTextChar >= '0' && iMappingTextChar <= '9') || (iMappingTextChar >= 'a' && iMappingTextChar <= 'f')) {
*pAddress = 0; // 初始化pAddress为0
iMappingTextChar = BBOX_GetCharFromFile(pstIO); // 从文件中获取一个字符
/* left shift the variable, and add the num converted from character at the end. */
*pAddress =
(*pAddress << ONE_HEXA_DECIMAL_BITS) |
// 循环直到遇到非数字字符和非小写字母字符
while ((iMappingTextChar >= '0' && iMappingTextChar <= '9') || (iMappingTextChar >= 'a' && iMappingTextChar <= 'f')) {
/* 将变量左移,并在末尾添加由字符转换而来的数字 */
*pAddress = (*pAddress << ONE_HEXA_DECIMAL_BITS) |
(unsigned int)(iMappingTextChar < 'A' ? iMappingTextChar - '0'
: ((unsigned int)iMappingTextChar & 0xF) + ASC2_CHAR_GREATER_NUM);
iMappingTextChar = BBOX_GetCharFromFile(pstIO); /* read next character */
: ((unsigned int)iMappingTextChar & 0xF) + ASC2_CHAR_GREATER_NUM);
iMappingTextChar = BBOX_GetCharFromFile(pstIO); // 读取下一个字符
}
return iMappingTextChar;
return iMappingTextChar; // 返回读取的字符
}
/*
* when read file /proc/self/maps, ignore unusefull information and skip to the end of line
* after we have geting all necessary information.
* return : count of character store into buffer - success
* RET_ERR - failed
* /proc/self/maps时
* -
* RET_ERR -
*/
int BBOX_SkipToLineEnd(struct BBOX_READ_FILE_IO* pstReadIO)
{
int iGetChar = -1;
// 检查pstReadIO是否为NULL
if (NULL == pstReadIO) {
bbox_print(PRINT_ERR, "BBOX_SkipToLineEnd parameters is invalid: pstReadIO is NULL.\n");
bbox_print(PRINT_ERR, "BBOX_SkipToLineEnd参数无效pstReadIO为NULL。\n");
return RET_ERR;
}
do {
/* reads characters until the newline character */
/* 读取字符直到换行符 */
iGetChar = BBOX_GetCharFromFile(pstReadIO);
// 检查读取字符是否失败
if (RET_ERR == iGetChar) {
bbox_print(PRINT_ERR, "BBOX_SkipToLineEnd is failed, iGetChar= %d.\n", iGetChar);
bbox_print(PRINT_ERR, "BBOX_SkipToLineEnd失败iGetChar = %d。\n", iGetChar);
return RET_ERR;
}
} while (iGetChar != '\n');
@ -202,18 +220,17 @@ int BBOX_SkipToLineEnd(struct BBOX_READ_FILE_IO* pstReadIO)
}
/*
* judge whether the range between *pStartAddress* and *pEndAddress* is in black list or not.
* If found, return the blacklist item which cover it, else return NULL.
* NULL
*
* NOTE: this function is a thread-unsafe function since it works as an iterator.
* 线使
*/
BBOX_BLACKLIST_STRU *_BBOX_FindAddrInBlackList(const void *pStartAddress, const void *pEndAddress)
BBOX_BLACKLIST_STRU *_BBOX_FindAddrInBlackList(const void* pStartAddress, const void* pEndAddress)
{
int i = 0;
int iPerformance = 0;
size_t uiPageSize = sys_sysconf(_SC_PAGESIZE);
size_t uiPageSize = sys_sysconf(_SC_PAGESIZE);
/* if the cursor reachs the end of blacklist, start a new trip. */
/* 如果游标达到黑名单的末尾,则开始新的遍历。 */
if (g_iPosBlackList >= g_iNumBlackList) {
g_iPosBlackList = 0;
}
@ -222,41 +239,41 @@ BBOX_BLACKLIST_STRU *_BBOX_FindAddrInBlackList(const void *pStartAddress, const
iPerformance++;
/*
* if the endAddress of segemnt is less than the startAddress of this item, it means there is
* no cross with the rest blacklist items since blacklist items are in increasing order.
*
*
*/
if (pEndAddress <= g_stBlackList[i].pBlackStartAddr) {
bbox_print(PRINT_DBG, "\nFIND BL BY %d TIMES, POS = %d.\n\n", iPerformance, g_iPosBlackList);
bbox_print(PRINT_DBG, "not find black list in segment.\n");
bbox_print(PRINT_DBG, "\n通过%d次查找POS = %d找到黑名单。\n\n", iPerformance, g_iPosBlackList);
bbox_print(PRINT_DBG, "在段中未找到黑名单。\n");
return NULL;
}
if (pStartAddress <= g_stBlackList[i].pBlackStartAddr &&
g_stBlackList[i].pBlackStartAddr < pEndAddress) {
g_iPosBlackList = i;
bbox_print(PRINT_DBG, "\nFIND BL BY %d TIMES, POS = %d.\n\n", iPerformance, g_iPosBlackList);
bbox_print(PRINT_DBG, "find black list in segment.\n");
bbox_print(PRINT_DBG, "\n通过%d次查找POS = %d找到黑名单。\n\n", iPerformance, g_iPosBlackList);
bbox_print(PRINT_DBG, "在段中找到黑名单。\n");
return &(g_stBlackList[i]);
}
if (pStartAddress < g_stBlackList[i].pBlackEndAddr &&
g_stBlackList[i].pBlackEndAddr <= pEndAddress) {
if (((uintptr_t)pEndAddress - (uintptr_t)(g_stBlackList[i].pBlackEndAddr)) < uiPageSize) {
bbox_print(PRINT_DBG, "find black list in segment, but size < 4K, do not care return.\n");
bbox_print(PRINT_DBG, "在段中找到黑名单但大小小于4K不用关心返回NULL。\n");
return NULL;
} else {
g_iPosBlackList = i;
bbox_print(PRINT_DBG, "\nFIND BL BY %d TIMES, POS = %d.\n\n", iPerformance, g_iPosBlackList);
bbox_print(PRINT_DBG, "find black list in segment.\n");
bbox_print(PRINT_DBG, "\n通过%d次查找POS = %d找到黑名单。\n\n", iPerformance, g_iPosBlackList);
bbox_print(PRINT_DBG, "在段中找到黑名单。\n");
return &(g_stBlackList[i]);
}
}
}
bbox_print(PRINT_DBG, "\nFIND BL BY %d TIMES, POS = %d.\n\n", iPerformance, g_iPosBlackList);
bbox_print(PRINT_DBG, "not find black list in segment.\n");
bbox_print(PRINT_DBG, "\n通过%d次查找POS = %d未找到黑名单。\n\n", iPerformance, g_iPosBlackList);
bbox_print(PRINT_DBG, "在段中未找到黑名单。\n");
/* no cross between this segment and blacklist items. */
/* 此段与黑名单项之间无交叉。 */
return NULL;
}
@ -266,23 +283,25 @@ BBOX_BLACKLIST_STRU *_BBOX_FindAddrInBlackList(const void *pStartAddress, const
* unsigned long long uiLen : memory size
* return RET_OK if success else RET_ERR.
*/
/* 向黑名单列表添加地址 */
int _BBOX_AddBlackListAddress(void* pAddress, unsigned long long uiLen)
{
unsigned int uiFound = 0;
// 如果地址为空或者长度小于最小限制,打印错误信息并返回错误码
if (pAddress == NULL || uiLen < BBOX_BLACK_LIST_MIN_LEN) {
bbox_print(PRINT_ERR, "parameter uiLen(%llu) is invaild.\n", uiLen);
return RET_ERR;
}
/* use atomic increment to control concurrency. */
/* 使用原子增加操作来控制并发 */
while (BBOX_AtomicIncReturn(&g_stLockBlackList) > 1) {
BBOX_AtomicDec(&g_stLockBlackList);
bbox_print(PRINT_DBG, "add blacklist addr is running, waiting.\n");
sleep(1);
}
/* if too many blacklist items were added, return error while its upper limits reaches. */
// 如果黑名单项目数量达到上限,打印错误信息并返回错误码
if (g_iNumBlackList >= BBOX_BLACK_LIST_COUNT_MAX) {
BBOX_AtomicDec(&g_stLockBlackList);
bbox_print(PRINT_ERR, "blacklist addr total reach max, failed.\n");
@ -290,11 +309,11 @@ int _BBOX_AddBlackListAddress(void* pAddress, unsigned long long uiLen)
}
/*
* suppose that address became bigger and bigger, move forward from blacklist's tail,
* and find the proper postion to insert this address into the blacklist.
*
*
*/
for (int i = g_iNumBlackList - 1; i >= 0; i--) {
/* if try to add the same address again, report error. */
/* 如果试图再次添加相同的地址,报告错误 */
if (g_stBlackList[i].pBlackStartAddr == pAddress) {
BBOX_AtomicDec(&g_stLockBlackList);
@ -319,7 +338,7 @@ int _BBOX_AddBlackListAddress(void* pAddress, unsigned long long uiLen)
}
}
/* if no found, it means this address is smaller than allput it in the head. */
/* 如果没有找到,说明该地址比所有地址都小,将其置于首位 */
if (uiFound == 0) {
g_stBlackList[0].pBlackStartAddr = pAddress;
g_stBlackList[0].uiLength = uiLen;
@ -335,42 +354,43 @@ int _BBOX_AddBlackListAddress(void* pAddress, unsigned long long uiLen)
}
/*
* drop a blaclist item to dump it in core file.
* void *pAddress : the head address of excluded memory
* return RET_OK if success else RET_ERR.
*
* void *pAddress :
* return RET_OK RET_ERR
*/
int _BBOX_RmvBlackListAddress(void* pAddress)
{
unsigned int uiFound = 0;
// 如果地址为空,打印错误信息并返回错误码
if (pAddress == NULL) {
bbox_print(PRINT_ERR, "parameter pAddress is invaild.\n");
return RET_ERR;
}
/* use atomic increment to control concurrency. */
/* 使用原子增加操作来控制并发 */
while (BBOX_AtomicIncReturn(&g_stLockBlackList) > 1) {
BBOX_AtomicDec(&g_stLockBlackList);
bbox_print(PRINT_DBG, "remove blacklist addr is running, waiting.\n");
sleep(1);
}
/* if blacklist is empty, return error. */
// 如果黑名单为空,返回错误码
if (g_iNumBlackList == 0) {
BBOX_AtomicDec(&g_stLockBlackList);
bbox_print(PRINT_ERR, "blacklist addr total is zero, failed.\n");
return RET_ERR;
}
/* find the specified address and drop it from blacklist. */
// 找到指定的地址并从黑名单中删除
for (int i = 0; i < g_iNumBlackList; i++) {
if (pAddress == g_stBlackList[i].pBlackStartAddr) {
uiFound = 1;
}
/* if found, move subsequent items a step forward. */
/* 如果找到,将后续项目向前移动一步 */
if (uiFound == 1) {
/* if it is the last, clear it and stop. */
/* 如果是最后一个,清除并停止 */
if (i == (g_iNumBlackList - 1)) {
int rc = memset_s(&g_stBlackList[i], sizeof(g_stBlackList[0]), 0, sizeof(g_stBlackList[0]));
securec_check_c(rc, "\0", "\0");
@ -402,6 +422,8 @@ int _BBOX_RmvBlackListAddress(void* pAddress)
* return : count of character store into buffer - success
* RET_ERR - failed
*/
```c
// 获取系统状态信息
int BBOX_GetStatusInfo(char* pBuffer, unsigned int uiBufLen)
{
int iResult = 0;
@ -409,15 +431,16 @@ int BBOX_GetStatusInfo(char* pBuffer, unsigned int uiBufLen)
int iAllSize = 0;
int iReadSize = 0;
// 检查参数是否有效
if (NULL == pBuffer) {
bbox_print(PRINT_ERR, "BBOX_GetStatusInfo parameters is invalid.\n");
bbox_print(PRINT_ERR, "BBOX_GetStatusInfo参数无效。\n");
return RET_ERR;
}
/* information title */
iResult = bbox_snprintf(pBuffer, uiBufLen, "\nSTATUS INFO\n--------------------------------------------\n");
/* 信息标题 */
iResult = bbox_snprintf(pBuffer, uiBufLen, "\n状态信息\n--------------------------------------------\n");
if (iResult <= 0 || iResult > (int)uiBufLen) {
bbox_print(PRINT_ERR, "bbox_snprintf is failed, errno = %d.\n", errno);
bbox_print(PRINT_ERR, "bbox_snprintf执行失败errno = %d。\n", errno);
return RET_ERR;
}
@ -426,18 +449,18 @@ int BBOX_GetStatusInfo(char* pBuffer, unsigned int uiBufLen)
uiBufLen -= iResult;
iAllSize += iResult;
/* open /proc/self/status */
/* 打开/proc/self/status */
BBOX_NOINTR(iStatFD = sys_open(BBOX_SELF_STATUS_PATH, O_RDONLY, 0));
if (iStatFD < 0) {
bbox_print(PRINT_ERR, "sys_open is failed, errno = %d.\n", errno);
bbox_print(PRINT_ERR, "sys_open执行失败errno = %d。\n", errno);
return RET_ERR;
}
/* read /proc/self/status */
/* 读取/proc/self/status */
BBOX_NOINTR(iReadSize = sys_read(iStatFD, pBuffer, uiBufLen));
if (iReadSize < 0) {
(void)sys_close(iStatFD);
bbox_print(PRINT_ERR, "sys_read is failed, errno = %d.\n", errno);
bbox_print(PRINT_ERR, "sys_read执行失败errno = %d。\n", errno);
return RET_ERR;
}
@ -448,11 +471,11 @@ int BBOX_GetStatusInfo(char* pBuffer, unsigned int uiBufLen)
}
/*
* get status information of cpu
* in : char *pBuffer - buffer to store result
* unsigned int uiBufLen - buffer size
* return : count of character store into buffer - success
* RET_ERR - failed
* CPU信息
* char *pBuffer -
* unsigned int uiBufLen -
* -
* RET_ERR -
*/
int BBOX_GetCpuInfo(char* pBuffer, unsigned int uiBufLen)
{
@ -461,15 +484,16 @@ int BBOX_GetCpuInfo(char* pBuffer, unsigned int uiBufLen)
int iAllSize = 0;
int iReadSize = 0;
// 检查参数是否有效
if (NULL == pBuffer) {
bbox_print(PRINT_ERR, "BBOX_GetCpuInfo parameters is invalid.\n");
bbox_print(PRINT_ERR, "BBOX_GetCpuInfo参数无效。\n");
return RET_ERR;
}
/* information title */
iResult = bbox_snprintf(pBuffer, uiBufLen, "\nCPU INFO\n--------------------------------------------\n");
/* 信息标题 */
iResult = bbox_snprintf(pBuffer, uiBufLen, "\nCPU信息\n--------------------------------------------\n");
if (iResult <= 0 || iResult > (int)uiBufLen) {
bbox_print(PRINT_ERR, "bbox_snprintf is failed, errno = %d.\n", errno);
bbox_print(PRINT_ERR, "bbox_snprintf执行失败errno = %d。\n", errno);
return RET_ERR;
}
@ -478,18 +502,18 @@ int BBOX_GetCpuInfo(char* pBuffer, unsigned int uiBufLen)
uiBufLen -= iResult;
iAllSize += iResult;
/* open /proc/stat */
/* 打开/proc/stat */
BBOX_NOINTR(iStatFD = sys_open(BBOX_PROC_INTER_PATH, O_RDONLY, 0));
if (iStatFD < 0) {
bbox_print(PRINT_ERR, "sys_open is failed, errno = %d.\n", errno);
bbox_print(PRINT_ERR, "sys_open执行失败errno = %d。\n", errno);
return RET_ERR;
}
/* read /proc/stat */
/* 读取/proc/stat */
BBOX_NOINTR(iReadSize = sys_read(iStatFD, pBuffer, uiBufLen));
if (iReadSize < 0) {
(void)sys_close(iStatFD);
bbox_print(PRINT_ERR, "sys_read is failed, errno = %d.\n", errno);
bbox_print(PRINT_ERR, "sys_read执行失败errno = %d。\n", errno);
return RET_ERR;
}
@ -500,11 +524,11 @@ int BBOX_GetCpuInfo(char* pBuffer, unsigned int uiBufLen)
}
/*
* get information of system internal storage
* in : char *pBuffer - buffer to store result
* unsigned int uiBufLen - buffer size
* return : count of character store into buffer - success
* RET_ERR - failed
*
* char *pBuffer -
* unsigned int uiBufLen -
* -
* RET_ERR -
*/
int BBOX_GetMemInfo(char* pBuffer, unsigned int uiBufLen)
{
@ -513,15 +537,16 @@ int BBOX_GetMemInfo(char* pBuffer, unsigned int uiBufLen)
int iAllSize = 0;
int iReadSize = 0;
// 检查参数是否有效
if (NULL == pBuffer) {
bbox_print(PRINT_ERR, "BBOX_GetMemInfo parameters is invalid.\n");
bbox_print(PRINT_ERR, "BBOX_GetMemInfo参数无效。\n");
return RET_ERR;
}
/* information title */
iResult = bbox_snprintf(pBuffer, uiBufLen, "\nMEM INFO\n--------------------------------------------\n");
/* 信息标题 */
iResult = bbox_snprintf(pBuffer, uiBufLen, "\n内存信息\n--------------------------------------------\n");
if (iResult <= 0 || iResult > (int)uiBufLen) {
bbox_print(PRINT_ERR, "bbox_snprintf is failed, errno = %d.\n", errno);
bbox_print(PRINT_ERR, "bbox_snprintf执行失败errno = %d。\n", errno);
return RET_ERR;
}
@ -530,18 +555,18 @@ int BBOX_GetMemInfo(char* pBuffer, unsigned int uiBufLen)
uiBufLen -= iResult;
iAllSize += iResult;
/* open /proc/meminfo */
/* 打开/proc/meminfo */
BBOX_NOINTR(iStatFD = sys_open(BBOX_PROC_MEMINFO_PATH, O_RDONLY, 0));
if (iStatFD < 0) {
bbox_print(PRINT_ERR, "sys_open is failed, iStatFD = %d.\n", iStatFD);
bbox_print(PRINT_ERR, "sys_open执行失败iStatFD = %d。\n", iStatFD);
return RET_ERR;
}
/* read /proc/meminfo */
/* 读取/proc/meminfo */
BBOX_NOINTR(iReadSize = sys_read(iStatFD, pBuffer, uiBufLen));
if (iReadSize < 0) {
(void)sys_close(iStatFD);
bbox_print(PRINT_ERR, "sys_read is failed, iReadSize = %d.\n", iReadSize);
bbox_print(PRINT_ERR, "sys_read执行失败iReadSize = %d。\n", iReadSize);
return RET_ERR;
}
@ -551,6 +576,7 @@ int BBOX_GetMemInfo(char* pBuffer, unsigned int uiBufLen)
return iAllSize;
}
/*
* get information of ps command
* in : char *pBuffer - buffer to write result information
@ -558,6 +584,18 @@ int BBOX_GetMemInfo(char* pBuffer, unsigned int uiBufLen)
* return : success - count of characters written to the buffer
* failed - RET_ERR
*/
/*
BBOX_GetPsInfo
pBufferuiBufLen
NULL检查pBuffer为NULL
使bbox_snprintf函数将一些信息标题写入缓冲区线bbox_snprintf返回值小于等于0
"ps"使sys_popen函数打开一个管道iCommandFD文件描述符sys_popen返回的文件描述符小于0
使sys_read函数从iCommandFD文件描述符中读取数据sys_read返回的字节数小于0sys_pclose函数关闭打开的管道
iAllSize变量中iReadSize不为0'\0'
iAllSize变量的值
_BBOX_GetAddonInfoBBOX_GetPsInfo函数BBOX_GetPsInfo类似
#ifdef __cplusplus部分是对C++
*/
int BBOX_GetPsInfo(char* pBuffer, unsigned int uiBufLen)
{
int iResult = 0;

View File

@ -64,6 +64,15 @@ noteThe two pointers shouldn't be null. The last argument shouldn't less than
date: 2022/8/2
contact tel: 18720816902
*/
/*
bbox_strncmppszSrcpszTargetcount
cRes并初始化为0
使while循环进行字符串比较count大于0
cRes00
11
count减1
cRescRes为0cRes小于0cRes大于0
*/
s32 bbox_strncmp(const char* pszSrc, const char* pszTarget, s32 count)
{
signed char cRes = 0;
@ -167,6 +176,15 @@ note: I think the function isn't perfect, though it's not a core function. For e
date: 2022/8/2
contact tel:same
*/
/*
bbox_atoipszString
n和iNeg0n用于存储转换后的整数值iNeg用于表示是否为负数
'-'iNeg设置为1
iNeg为1
使while循环'0''9'
n乘以10'0'n中
n的值iNeg为1niNeg为0n
*/
s32 bbox_atoi(const char* pszString)
{
s32 n = 0;
@ -387,6 +405,27 @@ note: The string that indicates pszMode should only be "r" or "w",
date: 2022/8/2
contact tel: same
*/
/*
sys_popen的作用是打开一个管道
pszCmdpszMode
pszCmd和pszMode指针是否为空errno为EINVAL-1
pszMode只能为'r''w'errno为EINVAL-1
使bbox_GetFreePid函数获取一个空闲的管道ID-1
使sys_pipe函数创建一个管道-1
使sys_fork函数创建子进程ID-1
- pArgv
-
-
-
- 使sys_execve函数执行命令使sys_exit函数退出进程
ID和子进程ID保存起来
sys_pclose的作用是关闭由sys_popen打开的管道iFd
使bbox_FindPid函数根据文件描述符查找对应的管道ID-1
使sys_close函数关闭文件描述符
使sys_waitpid函数等待子进程的退出
ID
*/
s32 sys_popen(char* pszCmd, const char* pszMode)
{
struct PIPE_ID* volatile stCurPid = NULL;

View File

@ -139,51 +139,59 @@ contact tel: 18720816902
*/
s32 bbox_vsnprintf(BBOX_vnprintCallBack pCallback, void* ptr, s32 iSize, const char* pFmt, va_list ap)
{
// 定义变量
s32 iCount = 0; // 记录写入缓冲区的字符数
char c; // 临时存储格式化字符串中的字符
s32 iCheckFmt = 0; // 判断是否处于格式化标识符 '%' 的状态
s32 iQualifier = 0; // 判断是否有 'l' 或 'z' 限定符
s32 iSizeTConv = 0; // 判断是否有 'z' 限定符
s32 iRet = 0; // 用于保存回调函数的返回值
s32 iCount = 0;
char c;
s32 iCheckFmt = 0;
s32 iQualifier = 0;
s32 iSizeTConv = 0;
s32 iRet = 0;
// 检查缓冲区大小是否合法
if (iSize <= 0) {
return 0;
}
/* traversal handles formatting strings */
// 遍历格式化字符串
while (0 == iRet) {
c = *(pFmt++);
// 判断是否遍历完格式化字符串
if (!c) {
break;
}
/* judge format type if % */
// 判断是否为格式化标识符 '%'
if (c == '%' && 0 == iCheckFmt) {
// 初始化限定符和转换说明符
iQualifier = 0;
iSizeTConv = 0;
iCheckFmt = 1;
continue;
} else if (0 == iCheckFmt) {
/* copy */
// 复制非格式化标识符
iRet = pCallback(c, ptr, &iCount, iSize);
continue;
}
/* check whether the parameter has l */
// 判断是否有 'l' 限定符或 'z' 限定符
if (c == 'l' && iQualifier == 0) {
iQualifier = 1;
iQualifier = 1; // 标记有 'l' 限定符
continue;
} else if (c == 'z') {
iSizeTConv = 1;
iSizeTConv = 1; // 标记有 'z' 限定符
continue;
}
// 根据格式化标识符的类型执行相应的操作
switch (c) {
case 'c': {
// 处理字符类型
char ch = (char)va_arg(ap, int);
iRet = pCallback(ch, ptr, &iCount, iSize);
iRet = pCallback(ch, ptr, &iCount, iSize); // 调用回调函数处理字符
} break;
case 'd': {
// 处理有符号十进制整数类型
signed long long n = 0;
if (iSizeTConv) {
#if (defined(__x86_64__)) || (defined(__aarch64__))
@ -197,19 +205,22 @@ s32 bbox_vsnprintf(BBOX_vnprintCallBack pCallback, void* ptr, s32 iSize, const c
s32 isNeg = (n < 0) ? 1 : 0;
n = (isNeg) ? (-1 * n) : (n);
iRet = bbox_put_dox(pCallback, ptr, &iCount, iSize, (u64)n, 10, isNeg);
iRet = bbox_put_dox(pCallback, ptr, &iCount, iSize, (u64)n, 10, isNeg); // 调用回调函数处理数字
} break;
case 'l': {
// 处理长整型类型
signed long long n = (iQualifier) ? va_arg(ap, long long) : va_arg(ap, long);
s32 isNeg = (n < 0) ? 1 : 0;
n = (isNeg) ? (-1 * n) : (n);
iRet = bbox_put_dox(pCallback, ptr, &iCount, iSize, (u64)n, 10, isNeg);
iRet = bbox_put_dox(pCallback, ptr, &iCount, iSize, (u64)n, 10, isNeg); // 调用回调函数处理数字
} break;
case 'x': {
// 处理十六进制整数类型
unsigned long long n = (iQualifier) ? va_arg(ap, unsigned long int) : va_arg(ap, unsigned int);
iRet = bbox_put_dox(pCallback, ptr, &iCount, iSize, (u64)n, 16, 0);
iRet = bbox_put_dox(pCallback, ptr, &iCount, iSize, (u64)n, 16, 0); // 调用回调函数处理数字
} break;
case 'u': {
// 处理无符号十进制整数类型
unsigned long long n = 0;
if (iSizeTConv) {
#if (defined(__x86_64__)) || (defined(__aarch64__))
@ -221,37 +232,41 @@ s32 bbox_vsnprintf(BBOX_vnprintCallBack pCallback, void* ptr, s32 iSize, const c
n = (iQualifier) ? va_arg(ap, unsigned long long) : va_arg(ap, unsigned int);
}
iRet = bbox_put_dox(pCallback, ptr, &iCount, iSize, (u64)n, 10, 0);
iRet = bbox_put_dox(pCallback, ptr, &iCount, iSize, (u64)n, 10, 0); // 调用回调函数处理数字
} break;
case 'p': {
// 处理指针类型
unsigned long long n = va_arg(ap, unsigned long);
iRet = bbox_put_dox(pCallback, ptr, &iCount, iSize, (u64)n, 16, 0);
iRet = bbox_put_dox(pCallback, ptr, &iCount, iSize, (u64)n, 16, 0); // 调用回调函数处理数字
} break;
case 's': {
// 处理字符串类型
char* p = va_arg(ap, char*);
if (p == NULL) {
p = "<NULL>";
}
while (*p && (!iRet)) {
iRet = pCallback(*p, ptr, &iCount, iSize);
iRet = pCallback(*p, ptr, &iCount, iSize); // 调用回调函数处理字符
p++;
}
} break;
default:
iRet = pCallback(c, ptr, &iCount, iSize);
iRet = pCallback(c, ptr, &iCount, iSize); // 调用回调函数处理字符
break;
}
// 重置限定符和转换说明符
iQualifier = 0;
iCheckFmt = 0;
}
// 检查回调函数的返回值和终止符的写入情况
if (iRet != RET_OK || pCallback(0, ptr, &iCount, iSize) != RET_OK) {
return RET_ERR;
}
return iCount;
return iCount; // 返回写入缓冲区的字符数
}
/*
@ -269,20 +284,23 @@ note: none
date: 2022/8/3
contact tel: 18720816902
*/
/*
bbox_SnprintCallback函数是一个回调函数bbox_snprintf函数中的格式化字符串c写入到pszBuff指向的缓冲区中pszBuff和piCount的值
*/
s32 bbox_SnprintCallback(char c, void* pPtr, s32* piCount, s32 iSize)
{
char** pszBuff = (char**)pPtr;
/* return if the buffer length is exceeded */
/* 如果超过了缓冲区的长度限制,则返回错误 */
if (*piCount >= iSize - 1) {
/* set the last bit to 0 and return err, means that exit snprintf_s function. */
/* 将最后一位设置为0并返回错误表示退出snprintf_s函数 */
**pszBuff = 0;
return RET_ERR;
}
**pszBuff = c;
(*pszBuff)++;
(*piCount)++;
**pszBuff = c; // 将字符c写入到缓冲区中
(*pszBuff)++; // 更新pszBuff的地址
(*piCount)++; // 更新piCount的值
return RET_OK;
}
@ -294,6 +312,7 @@ s32 bbox_SnprintCallback(char c, void* pPtr, s32* piCount, s32 iSize)
* pFmt - string format
* return : string length
*/
//bbox_snprintf函数是一个简化版的snprintf函数用于格式化输出字符串到指定的缓冲区中。
s32 bbox_snprintf(char* pszBuff, s32 iSize, const char* pFmt, ...)
{
va_list ap;
@ -313,6 +332,10 @@ s32 bbox_snprintf(char* pszBuff, s32 iSize, const char* pFmt, ...)
* iSize - length limit
* return : string length
*/
/*
bbox_PrintCallback函数是一个回调函数bbox_printf函数和bbox_print函数中的格式化字符串
c写入到指定的文件描述符中g_pcCurWriteLogPos和g_iLastLogLen的值
*/
s32 bbox_PrintCallback(char c, void* pPtr, s32* piCount, s32 iSize)
{
s32* fd = (s32*)pPtr;
@ -321,14 +344,14 @@ s32 bbox_PrintCallback(char c, void* pPtr, s32* piCount, s32 iSize)
return RET_OK;
}
/* write */
/* 写入文件描述符 */
if (fd != 0 && *fd >= 0) {
sys_write(*fd, &c, 1);
}
/* return if the buffer length is exceeded */
/* 如果超过了缓冲区的长度限制,则返回错误 */
if (g_iLastLogLen <= 1) {
/* set the last bit to 0 and return err, means that exit snprintf_s function. */
/* 将最后一位设置为0并返回错误表示退出snprintf_s函数 */
*g_pcCurWriteLogPos = 0;
if (g_iLogScreen) {
return RET_OK;
@ -337,9 +360,9 @@ s32 bbox_PrintCallback(char c, void* pPtr, s32* piCount, s32 iSize)
return RET_ERR;
}
*g_pcCurWriteLogPos = c;
(g_pcCurWriteLogPos)++;
(g_iLastLogLen)--;
*g_pcCurWriteLogPos = c; // 将字符c写入到缓冲区中
(g_pcCurWriteLogPos)++; // 更新g_pcCurWriteLogPos的地址
(g_iLastLogLen)--; // 更新g_iLastLogLen的值
return RET_OK;
}
@ -347,6 +370,7 @@ s32 bbox_PrintCallback(char c, void* pPtr, s32* piCount, s32 iSize)
/*
* simple signal-safe function printf
*/
//bbox_printf函数是一个简化版的printf函数用于将格式化的字符串输出到标准输出。
void bbox_printf(const char* pFmt, ...)
{
s32 fd = 1;
@ -360,6 +384,7 @@ void bbox_printf(const char* pFmt, ...)
/*
* simple signal-safe function print
*/
//bbox_print函数是一个简化版的printf函数可以根据打印级别和屏幕打印级别来输出格式化的字符串到标准输出。
void bbox_print(EN_PRINT_TYPE enType, const char* pFmt, ...)
{
s32 fd = 1;
@ -383,6 +408,7 @@ void bbox_print(EN_PRINT_TYPE enType, const char* pFmt, ...)
/*
* set print level
*/
//bbox_set_log_level函数用于设置日志级别根据传入的enLevel参数来设置全局变量g_enLogLevel的值。
s32 bbox_set_log_level(EN_PRINT_TYPE enLevel)
{
if (enLevel < PRINT_DBG || enLevel > PRINT_ERR) {
@ -397,6 +423,7 @@ s32 bbox_set_log_level(EN_PRINT_TYPE enLevel)
/*
* set screen print level
*/
//bbox_set_screen_log_level函数用于设置屏幕打印级别根据传入的enLevel参数来设置全局变量g_enScreenLogLeven的值。
s32 bbox_set_screen_log_level(EN_PRINT_TYPE enLevel)
{
if (enLevel < PRINT_DBG || enLevel > PRINT_ERR) {

View File

@ -72,6 +72,14 @@ note: The stack this function creats is actually a character array.
date: 2022/8/3
contact tel: 18720816902
*/
/*
void BBOX_ReserveZeroStack(s32 count)
1. count的字符数组buff
2. memset_s函数将buff的值全部设置为0
3. sys_read函数将buff的值从文件描述符-1使
*/
void BBOX_ReserveZeroStack(s32 count)
{
char buff[count];
@ -86,6 +94,13 @@ void BBOX_ReserveZeroStack(s32 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, ...)
1. pArg和pFn是否为NULLNULL则返回-1
2. sys__clone函数克隆当前进程
3. pid
*/
s32 BBOX_CloneRun(u32 uFlags, s32 (*pFn)(void*), void* pArg, ...)
{
/* reserve 4K when calling and running a function to protect waitpid can exit correct. */
@ -153,6 +168,26 @@ note: none
date: 2022/8/3
contact tel: 18720816902
*/
/*
线ID的函数
TASK_ATTACH_INFO结构体的指针pstTaskInfoiSize和指向字符数组的指针szTaskPath
1. pstTaskInfo和szTaskPath是否为NULL-1
2. 使sys_open函数以只读和目录模式打开指定的路径szTaskPathiProc中
3. iProc小于0-1
4. 使/proc/[pid]/task目录下的所有文件iThreadCount表示已经获取的进程和线程ID的数量
5. 使sys_getdents函数读取目录项szBuff中nBytes中
6. nBytes小于0errout标签
7. nBytes等于0使sys_lseek函数将文件指针设置到目录的开头位置
8. 线
9. pidpid存储到pstTaskInfo数组对应的元素中
10. iThreadCount加1线ID的数量
11. 使sys_close函数关闭iProc
12. 线ID的数量iThreadCount-1
*/
s32 BBOX_GetTaskId(struct TASK_ATTACH_INFO* pstTaskInfo, s32 iSize, char* szTaskPath)
{
s32 iProc = -1;
@ -248,6 +283,19 @@ note: none
date: 2022/8/3
contact tel: 18720816902
*/
/*
s32 BBOX_PtraceAttachPid(struct TASK_ATTACH_INFO* pstTaskInfo, s32 iPidCount, s32 iDoPtraceCheck)
pstTaskInfo和iPidCount是否合法
使pstTaskInfo数组中的每个任务
使sys_ptrace函数将指定任务的跟踪状态设置为跟踪状态
使sys_waitpid函数等待指定任务结束
EINTR使sys_ptrace函数将跟踪状态取消
iDoPtraceCheck为真使sys_ptrace函数检查跟踪状态是否有效
cIsAttached成员变量设置为已跟踪状态
*/
s32 BBOX_PtraceAttachPid(struct TASK_ATTACH_INFO* pstTaskInfo, s32 iPidCount, s32 iDoPtraceCheck)
{
u32 i;
@ -367,20 +415,26 @@ note: none
date: 2022/8/3
contact tel: 18720816902
*/
/*
BBOX_ListParams的指针pstArgs线iMaxThreadCount和一个指向char类型的指针pszProcSelfTask作为参数
使ptrace操作来追踪并运行线程
*/
s32 BBOX_PtraceAndRun(struct BBOX_ListParams* pstArgs, s32 iMaxThreadCount, char* pszProcSelfTask)
{
struct TASK_ATTACH_INFO stTaskInfo[iMaxThreadCount];
pid_t thread_pids[iMaxThreadCount];
// 声明一些变量
struct TASK_ATTACH_INFO stTaskInfo[iMaxThreadCount]; // 存储线程信息的数组
pid_t thread_pids[iMaxThreadCount]; // 存储线程PID的数组
struct TASK_CHECK_RESUME_ARGS stTaskCheck; // 追踪线程所需参数
s32 iThreadCount = 0; // 线程数量
s32 iAttachCount = 0; // 被追踪的线程数量
s32 iRet = 0; // 返回值变量
s32 iDoPtraceCheck = 1; // 是否需要使用ptrace检查
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) {
// 参数检查,如果参数无效则打印错误信息并返回错误码
if (pstArgs == NULL || pszProcSelfTask == NULL || iMax 线0) {
bbox_print(PRINT_ERR,
"Parameter is invald, pstArgs or pszProcSelfTask is NULL, iMaxThreadCount = %d \n",
iMaxThreadCount);
@ -388,6 +442,7 @@ s32 BBOX_PtraceAndRun(struct BBOX_ListParams* pstArgs, s32 iMaxThreadCount, char
return RET_ERR;
}
// 初始化stTaskInfo、thread_pids和stTaskCheck为0
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));
@ -395,6 +450,7 @@ s32 BBOX_PtraceAndRun(struct BBOX_ListParams* pstArgs, s32 iMaxThreadCount, char
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");
@ -402,19 +458,21 @@ s32 BBOX_PtraceAndRun(struct BBOX_ListParams* pstArgs, s32 iMaxThreadCount, char
goto errout;
}
// 根据pstArgs的enGetType判断是否需要使用ptrace检查
if (GET_TYPE_DUMP != pstArgs->enGetType) {
iDoPtraceCheck = 0;
} else {
iDoPtraceCheck = 1;
}
// 使用BBOX_PtraceAttachPid函数对线程进行ptrace追踪
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. */
// 将已经被追踪的线程的PID复制到thread_pids数组中
for (i = 0; i < iThreadCount; i++) {
if (!stTaskInfo[i].cIsAttached) {
continue;
@ -423,23 +481,26 @@ s32 BBOX_PtraceAndRun(struct BBOX_ListParams* pstArgs, s32 iMaxThreadCount, char
iAttachCount++;
}
// 设置stTaskCheck的相应参数
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;
}
@ -454,30 +515,38 @@ note: none
date: 2022/8/3
contact tel: 18720816902
*/
/*
char类型的指针pFileName作为参数g_acBBoxLog中的内容输出到文件中
*/
// 函数声明将全局变量g_acBBoxLog中的内容输出到文件中
void BBOX_PrintFailedLog(const char* pFileName)
{
ssize_t iRet = 0;
s32 iWriteSize = 0;
s32 iBboxLogFd = -1;
ssize_t iRet = 0; // 返回值变量
s32 iWriteSize = 0; // 写入的数据大小变量
s32 iBboxLogFd = -1; // 文件描述符变量,初始化为-1
// 使用sys_open函数打开文件以可读写和创建方式打开文件的访问权限为0600
iBboxLogFd = sys_open(pFileName, O_RDWR | O_CREAT | O_TRUNC, 0600);
if (iBboxLogFd < 0) {
bbox_print(PRINT_ERR, "open failed, errno = %d\n", errno);
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;
// 使用sys_write函数将g_acBBoxLog中的内容写入到文件中
iRet = sys_write(iBboxLogFd, g_acBBoxLog, iWriteSize);
if (iRet < 0) {
bbox_print(PRINT_ERR, "write failed, errno = %d\n", errno);
bbox_print(PRINT_ERR, "write failed, errno = %d\n", errno); // 打印错误信息
sys_close(iBboxLogFd);
sys_close(iBboxLogFd); // 关闭文件描述符
return;
}
// 使用sys_close函数关闭文件描述符
sys_close(iBboxLogFd);
}
@ -491,59 +560,69 @@ 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;
pid_t ppid = 0; // 父进程的进程ID
s32 iMaker = -1; // socket的文件描述符初始化为-1
s32 iMaxThreadCount = 0; // 最大线程数初始化为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;
struct kernel_stat stMarkerSB; // 文件状态结构体
char szProcSelfTask[BBOX_PROC_PATH_LEN]; // 存放进程任务路径的数组
char pszMarkPath[BBOX_PROC_PATH_LEN]; // 存放标记路径的数组
stack_t altstack; // 备用信号栈结构体
errno_t rc = EOK; // 错误号变量初始化为EOK
// 如果pstArgs为空指针则打印错误信息并返回
if (pstArgs == NULL) {
bbox_print(PRINT_ERR, "pstArgs is NULL.\n");
return;
}
// 获取父进程的进程ID
ppid = sys_getppid();
// 创建一个socket使用本地通信的地址族数据报套接字类型协议为0自动选择协议
iMaker = sys_socket(PF_LOCAL, SOCK_DGRAM, 0);
if (iMaker < 0) {
bbox_print(PRINT_ERR, "sys_socket error, errno = %d\n", errno);
goto errout;
}
// 设置socket的关闭执行标记为FD_CLOEXEC确保在exec族函数调用时关闭socket
if (sys_fcntl(iMaker, F_SETFD, FD_CLOEXEC) < 0) {
bbox_print(PRINT_ERR, "sys_fcntl error, errno = %d\n", errno);
goto errout;
}
// 使用bbox_snprintf函数将父进程的任务路径写入szProcSelfTask数组中
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;
}
// 使用bbox_snprintf函数将标记路径写入pszMarkPath数组中
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;
}
// 打印提示信息显示正在获取pid为ppid的进程的信息
bbox_print(PRINT_TIP, "Get information for pid %d:\n", ppid);
// 使用memset_s函数将stMarkerSB结构体清零
rc = memset_s(&stMarkerSB, sizeof(stMarkerSB), 0, sizeof(stMarkerSB));
securec_check_c(rc, "\0", "\0");
// 使用sys_stat函数获取pszMarkPath对应文件的状态信息并保存到stMarkerSB结构体中
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;
@ -551,48 +630,61 @@ void BBOX_ListThread(struct BBOX_ListParams* pstArgs)
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. */
// 对线程执行ptrace并运行
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");
// 关闭socket
sys_close(iMaker);
// 如果pstArgs的结果不等于RET_OK则调用BBOX_PrintFailedLog函数打印失败日志
if (RET_OK != pstArgs->iResult) {
BBOX_PrintFailedLog((char*)(((struct BBOX_ListDirParam*)(pstArgs->pDoneArgs))->pArg2));
}
// 如果pstArgs的回调函数不为空则调用回调函数
if (pstArgs->pDoneCallback != NULL) {
pstArgs->pDoneCallback(pstArgs->pDoneArgs);
}
// 退出线程返回值为0
sys_exit(0);
// 错误处理
errout:
if (iMaker > 0) {
sys_close(iMaker);
}
// 打印错误信息
bbox_print(PRINT_ERR, "Get information failed.\n");
// 设置pstArgs的结果为-1并保存错误号
pstArgs->iResult = -1;
pstArgs->iError = errno;
// 调用BBOX_PrintFailedLog函数打印失败日志
BBOX_PrintFailedLog((char*)(((struct BBOX_ListDirParam*)(pstArgs->pDoneArgs))->pArg2));
// 如果pstArgs的回调函数不为空则调用回调函数
if (pstArgs->pDoneCallback != NULL) {
pstArgs->pDoneCallback(pstArgs->pDoneArgs);
}
// 退出线程返回值为1
sys_exit(1);
}
@ -609,6 +701,9 @@ note: none
date: 2022/8/3
contact tel: 18720816902
*/
/*
*
*/
s32 BBOX_GetClonePidResult(pid_t iClonePid, struct BBOX_ListParams* pstArgs, s32 iCloneErrno)
{
s32 iStatus = 0;
@ -616,7 +711,7 @@ s32 BBOX_GetClonePidResult(pid_t iClonePid, struct BBOX_ListParams* pstArgs, s32
if (iClonePid < 0) {
bbox_print(PRINT_ERR, "Clone failed, can't create child process, errno = %d.\n", iCloneErrno);
bbox_print(PRINT_ERR, "克隆进程失败无法创建子进程errno = %d。\n", iCloneErrno);
BBOX_PrintFailedLog((char*)(((struct BBOX_ListDirParam*)(pstArgs->pDoneArgs))->pArg2));
if (pstArgs->pDoneCallback != NULL) {
@ -626,12 +721,12 @@ s32 BBOX_GetClonePidResult(pid_t iClonePid, struct BBOX_ListParams* pstArgs, s32
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));
bbox_print(PRINT_LOG, "克隆进程的pid %d 返回值为 %x状态为 %x\n", iClonePid, iRet, WIFEXITED(iStatus));
if (iRet < 0) {
pstArgs->iError = errno;
@ -656,21 +751,22 @@ s32 BBOX_GetClonePidResult(pid_t iClonePid, struct BBOX_ListParams* pstArgs, s32
} else if (!WIFEXITED(iStatus)) {
pstArgs->iError = EFAULT;
pstArgs->iResult = -1;
bbox_print(PRINT_ERR, "WIFEXITED status failed");
bbox_print(PRINT_ERR, "WIFEXITED 状态判断失败");
} else {
pstArgs->iError = iCloneErrno;
pstArgs->iResult = -1;
bbox_print(PRINT_ERR, "WIFEXITED error, errno = %d\n", iCloneErrno);
bbox_print(PRINT_ERR, "WIFEXITED 错误,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, ...)
/*
* 线
*/
s32 BBOX_GetAllThreads(GET_THREAD_TYPE enType, BBOX_GetAllThreadDone pDone, void* pDoneArgs, BBOX_GetAllThreadsCallBack pCallback, ...)
{
struct BBOX_ListParams stArgs;
struct kernel_sigset_t stSigBlocked;
@ -685,14 +781,14 @@ s32 BBOX_GetAllThreads(
if (BBOX_AtomicIncReturn(&g_isBusy) > 1) {
BBOX_AtomicDec(&g_isBusy);
bbox_print(PRINT_ERR, "Dump task is running.\n");
bbox_print(PRINT_ERR, "Dump任务正在运行中。\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_print(PRINT_ERR, "参数无效enType = %d可能 pCallback 为空", enType);
BBOX_AtomicDec(&g_isBusy);
return -1;
}
@ -706,19 +802,19 @@ s32 BBOX_GetAllThreads(
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 */
/* 保留 32K */
BBOX_ReserveZeroStack(1024 * 32);
/* check and set dump flag. */
/* 检查并设置dump标志 */
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. */
/* 设置dump线程的启动参数 */
stArgs.iResult = -1;
stArgs.iError = 0;
stArgs.pAltStackMem = g_szAltStackMem;
@ -727,36 +823,35 @@ s32 BBOX_GetAllThreads(
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);
bbox_print(PRINT_ERR, "sys_sigprocmask 错误,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. */
/* 如果类型是快照则复制VMA */
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");
bbox_print(PRINT_ERR, "BBOX_GetClonePidResult 错误\n");
}
errout:

View File

@ -73,29 +73,50 @@ note: none
date: 2022/8/4
contact tel: 18720816902
*/
static void coredump_handler(int sig, siginfo_t *si, void *uc)
{
/**
*
*
*
*
* - sig
* - si
* - uc
*/
static void coredump_handler(int sig, siginfo_t *si, void *uc) {
// 此变量存储第一个遇到致命错误的线程的线程ID。
static volatile int64 first_tid = INVALID_TID;
// 获取当前线程的线程ID。
int64 cur_tid = (int64)pthread_self();
// 检查是否为任何线程首次遇到的致命错误。
if (first_tid == INVALID_TID &&
__sync_bool_compare_and_swap(&first_tid, INVALID_TID, cur_tid)) {
/* Only first fatal error will set db state and generate fatal error log */
/* 只有首个致命错误会设置数据库状态并生成致命错误日志 */
// 将数据库状态文件设置为 COREDUMP_STATE表示发生了核心转储。
(void)SetDBStateFileState(COREDUMP_STATE, false);
// 如果启用了 FFIC 日志,则生成一个错误消息。
if (g_instance.attr.attr_common.enable_ffic_log) {
(void)gen_err_msg(sig, si, (ucontext_t *)uc);
}
} else {
/*
* Subsequent fatal error will go to here. If it comes from different thread,
* wait until first error handler end, and if it is a reentry, terminate process.
* 线
*
*/
// 如果这不是第一个致命错误并且来自不同的线程,
// 则等待第一个错误处理器结束,如果是重新进入,则终止进程。
if (first_tid != cur_tid) {
(void)pause();
}
}
// 恢复信号的默认处理器。
(void)pqsignal(sig, SIG_DFL);
// 再次触发该信号,以调用默认的信号处理器。
(void)raise(sig);
}
@ -162,30 +183,40 @@ note: none
date: 2022/8/4
contact tel: 18720816902
*/
static void get_bbox_coredump_pattern_path(char* path, Size len)
{
/**
*
*
*
* - path
* - len
*/
static void get_bbox_coredump_pattern_path(char* path, Size len) {
FILE* fp = NULL;
char* p = NULL;
struct stat stat_buf;
if ((fp = fopen("/proc/sys/kernel/core_pattern", "r")) == NULL) {
write_stderr("cannot open file: /proc/sys/kernel/core_pattern.\n");
// 打开文件失败,写入错误提示信息,并返回。
write_stderr("无法打开文件:/proc/sys/kernel/core_pattern。\n");
return;
}
if (fgets(path, len, fp) == NULL) {
// 获取核心模式路径失败,关闭文件,写入错误提示信息,并返回。
fclose(fp);
write_stderr("failed to get the core pattern path.\n ");
write_stderr("无法获取核心模式路径。\n");
return;
}
fclose(fp);
if ((p = strrchr(path, '/')) == NULL) { /* a relative-path file */
if ((p = strrchr(path, '/')) == NULL) { /* 相对路径文件 */
*path = '\0';
} else { /* an absolute-path file */
} else { /* 绝对路径文件 */
*(++p) = '\0';
// 检查路径是否有效并且具有写权限。
if (stat(path, &stat_buf) != 0 || !S_ISDIR(stat_buf.st_mode) || access(path, W_OK) != 0) {
write_stderr("The core dump path is an invalid directory\n");
// 核心转储路径是无效的目录,写入错误提示信息,并清空路径。
write_stderr("核心转储路径是无效的目录。\n");
*path = '\0';
}
}
@ -202,21 +233,28 @@ note: none
date: 2022/8/4
contact tel: 18720816902
*/
static void build_bbox_corepath(char *bbox_core_path, Size path_size, char *config_path)
{
/**
* bbox
*
*
* - bbox_core_path bbox
* - path_size
* - config_path NULL使
*/
static void build_bbox_corepath(char *bbox_core_path, Size path_size, char *config_path) {
struct stat stat_buf;
/*
* the guc parameter bbox_dump_path is set to NULL as default.
* bbox_dump_path has to be a valid directory, if it is altered by users.
* guc bbox_dump_path NULL
* bbox_dump_path
*/
if (config_path != NULL && config_path[0] != '\0') {
if (stat(config_path, &stat_buf) != 0 || !S_ISDIR(stat_buf.st_mode) || access(config_path, W_OK) != 0) {
ereport(WARNING,
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
errmsg("bbox_dump_path %s is an invalid directory!\n", config_path)));
errmsg("bbox_dump_path %s 是一个无效的目录!\n", config_path)));
/* if bbox_dump_path is invalid, the path of core dump will be set as default. */
/* 如果 bbox_dump_path 是无效的,将使用默认的核心转储路径。 */
get_bbox_coredump_pattern_path(bbox_core_path, path_size);
} else {
errno_t rc = strcpy_s(bbox_core_path, path_size, config_path);
@ -224,29 +262,27 @@ static void build_bbox_corepath(char *bbox_core_path, Size path_size, char *conf
}
} else {
/*
* default path of the core dump will be obtained
* by reading the file "/proc/sys/kernel/core_pattern"
* "/proc/sys/kernel/core_pattern"
*/
get_bbox_coredump_pattern_path(bbox_core_path, path_size);
}
}
/*
* check_bbox_corepath - check coredump path for bbox
* check_bbox_corepath - bbox
*/
bool check_bbox_corepath(char** newval, void** extra, GucSource source)
{
bool check_bbox_corepath(char** newval, void** extra, GucSource source) {
if (t_thrd.proc_cxt.MyProcPid != PostmasterPid)
return true;
char core_dump_path[BBOX_PATH_SIZE] = {0};
/* determine which path is used for bbox core dump file */
/* 确定用于 bbox 核心转储文件的路径 */
build_bbox_corepath(core_dump_path, sizeof(core_dump_path), (newval != NULL) ? *newval : NULL);
if (core_dump_path[0] != '\0' && BBOX_SetCoredumpPath(core_dump_path) == RET_OK) {
ereport(LOG,
(errcode(ERRCODE_INVALID_PARAMETER_VALUE), errmsg("bbox_dump_path is set to %s", core_dump_path)));
(errcode(ERRCODE_INVALID_PARAMETER_VALUE), errmsg("bbox_dump_path 设置为 %s", core_dump_path)));
}
char* result = (char*)MemoryContextAlloc(SESS_GET_MEM_CXT_GROUP(MEMORY_CONTEXT_DFX), BBOX_PATH_SIZE);
@ -302,39 +338,59 @@ note: none
date: 2022/8/4
contact tel: 18720816902
*/
/**
*
*
*
* - source
*
*
* -
*/
static List* split_string_into_blacklist(const char* source)
{
List *result = NIL;
char *str = pstrdup(source);
char *first_ch = str;
int len = strlen(str) + 1;
List *result = NIL; // 初始化列表为空
char *str = pstrdup(source); // 复制源字符串
char *first_ch = str; // 指向第一个字符的指针
int len = strlen(str) + 1; // 字符串长度加1包括结尾的空字符
for (int i = 0; i < len; i++) {
if (str[i] == ',' || str[i] == '\0') {
/* replace ',' with '\0'. */
/* 将 ',' 替换为 '\0' */
str[i] = '\0';
/* copy this into result. */
/* 将该字符串添加到结果列表中 */
result = lappend(result, pstrdup(first_ch));
/* move to the head of next string. */
/* 移动到下一个字符串的开头 */
first_ch = str + i + 1;
i++;
}
}
pfree(str);
pfree(str); // 释放复制的字符串内存
return result;
return result; // 返回拆分后的黑名单列表
}
/**
* bbox
*
*
* - newval
* - extra
* - source
*
*
* - true false
*/
bool check_bbox_blacklist(char** newval, void** extra, GucSource source)
{
if (t_thrd.proc_cxt.MyProcPid != PostmasterPid)
return true;
List *result = split_string_into_blacklist(*newval);
List *result = split_string_into_blacklist(*newval); // 将配置项的值拆分为黑名单列表
ListCell *lc = NULL;
uint64 mask = 0;
uint64 mask = 0; // 用于保存黑名单掩码
size_t i;
foreach(lc, result) {
@ -349,45 +405,62 @@ bool check_bbox_blacklist(char** newval, void** extra, GucSource source)
}
if (i == sizeof(g_blacklist_items) / sizeof(BlacklistItem)) {
ereport(WARNING,
(errmsg("blacklist item %s does not exist, so it is ignored.", (char*)lfirst(lc))));
(errmsg("黑名单项 %s 不存在,已忽略。", (char*)lfirst(lc))));
}
}
list_free_deep(result);
list_free_deep(result); // 释放拆分后的黑名单列表内存
*extra = MemoryContextAlloc(SESS_GET_MEM_CXT_GROUP(MEMORY_CONTEXT_DFX), sizeof(uint64));
if (*extra == NULL)
return false;
*((uint64*)*extra) = (mask == 0) ? DEFAULT_BLACKLIST_MASK : mask;
*((uint64*)*extra) = (mask == 0) ? DEFAULT_BLACKLIST_MASK : mask; // 设置附加信息为黑名单掩码
return true;
}
/**
* bbox
*
*
* - newval
* - extra
*/
void assign_bbox_blacklist(const char* newval, void* extra)
{
if (t_thrd.proc_cxt.MyProcPid == PostmasterPid) {
g_instance.attr.attr_common.bbox_blacklist_mask = *((uint64*)extra);
g_instance.attr.attr_common.bbox_blacklist_mask = *((uint64*)extra); // 设置 bbox 黑名单掩码
}
}
/**
* bbox
*
*
* - bbox
*/
const char* show_bbox_blacklist()
{
StringInfoData str;
initStringInfo(&str);
initStringInfo(&str); // 初始化字符串信息
for (size_t i = 0; i < sizeof(g_blacklist_items) / sizeof(BlacklistItem); i++) {
if ((BLACKLIST_ITEM_MASK(g_blacklist_items[i].blacklist_ID) & BBOX_BLACKLIST) != 0) {
appendStringInfo(&str, "%s,", g_blacklist_items[i].blacklist_name);
}
}
if (str.len >= 0) {
str.data[--str.len] = '\0';
str.data[--str.len] = '\0'; // 将最后一个逗号替换为结束符
}
return str.data;
return str.data; // 返回黑名单字符串
}
/*
* assign_bbox_coredump - set coredump for bbox or not
/**
* bbox
*
*
* - newval
* - extra
*/
void assign_bbox_coredump(const bool newval, void* extra)
{
@ -395,7 +468,7 @@ void assign_bbox_coredump(const bool newval, void* extra)
return;
if (newval && !FencedUDFMasterMode) {
(void)install_signal(SIGABRT, bbox_handler);
(void)install_signal(SIGABRT, bbox_handler); // 安装信号处理程序
(void)install_signal(SIGBUS, bbox_handler);
(void)install_signal(SIGILL, bbox_handler);
(void)install_signal(SIGSEGV, bbox_handler);
@ -407,33 +480,33 @@ void assign_bbox_coredump(const bool newval, void* extra)
}
}
/*
* do initilaization for dumping core file
/**
* bbox
*/
void bbox_initialize()
{
char core_dump_path[BBOX_PATH_SIZE] = {0};
char core_dump_path[BBOX_PATH_SIZE] = {0}; // 存储核心转储路径的缓冲区
/* determine path which is used for bbox core dump file */
/* 确定用于 bbox 核心转储文件的路径 */
build_bbox_corepath(core_dump_path, sizeof(core_dump_path),
u_sess->attr.attr_common.bbox_dump_path);
if (u_sess->attr.attr_common.enable_bbox_dump && *core_dump_path != '\0' &&
CheckFilenameValid(core_dump_path) == RET_OK &&
BBOX_SetCoredumpPath(core_dump_path) == 0) {
write_stderr("bbox_dump_path is set to %s\n", core_dump_path);
write_stderr("bbox_dump_path 设置为 %s\n", core_dump_path); // 打印核心转储路径
}
/*
* no matter bbox_dump_count is default (8) or set by users, call function BBOX_SetCoreFileCount.
* Note: bbox_dump_count cannot be smaller than 1.
* bbox_dump_count (8) BBOX_SetCoreFileCount
* bbox_dump_count 1
*/
if (u_sess->attr.attr_common.bbox_dump_count != 0 &&
BBOX_SetCoreFileCount(u_sess->attr.attr_common.bbox_dump_count) != 0) {
write_stderr("failed to set coredump count.\n");
write_stderr("设置核心转储文件计数失败。\n"); // 打印设置核心转储文件计数失败信息
}
assign_bbox_coredump(u_sess->attr.attr_common.enable_bbox_dump, NULL);
assign_bbox_coredump(u_sess->attr.attr_common.enable_bbox_dump, NULL); // 设置是否进行 bbox 核心转储
}
/*
@ -452,8 +525,8 @@ void bbox_blacklist_add(BlacklistIndex item, void* addr, uint64 size)
}
/*
* remove an blacklist item.
* void *pAddress : the head address of excluded memory
*
* void *pAddress :
*/
void bbox_blacklist_remove(BlacklistIndex item, void* addr)
{
@ -464,14 +537,9 @@ void bbox_blacklist_remove(BlacklistIndex item, void* addr)
}
/*
function name: CheckFilenameValid
description: Check if the filename is in line with norms, or if dangerous characters appear
the filename is invalid.
arguments: A pointer to string indicating filename.
return value: An integer, if function works normally, the value is RET_OK, else it's RET_ERR.
note: none
date: 2022/8/4
contact tel: 18720816902
:
:
: RET_OK RET_ERR
*/
int CheckFilenameValid(const char* inputEnvValue)
{
@ -491,4 +559,3 @@ int CheckFilenameValid(const char* inputEnvValue)
}
return RET_OK;
}

0
src/gausskernel/cbb/communication/libcomm.cpp Executable file → Normal file
View File

View File

@ -41,64 +41,64 @@
#include "libcomm_common.h"
int binary_semaphore::init() {
atomic_set(&b_flag, 0);
atomic_set(&waiting_count, 0);
atomic_set(&b_destroy, 0);
atomic_set(&destroy_wait, 0);
int err = pthread_cond_init(&cond, NULL);
atomic_set(&b_flag, 0); // 初始化 b_flag 为 0
atomic_set(&waiting_count, 0); // 初始化 waiting_count 为 0
atomic_set(&b_destroy, 0); // 初始化 b_destroy 为 0
atomic_set(&destroy_wait, 0); // 初始化 destroy_wait 为 0
int err = pthread_cond_init(&cond, NULL); // 初始化 cond若失败则返回错误码
if (err != 0)
return err;
err = pthread_mutex_init(&mutex, NULL);
err = pthread_mutex_init(&mutex, NULL); // 初始化 mutex若失败则销毁 cond并返回错误码
if (err != 0) {
LIBCOMM_PTHREAD_COND_DESTORY(&cond);
return err;
}
return err;
return err; // 返回错误码
}
int binary_semaphore::destroy(bool do_destroy) {
const int ret = 0;
atomic_set(&b_destroy, 1);
while (destroy_wait != 0) {
post();
usleep(100);
}
if (do_destroy) {
LIBCOMM_PTHREAD_COND_DESTORY(&cond);
LIBCOMM_PTHREAD_MUTEX_DESTORY(&mutex);
}
return ret;
const int ret = 0;
atomic_set(&b_destroy, 1); // 将 b_destroy 置为 1 表示要销毁
while (destroy_wait != 0) { // 若存在等待销毁的线程,则发送信号,并休眠 100 微秒
post();
usleep(100);
}
if (do_destroy) { // 若指定要进行销毁,则销毁 cond 和 mutex
LIBCOMM_PTHREAD_COND_DESTORY(&cond);
LIBCOMM_PTHREAD_MUTEX_DESTORY(&mutex);
}
return ret; // 返回 0
}
void binary_semaphore::reset() {
atomic_set(&b_flag, 0);
while (destroy_wait != 0) {
atomic_set(&b_flag, 0); // 将 b_flag 重置为 0
while (destroy_wait != 0) { // 若存在等待销毁的线程,则发送信号,并休眠 100 微秒
post();
usleep(100);
}
}
void binary_semaphore::post() {
LIBCOMM_PTHREAD_MUTEX_LOCK(&mutex);
void binary_semaphore::post() {
LIBCOMM_PTHREAD_MUTEX_LOCK(&mutex); // 上锁 mutex
/* thread will poll up when someone has posted before */
atomic_set(&b_flag, 1);
if (waiting_count > 0) {
atomic_set(&b_flag, 1); // 将 b_flag 置为 1 表示已有线程发送信号
if (waiting_count > 0) { // 若存在等待的线程,则发送一个信号给等待线程
LIBCOMM_PTHREAD_COND_SIGNAL(&cond);
}
LIBCOMM_PTHREAD_MUTEX_UNLOCK(&mutex);
LIBCOMM_PTHREAD_MUTEX_UNLOCK(&mutex); // 解锁 mutex
}
void binary_semaphore::post_all() {
LIBCOMM_PTHREAD_MUTEX_LOCK(&mutex);
atomic_set(&b_flag, 1);
if (waiting_count > 0) {
LIBCOMM_PTHREAD_MUTEX_LOCK(&mutex); // 上锁 mutex
atomic_set(&b_flag, 1); // 将 b_flag 置为 1 表示已有线程发送信号
if (waiting_count > 0) { // 若存在等待的线程,则发送广播给所有等待线程
LIBCOMM_PTHREAD_COND_BROADCAST(&cond);
}
LIBCOMM_PTHREAD_MUTEX_UNLOCK(&mutex);
LIBCOMM_PTHREAD_MUTEX_UNLOCK(&mutex); // 解锁 mutex
}
int binary_semaphore::wait() {
if (b_flag) {
if (b_flag) { // 若 b_flag 为 1则表示已有线程发送信号不需要等待
/* reset b_flag is no one is waitting */
if (waiting_count == 0)
atomic_set(&b_flag, 0);
@ -106,29 +106,29 @@ int binary_semaphore::wait() {
}
int ret = 0;
LIBCOMM_PTHREAD_MUTEX_LOCK(&mutex);
while (!b_flag) {
atomic_add(&waiting_count, 1);
ret = pthread_cond_wait(&cond, &mutex);
LIBCOMM_PTHREAD_MUTEX_LOCK(&mutex); // 上锁 mutex
while (!b_flag) { // 若 b_flag 为 0则表示没有线程发送信号需要等待
atomic_add(&waiting_count, 1);
ret = pthread_cond_wait(&cond, &mutex); // 等待信号,并当有信号到来时解锁 mutex 并接收信号
atomic_sub(&waiting_count, 1);
}
if (b_destroy)
if (b_destroy) // 若 b_destroy 为 1则表示要销毁返回错误码
ret = -1;
/* reset b_flag is no one is waitting */
if (waiting_count == 0)
atomic_set(&b_flag, 0);
LIBCOMM_PTHREAD_MUTEX_UNLOCK(&mutex);
LIBCOMM_PTHREAD_MUTEX_UNLOCK(&mutex); // 解锁 mutex
return ret;
return ret; // 返回错误码
}
void binary_semaphore::destroy_wait_add() {
atomic_add(&destroy_wait, 1);
atomic_add(&destroy_wait, 1); // 销毁等待数 +1
}
void binary_semaphore::destroy_wait_sub() {
atomic_sub(&destroy_wait, 1);
atomic_sub(&destroy_wait, 1); // 销毁等待数 -1
}
/** The parameter timeout should be in second, if it is minus or zero, the function
@ -137,138 +137,139 @@ void binary_semaphore::destroy_wait_sub() {
int binary_semaphore::timed_wait(int timeout) {
int ret = -1;
if (timeout <= 0) {
if (timeout <= 0) { // 若超时时间小于等于 0则与 _wait() 函数一样
ret = wait();
return ret;
}
if (b_flag) {
if (b_flag) { // b_flag 为 1表示已有线程发送信号不需要等待
/* reset b_flag is no one is waitting */
if (waiting_count == 0)
atomic_set(&b_flag, 0);
return 0;
}
LIBCOMM_PTHREAD_MUTEX_LOCK(&mutex);
if (b_flag) {
LIBCOMM_PTHREAD_MUTEX_LOCK(&mutex); // 上锁 mutex
if (b_flag) { // b_flag 为 1表示已有线程发送信号不需要等待
atomic_set(&b_flag, 0);
LIBCOMM_PTHREAD_MUTEX_UNLOCK(&mutex);
ret = 0;
return ret;
}
struct timespec ts;
clock_gettime(CLOCK_REALTIME, &ts);
ts.tv_sec += timeout;
clock_gettime(CLOCK_REALTIME, &ts); // 获取当前时间
ts.tv_sec += timeout; // 计算超时的时间点
ts.tv_nsec = 0;
atomic_add(&waiting_count, 1);
atomic_add(&waiting_count, 1); // 增加等待线程数
ret = pthread_cond_timedwait(&cond, &mutex, &ts);
ret = pthread_cond_timedwait(&cond, &mutex, &ts); // 等待信号,若超过超时时间仍未接收到信号,则返回 ETIMEDOUT
atomic_sub(&waiting_count, 1);
if (b_flag) {
atomic_sub(&waiting_count, 1); // 减少等待线程数
if (b_flag) { // b_flag 为 1表示已有线程发送信号不需要等待
/* reset b_flag is no one is waitting */
if (waiting_count == 0)
atomic_set(&b_flag, 0);
ret = 0;
}
if (b_destroy)
if (b_destroy) // 若 b_destroy 为 1则表示要销毁返回错误码
ret = -1;
LIBCOMM_PTHREAD_MUTEX_UNLOCK(&mutex);
LIBCOMM_PTHREAD_MUTEX_UNLOCK(&mutex); // 解锁 mutex
return ret;
return ret; // 返回错误码
}
int hash_entry::_init() {
return sem.init();
return sem.init(); // 调用 binary_semaphore 对象 sem 的 init() 函数
}
void hash_entry::_destroy() {
sem.destroy(true);
sem.destroy(true); // 调用 binary_semaphore 对象 sem 的 destroy() 函数
}
void hash_entry::_signal() {
sem.post();
sem.post(); // 调用 binary_semaphore 对象 sem 的 post() 函数
}
void hash_entry::_signal_all() {
sem.post_all();
sem.post_all(); // 调用 binary_semaphore 对象 sem 的 post_all() 函数
}
void hash_entry::_wait() {
sem.wait();
sem.wait(); // 调用 binary_semaphore 对象 sem 的 wait() 函数
}
void hash_entry::_hold_destroy() {
sem.destroy_wait_add();
sem.destroy_wait_add(); // 调用 binary_semaphore 对象 sem 的 destroy_wait_add() 函数
}
void hash_entry::_release_destroy() {
sem.destroy_wait_sub();
sem.destroy_wait_sub(); // 调用 binary_semaphore 对象 sem 的 destroy_wait_sub() 函数
}
int hash_entry::_timewait(int timeout) {
return sem.timed_wait(timeout);
return sem.timed_wait(timeout); // 调用 binary_semaphore 对象 sem 的 timed_wait() 函数
}
void node_sock::reset_all() {
ctrl_tcp_sock = -1;
ctrl_tcp_port = -1;
ctrl_tcp_sock_id = 0;
libcomm_reply_sock = -1;
libcomm_reply_sock_id = -1;
ctrl_tcp_sock = -1; // 重置 ctrl_tcp_sock 为 -1 表示未连接
ctrl_tcp_port = -1; // 重置 ctrl_tcp_port 为 -1
ctrl_tcp_sock_id = 0; // 重置 ctrl_tcp_sock_id 为 0
libcomm_reply_sock = -1; // 重置 libcomm_reply_sock 为 -1 表示未连接
libcomm_reply_sock_id = -1; // 重置 libcomm_reply_sock_id 为 -1
errno_t ss_rc = 0;
ss_rc = memset_s(remote_host, HOST_ADDRSTRLEN, 0x0, HOST_ADDRSTRLEN);
ss_rc = memset_s(remote_host, HOST_ADDRSTRLEN, 0x0, HOST_ADDRSTRLEN); // 清空 remote_host 数组
securec_check(ss_rc, "\0", "\0");
ss_rc = memset_s(remote_nodename, NAMEDATALEN, 0x0, NAMEDATALEN);
ss_rc = memset_s(remote_nodename, NAMEDATALEN, 0x0, NAMEDATALEN); // 清空 remote_nodename 数组
securec_check(ss_rc, "\0", "\0");
ss_rc = memset_s(&to_ss, sizeof(struct sockaddr_storage), 0x0, sizeof(struct sockaddr_storage));
ss_rc = memset_s(&to_ss, sizeof(struct sockaddr_storage), 0x0, sizeof(struct sockaddr_storage)); // 清空 to_ss 结构体
securec_check(ss_rc, "\0", "\0");
}
void node_sock::init() {
reset_all();
LIBCOMM_PTHREAD_MUTEX_INIT(&_slock, 0);
LIBCOMM_PTHREAD_MUTEX_INIT(&_tlock, 0);
reset_all(); // 初始化相关成员变量
LIBCOMM_PTHREAD_MUTEX_INIT(&_slock, 0); // 初始化锁 _slock
LIBCOMM_PTHREAD_MUTEX_INIT(&_tlock, 0); // 初始化锁 _tlock
}
void node_sock::clear() {
reset_all();
reset_all(); // 清空相关成员变量
}
void node_sock::destroy() {
clear();
LIBCOMM_PTHREAD_MUTEX_DESTORY(&_slock);
LIBCOMM_PTHREAD_MUTEX_DESTORY(&_tlock);
clear(); // 清空相关成员变量
LIBCOMM_PTHREAD_MUTEX_DESTORY(&_slock); // 销毁锁 _slock
LIBCOMM_PTHREAD_MUTEX_DESTORY(&_tlock); // 销毁锁 _tlock
}
void node_sock::lock() {
LIBCOMM_PTHREAD_MUTEX_LOCK(&_tlock);
LIBCOMM_PTHREAD_MUTEX_LOCK(&_tlock); // 上锁 _tlock
}
void node_sock::unlock() {
LIBCOMM_PTHREAD_MUTEX_UNLOCK(&_tlock);
LIBCOMM_PTHREAD_MUTEX_UNLOCK(&_tlock); // 解锁 _tlock
}
void node_sock::close_socket(int flag) {
lock();
close_socket_nl(flag);
lock();
close_socket_nl(flag); // 关闭 socket
unlock();
}
void node_sock::close_socket_nl(int flag) { // close without lock
void node_sock::close_socket_nl(int flag) { // 关闭 socket但不进行上锁
switch (flag) {
case CTRL_TCP_SOCK:
if (ctrl_tcp_sock >= 0) {
close(ctrl_tcp_sock);
close(ctrl_tcp_sock); // 关闭 ctrl_tcp_sock
ctrl_tcp_sock = -1;
ctrl_tcp_sock_id = -1;
}
break;
default:
break;
}
break;
}
}
void node_sock::set(int val, int flag) {
lock();
@ -276,49 +277,48 @@ void node_sock::set(int val, int flag) {
unlock();
}
void node_sock::set_nl(int val, int flag) { // set without lock
switch (flag) {
case CTRL_TCP_SOCK:
ctrl_tcp_sock = val;
break;
case CTRL_TCP_PORT:
ctrl_tcp_port = val;
break;
case CTRL_TCP_SOCK_ID:
ctrl_tcp_sock_id = val;
break;
default:
break;
void node_sock::set_nl(int val, int flag) {
switch (flag) { // 根据flag的不同选择对应的操作
case CTRL_TCP_SOCK: // 如果flag是CTRL_TCP_SOCK
ctrl_tcp_sock = val; // 将val赋值给ctrl_tcp_sock
break; // 结束该case
case CTRL_TCP_PORT: // 如果flag是CTRL_TCP_PORT
ctrl_tcp_port = val; // 将val赋值给ctrl_tcp_port
break; // 结束该case
case CTRL_TCP_SOCK_ID: // 如果flag是CTRL_TCP_SOCK_ID
ctrl_tcp_sock_id = val; // 将val赋值给ctrl_tcp_sock_id
break; // 结束该case
default: // 如果flag不是上述三种情况
break; // 不执行任何操作
}
}
int node_sock::get(int flag, int* id) {
int val = -1;
lock();
val = get_nl(flag, id);
unlock();
return val;
int val = -1; // 初始化val为-1
lock(); // 加锁
val = get_nl(flag, id); // 调用get_nl函数获取val的值
unlock(); // 解锁
return val; // 返回val的值
}
int node_sock::get_nl(int flag, int* id) const { // get without lock
int val = -1;
switch (flag) {
case CTRL_TCP_SOCK:
val = ctrl_tcp_sock;
if (id != NULL)
*id = ctrl_tcp_sock_id;
break;
case CTRL_TCP_PORT:
val = ctrl_tcp_port;
break;
case CTRL_TCP_SOCK_ID:
val = ctrl_tcp_sock_id;
if (id != NULL)
*id = ctrl_tcp_sock_id;
break;
default:
break;
int node_sock::get_nl(int flag, int* id) const {
int val = -1; // 初始化val为-1
switch (flag) { // 根据flag的不同选择对应的操作
case CTRL_TCP_SOCK: // 如果flag是CTRL_TCP_SOCK
val = ctrl_tcp_sock; // 将ctrl_tcp_sock的值赋给val
if (id != NULL) // 如果id不为空指针
*id = ctrl_tcp_sock_id; // 将ctrl_tcp_sock_id的值赋给id所指向的变量
break; // 结束该case
case CTRL_TCP_PORT: // 如果flag是CTRL_TCP_PORT
val = ctrl_tcp_port; // 将ctrl_tcp_port的值赋给val
break; // 结束该case
case CTRL_TCP_SOCK_ID: // 如果flag是CTRL_TCP_SOCK_ID
val = ctrl_tcp_sock_id; // 将ctrl_tcp_sock_id的值赋给val
if (id != NULL) // 如果id不为空指针
*id = ctrl_tcp_sock_id; // 将ctrl_tcp_sock_id的值赋给id所指向的变量
break; // 结束该case
default: // 如果flag不是上述三种情况
break; // 不执行任何操作
}
return val;
return val; // 返回val的值
}

View File

@ -0,0 +1,135 @@
/*
* 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.
* -------------------------------------------------------------------------
*
* datasource.cpp
* support for data source
*
* IDENTIFICATION
* src/gausskernel/process/datasource/datasource.cpp
*
* -------------------------------------------------------------------------
*//*
* data_source.c
* Support functions for operations on data sources.
*
* This module is responsible for interfacing with the pg_extension_data_source
* system catalog table, and providing a low-level API for working with these
* objects. It is also responsible for interpreting some of the common fields
* that are used throughout the system.
*
*/
#include "postgres.h"
#include "access/htup_details.h"
#include "access/reloptions.h"
#include "catalog/catalog.h"
#include "catalog/dependency.h"
#include "catalog/indexing.h"
#include "catalog/pg_extension_data_source.h"
#include "utils/builtins.h"
#include "utils/fmgroids.h"
#include "utils/syscache.h"
/*
* get_data_source_oid - oid
*
* @param sourcename:
* @param missing_ok: true表示允许false表示不允许
* @return oid
*/
Oid get_data_source_oid(const char* sourcename, bool missing_ok)
{
Oid oid;
oid = GetSysCacheOid1(DATASOURCENAME, CStringGetDatum(sourcename));
if (!OidIsValid(oid) && !missing_ok)
ereport(ERROR,
(errmodule(MOD_EC), errcode(ERRCODE_UNDEFINED_OBJECT), errmsg("source \"%s\" does not exist", sourcename)));
return oid;
}
/**
* GetDataSource -
*
* @param sourceid: oid
* @return
*/
DataSource* GetDataSource(Oid sourceid)
{
Form_pg_extension_data_source sourceform = NULL;
DataSource* source = NULL;
HeapTuple tp = NULL;
Datum datum;
bool isnull = false;
tp = SearchSysCache1(DATASOURCEOID, ObjectIdGetDatum(sourceid));
if (!HeapTupleIsValid(tp))
ereport(ERROR,
(errmodule(MOD_EC),
errcode(ERRCODE_UNDEFINED_OBJECT),
errmsg("cache lookup failed for data source %u", sourceid)));
sourceform = (Form_pg_extension_data_source)GETSTRUCT(tp);
source = (DataSource*)palloc0(sizeof(DataSource));
source->sourceid = sourceid;
source->srcname = pstrdup(NameStr(sourceform->srcname));
source->owner = sourceform->srcowner;
/* Extract source type */
datum = SysCacheGetAttr(DATASOURCEOID, tp, Anum_pg_extension_data_source_srctype, &isnull);
source->srctype = isnull ? NULL : pstrdup(TextDatumGetCString(datum));
/* Extract source version */
datum = SysCacheGetAttr(DATASOURCEOID, tp, Anum_pg_extension_data_source_srcversion, &isnull);
source->srcversion = isnull ? NULL : pstrdup(TextDatumGetCString(datum));
/* Extract the srcoptions */
datum = SysCacheGetAttr(DATASOURCEOID, tp, Anum_pg_extension_data_source_srcoptions, &isnull);
if (isnull)
source->options = NIL;
else
source->options = untransformRelOptions(datum);
ReleaseSysCache(tp);
return source;
}
/**
* GetDataSourceByName -
*
* @param sourcename:
* @param missing_ok: true表示允许false表示不允许
* @return NULL
*/
DataSource* GetDataSourceByName(const char* sourcename, bool missing_ok)
{
Oid sourceid;
if (sourcename == NULL)
return NULL;
sourceid = get_data_source_oid(sourcename, missing_ok);
if (!OidIsValid(sourceid))
return NULL;
return GetDataSource(sourceid);
}

View File

@ -20,29 +20,35 @@
* src/gausskernel/process/datasource/datasource.cpp
*
* -------------------------------------------------------------------------
*//*
* data_source.c
* Support functions for operations on data sources.
*
* This module is responsible for interfacing with the pg_extension_data_source
* system catalog table, and providing a low-level API for working with these
* objects. It is also responsible for interpreting some of the common fields
* that are used throughout the system.
*
*/
#include "postgres.h"
#include "knl/knl_variable.h"
#include "postgres.h"
#include "access/htup_details.h"
#include "access/reloptions.h"
#include "catalog/catalog.h"
#include "catalog/dependency.h"
#include "catalog/indexing.h"
#include "catalog/pg_extension_data_source.h"
#include "datasource/datasource.h"
#include "lib/stringinfo.h"
#include "miscadmin.h"
#include "utils/builtins.h"
#include "utils/memutils.h"
#include "utils/rel.h"
#include "utils/rel_gs.h"
#include "utils/fmgroids.h"
#include "utils/syscache.h"
/*
* get_data_source_oid
* look up the OID by source name
* get_data_source_oid - oid
*
* @IN sourcename: source name
* @IN missing_ok: If missing_ok is false, throw an error if name not found.
* If true, just return InvalidOid.
* @RETURN: oid of the data source.
* @param sourcename:
* @param missing_ok: true表示允许false表示不允许
* @return oid
*/
Oid get_data_source_oid(const char* sourcename, bool missing_ok)
{
@ -56,12 +62,11 @@ Oid get_data_source_oid(const char* sourcename, bool missing_ok)
return oid;
}
/*
* GetDataSource
* look up the data source definition
/**
* GetDataSource -
*
* @IN sourceid: data source oid
* @RETURN: a data source
* @param sourceid: oid
* @return
*/
DataSource* GetDataSource(Oid sourceid)
{
@ -106,13 +111,12 @@ DataSource* GetDataSource(Oid sourceid)
return source;
}
/*
* GetDataSourceByName
* look up the data source definition by name.
/**
* GetDataSourceByName -
*
* @IN sourcename: source name
* @IN missing_ok: missing source name ok
* @RETURN: data source
* @param sourcename:
* @param missing_ok: true表示允许false表示不允许
* @return NULL
*/
DataSource* GetDataSourceByName(const char* sourcename, bool missing_ok)
{
@ -128,3 +132,4 @@ DataSource* GetDataSourceByName(const char* sourcename, bool missing_ok)
return GetDataSource(sourceid);
}

File diff suppressed because it is too large Load Diff

View File

@ -40,6 +40,7 @@
bool GlobalPlanCache::MsgCheck(const SharedInvalidationMessage *msg)
{
// 检查共享缓存清理消息的合法性
if (msg->id >= 0) {
if (msg->cc.id == PROCOID || msg->cc.id == NAMESPACEOID || msg->cc.id == OPEROID || msg->cc.id == AMOPOPID) {
return true;
@ -53,6 +54,7 @@ bool GlobalPlanCache::MsgCheck(const SharedInvalidationMessage *msg)
bool GlobalPlanCache::NeedDropEntryByLocalMsg(CachedPlanSource* plansource, int tot, const int *idx, const SharedInvalidationMessage *msgs)
{
// 检查本地缓存是否需要被清除
Oid database_id = plansource->gpc.key->env.plainenv.database_id;
for (int j = 0; j < tot; j++) {
@ -92,6 +94,7 @@ bool GlobalPlanCache::NeedDropEntryByLocalMsg(CachedPlanSource* plansource, int
void GlobalPlanCache::InvalMsg(const SharedInvalidationMessage *msgs, int n)
{
// 处理共享缓存清理消息
int *idx = (int *)palloc0(n * sizeof(int));
int tot = 0;

File diff suppressed because it is too large Load Diff

View File

@ -68,20 +68,21 @@
static bool run_sql_job(Datum job_name, StringInfoData *buf);
static bool run_procedure_job(Datum job_name, StringInfoData *buf);
static char *run_external_job(Datum job_name);
/*
* @brief delete_by_syscache
* Perform a simple heap delete by searching syscache.
* @param rel Target relation
* @param object_name Delete by key
* @param cache_id Cache ID
*
* @param rel
* @param object_name
* @param cache_id ID
*/
static void delete_by_syscache(Relation rel, const Datum object_name, SysCacheIdentifier cache_id)
{
/* 在系统缓存中查找对象 */
CatCList *tuples = SearchSysCacheList1(cache_id, object_name);
if (tuples == NULL) {
return;
}
/* 循环遍历对象并删除 */
for (int i = 0; i < tuples->n_members; i++) {
HeapTuple tuple = t_thrd.lsc_cxt.FetchTupleFromCatCList(tuples, i);
simple_heap_delete(rel, &tuple->t_self);
@ -91,7 +92,7 @@ static void delete_by_syscache(Relation rel, const Datum object_name, SysCacheId
/*
* @brief delete_from_attribute
* Delete from gs_job_attribute.
* gs_job_attribute表中删除
* @param object_name
*/
void delete_from_attribute(const Datum object_name)
@ -103,7 +104,7 @@ void delete_from_attribute(const Datum object_name)
/*
* @brief delete_from_argument
* Delete from gs_job_argument.
* gs_job_argument表中删除
* @param job_name
*/
void delete_from_argument(const Datum object_name)
@ -115,7 +116,7 @@ void delete_from_argument(const Datum object_name)
/*
* @brief delete_from_job
* Delete from pg_job.
* pg_job表中删除
* @param job_name
*/
void delete_from_job(const Datum job_name)
@ -130,7 +131,7 @@ void delete_from_job(const Datum job_name)
/*
* @brief delete_from_job_proc
* Delete from pg_job_proc.
* pg_job_proc表中删除
* @param job_name
*/
void delete_from_job_proc(const Datum job_name)
@ -142,34 +143,35 @@ void delete_from_job_proc(const Datum job_name)
}
heap_close(rel, NoLock);
}
HeapTuple search_from_pg_job(Relation pg_job_rel, Datum job_name)
{
ScanKeyInfo scan_key_info1;
scan_key_info1.attribute_value = job_name;
scan_key_info1.attribute_number = Anum_pg_job_job_name;
scan_key_info1.procedure = F_TEXTEQ;
scan_key_info1.attribute_value = job_name; // 设置扫描键的属性值为job_name
scan_key_info1.attribute_number = Anum_pg_job_job_name; // 设置扫描键的属性编号为Anum_pg_job_job_name
scan_key_info1.procedure = F_TEXTEQ; // 设置扫描键的比较函数为F_TEXTEQ
ScanKeyInfo scan_key_info2;
scan_key_info2.attribute_value = PointerGetDatum(u_sess->proc_cxt.MyProcPort->database_name);
scan_key_info2.attribute_number = Anum_pg_job_dbname;
scan_key_info2.procedure = F_NAMEEQ;
scan_key_info2.attribute_value = PointerGetDatum(u_sess->proc_cxt.MyProcPort->database_name); // 设置扫描键的属性值为当前数据库名称
scan_key_info2.attribute_number = Anum_pg_job_dbname; // 设置扫描键的属性编号为Anum_pg_job_dbname
scan_key_info2.procedure = F_NAMEEQ; // 设置扫描键的比较函数为F_NAMEEQ
List *tuples = search_by_sysscan_2(pg_job_rel, &scan_key_info1, &scan_key_info2);
List *tuples = search_by_sysscan_2(pg_job_rel, &scan_key_info1, &scan_key_info2); // 在pg_job_rel上执行扫描操作并返回符合条件的元组列表
if (tuples == NIL) {
return NULL;
}
Assert(list_length(tuples) == 1);
Assert(list_length(tuples) == 1); // 断言元组列表长度为1
if (list_length(tuples) != 1) {
ereport(ERROR, (errmodule(MOD_JOB), errcode(ERRCODE_UNDEFINED_OBJECT),
errmsg("find %d tuples match job_name %s in system table pg_job.", list_length(tuples),
TextDatumGetCString(job_name)),
errdetail("N/A"), errcause("job name is not exist"), erraction("Please check job_name")));
}
HeapTuple tuple = (HeapTuple)linitial(tuples);
list_free_ext(tuples);
return tuple;
HeapTuple tuple = (HeapTuple)linitial(tuples); // 获取元组列表中的第一个元组
list_free_ext(tuples); // 释放元组列表的内存
return tuple; // 返回元组
}
/*
* @brief update_pg_job
* Update pg_job.
@ -277,12 +279,18 @@ List *search_related_attribute(Relation gs_job_attribute_rel, Datum attribute_na
/*
* @brief disable_related_jobs_force
*//*
* @brief disable_related_jobs_force
*
* @param gs_job_attribute_rel
* @param disable_job_names
*/
static void disable_related_jobs_force(Relation gs_job_attribute_rel, List *disable_job_names)
{
ListCell *lc = NULL;
foreach (lc, disable_job_names) {
Datum job_name = PointerGetDatum(lfirst(lc));
// 禁用指定名称的作业
update_pg_job(job_name, Anum_pg_job_enable, BoolGetDatum(false));
}
}
@ -291,8 +299,9 @@ static void disable_related_jobs_force(Relation gs_job_attribute_rel, List *disa
* @brief reset_job_class
*
* @param gs_job_attribute_rel
* @param disable_job_names
* @param attribute_name
* @param disable_job_names job_class
* @param attribute_name job_class
* @param force
*/
static void reset_job_class(Relation gs_job_attribute_rel, List *disable_job_names, Datum attribute_name, bool force)
{
@ -306,10 +315,12 @@ static void reset_job_class(Relation gs_job_attribute_rel, List *disable_job_nam
ListCell *lc = NULL;
foreach (lc, disable_job_names) {
Datum job_name = PointerGetDatum(lfirst(lc));
// 将指定作业的 attribute_name 属性重置为默认 job_class
update_attribute(job_name, attribute_name, CStringGetTextDatum("DEFAULT_JOB_CLASS"));
}
}
/*
* @brief search_related_jobs
* search all related jobs.
@ -318,6 +329,7 @@ static void reset_job_class(Relation gs_job_attribute_rel, List *disable_job_nam
* @param force
* @return List*
*/
//search_related_jobs 函数:用于查找所有与给定对象和属性名相关的任务,并返回任务名称列表。
static List *search_related_jobs(Relation gs_job_attribute_rel, Datum object_name, Datum attribute_name, bool force)
{
List *tuples = search_related_attribute(gs_job_attribute_rel, attribute_name, object_name);
@ -352,6 +364,7 @@ static List *search_related_jobs(Relation gs_job_attribute_rel, Datum object_nam
* Drop inline program if exists.
* @param job_name
*/
//drop_inline_program 函数:删除指定任务的内联程序(如果存在)及其相关信息。
void drop_inline_program(const Datum job_name)
{
Datum attribute_name = CStringGetTextDatum("program_name");
@ -380,6 +393,7 @@ void drop_inline_program(const Datum job_name)
* @param force
* @param simple when set to true, do not disable relatied objects
*/
//drop_single_object_name 函数:删除指定的对象,并禁用所有相关对象。
static void drop_single_object_name(Datum object_name, const char *object_type, bool force)
{
check_object_type_matched(object_name, object_type);
@ -417,6 +431,7 @@ static void drop_single_object_name(Datum object_name, const char *object_type,
* Note:
* Dropping a job class requires the MANAGE SCHEDULER system privilege.
*/
//此函数用于删除单个作业类。
void drop_single_job_class_internal(PG_FUNCTION_ARGS)
{
check_object_is_visible(PG_GETARG_DATUM(0), false);
@ -433,6 +448,7 @@ void drop_single_job_class_internal(PG_FUNCTION_ARGS)
* @brief drop_single_program_internal
* Drop a single program.
*/
//此函数用于删除单个程序。
void drop_single_program_internal(PG_FUNCTION_ARGS)
{
check_object_is_visible(PG_GETARG_DATUM(0), false);
@ -459,6 +475,7 @@ void drop_single_program_internal(PG_FUNCTION_ARGS)
* @brief drop_single_schedule_internal
* Drop a single schedule.
*/
//此函数用于删除单个调度。
void drop_single_schedule_internal(PG_FUNCTION_ARGS)
{
check_object_is_visible(PG_GETARG_DATUM(0), false);
@ -471,6 +488,7 @@ void drop_single_schedule_internal(PG_FUNCTION_ARGS)
* @brief drop_credential_internal
* Drop a single credential.
*/
//此函数用于删除单个凭据。
void drop_credential_internal(PG_FUNCTION_ARGS)
{
if (!superuser()) {
@ -1725,4 +1743,4 @@ void remove_scheduler_objects_from_owner(const char *user_str)
}
list_free_deep(drop_object_names);
list_free_deep(drop_object_types);
}
}

909
src/gausskernel/process/job/job_scheduler.cpp Executable file → Normal file

File diff suppressed because it is too large Load Diff

17
src/gausskernel/process/job/job_worker.cpp Executable file → Normal file
View File

@ -93,6 +93,7 @@ static void FreeJobWorkerInfo(int code, Datum arg);
*
* Returns: bool
*/
//此函数用于判断当前线程是否为作业工作进程。如果是作业工作进程则返回true否则返回false。
bool IsJobWorkerProcess(void)
{
return t_thrd.role == JOB_WORKER;
@ -103,6 +104,7 @@ bool IsJobWorkerProcess(void)
*
* Returns: void
*/
//此函数用于为作业工作进程注册信号处理程序。
static void SetupSignalHook(void)
{
(void)gspqsignal(SIGHUP, SIG_IGN);
@ -122,6 +124,7 @@ static void SetupSignalHook(void)
*
* Returns: void
*/
//此函数用于在线程退出时释放作业工作进程的信息。
static void FreeJobWorkerInfo(int code, Datum arg)
{
if (t_thrd.job_cxt.MyWorkerInfo != NULL) {
@ -148,6 +151,20 @@ static void FreeJobWorkerInfo(int code, Datum arg)
* @in argv: detail info for each args.
* Returns: void
*/
/*
线
PgBackendStatus和pg_stat_activity
退
*/
void JobExecuteWorkerMain()
{
sigjmp_buf local_sigjmp_buf;

543
src/gausskernel/process/main/main.cpp Executable file → Normal file
View File

@ -76,228 +76,245 @@ extern int encrypte_main(int argc, char* const argv[]);
*/
int main(int argc, char* argv[])
{
char* mmap_env = NULL;
syscall_lock_init();
char* mmap_env = NULL;
syscall_lock_init();
// 从环境变量中获取GAUSS_MMAP_THRESHOLD的值并设置mmap_threshold变量
mmap_env = gs_getenv_r("GAUSS_MMAP_THRESHOLD");
if (mmap_env != NULL) {
check_backend_env(mmap_env);
mmap_threshold = (size_t)atol(mmap_env);
}
// 初始化KNL实例
knl_instance_init();
// 创建增量检查点上下文
g_instance.increCheckPoint_context = AllocSetContextCreate(
INSTANCE_GET_MEM_CXT_GROUP(MEMORY_CONTEXT_STORAGE),
"IncreCheckPointContext",
ALLOCSET_DEFAULT_MINSIZE,
ALLOCSET_DEFAULT_INITSIZE,
ALLOCSET_DEFAULT_MAXSIZE,
SHARED_CONTEXT);
// 创建备机帐号上下文
g_instance.account_context = AllocSetContextCreate(g_instance.instance_context,
"StandbyAccontContext",
ALLOCSET_DEFAULT_MINSIZE,
ALLOCSET_DEFAULT_INITSIZE,
ALLOCSET_DEFAULT_MAXSIZE,
SHARED_CONTEXT);
// 创建通信全局内存上下文
g_instance.comm_cxt.comm_global_mem_cxt = AllocSetContextCreate(g_instance.instance_context,
"CommunnicatorGlobalMemoryContext",
ALLOCSET_DEFAULT_MINSIZE,
ALLOCSET_DEFAULT_INITSIZE,
ALLOCSET_DEFAULT_MAXSIZE,
SHARED_CONTEXT);
// 创建内置过程内存上下文
g_instance.builtin_proc_context = AllocSetContextCreate(g_instance.instance_context,
"builtin_procGlobalMemoryContext",
ALLOCSET_DEFAULT_MINSIZE,
ALLOCSET_DEFAULT_INITSIZE,
ALLOCSET_DEFAULT_MAXSIZE,
SHARED_CONTEXT);
/*
* Fire up essential subsystems: error and memory management
*
* Code after this point is allowed to use elog/ereport, though
* localization of messages may not work right away, and messages won't go
* anywhere but stderr until GUC settings get loaded.
*/
// 初始化内存上下文
MemoryContextInit();
// 设置全局变量PmTopMemoryContext为顶层内存上下文
PmTopMemoryContext = t_thrd.top_mem_cxt;
// 初始化线程
knl_thread_init(MASTER_THREAD);
// 创建虚拟会话
t_thrd.fake_session = create_session_context(t_thrd.top_mem_cxt, 0);
t_thrd.fake_session->status = KNL_SESS_FAKE;
// 将当前会话设置为虚拟会话
u_sess = t_thrd.fake_session;
// 设置SelfMemoryContext为默认内存上下文组
SelfMemoryContext = THREAD_GET_MEM_CXT_GROUP(MEMORY_CONTEXT_DEFAULT);
// 切换到默认内存上下文组
MemoryContextSwitchTo(THREAD_GET_MEM_CXT_GROUP(MEMORY_CONTEXT_DEFAULT));
// 获取程序名称
progname = get_progname(argv[0]);
mmap_env = gs_getenv_r("GAUSS_MMAP_THRESHOLD");
if (mmap_env != NULL) {
check_backend_env(mmap_env);
mmap_threshold = (size_t)atol(mmap_env);
}
knl_instance_init();
g_instance.increCheckPoint_context = AllocSetContextCreate(
INSTANCE_GET_MEM_CXT_GROUP(MEMORY_CONTEXT_STORAGE),
"IncreCheckPointContext",
ALLOCSET_DEFAULT_MINSIZE,
ALLOCSET_DEFAULT_INITSIZE,
ALLOCSET_DEFAULT_MAXSIZE,
SHARED_CONTEXT);
g_instance.account_context = AllocSetContextCreate(g_instance.instance_context,
"StandbyAccontContext",
ALLOCSET_DEFAULT_MINSIZE,
ALLOCSET_DEFAULT_INITSIZE,
ALLOCSET_DEFAULT_MAXSIZE,
SHARED_CONTEXT);
g_instance.comm_cxt.comm_global_mem_cxt = AllocSetContextCreate(g_instance.instance_context,
"CommunnicatorGlobalMemoryContext",
ALLOCSET_DEFAULT_MINSIZE,
ALLOCSET_DEFAULT_INITSIZE,
ALLOCSET_DEFAULT_MAXSIZE,
SHARED_CONTEXT);
g_instance.builtin_proc_context = AllocSetContextCreate(g_instance.instance_context,
"builtin_procGlobalMemoryContext",
ALLOCSET_DEFAULT_MINSIZE,
ALLOCSET_DEFAULT_INITSIZE,
ALLOCSET_DEFAULT_MAXSIZE,
SHARED_CONTEXT);
/*
* Fire up essential subsystems: error and memory management
*
* Code after this point is allowed to use elog/ereport, though
* localization of messages may not work right away, and messages won't go
* anywhere but stderr until GUC settings get loaded.
*/
MemoryContextInit();
PmTopMemoryContext = t_thrd.top_mem_cxt;
knl_thread_init(MASTER_THREAD);
t_thrd.fake_session = create_session_context(t_thrd.top_mem_cxt, 0);
t_thrd.fake_session->status = KNL_SESS_FAKE;
u_sess = t_thrd.fake_session;
SelfMemoryContext = THREAD_GET_MEM_CXT_GROUP(MEMORY_CONTEXT_DEFAULT);
MemoryContextSwitchTo(THREAD_GET_MEM_CXT_GROUP(MEMORY_CONTEXT_DEFAULT));
progname = get_progname(argv[0]);
/*
* Platform-specific startup hacks
*/
startup_hacks(progname);
* Platform-specific startup hacks
*/
startup_hacks(progname);
/* if gaussdb's name is gs_encrypt, so run in encrypte_main() */
if (!strcmp(progname, "gs_encrypt")) {
return encrypte_main(argc, argv);
}
// 初始化plog全局内存
init_plog_global_mem();
/*
* Remember the physical location of the initially given argv[] array for
* possible use by ps display. On some platforms, the argv[] storage must
* be overwritten in order to set the process title for ps. In such cases,
* save_ps_display_args makes and returns a new copy of the argv[] array.
*
* save_ps_display_args may also move the environment strings to make
* extra room. Therefore this should be done as early as possible during
* startup, to avoid entanglements with code that might save a getenv()
* result pointer.
*/
argv = save_ps_display_args(argc, argv);
/*
* If supported on the current platform, set up a handler to be called if
* the backend/postmaster crashes with a fatal signal or exception.
*/
#if defined(WIN32) && defined(HAVE_MINIDUMP_TYPE)
pgwin32_install_crashdump_handler();
#endif
/*
* Set up locale information from environment. Note that LC_CTYPE and
* LC_COLLATE will be overridden later from pg_control if we are in an
* already-initialized database. We set them here so that they will be
* available to fill pg_control during initdb. LC_MESSAGES will get set
* later during GUC option processing, but we set it here to allow startup
* error messages to be localized.
*/
set_pglocale_pgservice(argv[0], PG_TEXTDOMAIN("gaussdb"));
#ifdef WIN32
/*
* Windows uses codepages rather than the environment, so we work around
* that by querying the environment explicitly first for LC_COLLATE and
* LC_CTYPE. We have to do this because initdb passes those values in the
* environment. If there is nothing there we fall back on the codepage.
*/
{
char* env_locale = NULL;
if ((env_locale = gs_getenv_r("LC_COLLATE")) != NULL) {
check_backend_env(env_locale);
pg_perm_setlocale(LC_COLLATE, env_locale);
} else
pg_perm_setlocale(LC_COLLATE, "");
if ((env_locale = gs_getenv_r("LC_CTYPE")) != NULL) {
check_backend_env(env_locale);
pg_perm_setlocale(LC_CTYPE, env_locale);
} else
pg_perm_setlocale(LC_CTYPE, "");
}
#else
pg_perm_setlocale(LC_COLLATE, "");
pg_perm_setlocale(LC_CTYPE, "");
#endif
/* if gaussdb's name is gs_encrypt, so run in encrypte_main() */
if (!strcmp(progname, "gs_encrypt")) {
return encrypte_main(argc, argv);
}
init_plog_global_mem();
/*
* Remember the physical location of the initially given argv[] array for
* possible use by ps display. On some platforms, the argv[] storage must
* be overwritten in order to set the process title for ps. In such cases
* save_ps_display_args makes and returns a new copy of the argv[] array.
*
* save_ps_display_args may also move the environment strings to make
* extra room. Therefore this should be done as early as possible during
* startup, to avoid entanglements with code that might save a getenv()
* result pointer.
*/
argv = save_ps_display_args(argc, argv);
/*
* If supported on the current platform, set up a handler to be called if
* the backend/postmaster crashes with a fatal signal or exception.
*/
#if defined(WIN32) && defined(HAVE_MINIDUMP_TYPE)
pgwin32_install_crashdump_handler();
#endif
/*
* Set up locale information from environment. Note that LC_CTYPE and
* LC_COLLATE will be overridden later from pg_control if we are in an
* already-initialized database. We set them here so that they will be
* available to fill pg_control during initdb. LC_MESSAGES will get set
* later during GUC option processing, but we set it here to allow startup
* error messages to be localized.
*/
set_pglocale_pgservice(argv[0], PG_TEXTDOMAIN("gaussdb"));
#ifdef WIN32
/*
* Windows uses codepages rather than the environment, so we work around
* that by querying the environment explicitly first for LC_COLLATE and
* LC_CTYPE. We have to do this because initdb passes those values in the
* environment. If there is nothing there we fall back on the codepage.
*/
{
char* env_locale = NULL;
if ((env_locale = gs_getenv_r("LC_COLLATE")) != NULL) {
check_backend_env(env_locale);
pg_perm_setlocale(LC_COLLATE, env_locale);
} else
pg_perm_setlocale(LC_COLLATE, "");
if ((env_locale = gs_getenv_r("LC_CTYPE")) != NULL) {
check_backend_env(env_locale);
pg_perm_setlocale(LC_CTYPE, env_locale);
} else
pg_perm_setlocale(LC_CTYPE, "");
}
#else
pg_perm_setlocale(LC_COLLATE, "");
pg_perm_setlocale(LC_CTYPE, "");
#endif
/*
* We keep these set to "C" always, except transiently in pg_locale.c; see
* that file for explanations.
*/
pg_perm_setlocale(LC_MONETARY, "C");
pg_perm_setlocale(LC_NUMERIC, "C");
pg_perm_setlocale(LC_TIME, "C");
/*
* Now that we have absorbed as much as we wish to from the locale
* environment, remove any LC_ALL setting, so that the environment
* variables installed by pg_perm_setlocale have force.
*/
(void)unsetenv("LC_ALL");
/*
* Catch standard options before doing much else
*/
if (argc > 1) {
if (strcmp(argv[1], "--help") == 0 || strcmp(argv[1], "-?") == 0) {
help(progname);
exit(0);
}
if (strcmp(argv[1], "--version") == 0 || strcmp(argv[1], "-V") == 0) {
puts("gaussdb " DEF_GS_VERSION);
exit(0);
}
}
/*
* Make sure we are not running as root.
*/
check_root(progname);
/*
* Dispatch to one of various subprograms depending on first argument.
*/
#ifdef WIN32
/*
* Start our win32 signal implementation
*
* SubPostmasterMain() will do this for itself, but the remaining modes
* need it here
*/
pgwin32_signal_initialize();
#endif
t_thrd.mem_cxt.gs_signal_mem_cxt = AllocSetContextCreate(
t_thrd.top_mem_cxt, "gs_signal", ALLOCSET_DEFAULT_MINSIZE, ALLOCSET_DEFAULT_INITSIZE, ALLOCSET_DEFAULT_MAXSIZE);
if (NULL == t_thrd.mem_cxt.gs_signal_mem_cxt) {
ereport(LOG, (errmsg("could not start a new thread, because of no enough system resource. ")));
proc_exit(1);
}
/*
* @BuiltinFunc
* Create a global BuiltinFunc object shared among threads
*/
if (g_sorted_funcs[0] == NULL) {
initBuiltinFuncs();
}
bool isBoot = (argc > 1 && strcmp(argv[1], "--boot") == 0);
if (isBoot) {
IsInitdb = true;
gs_signal_monitor_startup();
gs_signal_slots_init(1);
(void)gs_signal_unblock_sigusr2();
gs_signal_startup_siginfo("AuxiliaryProcessMain");
BootStrapProcessMain(argc, argv); /* does not return */
}
if (argc > 1 && strcmp(argv[1], "--describe-config") == 0)
exit(GucInfoMain());
if (argc > 1 && strcmp(argv[1], "--single") == 0) {
IsInitdb = true;
gs_signal_monitor_startup();
gs_signal_slots_init(1);
(void)gs_signal_unblock_sigusr2();
gs_signal_startup_siginfo("PostgresMain");
exit(PostgresMain(argc, argv, NULL, get_current_username(progname)));
}
exit(PostmasterMain(argc, argv));
}
/*
* We keep these set to "C" always, except transiently in pg_locale.c; see
* that file for explanations.
*/
pg_perm_setlocale(LC_MONETARY, "C"); // 将货币格式化设置为"C"语言环境
pg_perm_setlocale(LC_NUMERIC, "C"); // 将数字格式化设置为"C"语言环境
pg_perm_setlocale(LC_TIME, "C"); // 将时间格式化设置为"C"语言环境
/*
* Now that we have absorbed as much as we wish to from the locale
* environment, remove any LC_ALL setting, so that the environment
* variables installed by pg_perm_setlocale have force.
*/
(void)unsetenv("LC_ALL"); // 移除LC_ALL设置以确保pg_perm_setlocale设置的环境变量生效
/*
* Catch standard options before doing much else
*/
if (argc > 1) {
if (strcmp(argv[1], "--help") == 0 || strcmp(argv[1], "-?") == 0) {
help(progname); // 显示帮助信息
exit(0);
}
if (strcmp(argv[1], "--version") == 0 || strcmp(argv[1], "-V") == 0) {
puts("gaussdb " DEF_GS_VERSION); // 显示版本号
exit(0);
}
}
/*
* Make sure we are not running as root.
*/
check_root(progname); // 检查是否以root用户身份运行
/*
* Dispatch to one of various subprograms depending on first argument.
*/
#ifdef WIN32
/*
* Start our win32 signal implementation
*
* SubPostmasterMain() will do this for itself, but the remaining modes
* need it here
*/
pgwin32_signal_initialize(); // 在Windows平台上启动信号处理
#endif
t_thrd.mem_cxt.gs_signal_mem_cxt = AllocSetContextCreate(
t_thrd.top_mem_cxt, "gs_signal", ALLOCSET_DEFAULT_MINSIZE, ALLOCSET_DEFAULT_INITSIZE, ALLOCSET_DEFAULT_MAXSIZE);
if (NULL == t_thrd.mem_cxt.gs_signal_mem_cxt) {
ereport(LOG, (errmsg("could not start a new thread, because of no enough system resource. ")));
proc_exit(1);
}
/*
* @BuiltinFunc
* Create a global BuiltinFunc object shared among threads
*/
if (g_sorted_funcs[0] == NULL) {
initBuiltinFuncs(); // 初始化内置函数相关的全局变量
}
bool isBoot = (argc > 1 && strcmp(argv[1], "--boot") == 0);
if (isBoot) {
IsInitdb = true;
gs_signal_monitor_startup(); // 启动信号监控工作线程
gs_signal_slots_init(1); // 初始化信号插槽
(void)gs_signal_unblock_sigusr2(); // 解除SIGUSR2信号的阻塞
gs_signal_startup_siginfo("AuxiliaryProcessMain"); // 记录启动信息
BootStrapProcessMain(argc, argv); /* does not return */
}
if (argc > 1 && strcmp(argv[1], "--describe-config") == 0)
exit(GucInfoMain()); // 打印GUC参数信息
if (argc > 1 && strcmp(argv[1], "--single") == 0) {
IsInitdb = true;
gs_signal_monitor_startup(); // 启动信号监控工作线程
gs_signal_slots_init(1); // 初始化信号插槽
(void)gs_signal_unblock_sigusr2(); // 解除SIGUSR2信号的阻塞
gs_signal_startup_siginfo("PostgresMain"); // 记录启动信息
exit(PostgresMain(argc, argv, NULL, get_current_username(progname))); // 进入PostgreSQL主循环
}
exit(PostmasterMain(argc, argv)); // 进入Postmaster主循环
/*
* Place platform-specific startup hacks here. This is the right
@ -496,43 +513,55 @@ static void check_root(const char* progname)
}
#endif /* WIN32 */
}
/**
* get_current_username -
* @progname:
*
*
*/
static char* get_current_username(const char* progname)
{
#ifndef WIN32 // 非Windows平台代码
struct passwd* pw = NULL;
char* pRet = NULL;
(void)syscalllockAcquire(&getpwuid_lock); // 获取线程锁
pw = getpwuid(geteuid()); // 获取与实际用户ID关联的密码记录
if (pw == NULL) { // 如果无法获取则报错
(void)syscalllockRelease(&getpwuid_lock);
write_stderr("%s: invalid effective UID: %d\n", progname, (int)geteuid());
exit(1);
}
/* Allocate new memory because later getpwuid() calls can overwrite it. */
pRet = MemoryContextStrdup(SESS_GET_MEM_CXT_GROUP(MEMORY_CONTEXT_CBB), pw->pw_name); // 分配新内存来储存用户名,并返回该内存地址
(void)syscalllockRelease(&getpwuid_lock); // 释放线程锁
return pRet; // 返回用户名
#else // Windows平台代码
unsigned long namesize = 256 /* UNLEN */ + 1;
char* name = NULL;
name = MemoryContextAlloc(
SESS_GET_MEM_CXT_GROUP(MEMORY_CONTEXT_CBB), namesize); // 分配内存来储存用户名,返回该内存地址
if (!GetUserName(name, &namesize)) { // 获取当前用户的用户名
write_stderr("%s: could not determine user name (GetUserName failed)\n", progname);
exit(1);
}
return name; // 返回用户名
#endif
}
/**
* syscall_lock_init -
*
* getenv线
*/
static void syscall_lock_init(void)
{
syscalllockInit(&getpwuid_lock); // 初始化获取用户ID对应密码记录的线程锁
syscalllockInit(&env_lock); // 初始化 getenv 的线程锁
syscalllockInit(&dlerror_lock); // 初始化 dlerror 的线程锁
syscalllockInit(&kerberos_conn_lock); // 初始化 Kerberos 连接相关的线程锁
syscalllockInit(&read_cipher_lock); // 初始化加密算法相关的线程锁
}
static char* get_current_username(const char* progname)
{
#ifndef WIN32
struct passwd* pw = NULL;
char* pRet = NULL;
(void)syscalllockAcquire(&getpwuid_lock);
pw = getpwuid(geteuid());
if (pw == NULL) {
(void)syscalllockRelease(&getpwuid_lock);
write_stderr("%s: invalid effective UID: %d\n", progname, (int)geteuid());
exit(1);
}
/* Allocate new memory because later getpwuid() calls can overwrite it. */
pRet = MemoryContextStrdup(SESS_GET_MEM_CXT_GROUP(MEMORY_CONTEXT_CBB), pw->pw_name);
(void)syscalllockRelease(&getpwuid_lock);
return pRet;
#else
unsigned long namesize = 256 /* UNLEN */ + 1;
char* name = NULL;
name = MemoryContextAlloc(SESS_GET_MEM_CXT_GROUP(MEMORY_CONTEXT_CBB), namesize);
if (!GetUserName(name, &namesize)) {
write_stderr("%s: could not determine user name (GetUserName failed)\n", progname);
exit(1);
}
return name;
#endif
}
static void syscall_lock_init(void)
{
syscalllockInit(&getpwuid_lock);
syscalllockInit(&env_lock);
syscalllockInit(&dlerror_lock);
syscalllockInit(&kerberos_conn_lock);
syscalllockInit(&read_cipher_lock);
}

View File

@ -1,27 +1,4 @@
/*
* 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.
* -------------------------------------------------------------------------
*
* alarmchecker.cpp
*
* openGauss Alarm checker thread Implementation
*
* IDENTIFICATION
* src/gausskernel/process/postmaster/alarmchecker.cpp
*
* -------------------------------------------------------------------------
*/
//这些是各种头文件的引用包含了一些系统库、PostgreSQL内部模块和自定义的模块
#include "postgres.h"
#include "knl/knl_variable.h"
@ -46,18 +23,15 @@
#include "postmaster/alarmchecker.h"
#include "gssignal/gs_signal.h"
#include "replication/walsender.h"
//定义一些全局变量
int g_alarmReportInterval;//报警上报的时间间隔
char g_alarmComponentPath[MAXPGPATH];// 报警组件的路径
int g_alarmReportMaxCount;//报警上报的最大次数
// declare the global variable of alarm module
int g_alarmReportInterval;
char g_alarmComponentPath[MAXPGPATH];
int g_alarmReportMaxCount;
/* seconds, interval of alarm check loop. */
static const int AlarmCheckInterval = 1;
bool enable_alarm = false;
static const int AlarmCheckInterval = 1;//定义了一个静态常量 AlarmCheckInterval值为1表示报警检查的时间间隔单位
bool enable_alarm = false;//定义并初始化了一个bool型变量 enable_alarm初始值为 false表示是否启用报警功能。
//定义了静态变量 DataInstAlarmList 和 DataInstAlarmListSize用于存储报警项的列表和列表大小
static Alarm* DataInstAlarmList = NULL;
static int DataInstAlarmListSize = 0;
AlarmCheckResult DataOrRedoDirNotExistChecker(Alarm* alarm, AlarmAdditionalParam* additionalParam);
@ -70,15 +44,17 @@ static void acSigquitHandler(SIGNAL_ARGS);
extern AlarmCheckResult DataInstArchChecker(Alarm* alarm, AlarmAdditionalParam* additionalParam);
extern AlarmCheckResult ConnAuthMethodChecker(Alarm* alarm, AlarmAdditionalParam* additionalParam);
extern AlarmCheckResult DataInstConnToGTMChecker(Alarm* alarm, AlarmAdditionalParam* additionalParam);
//用于初始化报警项列表
void DataInstAlarmItemInitialize(void)
{
DataInstAlarmListSize = 6;
DataInstAlarmList = (Alarm*)AlarmAlloc(sizeof(Alarm) * DataInstAlarmListSize);
DataInstAlarmListSize = 6;//设置列表大小为6
DataInstAlarmList = (Alarm*)AlarmAlloc(sizeof(Alarm) * DataInstAlarmListSize);//给 DataInstAlarmList分配内存
//如果分配失败
if (NULL == DataInstAlarmList) {
AlarmLog(ALM_LOG, "Out of memory: DataInstAlarmItemInitialize failed.");
AlarmLog(ALM_LOG, "Out of memory: DataInstAlarmItemInitialize failed.");//记录错误日志并退出程序
exit(1);
}
//调用函数AlarmItemInitialize对每个报警项进行初始化每个报警项由一个Alarm结构体表示包含报警项的类型、报警状态和报警检查函数
// ALM_AI_MissingDataInstDataOrRedoDir
AlarmItemInitialize(
&(DataInstAlarmList[0]), ALM_AI_MissingDataInstDataOrRedoDir, ALM_AS_Normal, DataOrRedoDirNotExistChecker);
@ -96,50 +72,38 @@ void DataInstAlarmItemInitialize(void)
AlarmItemInitialize(
&(DataInstAlarmList[5]), ALM_AI_AbnormalDataInstConnToGTM, ALM_AS_Normal, DataInstConnToGTMChecker);
}
//用于启动报警检查进程
ThreadId startAlarmChecker(void)
{
if (!IsPostmasterEnvironment || !enable_alarm) {
//看是否处于Postmaster环境并且是否启用了报警功能
if (!IsPostmasterEnvironment || !enable_alarm) {//如果不满足条件则返回0。
return 0;
}
//否则调用initialize_util_thread函数来启动报警检查器线程。
return initialize_util_thread(ALARMCHECK);
}
//定义了一个名为AlarmCheckerMain的静态函数。
//NON_EXEC_STATIC用于指定函数不会被直接执行而是作为子进程在PostgreSQL中运行。
NON_EXEC_STATIC void AlarmCheckerMain()
{
IsUnderPostmaster = true;//设置变量IsUnderPostmaster为true表示当前进程是一个后台进程
/* we are a postmaster subprocess now */
IsUnderPostmaster = true;
/* reset t_thrd.proc_cxt.MyProcPid */
t_thrd.proc_cxt.MyProcPid = gs_thread_self();
/* record Start Time for logging */
t_thrd.proc_cxt.MyStartTime = time(NULL);
/* reord my name */
t_thrd.proc_cxt.MyProgName = "AlarmChecker";
/* Identify myself via ps */
init_ps_display("AlarmChecker", "", "", "");
t_thrd.proc_cxt.MyProcPid = gs_thread_self();//重置t_thrd.proc_cxt.MyProcPid为当前线程
t_thrd.proc_cxt.MyStartTime = time(NULL);//记录当前时间为t_thrd.proc_cxt.MyStartTime
t_thrd.proc_cxt.MyProgName = "AlarmChecker";//将当前进程名设置为AlarmChecker
init_ps_display("AlarmChecker", "", "", "");//调用函数init_ps_display来显示初始化进程状态
//调用函数AlarmLog记录日志表示报警检查程序已经启动
AlarmLog(ALM_LOG, "alarm checker started.");
//调用函数InitializeLatchSupport来初始化latch支持。
InitializeLatchSupport(); /* needed for latch waits */
/* Initialize private latch for use by signal handlers */
//初始化一个latch对象用于处理信号处理程序中的同步等待。
InitLatch(&t_thrd.alarm_cxt.AlarmCheckerLatch);
/*
* Properly accept or ignore signals the postmaster might send us
*
* Note: we deliberately ignore SIGTERM, because during a standard Unix
* system shutdown cycle, init will SIGTERM all processes at once. We
* want to wait for the backends to exit, whereupon the postmaster will
* tell us it's okay to shut down (via SIGUSR2).
*/
(void)gspqsignal(SIGHUP, acSighupHandler); /* set flag to read config file */
//使用gspqsignal函数设置了一些信号的处理行为如SIGHUP、SIGINT、SIGTERM等。
(void)gspqsignal(SIGHUP, acSighupHandler);
(void)gspqsignal(SIGINT, SIG_IGN);
(void)gspqsignal(SIGTERM, SIG_IGN);
(void)gspqsignal(SIGQUIT, acSigquitHandler);
@ -147,160 +111,141 @@ NON_EXEC_STATIC void AlarmCheckerMain()
(void)gspqsignal(SIGPIPE, SIG_IGN);
(void)gspqsignal(SIGUSR1, SIG_IGN);
(void)gspqsignal(SIGUSR2, SIG_IGN);
//对于某些信号通过SIG_IGN忽略而对于其他信号通过SIG_DFL恢复为默认行为。
/*
* Reset some signals that are accepted by postmaster but not here
*/
(void)gspqsignal(SIGCHLD, SIG_DFL);
(void)gspqsignal(SIGTTIN, SIG_DFL);
(void)gspqsignal(SIGTTOU, SIG_DFL);
(void)gspqsignal(SIGCONT, SIG_DFL);
(void)gspqsignal(SIGWINCH, SIG_DFL);
//设置信号掩码使得非阻塞的信号可用
gs_signal_setmask(&t_thrd.libpq_cxt.UnBlockSig, NULL);
//解除SIGUSR2信号的阻塞
(void)gs_signal_unblock_sigusr2();
/* all is done info top memory context. */
//切换到默认内存上下文中
(void)MemoryContextSwitchTo(THREAD_GET_MEM_CXT_GROUP(MEMORY_CONTEXT_DEFAULT));
//调用初始化报警项列表
DataInstAlarmItemInitialize();
for (;;) {
/* Clear any already-pending wakeups */
//清除任何已经挂起的唤醒信号
ResetLatch(&t_thrd.alarm_cxt.AlarmCheckerLatch);
/* the normal shutdown case */
if (t_thrd.alarm_cxt.gotSigdie)
if (t_thrd.alarm_cxt.gotSigdie)// 接收到终止信号,跳出循环,结束线程
break;
/*
* reload the postgresql.conf
*/
//检查是否接收到了SIGDIE信号
if (t_thrd.alarm_cxt.gotSighup) {
t_thrd.alarm_cxt.gotSighup = false;
t_thrd.alarm_cxt.gotSighup = false;//接收到重新加载postgresql.conf配置文件
ProcessConfigFile(PGC_SIGHUP);
}
//进行报警检查
AlarmCheckerLoop(DataInstAlarmList, DataInstAlarmListSize);
/*
* Sleep until there's something to do
*/
//进入休眠状态,等待下一次循环
(void)WaitLatch(&t_thrd.alarm_cxt.AlarmCheckerLatch, WL_LATCH_SET | WL_TIMEOUT, AlarmCheckInterval * 1000);
}
//调用AlarmLog函数记录日志表示报警检查程序即将关闭
AlarmLog(ALM_LOG, "alarm checker shutting down...");
//结束进程
proc_exit(0);
}
/*
* signal handle functions
*/
/*
* @@GaussDB@@
* Brief : handle SIGHUP signal and set t_thrd.alarm_cxt.gotSighup flag
* Description :
* Notes :
*/
//定义了一个名为acSighupHandler的静态函数用于处理SIGHUP信号SIGNAL_ARGS是用于接收信号处理程序的参数。
static void acSighupHandler(SIGNAL_ARGS)
{
int save_errno = errno;
t_thrd.alarm_cxt.gotSighup = true;
int save_errno = errno;//保存当前错误码
t_thrd.alarm_cxt.gotSighup = true;//置为true表示接收到了SIGHUP信号
//调用SetLatch函数设置latch对象以唤醒等待该latch的进程
SetLatch(&t_thrd.alarm_cxt.AlarmCheckerLatch);
//恢复之前保存的错误码
errno = save_errno;
}
/*
* @@GaussDB@@
* Brief : handle SIGTERM, SIGINT signal and set t_thrd.alarm_cxt.gotSigdie flag
* Description :
* Notes :
*/
//定义了一个名为acSigquitHandler的静态函数用于处理SIGQUIT信号。SIGNAL_ARGS用于接收信号处理程序的参数。
static void acSigquitHandler(SIGNAL_ARGS)
{
int save_errno = errno;
t_thrd.alarm_cxt.gotSigdie = true;
int save_errno = errno;//保存当前错误码
t_thrd.alarm_cxt.gotSigdie = true;//置为true表示接收到了SIGQUIT信号
//调用SetLatch函数设置latch对象以唤醒等待该latch的进程
SetLatch(&t_thrd.alarm_cxt.AlarmCheckerLatch);
//恢复之前保存的错误码
errno = save_errno;
}
//定义了一个名为isDirExist的函数用于判断指定目录是否存在。参数dir表示要检查的目录路径。
bool isDirExist(const char* dir)
{
struct stat stat_buf;
if (stat(dir, &stat_buf) != 0)
struct stat stat_buf;//定义了一个stat结构体用于存储目录的属性信息
//使用stat函数获取目录的属性信息
if (stat(dir, &stat_buf) != 0)//如果返回值不为0
return false;//获取失败说明目录不存在返回false
//判断获取到的目录的属性中的st_mode字段是否为目录类型
if (!S_ISDIR(stat_buf.st_mode))//若不是目录类型则返回false
return false;
if (!S_ISDIR(stat_buf.st_mode))
return false;
//这是对非Windows和非Cygwin系统上的额外检查
#if !defined(WIN32) && !defined(__CYGWIN__)
if (stat_buf.st_uid != geteuid())
if (stat_buf.st_uid != geteuid())//检查目录的拥有者是否与当前用户ID相同
return false;
if ((stat_buf.st_mode & S_IRWXU) != S_IRWXU)
if ((stat_buf.st_mode & S_IRWXU) != S_IRWXU)//检查目录的权限是否设置为用户可读、写、执行的权限
return false;
#endif
//目录存在且满足所有条件返回true否则返回false
return true;
}
//定义了一个名为DataOrRedoDirNotExistChecker的函数用于检查数据目录和pg_xlog目录是否存在。
//有两个参数alarm表示报警对象additionalParam表示额外的参数。
AlarmCheckResult DataOrRedoDirNotExistChecker(Alarm* alarm, AlarmAdditionalParam* additionalParam)
{
if (isDirExist(t_thrd.proc_cxt.DataDir) && isDirExist("pg_xlog")) {
// fill the alarm message
WriteAlarmAdditionalInfo(additionalParam,
//调用isDirExist函数判断数据目录和pg_xlog目录是否都存在
if (isDirExist(t_thrd.proc_cxt.DataDir) && isDirExist("pg_xlog")) {//如果两个目录都存在,则执行以下操作:
// fill the alarm message //- 使用WriteAlarmAdditionalInfo函数填充报警消息的额外信息。
WriteAlarmAdditionalInfo(additionalParam,
g_instance.attr.attr_common.PGXCNodeName,
"",
"",
alarm,
ALM_AT_Resume,
g_instance.attr.attr_common.PGXCNodeName);
return ALM_ACR_Normal;
} else {
return ALM_ACR_Normal;//- 返回ALM_ACR_Normal表示检查结果正常。
} else { //如果两个目录有任何一个不存在,则执行以下操作
// fill the alarm message
WriteAlarmAdditionalInfo(additionalParam,
WriteAlarmAdditionalInfo(additionalParam, //使用WriteAlarmAdditionalInfo函数填充报警消息的额外信息
g_instance.attr.attr_common.PGXCNodeName,
"",
"",
alarm,
ALM_AT_Fault,
g_instance.attr.attr_common.PGXCNodeName);
return ALM_ACR_Abnormal;
return ALM_ACR_Abnormal;// 返回ALM_ACR_Abnormal表示检查结果异常
}
}
/* implementation of alarm module. */
//定义了一个名为AlarmFree的函数用于释放内存。pointer表示要释放的内存指针。
void AlarmFree(void* pointer)
{
//检查指针是否为空
if (pointer != NULL)
pfree(pointer);
pfree(pointer);//如果不为空则调用pfree函数释放内存
}
//定义了一个名为AlarmAlloc的函数用于分配内存。size表示要分配的内存大小
void* AlarmAlloc(size_t size)
{
return palloc(size);
return palloc(size);//调用palloc函数分配内存并将分配的内存地址返回
}
//定义了一个名为AlarmLogImplementation的函数用于记录报警日志。
//有三个参数level表示日志级别prefix表示日志前缀logtext表示要记录的日志文本。
void AlarmLogImplementation(int level, const char* prefix, const char* logtext)
{
//使用switch语句根据日志级别执行不同的操作。
switch (level) {
case ALM_DEBUG:
ereport(DEBUG3, (errmsg("%s%s", prefix, logtext)));
case ALM_DEBUG://如果级别是ALM_DEBUG
ereport(DEBUG3, (errmsg("%s%s", prefix, logtext)));//调用ereport函数使用DEBUG3级别记录日志
break;
case ALM_LOG:
ereport(LOG, (errmsg("%s%s", prefix, logtext)));
case ALM_LOG://如果级别是ALM_LOG
ereport(LOG, (errmsg("%s%s", prefix, logtext)));//调用ereport函数使用LOG级别记录日志。
break;
default:
break;
break;//其他情况不执行任何操作。
}
}