phillip@cbmvax.UUCP (03/30/87)
[yeah, bugs come and go, but COBOL insists on staying...] In the process structure you will find a field labeled "pr_PktWait." This is a pointer for a alternate wait routine for AmigaDOS message handling. Everytime the AmigaDOS taskwait() routine is called a check is made to see if the process PktWait field is non-zero...if non-zero a subroutine call is made to that address. The requirement of the subroutine is to wait for a message to arrive at the process port (pr_MsgPort) and to return the address of the message (NOT PACKET!) in D0. Anyway, what follows is a simple program that will allow you to monitor any process for packet activity. A binary is available for the asking. (uuencoded) BTW, When you call a AmigaDOS routine [like Read()] that talks to a AmigaDOS handler you can monitor a process receiving packets. -phil [ I promise this time no two signatures ] ============================================================================== Phillip Lindsay - Commodore Business Machines - Amiga Technical Support UUCP: {ihnp4|seismo|caip}!cbmvax!phillip - Phone: (215) 431-9180 No warranty is implied or otherwise given in the form of suggestion or example. Any opinions found here are of my making. /* eof */ --------------ok...SA take out your blade and slice here---------------------- #! /bin/sh # This is a shell archive, meaning: # 1. Remove everything above the #! /bin/sh line. # 2. Save the resulting text in a file. # 3. Execute the file with /bin/sh (not csh) to create the files: # makefile # monproc.c # getprocs.c # givepkt.c # This archive created: Mon Mar 30 10:11:06 1987 export PATH; PATH=/bin:$PATH echo shar: extracting "'makefile'" '(220 characters)' if test -f 'makefile' then echo shar: will not over-write existing file "'makefile'" else sed 's/^ X//' << \SHAR_EOF > 'makefile' X# monproc - mointor process packet activity X# X# X XCFLAGS = +l -dMANX X XOBJS = monproc.o getprocs.o givepkt.o X Xall: $(OBJS) X ln -o monproc $(OBJS) -lc32 X Xmonproc: monproc.o X Xgetprocs: getprocs.o X Xgivepkt: givepkt.o X X# eof SHAR_EOF if test 220 -ne "`wc -c < 'makefile'`" then echo shar: error transmitting "'makefile'" '(should have been 220 characters)' fi fi # end of overwriting check echo shar: extracting "'monproc.c'" '(6161 characters)' if test -f 'monproc.c' then echo shar: will not over-write existing file "'monproc.c'" else sed 's/^ X//' << \SHAR_EOF > 'monproc.c' X/* monproc.c - monitor amigados process packet activity. X * X * Phillip Lindsay (c) 1987 Commodore-Amiga, Inc. X * X */ X X#include <exec/types.h> X#include <exec/nodes.h> X#include <exec/lists.h> X#include <exec/memory.h> X#include <exec/ports.h> X#include <exec/tasks.h> X#include <exec/semaphores.h> X#include <libraries/dos.h> X#include <libraries/dosextens.h> X#include <libraries/filehandler.h> X X#ifdef MANX X#include <functions.h> X#include <stdio.h> X#else X#define index stpchr /* can you say "ANSI STANDARD"...I knew you could... */ X#include <lattice/stdio.h> X#endif X X/* constants */ X X#define ONE 1L X X/* AmigaDOS uses task signal bit 8 for message signaling */ X#define DOS_SIGNAL 8 X#define DOS_MASK ( ONE << DOS_SIGNAL ) X X/* referenced globals */ Xextern void getprocs(),freeprocs(),givepkt(); Xvoid memfill(); Xextern struct DosLibrary *DOSBase; Xstruct Message *packetwait(); XLONG pw(); /* this the asm stub that calls packetwait() */ X X/* global data structures */ Xstruct MsgPort *deviceid; Xstruct Process *memyselfNi; XULONG mymask; Xstruct SignalSemaphore canreturn; Xstruct Message *mymess; X X Xmain() X{ X struct List procs; X struct Node *proc; X register struct Process *devproc; X register struct DosPacket *pkt; X BYTE mypri; X register ULONG waitmask,signals,oldpktwait; X LONG mysignal; X ULONG count,choice; X UBYTE processname[81]; X X puts("MONPROC - monitor AmigaDOS process packet activity.\n"); X X memyselfNi = (struct Process *) FindTask(NULL); X NewList(&procs); /* initialize list header */ X getprocs(&procs); /* fill list with "active" devices */ X X if(procs.lh_TailPred == &procs) /* list empty (should never happen) */ X { X puts("No processes."); X exit(0); X } X X/* X * I am assuming that process list won't change. This is for hackers only. X */ X do X { X puts("Enter NUMBER for process to monitor:"); X puts("Pick# Process MsgPort Name"); X for(count = 1,proc = procs.lh_Head;proc->ln_Succ;proc=proc->ln_Succ,count++) X printf("%4ld. %08lx %08lx %s\n",count, X ((struct Process *)proc->ln_Name), X &(((struct Process *)proc->ln_Name)->pr_MsgPort), X ((struct Process *)proc->ln_Name)->pr_Task.tc_Node.ln_Name); X printf("\nNUMBER: "); X fflush(stdout); X } while( scanf("%ld",&choice) == EOF ) ; X X X if(!choice || choice >= count) X { X puts("Operation aborted."); X freeprocs(&procs); X exit(0); X } X X/* what did he/she pick? */ X for(count = 1,proc = procs.lh_Head;proc->ln_Succ;proc=proc->ln_Succ,count++) X if(choice == count) X { X devproc = (struct Process *) proc->ln_Name; X break; X } X X/* we don't need our process list anymore */ X freeprocs(&procs); X X/* make a copy of the process name */ X strcpy(processname,devproc->pr_Task.tc_Node.ln_Name); X X/* get process msgport of process we will be monitoring */ X deviceid = &devproc->pr_MsgPort; X X/* grab a signal for task intercommunication */ X mysignal = (LONG) AllocSignal(-1L); X if(mysignal == -1) X { X puts("Can't allocate a task signal."); X exit(0); X } X X mymask = ONE << mysignal; X X waitmask = SIGBREAKF_CTRL_C | mymask; X X/* initialize our semaphore */ X memfill(&canreturn,(ULONG)sizeof(canreturn),0L); X InitSemaphore(&canreturn); X X Forbid(); X mypri = devproc->pr_Task.tc_Node.ln_Pri; X Permit(); X X/* make sure our priority is greater than the device task */ X SetTaskPri(memyselfNi, (ULONG)(mypri+1) ); X X puts("Waiting for messages...[CTRL_C to quit monitoring...]"); X X /* install our packet wait function */ X Forbid(); X oldpktwait = (ULONG) devproc->pr_PktWait; X devproc->pr_PktWait = (APTR) pw; X Permit(); X X/* X * I am using semaphores to control the monitoring of the handler's packets. X * There is probably a hundred better ways of doing this. I just went with X * what first came to mind. Since I am a higher priority than the handler... X * Once I am awake I will obtain the semaphore before the lower priority X * task has a chance...I will give it back to him once I am done with the X * packet data structure. X */ Xdo X { X X signals = (ULONG) Wait(waitmask); X ObtainSemaphore(&canreturn); X X if(signals & mymask) /* did the packetwait code signal us? */ X { /* yes, let's boogie... */ X pkt = (struct DosPacket *) mymess->mn_Node.ln_Name; /* get packet address */ X printf("%s: ",processname); X givepkt(pkt); X } X X ReleaseSemaphore(&canreturn); X X } while(!(signals & SIGBREAKF_CTRL_C)); X X /* remove our packet wait function and install previous value */ X Forbid(); X devproc->pr_PktWait = (APTR) oldpktwait; X Permit(); X SetTaskPri(memyselfNi,0L); X puts("\nThere is no safe way to leave since the process is waiting in"); X puts("our installed code. We have de-installed ourselves, but you should"); X puts("be certain that the process received a packet AFTER we have been"); X puts("de-installed. Press CTRL-E if you are certain this has happened."); X Wait(SIGBREAKF_CTRL_E); X FreeSignal(mysignal); X puts("All done."); X X} /* end of main() */ X X X/** X ** local subroutines X **/ X X/* X * packetwait() ... Waits for a message to arrive at your port and X * returns it to you. X */ Xstruct Message *packetwait() X{ X#ifdef MANX /* if MANX make sure we can see our data */ X geta4(); X#endif X /* wait for packet */ X SetSignal(FALSE,DOS_MASK); /* clear sigbit 8 */ X while( !(mymess = (struct Message *) GetMsg(deviceid)) ) Wait(DOS_MASK); X Signal(memyselfNi,mymask); /* Wake up monitoring task he will grab the data */ X ObtainSemaphore(&canreturn); /* we get this guy when we CAN return */ X ReleaseSemaphore(&canreturn); X X return(mymess); X} X X/* X * memfill() - fill memory with supplied byte value for "size" bytes X */ Xvoid memfill(source,size,value) XUBYTE *source; XULONG size; XUBYTE value; X{ X register UBYTE *msource=source, X mvalue=value; X register ULONG msize=size; X X if(msize) X { X do X { X --msize; X msource[msize] = mvalue; X } while(msize); X X } X} X X/* X * This code stub has been known to save lives... X */ X X#if MANX X#asm X XREF _packetwait X X XDEF _pw X_pw: X movem.l a2/a3/a4,-(sp) X jsr _packetwait X movem.l (sp)+,a2/a3/a4 X rts X#endasm X#endif X X/* end of procdev.c */ SHAR_EOF if test 6161 -ne "`wc -c < 'monproc.c'`" then echo shar: error transmitting "'monproc.c'" '(should have been 6161 characters)' fi fi # end of overwriting check echo shar: extracting "'getprocs.c'" '(3659 characters)' if test -f 'getprocs.c' then echo shar: will not over-write existing file "'getprocs.c'" else sed 's/^ X//' << \SHAR_EOF > 'getprocs.c' X/* getprocs.c - Grab all available processes and return them to you in a X * simple exec list. The list is made up of nodes--the "name" X * fields pointing to the process structure. X * X * Phillip Lindsay (c) 1987 Commodore-Amiga Inc. X * You may use this source as long as the copyright notice is left intact. X */ X X#include <exec/types.h> X#include <exec/nodes.h> X#include <exec/lists.h> X#include <exec/memory.h> X#include <exec/tasks.h> X#include <exec/execbase.h> X#include <libraries/dos.h> X#include <libraries/dosextens.h> X#include <libraries/filehandler.h> X X#ifdef MANX X#include <functions.h> X#include <stdio.h> X#else X#include <lattice/stdio.h> X#endif X X/* getnode() will allocate a node structure for you. And initialize the node X * structure with the given values. X */ Xstruct Node *getnode(name,type,pri) Xchar *name; XUBYTE type,pri; X{ X register struct Node *mynode; X X mynode = (struct Node *) X AllocMem((ULONG)sizeof(*mynode),MEMF_PUBLIC | MEMF_CLEAR); X X if(!mynode) return((struct Node *)NULL); X X mynode->ln_Name = name; X mynode->ln_Type = type; X mynode->ln_Pri = pri; X X return(mynode); X} X X/* freenode() frees a given Exec node. X * Make sure you remove node from any list. X */ Xvoid freenode(mynode) Xstruct Node *mynode; X{ X FreeMem(mynode,(ULONG)sizeof(*mynode)); X} X X X/* getprocs() will grab all processes in the system task's list and X * append an exec node to a given list. The node name field filled X * with a pointer to the process strcuture. X * WARNING: This isn't a casual subroutine. The returned list is valid as X * long as a process is not ended or added after this subroutine is X * called. To be real safe you should probably check to see if the X * process is still around before trying to look at the data structure. X */ Xvoid getprocs(plist) Xstruct List *plist; /* passed a pointer to a initialized exec list */ X{ X extern struct ExecBase *SysBase; X register struct ExecBase *execbase=SysBase; X register struct List *proclist; X register struct Node *aproc,*bproc; X register USHORT count=0; X X/* I haven't clocked this code, but you shouldn't as a rule stay disabled for X * no more than 250ms. I'm have no doubt I'm illegal, but you can't be X * too safe when dealing with something that changes with a blink of a X * interrupt. X */ X X Disable(); X X/* first we deal with ourselves... */ X if(execbase->ThisTask->tc_Node.ln_Type == NT_PROCESS) X { X if((bproc=getnode(execbase->ThisTask,0,0))) X { X AddTail(plist,bproc); X } X } X X/* hopefully the added braces make the flow clear */ X for(;count <= 1;count++) X { X if(!count) X proclist = &execbase->TaskReady; X else X proclist = &execbase->TaskWait; X X if(proclist->lh_TailPred != proclist) X { X for(aproc = proclist->lh_Head;aproc->ln_Succ;aproc=aproc->ln_Succ) X { X if(aproc->ln_Type == NT_PROCESS) X { X if((bproc=getnode(aproc,0,0))) X { X AddTail(plist,bproc); X } X } X } X } X } X X Enable(); X X} /* end of getprocs() */ X X X/* freeprocs() will free all nodes in a given list. Function assumes nodes where X * initialized with getnode(). X */ Xvoid freeprocs(plist) Xstruct List *plist; X{ X register struct Node *proc; X X while((proc=RemTail(plist))) X freenode(proc); X} X X/* Xmain() X { X struct List procs; X struct Node *proc; X X NewList(&procs); ** Initialize list header ** X getprocs(&procs); ** Fill list ** X X ** print any processess in list.... if any ** X if(procs.lh_TailPred != &procs) X for(proc = procs.lh_Head;proc->ln_Succ;proc=proc->ln_Succ) X puts( ((struct Process *)proc->ln_Name)->pr_Task.tc_Node.ln_Name ); X X freeprocs(&procs); X } X X*/ X SHAR_EOF if test 3659 -ne "`wc -c < 'getprocs.c'`" then echo shar: error transmitting "'getprocs.c'" '(should have been 3659 characters)' fi fi # end of overwriting check echo shar: extracting "'givepkt.c'" '(4342 characters)' if test -f 'givepkt.c' then echo shar: will not over-write existing file "'givepkt.c'" else sed 's/^ X//' << \SHAR_EOF > 'givepkt.c' X/* givepkt.c - This doesn't do much, it takes a packet type (number) and X * gives you something more readable on stdout. X * X * Phillip Lindsay (c) 1987 Commodore-Amiga Inc. X * You may use this source as long as the copyright notice is left intact. X * X */ X X#include <exec/types.h> X#include <libraries/dosextens.h> X X/* packet types */ X#define _ACTION_NIL 0L X#define _ACTION_GET_BLOCK 2L X#define _ACTION_SET_MAP 4L X#define _ACTION_DIE 5L X#define _ACTION_EVENT 6L X#define _ACTION_CURRENT_VOLUME 7L X#define _ACTION_LOCATE_OBJECT 8L X#define _ACTION_RENAME_DISK 9L X#define _ACTION_FREE_LOCK 15L X#define _ACTION_DELETE_OBJECT 16L X#define _ACTION_RENAME_OBJECT 17L X#define _ACTION_MORE_CACHE 18L X#define _ACTION_COPY_DIR 19L X#define _ACTION_WAIT_CHAR 20L X#define _ACTION_SET_PROTECT 21L X#define _ACTION_CREATE_DIR 22L X#define _ACTION_EXAMINE_OBJECT 23L X#define _ACTION_EXAMINE_NEXT 24L X#define _ACTION_DISK_INFO 25L X#define _ACTION_INFO 26L X#define _ACTION_FLUSH 27L X#define _ACTION_SET_COMMENT 28L X#define _ACTION_PARENT 29L X X/* This is normally a returning timer device request. (internal) */ X#define _ACTION_TIMER 30L X X#define _ACTION_INHIBIT 31L X#define _ACTION_DISK_TYPE 32L X#define _ACTION_DISK_CHANGE 33L X#define _ACTION_SET_FILE_DATE 34L X#define _ACTION_READ 82L X#define _ACTION_WRITE 87L X#define _ACTION_SET_SCREEN_MODE 994L X/* X * When a handler internally sends a device i/o request they are sent using X * their process port and in the form of a "packet" the packet types below: X * (ACTION_TIMER above also falls into this catagory) X */ X#define _ACTION_READ_INTERNAL 1001L X#define _ACTION_WRITE_INTERNAL 1002L X X#define _ACTION_FIND_INPUT 1005L X#define _ACTION_FIND_OUTPUT 1006L X#define _ACTION_CLOSE 1007L X#define _ACTION_SEEK 1008L X Xvoid givepkt(pkt) Xstruct DosPacket *pkt; X{ X switch(pkt->dp_Type) X { X case _ACTION_NIL: X puts("ACTION_NIL"); X break; X X case _ACTION_GET_BLOCK: X puts("ACTION_GET_BLOCK"); X break; X X case _ACTION_SET_MAP: X puts("ACTION_SET_MAP"); X break; X X case _ACTION_DIE: X puts("ACTION_DIE"); X break; X X case _ACTION_EVENT: X puts("ACTION_EVENT"); X break; X X case _ACTION_CURRENT_VOLUME: X puts("ACTION_CURRENT_VOLUME"); X break; X X case _ACTION_LOCATE_OBJECT: X puts("ACTION_LOCATE_OBJECT"); X break; X X case _ACTION_RENAME_DISK: X puts("ACTION_RENAME_DISK"); X break; X X case _ACTION_FREE_LOCK: X puts("ACTION_FREE_LOCK"); X break; X X case _ACTION_DELETE_OBJECT: X puts("ACTION_DELETE_OBJECT"); X break; X X case _ACTION_RENAME_OBJECT: X puts("ACTION_RENAME_OBJECT"); X break; X X case _ACTION_MORE_CACHE: X puts("ACTION_MORE_CACHE"); X break; X X case _ACTION_COPY_DIR: X puts("ACTION_COPY_DIR"); X break; X X case _ACTION_WAIT_CHAR: X puts("ACTION_WAIT_CHAR"); X break; X X case _ACTION_SET_PROTECT: X puts("ACTION_SET_PROTECT"); X break; X X case _ACTION_CREATE_DIR: X puts("ACTION_CREATE_DIR"); X break; X X case _ACTION_EXAMINE_OBJECT: X puts("ACTION_EXAMINE_OBJECT"); X break; X X case _ACTION_EXAMINE_NEXT: X puts("ACTION_EXAMINE_NEXT"); X break; X X case _ACTION_DISK_INFO: X puts("ACTION_DISK_INFO"); X break; X X case _ACTION_INFO: X puts("ACTION_INFO"); X break; X X case _ACTION_FLUSH: X puts("ACTION_FLUSH"); X break; X X case _ACTION_SET_COMMENT: X puts("ACTION_SET_COMMENT"); X break; X X case _ACTION_PARENT: X puts("ACTION_PARENT"); X break; X X case _ACTION_TIMER: X puts("ACTION_TIMER"); X break; X X case _ACTION_INHIBIT: X puts("ACTION_INHIBIT"); X break; X X case _ACTION_DISK_TYPE: X puts("ACTION_DISK_TYPE"); X break; X X case _ACTION_DISK_CHANGE: X puts("ACTION_DISK_CHANGE"); X break; X X case _ACTION_SET_FILE_DATE: X puts("ACTION_SET_FILE_DATE"); X break; X X case _ACTION_READ: X puts("ACTION_READ"); X break; X X case _ACTION_WRITE: X puts("ACTION_WRITE"); X break; X X case _ACTION_SET_SCREEN_MODE: X puts("ACTION_SET_SCREEN_MODE"); X break; X X case _ACTION_READ_INTERNAL: X puts("ACTION_READ_INTERNAL"); X break; X X case _ACTION_WRITE_INTERNAL: X puts("ACTION_WRITE_INTERNAL"); X break; X X case _ACTION_FIND_INPUT: X puts("ACTION_FIND_INPUT"); X break; X X case _ACTION_FIND_OUTPUT: X puts("ACTION_FIND_OUTPUT"); X break; X X case _ACTION_CLOSE: X puts("ACTION_CLOSE"); X break; X X case _ACTION_SEEK: X puts("ACTION_SEEK"); X break; X X default: X printf("Unknown packet: %ld\n",pkt->dp_Type); X break; X } X} X X/* end of givepkt.c */ SHAR_EOF if test 4342 -ne "`wc -c < 'givepkt.c'`" then echo shar: error transmitting "'givepkt.c'" '(should have been 4342 characters)' fi fi # end of overwriting check # End of shell archive exit 0
phillip@cbmvax.UUCP (03/31/87)
I forgot to mention some hints on "monproc" operation. 1. Execute "monproc" in his own CLI. 2. When selecting a process to monitor and names are the same use the process address to see who is who. Higher addresses are usually the most newly created processes. (ie. The "File System" process with the lowest address is in most cases [if not all] "DF0:") -phil ============================================================================== Phillip Lindsay - Commodore Business Machines - Amiga Technical Support UUCP: {ihnp4|seismo|caip}!cbmvax!phillip - Phone: (215) 431-9180 No warranty is implied or otherwise given in the form of suggestion or example. Any opinions found here are of my making. /* eof */