|  | >Look in the VMS sources, at routine EXE$FORCEX. This routine queues a user-mode
>AST to a target process, with the AST's service-routine being SYS$EXIT.
>It should not be too difficult to extend this code to do what you wish.
I once did this (although I don't have the code right now...) it is very
easy, the $FORCEX code works just as it is.
The only snag is that the AST to be executed by the other process has to
be either in system space (maybe in a bit of nonpaged pool) or in its process
space. I wrote a profiler (we were too cheap to buy PCA :-) which required
the process being profiled to be linked with the AST code in a based cluster
at some large address like %X100000 . The AST did things like looking back
through the stack to get call frame information, if the current PC was not
in any known routine of the program. As far as I know, the presence of the
AST code doesn't affect the program in any way, although it does sometimes
reshuffle a few virtual addresses. 
I may be able to post code if you need it.
= Giles =
 | 
|  | In the code that follows the <FF>, ASTADR is presumed to be the address of
the AST in the *other_guy's* process space. You can put it there by linking
the other process' image with a based cluster:
$ LINK blah,blah,sys$input/options
cluster=ast_code,%X100000,,ast_code.obj
Then use 100000 (hex) as the value of ASTADR.
= Giles =
	.title	QAST - que an AST to another process.
        .library	/SYS$LIBRARY:LIB.MLB/
	$acbdef
	$ipldef
	$pcbdef
	$prdef
	$pridef
	$ssdef
;
epid=4
prcnam=8
astadr=12
astprm=16
;
        .PSECT	KERNEL_QAST,con,exe,nowrt,long
;
; CALLING SEQUENCE:
;	integer*4 epid,astprm,QAST
;	character*12 prcnam                  ! or 0
;	external ASTADR
;	iret=QAST(epid,prcnam,%LOC(ASTADR),astprm)
;
; INPUT PARAMETERS:
;	epid(ap)   - address of pid (r/w)
;	prcnam(ap) - address of process name (descr) or 0 if using pid
;	astadr(ap) - address of ast within the process' space (***by ref***)
;	astprm(ap) - ast parameter
;
; OUTPUT PARAMETERS:
;	epid(ap)   - pid of process for which exit was forced
;	QAST       - completion status
;
; COMPLETION CODES:
;	ss$_normal  -  successful completion
;	ss$_accvio  -  cant read arg list
;
	.entry	QAST,^M<R2,R3,R4,R5>
;
	$cmkrnl_s -
		routin=kernel_qast,-
		arglst=(ap)
	ret
;
        .entry	KERNEL_QAST,^m<r2,r3,r4,r5>
;
	ifnord	#4,astadr(ap),30$	; other 2 checked by EXE$NAMPID
	ifnord	#4,astprm(ap),30$
	movl	g^SCH$GL_CURPCB,r4
	jsb	g^EXE$NAMPID		; name to PID
	setipl	#0
	blbc	r0,20$
	pushl	r1
	jsb	g^EXE$ALLOCIRP		; give us an IRP to make an ACB
	blbc	r0,20$
;
	movb	#3,acb$b_rmod(r2)	; build an ACB for user mode
	movl	(sp)+,acb$l_pid(r2)
	movl	@astadr(ap) ,acb$l_ast(r2)
	movl	@astprm(ap),acb$l_astprm(r2)
	movl	r2,r5
	movzbl	#pri$_resavl,r2
;
	jsb	g^SCH$QAST		; queue the ACB
;
	movzwl	#ss$_normal,r0
20$:	ret
;
30$:	movzwl	#ss$_accvio,r0		; error return
	ret
;
	.end
 | 
|  |     Thanks. It's much simpler than I thought it would be.
    
    Now, since I can't force everything on the system to be linked with
    a fixed base code segment, I wonder if there is some scratch space
    in the allocated IRP/ACB wherein I could put the CALL/RET and arglist
    for the system service call I desire to have executed. Also, if
    I put this stuff in the IRP, can the acmode of the AST stay 'user'?
    
    Dave
 |