Go to main content

man pages section 2: System Calls

Exit Print View

Updated: Wednesday, July 27, 2022
 
 

getrctlx(2)

Name

setrctl, setrctlx, getrctl, getrctlx - set or get resource control values

Synopsis

#include <rctl.h>

int setrctl(const char *controlname, rctlblk_t *old_blk,
     rctlblk_t *new_blk, uint_t flags);
int setrctlx(const char *controlname, rctlblk_t *old_blk,
     rctlblk_t *new_blk, idtype_t idtype, id_t id, uint_t flags);
int getrctl(const char *controlname, rctlblk_t *old_blk,
     rctlblk_t *new_blk, uint_t flags);
int getrctlx(const char *controlname, rctlblk_t *old_blk,
     rctlblk_t *new_blk, idtype_t idtype, id_t id, uint_t flags);

Description

The setrctl(), setrctlx(), getrctl(), and getrctlx() functions provide interfaces for the modification and retrieval of resource control (rctl) values on active entities on the system, such as processes, tasks, projects or zones. All rctl values are unsigned 64-bit integers; a collection of flags are defined that modify which rctl value is to be set or retrieved.

For setrctlx() and getrctlx() functions, the entity is determined by arguments idtype and id. Valid values of idtype are P_PID, P_TASKID, P_PROJID and P_ZONEID. If id is P_MYID, then the caller's entity is selected. If the caller is inside a non-global zone, any entity outside of the caller's zone is not visible. A caller in the global zone can see all processes, tasks, and zones on the system, but only projects in the global zone, as project ids are unique only to a single zone.

When the controlname refers to a resource control associated to a wider scope of entity than the entity given by idtype, these functions will act on the wider entity, which the entity given by (idtype, id) pair belongs to. For example, if idtype is P_TASKID, id is 100, and controlname is "project.max-lwps", then these functions will act on the rctl "project.max-lwps" of the project and task with id 100 belongs to. Note that each project has its own "project.max-lwps" rctl. An rctl is determined by a pair of rctl name and the entity. Conversely, if the resource control specified by controlname is associated to a narrower range of entity than the entity given by idtype, these functions fail.

For setrctl() and getrctl(), the resource control of the caller's entity is used. That is, setrctl() and getrctl() are effectively same as setrctlx() and getrctlx() with arguments idtype equals to P_PID and id equals to P_MYID.

getrctl() and getrctlx() functions read rctl-related data. Their behavior depends on the value of flags. Valid values of flags are RCTL_FIRST, RCTL_SYSTEM, RCTL_SRCH, RCTL_NEXT and RCTL_USAGE. In any case, new_blk must point to a valid rctlblk_t object.

When flags is RCTL_FIRST, the data of the first rctl value is copied to the rctlblk_t object pointed by new_blk.

When flags is RCTL_SYSTEM, the data of the system default rctl value is copied to the rctlblk_t object pointed by new_blk.

When flags is RCTL_SRCH, old_blk must point to an existing rctl value. Information of the matching rctl value is copied to new_blk. Note that, content of old_blk and new_blk may differ because of the matching rule. For example, signal is ignored for matching, but new_blk contains the signal information of the matching rctl. Otherwise, these functions fail.

When flags is RCTL_NEXT, old_blk must point to an existing rctl value. If that rctl value has a next rctl value, then this next rctl value is copied to new_blk. Otherwise, these functions fail.

When flags is RCTL_USAGE, the current value of the resource usage, if it exists, is placed in the value field of the resource control block specified by new_blk. This value can be obtained with rctlblk_get_value(3C). All other members of the returned block are undefined and might be invalid.

setrctl() and setrctlx() functions modify rctl values. Their behavior depends on the value of flags. Valid values of flags includes RCTL_INSERT, RCTL_DELETE, RCTL_REPLACE and RCTL_OVERWRITE. In some cases, these flags can be ORed with RCTL_USE_RECIPIENT_PID. All other values of flags are invalid. In any case, new_blk must point to a valid rctlblk_t object.

Since setrctl() and setrctlx() modify rctl values, the caller must meet certain access criteria in order to modify rctl values. The requirement to access an entity to modify rctl is as follows:

  • If the entity is a process, the caller must own the process. If the rctl value being modified is privileged, the PRIV_SYS_RESOURCE privilege is also required. There is one exception to this rule when replacing rctl values. It will be described in the corresponding section.

  • If the entity is a task, the caller must own at least one process of the task. If the rctl value being modified is privileged, the PRIV_SYS_RESOURCE privilege is also required.

  • If the entity is a project, the caller must have PRIV_SYS_RESOURCE privilege.

  • If the entity is a zone, the caller must have PRIV_SYS_RESOURCE privilege and the caller must be in the global zone.

In addition, if the privilege is RCPRIV_SYSTEM, the modification of this rctl value is not allowed at all. This rctl value is fixed for the duration of the operating system instance.

When flags is RCTL_INSERT, new_blk must point to a non-existing rctl value and that rctl value will be inserted. However, the function may fail if there are too many rctl values. The maximum number of rctl values per rctl is fixed for the duration of the operating system instance and can be retrieved by sysconf(3C) with argument _SC_RCTL_VAL_MAX_NUM.

When flags is RCTL_DELETE, new_blk must point to an existing rctl value, and that rctl value will be deleted.

When flags is RCTL_REPLACE, old_blk must point to an existing rctl value, and new_blk must point to a non-existing rctl values except old_blk and new_blk is considered equal. The rctl value pointed by old_blk will be replaced by the rctl value pointed by new_blk. The access requirement for replacing rctl values is same as that required to perform same operation by combination of deletion and insertion, except the following case:

  • The global flag of the rctl, which can be retrieved by the rctlblk_get_global_flags() function, has RCTL_GLOBAL_LOWERABLE bit set, and new_blk is equal to old_blk except new_blk is lowering the enforced value set and read by rctlblk_set_value() and rctlblk_get_value(). In this case, privilege check against PRIS_SYS_RESOURCE() is skipped.

When flags is RCTL_OVERWRITE, new_blk must point to a valid rctl value. All rctl values which have same privilege as that of new_blk in the same rctl are deleted and new_blk is inserted. The access requirement for overwriting rctl values is same as that required to perform same operation by combination of deletion and insertion. This operation can fail when there are too many rctl values already in the rctl to insert a new one.

When setrctl() or setrctlx() is called with flags RCTL_INSERT, RCTL_REPLACE or RCTL_OVERWRITE, if newly inserted rctl value has privilege RCPRIV_BASIC and a signal is specified by RCTL_LOCAL_SIGNAL bit in its flag, then the caller can set RCTL_USE_RECIPIENT_PID bit to flags to let setrctl() or setrctlx() functions use recipient pid set by rctlblk_set_recipient_pid() function. In this case, the caller must own the recipient process and the recipient process must be a member of the target entity. Using RCTL_USE_RECIPIENT_PID in all other cases are invalid.

In the same situation when we create a new basic rctl value with a signal, and if RCTL_USE_RECIPIENT_PID is not given, the system tries to deduce the default recipient process for the signal. If the target entity is a process, the same process is used as recipient process. If the target entity is a task and the calling process is in the target task, then the calling process is used as the recipient pid. Otherwise, the system cannot infer the recipient process and these functions fail.

Some rctls do not allow any RCPRIV_BASIC value at all. This can be checked by comparing the global flag of the rctl with RCTL_GLOBAL_NOBASIC bit. Even when RCPRIV_BASIC value is allowed, at most one RCPRIV_BASIC resource control value is permitted per rctl. Any kind of successful insertion of an RCPRIV_BASIC value will cause any existing RCPRIV_BASIC value owned by that rctl to be deleted. Because of this behavior, when calling the setrctl() and setrctlx() functions, the flags RCTL_INSERT and RCTL_OVERWRITE are effectively same when the inserted rctl value has the privilege RCPRIV_BASIC and is not an existing rctl value in the rctl.

The kernel maintains a history of which resource control values have triggered for a particular entity, retrievable from a resource control block with the rctlblk_set_value(3C) function. The insertion or deletion of a resource control value at or below the currently enforced value might cause the currently enforced value to be reset. In the case of insertion, the newly inserted value becomes the actively enforced value. In the case of deletion of the currently enforced value, the next higher value becomes the actively enforced value.

The various resource control block properties are described on the rctlblk_set_value(3C) manual page.

Process and task scope resource controls are inherited from the predecessor process or task.

One of the exec(2) functions can modify the resource controls of a process by resetting their histories, as noted above for insertion or deletion operations.

Return Values

Upon successful completion, the setrctl(), setrctlx(), getrctl() and getrctlx() functions return 0. Otherwise they return -1 and set errno to indicate the error.

Errors

The setrctl(), setrctlx(), getrctl() and getrctlx() functions will fail if:

EFAULT

The controlname, old_blk, or new_blk argument points to an illegal address when they are needed.

EINVAL

Wrong input values. They can be invalid controlname, flags, or rctl values pointed by old_blk or new_blk when they are needed.

The setrctlx() and getrctlx() functions will fail if:

EINVAL

idtype is invalid or not consistent with controlname.

ESRCH

There is no entity matched by id or visible to the zone of the caller.

The setrctl() and setrctlx() functions will fail if:

EINVAL

new_blk refers to an existing rctl values when inserting or replacing an rctl value.

RCTL_USE_RECIPIENT_PID is used with process rctl, and the recipient pid is different from the pid of the target process.

ESRCH

No matching rctl value found when deleting or replacing rctl values.

RCTL_USE_RECIPIENT_PID is used with non-process rctl, and the recipient pid does not exist in the target entity.

ENOSPC

There are too many rctl values on the rctl, so new rctl value cannot be inserted.

EACCES

The caller does not have sufficient privilege to control the target entity.

RCTL_USE_RECIPIENT_PID is used with process rctl, and the caller does not own the process pointed by recipient pid.

EPERM

The caller tried to modify system rctl values.

The setrctlx() function will fail if:

EINVAL

Inserting new basic rctl values with signal action by RCTL_INSERT, RCTL_REPLACE, or RCTL_OVERWRITE, but RCTL_USE_RECIPIENT_PID is not given, and the system cannot deduce recipient pid.

The getrctl() and getrctlx() functions will fail if:

ESRCH

The rctl value pointed by old_blk can not be found when looking for the next value.

ENOENT

No value beyond the given rctl value exists when looking for the next value by RCTL_NEXT.

No value matching the given rctl value exists when searching for the rctl value by RCTL_SRCH.

ENOTSUP

The rctl requested by RCTL_USAGE does not support the usage operation.

Examples

Example 1 Retrieve a rctl value.

Obtain the lowest enforced rctl value on the rctl limiting the number of LWPs in a task.

#include <rctl.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>

...

rctlblk_t *rblk;

if ((rblk = (rctlblk_t *)malloc(rctlblk_size())) == NULL) {
        (void) fprintf(stderr, "malloc failed: %s\n",
            strerror(errno));
        exit(1);
}

if (getrctl("task.max-lwps", NULL, rblk, RCTL_FIRST) == -1)
        (void) fprintf(stderr, "failed to get rctl: %s\n",
            strerror(errno));
else
        (void) printf("task.max-lwps = %llu\n",
            rctlblk_get_value(rblk));
Example 2 Overwrite rctl Values

Purge and set a new privileged rctl value of max-lwps of a given task.

#include <errno.h>
#include <rctl.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

/*
 * Return 1 on success, 0 and set errno on failure.
 */
int
overwrite_task_max_lwp(taskid_t task_id, rctl_qty_t qty)
{
        int ret;
        rctlblk_t *rblk;

        if ((rblk = malloc(rctlblk_size())) == NULL) {
                (void) fprintf(stderr, "malloc failed: %s\n",
                    strerror(errno));
                return (0);
        }

        rctlblk_set_privilege(rblk, RCPRIV_PRIVILEGED);
        rctlblk_set_value(rblk, qty);
        rctlblk_set_local_flags(rblk, 0);
        rctlblk_set_local_action(rblk, 0, 0);

        if (setrctlx("task.max-lwps", NULL, rblk, P_TASKID, task_id,
            RCTL_OVERWRITE) == 0) {
                 ret = 1;
        } else {
                (void) fprintf(stderr, "failed to set rctl: %s\n",
                    strerror(errno));
                ret = 0;
        }
        free(rblk);
        return (ret);
}

Usage

In an rctl, rctl values are ordered by the following criteria:

  1. Their values (including RCTL_LOCAL_MAXIMAL bit of their flag) are compared first.

  2. If their values match, then an rctl value has RCTL_LOCAL_DENY bit on its action is considered larger than one without RCTL_LOCAL_DENY bit.

  3. After that, privileges are compared. RCPRIV_BASIC is considered the lowest and RCPRIV_SYSTEM is considered the largest.

If rctl values are not distinguishable in all above criteria, they are considered equal and there can be no duplicate rctl values in an rctl by criteria. This rule of determining the equality of rctl values is applied whenever searching or matching rctl values.

The resource control facility provides the backend implementation for both setrctl()/getrctl() and setrlimit()/getrlimit(). The facility behaves consistently when either of these interfaces is used exclusively; when using both interfaces, the caller must be aware of the ordering issues above, as well as the limit equivalencies described in the following paragraph.

The hard and soft process limits made available with setrlimit() and getrlimit() are mapped to the resource controls implementation. (New process resource controls will not be made available with the rlimit interface.) Because of the RCTL_INSERT and RCTL_DELETE operations, it is possible that the set of values defined on a resource control has more or fewer than the two values defined for an rlimit. In this case, the soft and hard limit are computed as follows:

  • If RCTL_LOCAL_DENY is allowed, that is, the rctl does not have RCTL_GLOBAL_DENY_NEVER set, then the soft limit is the lowest priority rctl value with the RCTL_LOCAL_DENY flag set, and the hard limit is the rctl value with the lowest priority equal to or exceeding RCPRIV_PRIVILEGED with the RCTL_LOCAL_DENY flag set.

  • If RCTL_LOCAL_DENY is not allowed, that is, the rctl has RCTL_GLOBAL_DENY_NEVER set, then the soft limit is the lowest priority rctl value, and the hard limit is the rctl value with the lowest priority equal to or exceeding RCPRIV_PRIVILEGED.

If no identifiable soft limit exists on the resource control and setrlimit() is called, a new resource control value is created. If a resource control does not have the global RCTL_GLOBAL_LOWERABLE property set, its hard limit will not allow lowering by unprivileged callers.

Attributes

See attributes(7) for descriptions of the following attributes:

ATTRIBUTE TYPE
ATTRIBUTE VALUE
MT-Level
Async-Signal-Safe

See Also

rctladm(8), getrlimit(2), errno(3C), rctlblk_set_value(3C), sysconf(3C), attributes(7), resource-controls(7)