使用C中的名称计算AIX中的运行进程

时间:2015-01-12 08:43:19

标签: unix process kernel aix

操作系统: IBM AIX 5.3

编译器: xlc

Hello Everyone

我有一个项目使用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;
}

更新13 / Jan / 2015

感谢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;
}

1 个答案:

答案 0 :(得分:0)

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

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