c
c Author:
c                     Mark R. Vevle
c                     X-Ray Crystallographic Core Facility
c                     University of Alabama at Birmingham
c                     244 BHS, THT 79
c                     University Station
c                     Birmingham, Alabama  35294
c                     (205) 934 - 1973/2657
c



	Program Smaug
c
	Implicit None
c
	Include '($DVIDef)'
c
	Integer*4	User_Table( 5, 128 )	/ 640* 0 /
	Integer*4	User_Index( 2, 128 )	/ 256* 0 /
c
	Common /UsrTbl/	User_Table,		User_Index
c
	Character*128	Image_Name
	Character*7	Terminal
c
	Common /JpiStr/	Image_Name,		Terminal
c
	Integer*4	Process_Id,		Base_Priority
	Integer*4	Process_State,		Process_Status
	Integer*4	Cpu_Time,		Process_Index
c
	Common /JpiVal/	Process_Id,		Base_Priority,
	1		Process_State,		Process_Status,
	1		Cpu_Time,		Process_Index
c
	Integer*4	Pid,			Io_Status( 2 )
	Integer*4	GetJpi_Flag / 1 /,	GetJpi_List( 24 )
	Integer*4	Image_Length,		Terminal_Length
c
	Common /JpiPrm/	GetJpi_Flag,		Pid,
	1		GetJpi_List,		Io_Status,
	1		Image_Length,		Terminal_Length
c
	Integer*4	Normal_Priority / 4 /,	Lowered_Priority / 3 /
c
	Common /Prior/	Normal_Priority,	Lowered_Priority
c
	Character*64	Physical_Terminal
c
	Integer*4	Item_List( 6 ),	Phys_Term_Length
c
	Common /GetDvi/	Item_List,	Physical_Terminal,
	1		Phys_Term_Length
c
	Integer*2	Short_List( 2, 6 )
c
	Equivalence	( Item_List,	Short_List )
c
	Short_List( 1, 1 ) = 64
	Short_List( 2, 1 ) = DVI$_TT_PHYDEVNAM
	Item_List( 2 ) = %Loc ( Physical_Terminal )
	Item_List( 3 ) = %Loc ( Phys_Term_Length )
	Item_List( 4 ) = 0
	Item_List( 5 ) = 0
	Item_List( 6 ) = 0
c
c *** Boost my Priority to 6
c
	Call Modify_Priority ( 6, 0 )
c
c *** Setup GetJpi request
c
	Call SetUp_GetJpi
c
c *** Go into the monitor loop (we will never return from this loop)
c
	Call Loop
c
	End



	Subroutine Loop
c
	Implicit None
c
	Integer*4	User_Count,		I
c
	Do While ( .True. )
c
c	    *** Check the users
c
	    Call Check_Users ( User_Count )
c
c	    *** Wait for a wakeup call from the system
c
	    If ( User_Count .Le. 2 ) Then
c
c		*** Wait ten minutes before we check again since
c		    we currently do not have enough users on the
c		    system.
c
		Call Lib$Wait ( 600.0 )
c
	    Else
c
		Call Lib$Wait ( 5.0 )
c
	    End If
c
c	    *** Make another pass
c
	End Do
c
	Return
	End



	Subroutine Check_Users ( User_Count )
c
	Implicit None
c
c *** include system return codes
c
	Include '($SSDEF)'
c
	Include 'UsrTbl.For'
	Include 'JpiVal.For'
	Include 'JpiPrm.For'
	Include 'JpiStr.For'
	Include 'GetDvi.For'
	Include 'Prior.For'
c
	Integer*4	Sys$GetJpiW,		Sys$GetDviW
	Integer*4	Jpi_Status,		Wait_Status
	Integer*4	Percent_Used,		User_Count
	Integer*4	Cpu_Used,		Cpu_limit
	Integer*4	User_Ptr,		Priority
	Integer*4	Process,		I
	Integer*4	Active_Users,		K
	Integer*4	Istat
c
	User_Count = 0
	Active_Users = 0
	Pid = -1
c
c	*** Get First Process
c
	Image_Name = '                                ' //
	1	     '                                ' //
	1	     '                                ' //
	1	     '                                '
c
	Jpi_Status = Sys$GetJpiW ( , Pid, , GetJpi_List, , , )
c
	Do While ( Jpi_Status .ne. SS$_NoMoreProc )
c
	    If	( ( Terminal_Length .ne. 0 ) .and.
	1	  ( Base_Priority .le. Normal_Priority ) ) Then
c
		Call Sys$GetDviW ( , , Terminal( : Terminal_Length ),
	1				Item_List, , , , )
c
		If ( Phys_Term_Length .ne. 0 ) Terminal = Physical_Terminal
c
D		Type *, '"' // IMAGE_NAME( :IMAGE_LENGTH)// '"' //
D	1		TERMINAL // '"'
c
		If ( ( Index( Terminal, 'TXA3' ) .ne. 0 ) .and.
	1	     ( Index( Image_Name,
	1	       '[SYSS2.PSFRODO.][EXE]PSFRODO.EXE' ) .ne. 0 ) ) Then
c
c		    *** Ignore FRODO programs when run from the graphics
c			terminal and at normal or increased priority.
c
		    User_Count = User_Count + 1
c
		    If ( Base_Priority .eq. Lowered_Priority )
	1		Call Modify_Priority (	Normal_Priority,
	1					Process_Id )
c
		Else If ( ( Index( Image_Name,
	1		    'DUA0:[SYS0.][SYSEXE]' ) .ne. 0 ) .and.
	1		  ( Index( Image_Name, 'FORTRAN' ) .eq. 0 ) .and.
	1		  ( Index( Image_Name, 'LINK' ) .eq. 0 ) .and.
	1		  ( Index( Image_Name, 'BACKUP' ) .eq. 0 ) .and.
	1		  ( Index( Image_Name, 'MACRO32' ) .eq. 0 ) .and.
	1		  ( Index( Image_Name, 'VAX11C' ) .eq. 0 ) .and.
	1		  ( Index( Image_Name, 'VAXC' ) .eq. 0 ) ) Then
c
c		    *** Ignore SYSTEM programs and be sure they are
c			running at normal priority
c
		    User_Count = User_Count + 1
c
		    If ( Base_Priority .eq. Lowered_Priority )
	1		Call Modify_Priority (	Normal_Priority,
	1					Process_Id )
c			
		Else
c
c		    *** Determine how much of the CPU is being used by
c			this process.
c
		    Active_Users = Active_Users + 1
		    User_Count = User_Count + 1
		    Call Cpu_Usage( Active_Users )
c
		End If
c
	    Else If ( Terminal_Length .ne. 0 ) Then
c
		User_Count = User_Count + 1
c
	    End if
c
	    Image_Name = '                                ' //
	1		 '                                ' //
	1		 '                                ' //
	1		 '                                '
c
c	    *** Get the next Process
c
	    Jpi_Status = Sys$GetJpiW ( , Pid, , GetJpi_List, , , )
c
c	     *** Keep going
c
	End do
c
c	*** Now modify priorities
c
	If ( User_Count .gt. 0 ) Then
c
	    Cpu_Limit = 100 / User_Count
c
D	    Type 30, Cpu_Limit, User_Count, Active_Users
c
	    Do I = 1, Active_Users
c
		User_Ptr = User_Index( 2, I )
		Process  = User_Index( 1, I )
		Cpu_Used = User_Table( 4, User_Ptr )
		Priority = User_Table( 5, User_Ptr )
c
D		Type 10, User_Index( 1, I ), User_Index( 2, I )
D		Type 20, Cpu_Used, Priority
c
		If ( ( Cpu_Used .ge. Cpu_Limit ) .and.
	1	     ( Priority .eq. Normal_Priority ) .and.
	1	     ( Process  .gt. 0 ) ) Then
c
c		    *** This user needs to have his priority reduced
c
D		    Type *, '%SMAUG-D-DRPPRI, reduce priority'
c
		    Call Modify_Priority (	Lowered_Priority,
	1					Process )
c
		Else If ( ( Cpu_Used .lt. Cpu_Limit ) .and.
	1		  ( Priority .eq. Lowered_Priority ) .and. 
	1		  ( Process  .gt. 0 ) ) Then
c
c		    *** This user can have his priority raised back
c			to normal
c
D		    Type *, '%SMAUG-D-INCPRI, increase priority'
c
		    Call Modify_Priority (	Normal_Priority,
	1					Process )
c
		End If
c
	    End Do
c
	End If
c
D10	Format ( //, ' %SMAUG-D-CANDIDATE, User:', Z10.8,
D	1	' Pointer:', Z10.8 )
D20	Format ( ' %SMAUG-D-VALUES, CPU Used: ', I4, ' Priority: ', I2 )
D30	Format ( //, ' %SMAUG-D-CONTROL, CPU Limit:', I4, ' User count: ',
D	1	     I4, ' Active users: ', I4 )
c
	Return
	End



	Subroutine Cpu_Usage ( User_Count )
c
	Implicit None
c
	Include 'UsrTbl.For'
	Include 'JpiVal.For'
c
	Integer*4	Elapsed_Time( 2 ),	Cpu_used
	Integer*4	Old_Cpu_Time,		Percent_Cpu
	Integer*4	User_Count,		Timer_Status
c
	Integer*4	Lib$Init_Timer,		Lib$Stat_Timer
c
	Integer*2	User_Ptr
c
	User_Ptr = Process_Index
	User_Index( 1, User_Count ) = Process_id
	User_Index( 2, User_Count ) = Process_Index
	User_Table( 5, User_Ptr ) = Base_Priority
c
c *** Get Elapsed Time
c
	If ( User_Table( 1, User_Ptr ) .eq. 0 ) Then
c
c	    *** We have a new user to enter in the process table
c		Also start a timer for this user
c
	    Timer_Status = Lib$Init_Timer( User_Table( 1, User_Ptr ) )
	    If ( .not. Timer_Status ) Call Exit ( Timer_Status )
	    User_Table( 3, User_Ptr ) = Cpu_Time
	    User_Table( 4, User_Ptr ) = 0
c
	Else 
c
c	    *** Get the elapsed time
c
	    Timer_Status = Lib$Stat_Timer( 1, Elapsed_Time,
	1				   User_Table( 1, User_Ptr ) )
c
c	    *** Restart timer for this user
c
	    Timer_Status = Lib$Init_Timer( User_Table( 1, User_ptr ) )
c
	    If ( Process_State .ne. 2 ) Then
c
c		*** Process is not in the dreaded 'MWAIT' state
c
		Old_Cpu_Time = User_Table( 3, User_ptr )
		User_Table( 3, User_ptr ) = Cpu_Time
		Cpu_used = ( Cpu_Time - Old_Cpu_Time ) * 100
c
		If ( Cpu_Used .gt. 0 )  Then
c
c		    *** Calculate amount of CPU used.
c
		    Percent_Cpu = Abs(Elapsed_Time( 1 ) / 100000)
		    Percent_Cpu = Cpu_Used / Percent_Cpu
c
c		    *** Save the amount of CPU used by this process
c
		    User_Table( 4, User_Ptr ) = Percent_Cpu
c
		Else
c
c		    *** The user has not used any cpu time
c
		    User_Table( 4, User_Ptr ) = 0
c
		End If
c
	    Else
c
c		*** The user is in the awful 'MWAIT' state so do
c		    not do anything
c
		User_Table( 1, User_ptr ) = 0
		User_Table( 4, User_Ptr ) = 0
c
	    End If
c
	End If
c
	Return
	End



	Subroutine Modify_Priority ( New_Priority, User_Pid )
c
	Implicit None
c
	Integer*4	New_Priority,		User_Pid 
	Integer*4	Sys$SetPri,		Return_Status
c
	If ( User_Pid .eq. 0 ) Then
c
c	    *** Modify my priority
c
	    Return_Status = Sys$SetPri( , , %Val ( 6 ), )
c
	Else
c
c	    *** Modify someone else's priority
c
	    Return_Status = Sys$SetPri( User_Pid, , %Val ( New_Priority ), )
c
	End If
c
D	If ( .not. Return_Status ) Then
D		Call Errrec( Return_Status )
D		Type 10, User_Pid, New_Priority
D	End If
c
	Return
c
D10	Format ( '-SMAUG-E-MODPRIFAIL, failure to modify priority of ',
D	1	 Z10.8, ' to ', I4 )
	End



	Subroutine Setup_GetJpi
c
	Implicit None
c
c	*** Job/Process information request type codes ***
c
	Include '($JPidef)'
c
	Include 'JpiStr.For'
	Include 'JpiVal.For'
	Include 'JpiPrm.For'
c
	Integer*2	Short_List( 2, 24 )
c
	Equivalence (	GetJpi_List,	Short_List	)
c
c *** Set up the Jpi request (never changes) ***
c
c *** Base Priority
	short_List( 1, 1 )	= 4
	short_List( 2, 1 )	= Jpi$_Prib
	GetJpi_List( 2 )	= %Loc ( Base_Priority )
	GetJpi_List( 3 )	= 0
c *** Image Name
	short_List( 1, 4 )	= 128
	short_List( 2, 4 )	= Jpi$_ImagName
	GetJpi_List( 5 )	= %Loc ( Image_Name )
	GetJpi_List( 6 )	= %Loc ( Image_Length )
c *** Current State
	short_List( 1, 7 )	= 4
	short_List( 2, 7 )	= Jpi$_State
	GetJpi_List( 8 )	= %Loc ( Process_State )
	GetJpi_List( 9 )	= 0
c *** Terminal
	short_List( 1, 10 )	= 7
	short_List( 2, 10 )	= Jpi$_Terminal
	GetJpi_List( 11 )	= %Loc ( Terminal )
	GetJpi_List( 12 )	= %Loc ( Terminal_Length )
c *** Process Identification
	short_List( 1, 13 )	= 4
	short_List( 2, 13 )	= Jpi$_Pid
	GetJpi_List( 14 )	= %Loc ( Process_id )
	GetJpi_List( 15 )	= 0
c *** Cpu Time
	short_List( 1, 16 )	= 4
	short_List( 2, 16 )	= Jpi$_CpuTim
	GetJpi_List( 17 )	= %Loc ( Cpu_Time )
	GetJpi_List( 18 )	= 0
c *** Process_Index
	short_List( 1, 19 )	= 4
	short_List( 2, 19 )	= Jpi$_Proc_Index
	GetJpi_List( 20 )	= %Loc ( Process_Index )
	GetJpi_List( 21 )	= 0
c *** Mark end of options
	GetJpi_List( 22 )	= 0
	GetJpi_List( 23 )	= 0
	GetJpi_List( 24 )	= 0
c
	Return
	End



	subroutine errrec( status )
c
c *** declarations
c
	integer*4	status,	sys$putmsg,	msg_stat,	arg_vct(2)
	integer*2	s_arg_vct(4)
c
	equivalence(	arg_vct,	s_arg_vct	)
c
	s_arg_vct( 1 ) = 1
	s_arg_vct( 2 ) = 0
	arg_vct( 2 ) = status
	msg_stat = sys$putmsg( arg_vct, , , )
	if ( .not. msg_stat ) stop '-RMDEMO-F-NORECOV, unable to recover.'
c
	return
	end
