本章介绍了工作负荷分层结构,并且提供了有关项目和任务的信息。本章包含以下主题:
Solaris OS 使用工作负荷分层结构组织系统中所执行的工作。任务是指表示工作负荷组件的进程集合。项目是指表示整个工作负荷的任务集合。在任何给定的时间,进程都只能是一个任务和一个项目的组件。下图说明了工作负荷分层结构中的关系。
作为多个项目成员的用户可以同时运行多个项目中的进程。由某个进程启动的所有进程都会继承父进程的项目。在启动脚本中切换到新项目时,所有子进程都会在该新项目中运行。
正在执行的用户进程有关联的用户标识 (uid)、组标识 (gid) 和项目标识 (projid)。进程属性和功能是从用户、组和项目标识继承而来,从而形成任务的执行环境。
有关项目和任务的深入讨论,请参见《系统管理指南:Solaris Containers-资源管理和 Solaris Zones》中的第 2 章 “项目和任务(概述)”。有关用于管理项目和任务的管理命令,请参见《系统管理指南:Solaris Containers-资源管理和 Solaris Zones》中的第 3 章 “管理项目和任务”。
project 文件是工作负荷分层结构的核心。project 数据库是在系统中通过 /etc/project 文件或在网络上通过名称服务(如 NIS 或 LDAP)来维护的。
/etc/project 文件包含五个标准项目。
此项目用于所有系统进程和守护进程。
所有的根进程都在 user.root 项目中运行。
此特殊项目用于 IPQoS。
缺省项目会指定给每个用户。
此项目用于 staff 组中的所有用户。
要通过编程方式访问项目文件,请使用以下结构:
struct project { char *pj_name; /* name of the project */ projid_t pj_projid; /* numerical project ID */ char *pj_comment; /* project comment */ char **pj_users; /* vector of pointers to project user names */ char **pj_groups; /* vector of pointers to project group names */ char *pj_attr; /* project attributes */ };
project 结构成员包括以下各项:
项目的名称。
项目 ID。
用户提供的项目说明。
指向项目用户成员的指针。
指向项目组成员的指针。
项目属性。使用这些属性可为资源控制和项目池设置值。
通过项目属性,可以控制资源的使用情况。可以使用四种前缀对各种类型的资源控制属性进行分组:
project.*-此前缀表示用于控制项目的属性。例如,project.max-device-locked-memory 可指明所允许的锁定内存总量(以字节数表示)。project.pool 属性将项目绑定到资源池。请参见第 6 章,动态资源池。
task.*-此前缀用于应用于任务的属性。例如,task.max-cpu-time 属性设置此任务进程可用的最长 CPU 时间(以秒数表示)。
process.*-此前缀用于进程控制项。例如,process.max-file-size 控制项设置可由此进程写入的最大文件偏移量(以字节数表示)。
zone.*-zone.* 前缀适用于区域中的项目、任务和进程。例如,zone.max-lwps 可以防止一个区域中有过多 LWP 影响其他区域。可以使用 project.max-lwps 的各项在区域内的各个项目之间进一步细分区域的所有 LWP。
有关资源控制的完整列表,请参见 resource_controls(5)。
以下函数用于协助开发者处理项目。这些函数使用的各项用于描述 project 数据库中的用户项目。
处理完成后,关闭项目数据库并取消分配资源。
返回一个指针,该指针指向包含项目数据库中的项的结构。fgetprojent() 从流中读取行,而不是使用 nsswitch.conf 读取行。
检查项目关键字的有效性,查找项目并返回指向项目结构(如果找到)的指针。
搜索 project 数据库中带有指定项目 ID 的数字的项。
搜索 project 数据库中带有指定项目名称的字符串的项。
返回一个指针,该指针指向包含项目数据库中的项的结构。
检查是否允许指定的用户使用指定的项目。
将用户进程添加到项目中。
反绕 project 数据库,以允许重复搜索。
setprojent() 开始会反绕 project 数据库来进行启动。
getprojent() 是使用 project.h 中定义的保守最大缓冲区大小来调用的。
endprojent() 用于关闭 project 数据库并释放资源。
#include <project.h> struct project projent; char buffer[PROJECT_BUFSZ]; /* Use safe buffer size from project.h */ ... struct project *pp; setprojent(); /* Rewind the project database to start at the beginning */ while (1) { pp = getprojent(&projent, buffer, PROJECT_BUFSZ); if (pp == NULL) break; printf("%s:%d:%s\n", pp->pj_name, pp->pj_projid, pp->pj_comment); ... }; endprojent(); /* Close the database and free project resources */
以下示例调用 getprojbyid() 来获取与调用方的项目 ID 匹配的项目数据库项。然后,该示例将列显项目名称和项目 ID。
#include <project.h> struct project *pj; char buffer[PROJECT_BUFSZ]; /* Use safe buffer size from project.h */ main() { projid_t pjid; pjid = getprojid(); pj = getprojbyid(pjid, &projent, buffer, PROJECT_BUFSZ); if (pj == NULL) { /* fail; */ } printf("My project (name, id) is (%s, %d)\n", pp->pj_name, pp->pj_projid); }
编写应用程序时,请注意以下问题:
不存在可以显式创建新项目的函数。
如果 project 数据库中不存在用户的缺省项目,则该用户无法登录。
用户登录时,系统会在该用户的缺省项目中创建新任务。
进程与新项目的关联会将新项目的资源控制和池成员关系应用于进程。
setproject() 需要权限。如果您拥有进程,则 newtask 命令不需要权限。虽然二者均可用于创建任务,但仅有 newtask 可以更改运行的进程对应的项目。
任务之间不存在任何父/子关系。
可以使用 newtask -F 或setproject() 来创建最终任务,从而将调用方与新项目关联。尝试准确估计总体资源记帐时,最终任务非常有用。
可重复执行函数 getprojent()、getprojbyname()、getprojbyid()、getdefaultproj() 和 inproj() 会使用调用方提供的缓冲区来存储返回的结果。在单线程应用程序和多线程应用程序中可以安全地使用这些函数。
可重复执行函数需要以下附加参数: proj、buffer 和 bufsize。proj 参数必须是指向调用方所分配的 project 结构的指针。成功完成后,这些函数将返回此结构中的项目项。project 结构所引用的存储空间是从 buffer 参数指定的内存中分配的。bufsize 用于指定大小(以字节数表示)。
如果使用不正确的缓冲区大小,则 getprojent() 会返回 NULL,并将 errno 设置为 ERANGE。