2023-12-22 Get top cpu usage percentage job (TOPCPUPCT)
File : QRPGLESRC
Member: TOPCPUPCT
Type : RPGLE
**
** Program . . : TopCpuPct
** Description : Finds CPU Top and notifies caller
** Author . . : Vengoal Chang
** Published . : AS400 ePaper
** Date . . . : November 21, 2023
**
**
** Program summary
** ---------------
**
** Work management APIs:
** QGYOLJOB Open list of jobs Lists jobs on the system based on
** the specified selection criteria.
**
** Optionally a sort order for the
** returned jobs can be specified -
** in this case the processor unit
** time percentage in descending
** order - listing the jobs having
** the highest CPU usage first.
**
** The CPU processor time is measured
** for an interval of 10 seconds in
** this example.
**
** The QGYOLJOB API is found in the
** QGY library as are all other open
** list APIs.
**
** QWVRCSTK Retrieve Call Stack Lists the program call stack for
** the specified job or thread.
** The current invocation level is
** returned first.
**
** Message handling API:
** QMHSNDM Send message Sends a message to the specified
** non-program message queue - here
** an informational message is sent
** to the current user running this
** program.
**
** Open list APIs:
** QGYGTLE Get list entries To retrieve open lists entries
** from an already open list the
** QGYGTLE (Get List Entries) API
** is available.
**
** QGYCLST Close list This API closes the previously
** opened list identified by the
** request handle parameter.
** Storage allocated is freed.
**
** MI builtins:
** _MEMMOVE Copy memory Copies a string from one pointer
** specified location to another.
**
** Unix Type - Signal APIs:
** Sleep Suspends program processing for
** the specified number of seconds.
**
**
** Sequence of events:
** 1. The act jobs processor time limit percentage is retrieved
**
** 2. The list jobs API input parameters are initialized
**
** 3. The open list of jobs API is called to reset the job
** statistics.
**
** 4. Program is suspended for some seconds
**
** 5. The open list of jobs API is called to list the interactive
** jobs on the system returning the most CPU intensive jobs
** for the elapsed period first.
**
** 6. For each top cpu percent job a message is sent to the
** message queue.
**
** 7. The job list resources are cleaned up.
**
** 8. The program will loop 1 to 7, until manual job.
**
** Programmer's notes:
**
** As mentioned above library QGY must be in the job library list
** to succesfully run this program.
**
** To retrieve another job's call stack *JOBCTL special authority is
** required.
**
**
** Compile options:
**
** CrtRpgMod Module( TOPCPUPCT ) DbgView( *LIST )
**
** CrtPgm Pgm( TOPCPUPCT )
** Module( TOPCPUPCT )
**
** Usage sample:
** Get top first CPU% job per 60 secs with following:
** SBMJOB
** CMD(TOPCPUPCT TOPCOUNT(001) INTERVAL(00060)
** TOMSGQ(*SYSOPR))
** Job(TOPPCTPCT)
**
** Get top 5 CPU% job per 60 secs with following:
** SBMJOB
** CMD(TOPCPUPCT TOPCOUNT(005) INTERVAL(00060)
** TOMSGQ(*SYSOPR))
** Job(TOPPCTPCT)
**
**-- Control spec: -----------------------------------------------------**
H Option( *SrcStmt ) DecEdit( *JobRun ) BndDir( 'QC2LE' )
H DftActGrp(*NO)
**-- System information: -----------------------------------------------**
D PgmSts SDs
D PsPgmNam *Proc
D PsSts 5a Overlay( PgmSts: 11 )
D PsCurJob 10a Overlay( PgmSts: 244 )
D PsUsrPrf 10a Overlay( PgmSts: 254 )
D PsJobNbr 6a Overlay( PgmSts: 264 )
D PsCurUsr 10a Overlay( PgmSts: 358 )
**-- API error data structure: -----------------------------------------**
D ApiError Ds
D AeBytPrv 10i 0 Inz( %Size( ApiError ))
D AeBytAvl 10i 0
D AeExcpId 7a
D 1a
D AeExcpDta 128a
**-- API parameters: ---------------------------------------------------**
D JlRtnRcdNbr s 10i 0 Inz( 1 )
D JlNbrFldRtn s 10i 0 Inz( %Elem( JlKeyFld ))
D JlKeyFld s 10i 0 Dim( 3 )
**-- Job information:
D JlJobInf Ds 512
D JbJobId 26a
D JbJobUsd 10a Overlay( JbJobId: 1 )
D JbUsrUsd 10a Overlay( JbJobId: *Next )
D JbNbrUsd 6a Overlay( JbJobId: *Next )
D JbActSts 4a
D JbJobTyp 1a
D JbJobSubTyp 1a
D JbDtaLen 10i 0
D 4a
D JbDta 256a
**-- Key information:
D JlKeyInf Ds
D KiFldNbrRtn 10i 0
D KiKeyInf 20a Dim( %Elem( JlKeyFld ))
D KiFldInfLen 10i 0 Overlay( KiKeyInf : 1 )
D KiKeyFld 10i 0 Overlay( KiKeyInf : 5 )
D KiDtaTyp 1a Overlay( KiKeyInf : 9 )
D 3a Overlay( KiKeyInf : 10 )
D KiDtaLen 10i 0 Overlay( KiKeyInf : 13 )
D KiDtaOfs 10i 0 Overlay( KiKeyInf : 17 )
**-- Sort information:
D JlSrtInf Ds
D SiNbrKeys 10i 0 Inz( 1 )
D SiSrtInf 12a Dim( 10 )
D SiKeyFldOfs 10i 0 Overlay( SiSrtInf : 1 )
D SiKeyFldLen 10i 0 Overlay( SiSrtInf : 5 )
D SiKeyFldTyp 5i 0 Overlay( SiSrtInf : 9 )
D SiSrtOrd 1a Overlay( SiSrtInf : 11 )
D SiRsv 1a Overlay( SiSrtInf : 12 )
**-- List information:
D JlLstInf Ds
D LiRcdNbrTot 10i 0
D LiRcdNbrRtn 10i 0
D LiHandle 4a
D LiRcdLen 10i 0
D LiInfSts 1a
D LiDts 13a
D LiLstSts 1a
D 1a
D LiInfLen 10i 0
D LiRcd1 10i 0
D 40a
**-- Selection information:
D JlSltInf Ds
D SiJobNam 10a Inz( '*ALL' )
D SiUsrNam 10a Inz( '*ALL' )
D SiJobNbr 6a Inz( '*ALL' )
D SiJobTyp 1a Inz( '*' )
D 1a
D SiOfsPriSts 10i 0 Inz( 60 )
D SiNbrPriSts 10i 0 Inz( 0 )
D SiOfsActSts 10i 0 Inz( 70 )
D SiNbrActSts 10i 0 Inz( 0 )
D SiOfsJbqSts 10i 0 Inz( 78 )
D SiNbrJbqSts 10i 0 Inz( 0 )
D SiOfsJbqNam 10i 0 Inz( 88 )
D SiNbrJbqNam 10i 0 Inz( 0 )
**
D SiPriSts 10a Dim( 1 )
D SiActSts 4a Dim( 2 )
D SiJbqSts 10a Dim( 1 )
D SiJbqNam 20a Dim( 1 )
**-- Job information key fields:
D JbKeyDta Ds
D JbPrcUniTim 20u 0
D JbPrcUniPct 9b 1
D JbPrcUniTimE 20u 0
**-- General return data:
D JlGenDta Ds
D GdBytRtn 10i 0
D GdBytAvl 10i 0
D GdElpTim 20u 0
D 16a
**-- MatRmd parameters: ------------------------------------------------**
D MatRscMgDt Ds
D RdBytPrv 10i 0 Inz( %Size( MatRscMgDt ))
D RdBytAvl 10i 0
D RdTimDay 8a
D RdData
D RdPrcTimIpl 20u 0 Overlay( RdData: 1 )
D RdPrcTimScWl 20u 0 Overlay( RdData: *Next )
D RdPrcTimDb 20u 0 Overlay( RdData: *Next )
D RdPrcTimDbTh 5u 0 Overlay( RdData: *Next )
D RdPrcTimDbLm 5u 0 Overlay( RdData: *Next )
D RdRsv1 10u 0 Inz( x'00' )
D Overlay( RdData: *Next )
D RdPrcTimInt 20u 0 Overlay( RdData: *Next )
D RdPrcTimIntT 4b 1 Overlay( RdData: *Next )
D RdPrcTimIntL 4b 1 Overlay( RdData: *Next )
D RdRsv2 10u 0 Inz( x'00' )
D Overlay( RdData: *Next )
**
D MatCtlDta Ds
D CdSltOpt 1a Inz( x'01' )
D CdRsv 7a Inz( *Allx'00' )
**-- Global variables: -------------------------------------------------**
D Ix s 5i 0
D Count s 5i 0
D Interval s 10u 0
D TopCount s 3S 0
D PgmNam s 10a
D MsgDta s 256a Varying
D MsgKey s 4a
D SysTime s z inz(*sys)
**-- API constants: ----------------------------------------------------**
D JOB_RESET_STAT c '1'
D JOB_KEEP_STAT c '0'
**-- Open list of jobs: ------------------------------------------------**
D LstJobs Pr ExtPgm( 'QGYOLJOB' )
D LjRcvVar 65535a Options( *VarSize )
D LjRcvVarLen 10i 0 Const
D LjFmtNam 8a Const
D LjRcvVarDfn 65535a Options( *VarSize )
D LjRcvDfnLen 10i 0 Const
D LjLstInf 80a
D LjNbrRcdRtn 10i 0 Const
D LjSrtInf 1024a Const Options( *VarSize )
D LjJobSltInf 1024a Const Options( *VarSize )
D LjJobSltLen 10i 0 Const
D LjNbrFldRtn 10i 0 Const
D LjKeyFldRtn 10i 0 Const Options( *VarSize ) Dim( 32 )
D LjError 1024a Options( *VarSize )
**
D LjJobSltFmt 8a Const Options( *NoPass )
**
D LjResStc 1a Const Options( *NoPass )
D LjGenRtnDta 32a Options( *NoPass: *VarSize )
D LjGenRtnDtaLn 10i 0 Const Options( *NoPass )
**-- Get list entry: ---------------------------------------------------**
D GetLstEnt Pr ExtPgm( 'QGYGTLE' )
D GlRcvVar 65535a Options( *VarSize )
D GlRcvVarLen 10i 0 Const
D GlHandle 4a Const
D GlLstInf 80a
D GlNbrRcdRtn 10i 0 Const
D GlRtnRcdNbr 10i 0 Const
D GlError 1024a Options( *VarSize )
**-- Close list: -------------------------------------------------------**
D CloseLst Pr ExtPgm( 'QGYCLST' )
D ClHandle 4a Const
D ClError 1024a Options( *VarSize )
**-- Send message: -----------------------------------------------------**
D SndMsg Pr ExtPgm( 'QMHSNDM' )
D SmMsgId 7a Const
D SmMsgFq 20a Const
D SmMsgDta 512a Const Options( *VarSize )
D SmMsgDtaLen 10i 0 Const
D SmMsgTyp 10a Const
D SmMsgQq 1000a Const Options( *VarSize )
D SmMsgQnbr 10i 0 Const
D SmMsgQrpy 20a Const
D SmMsgKey 4a
D SmError 10i 0 Const
**
D SmCcsId 10i 0 Const Options( *NoPass )
**-- Copy memory: ------------------------------------------------------**
D memcpy Pr * ExtProc( '_MEMMOVE' )
D outmem * Value
D inpmem * Value
D memsiz 10u 0 Value
**-- Delay job: --------------------------------------------------------**
D sleep Pr 10i 0 ExtProc( 'sleep' )
D seconds 10u 0 Value
**-- Get top stack entry: ----------------------------------------------**
D GetTopStkE Pr 20a
D GtJobId 26a Const
**-- Materialize resource management data: -----------------------------**
D MatRmd Pr ExtProc( '_MATRMD' )
D Rcv Like( MatRscMgDt )
D Ctl Like( MatCtlDta )
**
**-- Mainline: ---------------------------------------------------------**
**
C *Entry Plist
C Parm TopCount_p 3
C Parm Interval_p 5
C Parm ToMsgQ 10
**
C Eval TopCount = %Int(TopCount_p)
C Eval Interval = %Int(Interval_p)
C Select
C When ToMsgQ = '*SYSOPR'
C Eval ToMsgQ = 'QSYSOPR'
C When ToMsgQ = '*CURUSR'
C Eval ToMsgQ = PsCurUsr
C EndSl
**
**-- Job information return fields:
C Eval JlKeyFld(1) = 312
C Eval JlKeyFld(2) = 314
C Eval JlKeyFld(3) = 315
**
**-- Sort field specification:
C Eval SiNbrKeys = 1
C Eval SiKeyFldOfs(1) = 49
C Eval SiKeyFldLen(1) = 4
C Eval SiKeyFldTyp(1) = 0
C Eval SiSrtOrd(1) = '2'
C Eval SiRsv(1) = x'00'
**
**-- Initialize job CPU measurement:
**-- NOTE: Statistics only reset if return records are requested
**
C DoW 1 = 1
C CallP LstJobs( JlJobInf
C : %Size( JlJobInf )
C : 'OLJB0300'
C : JlKeyInf
C : %Size( JlKeyInf )
C : JlLstInf
C : 1
C : JlSrtInf
C : JlSltInf
C : %Size( JlSltInf )
C : JlNbrFldRtn
C : JlKeyFld
C : ApiError
C : 'OLJS0100'
C : JOB_RESET_STAT
C : JlGenDta
C : %Size( JlGenDta )
C )
**
**-- Wait 10 seconds:
C CallP sleep( Interval )
**
**-- Retrieve job list:
C CallP LstJobs( JlJobInf
C : %Size( JlJobInf )
C : 'OLJB0300'
C : JlKeyInf
C : %Size( JlKeyInf )
C : JlLstInf
C : 1
C : JlSrtInf
C : JlSltInf
C : %Size( JlSltInf )
C : JlNbrFldRtn
C : JlKeyFld
C : ApiError
C : 'OLJS0100'
C : JOB_KEEP_STAT
C : JlGenDta
C : %Size( JlGenDta )
C )
**
C If AeBytAvl = *Zero
**
C Eval Count = 0
C DoW LiLstSts <> '2' Or
C LiRcdNbrTot > JlRtnRcdNbr
**
C ExSr GetCpuDta
C ExSr ChkCpuPct
**
C* ExSr SndCmpMsg
**
C If Count >= TopCount
C Leave
C EndIf
**
C Eval JlRtnRcdNbr = JlRtnRcdNbr + 1
**
C CallP GetLstEnt( JlJobInf
C : %Size( JlJobInf )
C : LiHandle
C : JlLstInf
C : 1
C : JlRtnRcdNbr
C : ApiError
C )
**
C If AeBytAvl > *Zero
C Leave
C EndIf
**
C EndDo
**
C CallP CloseLst( LiHandle
C : ApiError
C )
**
C EndIf
**
C EndDo
**
C Eval *InLr = *On
**
C Return
**
**-- Get CPU data: -----------------------------------------------------**
C GetCpuDta BegSr
**
C Clear JbKeyDta
**
C For Ix = 1 To KiFldNbrRtn
**
C Select
C When KiKeyFld(Ix) = 312
C CallP memcpy( %Addr( JbPrcUniTim )
C : %Addr( JlJobInf ) +
C KiDtaOfs(Ix)
C : KiDtaLen(Ix)
C )
**
C When KiKeyFld(Ix) = 314
C CallP memcpy( %Addr( JbPrcUniPct )
C : %Addr( JlJobInf ) +
C KiDtaOfs(Ix)
C : KiDtaLen(Ix)
C )
**
C When KiKeyFld(Ix) = 315
C CallP memcpy( %Addr( JbPrcUniTimE )
C : %Addr( JlJobInf ) +
C KiDtaOfs(Ix)
C : KiDtaLen(Ix)
C )
C EndSl
C EndFor
**
C EndSr
**-- Check CPU percent: ------------------------------------------------**
C ChkCpuPct BegSr
**
C Eval Count = Count + 1
C Eval PgmNam = GetTopStkE( JbJobId )
**
C Eval SysTime = %Timestamp()
C Eval MsgDta =
C '{ "CPUPCTMSG": { ' +
C '"QDATETIME" : "' +
C %Char(%Timestamp():*ISO) + '", ' +
C '"JobNam" : "' +
C %Trim(JbJobUsd) + '", ' +
C '"JobUsr" : "' +
C %Trim(JbUsrUsd) + '", ' +
C '"JobNbr" : "' +
C %Trim(JbNbrUsd) + '", ' +
C '"CpuPct" : "' +
C %Char( JbPrcUniPct ) + '", ' +
C '"PgmNam" : "' +
C %Trim( PgmNam ) + '" ' +
C '} }'
**
C CallP(e) SndMsg( *Blanks
C : *Blanks
C : MsgDta
C : %Len( MsgDta )
C : '*INFO'
C : ToMsgQ + '*LIBL'
C : 1
C : *Blanks
C : MsgKey
C : 0
C )
**
C EndSr
**-- Get top stack entry: ----------------------------------------------**
P GetTopStkE B Export
D Pi 20a
D GtJobId 26a Const
**-- API parameters:
D CsRcvVar Ds
D CsBytRtn 10i 0
D CsBytAvl 10i 0
D CsNbrStkE 10i 0
D CsOfsStkE 10i 0
D CsNbrEntRtn 10i 0
D CsThrId 8a
D CsInfSts 1a
D CsCalStk 32767a
**
D CsCalStkE Ds Based( pCalStkE )
D CsStkEntLen 10i 0
D CsOfsStmIds 10i 0
D CsNbrStmIds 10i 0
D CsOfsPrcNam 10i 0
D CsLenPrcNam 10i 0
D CsRqsLvl 10i 0
D CsPgmNam 10a
D CsPgmLib 10a
D CsMiInst 10i 0
D CsModNam 10a
D CsModLib 10a
D CsCtlBdy 1a
D CsRsv 3a
D CsActGrpNbr 10u 0
D CsActGrpNam 10a
D CsAddInf 4096a
**
D CsStmIds 10a Dim( 16 )
D CsPrcNam 512a
**
D CsJobId Ds
D JiJobId 26a
D JiJobNam 10a Overlay( JiJobId: 1 )
D JiUsrNam 10a Overlay( JiJobId: *Next )
D JiJobNbr 6a Overlay( JiJobId: *Next )
D JiIntId 16a
D JiRsv 2a Inz( *Allx'00' )
D JiThrInd 10i 0 Inz( 2 )
D JiThrId 8a Inz( *Allx'00' )
**-- Retrieve call stack:
D RtvCalStk Pr ExtPgm( 'QWVRCSTK' )
D RcRcvVar 32767a
D RcRcvVarLen 10i 0 Const
D RcRcvInfFmt 8a Const
D RcJobId 56a Const
D RcJobIdFmt 8a Const
D RcError 32767a Options( *VarSize )
**
D EntNbr s 5u 0
**-- Get stack entries: ------------------------------------------------**
**
C Eval JiJobId = GtJobId
**
C CallP RtvCalStk( CsRcvVar
C : %Size( CsRcvVar )
C : 'CSTK0100'
C : CsJobId
C : 'JIDF0100'
C : ApiError
C )
**
C If AeBytAvl = *Zero
C Eval pCalStkE = %Addr( CsRcvVar ) + CsOfsStkE
**
C For EntNbr = 1 to CsNbrEntRtn
**
C If EntNbr = 1
**
C Eval CsStmIds = *Blanks
C Eval CsPrcNam = *Blanks
**
C If CsOfsStmIds > *Zero
C CallP MemCpy( %Addr( CsStmIds )
C : %Addr( CsCalStkE ) +
C CsOfsStmIds
C : CsNbrStmIds * %Size( CsStmIds )
C )
C EndIf
**
C If CsOfsPrcNam > *Zero
C CallP MemCpy( %Addr( CsPrcNam )
C : %Addr( CsCalStkE ) +
C CsOfsPrcNam
C : CsLenPrcNam
C )
C EndIf
**
C Leave
C EndIf
**
C If EntNbr < CsNbrEntRtn
C Eval pCalStkE = PCalStkE + CsStkEntLen
C EndIf
C EndFor
**
C Return CsPgmNam + CsPgmLib
**
C Else
C Return *Blanks
C EndIf
**
P GetTopStkE E
File : QCMDSRC
Member: TOPCPUPCT
Type : CMD
/* =============================================================== */
/* = Command....... TopCpuPct = */
/* = CPP........... TopCpuPct RPGLE = */
/* = Description... Send WRKACTJOB CPUPCT top to user = */
/* = = */
/* = = */
/* = CrtCmd Cmd( TopCpuPct ) = */
/* = Pgm( TopCpuPct ) = */
/* = SrcFile( YourSourceFile ) = */
/* =============================================================== */
/* = Date : 2023/11/21 = */
/* = Author: Vengoal Chang = */
/* =============================================================== */
CMD PROMPT('Top Cpu Percent Job')
PARM KWD(TOPCOUNT) TYPE(*CHAR) LEN(3) +
RANGE('001' '999') +
FULL(*YES) +
PROMPT('TOP CPU JOB COUNT')
PARM KWD(INTERVAL) TYPE(*CHAR) LEN(5) +
RANGE('00001' '99999') +
FULL(*YES) +
PROMPT('Interval second')
PARM KWD(TOMSGQ) TYPE(*CHAR) LEN(10) +
DFT(*SYSOPR) +
SPCVAL((*SYSOPR) (*CURUSR)) +
PROMPT('Message To MsgQ')
Program to capture CPU usage over time (with SQL)
A blog about IBM i (AS/400), MQ and other things developers or Admins need to know.
星期五, 12月 22, 2023
2023-12-22 Get top cpu usage percentage job (TOPCPUPCT)
星期四, 12月 07, 2023
MessageQ Break-Handling Programs
The section from the V4R3 CL Programmers Guide on break handlers.
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
8.4 Break-Handling Programs
A break-handling program is one that is automatically called when a message
arrives at a message queue that is in *BREAK mode. Both the name
of the program and the break delivery name must be specified on the same
Change Message Queue (CHGMSGQ) command. Although the program
is specified on the CHGMSGQ command, it is one or more procedures within the
program that processes the message. A procedure within this
program must run a Receive Message (RCVMSG) command to receive the message.
To receive and handle the message, the user-defined
program called to handle messages for break delivery is passed parameters
(more specifically, the first procedure to run within the program is
passed these parameters). The parameters identify the message queue and the
message reference key (MRK) of the message causing the
break. See the Break Handling exit program in the System API Reference,
SC41-5801 book, for a list of the parameters. If the break-handling
program is called, it interrupts the job in which the message occurred and
runs. When the break-handling program ends, the original program
resumes processing.
The following program (PGMA), which consists of only this one procedure, is
an example of a break-handling program.
PGM PARM(&MSGQ &MSGLIB &MRK)
DCL VAR(&MSGQ) TYPE(*CHAR) LEN(10)
DCL VAR(&MSGLIB) TYPE(*CHAR) LEN(10)
DCL VAR(&MRK) TYPE(*CHAR) LEN(4)
DCL VAR(&MSG) TYPE(*CHAR) LEN(75)
RCVMSG MSGQ(&MSGLIB/&MSGQ) MSGKEY(&MRK) +
MSG(&MSG)
.
.
.
ENDPGM
After the break-handling program is created, running the following command
connects it to the QSYSMSG message queue.
CHGMSGQ MSGQ(QSYS/QSYSMSG) DLVRY(*BREAK) PGM(PGMA)
Notes:
1. When messages are handled, they should be removed from the message
queue. When a message queue is put in break mode, any message
on the queue will cause the break-handling program to get called.
2. The procedure or program receiving the message should not be coded with
a wait-time other than zero to receive a message. You can specify
a value other than zero for the wait parameter with the Receive Message
(RCVMSG) command. The message arrival event cannot be handled
by the system while the job is running a break-handling event.
An example of a break-handling program is to have the program send a
message, which is normally sent to the QSYSOPR queue, to another
queue in place of or in addition to QSYSOPR.
The following is an example of a user-defined program (again with only one
procedure) to handle break messages. The display station user does
not need to respond to the messages CPA5243 (Press Ready, Start, or
Start-Stop on device &1) and CPA5316 (Verify alignment on device &3)
when this program is used.
BRKPGM: PGM (&MSGQ &MSGQLIB &MSGMRK)
DCL &MSGQ TYPE(*CHAR) LEN(10)
DCL &MSGQLIB TYPE(*CHAR) LEN(10)
DCL &MSGMRK TYPE(*CHAR) LEN(4)
DCL &MSGID TYPE(*CHAR) LEN(7)
RCVMSG MSGQ(&MSGQLIB/&MSGQ) MSGKEY(&MSGMRK) +
MSGID(&MSGID) RMV(*NO)
/* Ignore message CPA5243 */
IF (&MSGID *EQ 'CPA5243') GOTO ENDBRKPGM
/* Reply to forms alignment message */
IF (&MSGID *EQ 'CPA5316') +
DO
SNDRPY MSGKEY(&MSGMRK) MSGQ(&MSGQLIB/&MSGQ) RPY(I)
ENDDO
/* Other messages require user intervention */
ELSE CMD(DSPMSG MSGQ(&MSGQLIB/&MSGQ))
ENDBRKPGM: ENDPGM
Attention:
In the above example of a break-handling program, if a CPA5316 message
should arrive at the queue while the DSPMSG command is running, the
DSPMSG display shows the original message that caused the break and the
CPA5316 message. The DSPMSG display waits for the operator to
reply to the CPA5316 message before proceeding.
Note: This program cannot open a display file if the interrupted program is
waiting for input data from the display.
You can use the system reply list to indicate the system will issue a reply
to predefined inquiry messages. The display station user, therefore,
does not need to reply. For more information, see "Using the System Reply
List" in topic 8.6.
A procedure within a user break-handling program may need a Suspend and
Restore procedure to ensure the display is suspended and restored
while the message handling function is being performed. The Suspend and
Restore procedure is necessary only if the following conditions exist:
A procedure in the break-program displays other menus or screens
The break-program calls other programs which may display other menus or
screens.
The following example clarifies the user procedure and display file needed
to suspend and restore the display:
Note: RSTDSP(*YES) must be specified to create the display file.
A R SAVFMT OVERLAY KEEP
A*
A R DUMMY OVERLAY
A KEEP
A ASSUME
A DUMMYR 1A 1 2DSPATR(ND)
PGM PARM(&MSGQ &MSGLIB &MRK)
DCL VAR(&MSGQ) TYPE(*CHAR) LEN(10)
DCL VAR(&MSGLIB) TYPE(*CHAR) LEN(10)
DCL VAR(&MRK) TYPE(*DEC) LEN(4)
DCLF FILE(UDDS/BRKPGMFM)
SNDF RCDFMT(SAVFMT)
CALL PGM(User's Break Program)
SNDF RCDFMT(SAVFMT)
ENDPGM
To compile, use the following command: CRTCLPGM PGM(xxx/MSG2LIN24) SRCFILE(xxx/QCLSRC) Key the program into source physical file QCLSRC in one of your libraries (represented by xxx), then compile the program by executing the CRTCLPGM as indicated. Now run the following command: CHGMSGQ MSGQ(…) DLVRY(*BREAK) PGM(xxx/MSG2LIN24)
訂閱:
文章 (Atom)