From:	CRDGW2::CRDGW2::MRGATE::"SMTP::CRVAX.SRI.COM::RELAY-INFO-VAX" 26-FEB-1992 20:12:00.86
To:	ARISIA::EVERHART
CC:	
Subj:	Re: Process State Detection as an Event

From:	RELAY-INFO-VAX@CRVAX.SRI.COM@SMTP@CRDGW2
To:	Everhart@Arisia@MRGATE

Received:  by crdgw1.ge.com (5.57/GE 1.123)
	 id AA14274; Wed, 26 Feb 92 19:23:39 EST
Received: From UCBVAX.BERKELEY.EDU by CRVAX.SRI.COM with TCP; Wed, 26 FEB 92 15:03:31 PST
Received: by ucbvax.Berkeley.EDU (5.63/1.43)
	id AA01908; Wed, 26 Feb 92 14:47:47 -0800
Received: from USENET by ucbvax.Berkeley.EDU with netnews
	for info-vax@kl.sri.com (info-vax@kl.sri.com)
	(contact usenet@ucbvax.Berkeley.EDU if you have questions)
Date: 22 Feb 92 09:15:27 GMT
From: van-bc!rsoft!agate!spool.mu.edu!sdd.hp.com!elroy.jpl.nasa.gov!news.claremont.edu!lucy.claremont.edu!jwilkinson@ucbvax.Berkeley.EDU
Organization: Harvey Mudd College
Subject: Re: Process State Detection as an Event
Message-Id: <1992Feb22.011527.1@lucy.claremont.edu>
References: <1992Feb19.013724.12701@colorado.edu>, <1992Feb19.072622.288@cmkrnl.com>
Sender: info-vax-request@kl.sri.com
To: info-vax@kl.sri.com

In article <1992Feb19.072622.288@cmkrnl.com>, jeh@cmkrnl.com writes:
> In article <1992Feb19.013724.12701@colorado.edu>,
>  toupine@ciaibbs.Colorado.EDU (edward toupin) writes:
>> PROBLEM
>> 
>> 	I need a way to monitor the states of some of these HIBernating
>> 	processes to detect when they are awakened.
>>
>> QUESTION
>> 
>> 	Is there a smart way of detecting an event (i.e. state change)
>> 	of a process from another process other than $GETJPI?
> 
> Not without some serious kernel-mode hacking.  You'd be better off finding
> the $WAKE call in the process in question and patching in a $WAKE to your
> monitor process.  
> 
>> 	Can an AST be useful is this case?
> 
> No, ASTs (other than special kernel ASTs) are only delivered to the process
> that requests them.
> 
>> 	Are any system flags available that can be detected to
>> 	test for state change?
> 
> For a generalized "state change", no.  Calling $WAKE sets a "wake pending" 
> bit in the Process Control Block.  However, this bit is not set for long, and
> in any case you can't look at it without getting into at least executive mode.
> 
>> 	Is there a way to intercept the system call SYS$WAKE() when
>> 	it is placed to another process?
> 
> Again, not without some kernel-mode hacking.
> 
> Look.  The reason you didn't get a satisfactory response the last time you
> posted this was not that your request was worded poorly.  We understood what
> you wanted the first time.  Unfortunately, what you want isn't possible with
> VMS as shipped. 
> 
> I suppose you could hack RSE (Report System Event -- a part of the exec to
> which "events" which may make processes computable are reported) to do a $WAKE
> on a designated process when another designated process was made computable.
> However it would be moderately costly, as every trip through RSE would involve
> a search ("is this process one that I'm monitoring?"), unless you find a
> longword in the watched process's PCB that you could steal for the purpose
> (risky).  Uh, don't bother searching the Grey Wall for RSE -- it's described 
> in the internals manual.
> 
> Perhaps this discussion will prod someone with more free time than I have to
> write such an "RSE interceptor"...
> 
> 	--- Jamie Hanrahan, Kernel Mode Consulting, San Diego CA

One may solve the problem by using a watchpoint.  I needed something similar to
what the original poster wanted, so I wrote a short program to list of state
changes of a given process.  I believe that state changes that happen close
together may be somewhat out of order (maybe the way I programmed it), but this
still has its uses.  One may use WP (in SYS$SYSTEM) to generate equivalent
information, although this program lends itself a little better to the problem.

I don't know how reliable WPDRIVER is, so use this with caution.  This code
should run on VMS V4.0 and higher, and requires PHY_IO and CMEXEC privileges.
Don't forget to install the driver.

JaW

jwilkinson@hmcvax.claremont.edu

$! ------------------ CUT HERE -----------------------
$ v='f$verify(f$trnlnm("SHARE_VERIFY"))'
$!
$! This archive created by VMS_SHARE Version 7.2-007  22-FEB-1990
$!   On 22-FEB-1992 00:51:24.31   By user JWILKINSON 
$!
$! This VMS_SHARE Written by:
$!    Andy Harper, Kings College London UK
$!
$! Acknowledgements to:
$!    James Gray       - Original VMS_SHARE
$!    Michael Bednarek - Original Concept and implementation
$!
$! TO UNPACK THIS SHARE FILE, CONCATENATE ALL PARTS IN ORDER
$! AND EXECUTE AS A COMMAND PROCEDURE  (  @name  )
$!
$! THE FOLLOWING FILE(S) WILL BE CREATED AFTER UNPACKING:
$!       1. GET_STATE_ADDRESS.MAR;1
$!       2. STATE.FOR;1
$!
$set="set"
$set symbol/scope=(nolocal,noglobal)
$f=f$parse("SHARE_TEMP","SYS$SCRATCH:.TMP_"+f$getjpi("","PID"))
$e="write sys$error  ""%UNPACK"", "
$w="write sys$output ""%UNPACK"", "
$ if f$trnlnm("SHARE_LOG") then $ w = "!"
$ ve=f$getsyi("version")
$ if ve-f$extract(0,1,ve) .ges. "4.4" then $ goto START
$ e "-E-OLDVER, Must run at least VMS 4.4"
$ v=f$verify(v)
$ exit 44
$UNPACK: SUBROUTINE ! P1=filename, P2=checksum
$ if f$search(P1) .eqs. "" then $ goto file_absent
$ e "-W-EXISTS, File ''P1' exists. Skipped."
$ delete 'f'*
$ exit
$file_absent:
$ if f$parse(P1) .nes. "" then $ goto dirok
$ dn=f$parse(P1,,,"DIRECTORY")
$ w "-I-CREDIR, Creating directory ''dn'."
$ create/dir 'dn'
$ if $status then $ goto dirok
$ e "-E-CREDIRFAIL, Unable to create ''dn'. File skipped."
$ delete 'f'*
$ exit
$dirok:
$ w "-I-PROCESS, Processing file ''P1'."
$ if .not. f$verify() then $ define/user sys$output nl:
$ EDIT/TPU/NOSEC/NODIS/COM=SYS$INPUT 'f'/OUT='P1'
PROCEDURE Unpacker ON_ERROR ENDON_ERROR;SET(FACILITY_NAME,"UNPACK");SET(
SUCCESS,OFF);SET(INFORMATIONAL,OFF);f:=GET_INFO(COMMAND_LINE,"file_name");b:=
CREATE_BUFFER(f,f);p:=SPAN(" ")@r&LINE_END;POSITION(BEGINNING_OF(b));
LOOP EXITIF SEARCH(p,FORWARD)=0;POSITION(r);ERASE(r);ENDLOOP;POSITION(
BEGINNING_OF(b));g:=0;LOOP EXITIF MARK(NONE)=END_OF(b);x:=ERASE_CHARACTER(1);
IF g=0 THEN IF x="X" THEN MOVE_VERTICAL(1);ENDIF;IF x="V" THEN APPEND_LINE;
MOVE_HORIZONTAL(-CURRENT_OFFSET);MOVE_VERTICAL(1);ENDIF;IF x="+" THEN g:=1;
ERASE_LINE;ENDIF;ELSE IF x="-" THEN IF INDEX(CURRENT_LINE,"+-+-+-+-+-+-+-+")=
1 THEN g:=0;ENDIF;ENDIF;ERASE_LINE;ENDIF;ENDLOOP;t:="0123456789ABCDEF";
POSITION(BEGINNING_OF(b));LOOP r:=SEARCH("`",FORWARD);EXITIF r=0;POSITION(r);
ERASE(r);x1:=INDEX(t,ERASE_CHARACTER(1))-1;x2:=INDEX(t,ERASE_CHARACTER(1))-1;
COPY_TEXT(ASCII(16*x1+x2));ENDLOOP;WRITE_FILE(b,GET_INFO(COMMAND_LINE,
"output_file"));ENDPROCEDURE;Unpacker;QUIT;
$ delete/nolog 'f'*
$ CHECKSUM 'P1'
$ IF CHECKSUM$CHECKSUM .eqs. P2 THEN $ EXIT
$ e "-E-CHKSMFAIL, Checksum of ''P1' failed."
$ ENDSUBROUTINE
$START:
$ create 'f'
X`09.title`09GET_STATE_ADDRESS routine`09`09; title
X`09.ident`09"V1.00"`09`09`09`09`09; version information
X;+
X;`09GET_STATE_ADDRESS.MAR - given an extended process identification
X;`09`09`09`09longword, this routine returns the address of
X;`09`09`09`09the state word in the process control block.
X;
X;`0921 February 1992`09James Wilkinson
X;-
X`09.link`09 "SYS$SYSTEM:SYS.STB" /selective_search
X`09.library "SYS$LIBRARY:LIB.MLB"
X
X`09$pcbdef`09`09`09`09`09`09; process control block
X`09$ssdef`09`09`09`09`09`09; system services def
X
X`09.psect`09$LOCAL`09pic,noshr,rd,wrt,noexe,byte`09; local data
X
Xargs:`09.long`091`09`09`09`09`09; one argument
Xvar:`09.blkl`091`09`09`09`09`09; epid -> pcb+state
X
X`09.psect`09$CODE`09pic,shr,rd,nowrt,exe`09`09; code follows
X
X`09.entry`09GET_STATE_ADDRESS, `5Em<>`09`09`09; entry point
X
X`09movl`09@4(ap), var
X`09$CMEXEC_S`09routin=10$, -`09`09`09; executive mode code
X`09`09`09arglst=args`09`09`09; with epid input
X`09addl3`09var,#PCB$W_STATE,@4(ap)`09`09`09; return pcb+state
X`09ret
X
X10$:`09.word`09`5Em<>
X`09movl`094(ap), r0`09`09`09`09; EPID in r0
X`09jsb`09g`5EEXE$EPID_TO_PCB`09`09`09; convert to PCB addr
X`09bneq`0920$`09`09`09`09`09; we are happening
X`09movzwl`09#SS$_NONEXPR, r0`09`09`09; no such luck
X`09brb`0930$`09`09`09`09`09; get out
X20$:`09movl`09r0, 4(ap)`09`09`09`09; save address
X`09movzwl`09#SS$_NORMAL, r0`09`09`09`09; it worked out
X30$:`09ret`09`09`09`09`09`09; back to user mode
X
X`09.end`09`09`09`09`09`09; end GET_STATE_ADDRESS
$ CALL UNPACK GET_STATE_ADDRESS.MAR;1 1296911050
$ create 'f'
X****************************************************************************
V****
X*                                                                        `20
V     *
X*  STATE - program to list state changes using WPDRIVER.  To setup your syst
Vem *
X*`09   for this program, you need to install WPDRIVER:                     *
X*              $ MCR SYSGEN
V                                                    *
X*`09       SYSGEN> CONNECT WPA /NOADAPTER /DRIVER=WPDRIVER                 *
X*`09   Determine the pid of the process you wish to watch, then run this   *
X*`09   program.  A watchpoint is set on the appropriate word for the       *
X*`09   process, and changes of state are listed, as well as the time of    *
X*`09   the change, until you hit a Crtl-Y.  Note that these states don't   *
X*`09   always seem to be in order - changes which are very close together  *
X*`09   time-wise may be out of order.  Note that SYS$SYSTEM:WP.EXE will    *
X*          also list aspects relating to a watchpoint - this program is
V        *
X*          intended to provide an example of such functionality from within
V    *
X*          one's own code.
V                                                     *
X*                                                                        `20
V     *
X*                              *** CAUTION ***
V                                 *
X*          This program relies on an unsupported driver, which may affect yo
Vur *
X*`09   system in some adverse way when used by this program.  Use at your  *
X*`09   own risk.                                                           *
X*                                                                        `20
V     *
X*          21 February 1992  James Wilkinson (jwilkinson@hmcvax.claremont.ed
Vu) *
X*                                                                        `20
V     *
X*          Reference: Hunter Goatley, VAX Professional, Dec '90, p. 25
V         *
X*                                                                        `20
V     *
X****************************************************************************
V****
X
X`09program state
X
X`09implicit none
X
X`09include '($SYSSRVNAM)/nolist'`09`09`09! system service names
X`09include '($IODEF)/nolist'`09`09`09! I/O definitions
X
X`09structure /control_block/`09`09`09! watchpoint control
X`09`09`09`09`09`09`09! block
X`09  integer*4
X`091`09WPCB$Q_INITCNTNTS(2)
X`09  integer*2
X`091`09WPCB$W_SIZE
X`09  byte
X`091`09WPCB$B_TYPE,
X`091`09WPCB$B_RESERVED01,
X`091`09WPCB$B_FLD_LEN,
X`091`09WPCB$B_STATE
X`09  integer*2
X`091`09WPCB$W_RESERVED02
X`09  integer*4
X`091`09WPCB$L_LINK,
X`091`09WPCB$L_WPRE,
X`091`09WPCB$L_FLD_ADR,
X`091`09WPCB$L_FLD_ADR1,
X`091`09WPCB$L_FLD_ADR2,
X`091`09WPCB$L_FLD_ADR3,
X`091`09WPCB$L_FLD_ADR4,
X`091`09WPCB$L_FLD_ADR5,
X`091`09WPCB$L_FLD_ADR6,
X`091`09WPCB$L_FLD_ADR7,
X`091`09WPCB$L_TOUCHED,
X`091`09WPCB$L_COUNT,
X`091`09WPCB$L_TTE,
X`091`09WPCB$L_PC,
X`091`09WPCB$L_PSL,
X`091`09WPCB$Q_TIME(2),
X`091`09WPCB$L_R0,
X`091`09WPCB$L_R1,
X`091`09WPCB$L_R2,
X`091`09WPCB$L_R3,
X`091`09WPCB$L_R4,
X`091`09WPCB$L_R5,
X`091`09WPCB$L_R6,
X`091`09WPCB$L_R7,
X`091`09WPCB$L_R8,
X`091`09WPCB$L_R9,
X`091`09WPCB$L_R10,
X`091`09WPCB$L_R11,
X`091`09WPCB$L_AP,
X`091`09WPCB$L_FP,
X`091`09WPCB$L_SP
X`09  byte
X`091`09WPCB$B_BCNT
X`09  character*15
X`091`09WPCB$T_ISTREAM
X`09  integer*4
X`091`09WPCB$Q_PREVCNTNTS(2),
X`091`09WPCB$Q_POSTCNTNTS(2)
X
X`09end structure
X
X`09structure /tte_block/`09`09`09`09! watchpoint TTE block
X
X`09  integer*4
X`091`09WPTTE$L_FIELD
X`09  byte
X`091`09WPTTE$B_TOUCHED,
X`091`09WPTTE$B_OPCODE
X`09  integer*2
X`091`09WPTTE$W_RELBCKPTR
X`09  integer*4
X`091`09WPTTE$L_PC,
X`091`09WPTTE$L_PSL,
X`091`09WPTTE$Q_TIME(2)
X`09  union
X`09    map
X`09      integer*4
X`091`09WPTTE$Q_PREVCNTNTS(2)
X`09    end map
X`09    map
X`09      integer*2
X`091`09state
X`09    end map
X`09  end union
X
X`09end structure
X
X`09structure /statistics_block/`09`09`09! watchpoint stat block
X
X`09  integer*4
X`091`09WPSTAT$L_BCNT,
X`091`09WPSTAT$L_TOTAL_TTE,
X`091`09WPSTAT$L_TTE_COPIED
X`09  record /control_block/
X`091`09cb
X`09  record /tte_block/
X`091`09tte(1000)`09`09`09`09! allow for 1K TTEs
X
X`09end structure
X
X`09structure /handle/`09`09`09`09! exit handler block
X`09  integer*4
X`091`09forward_link,
X`091`09exit_handler,
X`091`09argument_count,
X`091`09condition_value,
X`091`09p1,
X`091`09p2
X`09end structure
X
X`09real*4
X`091`09wait_interval
X`09parameter
X`091`09(wait_interval = 3.)`09`09`09! scan interval (secs)
X
X`09character*(*)
X`091`09control_string
X`09parameter
X`091`09(control_string = '!5AS !%D')`09`09! output format
X
X`09character*80
X`091`09message`09`09`09`09`09! output message
X
X`09integer*2
X`091`09io_status_block(4)`09`09`09! I/O status block
X
X`09integer*4
X`091`09io_status,`09`09`09`09! FORTRAN I/O status
X`091`09state_address,`09`09`09`09! address of state word
X`091`09channel,`09`09`09`09! I/O channel
X`091`09statistics_size,`09`09`09! size of stat block
X`091`09tte_listed,`09`09`09`09! # of entries listed
X`091`09tte_delta,`09`09`09`09! # of TTE no yet listed
X`091`09tte_index,`09`09`09`09! index into TTE array
X`091`09message_length,`09`09`09`09! output length
X`091`09status,`09`09`09`09`09! completion status
X`091`09get_state_address`09`09`09! obtain pcb+state addr
X
X`09record /handle/
X`091`09exit_block`09`09`09`09! exit handler block
X
X`09record /statistics_block/
X`091`09statistics`09`09`09`09! WP information
X
X`09character*5
X`091`09process_state(0:15)`09`09`09! ascii state reps
X`091`09/'?????','COLPG','MWAIT','  CEF','  PFW','  LEF',' LEFO',
X`091`09 '  HIB',' HIBO',' SUSP','SUSPO','  FPG','  COM',' COMO',
X`091`09 '  CUR','?????'/
X
X`09external
X`091`09exit_handler
X
X`09! begin code
X`09!
X`09io_status = 1
X
X`09do while (io_status .ne. 0)`09`09`09! get process id
X`09  write (6, '(x,''Pid: '',$)')
X`09  read (5, '(z8.8)', iostat=io_status)
X`091`09state_address`09`09`09`09! will become address
X`09end do
X
X`09status = get_state_address (state_address)`09! convert pid to addr
X`09call check (status)
X
X`09status = SYS$ASSIGN (`09`09`09`09! contact WPDRIVER
X`091`09`09'WPA0:',
X`091`09`09channel,,,
X`091`09`09)
X`09call check (status)
X
X`09status = SYS$QIOW (,`09`09`09`09! initiate a watchpoint
X`091`09`09%val(channel),
X`091`09`09%val(IO$_ACCESS),
X`091`09`09io_status_block,,,,
X`091`09`09%val(2),`09`09`09! watch two bytes
X`091`09`09%val(state_address),,,`09`09! at this address
X`091`09`09)
X`09if (status) status = zext(io_status_block(1))
X`09call check (status)
X
X`09! prepare information for exit handler
X`09!
X`09exit_block.exit_handler = %loc(exit_handler)
X`09exit_block.argument_count = 3
X`09exit_block.condition_value = %loc(status)
X`09exit_block.p1 = %loc(channel)
X`09exit_block.p2 = %loc(state_address)
X
X`09status = SYS$DCLEXH (`09`09`09`09! declare exit handler
X`091`09`09exit_block
X`091`09`09)
X`09call check (status)
X
X`09statistics_size = sizeof(statistics)`09`09! info we can handle
X
X`09do while (.true.)`09`09`09`09! loop forever
X
X`09  status = SYS$QIOW (,`09`09`09`09! get statistics
X`091`09`09%val(channel),
X`091`09`09%val(IO$_RDSTATS),
X`091`09`09io_status_block,,,
X`091`09`09statistics,`09`09`09! buffer address
X`091`09`09%val(statistics_size),`09`09! size of buffer
X`091`09`09%val(state_address),,,`09`09! watchpoint address
X`091`09`09)
X`09  if (status) status = zext(io_status_block(1))
X`09  call check (status)
X
X`09  ! check for any now TTEs
X`09  !
X`09  tte_delta = statistics.WPSTAT$L_TOTAL_TTE - tte_listed
X
X`09  if (tte_delta .gt. 0) then
X
X`09    ! scan new entries in inverse order to print out latest last
X`09    !
X`09    do tte_index=tte_delta,1,-1
X
X`09      status = SYS$FAO (`09`09`09! format the output
X`091`09`09control_string,`09`09`09! format control string
X`091`09`09message_length,`09`09`09! size of output
X`091`09`09message,`09`09`09! output buffer
X`091`09`09process_state(statistics.tte(tte_index).state),! state
X`091`09`09statistics.tte(tte_index).WPTTE$Q_TIME ! time of change
X`091`09`09)
X`09      call check (status)
X
X`09      type *, message(:message_length)`09`09! emit message
X
X`09    end do
X
X`09    tte_listed = statistics.WPSTAT$L_TOTAL_TTE`09! update TTE pointer
X
X`09  end if
X
X`09  call LIB$WAIT (wait_interval)`09`09`09! wait a spell
X
X`09end do
X
X`09end
X
X****************************************************************************
V****
X
X`09subroutine exit_handler (status, channel, state_address) ! clean up
X
X`09implicit none
X
X`09include '($IODEF)/nolist'`09`09`09! I/O definitions
X
X`09integer*4
X`091`09status,`09`09`09`09`09! final status
X`091`09channel,`09`09`09`09! channel to WPA0:
X`091`09state_address`09`09`09`09! watchpoint address
X
X `09call SYS$QIOW (,`09`09`09`09! cancel watchpoint
X`091`09`09%val(channel),
X`091`09`09%val(IO$_DEACCESS),,,,,,
X`091`09`09%val(state_address),,,`09`09! watchpoint address
X`091`09`09)
X
X`09call SYS$DASSGN (`09`09`09`09! deassign channel
X`091`09`09%val(channel)
X`091`09`09)
X
X`09end
X
X****************************************************************************
V****
X
X`09subroutine check (status)`09`09`09! check status longword
X
X`09implicit none
X
X`09integer*4
X`091`09status
X
X`09if (.not. status) call LIB$STOP (%val(status))`09! whine and die if bad
X
X`09return
X`09end
$ CALL UNPACK STATE.FOR;1 643116076
$ v=f$verify(v)
$ EXIT

