Using Rexx under z/OS Unix Services to display thread information

I wanted to display information about threads running in a big Java application, and see what was executing during set up.

Rexx can provide information on threads, and so I was able to create a script which provided process thread data. There was documentation, but it was not very clear, so I’m documenting what I learned

My program

/* rexx */ 
do k = 1 to 20
call procinfo
say "jobname asid ppid pid threadid tcb cmdline"
do i=1 to bpxw_pid.0
x =procinfo(bpxw_pid.i,'process')
if x = '' then iterate
if bpxw_LOGNAME.i <> "ZWESVUSR" then iterate
y = procinfo(bpxw_pid.i,'thread')
if y = '' then iterate
do j=1 to bpxw_threads
xtcb = d2x( bpxw_TCB.j)
say bpxw_JOBNAME d2x(bpxw_ASID) right(bpxw_PPID,8),
right(bpxw_PID,8) bpxw_THREAD_ID.j xtcb bpxw_CMDLINE
end
end
sleep(1)
end
  • call procinfo returns a list of process ids in a stem bpxw_pid. and userids in a stem bpxw_LOGNAME
  • do i=1 to bpxw_pid.0 iterate through the list of the processes
  • x =procinfo(bpxw_pid.i,’process’) get the process information about the process id in bpxw_pid.i.
  • if x = ” then iterate if the thread no longer exists – do the next one
  • if bpxw_LOGNAME.i <> “ZWESVUSR” then iterate ignore threads from other userids
  • y = procinfo(bpxw_pid.i,’thread’) get the thread information for the process id in bpxw_pid.i.
  • if y = ” then iterate if no data is returned skip this
  • do j=1 to bpxw_threads for each thread in the process …
  • xtcb = d2x( bpxw_TCB.j) convert the thread TCB from decimal to hex.
  • say …
    • bpxw_JOBNAME this is from the process information
    • d2x(bpxw_ASID) display the ASID of the process in hex
    • bpxw_THREAD_ID.j the thread id.

Can I easily make an ISPF edit line command macro?

The key word in the title is easily. If you search for “Working with an edit line command table”, the documentation gives you instructions on how to create a table, then add your definition, create your macro, and then use it. When you were expecting to do this invisibly for the end user, it is a lot of work.

A command line rexx program can process line commands. I created a command line program so when I use it, and use S or SS..SS line commands, the macro can extract the tagged lines, and so do things with the tagged data.

The command line Rexx

/* REXX */ 
address isredit
'MACRO (a) NOPROCESS '
'process range S '
IF RC = 0
THEN DO
"(first) = LINENUM .ZFRANGE"
"(last) = LINENUM .ZLRANGE"
data = ""
/* build up a long string from the tagged lines */
do i = first to last
"(l) = LINE (i)"
data = data || strip(l) || " "
end
l = data
address ispexec "edit dataset('COLIN.$$TEMP$$') macro(l2) parm(l)"
END

Where the lines of interest are

  • ‘MACRO (a) NOPROCESS ‘
    • Usually when a command line macro is processed, ISPF processes any outstanding line commands (such as D) before processing any commands in the rexx exec. The NOPROCESS says – hold off doing this until instructed.
    • a is the data passed in
  • ‘process range S ‘
    • This locates any line commands beginning with S, for a single line, or SS…SS for multiple lins.
  • if rc = 0 then do
  • “(first) = LINENUM .ZFRANGE”
    • get the line number of the First in the RANGE
  • “(last) = LINENUM .ZLRANGE”
    • get the line number of the Last in the Range.
  • data = “”
  • do i = first to last /* process the data build up the string */
    • “(l) = LINE (i)”
    • data = data || strip(l) || ” “
  • end
  • ldata = data
  • address ispexec “edit dataset(‘COLIN.$$TEMP$$’) macro(l2) parm(ldata)”
    • Invoke edit on a file – invoke macro l2, and pass the data in the rexx variable ldata
  • END

If the “process range” gives a non zero return code, set an error message

else do 
zedsmsg = 'You need to specify line prefix s|ss ss'
zedlmsg = 'You need to specify line prefix s|ss ss long message'
address ispexec 'SETMSG MSG(ISRZ001)'
end

This sets a Short message (zedSmsg) which is display at the top right of the display, and a long message (zedLmsg) if the user presses PF1 on the short message.

Macro L2

This macro is processed when the edit dataset(..) macro(l2) command is issued

/* REXX */ 
address isredit
'MACRO (a) '

say "Passed data" a
...