[net.micro.amiga] cpri: change AmigaDOS process priorities

dewi@druca.UUCP (WilliamsD) (05/06/86)

--

Here's a belated contribution to the discussion on process priorities.
cpri uses the Exec SetTaskPri function to fiddle around with the process
priorities of running CLI processes.

I've also thrown in a "ps" command, as a replacement for "status". I've
no idea why status displays all those question marks - ps gives you the
command name instead.

This posting contains the following items:
	ps+cpri.doc	a readme file
	ps.c		source for the ps command
	cpri.c		source for the cpri command
	ps.Z.b		the executable, run through compress and btoa
	cpri.Z.b	the executable, run through compress and btoa

To regenerate the executables, run them through atob and then uncompress (or
compress -d). atob, btoa and compress are part of the mod.sources
distribution.

------------------------------ cut here ----------------------------------
echo "creating source files:"
echo "\tps+cpri.doc"
cat <<"FUNKYSTUFF" >ps+cpri.doc
		Documentation for the ps and cpri commands
		------------------------------------------
ps and cpri are commands that allow you to investigate and change the
priorities of running AmigaDOS processes. In addition, ps can be viewed
as a replacement for the "status" command.

syntax
------
	cpri priority CLI-process-number
	ps   [-f]

Priorities run in the range -128 to 127.

The CLI-process-number is that reported by the status and ps commands, and
has values between 1 and 20.

Note that only AmigaDOS user processes can have their priority changed --
you can't fiddle around with the priority of filesystem tasks, for
instance. In general, this works for processes, not tasks.

using cpri
----------
You have to take a certain amount of care in the use of this command. cpri'ing
a cpu-bound process to a priority greater than zero will lock up your machine
until it completes.

In order to experiment with this command, you can do the following:

	1. Create and compile cpuhog.c, which has the following contents:
		main()	{ for(;;) Chk_Abort(); 	}
	2. Run nine or ten cpuhogs in background. They'll be running at
	   priority -5.
	3. See how the responsiveness of the initial CLI degrades as you
	   start cpri'ing each cpuhog command to priority 0.
	4. To get rid of a cpuhog, use the break command:
		break CLI-process-number
	5. If you *really* must, set the priority of a cpuhog to a +ve value.
	   Congratulations. You'll have to reboot, because your initial CLI
	   won't get any CPU until cpuhog completes or waits -- and it never
	   will!

suggested uses
--------------
You can prioritize background tasks. If two or more are running, temporarily
lowering the priority of some will allow the others to complete faster.

ps
--
A replacement command for status, called "ps", is part of this package. I
wrote it because I didn't like the way that status kept reporting most of
my CLI commands as "????????". I assume that's a bug in status, but it may
be a feature...

ps will report command names and process numbers. If given a "-f" command line
flag, CLI type and process priority is also reported.

bugs
----
cpri should really be folded into run. Sort of like the UNIX nice command.
FUNKYSTUFF
echo "\tps.c"
cat <<"FUNKYSTUFF" >ps.c
#include	<stdio.h>
#include	<libraries/dos.h>
#include	<libraries/dosextens.h>
#include	<exec/memory.h>
#include	<exec/tasks.h>

/*
 * P S :	Like the UN*X command of the same name, this reports on
 *		running processes in the system. The current version only
 *		reports CLI processes, so you don't see the filesystem
 *		tasks. Written because I got tired of seeing the question
 *		marks that status spits out at every opportunity.
 *		This will build OK with 16 bit integers.
 *
 * Usage:	ps [-f]
 *
 * Author:	Dewi Williams ..!ihnp4!druca!dewi
 * Status:	Public domain.
 */
 
/* Defines */

/* Change typeless BCPL BPTR to typed C (for struct pointers). Don't
 * use this define on an APTR, that's only a badly disguised void *.
 */
#define	BPTR_TO_C(strtag, var)  ((struct strtag *)(BADDR( (ULONG) var)))

/* Use AmigaDOS i/o to keep executable size down */
#define WSTR(s)		(void)Write(OutLock, s, (long)strlen(s))
#define WCHR(s)		(void)Write(OutLock, s, 1L)	/* char w/ d. quotes */

#define TO_ASC(n)	((n) + '0')		/* make it printable! */

/* Casting conveniences */
#define	PROC(task)		((struct Process *)task)
#define ROOTNODE		((struct RootNode *)DOSBase->dl_Root)
#define CLI(proc)		(BPTR_TO_C(CommandLineInterface, proc->pr_CLI))

/* Externs */
extern struct DosLibrary *DOSBase;	/* dos library base pointer */
extern struct FileLock	 *Output();	/* get output file handle */

/* Globals */
static struct FileLock	 *OutLock;	/* used by WSTR define */
static int		 fullopt = 0;	/* set by -f command line flag */

main(argc, argv)
int	argc;
char	**argv;
{
	register ULONG	 *tt;		/* References TaskArray  	*/
	register int	 count;		/* loop variable 	 	*/
	register UBYTE	 *port;		/* msgport & ptr arith   	*/
	register struct Task *task;	/* EXEC descriptor	 	*/
	char		 strbuf[256];	/* scratch for btocstr() 	*/
	char		 *btocstr();	/* BCPL BSTR to ASCIIZ   	*/
	void		 disp_hdr();	/* display ps header	 	*/
	void		 display();	/* display data for one process */

	OutLock = Output();		/* initialize output handle 	*/

	if (argc > 1 && strcmp(argv[1], "-f") == 0) fullopt = 1;

	tt = (unsigned long *)(BADDR(ROOTNODE->rn_TaskArray));

	if (fullopt) disp_hdr();

	Forbid();		/* need linked list consistency */
	
	/* Loop through the data for the CLI processes. */
	for (count = 1; count <= (int)tt[0] ; count++) {/* or just assume 20?*/
		if (tt[count] == 0) continue;		/* nobody home */

		/* Start by pulling out MsgPort addresses from the TaskArray
		 * area. By making unwarranted assumptions about the layout
		 * of Process and Task structures, we can derive these
		 * descriptors. Every task has an associated process, since
		 * this loop drives off a CLI data area.
		 */

		port = (UBYTE *)tt[count];
		task = (struct Task *)(port - sizeof(struct Task));

		/* Sanity check just in case */
		if (PROC(task)->pr_TaskNum == 0 || PROC(task)->pr_CLI == NULL)
			continue;		/* or complain? */

		/* Pass the C string version of the command name to
		 * the display routine.
		 */
		display(count, task->tc_Node.ln_Name,
			btocstr(CLI(PROC(task))->cli_CommandName, strbuf), 
			task->tc_Node.ln_Pri);
	}
	Permit();		/* outside critical region */
	exit(0);
}

/*
 * Convert a BCPL string to a C string. To avoid scrogging in-memory
 * stuff, it copies it first. Your data area better be big enough!
 */

char *
btocstr(b, buf)
ULONG	b;
char	*buf;
{
	register char	*s;

	s = (char *)BADDR(b);	/* Shift & get length-prefixed str */
	(void)movmem(s +1, buf, s[0]);	/* a.k.a memcpy */
	buf[s[0]] = '\0';
	return buf;
}

/*
 * Display the header for the output.
 */

void 
disp_hdr()
{
	WSTR("Process #  CLI Type         Command Name         Priority\n");
}

/*
 * Display the information for a particular CLI process. Keep the format
 * string in sync with that of disp_hdr().
 */

void  
display(tnum, type, name, pri)
int	tnum;		/* CLI process number */
char	*type;		/* Initial, Background or New CLI */
char	*name;		/* Command name if CLI's running one */
int	pri;		/* priority of CLI & command */
{
	char 		*psitoa();
	char 		buf[80];
	char		*ext_len();
	register char	*p = buf;

	if (*name == '\0') name = "<Cli>";	/* Null, nothing loaded */

	if (fullopt) {
		p = ext_len(psitoa(tnum, p), 11);
		strcpy(p, type);
		p = ext_len(p, 17);
		strcpy(p, name);
		p = ext_len(p, 21);
		(void)psitoa(pri, p);
	} else {
		p = ext_len(psitoa(tnum, p), 2);
		*p++ = ':';
		*p++ = ' ';
		strcpy(p, name);
	}

	WSTR(buf);	
	WCHR("\n");
}

/*
 * Everything after here is a hack to avoid dragging in printf.
 * ------------------------------------------------------------
 */
 
/*
 * Limited itoa style function. Don't use it anywhere else! Used to keep
 * things small & avoid printf. Has a very limited range (3 digits +/- sign).
 * This hack avoids having to do the recursion & reverse of K&R itoa.
 */
 
char *
psitoa(num, into)
int	num;				/* number to convert  */
char	*into;				/* write it into here */
{
	register char	*p = into;
	
	if (num < 0) {
		*p++ = '-';
		num = -num;
	}
	if (num > 99) {
		*p++ = TO_ASC(num/100);
		*p++ = TO_ASC((num%100)/10);
		*p++ = TO_ASC(num%10);
	} else if (num > 9) {
		*p++ = TO_ASC(num/10);
		*p++ = TO_ASC(num%10);
	} else
		*p++ = TO_ASC(num);

	*p = '\0';			/* end of the string */
	return into;
}

/*
 * Extend to length. Assumes strlen(s) never greater than len.
 */

char *
ext_len(s, len)
char	*s;			/* must be large enough for extension to len */
int	len;
{
	register int	leftover;
	register int	slen = strlen(s);
	register char	*p = s + slen;	
	
	for(leftover = len - slen; leftover > 0; leftover--)
		*p++ = ' ';

	*p = '\0';		/* null terminate */
	return p;		/* return loc after string */
}
FUNKYSTUFF
echo "\tcpri.c"
cat <<"FUNKYSTUFF" >cpri.c
/*
 * C P R I :	This allows you to muck around with the priorities of 
 *		running AmigaDOS processes.
 */

#include	<stdio.h>
#include	<ctype.h>
#include	<libraries/dos.h>
#include	<libraries/dosextens.h>
#include	<exec/tasks.h>

/* Externs */
extern struct DosLibrary *DOSBase;	/* dos library base pointer */
extern struct FileLock	 *Output();	/* get output file handle */
extern	short		 SetTaskPri();	/* sets priority for specified task */

/* Globals */
static struct FileLock	 *OutLock;	/* used by WSTR define */

/* Defines */

/* Use AmigaDOS i/o to keep executable size down */
#define WSTR(s)		 (void)Write(OutLock, s, (long)strlen(s))

/* Casting conveniences */
#define ROOTNODE	((struct RootNode *)DOSBase->dl_Root)

main(argc, argv)
int	argc;
char	**argv;
{
	void		usage();
	char		*pris = argv[1];
	int		sign  = 1;
	long		pri, atol();
	struct Task 	*tcb;
	unsigned long   *tt, procnum;
	struct   Task	*task;
	UBYTE		*port;

	OutLock = Output();
					
	if (argc != 3) usage();

	/* Handle any leading + or - sign */
	if (*pris == '+') {
		pris++;
	} else if (*pris == '-') {
		pris++;
		sign = -1;
	}
	
	/* What's left must be a digit string */
	if (*pris == '\0' || (!isdigstr(pris)) ) usage();
	
	pri = atol(pris) * sign;		/* got the priority */

	/* Bound check the priority */
	if (pri	< -128 || pri > 127) {
		WSTR("Bad priority: range is -128 to 127\n");
		exit(20);
	}
	
	/* The second parameter should be a CLI procnum */
	if ( !isdigstr(argv[2]) ) usage();
	
	procnum = atol(argv[2]);
	tt = (unsigned long *)(BADDR(ROOTNODE->rn_TaskArray));

	/* Validate with range check */
	if (procnum > tt[0] || tt[procnum] == 0L) {
		WSTR("Invalid process number\n");
		exit(20);
	}

	Forbid();	/* task mustn't go away while we fiddle with it */
	port = (UBYTE *)tt[procnum];
	tcb = (struct Task *)(port - sizeof(struct Task));

	/* Now we have a task, let's set its priority */
	(void)SetTaskPri(tcb, pri);	
	Permit();
}

void
usage()
{
	WSTR("usage: cpri [+/-]priority CLI-process-number\n");
	exit(20);
}

isdigstr(s)
char	*s;
{
	register char	*p;
	
	for(p =s ; *p != '\0'; p++)
		if (!isdigit(*p) )
			return 0;
	return 1;
}
FUNKYSTUFF
echo "\tps.Z.b"
cat <<"FUNKYSTUFF" >ps.Z.b
xbtoa Begin
+.\>j!">52Y[G6I"q(bD-t#\6-4'jQA%9KLY(NO?<;?b!aZ0PZSEN:I.KpAKNYo,(&-)]^2]RqC!FU
i)8d-kQ!$ED)!'2N(PQ3FJ+9s!SJ-<)a"%\X^2ZQ75Leqt#M'5KY$95q%(B@qh&bs3V!/qa6"HX%mW
^IU4!,&7'<En",S@9s`B]<$R$]?3$>QJ5S7`XE%!*GeSn^iB<"@raq(kACka1isCZDu&V859-r_U&;
Z!l3^>$@[(#i:"cL!">Y7_5.?dJ2`k4)A7(fV]I<`R!]##Ul1Et/^+@I)"<4\'.mHi]kTi"jN0'L1I
+i"J4K_3>Q[f!4gJ7\Y_C_S$UQq30?&u.ml7YJ/d'b14@'%MZqLH4]YFS@+rpZ?GRVMl#8D3k0h*%%
bQ5Qd+Fl-K'1m^>736E4;;m9Q%e3"-D1pjP)'CmN7N3D##U4n8]HKc`FQB+q!":moTnF+`LnTPC[ch
1S,*HU`MCPnkjG,G38>D.EB_2fdc8F"pPU&5>Sc]a1&=F.uR"7L9q>_Y_$;LTZ5ZUIITu@O)!3gup5
=C9W8,rq5`=o))'S%3NOoRmnj#JJb!U]pk-NF_qW_3=s"?L4<%QIVl22]CVJYN5O+Xru08Iu(IH\+Q
$U&ol1;Aa*6g#o+O8BQMs;CKB_?\ZsC.pjD1>,_RY)?NlL;]a);If0"S)3k:b,*Dsp+G^.A/H)JtJ-
=^6"+otjaMSR*UuB49;-))7![QQs;F(Sm_8*.[h?lLU7')'W\mr8B"qpDT@Y:4d*Pr<eA6<me$lf](
n%UIY4>7XD%,p]#"p9C[_R_L]^r-RJ>k,d@#dJ7KqQd=Z^r$FOn\GO(gi1C<G<Ega$%q2eb6ZHWL_(
3+2dWu5eM3[d%.n;48-C'0T+1kR:k2_N<RZt$3,"(=&R[$6YIkuO1##P*\,d,d+=J?P!?hUu_AABR/
4'Kf";3X#6"Dc*!(dX9%SB1Vm78hNR,NQ(EMBZA!d$gV9GGVH_bUV8!+H9Ce.Rjp'7d%@&KlV^km(&
*1%>`?42G?FBai4;N#;[:2[0E3!$_q,?jJFe#Z2`)pi-pSPPacj^qdi0s+#YYl;I\f"pH-^Z',I=,7
mKLAhYnB&kZPNL$nZ%mQ(AfGZP+is2\h*!(sHs#Q\QTYgiME=Al%ih['CTJl;1"OTR:2$c!!&&V.30
5lbBp`?\/T![,]P!?ms7$$d'f+:`oY,lkmf9JOM+r!,JM#QP?*j2:soiX,jX!<NaaTEGXQ1_9Wj%+K
5=dZC+D'*(<)X%:GP=<\%bX<95t;8E5dUD!o,B*dT:KNbJ)$C=Rt&31R/+=Q26)[qN8C3dVqHK'tt!
^[PlS.'UDJh9]E#9VsiQj3YR`$MEZ'3b<o07^nn"\<&-f[3G3^LN'V$@sXh+9>EVBUqHEYmGbe!!R0
=K8p4h(e9,W=)%mCF!T-K7fbmpA<92!$iit6^]7OJRE.fT&daVXU_sG'8T45o#Sp5<&_\T95_;9:4K
IIl,]Q>c$mL_C(k<11BF/D[nr$nk5nZ`q#XpMsOcT^j,Sa0J4#DosS7.:$>+g\\3(a/Td#Slk^n5?A
6T2FSA/U&/9seFE&=*lZ/`-%=7NbMD7KEYKI.84N+:oCc$ihE+nJt%@cklceKJJL<'O5$=I_-:c5'4
%WhV\\X^]?ef3.Z`?!.YI7i<QYN$;t.85T'>`TI8UZ$,hq`$kQh2;ZK(7(IZ&7rm20K&HdV@0O\,eB
Eq0pP9Q1t^l,d#i*oU"'O:^U(eb*d;ZY#GI0.8%$!h4E"\K1:$qM17=htXhB+r=V!%J6S!%G/6$&e'
m*u_*A)8^n*i!>)=+:K/+hCo0CVEkW2#_O*@=<]f!_$jq+K3nX0fEd)%>lX;K&1lk&3^qUq!!&#n.(
_)87(*Qi808rcd(]81aV(>5`>NVM+BeJ2'D`<C.oqQ[=85?!YuRDDb^]dG:,.Y/f]/_t6-!:)E\5$7
mXQkI-V)MqA\\G!4nJg\%/:,=D"SGjo]%_1?r1n7$(C@>B07$(Y'E+NSf.<C4m9F%GnA':p)GH5$C-
>nF[.S\5_&k/+s=Vc4cY!eX'U6C!Z:j+6KdVV3n!C3!AZoGmG`JH`plD'6)^=c0Yf[+%IG,F!(#.?J
sKmTbQ*H`C=Jc)$a@$)!A+Mk"Pc6B,tR$K$lo<jCdGeAjn1Sk:r,nc;,mUPklh^8P61A$"A+sj%,_]
5IGZCZ-b/1YglV)%W,1RF#XZ];i:</l+Qe/%6Z`;^^m:BdjXZ8,$"[!AS%DA@32>.-CMlb2U#D+6&3
t=[d-&$.U'`9XiZFBr:8![.hCoVsb5MqSRM"QCb]R%nNIG6.h;Jl]^tCW7mP5k&h(+hFqT:G;n#?9%
#YgMo1j<t15Ho.mJ(PpnO63em<1RfSkd)B6?q3Ld&s7knA,u-r843kA!-oPP*<d=sZ44+8$GkZSf<2
Qj5l_36Gl-7R%Q=L0:%!%WgY3$*\%2[WmWQ5>h=!P:!p33q!SI;+ps+)t_>W#=3*RNkLe+j05k'@Er
87iV\A81G
xbtoa End N 2003 7d3 E a6 S 314a0 R aec03052
FUNKYSTUFF
echo "\tcpri.Z.b"
cat <<"FUNKYSTUFF" >cpri.Z.b
xbtoa Begin
+.\>j!">52Y[G6I"q(bD.%j'r-4'jQA(\[jY(KWB<;@o%72l46<k&/qi#f]SHiO<EVpC2P";4T4!T]
'Q7t_/n&9&M;R7EGV/0Gg@/*.*o#,JU]#mS:CIR/`)"jk,F!i75@rnFIAC",F@L7E8QU4l1*!\e#-U
'-:?S[nk..XP3_!$>ufR+6s;R*,L?<WMr.O298HJ-`V]@(>,:_J`6nd0%1V9*<2b+p%B=^gmGh?Eg*
enpm>[mf5':_#jZ@[.L:ZnHe]>$NLHW\m!k^/Pi8d("gON'A?X+s4";]"%\Z4OWmIe-oYhYOFQ\I\h
dbqSLmKD+E1+O?+U_R2uo>.9\J$/-(6i@VMn)'BjCrHTN9=k2-N,JPm50OlBKm)Ft;4-*_57I@gOdl
EFIZfo$CqY?1O4,"r'jtL4g4G3)PGB@?:Kk*-.kF7Z)<KT`YR@K]0ogAUol^*$DU"K+'_i5fXfdm!+
-a!0Ck<MCPpq,)e;*BHrNuo&q<[65#]>)g6nN7N+e>n\uDWb^lN.FgN;])0/i9V3YAXkTuU*Jj?3$B
G.:A5bDKD;?:[Rf@adVf]U=e-LA3FCTk^r8Uqu8;9'Ybd.lT;8:n(b$>"@2jGIZY#f7-H,gc[N?\UR
2$Zho--30)r>/mA'?CL,U8q%]DW,J,^C72*U=[bS/-pYX>#_2r-"VM4i`=PbJ",I!mfDpP:Je4+Y!G
3GS#66#s!MYBJ."^e^@@;ZU*!(T+N^b?=E=N$m%#`lM7&:%')%+_P<<@)m$O/Y:!2+7&<>g<W!<+`-
0E=TL&?ZR;nRF*X8qd'V'#WdD;OT3=+G_n*4BN.''1.uN+Nl\?Cp_Y8;=1c'.&-nWB>A9u5=>JQ"p#
Y6_o+J:5k&V2,((O?59PdoJM_p3NC"30+:S;n!Y"%h,=PjC9/:*=+@BomXFU?l!/Mak'Zl`,_@qHe_
Eu$@Uu2@uWjiEB+<;]CTnr,391&]t!+S=q8.8o80SKlh">tfS!<b*m3%b=Fcj93KC*ML@J.eq[I>.d
G;=0#_5I<\G?,A:aq*t:llMq>a"T6)H!Xu(:!QK(,;fbP2@Km!&S:X-M!Wd=l9*?ZZTaT)4_RJm=_g
sot]$KG0mq+frr:%ZAJ34)WJjE-#a<RsU#s]oD$37/tTopZJXM@#B.La*Z&LQ9;!HfXr5qg7/BE`:P
0Sg\W!>(J$Sde.V$&lQ*!.XN/o`1ZlHMq4O85Oq2m%Xloi+"tYTUikn#/JMuidke5"c$o%\uQ7uJn7
dg#LQud&.3tKOrsdH.X87`3=B$=U6`1e!!/Ycb8^ll5oX?"0,tBC/8)bK%1(n0Pm,QH6\I_>'EJDV;
!_U+R+^YuJ3u#h63n3#i+OC@/<!F2Kt8+O&12(IJE`/I@))fVWX-P/]o7b:jJ"[$!.ZMaLH1Z6JKiM
U/@67%/Q)ScAuYk?.1cLr3%T\9#\h@GK[(2s5S!kA_MI%4+pWJq`73RP(JO0*(oRR*!!#:nZm]C-`e
`_-Q%;Pm!!3u1+l+&BU(8Ddi<_h16cY93)__DJ'1c4-!4_M7#&$Jpe3r+rG3=_/GsVh?i78bgi6CG(
lNImYM*KSN9lL0l?;-12!8?DViICn[!goW5H?TQ2UjtJ:!/**+$&F,K16noi,p7H#b#o@p"Ja?JF\;
@l'9!%p!$HuD4HW=(j?jX%9P,,<+IeuX5^JD6_].aR]JPEf7WKVX)o=iF1ml)fE+nK/_[t:@NcHBD&
Aj"r;7_6Z-8#:[N>.+^'9F'=%I2jk+:RbMcl$55;O%F"llun0BS&16F2_0MisMA+!j$qAKGea55Qj,
e!&KQA.9<su2@ec,E#joaGiFMoRLT@:m?g&fdM/:g@A>q.`EI;8)s4O[F,bbP%j&&5(j(K5+F!u[P^
icjn7)er&:nF*0EiRa+<+BIL.R$u!YBHc-[!K]8O.e+dGj;qSe[B(H%l=EH8ZDOT^<H_<X0ta"!P!>
J.+%<"p(7f$>JOU'S=\:+^b:eB;pOG>R(<Mr,mn;5ah^QVMkFR_\osT#lka)?3![7%EXf%p3J_!5hH
,Js7dH4:b!Y.W.6/55\RT4+G#P%?nF^,`4!G]%M??3FJ<`+49!&*#Eo;-')mY//5-$P:DaQ_reE7f$
NL96QoPbMYW//G%fckX`3jEd!(cI,'/q;Vcu<%d#[gmKW0.1T;hYlinIJ7ibf:p5D24N(A9[f9$m\<
`P3J9@*@Nqh')%)==R9KJ:RDYbFtIUEr!sV1f$"&#7$,=ARG><I+4q^B*NmWI//s2cA$3/%WGuN5qa
6VP)#u`*&qGeJ3$JH\LI)CiBR(Rc*<d;]UYjbY8llo8R)ZM02pLSZ6NROd%^i6*c%&]]qUD8EFTPUg
l2\?jeZb'VXAc6O>2*3\\B_LbGJ.chK-2<>E3qm]JS9=Bi7Q+G[^)6ZC]FG8
xbtoa End N 1917 77d E db S 3115d R a7281ff
FUNKYSTUFF
echo "source file creation complete"
exit 0
---
-- 


----------------------------------------------------------------------
	Dewi Williams.
				uucp:	   ..!ihnp4!druca!dewi
				phone:     (303) 538 4884