|
|
#include <sys/types.h> #include <sys/procset.h> #include <sys/priocntl.h> #include <sys/fppriocntl.h> #include <sys/tspriocntl.h>long priocntl(idtype_t idtype, id_t id, int cmd, void *arg);
The schedulable entity for the system is the light-weight process (LWP). Scheduling priorities and classes are attributes of LWPs and not processes. The priocntl system call gets or sets scheduler parameters for a lightweight process (LWP) or a set of LWPs.
Four priority classes are supported. The time-sharing class (TS) adjusts priorities dynamically in an attempt to provide good response time to interactive LWPs and good throughput to CPU-intensive LWPs. The fixed class (FC) is similar to the time-sharing policy, except that it does not adjust priorities. The fixed priority class (FP) supports real-time scheduling, and allows administrators to set priorities for individual LWPs. There is also a system (sys) class that uses a fixed-priority policy to run kernel processes. The system class is reserved for use by the kernel; users may neither add nor remove a process from the system class.
In the default configuration, the highest-priority fixed priority class LWP always gets the CPU as soon as it is runnable, even if system class processes are runnable. It is important to note that the indiscriminate use of fixed priority LWPs can have a dramatic negative effect on overall system performance, particularly the performance of time-sharing LWPs.
priocntl provides an interface for specifying a set of processes or LWPs to which the system call is to apply. The priocntlset system call provides the same functions as priocntl, but allows a more general interface for specifying the set of processes to which the system call is to apply.
For priocntl, the idtype and id arguments are used together to specify the set of processes or LWPs. The interpretation of id depends on the value of idtype. The possible values for idtype and corresponding interpretations of id are as follows:
An id value of P_MYID can be used with the idtype value to specify the calling process's process ID, parent process ID, process group ID, session ID, class ID, user ID, group ID, or the LWP ID of the calling LWP.
To change the scheduling parameters of an LWP (using the PC_SETPARMS command as explained below) the real or effective user ID of the LWP calling priocntl must match the real or effective user ID of the receiving LWP or the calling LWP must have appropriate privilege. See the subsections below for details for each class. These are the minimum permission requirements enforced for all classes. An individual class can impose additional permissions requirements when setting processes to that class or when setting class-specific scheduling parameters.
The sys scheduling class exists for scheduling the execution of certain special system processes. It is not possible to change the class of any LWP to sys. In addition, any processes in the sys class that are included in a specified set of processes are disregarded by priocntl. For example, an idtype of P_UID and an id value of zero would specify all processes with a user ID of zero except processes in the sys class and (if changing the parameters using PC_SETPARMS) the init process.
The init process is a special case. In order for a priocntl call to change the class or other scheduling parameters of the init process (process ID 1), it must be the only process specified by idtype and id. The init process may be assigned to any class configured on the system, but the time-sharing class is almost always the appropriate choice.
The data type and value of arg are specific to the type of command specified by cmd.
Use the structure of type PC_GETCID and PC_GETCLINFO containing the following members:
id_t pc_cid; /* Class id */ char pc_clname[PC_CLNMSZ]; /* Class name */ long pc_clinfo[PC_CLINFOSZ]; /* Class information */
pc_cid is a class ID returned by priocntl PC_GETCID. pc_clname is a buffer of size PC_CLNMSZ (defined in sys/priocntl.h) used to hold the class name (FP for or TS for time-sharing).
pc_clinfo is a buffer of size PC_CLINFOSZ (defined in sys/priocntl.h) used to return data describing the attributes of a specific class. The format of this data is class-specific and is described under the appropriate heading below.
The PC_SETPARMS and PC_GETPARMS commands use a structure containing the following members:
id_t pc_cid; /* Process class */ long pc_clparms[PC_CLPARMSZ]; /* Class-specific params */
pc_cid is a class ID (returned by priocntl PC_GETCID). The special class ID PC_CLNULL can also be assigned to pc_cid when using the PC_GETPARMS command as explained below.
The pc_clparms buffer holds class-specific scheduling parameters. The format of this parameter data for a particular class is described under the appropriate heading below. PC_CLPARMSZ is the length of the pc_clparms buffer and is defined in sys/priocntl.h.
The following commands are supported:
cmd | arg Type | Function |
---|---|---|
PC_GETCID | pcinfo_t | get class ID and attributes |
PC_GETCLINFO | pcinfo_t | get class name and attributes |
PC_SETPARMS | pcparms_t | set class and scheduling parameters |
PC_GETPARMS | pcparms_t | get class and scheduling parameters |
typedef struct pcinfo { id_t pc_cid; /* class id */ char pc_clname[PC_CLNMSZ]; /* class name */ long pc_clinfo[PC_CLINFOSZ]; /* class information */ } pcinfo_t;
The PC_GETCID command gets scheduler class ID and parameters given the class name. The class ID is used in some of the other priocntl commands to specify a scheduler class. The valid class names are TS for time-sharing, FC for fixed class, and FP for fixed priority.
For the fixed priority class, pc_clinfo contains an fpinfo structure, which holds fp_maxpri, the maximum valid fixed priority; in the default configuration, this is the highest priority any process or LWP can have. The minimum valid fixed priority is zero. fp_maxpri is a configurable value; see ``Process scheduling'' in Programming with system calls and libraries for information on how to configure process and LWP priorities.
typedef struct fpinfo { short fp_maxpri; /* maximum fixed priority */ } fpinfo_t;
For the time-sharing class, pc_clinfo contains a tsinfo structure, which holds ts_maxupri, the maximum time-sharing user priority. The minimum time-sharing user priority is -ts_maxupri. ts_maxupri is also a configurable value.
typedef struct tsinfo { short ts_maxupri; /* limits of user priority range */ } tsinfo_t;
For the fixed class, pc_clinfo contains a fcinfo structure, which holds fc_maxupri, the maximum fixed class user priority. The minimum fixed class user priority is -fc_maxupri. fc_maxupri is also a configurable value.
typedef struct fcinfo { short fc_maxupri; /* limits of user priority range */ } fcinfo_t;
The following program is a cheap substitute for priocntl -l; it gets and prints the range of valid priorities for the time-sharing and fixed priority scheduler classes.
/* * Get scheduler class IDs and priority ranges. */#include <sys/types.h> #include <sys/priocntl.h> #include <sys/fppriocntl.h> #include <sys/tspriocntl.h> #include <stdio.h> #include <string.h> #include <stdlib.h> #include <errno.h>
main () { pcinfo_t pcinfo; tsinfo_t *tsinfop; fpinfo_t *fpinfop; short maxtsupri, maxfppri;
/* time sharing */ (void) strcpy (pcinfo.pc_clname, "TS"); if (priocntl (0L, 0L, PC_GETCID, &pcinfo) == -1L) { perror ("PC_GETCID failed for time-sharing class"); exit (1); } tsinfop = (struct tsinfo *) pcinfo.pc_clinfo; maxtsupri = tsinfop->ts_maxupri; (void) printf("Time sharing: ID %ld, priority range -%d through %d\n", pcinfo.pc_cid, maxtsupri, maxtsupri);
/* fixed priority */ (void) strcpy(pcinfo.pc_clname, "FP"); if (priocntl (0L, 0L, PC_GETCID, &pcinfo) == -1L) { perror ("PC_GETCID failed for fixed priority class"); exit (2); } fpinfop = (struct fpinfo *) pcinfo.pc_clinfo; maxfppri = fpinfop->fp_maxpri; (void) printf("Fixed priority: ID %ld, priority range 0 through %d\n", pcinfo.pc_cid, maxfppri); return (0); }
The following screen shows the output of this program, called
getcid
in this example.
$ getcid
Time sharing: ID 1, priority range -20 through 20
Fixed priority: ID 2, priority range 0 through 59
The following function is useful in the examples below. Given a class name, it uses PC_GETCID to return the class ID and maximum priority in the class.
/* * Return class ID and maximum priority. * Input argument name is class name. * Maximum priority is returned in *maxpri. */id_t schedinfo (name, maxpri) char *name; short *maxpri; { pcinfo_t info; tsinfo_t *tsinfop; fpinfo_t *fpinfop;
(void) strcpy(info.pc_clname, name); if (priocntl (0L, 0L, PC_GETCID, &info) == -1L) { return (-1); } if (strcmp(name, "TS") == 0) { tsinfop = (struct tsinfo *) info.pc_clinfo; *maxpri = tsinfop->ts_maxupri; } else if (strcmp(name, "FP") == 0) { fpinfop = (struct fpinfo *) info.pc_clinfo; *maxpri = fpinfop->fp_maxpri; } else { return (-1); } return (info.pc_cid); }
The PC_GETCLINFO command gets a scheduler class name and parameters given the class ID. This command makes it easy to write applications that make no assumptions about what classes are configured.
The following program uses PC_GETCLINFO to get the class name of a process or LWP based on the process ID. This program assumes the existence of a function getclassID, that retrieves the class ID of a process or LWP given the process ID; this function is given in the following section.
/* Get scheduler class name given process ID. */main (argc, argv) int argc; char *argv[]; { pcinfo_t pcinfo; id_t pid, classID; id_t getclassID();
if ((pid = atoi(argv[1])) <= 0) { perror ("bad pid"); exit (1); } if ((classID = getclassID(pid)) == -1) { perror ("unknown class ID"); exit (2); } pcinfo.pc_cid = classID; if (priocntl (0L, 0L, PC_GETCLINFO, &pcinfo) == -1L) { perror ("PC_GETCLINFO failed"); exit (3); } (void) printf("process ID %d, class %s\n", pid, pcinfo.pc_clname); }
typedef struct pcparms { id_t pc_cid; /* process or LWP class */ long pc_clparms[PC_CLPARMSZ]; /* class specific */ } pcparms_t;
Ignoring class-specific information for the moment, we can write a simple function for returning the scheduler class ID of a process or LWP, as promised in the previous section.
/* * Return scheduler class ID of process or LWP with ID pid. */getclassID (pid) id_t pid; { pcparms_t pcparms;
pcparms.pc_cid = PC_CLNULL; if (priocntl(P_PID, pid, PC_GETPARMS, &pcparms) == -1) { return (-1); } return (pcparms.pc_cid); }
For the real-time class, For the fixed priority class, pc_clparms contains an fpparms structure. fpparms holds scheduler parameters specific to the
typedef struct fpparms { short fp_pri; /* fixed priority */ ulong fp_tqsecs; /* seconds in time quantum */ long fp_tqnsecs; /* additional nsecs in quantum */ } fpparms_t;
fp_pri is the fixed priority; fp_tqsecs is the number of seconds and fp_tqnsecs is the number of additional nanoseconds in a time slice. That is, fp_tqsecs seconds plus fp_tqnsecs nanoseconds is the interval an LWP may use the CPU without sleeping before the scheduler gives another LWP a chance at the CPU.
For the time-sharing class, pc_clparms contains a tsparms structure. tsparms holds the scheduler parameter specific to the time-sharing class:
typedef struct tsparms { short ts_uprilim; /* user priority limit */ short ts_upri; /* user priority */ } tsparms_t;
ts_upri is the user priority, the user-controlled component of a time-sharing priority. ts_uprilim is the user priority limit, the maximum user priority a process or LWP may set for itself without being a privileged user. These values are described above in the discussion of the -s option of the priocntl command. Both the user priority and the user priority limit must be within the range reported by the priocntl -l command; this range is also reported by the PC_GETCID and PC_GETCLINFO commands to the priocntl system call.
The PC_GETPARMS command gets the scheduler class and parameters of a single process or LWP. The return value of the priocntl is the process ID of the process or LWP whose parameters are returned in the pcparms structure. The process or LWP chosen depends on the idtype and id arguments to priocntl and on the value of pcparms.pc_cid, which contains PC_CLNULL or a class ID returned by PC_GETCID:
What gets returned by PC_GETPARMS
pc_cid | |||
---|---|---|---|
Number of processes
selected by idtype and id | FP class ID | TS class ID | PC_CLNULL |
1 | FP parameters of process or LWP selected | TS parameters of process or LWP selected | class and parameters of process or LWP selected |
More than 1 | FP parameters of highest-priority FP process or LWP | TS parameters of process or LWP with highest user priority | (error) |
If idtype and id select a single process or LWP and pc_cid does not conflict with the class of that process or LWP, priocntl returns the scheduler parameters of the process or LWP. If they select more than one process or LWP of a single scheduler class, priocntl returns parameters using class-specific criteria as shown in the table. priocntl returns an error in the following cases:
The following program takes a process ID as its input and prints the scheduler class and class-specific parameters of that process or LWP:
/* * Get scheduler class and parameters of * process or LWP whose pid is input argument. */main (argc, argv) int argc; char *argv[]; { pcparms_t pcparms; fpparms_t *fpparmsp; tsparms_t *tsparmsp; id_t pid, fpID, tsID; id_t schedinfo(); short priority, tsmaxpri, fpmaxpri; ulong secs; long nsecs;
pcparms.pc_cid = PC_CLNULL; fpparmsp = (fpparms_t *) pcparms.pc_clparms; tsparmsp = (tsparms_t *) pcparms.pc_clparms; if ((pid = atoi(argv[1])) <= 0) { perror ("bad pid"); exit (1); }
/* get scheduler properties for this pid */ if (priocntl(P_PID, pid, PC_GETPARMS, &pcparms) == -1) { perror ("GETPARMS failed"); exit (2); }
/* get class IDs and maximum priorities for TS and FP */ if ((tsID = schedinfo ("TS", &tsmaxpri)) == -1) { perror ("schedinfo failed for TS"); exit (3); } if ((fpID = schedinfo ("FP", &fpmaxpri)) == -1) { perror ("schedinfo failed for FP"); exit (4); }
/* print results */ if (pcparms.pc_cid == fpID) { priority = fpparmsp->fp_pri; secs = fpparmsp->fp_tqsecs; nsecs = fpparmsp->fp_tqnsecs; (void) printf ("process %d: FP priority %d\n", pid, priority); (void) printf ("time slice %ld secs, %ld nsecs\n", secs, nsecs); } else if (pcparms.pc_cid == tsID) { priority = tsparmsp->ts_upri; (void) printf ("process %d: TS priority %d\n", pid, priority); } else { printf ("Unknown scheduler class %d\n", pcparms.pc_cid); exit (5); } return (0); }
The PC_SETPARMS command sets the scheduler class and parameters of a set of processes or LWPs. The idtype and id input arguments specify the processes or LWPs to be changed. The pcparms structure contains the new parameters: pc_cid contains the ID of the scheduler class to which the processes or LWPs are to be assigned, as returned by PC_GETCID; pc_clparms contains the class-specific parameters:
The following program takes a process ID as input, makes the process or LWP a fixed priority process or LWP with the highest valid priority minus 1, and gives it the default time slice for that priority. The program calls the schedinfo function listed above to get the real-time fixed priority class ID and maximum priority.
/* * Input arg is proc ID. Make process or LWP a fixed priority * process or LWP with highest priority minus 1. */main (argc, argv) int argc; char *argv[]; { pcparms_t pcparms; fpparms_t *fpparmsp; id_t pid, fpID; id_t schedinfo(); short maxrtpri; short maxfppri;
if ((pid = atoi(argv[1])) <= 0) { perror ("bad pid"); exit (1); }
/* Get highest valid FP priority. */ if ((fpID = schedinfo ("FP", &maxfppri)) == -1) { perror ("schedinfo failed for FP"); exit (2); }
/* Change proc to FP, highest prio - 1, default time slice */ pcparms.pc_cid = fpID; fpparmsp = (struct fpparms *) pcparms.pc_clparms; fpparmsp->fp_pri = maxfppri - 1; fpparmsp->fp_tqnsecs = FP_TQDEF;
if (priocntl(P_PID, pid, PC_SETPARMS, &pcparms) == -1) { perror ("PC_SETPARMS failed"); exit (3); } }
The following table lists the special values fp_tqnsecs can take when PC_SETPARMS is used on fixed priority processes and LWPs. When any of these is used, fp_tqsecs is ignored. These values are defined in the header file fppriocntl.h:
fp_tqnsecs | Time slice |
---|---|
FP_TQINF | infinite |
FP_TQDEF | default |
FP_NOCHANGE | unchanged |
FP_TQINF specifies an infinite time slice. FP_TQDEF specifies the default time slice configured for the fixed priority being set with the SETPARMS call. FP_NOCHANGE specifies no change from the current time slice; this value is useful, for example, when you change process or LWP priority but do not want to change the time slice. (You can also use FP_NOCHANGE in the fp_pri field to change a time slice without changing the priority.)