× The internal search function is temporarily non-functional. The current search engine is no longer viable and we are researching alternatives.
As a stop gap measure, we are using Google's custom search engine service.
If you know of an easy to use, open source, search engine ... please contact support@midrange.com.


  • Subject: Re: User space examples using List APIs
  • From: "Scott Klement" <infosys@xxxxxxxxxxxx>
  • Date: 08 Jun 1999 16:10:01 -0500

"Dan Bale" <dbale@genfast.com> wrote:
>
> Colin & Scott,
>
> Scott, wow!!!  That was a beautiful piece of work you did in that la
>  email, I
> really appreciate the effort you made to explain everything.  I'm
>  still trying
> to get a handle on the pointer thingy, but that will take some
>  practice, I'm

Yes, pointers are a a bit confusing at first.   My philosophy for
understanding them is this:
    1) What is a variable to the system?  Its a convienient name
        used by a programmer to reference an area of memory, and
        what type of data can be found in that area of memory.
    2) What is a pointer?  its the address component of a variable!
        its the part of a variable where the address is memory is
        actually stored.
    3) You cannot directly set a pointer to a specific address,
        because many different things are happening on your computer
        and each of them is using memory.  Therefore, the operating
        system makes sure you use memory that it has allocated to
        your job.

If you think about these things, it may become clear why pointers
are useful.  Its useful to be able to tell other programs in your
job where data resides, so it can access or even change that data.

And thats why pointers are so useful in this situation.  The QUSLMBR
API and the QUSCRTUS API are both different programs.  How do you
access the same data that they populated, without doing many calls
back and forth?   Either by getting a pointer to their data, or by
sending them a pointer telling them where to put the result!  Its
actually pretty simple, when you think of it that way...

>
>  Once I did, I've been trying to clean it
> up and make it more usable.  Actually, I need to use the MBRL0200
>  format, and so
> I modified the code to handle that as well.  However, I'm stuck on h
>  to define
> the subfields for this format directly.  In IBM's example, format
>  MBRL0100 was
> used, which defines just the member name.  MbrARR, as defined below,
>  is the
> source for which the MBRL0x00 information is retrieved.  If I tried
>  change
> this to a data structure, I got errors.  So I ended up using "Eval
>  MbrARRds =
> MbrARR(index)" where MbrARRds is a data structure in which the
>  MBRL0200
> subfields are defined; not very elegant.  (I probably missed somethi
>  really
> simple here, so feel free to point it out.)
>
> d MbrARR          s            100    Based(MbrPtr) Dim(32767)
> d MbrARRds        ds           100
> d  MBName                 1     10
> d  MBSeu2                11     20
> d  MBCreateDtTm          21     33
> d  MBCCen                21     21s 0
> d  MBCDat                22     27s 0
> d  MBCTim                28     33s 0
> d  MBChangeDtTm          34     46
> d  MBUpdC                34     34s 0
> d  MBUpdD                35     40s 0
> d  MBUpdT                41     46s 0
> d  MBMTxt                47     96

I'd do it more like this:

d MbrPtr          s               *
d MbrARRds        ds                  based(MbrPtr)
d  MBName                 1     10
d  MBSeu2                11     20
d  MBCreateDtTm          21     33
d  MBCCen                21     21s 0
d  MBCDat                22     27s 0
d  MBCTim                28     33s 0
d  MBChangeDtTm          34     46
d  MBUpdC                34     34s 0
d  MBUpdD                35     40s 0
d  MBUpdT                41     46s 0
d  MBMTxt                47     96

If you do this, with the example code that I send in th  last
message, you could simply change the line that says:
     p_MbrName = OffsetPtr(p_LH: Offset)
to say:
    MbrPtr = OffsetPtr(p_LH: Offset)

and, of course, change the call to QUSLMBR to use MBRL0200 instead
of MBRL0100...  and that SHOULD be all you'd have to change.

What will, effectively, happen when you do this is that you'll be
placing the MbrARRds structure above into the area of memory that
the QUSLMBR API placed the data in.

Therefore, PRESTO, you've got your data structure populated.

In my opinion this is a much more elegant solution.  In your example,
you are, (apparently) assuming that each entry returned by QUSLMBR
will always be 100 bytes long, and that you'll never have more than
32k of them.   My method does not make these assumptions. :)

The reason IBM's books teach you to use those big nasty arrays is
because you can't do pointer arithmetic in the older versions of
RPG (such as mine!)   So how do you tell the system that you want
a pointer to move to a certain offset?   Someone came up with the
idea of putting a big array over the area, and then using the address
of each element in the array as a way of moving the pointer.

In your release (V4R2) however, you don't need to mess with the
big array thing, you can do direct pointer manipulation, as I
explained in my last post.

(I hope this is all making sense, I'm starting to feel like I'm
babbling)


>
> Also, I've never used your technique for the prototyped program call
>   The ILE
> RPG reference says that these are dynamic calls.  Isn't there a
>  performance hit
> for that (vs. static calls, i.e. CALL 'QUSCRTUS'  ParmList)?  IBM
>  doesn't let on
> why, but the ILE RPG reference also states "The recommended way to
>  call a
> program or procedure (written in any language) is to code a prototyp
>  call."
> The ILE RPG Programmer's Guide states, "You can also write ILE
>  applications that
> can interrelate with faster static calls. Static calls involve calls
>  between
> procedures.  A procedure is a self-contained set of code that perfor
>  a task
> and then returns to the caller.  An ILE RPG module consists of an
>  optional main
> procedure followed by zero or more subprocedures. Because the
>  procedure names
> are resolved at bind time (that is, when you create the program),
>  static calls
> are faster than dynamic calls."  Does this imply that called program
>  objects
> must always be dynamically called, no matter the method used to code
>  the call?
> This is not how I remember it from the RPG-III CALL op code.  I thin
>  I've got
> some reading to do.
>
> - Dan Bale

Interesting.   Unfortunately, regardless of whether you use the
CALL op-code, or whether you use a prototype with EXTPGM keyword,
they're still BOTH dynamic calls!

Anytime you're calling an object thats a *PGM, its a "dynamic" call.
It has to find the program in your library list, start a new call
level (and sometimes even new activation group!) and so forth.  This
is what a dynamic call is..

A "static" call would be calling a procedure thats bound to your
program.  Thats very different from calling another program!  Its
more akin to calling a subroutine.   The difference, of course, is
that a static call can be to a subprocedure outside of your program,
either in another module (a module thats bound at compile-time) or
a service program (which is also bound at compile time, but is still
kept in a different object elsewhere on disk)

Since your calls are to QUSCRTUS, QUSLMBR, etc, they are all dynamic
calls.  Doesn't matter if you use a prototype or not.  Some APIs
(notably the CEExxx APIs or the Unix-type APIs, such as sockets or
IFS access APIs) are "bindable".   (This basically means that IBM
put them in a service program.)

However, the QUSxxx APIs are not bindable.   In fact, they're still
accessible from OPM programs.  Whether you prototype the call and
use callp or whether you use the CALL op-code, they're exactly the
same!

If they WERE bindable, how much difference would it make?  Not much.
You're doing, what, 3 calls?   One to create the user space, one
to list the members, and one to get a pointer?  The total time that
you'd save by static calls here is probably under a tenth of a second.

The main part that needs to be fast is the part that you're doing in
a loop.  The part that can be done, potentially, thousands of times.
and THAT part is using direct pointer access to the user space, not
making calls at all!

Heh... okay, I've been long-winded enough :)   Now let me know
if any of this made sense :)

Scott Klement
Information Systems Manager
Klement's Sausage Co, Inc
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* This is the RPG/400 Discussion Mailing List!  To submit a new         *
* message, send your mail to "RPG400-L@midrange.com".  To unsubscribe   *
* from this list send email to MAJORDOMO@midrange.com and specify       *
* 'unsubscribe RPG400-L' in the body of your message.  Questions should *
* be directed to the list owner / operator: david@midrange.com          *
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *


As an Amazon Associate we earn from qualifying purchases.

This thread ...


Follow On AppleNews
Return to Archive home page | Return to MIDRANGE.COM home page

This mailing list archive is Copyright 1997-2024 by midrange.com and David Gibbs as a compilation work. Use of the archive is restricted to research of a business or technical nature. Any other uses are prohibited. Full details are available on our policy page. If you have questions about this, please contact [javascript protected email address].

Operating expenses for this site are earned using the Amazon Associate program and Google Adsense.