365 lines
16 KiB
HTML
365 lines
16 KiB
HTML
<?xml version="1.0" encoding="UTF-8"?>
|
|
<!DOCTYPE html
|
|
PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
|
|
<html lang="en-us" xml:lang="en-us">
|
|
<head>
|
|
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
|
|
<meta name="security" content="public" />
|
|
<meta name="Robots" content="index,follow" />
|
|
<meta http-equiv="PICS-Label" content='(PICS-1.1 "http://www.icra.org/ratingsv02.html" l gen true r (cz 1 lz 1 nz 1 oz 1 vz 1) "http://www.rsac.org/ratingsv01.html" l gen true r (n 0 s 0 v 0 l 0) "http://www.classify.org/safesurf/" l gen true r (SS~~000 1))' />
|
|
<meta name="DC.Type" content="reference" />
|
|
<meta name="DC.Title" content="Example 2: An i5/OS ILE program that uses pointer arguments in a call to an i5/OS PASE procedure" />
|
|
<meta name="abstract" content="In this example, an i5/OS ILE program uses two different techniques to allocate and share memory storage with the i5/OS PASE procedure that it calls." />
|
|
<meta name="description" content="In this example, an i5/OS ILE program uses two different techniques to allocate and share memory storage with the i5/OS PASE procedure that it calls." />
|
|
<meta name="DC.Relation" scheme="URI" content="rzalfileproccalls.htm" />
|
|
<meta name="copyright" content="(C) Copyright IBM Corporation 2000, 2006" />
|
|
<meta name="DC.Rights.Owner" content="(C) Copyright IBM Corporation 2000, 2006" />
|
|
<meta name="DC.Format" content="XHTML" />
|
|
<meta name="DC.Identifier" content="rzalfileproccallsexamp2" />
|
|
<meta name="DC.Language" content="en-us" />
|
|
<!-- All rights reserved. Licensed Materials Property of IBM -->
|
|
<!-- US Government Users Restricted Rights -->
|
|
<!-- Use, duplication or disclosure restricted by -->
|
|
<!-- GSA ADP Schedule Contract with IBM Corp. -->
|
|
<link rel="stylesheet" type="text/css" href="./ibmdita.css" />
|
|
<link rel="stylesheet" type="text/css" href="./ic.css" />
|
|
<title>Example 2: An i5/OS ILE program that uses pointer arguments in a
|
|
call to an i5/OS PASE
|
|
procedure</title>
|
|
</head>
|
|
<body id="rzalfileproccallsexamp2"><a name="rzalfileproccallsexamp2"><!-- --></a>
|
|
<!-- Java sync-link --><script language="Javascript" src="../rzahg/synch.js" type="text/javascript"></script>
|
|
<h1 class="topictitle1">Example 2: An i5/OS ILE program that uses pointer arguments in a
|
|
call to an i5/OS PASE
|
|
procedure</h1>
|
|
<div><p>In this example, an <span class="keyword">i5/OS™</span> ILE
|
|
program uses two different techniques to allocate and share memory storage
|
|
with the <span class="keyword">i5/OS</span> PASE procedure
|
|
that it calls.</p>
|
|
<div class="example"><img src="./delta.gif" alt="Start of change" /><div class="note"><span class="notetitle">Note:</span> By using the following code examples, you
|
|
agree to the terms of the <a href="codedisclaimer.htm">Code license and disclaimer information</a>.</div>
|
|
<pre>/* Name: ileMain.c
|
|
*
|
|
* Call an i5/OS PASE procedure from ILE
|
|
*
|
|
* This example uses the Qp2dlopen, Qp2dlsym, and Qp2CallPase2 ILE
|
|
* functions to call an i5/OS PASE function passing in parameters
|
|
*
|
|
* Compile like so:
|
|
*
|
|
* CRTBNDC PGM(mylib/ilemain)
|
|
* SRCFILE(mylib/mysrcpf)
|
|
* TERASPACE(*YES *TSIFC)
|
|
*/
|
|
#include <stdio.h>
|
|
#include <stddef.h>
|
|
#include <errno.h>
|
|
#include <qp2user.h>
|
|
/* Use EBCDIC default job CCSID in Qp2dlopen and Qp2dlsym calls */
|
|
#define JOB_CCSID 0
|
|
|
|
/* start i5/OS PASE in this process */
|
|
void startPASE(void) {
|
|
/* start64 starts the 64 bit version of i5/OS PASE */
|
|
char *start64Path="/usr/lib/start64";
|
|
char *arg_list[2];
|
|
|
|
arg_list[0] = start64Path;
|
|
arg_list[1] = NULL;
|
|
Qp2RunPase(start64Path,
|
|
NULL,
|
|
NULL,
|
|
0,
|
|
819,
|
|
(char**)&arg_list,
|
|
NULL);
|
|
|
|
}
|
|
|
|
/* open a shared library */
|
|
|
|
QP2_ptr64_t openlib(char * libname) {
|
|
QP2_ptr64_t id;
|
|
int * paseErrno;
|
|
|
|
/* Qp2dlopen dynamically loads the specified library returning an
|
|
* id value that can be used in calls to Qp2dlsym and Qp2dlcose */
|
|
id = Qp2dlopen(libname,
|
|
(QP2_RTLD_NOW |
|
|
QP2_RTLD_MEMBER ),
|
|
JOB_CCSID);
|
|
if (id == 0) {
|
|
printf("Qp2dlopen failed. ILE errno=%i\n", errno);
|
|
if ((paseErrno=Qp2errnop()) != NULL)
|
|
printf("Qp2dlopen failed. i5/OS PASE errno=%i\n", *paseErrno);
|
|
printf("Qp2dlopen failed. Qp2dlerror = %s\n", Qp2dlerror());
|
|
}
|
|
|
|
return(id);
|
|
}
|
|
|
|
/* find an exported symbol */
|
|
|
|
void * findsym(const QP2_ptr64_t id, const char * functionname) {
|
|
void * symbol;
|
|
int * paseErrno;
|
|
|
|
/* Qp2dlsym locates the function descriptor for the
|
|
* specified function */
|
|
symbol = Qp2dlsym(id, functionname, JOB_CCSID, NULL);
|
|
if (symbol == NULL) {
|
|
printf("Qp2dlsym failed. ILE errno = %i\n", errno);
|
|
if ((paseErrno=Qp2errnop()) != NULL)
|
|
printf("Qp2dlsym failed. i5/OS PASE errno=%i\n", *paseErrno);
|
|
printf("Qp2dlsym failed. Qp2dlerror = %s\n", Qp2dlerror());
|
|
}
|
|
return(symbol);
|
|
}
|
|
|
|
/* call i5/OS PASE procedure */
|
|
int callPASE(const void * functionsymbol,
|
|
const void * arglist,
|
|
const QP2_arg_type_t * signature,
|
|
const QP2_result_type_t result_type,
|
|
void * buf,
|
|
const short buflen) {
|
|
int * paseErrno;
|
|
int rc;
|
|
|
|
/* Call Qp2CallPase2 to run the unction function */
|
|
rc = Qp2CallPase2(functionsymbol,
|
|
arglist,
|
|
signature,
|
|
result_type,
|
|
buf,
|
|
buflen);
|
|
if (rc != 0) {
|
|
printf("Qp2CallPase failed. rc=%i, ILE errno=%i\n", rc, errno);
|
|
if ((paseErrno=Qp2errnop()) != NULL)
|
|
printf("Qp2CallPase failed. i5/OS PASE errno=%i\n", *paseErrno);
|
|
printf("Qp2CallPase failed. Qp2dlerror=%s\n", Qp2dlerror());
|
|
}
|
|
}
|
|
|
|
|
|
int main(int argc, char *argv[])
|
|
{
|
|
/* we will call a function in i5/OS PASE named "paseFunction"
|
|
* the prototype for the function looks like this:
|
|
* int paseFunction(void * input, void * output ) */
|
|
|
|
/* "signature" is the argument signature for the PASE routine "paseFunction" */
|
|
const QP2_arg_type_t signature[] = {QP2_ARG_PTR64, QP2_ARG_PTR64, QP2_ARG_END};
|
|
|
|
/* "paseFunctionArglist" are the arguments for the PASE routine "paseFunction" */
|
|
struct {
|
|
QP2_ptr64_t inputPasePtr;
|
|
QP2_ptr64_t outputPasePtr;
|
|
} paseFunctionArglist;
|
|
|
|
|
|
/* "inputString" will be one of the arguments to the PASE routine
|
|
* "paseFunction" we will call
|
|
* This is the string "input" in ASCII */
|
|
const char inputString[] = {0x69, 0x6e, 0x70, 0x75, 0x74, 0x00};
|
|
|
|
/* "outputILEPtr" will be a pointer to storage malloc'd from PASE heap */
|
|
char * outputILEPtr;
|
|
|
|
/* "id" is the identifier for the library opened by Qp2dlopen */
|
|
QP2_ptr64_t id;
|
|
|
|
/* "paseFunction_ptr" is the pointer to the routine "paseFunction" in PASE */
|
|
void * paseFunction_ptr;
|
|
|
|
/* "inputAndResultBuffer" is the buffer of storage shared between ILE and PASE
|
|
* by Qp2CallPase2. This buffer contains space for the PASE function result */
|
|
struct {
|
|
QP2_dword_t result;
|
|
char inputValue[6];
|
|
} inputAndResultBuffer;
|
|
|
|
int rc;
|
|
int * paseErrno;
|
|
|
|
/* start i5/OS PASE in this process */
|
|
startPASE();
|
|
|
|
id = openlib("/home/joeuser/libpasefn.a(shr64.o)");
|
|
|
|
if (id !=0) {
|
|
/* Locate the symbol for "paseFunction" */
|
|
paseFunction_ptr = findsym(id, "paseFunction");
|
|
|
|
if (paseFunction_ptr != NULL) {
|
|
|
|
/* set input arguments for the call to paseFunction() */
|
|
|
|
/* copy the inputString into the inputAndResultBuffer */
|
|
strcpy(inputAndResultBuffer.inputValue, inputString);
|
|
|
|
/* by setting inputPasePtr argument to the offset of the
|
|
* inputValue by-address argument data in the
|
|
* inputAndResultbuffer structure and OR'ing that with
|
|
* QP2_ARG_PTR_TOSTACK QP2CallPase2 will "fixup" the
|
|
* actual argument pointer passed to the PASE function
|
|
* to point to the address (plus the offset) of the
|
|
* copy of the inputAndResultbuffer that Qp2CallPase2
|
|
* copies to i5/OS PASE storage */
|
|
paseFunctionArglist.inputPasePtr =
|
|
(QP2_ptr64_t)((offsetof(inputAndResultBuffer, inputValue))
|
|
| QP2_ARG_PTR_TOSTACK);
|
|
|
|
/* allocate memory from the i5/OS PASE heap for an output
|
|
* argument. Qp2malloc will also set the i5/OS PASE address
|
|
* of the allocated storage in the outputPasePtr
|
|
* argument */
|
|
outputILEPtr = Qp2malloc(10, &(paseFunctionArglist.outputPasePtr));
|
|
|
|
/* Call the function in i5/OS PASE */
|
|
rc = callPASE(paseFunction_ptr,
|
|
&paseFunctionArglist,
|
|
signature,
|
|
QP2_RESULT_DWORD,
|
|
&inputAndResultBuffer,
|
|
sizeof(inputAndResultBuffer));
|
|
if (rc != 0) {
|
|
|
|
printf("output from paseFunction = >%s<\n",
|
|
(char*)outputILEPtr);
|
|
printf("return code from paseFunction = %d\n",
|
|
(int)inputAndResultBuffer.result);
|
|
} /* rc != 0 */
|
|
} /* paseFunction_ptr != NULL */
|
|
} /* id != 0 */
|
|
|
|
/* Close the Qp2dlopen instance, and then call Qp2EndPase
|
|
* to end i5/OS PASE in this job */
|
|
Qp2dlclose(id);
|
|
Qp2EndPase();
|
|
return 0;
|
|
}
|
|
|
|
Source code for the i5/OS Procedure paseFunction that is called by the ileMain.c program:
|
|
|
|
/* i5/OS PASE function to be called from ILE
|
|
*
|
|
* Compile with something like:
|
|
* xlc -q64 -c -o paseFunction.o paseFunction.c
|
|
* ld -b64 -o shr64.o -bnoentry -bexpall -bM:SRE -lc paseFunction.o
|
|
* ar -X64 -r /home/joeuser/libpasefn.a shr64.o
|
|
*
|
|
* The ILE side of this example expects to find libpasefn.a in
|
|
* /home/joeuser/libpasefn.a
|
|
*
|
|
* The compiler options -qalign=natural and -qldbl128 are
|
|
* necessary only when interacting with i5/OS ILE programs
|
|
* to force relative 16-byte alignment of type long double
|
|
* (used inside type ILEpointer)
|
|
*/
|
|
|
|
#include <stdlib.h>
|
|
#include <stdio.h>
|
|
int paseFunction(void * inputPtr, void * outputPtr)
|
|
{
|
|
/* An output string to return from i5/OS PASE to ILE *
|
|
* this is the string "output" in EBCDIC */
|
|
const char outputValue[] = {0x96, 0xa4, 0xa3, 0x97, 0xa4, 0xa3, 0x00};
|
|
|
|
|
|
printf("Entered paseFunction The input is >%s<\n",
|
|
(char*)inputPtr);
|
|
|
|
/* copy the output results to the outputPtr argument */
|
|
memcpy(outputPtr, outputValue, sizeof(outputValue));
|
|
|
|
|
|
return(52); /* return something more interesting than 0 */
|
|
}</pre>
|
|
<img src="./deltaend.gif" alt="End of change" /></div>
|
|
<div class="section"><img src="./delta.gif" alt="Start of change" /><h4 class="sectiontitle">Various functions used in the ILE portion
|
|
of Example 2</h4><ul><li><strong>The startPASE() function</strong><p>Before i5/OS PASE can be used in a process, it
|
|
must be started. This is done automatically by calling an i5/OS PASE application
|
|
main entry point using the APIs, for example, QP2SHELL, QP2TERM, or Qp2RunPase.</p>
|
|
<p>However,
|
|
because this example is calling an i5/OS PASE function exported from a shared
|
|
library (not a main entry point), you must manually start i5/OS PASE. Two i5/OS PASE
|
|
starter utilities are available for this purpose: /usr/lib/start32 (to start
|
|
the 32-bit version of i5/OS PASE) and /usr/lib/start64 (to start the 64-bit
|
|
version of i5/OS PASE).</p>
|
|
<div class="p">Be
|
|
aware that each i5/OS process
|
|
can only have a single instance of i5/OS PASE running. The Qp2ptrsize() API
|
|
can be used to determine whether i5/OS PASE is already running. <ul><li>Qp2ptrsize() will return <tt class="sysout">0</tt> if i5/OS PASE is
|
|
not currently active in the process.</li>
|
|
<li>Qp2ptrsize() will return <tt class="sysout">4</tt> if i5/OS PASE is
|
|
active in 32-bit mode.</li>
|
|
<li>Qp2ptrsize() will return <tt class="sysout">8</tt> if i5/OS PASE is
|
|
active in 64-bit mode.</li>
|
|
</ul>
|
|
</div>
|
|
</li>
|
|
<li><strong>The openlib() and findsym() functions</strong><p>These functions open the i5/OS shared
|
|
library and obtain a pointer to the function you want to call using the Qp2dlopen()
|
|
and Qp2dlsym(). These functions are similar to the dlopen() and dlsym() routines
|
|
on many platforms.</p>
|
|
</li>
|
|
<li><strong>Set up arguments for the Qp2CallPase2 call</strong><p>Before calling Qp2CallPase2()
|
|
through the callPASE() function, the main() routine sets up the following
|
|
variables that define the interface between ILE and the i5/OS PASE function:</p>
|
|
<ul><li>The signature-array variable defines the arguments for the i5/OS PASE function.
|
|
The elements in the array are typically set using the #define found in the
|
|
qsysinc/h.qp2user include file.</li>
|
|
<li>The paseFunctionArglist structure contains the ILE variables that the i5/OS PASE
|
|
run time will map into the arguments that will be passed to the i5/OS PASE function
|
|
when the function is called. The members in paseFunctionArglist correspond
|
|
to the signature of the i5/OS PASE function declared in the signature array.</li>
|
|
<li>The inputAndResultBuffer structure contains the ILE variables that the i5/OS PASE
|
|
run time will use as a sort of shared buffer between ILE and the i5/OS PASE function
|
|
when the function is called. <p>The first member of the structure (<dfn class="term">result</dfn> in
|
|
this example) will contain the return value from the i5/OS PASE function. This variable must
|
|
match the result-type argument provided as the fourth argument in the call
|
|
to the Qp2CallPase2 API. Anything after this first element represents storage
|
|
that will be copied into the i5/OS PASE environment when the function is called.</p>
|
|
<p>In
|
|
this example, the inputValue element of the inputAndResultBuffer structure
|
|
will contain the by-address argument data that will be pointed at by the first
|
|
argument for the i5/OS PASE
|
|
function.</p>
|
|
</li>
|
|
<li>This example uses two different ways of setting pointer arguments for
|
|
the i5/OS PASE
|
|
function that is being called. <ul><li>The second argument to the function, paseFunctionArglist.outputPasePtr,
|
|
is set by calling the Qp2malloc() function. Qp2malloc() allocates memory from
|
|
the i5/OS PASE
|
|
runtime heap and returns both an ILEpointer and an i5/OS PASE pointer to the allocated storage.</li>
|
|
<li>The first argument, paseFunctionArglist.inputPasePtr, is set to the offset
|
|
of the inputValue element of the inputAndResultBuffer structure that is connected
|
|
with the qp2user.h #define QP2_ARG_PTR_TOSTACK by OR.<p>This tells the i5/OS PASE
|
|
run time to modify the actual pointer value provided on the call to the i5/OS PASE
|
|
function with the address where the inputAndResultBuffer.inputValue was copied
|
|
into i5/OS PASE
|
|
memory.</p>
|
|
</li>
|
|
</ul>
|
|
</li>
|
|
</ul>
|
|
</li>
|
|
<li><strong>The callPASE() function</strong><p>This function calls the i5/OS PASE function
|
|
using the Qp2CallPase2() API and the arguments set in the main() routine.</p>
|
|
</li>
|
|
<li><strong>End i5/OS PASE
|
|
in the process</strong><p> After the call to the i5/OS PASE function, the Qp2dlclose() API
|
|
is called to unload the i5/OS PASE shared library and Qp2EndPase() is called
|
|
to end the start64 program called at the beginning of the example.</p>
|
|
</li>
|
|
</ul>
|
|
<img src="./deltaend.gif" alt="End of change" /></div>
|
|
</div>
|
|
<div>
|
|
<div class="familylinks">
|
|
<div class="parentlink"><strong>Parent topic:</strong> <a href="rzalfileproccalls.htm" title="You can call the Qp2CallPase() and Qp2CallPase2() ILE procedures from within other ILE procedures to run an i5/OS PASE program in a job where the i5/OS PASE environment is already running.">Call an i5/OS PASE procedure from within i5/OS programs</a></div>
|
|
</div>
|
|
</div>
|
|
</body>
|
|
</html> |