iSeries (AS400) – can batch program send event-driven interrupt to interactive screen (not SNDBRKMSG)

265 pts.
Tags:
AS/400
AS/400 Display File
CL batch program
IBM iSeries
I am looking for a way for an active batch program (waits on a data queue) to send an interrupt display to one or more users, based on specific data the program receives from the data queue. The interrupt would be a 1-way advice - no need for a reply, only ENTER - overlaying the application currently active on the user's diisplay. The concept is the same as using SNDBRKMSG but I want to send a formatted display.

Is there a way to do this? Thanks for any help and suggestions.

Zack

 



Software/Hardware used:
iSeries (AS400)

Answer Wiki

Thanks. We'll let you know when a new response is added.

I tried to access that link, BigKat, but the page comes up blank – no errors, just blank. That has been happening a lot over the last few months with Systeminetwork site. BTW I Googled the article and got the same link and same results so I think the issue is with systeminetwork.

Is anyone else having trouble connecting to that site?

Discuss This Question: 8  Replies

 
There was an error processing your information. Please try again later.
Thanks. We'll let you know when a new response is added.
Send me notifications when members answer or reply to this question.

REGISTER or login:

Forgot Password?
By submitting you agree to receive email from TechTarget and its partners. If you reside outside of the United States, you consent to having your personal data transferred to and processed in the United States. Privacy
  • BigKat
    take a look at this link and see if it will help you easy co-op processing programming with data queues
    8,350 pointsBadges:
    report
  • BigKat
    sorry, that link is not right. The article I remember talked about how to make a program run like a PC's TSR (terminate and stay resident) and you could have that program run in every users startup program then when the event occurred, it would wake up and let the user do what they needed in that program. This article talks of some of that, and when I skimmed, I thought it was the right one.
    8,350 pointsBadges:
    report
  • BigKat
    THIS is the link to the article I was thinking of Scott Klement's TSR article
    8,350 pointsBadges:
    report
  • WoodEngineer
    I tried to access that link, BigKat, but the page comes up blank - no errors, just blank. That has been happening a lot over the last few months with Systeminetwork site. BTW I Googled the article and got the same link and same results so I think the issue is with systeminetwork. Is anyone else having trouble connecting to that site?
    6,875 pointsBadges:
    report
  • BigKat
    I have copied the article from the Scott Klement's TSR article link Terminate and Stay Resident...in RPG! Article ID: 57166 Posted September 11th, 2008 By: Scott Klement Signals are a Unix software tool that, when received, interrupt what a job is currently doing and invoke a subprocedure. As soon as that subprocedure is done running, the job continues where it left off. Programs can tell the operating system to send them an "alarm" signal after a certain duration of time. After making this request, the program can continue processing as normal. When the time interval expires, the system sends the signal and interrupts what the job is doing to deliver that signal to the designated procedure. I discovered one day (quite by accident, in fact) that the OS will continue to deliver these signals, even if the program that requested them has already ended! And even more interesting, if you end a program but leave it loaded in memory (by leaving LR turned off or by loading it into an ILE activation group), the subprocedures of that program can be run as signal handlers, even if the program has ended and the user is now running a completely separate and unrelated application. An Example Scenario Think about that for a moment: You can run a program, register a signal handler, and ask the OS to send you a signal in five minutes. Then your program can end. The user can proceed to run different programs, and five minutes later without warning, your program can suddenly wake up and do something! That's pretty neat, isn't it? I put this technique to use in my shop by searching for the arrival of a new EDI file. The folks who run the EDI system log on to their 5250 sign-on, and there's an initial program that's defined in their user profile. This initial program is loaded into an activation group by itself, and it remains there even after the program ends. It tells the operating system to send it a signal every 60 seconds and specifies a subprocedure to be called when those signals arrive. Then, it ends. The user doesn't even know the program was run, because it took only a millisecond or two to install itself into memory, and then it ended. Now the user can proceed to do his or her work, without even knowing that my program was loaded. Every 60 seconds, my subprocedure runs and checks for a new EDI file. If no file exists, it does nothing, and the user has no idea that the routine ran. If the file does exist, my subprocedure pops up a screen telling the user that the file has arrived, so the user knows to run the EDI import option. Program Activation In the old days of running RPG in the OPM environment, a program was activated when you called it. If you set the LR indicator on and ended the program, the variables would be reset, the files would be closed, and it would be deactivated from memory. Today in ILE RPG, the behavior is exactly the same when you specify DFTACTGRP(*YES) on the CRTBNDRPG command. However, if you specify DFTACTGRP(*NO), it doesn't quite work the same way. With DFTACTGRP(*NO), the RPG program follows the rules of ILE. In the ILE environment, a program is to remain activated until the activation group is reclaimed. Don't get me wrong. If you turn LR on, your files will still be closed, and your variables will be reset to their initial values the next time the program is called. However, in ILE, LR does not control whether the program is deactivated. Instead, the program is deactivated only if the activation group ends. The fact that it's still activated is useful, because it means it can sit dormant in memory until a signal arrives, then "wake up" and handle the signal. This is very similar to the way Terminate Stay Resident (TSR) programs work in MS-DOS. Those programs end (i.e., "terminate") in a manner that keeps them loaded into memory (i.e. ,"stay resident" in memory). Then, they can be attached to a hardware device (such as the system clock or the keyboard) and can take action when these hardware events occur. ILE programs don't work exactly like that, of course. They can't be connected to hardware events, but they can be connected to signals--and signals can be activated based on an interval of time, so that makes them very similar to an MS-DOS TSR that's based on the system clock. Register a Signal Handler Here's some code to register a signal handler: D act ds likeds(sigaction_t) D Interval ds likeds(itimerval) . . sigemptyset(act.sa_mask); sigaddset(act.sa_mask: SIGALRM); act.sa_handler = %paddr(check_edi); act.sa_flags = 0; act.sa_sigaction = *NULL; sigaction(SIGALRM: act: *omit); sigaction(SIGTERM: act: *omit); At the bottom of the preceding code snippet, I'm calling the sigaction() API. This tells the system what action to take when a given signal is received. I've provided a data structure named act that contains all the instructions for what to do when the SIGALRM and SIGTERM signals are sent. SIGALRM will be sent when my program tells the OS to send an alarm signal. This is the signal I was describing above as something that's sent after a given period of time has elapsed. Think of it as an alarm clock. SIGTERM is sent to my program when someone issues a *CNTRLD job end request. When either of these signals is received, I've told it to call my check_edi() subprocedure. I did that by specifying the procedure address (with the %paddr() BIF) as the signal handler in the act data structure. I've also set a "signal mask" in that data structure by calling the sigemptyset() and sigaddset() APIs. This signal mask is a list of signals that should not be sent while my check_edi() procedure is running. Since I call sigemptyset() to empty out the list, followed by sigaddset() to add the SIGALRM signal, the only one that'll be blocked while check_edi() runs is the SIGALRM signal. I block it so that my check_edi() routine isn't interrupted in the middle by a subsequent signal. Set up an Interval Timer There are two ways to tell the operating system that you want to be notified after a duration of time has passed. The easiest way is with the alarm() API: callp alarm(600); In this example, I've told it to send me an alarm signal after 10 minutes (600 seconds). The operating system will send me a SIGALRM signal after 10 minutes, and that means my check_edi() routine will be run. The alarm() API sends the signal only once, however. If I want to repeat the signal on a certain interval, I'll call the Set Interval Timer (setitimer) API instead. D Interval ds likeds(itimerval) . . Interval = *ALLx'00'; Interval.int_tv_sec = 60; Interval.val_tv_sec = 60; setitimer(ITIMER_REAL: Interval: *omit); In this example, I've told it to send the initial SIGALRM signal after 60 seconds. Thereafter, it should resend the same signal at 60-second intervals. In my "EDI Notification" example, I'll use setitimer() because I want the routine to be run repeatedly at 60-second intervals. If I used alarm(), it would be called only once. Be Prepared to Clean Up My EDI notification program is called EDIWARN, and it runs in an activation group also named EDIWARN (after the name of the program.) The idea is that it'll be the only program running in that activation group. If I want to shut down my warning program, all I have to do is reclaim that activation group. Because it's the only thing running in the EDIWARN activation group, I don't have to worry about accidentally reclaiming something else. When the activation group is ended, I need to disable the interval timer. If I don't do this, the system will still send the signal and still try to call my procedure. Since reclaiming the activation group has deactivated my program, that would be a very bad thing! Fortunately, there's an API called CEE4RAGE that can register a procedure to be run when an activation group ends. I can use that to stop the interval timer when the activation group is ended. D CEE4RAGE PR D procedure * procptr const D feedback 12A options(*omit) . . CEE4RAGE(%paddr(stop_check): *omit); *inlr = *on; return; The preceding code is run immediately after I start the interval timer. All it does is tell the system to call the stop_check() subprocedure when the activation group is about to end. Now that I've registered my interval timer and my procedure to call when the activation group ends, my program is done. It can now end, and let the user do other things, and therefore I set on LR and use RETURN to end the program. The program will still be loaded into the activation group, and the subprocedure named check_edi() will be called every 60 seconds by the operating system. The stop_check() subprocedure will be called when the activation group ends, and it will disable the interval timer by calling setitimer() again with all of the interval fields set to zero. P stop_check B D stop_check PI /free Interval = *ALLx'00'; setitimer(ITIMER_REAL: Interval: *omit); /end-free P E Checking for the EDI Upload File The actual logic to check whether new EDI data has arrived is quite a bit more complex than the sample code I'm posting here. Obviously, how you check for EDI will depend a lot on how your software works, and the odds are good that you're using a different EDI package than I am. In the interests of keeping the code simple and focused on the idea of waking up a subprocedure with a signal (rather than EDI business logic), I'm going to run a simple ALCOBJ on a file named EDIUPLD. If no EDI has been sent, we'll assume the EDIUPLD file doesn't exist, and therefore the ALCOBJ will error out. If the file does exist, the ALCOBJ will ensure that the application that's writing to the EDIUPLD file has completed before the "ready to process" message is displayed to the user. In other words, if my check_edi() routine happens to be run during the 30 seconds (or so) while the EDIUPLD file is being uploaded from the EDI application, the ALCOBJ will error out because it can't allocate the object. However, the next time my check_edi() routine is run, that upload should have been complete, and therefore the allocate will succeed, and the user will see the message. P check_edi B D check_edi PI D signo 10I 0 value D QCMDEXC PR extpgm('QCMDEXC') D cmd 200a const D len 15p 5 const D cmd s 200a /free if %shtdn() or signo=SIGTERM; stop_check(); return; endif; cmd = 'ALCOBJ OBJ((EDIUPLD *FILE *EXCLRD *FIRST)) + WAIT(1)'; callp(e) QCMDEXC(cmd: %len(cmd)); if not %error; open EDIWARNS; exfmt EDIWARNS1; close EDIWARNS; cmd = 'DLCOBJ OBJ((EDIUPLD *FILE *EXCLRD *FIRST))'; QCMDEXC(cmd: %len(cmd)); endif; /end-free P E The operating system always passes one parameter to the signal handler--and that's the signal that was received. If it's SIGTERM, then an ENDJOB OPTION(*CNTRLD) has been issued, so I'll stop the interval timer and let the job end gracefully. The only other signal I can receive is SIGALRM. When that happens, I run the ALCOBJ. If the object allocates successfully, I'll open a display file named EDIWARNS and use EXFMT to display the notification to the user. As I said, this routine is automatically called every 60 seconds, even after my program is done running! If there's no EDIUPLD file, the user won't even know it ran. If there is an EDIUPLD file, it'll pop up a message telling the user to process it. Code Download You can download the sample program described in this article, including the display file and my copy book with all the definitions needed for the signal APIs, at the following link: samples
    8,350 pointsBadges:
    report
  • WoodEngineer
    Thank you, BigKat.
    6,875 pointsBadges:
    report
  • TomLiotta
    A relatively simple break-handling program could also be used. Create a message queue in the interactive job and assign the break-handler. Whenever any other job sends a message to the message queue, the break-handler will be called. As of V5R4, the Call Job Interrupt Program (QWCJBITP) API might also be used; but that approaches the complexity of the "TSR" solution. One potential advantage is that there might be no changes needed to the interactive job. Note that whenever a job is interrupted, processes that are currently in progress might be disrupted. Tom
    125,585 pointsBadges:
    report
  • Zack
    Thank you Tom and BigKat for your responses and suggestions. Zack
    265 pointsBadges:
    report

Forgot Password

No problem! Submit your e-mail address below. We'll send you an e-mail containing your password.

Your password has been sent to:

To follow this tag...

There was an error processing your information. Please try again later.

REGISTER or login:

Forgot Password?
By submitting you agree to receive email from TechTarget and its partners. If you reside outside of the United States, you consent to having your personal data transferred to and processed in the United States. Privacy

Thanks! We'll email you when relevant content is added and updated.

Following