免费注册 查看新帖 |

Chinaunix

  平台 论坛 博客 文库
最近访问板块 发新帖
查看: 2301 | 回复: 0
打印 上一主题 下一主题

[Linux] pcs 集群使用popen打开某些程序,由于资源问题卡死无返回的处理方法 [复制链接]

论坛徽章:
0
跳转到指定楼层
1 [收藏(0)] [报告]
发表于 2016-03-08 11:08 |只看该作者 |倒序浏览
版权声明:本文为原创文章,转载请联系作者


在使用pacemaker维护的集群时,经常使用pcs 命令查询集群的状态,如:
      pcs status 查询集群下各主机的状态
         Cluster name: 111
         Last updated: Tue Mar  8 10:37:39 2016
         Last change: Mon Mar  7 14:22:04 2016 via crmd on cvm1457070021
        Stack: corosync
        Current DC: xxxxxx(2) - partition with quorum
        Version: 1.1.10-32.el7.centos.1-368c726
        2 Nodes configured
        6 Resources configured

       Online: [ xxxxxxxxx  xxxxxxxxx]

      Full list of resources:

     Clone Set: dlm-clone [dlm]
          Started: [ xxxxxxxxx  xxxxxxxxx]
        fence192.168.0.221        (stonith:fence_ipmilan):        Started xxxxxxxxxxxxx
        fence192.168.0.236        (stonith:fence_ipmilan):        Started xxxxxxxxxxxxx
    Clone Set: gfs2_cluster-clone [gfs2_cluster]
        Started: [ xxxxxxxxx  xxxxxxxxx]

    PCSD Status:
       192.168.x.xxx: Online
       192.168.x.xxx: Online

   Daemon Status:
       corosync: active/disabled
       pacemaker: active/disabled
       pcsd: active/enabled
      资源正常时,查询结果会马上返回。但是,当网络资源紧缺或者出现延迟的时候。此命令的返回有可能超过10 seconds,但是pacemaker的校验时间低于3 seconds。如果在集群中
使用此命令维护,长时间不返回。会导致集群自动fence。

     linux环境下,我们一般使用盘popen或者systemcall进行命令调用,并通过其返回值和打印值判断调用成功与否。当上述情况发生时,pclose会卡住,导致不能在规定时间内得到正确
的结果。并且由于pclose源码的问题,在多线程操作时,由于一个线程卡住不能释放资源,造成所有线程等待的问题。


     针对以上问题,经研究源码,修改popen  pclose函数为mypopen mypclose,代码如下

#include <sys/param.h>
#include <sys/wait.h>
#include <signal.h>
#include <errno.h>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <paths.h>


static struct pid {
        struct pid *next;
        FILE *fp;
        pid_t pid;
} *pidlist;

extern char **environ;   //版本控制
FILE *mypopen(const char *program, const char *type)
{
        struct pid * volatile cur;
        FILE *iop;
        int pdes[2];
        pid_t pid;
        char *argp[] = {"sh", "-c", NULL, NULL};  //调用shell

        if ((*type != 'r' && *type != 'w') || type[1] != '\0') {
                errno = EINVAL;
                return (NULL);
        }
        if ((cur = malloc(sizeof(struct pid))) == NULL)
                return (NULL);
        if (pipe(pdes) < 0) {
                free(cur);
                return (NULL);
        }

        switch (pid = fork()) {   //创建新进程
        case -1:                        /* Error. */
                (void)close(pdes[0]);
                (void)close(pdes[1]);
                free(cur);
                return (NULL);
                /* NOTREACHED */
        case 0:                                /* Child. */
            {
                struct pid *pcur;
                /*
                 * We fork()'d, we got our own copy of the list, no
                 * contention.
                 */
                for (pcur = pidlist; pcur; pcur = pcur->next)
                        close(fileno(pcur->fp));
                if (*type == 'r') {
                        (void) close(pdes[0]);
                        if (pdes[1] != STDOUT_FILENO) {
                                (void)dup2(pdes[1], STDOUT_FILENO);
                                (void)close(pdes[1]);
                        }
                } else {
                        (void)close(pdes[1]);
                        if (pdes[0] != STDIN_FILENO) {
                                (void)dup2(pdes[0], STDIN_FILENO);
                                (void)close(pdes[0]);
                        }
                }
                argp[2] = (char *)program;
                execve(_PATH_BSHELL, argp, environ);  //执行程序
                _exit(127);
                /* NOTREACHED */
            }
        }
        /* Parent; assume fdopen can't fail. */
        if (*type == 'r') {
                iop = fdopen(pdes[0], type);
                (void)close(pdes[1]);
        } else {
                iop = fdopen(pdes[1], type);
                (void)close(pdes[0]);
        }
        /* Link into list of file descriptors. */
        cur->fp = iop;
        cur->pid =  pid;
        cur->next = pidlist;
        pidlist = cur;
        return (iop);
}

/*
* pclose --
*        Pclose returns -1 if stream is not associated with a `popened' command,
*        if already `pclosed', or waitpid returns an error.
*/
int mypclose(FILE *iop,int flag = 0 /*加入控制标志,若为0,则调用waitpid直到返回;若为1,则立即返回*/)   
{
        struct pid *cur, *last;
        int pstat;
        pid_t pid;
        /* Find the appropriate file pointer. */
        for (last = NULL, cur = pidlist; cur; last = cur, cur = cur->next)
                if (cur->fp == iop)
                        break;
        if (cur == NULL)
                return (-1);
        (void)fclose(iop);
        if(0 == flag)
        {  //源代码方式
                do {
                        pid = waitpid(cur->pid, &pstat, 0);
                } while (pid == -1 && errno == EINTR);
        }
        else  
        { //增加方式
                if(pid != 0)
                        kill(pid,SIGKILL);  //强制结束调用
        }
        /* Remove the entry from the linked list. */
        if (last == NULL)
                pidlist = cur->next;
        else
                last->next = cur->next;
        free(cur);
        return (pid == -1 ? -1 : pstat);
}

       为了解决延迟问题,再封装一个函数,控制调用延时,代码如下:

int getResultFromPopenLinShi(const char* pCmd /*输入命令*/, char* pResult /*输出结果*/, int size /*输出结果大小*/, int time /*延迟时间*/)
{
        FILE *fp = NULL;
        int ret = 0;
    char tmpBuf[MAX_BUF_SIZE] = {0};
       
        if(pCmd == NULL || pResult == NULL || size == 0)
        {
        LogInfo("parameters error!\n");
                return -1;
        }
       
        char *bufAll = new char[size+1];
        memset(bufAll, 0 ,size+1);
       
        if(bufAll == NULL)
        {
                LogInfo("mem is not enough error!\n");
                return -1;
        }
       
        fp = mypopen(pCmd, "r");       
        if(fp == NULL)
        {
        LogInfo("popen failed");
                delete [] bufAll ;
                return -1;
        }
       
        int iCnt = time;
        int iSleepCnt = 0;
        int readAllCount = 0;
        bool bExitFlag = false;

        fcntl(fileno(fp), F_SETFL,O_NONBLOCK);
        while( (0 < iCnt))
        {
                ret = fread(tmpBuf,1,sizeof(tmpBuf)-1,fp);
                if(0 == ret)
                {
                        if(0 == mypclose(fp,2))
                        {
                                if(true != bExitFlag)
                                {
                                        bExitFlag = true;
                                        continue;
                                }
                                else
                                {
                                        break;
                                }
                        }
                        sleep(iSleepCnt++);
                        iCnt--;                
                        continue;
                }
        
                iSleepCnt = 1;
               
                readAllCount += ret;
               
                if(readAllCount > size)
                {
                        bExitFlag = true;
                       
                        strncat(bufAll, tmpBuf, size - strlen(bufAll));
                }
                else
                {
                        strcat(bufAll, tmpBuf);
                }
                memset(tmpBuf,0,MAX_BUF_SIZE);
        }

        memset(pResult, 0, size);
        if(strlen(bufAll) > size)
        {
                strncpy(pResult, bufAll, size-1);
        }
        else
        {
                strcpy(pResult, bufAll);
        }
        delete [] bufAll;
       
        mypclose(fp,1);
        return 0;
}
       调用此函数就能自定义延迟的控制popen和pclose的返回。



您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

北京盛拓优讯信息技术有限公司. 版权所有 京ICP备16024965号-6 北京市公安局海淀分局网监中心备案编号:11010802020122 niuxiaotong@pcpop.com 17352615567
未成年举报专区
中国互联网协会会员  联系我们:huangweiwei@itpub.net
感谢所有关心和支持过ChinaUnix的朋友们 转载本站内容请注明原作者名及出处

清除 Cookies - ChinaUnix - Archiver - WAP - TOP