【问题标题】:Count the running process in AIX by it's name in C按 C 中的名称计算 AIX 中正在运行的进程
【发布时间】:2015-03-09 23:43:46
【问题描述】:

操作系统:IBM AIX 5.3

编译器:xlc

大家好

我有一个项目,它使用 C 来处理一些使用多进程的文件。子进程数主要取决于传入文件的数量和当前运行的进程数。我需要一种可靠的方法来计算有多少子进程在后台运行。

通过效率比较,直接读取/proc目录可能比调用popen()执行$ ps -ef | grep blah性能更好。

我编写了一个函数来读取/proc/pid/psinfo 中的psinfo 并比较参数。 伪代码如下:

int count = 0;
dp = opendir("/proc");
while (readdir_r(...))
{
    if (dir is not a process)
        return -1;
    if (dir's owner is not current user)
        return -2;
    if (failed to open "/proc/[pid]/psinfo")
        return -3;
    if (failed to read "/proc/[pid]/psinfo")
        return -4;
    if (process's name matches the given pname)
        count += 1;
}
return count;

该函数通常在一次调用时完美运行。但是,当嵌入到 while 循环中时,它会返回 -2 或 -3 甚至错误的计数。

函数随机读取/proc/pid的属性失败。它告诉No such file or directory

最后也有很小的机会得到错误的计数。似乎有一个带有特定 pid 的额外进程,但在使用 ps 打印当前进程时消失了。

我认为在列出父目录后快速读取子目录时发生了任何变化。

我做错了什么还是有什么方法可以避免这种情况?

获取有关 AIX 中 psinfo 的额外信息 http://www-01.ibm.com/support/knowledgecenter/ssw_aix_53/com.ibm.aix.files/doc/aixfiles/proc.htm%23files-proc?lang=en[233]

这里是完整的源代码:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <dirent.h>
#include <sys/procfs.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <errno.h>

int countProcess(char *pname)
{
    DIR                 *dir;
    int                 fd;
    int                 pid;
    int                 uid;
    int                 pcounter = 0;
    struct psinfo       pinfo;
    struct dirent       entry;
    struct dirent       *result;
    struct stat         fsstat;
    char                path[256];
    char                process_path[256];

    /* Open the /proc directory */
    if ((dir = opendir("/proc")) == NULL)
    {
        return -1;
    }

    /* Retrieve the current user id */
    uid = getuid();

    /* Walk through the /proc dir */
    for (readdir_r(dir, &entry, &result); result != NULL; readdir_r(dir, &entry, &result))
    {
        /* See if this is a process, e.g., the dirname is a number
           If not, then start off again
         */
        if ((pid = atoi(entry.d_name)) == 0)
        {
            continue;
        }

        /* Get the attributes of process dir */
        snprintf(process_path, sizeof(process_path), "/proc/%s", entry.d_name);
        if (stat(process_path, &fsstat) == -1)
        {
            closedir(dir);
            return -2;
        }


        /* Verify if the process runs by current user
           If not, then start off again
         */
        if (fsstat.st_uid != uid)
        {
            continue;
        }

        /* Open and read from psinfo file */
        snprintf(path, sizeof(path), "/proc/%s/psinfo", entry.d_name);

        if ((fd = open(path, O_RDONLY)) < 0)
        {
            close(fd);
            closedir(dir);
            return -3;
        }

        if (read(fd, &pinfo, sizeof(pinfo)) < 0)
        {
            close(fd);
            closedir(dir);
            return -4;
        }

        /* String comparison, if same, increase the counter */
        if (!strcmp(pinfo.pr_psargs, pname))
        {
            pcounter++;
        }
        close(fd);

    }

    /* returns counter */
    closedir(dir);
    return pcounter;
}

2015 年 1 月 13 日更新

感谢 CoreyStup。 procinfo.h中提供的getprocs()函数可以绕过竞争条件

这是解决方案的代码

#include <stdio.h>
#include <unistd.h>
#include <procinfo.h>
#include <sys/types.h>

int countProcess(const char *pname)
{
    struct procsinfo            pinfo;
    pid_t                       pid = 0;
    uid_t                       uid;
    char                        args[256];
    int                         index;
    int                         pcounter = 0;

    memset(args, 0, sizeof(args));
    uid = getuid();

    /* Get procsinfo from internal API */
    while (0 < getprocs(&pinfo, (int)sizeof(struct procsinfo), NULL, 0, &pid, 1))
    {
        /* Skip the process that doesn't belong to current user */
        if (pinfo.pi_uid != uid)
        {
            continue;
        }

        /* Get process arguments */
        if (getargs(&pinfo, sizeof(struct procsinfo), args, sizeof(args)) != 0)
        {
            return -1;
        }

        /* getargs returns the args list seperated by 0, we need to use space to replace 0 */
        for (index = 0; index < 256 - 1 && !(args[index] == 0 && args[index + 1] == 0); index++)
        {
            if (args[index] == 0)
            {
                args[index] = ' ';
            }
        }
        if (!strncmp(args, pname, strlen(pname)))
        {
            pcounter++;
        }

    }
    return pcounter;
}

【问题讨论】:

    标签: unix process kernel aix


    【解决方案1】:

    尝试使用getprocs()。我发现它比使用 /proc 或 ps 进行炮击效果更好。

    我在这里举了一个例子:Need help in getting the process name based on the pid in aix

    【讨论】:

    • 谢谢,这个方法可以绕过竞态条件!
    猜你喜欢
    • 2012-09-05
    • 2018-02-28
    • 1970-01-01
    • 2014-05-16
    • 1970-01-01
    • 1970-01-01
    • 2011-03-02
    • 2021-03-14
    • 1970-01-01
    相关资源
    最近更新 更多