次の例は、マスターオブザーバプロセスです。図 5 は、マスター監視プロセスのリソース制御を示しています。
図 5 マスター監視プロセス
この例の重要なポイントは次のとおりです。
タスクの制限には特権が付与されているため、アプリケーションは制限を変更したり、シグナルなどのアクションを指定したりできません。マスタープロセスは、同じリソース制御を基本リソース制御としてタスク上に確立することでこの問題を解決します。マスタープロセスは、リソース上の同じ値またはわずかに少ない値を、異なるアクション (シグナル = XRES) で使用します。マスタープロセスはこのシグナルを待機するスレッドを作成します。
rctlblk は不透明です。構造体は動的に割り当てる必要があります。
スレッドを作成する前に、sigwait(2) の要求に応じてすべてのシグナルがブロックされることに注意してください。
スレッドはシグナルをブロックするために sigwait(2) を呼び出します。sigwait() が SIGXRES シグナルを返すと、スレッドがマスタープロセスの子に通知し、これによって使用する LWP 数の削減に適応します。それぞれの子についても、1 つの子に 1 つのスレッドが入った状態で同様にモデル化し、このシグナルを待機して、そのプロセスの LWP 使用率に適切に適応するようにしてください。
rctlblk_t *mlwprcb;
sigset_t smask;
/* Omit return value checking/error processing to keep code sample short */
/* First, install a RCPRIV_BASIC, v=1000, signal=SIGXRES rctl */
mlwprcb = calloc(1, rctlblk_size()); /* rctl blocks are opaque: */
rctlblk_set_value(mlwprcb, 1000);
rctlblk_set_privilege(mlwprcb, RCPRIV_BASIC);
rctlblk_set_local_action(mlwprcb, RCTL_LOCAL_SIGNAL, SIGXRES);
if (setrctl("task.max-lwps", NULL, mlwprcb, RCTL_INSERT) == -1) {
perror("setrctl");
exit (1);
}
/* Now, create the thread which waits for the signal */
sigemptyset(&smask);
sigaddset(&smask, SIGXRES);
thr_sigsetmask(SIG_BLOCK, &smask, NULL);
thr_create(NULL, 0, sigthread, (void *)SIGXRES, THR_DETACHED, NULL));
/* Omit return value checking/error processing to keep code sample short */
void *sigthread(void *a)
{
int sig = (int)a;
int rsig;
sigset_t sset;
sigemptyset(&sset);
sigaddset(&sset, sig);
while (1) {
rsig = sigwait(&sset);
if (rsig == SIGXRES) {
notify_all_children();
/* e.g. sigsend(P_PID, child_pid, SIGXRES); */
}
}
}
次の例では、特定のリソース制御 task.max-lwps の値-アクションペアがすべて一覧表示されています。この例の重要なポイントは、getrctl(2) が 2 つのリソース制御ブロックを取り、RCTL_NEXT フラグのリソース制御ブロックを返すことです。すべてのリソース制御ブロックを繰り返し処理するには、ここに示すように rcb_tmp rctl ブロックを使用してリソース制御ブロックの値を繰り返しスワップします。
rctlblk_t *rcb1, *rcb2, *rcb_tmp;
...
/* Omit return value checking/error processing to keep code sample short */
rcb1 = calloc(1, rctlblk_size()); /* rctl blocks are opaque: */
/* "rctlblk_t rcb" does not work */
rcb2 = calloc(1, rctlblk_size());
getrctl("task.max-lwps", NULL, rcb1, RCTL_FIRST);
while (1) {
print_rctl(rcb1);
rcb_tmp = rcb2;
rcb2 = rcb1;
rcb1 = rcb_tmp; /* swap rcb1 with rcb2 */
if (getrctl("task.max-lwps", rcb2, rcb1, RCTL_NEXT) == -1) {
if (errno == ENOENT) {
break;
} else {
perror("getrctl");
exit (1);
}
}
}
この例は、pool.comment プロパティーの設定と新規プロパティーの追加に示されている例と似ています。
特定のリソース制御の値-アクションペアをすべて表示のバッファースワッピングではなく bcopy() を使用します。
リソース制御値を変更するには、RCTL_REPLACE フラグを指定して setrctl() を呼び出します。新しいリソース制御ブロックは、新しい制御値を除いて古いリソース制御ブロックと同じです。
rctlblk_set_value(blk1, nshares);
if (setrctl("project.cpu-shares", blk2, blk1, RCTL_REPLACE) != 0)
この例ではプロジェクトの CPU 配分割り当て (project.cpu-shares) を取得し、その値を nshares に変更します。
/* Omit return value checking/error processing to keep code sample short */
blk1 = malloc(rctlblk_size());
getrctl("project.cpu-shares", NULL, blk1, RCTL_FIRST);
my_shares = rctlblk_get_value(blk1);
printout_my_shares(my_shares);
/* if privileged, do the following to */
/* change project.cpu-shares to "nshares" */
blk1 = malloc(rctlblk_size());
blk2 = malloc(rctlblk_size());
if (getrctl("project.cpu-shares", NULL, blk1, RCTL_FIRST) != 0) {
perror("getrctl failed");
exit(1);
}
bcopy(blk1, blk2, rctlblk_size());
rctlblk_set_value(blk1, nshares);
if (setrctl("project.cpu-shares", blk2, blk1, RCTL_REPLACE) != 0) {
perror("setrctl failed");
exit(1);
}
次の例では、超えることのできない 3000 LWP の特権付き制限をアプリケーションが設定しています。さらに、アプリケーションは 2000 LWP の基本制限も設定しています。この制限を超えると、SIGXRES がアプリケーションに送信されます。SIGXRES を受け取るとアプリケーションがすぐにその子プロセスに通知を送信し、次にその子プロセスが、使用するまたは必要となる LWP 数を減らす場合があります。
/* Omit return value and error checking */
#include <rctl.h>
rctlblk_t *rcb1, *rcb2;
/*
* Resource control blocks are opaque
* and must be explicitly allocated.
*/
rcb1 = calloc(rctlblk_size());
rcb2 = calloc(rctlblk_size());
/* Install an RCPRIV_PRIVILEGED, v=3000: do not allow more than 3000 LWPs */
rctlblk_set_value(rcb1, 3000);
rctlblk_set_privilege(rcb1, RCPRIV_PRIVILEGED);
rctlblk_set_local_action(rcb1, RCTL_LOCAL_DENY);
setrctl("task.max-lwps", NULL, rcb1, RCTL_INSERT);
/* Install an RCPRIV_BASIC, v=2000 to send SIGXRES when LWPs exceeds 2000 */
rctlblk_set_value(rcb2, 2000);
rctlblk_set_privilege(rcb2, RCPRIV_BASIC);
rctlblk_set_local_action(rcb2, RCTL_LOCAL_SIGNAL, SIGXRES);
setrctl("task.max-lwps", NULL, rcb2, RCTL_INSERT);