[comp.os.vms] Setting CPU limit on an executing process

adelman@LBL-CSA1.ARPA (Kenneth Adelman) (07/10/87)

    The following code allows you to set the CPU limit of a process
already executing. Unpack the files SETCPULIM.C and SETCPULIM-KERNEL.MAR,
compile them, and link them:

$ LINK/NOTRACE SETCPULIM,SETCPULIM-KERNEL,SYS$SYSTEM:SYS.STB/SELECTIVE

    Define a foreign symbol to run SETCPULIM. First argument is the
PID of the target, second is the new CPU limit in SECONDS. Zero
implies infinite.

    Could use some work on the user interface, but serves as a good
example of queueing special kernel ASTs to other processes. This is
necessary because the CPU limit is in the PHD, which might not be in
memory.

    As always... Use at your own risk.

					Kenneth Adelman
					LBL


$ Write Sys$Output "Creating setcpulim.c"
$ Copy Sys$Input setcpulim.c
$ Deck/Dollars="*setcpulim.c*"
/*  Program to poke the cpu limit of another process

    This program queues a special kernel AST to the target process
    to change its cpu limit.
*/

#include stdio

main(argc,argv)
int argc;
char *argv[];
{

	long status, sys$cmkrnl(), arglst[3];
	extern long pokecpulim();

	if (argc != 3) {
		fprintf(stderr,"Usage: %s pid cpulimt\n",argv[0]);
		exit(0x10000000);
	}

	arglst[0] = 1;

	if(!sscanf(argv[1],"%x",&arglst[1])) {
		fprintf(stderr,"%s: error parsing pid\n",argv[0]);
		exit(0x10000000);
	}

	if(!sscanf(argv[2],"%d",&arglst[2])) {
		fprintf(stderr,"%s: error parsing cpulimit\n",argv[0]);
		exit(0x10000000);
	}
	arglst[2] *= 100;

	status = sys$cmkrnl(pokecpulim,arglst);
	if (!(status&1)) return(status);

}
*setcpulim.c*
$ Write Sys$Output "Creating setcpulim-kernel.mar"
$ Copy Sys$Input setcpulim-kernel.mar
$ Deck/Dollars="*setcpulim-ker*"
	.title setcpulim-kernel
;
;	4(AP) = PID
;	8(AP) = LIMIT
;
	.library /SYS$LIBRARY:LIB/
	$acbdef

spec_limit  = acb$c_length
code_off    = acb$c_length+4

	$dyndef
	$ipldef
	$ssdef
	$pcbdef
	$phddef
	$pridef

	.entry pokecpulim,^m<r2,r3,r4,r5,r6>
;
;	Get the internal PID of the process to queue the nASTy by
;

	movl	4(ap),r0
	jsb	g^exe$epid_to_ipid
	tstl	r0
	beql	nonproc
	movl	r0,r6		;save ipid

;
;	Allocate a buffer to hold the ACB, three longwords of data, and the
;	AST code.
;

	movl	#codelen+code_off,r1
	jsb	g^exe$allocbuf
	blbs	r0,10$
	ret
10$:	movl	r2,r5		;save address

;
;	Fill in the ACB
;

	movl	r6,acb$l_pid(r5)
	movb	#dyn$c_acb,acb$b_type(r5)
	movw	#acb$c_length,acb$w_size(r5)
	movb	#1@acb$v_kast,acb$b_rmod(r5)
	movab	code_off(r5),acb$l_kast(r5)

;
;	Copy the code and the new CPU limit.
;

	movl	8(ap),spec_limit(r5)
	pushl	r5
	movc3	#codelen,w^code,@acb$l_kast(r5)
	popl	r5

;
;	Queue the nASTy
;

	movzbl	#pri$_ticom,r2	;set priority increment class
	movzwl	acb$l_pid(r5),r0   ;destination pid
begin_lock:
	dsbint	lock_ipl
	jsb	g^sch$qast
	enbint
	ret
lock_ipl:
	.long	ipl$_synch
end_lock:
	assume <end_lock-begin_lock> le 512
nonproc:
	movl	#ss$_nonexpr,r0
	ret

;
;	This *PIC* code executes in the context of the target.
;

code:
	movl	g^ctl$gl_phd,r1
	movl	spec_limit(r5),phd$l_cpulim(r1)
	setipl	#ipl$_astdel
	movl	r5,r0
	jmp	@#exe$deanonpaged
codelen = .-code
	.end
*setcpulim-ker*