I have already written about how to delay a RPG program by less than a second by using the USLEEP procedure. Now I need to do the same in a CL program.
As we are in 2021 I hope that all of your CL source members are all the type CLLE. The program I am going to show must be compiled using the Create Bound CL program command, CRTBNDCL, not using the Create CL program command, CRTCLPGM, which is the default for type CLP.
USLEEP is a UNIX type API. This means that it is case sensitive. When I use it in a program I must use usleep, and not USLEEP or Usleep. I am just going to refer to it in the text of this post as USLEEP as it is easier for you to see its name amongst the rest of the text.
Let me jump straight in and show the code for the simple program I wrote to show how to use USLEEP in a CL program.
01 PGM 02 DCL VAR(&MICROSECS) TYPE(*UINT) LEN(4) 03 DCL VAR(&RTNVAL) TYPE(*UINT) LEN(4) 04 CHGVAR VAR(&MICROSECS) VALUE(999999) 05 CALLPRC PRC('usleep') PARM((&MICROSECS *BYVAL)) + RTNVAL(&RTNVAL) 06 ENDPGM |
Line 2: In RPG this was a 10 long unsigned integer type variable. In CL it is still an unsigned integer, but it is four long. Notice that when I define the unsigned integer with no decimal places because an integer cannot contain a fraction of any number.
Line 3: This will contain the value returned from USLEEP. It is optional, and I am only including this to illustrate an issue later on.
Line 3: I am changing the value in &MICROSECS to be one microsecond less than a second.
Line 5: This is where I call USLEEP. As USLEEP is an external procedure I call it using the Call Procedure command, CALLPRC. I am passing the micro seconds, and getting the return value from the procedure in the &RTNVAL variable. Just for now ignore the *BYVAL I will talk about that later.
I place a debug break point at line 6, and call the program. When I check the value that was returned by USLEEP I see:
RTNVAL = 0 |
This means that the procedure was called and it executed without error.
What about the *BYVAL?
There are two ways I can pass a parameter to a procedure:
- By value: *BYVAL
- By reference: *BYREF
Parameters: Parameter . . . . . . > &MICROSECS Passed . . . . . . . . *BYVAL *BYREF, *BYVAL |
By passing by value means that USLEEP receives a copy of the parameter. Any changes made within the procedure do not change the value in the CL variable.
Passing by reference means that the pointer address of the variable is passed to the procedure.
The default for the CALLPRC command is *BYREF. If I change line 5 to be:
05 CALLPRC PRC('usleep') PARM((&MICROSECS)) + RTNVAL(&RTNVAL) |
The CALLPRC uses the default, *BYREF. When I call the program the value in &RTNVAL is not blank, which indicates that there was an error in the procedure.
&RTNVAL = 4294967295 |
Which is why I pass the micro seconds by value, not reference.
As you have seen it is as easy to call USLEEP in a CL as it is in RPG. So next time you need to delay job by a fraction of a second your CL programs don't have to call a RPG program to do so.
This article was written for IBM i 7.4, and should work for some earlier releases too.
This looks interesting. Thank you for posting.
ReplyDeleteThere is a typo in the text:
By reference: *BAYREF
Oops. Thank you for pointing that out. The correction has been made.
DeleteTechnically, &RTNVAL should be integer not unsigned integer and this is respectful of the prototype exposed by the API.
ReplyDeleteIn fact, you are getting a big number as an error, buy should be a negative number, that's the way of posix apis...
thanks
see this (follows by previous email) by IBM that confirm this
ReplyDeletehttps://www.ibm.com/support/pages/example-using-c-api-usleep
simple and cool Simon, thanks
ReplyDeleteGreat, thank you Simon for sharing!
ReplyDelete