mixed mode

Upload: milindmahadik

Post on 05-Apr-2018

224 views

Category:

Documents


0 download

TRANSCRIPT

  • 7/31/2019 Mixed Mode

    1/22

    Mixed-mode on Itanium-based platforms:why and how

    Introduction ..............................................................................................................................

    Executive summary ....................................................................................................................Mixed-mode: why......................................................................................................................

    Mixed-mode: in the past.............................................................................................................

    Mixed-mode: how .....................................................................................................................

    Mixed-mode: shared memory ..................................................................................................

    Mixed-mode: remote procedure call .........................................................................................

    Mixed-mode: performance ......................................................................................................

    Mixed-mode: guidelines..........................................................................................................

    Summary................................................................................................................................1

    Glossary.................................................................................................................................1

    For more information ...............................................................................................................1Appendix ...............................................................................................................................1

    HP-UX 11i release names and release identifiers......................................................................2

  • 7/31/2019 Mixed Mode

    2/22

    Introduction

    As HP customers make the transition from Precision Architecture (PA) to the Intel Itanium architecture, some aregoing to find themselves in the position of wanting to execute PA binaries on the Itanium-based platform. HP hasprovided the Dynamic Object Code Translator (code name Aries) to accommodate this need. Aries transparentlytranslates the PA code into Intel Itanium processor code on-the-fly, and offers performance sufficient for manyprograms that are not compute intensive. However, Aries must operate at the level of a complete program unit;you cannot have a main program written for the Itanium architecture call a PA function, nor vice versa. This canbe problematic in situations where the PA code is a third-party library that does not exist on Itanium-basedplatforms or when there is not time to port/recompile all the parts of the application. To overcome this problem,

    this paper offers two methods of creating mixed-mode applications, i.e., applications where code for onearchitecture is making calls to code in the other architecture. The two methods offered are the use of sharedmemory and the use of Remote Procedure Calls (RPC).

    Many customers will not need mixed-mode code, but those who need it will have few alternatives. The majorissues in constructing mixed-mode applications are process synchronization, data transfer and alignment, andre-entrant code. This paper provides information on how to address these issues in constructing mixed-modeapplications. It also provides guidelines for the use of this technology and performance comparisons that mayhelp to determine what the result of implementing a mixed-mode application will be.

    Executive summary

    In the transition from Precision Architecture to the Intel Itanium architecture, it may be necessary to create mixed-mode programs, i.e., programs where a library function written for one architecture must be called by codewritten for the other architecture. The tools provided for migrating applications between these architectures do nodirectly support this facility. This paper outlines a general method for accomplishing mixed-mode and two differenimplementations of the method. The issues associated with the method and implementations are discussed, andguidelines for the use of the methods and the implementations are provided. The method involves encapsulatingthe library in a server program, which can then be run under the HP-provided Dynamic Object Code Translator(DOCT/Aries). The calling program is modified by creating a stub for the library that sends data to the server andreceives the results back.

    There are performance impacts with this approach, but they are not always significant. This paper outlinessituations where the performance impact will be less significant and where it will be more significant.

    Mixed-mode: whyIn migrating from Precision Architecture to the Intel Itanium architecture, there are situations where the need formixed-mode applications can arise. Some examples are:

    The application requires a third-party library that is no longer in production (or the supplier has ceasedoperation). All that exists is the PA library binaryno source code is available.

    The application consists of complicated legacy (not easily ported) user interface code that feeds a compute-intensive core function that needs to be run faster. The core function can be ported quickly, but the user interfaccode would take too long.

    The application is large, consisting of many modules; and resource limitations dictate that it can only be portedincrementally, one source module at a time, but there isnt time to wait for all of it to be finished.

    All of these situations, and others, have a need for the ability to run programs that consist of a mix of Intel Itaniumarchitecture and Precision Architecture modules. If the module needed is actually a program, the situation canbe handled by the Dynamic Object Code Translator (Aries)and data can be passed between translated andnative programs. If the module is a function or group of functions, Aries cannot be invokedit operates only atthe program level.

    The need, then, is for a method to create a separate program that contains the needed function(s), and then toprovide a way to pass data back and forth between it and the main portion of the program.

    Mixed-mode on Itanium-based Platforms

  • 7/31/2019 Mixed Mode

    3/22

    Mixed-mode: in the past

    Historically, in the transition from the HP 3000 classic architecture to Precison Architecture, support wasprovided for mixed-mode applications. Tools were created to describe the interface between the routines, andstubs that would change the processor mode were created to enable mixed-mode processing to occur.

    In the transition from PA to the Intel Itanium architecture, it was decided that adding the overhead of checking formixed-mode to every function/subroutine/method call would be too large a penalty to pay for the convenience omixed-mode. This decision was based on the fact that there are fewer organizations running on home-grownsoftware; more companies now run on purchased applications that will be ported completely to Intel Itanium

    architecture by the application vendor. The number of companies who will need mixed-mode is expected to bemuch smaller.

    Mixed-mode: how

    The key to allowing code from the two different architectures (PA and Intel Itanium) to interoperate at a functionlevel is to raise the granularity of the interoperation from module-to-module to program-to-program. In this way,

    Aries can be used to run the PA portion of the code (because it is a program, not a function), and the Intel Itaniumprocessor code can run natively. The following graphic illustrates the situation:

    Figure 1. Mixed-mode: general architecture

    The key element in this method of creating a two-process mixed-mode application is the inter-processcommunication that occurs between the two processes. This communication must provide four basic functions:

    1. Transmission of the data from the calling process to the server process.

    2. Notification of the server process that data is ready.3. Notification of the calling process that the data has been processed and results are available.

    4. Transmission of the results back from the server process to the calling process.

    Mixed-mode on Itanium-based Platforms

  • 7/31/2019 Mixed Mode

    4/22

    There are quite a few forms of inter-process communication that are capable of meeting these basic requirementsSome of the candidates are:

    Shared filesrelatively high overhead, but suitable for really LARGE data. Synchronization must be provided bsome other method.

    Pipesgood choice, but requires marshaling of data to maintain alignment between the processes and has amoderate amount of system call overhead.

    Shared memoryfast; requires attention to alignment between 64- and 32-bit processes; requires a form ofsynchronization.

    Remote procedure callsbased on distributed computing environment (DCE) or open network computing

    (ONC). This method provides automatic data marshaling but has significant overhead. It can be inter-machineas well as inter-process, perhaps helping in situations with data migration issues. Synchronization is inherent inthe mechanism. Both mechanisms are available on HP-UX for Itanium-based systems, and obsolescence is notplanned for either.

    There are many choices for the inter-process communication. The two chosen for this discussion were based onavailable knowledge and the contrast between the two. They are:

    Shared memory with semaphore synchronization.

    Remote procedure calls based on DCE.

    In both cases, the two-process mixed-mode is implemented in several pieces:

    1. Code to create the communication infrastructuredata movement and synchronization.

    2. A stub routine to replace the original routine. This stub accepts the input data, sends the data to the other (serprocess, accepts the returned results, and returns the results to the main program.

    3. The server process that encapsulates the original routine. This process accepts the data sent from the stub in thmain, passes this data to the original routine, accepts the results back from the routine, and sends these resuback to the main program.

    4. The Dynamic Object Code Translator (DOCT)it runs the process containing the original (PA) routine.

    The following sections provide greater detail on how these pieces are created in the original (main) process, andin the new (server) process.

    Mixed-mode on Itanium-based Platforms

  • 7/31/2019 Mixed Mode

    5/22

    Mixed-mode: shared memoryIn the shared-memory implementation of two-process mixed-mode, data is passed between the two processesthrough a shared-memory segment, and synchronization is accomplished by using two semaphoresone toindicate input is available, and the other to indicate that results are available. For the sake of illustration, we willassume that the main program will run natively on the Intel Itanium architecture, and the server process will berunning under DOCT. Note that this means that the server process must be compiled and linked with the PAlibrary binary on a PA system.

    This method is illustrated in the figure below.

    Figure 2. Mixed-mode using shared memory

    One of the issues in client/server systems is the need for re-entrant code. What happens if several programs areusing the library routine at once? In this case, each instance of the main program, assumed to be single-threadedwill create its own copy of the server process so that the routine will always be executing in response to only onecall to it. Therefore, the code need not be re-entrant.

    To implement this method of mixed-mode, the following additions are made to the original main program:

    1. The shared memory segment and semaphores are created.

    2. The server program is started up. The keys to accessing the shared memory and semaphores are passed to it

    startup.3. The original routine is replaced by the stub routine that places the input data into shared memory and raises t

    input ready semaphore. The stub then waits on the results ready semaphore. When the semaphore is raisthe stub reads the results from shared memory and then returns them to the calling program.

    4. At the end of the program, the server process is killed and the shared memory and semaphores are released.

    Mixed-mode on Itanium-based Platforms

  • 7/31/2019 Mixed Mode

    6/22

    The server process (which is compiled and linked on a PA system in Figure 2) consists of several parts:

    1. The attachment to the shared memory and semaphores, based on the keys passed in.

    2. Waiting on the input ready semaphore. When it is raised, read in the data from shared memory.

    3. Call the original routine, passing it the input data.

    4. Take the results returned by the routine and place them in shared memory.

    5. Raise the results ready semaphore to signal the main.

    6. Return to waiting on the input ready semaphore.

    The major issues that are liable to be encountered in this method have to do with differing data sizes and

    alignments between 32- and 64-bit program models. These differences occur only when the library and main arenot running under the same model (32- or 64-bit). This is not a problem if both programs are running under thesame model.

    The size differences are as follows:

    Data type Size in 32-bit model Size in 64-bit model

    Pointer 32 bits (4 bytes) 64 bits (8 bytes)

    Long integer 32 bits (4 bytes) 64 bits (8 bytes)

    Most data types are aligned on byte addresses equivalent to their size, i.e., 8-byte data types are aligned on bytaddresses that are divisible by 8 (8-byte boundaries), and 4-byte data types are aligned on byte addresses thatare divisible by 4 (4-byte boundaries).

    The exception to this is the long double data type. This data type is 16 bytes (128 bits) long and is aligned on16-byte boundaries on PA in both the 32- and 64-bit models. On the Intel Itanium architecture, it aligns on 16-bytboundaries in the 64-bit model, but it aligns on 8-byte boundaries under the 32-bit model.

    Generally, alignment problems occur only if structures are being passed in shared memory. The rationale fordoing this is to create a structure containing all the parameters to be passed to the routine and then copy thestructure to shared memory. This is elegant, but it can create problems due either to alignment or to differing datasizes. Unless it is known that there are no data size differences, and no alignment (long double) issues, it is better

    to use a different method for placing the parameters into shared memory.The most foolproof method is to use an appropriately incremented pointer to place each parameter in sharedmemory individually and extract them in a similar manner in the server process. If long integers are beingpassed between 64-bit and 32-bit programs, the size must be taken into account and overlap or incorrect pointeravoided. Sometimes debugging the parameter placement by printing the addresses of the variables in sharedmemory from both original and server processes is a good idea, as this can quickly show misalignment of wherevariables are deemed to be placed by the two processes.

    Mixed-mode on Itanium-based Platforms

  • 7/31/2019 Mixed Mode

    7/22

    Mixed-mode: remote procedure callIn the remote procedure call (RPC) implementation of two-process mixed-mode, the data is passed between thetwo processes through the provided remote procedure call mechanism. This mechanism provides data marshalingand conversion, where needed, and is inherently synchronized. The mechanism allows remote calls, i.e., calls to procedure on another system, made via the network. This can allow the routine to run natively on a PA system,which might be useful if the routine reads or writes data files that would have alignment problems on the IntelItanium architecture (mainly as an interim step). For this illustration, we will assume that the main program isrunning natively on the Itanium architecture, and the server process has been created on a PA system and isrunning on an Itanium-based system under DOCT. In either case, the overhead of making each call is relativelyhighthis method may not be best for routines that expect to be called thousands of times per second.

    This method is illustrated in the figure below.

    Figure 3. Mixed-mode using RPC

    The DCE RPC mechanism handles the re-entrancy requirement transparentlyno further consideration of this issueis needed.

    To implement this method of mixed-mode, the following changes are made to the original program:

    1. The DCE connection to the server is initialized. This is best accomplished using boilerplate code.

    2. The original routine is replaced by the stub routine that translates the function call to the RPC call and then retthe results to the main.

    It is best to use the templates and Makefiles created for this paper to accomplish this activityDCE RPC is toocomplex to figure out on your own just for this project. Makefiles and templates are available on the HP DSPP

    Web site at http://atwnt959.external.hp.com/dspp/files/unprotected/ItaniumMixedMode.tar

    The server program is created in two partsthe server process and a container function that calls the originalfunction and returns the results. They are linked together at link time. The server program has three main functionasections:

    1. Registration of this service with the rpcd daemon. This is best left to the boilerplate code.

    2. Listen for the remote procedure calls and process them by calling the container function. This is done in one cathat actually contains the processing loop.

    3. Code to unregister the servicethis is normally never used, as the server waits for more calls until it is killed.

    Mixed-mode on Itanium-based Platforms

    http://atwnt959.external.hp.com/dspp/files/unprotected/ItaniumMixedMode.tarhttp://atwnt959.external.hp.com/dspp/files/unprotected/ItaniumMixedMode.tar
  • 7/31/2019 Mixed Mode

    8/22

    Construction of the main and server includes the creation of an Interface Definition file in the Interface DefinitionLanguage (IDL). This file describes the parameters to the call being made, in terms of what data type eachparameter is, and whether it is an input, output, or both. The compilation and linking together of these elements isbest done with the Makefiles provided. See the code and Makefile examples in the Appendix.

    The major issues that are likely to be encountered with this method involve the complexity of the DCE code(handled by using the templates referenced) and the overhead cost of each call if many are being made. See thefollowing section for details.

    Mixed-mode: performance

    Both of these methods involve executing at least a process context switch for each call, so the call mechanism ismuch more expensive, in terms of time taken, than the direct native procedure call. The RPC call overhead isapproximately 0.45 milliseconds on an HP Server rx2600 (Itanium 2-based 900 MHz system), and the shared-memory overhead is less than 0.01 milliseconds on the same system.

    From this, we can see that if the legacy library routine is called very often (hundreds to thousands of times asecond), it may cause noticeable performance degradation. If the legacy routine is not called this often, and itsnormal operation takes greater than 1 millisecond, the effect may not be noticeable, especially with the shared-memory method.

    Performance of code running under the DOCT, compared with the performance when running on the PA systemwill vary, depending on the application characteristics and which Itanium-based system it is running on.Measurements with the first generation of Itanium-based systems showed performance that was typically 3080%of the native PA performance. As new Intel Itanium processor generations have come into production, typical

    performance under the DOCT has improved and will continue to improve. We will likely reach a point whereperformance will be equal to or greater than the native PA performance on the systems customers would typicallybe migrating from (usually PA systems that are several years old). The following graph illustrates the performancecomparison of a simple application so far.

    Figure 4. Example comparison of native PA and Intel Itanium architecture Aries execution times

    Mixed-mode on Itanium-based Platforms

  • 7/31/2019 Mixed Mode

    9/22

    The PA systems used were:

    D380 (180 MHz, 1998), HP Server rp5450 (440 MHz, 2001), and HP Server rp7410 (750 MHz, 2003).

    The Itanium-based systems used were:

    Lion (i2000) pre-production (533 MHz, 2001), and HP Server rx2600 (900 MHz, 2002).

    The example used is a small program that calls a function to increment an argument, and it adds up the results fo100,000,000 calls. This is a compute-bound process; other types of programs will have different performance,but it is apparent that the difference between Aries performance and native PA performance is diminishing.Existing performance on a 1 GHz Itanium 2-based system approaches the performance of the HP Server rp5450system from two years ago. The 2003 release of the next generation of Itanium 2-based systems (Madison) is

    expected to run approximately 50% faster than the existing 1 GHz Intel Itanium 2 processors.

    Mixed-mode: guidelinesThe general guidelines for using the DOCT and mixed-mode are as follows:

    1. In making the transition to a new architecture, code that is recompiled and optimized for the new platform wialways be faster than code running under the Dynamic Object Code Translator.

    2. Code running under the DOCT on new Itanium 2-based systems may run as fast as it did on its nearly-current system.

    3. Two-process mixed-mode works best for applications that have the following characteristics:

    The legacy routine does a significant amount of work before returning, i.e., the work done takes as long orlonger than the call overhead.

    The application or legacy routine is more interactive or I/O bound than compute intensive.

    The overhead of the call is essentially irrelevantthe functionality is needed, and it is called tens of timesper second or less.

    In choosing which of the two methods to use for your application, the following points may be helpful.

    Advantages of RPC method:

    Automatic data marshalinggood if the data passed is complex or if 32-/64-bit size differences are an issue.

    Can be inter-systemuseful if data needs to be accessed directly on a PA system.

    Conceptually simplerre-entrancy and synchronization are handled.

    Disadvantages of RPC method:

    Requires purchase of PA product B6192AADCE programming environment to build the PA portion.

    Slower call mechanismmore overhead.

    More complicated codingDCE based, though using the templates, instructions, and Makefiles provided canhelp.

    Advantages of the shared-memory method:

    Lowest costnothing additional to buy.

    Fasterorder of magnitude faster call than RPC.

    Simpler codeuses well-known system programming calls.

    Disadvantages of the shared-memory method:

    Have to manage data alignment if 32-/64-bit model differs between library and main program.

    Not inter-systemdata must be available on Itanium-based platform.

    Mixed-mode on Itanium-based Platforms

  • 7/31/2019 Mixed Mode

    10/22

    Summary

    For those PA legacy libraries that cannot or will not be ported to the Intel Itanium architecture, there is a possiblesolutiontwo-process mixed-mode. This paper has outlined two methods for implementing two-process mixed-mode applications. The DCE RPC-based method offers more flexibility and easier data handling, but it is slowerand more complex than the shared-memory method. The shared-memory and semaphore-based method requiresall components to be on one Itanium-based system; it requires care in handling the data transfer but executes morquickly. Both methods require modification to the program that calls the legacy routine and the creation of aserver program around the legacy routine.

    Glossary

    Mixed-modea program that contains procedures compiled for different architectures, i.e., some procedures arecompiled for Precision Architecture, while others are compiled for the Intel Itanium architecture.

    DCEdistributed computing environmenta standard for performing multi-system computing, developed by theOpen Software Foundation.

    ONCopen network computinga standard for performing multi-system computing, developed by SunMicrosystems.

    RPCremote procedure calla mechanism for calling a procedure on one system from a procedure or programon another system via the intervening network.

    For more information

    Makefiles and templates for doing this are available on the HP DSPP Web site athttp://atwnt959.external.hp.com/dspp/files/unprotected/ItaniumMixedMode.tar.

    These are supplied on an as-is basisthey are not warranted or supported.

    Mixed-mode on Itanium-based Platforms

    http://atwnt959.external.hp.com/dspp/files/unprotected/ItaniumMixedMode.tarhttp://atwnt959.external.hp.com/dspp/files/unprotected/ItaniumMixedMode.tar
  • 7/31/2019 Mixed Mode

    11/22

    Appendix

    Below are program and Makefile examples:

    DCE RPC example:

    The comments surrounding and explaining the DCE code in these examples have been deleted for brevity. Fullycommented templates and examples, and instruction files, can be found in the tar archive located on the Web athttp://atwnt959.external.hp.com/dspp/files/unprotected/ItaniumMixedMode.tar.

    This is an example of the client program. This code would need to be integrated into the source of the main

    (calling) program.

    /* adder_client.c**************************************************************************** This is the code for the client program. It takes two arguments, a hostname* to contact for the server and a number which may be used as to control* how many iterations of a subroutine call (to or witin the old PA library)* are performed. To avoid having to create a full DCE cell environment, it* locates the server using the hostname provided and the endpoint mapper on* the server's host -- the client does not contact the name service for* server location information. The client uses the explicit binding* method, so it uses the hostname argument to construct a binding handle* (rpc_binding_handle_t bh). The client passes this binding handle to the* invocation of the remote procedure.** In a production application, the code that creates the DCE bindings from* the hostname must be integrated into the production source to allow the

    * use of the old PA library. The needed hostname may be obtained in any way* that suits - hard-coded, extracted from an environment variable, or, as* done here, from the command line.** A simple tracing facility is coded in - it is enabled at compile time* using the compiler flag -DTRACING****************************************************************************/

    /** (c) Copyright 2002 Hewlett-Packard Co.*//** @(#)HP DCE/9000 1.7.1* @(#)Module: client.c $Revision: 1.0$ $Date: 2002/01/17 22:08:09 $*//*

    */

    #include /* DCE Pthread facility */#include /* Standard POSIX defines */#include /* str*() routines */#include /* Standard IO library */#include /* DCE error facility */#include /* DCE error facility */#include "hpdcemacros.h" /* Common HP defs for this app */#include "adder.h" /* Output from adder.idl */

    #ifdef TRACINGtr_handle_t * tr_handle = NULL; /* Initialize for client */#endif /* TRACING */

    /** The DCE RPC binding handle is global so the 'fake' legacy routine can find it* to build the remote call*/rpc_binding_handle_t bh; /* "points" to the server */

    void main(int argc, char *argv[]){

    error_status_t st, _ignore; /* returned by DCE calls */dce_error_string_t dce_err_string; /* text describing error code */ndr_char *string_binding; /* used to create binding */unsigned long counter; /* routine iteration counter */unsigned_char_t *netaddr; /* network address of server */

    long total, adder(),i;

    #ifdef TRACINGstart_dce_tracing ();

    Mixed-mode on Itanium-based Platforms

    http://atwnt959.external.hp.com/dspp/files/unprotected/ItaniumMixedMode.tarhttp://atwnt959.external.hp.com/dspp/files/unprotected/ItaniumMixedMode.tar
  • 7/31/2019 Mixed Mode

    12/22

    #endif /* TRACING */

    if (argc != 3) {fprintf(stderr, "Usage: %s hostname counter\n", argv[0]);exit(1);

    } else {netaddr = (unsigned_char_t *)argv[1];counter = atoi(argv[2]);

    }

    /* Initialize the DCE connection */get_my_dce_connection (netaddr);/** Insert the test function call here

    */total=0;

    for ( i=0;i

  • 7/31/2019 Mixed Mode

    13/22

    */int get_my_dce_connection (unsigned_char_t *netaddr){

    error_status_t st, _ignore; /* returned by DCE calls */dce_error_string_t dce_err_string; /* text describing error code */ndr_char *string_binding; /* used to create binding */

    rpc_string_binding_compose(NULL, /* no object UUID */(unsigned_char_t *)"ip", /* protocol to use */netaddr, /* network addr of server */NULL, /* use a dynamic endpoint */NULL, /* misc. network options */&string_binding, /* returned string binding */&st); /* error status for this call */

    if (st != rpc_s_ok) {dce_error_inq_text(st, dce_err_string, (int *)&_ignore);PRINT_FUNC(PRINT_HANDLE, "Cannot compose string binding: %s\n",

    dce_err_string);exit(1);

    }

    rpc_binding_from_string_binding(string_binding, /* created above */&bh, /* allocated and returned */&st); /* error status for this call */

    if (st != rpc_s_ok) {dce_error_inq_text(st, dce_err_string, (int *)&_ignore);PRINT_FUNC(PRINT_HANDLE, "Cannot get a binding handle: %s\n",

    dce_err_string);exit(1);

    }

    /** At this point the application is not actually connected to any* server, but it has all the information needed to establish a* connection to the remote server. Connection establishment happens in* the client stub function call.*/PRINT_FUNC(PRINT_HANDLE, "Bound to %s\n", string_binding);

    rpc_string_free(&string_binding, /* DCE string to free */&_ignore); /* DCE return status */

    }

    The following code is a corresponding example of the client code. This is the code that will be wrapped aroundthe original legacy library to create the second process (the one that runs under the DOCT) in the two-processmixed-mode. This code would usually be compiled on a PA system, then moved to the Itanium-based system, and

    run (transparently) under DOCT. In the case of difficulty with migrating data being accessed by the library routinethis program could remain on the PA system and communicate with the rest of the application over the network.

    The program consists of two source modules: the main program, which establishes the communicationinfrastructure; and a container function, which is the wrapper around the original library. In the realimplementation, the binary library is linked into the container function at build time.

    /* adder_server.c**************************************************************************** This is the server program for the basic IPF/PA mixed mode* DCE RPC application. It must be built on an HP-UX 11.x PA system. It* will register the interface named "adder" with the local RPC runtime* and with the endpoint mapper daemon (rpcd) on the local host. It then* listens for incoming requests and serves each request in a separate* thread. The container function (see adder_container.c) is invoked to

    * serve the requests after the inbound arguments are unmarshalled.*****************************************************************************/

    /** (c) Copyright 1992, 1993, 1994 Hewlett-Packard Co.*//** @(#)HP DCE/9000 1.7.1* @(#)Module: server.c $Revision: 1.1.6.2 $ $Date: 1993/07/08 00:13:10 $*//**/

    #include /* POSIX threads facility */#include /* Standard POSIX defines */

    Mixed-mode on Itanium-based Platforms

  • 7/31/2019 Mixed Mode

    14/22

    #include /* str*() routines */#include /* Standard IO library */#include /* DCE error facility */#include "hpdcemacros.h" /* Common defs for this app */#include "adder.h" /* Output from adder.idl */

    #ifdef TRACINGtr_handle_t * tr_handle = NULL; /* Initialize for server */#endif /* TRACING */

    void main(int argc, char *argv[]){

    rpc_binding_vector_t *bvec; /* used to register w/runtime */

    error_status_t st, _ignore; /* returned by DCE calls */dce_error_string_t dce_err_string; /* text describing error code */ndr_char *string_binding; /* printable rep of binding */int i; /* index into bvec */

    #ifdef TRACING/** Initialize tracing.*/if (tr_handle == NULL) {

    char trace_name_buf[40];sprintf(trace_name_buf, "%s-%d", trace_name, getpid());tr_handle = tr_init("TR_DCE_SERVER", /* environment variable name */

    NULL, /* selector level defaults */NULL, /* filename for output */trace_name_buf); /* prefix string in output */

    if (tr_handle == NULL) {

    fprintf(stderr, "Unable to initialize tracing interface!\n");}

    }#endif /* TRACING */

    rpc_server_use_protseq((unsigned char *)"ip", /* prot seq to listen on */rpc_c_protseq_max_calls_default,&st); /* error status for this call */

    if (st != rpc_s_ok) {dce_error_inq_text(st, dce_err_string, (int *)&_ignore);PRINT_FUNC(PRINT_HANDLE, "Cannot use protocol sequence ip: %s\n",

    dce_err_string);exit(1);

    }

    rpc_server_register_if(adder_v1_0_s_ifspec, /* generated interface spec */NULL, /* No type UUIDs */

    NULL, /* Use supplied epv */&st); /* error status for this call */

    if (st != rpc_s_ok) {dce_error_inq_text(st, dce_err_string, (int *)&_ignore);PRINT_FUNC(PRINT_HANDLE,"Cannot register interface with runtime: %s\n",

    dce_err_string);exit(1);

    }

    rpc_server_inq_bindings(&bvec, /* runtime's binding vector */&st); /* error status for this call */

    if (st != rpc_s_ok) {dce_error_inq_text(st, dce_err_string, (int *)&_ignore);PRINT_FUNC(PRINT_HANDLE, "Cannot get bindings: %s\n", dce_err_string);exit(1);

    } elsePRINT_FUNC(PRINT_HANDLE, "Bindings:\n");

    for (i = 0; i < bvec->count; i++) {rpc_binding_to_string_binding(bvec->binding_h[i], /* a binding handle */

    &string_binding,/* returned string form */&st); /* error status for this call */

    if (st != rpc_s_ok) {dce_error_inq_text(st, dce_err_string, (int *)&_ignore);PRINT_FUNC(PRINT_HANDLE, "Cannot get string binding: %s\n",

    dce_err_string);} else

    PRINT_FUNC(PRINT_HANDLE, " %s\n", string_binding);

    rpc_string_free(&string_binding, &_ignore);}

    rpc_ep_register(adder_v1_0_s_ifspec, /* generated interface spec */

    Mixed-mode on Itanium-based Platforms

    bvec, /* runtime's binding vector */

  • 7/31/2019 Mixed Mode

    15/22

    NULL, /* no objects supported */(unsigned_char_t *) sleeper_description,&st); /* error status for this call */

    if (st != rpc_s_ok) {dce_error_inq_text(st, dce_err_string, (int *)&_ignore);PRINT_FUNC(PRINT_HANDLE, "Cannot register with endpoint map: %s\n",

    dce_err_string);exit(1);

    }

    PRINT_FUNC(PRINT_HANDLE, "Listening...\n");

    rpc_server_listen(rpc_c_listen_max_calls_default,&st); /* error status for this call */

    if (st != rpc_s_ok) {dce_error_inq_text(st, dce_err_string, (int *)&_ignore);PRINT_FUNC(PRINT_HANDLE, "Listen returned with error: %s\n",

    dce_err_string);} else

    PRINT_FUNC(PRINT_HANDLE, "Stopped listening...\n");

    /************************************************************************* IMPORTANT NOTE: We will probably never reach here. If you interrupt* the server with an asynchronous signal, such as a ^C (or SIGINT) from* the keyboard or a "kill " (a SIGTERM signal), it will cause the* process to exit; it will not reach here. See the lookup sample* application for code that is able to properly clean up after the* listen call.************************************************************************/

    PRINT_FUNC(PRINT_HANDLE, "Unregistering endpoints and interface...\n");

    rpc_ep_unregister(adder_v1_0_s_ifspec, /* IDL-generated ifspec */bvec, /* this server's bindings */NULL, /* no object UUIDs supported */&_ignore); /* ignore any errors */

    rpc_binding_vector_free(&bvec, &_ignore);

    rpc_server_unregister_if(adder_v1_0_s_ifspec, /* IDL-generated ifspec */NULL, /* No object UUID */&_ignore); /* ignore any errors */

    exit(0);}

    The following code is the container function, which makes the call to the legacy routine./* adder_container.c**************************************************************************** This is the server-side RPC container function; this is the function that* actually implements the remote procedure defined in the .idl file. The* server stub (called by the RPC runtime) calls this function when an RPC* request comes in for this interface.** The container function takes the arguments defined in the .idl file,* performs its function and returns results as defined in the .idl file.****************************************************************************/

    /** (c) Copyright 2002 Hewlett-Packard Co.*/

    /** @(#)HP DCE/9000 1.7.1* @(#)Module: container.c $Revision: 1. $ $Date: 2002/01/18 00:11:59 $*//**/

    #include /* Standard POSIX defines */#include /* Standard IO library */#include "hpdcemacros.h" /* Common defs for this app */#include "adder.h" /* Output from the idl compiler */

    /** The container function simply accepts the arguments passed from the client* RPC call, and returns an results. Since the .idl file speficies use of explicit

    Mixed-mode on Itanium-based Platforms

    * binding the manager must take a binding handle as its first argument.

  • 7/31/2019 Mixed Mode

    16/22

    ** Note: the code in this container function must be (and is) reentrant as it* may be running simultaneously in multiple server threads.*/long remote_adder

    (/* [in] */ handle_t h, /* Use explicit binding *//* [in] */ long xin /* Input parameter */)

    {long result;

    /** Insert the call to the legacy library routine here

    */result=adder (xin);

    return result;}

    Another piece of this system is the IDL (Interface Definition Language) file that defines the Remote Procedure Callinterface. It contains a Unique Universal Identifier (UUID) that must be generated for each interface created. TheUUID is created by the uuidgen command and copied into the file.

    /* adder.idl***************************************************************************** This .idl file declares an interface with a set of remotely-callable

    * procedures. This file is compiled by the idl compiler into a C interface* declaration (.h) and a C client stub (_cstub.c) and server stub* (_sstub.c) that interface with the RPC runtime.****************************************************************************/

    /** (c) Copyright 1992, 1993, 1994 Hewlett-Packard Co.*//** @(#)HP DCE/9000 1.7.1* @(#)Module: sleeper.idl $Revision: 1.1.6.2 $ $Date: 1993/07/08 00:14:24 $*//**/

    /** This definition declares the interface for this application and

    * associates it with a globally (universally) unique identifier, or UUID.* The RPC runtime uses the UUID to identify this interface. If you* leverage this code, BE SURE TO CHANGE THE UUID! Do this by running the* program "uuidgen" and putting the uuidgen output in place of the one* supplied. Failure to do this may cause bizarre results.*/[uuid(6fae8c4e-2163-11d6-8328-080009046d0b), /* NOTE: CHANGE THIS!!! */version(1.0)]interface adder{

    long remote_adder([in] handle_t h, /* Use explicit binding */[in] int intin /* Input integer */);

    }

    The final piece of this system is the Makefile for creating it.

    # Makefile## (c) Copyright 2002 Hewlett-Packard Co.## @(#)HP DCE/9000 1.7.1# @(#)Module: Makefile $Revision: 1.0 $ $Date: 2002/01/17 16:19 UTC $### The application name:O_P_L=adder

    # The Optional HP-AnsiC compiler is required for HP DCE/9000

    Mixed-mode on Itanium-based Platforms

  • 7/31/2019 Mixed Mode

    17/22

    # application development (see: /opt/ansic)CC = /opt/ansic/bin/cc

    DEBUG = -gINCENV = -I. -I/usr/include -I/opt/dce/includeANSI_FLAGS = -AaTHREADS_FLAGS = -D_REENTRANT -D_POSIX_C_SOURCE=199506LHP_FLAGS = -D_HPUX_SOURCE

    CFLAGS = ${ANSI_FLAGS} ${THREADS_FLAGS} ${HP_FLAGS} ${INCENV}LIBS = -lpthread -ldcektLDFLAGS = -lm -L/opt/dce/lib

    PROGRAMS = ${O_P_L}_server ${O_P_L}_client

    server_OFILES = ${O_P_L}_sstub.o ${O_P_L}_container.o ${O_P_L}_server.o ${O_P_L}.oclient_OFILES = ${O_P_L}_cstub.o ${O_P_L}_client.o

    IDLFLAGS = -keep c_source ${INCENV}IDLFILES = ${O_P_L}.idlIDLGEN = ${O_P_L}.h ${O_P_L}_*stub.cIDL = idl

    all: objects ${PROGRAMS}objects: ${server_OFILES} ${client_OFILES}fresh: clean all

    clean:;rm -f ${server_OFILES} ${client_OFILES} ${PROGRAMS} ${IDLGEN}

    clobber: cleanrm -f a.out core ERRS make.out *~

    ${O_P_L}_server: ${server_OFILES}$(CC) ${LDFLAGS} ${server_OFILES} ${LIBS} -o $@

    ${O_P_L}_client: ${client_OFILES}$(CC) ${LDFLAGS} ${client_OFILES} ${LIBS} -o $@

    ${O_P_L}_cstub.c ${O_P_L}_sstub.c ${O_P_L}.h: ${IDLFILES}$(IDL) ${IDLFLAGS} ${IDLFILES}

    ${O_P_L}_cstub.o ${O_P_L}_sstub.o ${O_P_L}_container.o server.o client.o: ${O_P_L}.h${O_P_L}_container.o ${O_P_L}_server.o ${O_P_L}_client.o: hpdcemacros.h

    The shared-memory/semaphore example:

    This example consists of two programs, each of which consists of two parts. The client program is the original

    main program (addtypes_client.c), modified to call a resource cleanup routine. The cleanup routine and thecommunication stub (called by the legacy routine name) are in a second file (addtypes_shm.c). This file iscompiled separately and then linked into the original main at link time to create the client program. The serverprogram consists of the communication stub (addtypes_server.c) and the linked-in legacy library (addtypes.o). Amore detailed description of the code is on the Web site.

    This is the client (original main program) code. It has been modified only at its termination to call a routine torelease the resources used for inter-process communication.

    /* addtypes_client.c *//* The modified 'main' program that calls the legacy library *//* The legacy library is the 'addtypes' routine */main(){long double myldouble=99999999990000000.0;

    double mydouble=9900000.0;long mylong=99000;int myint=990;char mychar='9';long double result,addtypes();

    result=addtypes (mychar,myint,mylong,mydouble,myldouble);printf ("Client Result = %18.1Lf\n",result);myint++;result=addtypes (mychar,myint,mylong,mydouble,myldouble);printf ("Client Result = %18.1Lf\n",result);

    /* ***** the modification to the original program ***** */return_resources();

    exit(0);

    Mixed-mode on Itanium-based Platforms

    }

  • 7/31/2019 Mixed Mode

    18/22

    This is the client-side communication stub. It creates the shared-memory segment and semaphores, forks theserver program, and then uses the shared memory and semaphores to communicate with the server. It alsocontains the routine (release_resources) called at the end of the main program.

    /* addtypes_shm.c *//* This is the client side communication stub *//* for the 'addtypes' function. *//* It masquerades as the original function, accepting its *//* arguments and returning the expected result. */

    #include #include #include

    #define SHMSZ 2048

    /* Make the shared memory and semaphore ids, the server pid, and the *//* shared memory pointer available to all of the code in this source *//* module. */static int shmid, semid;static pid_t cpid;static char *shmptr;

    long double addtypes(char mychar,int myint,long mylong,double mydouble,long double myldouble)

    {extern pid_t cpid;extern int shmid, semid;extern char *shmptr;/* flag for first time through */static int first_time=1;

    char semchar[20]="",shmchar[20]="";char *charptr;long double result;key_t shmkey, semkey;struct sembuf sops[1];int status,flag;void exit(int status);

    /* The first time this function is called, it must set up the *//* infrastructire - shared memory, semaphores, and server program */if ( first_time )

    {first_time=0;/* First create the semaphores and shared memory segment */semkey=IPC_PRIVATE;flag=0660;

    semid=semget (semkey,2,flag);if ( semid < 0 ) perror ("Semget failed");/* DEBUG printf ("Semget worked : SEMID=%d\n",semid); *//* Initialize the semaphores to zero */status=semctl (semid,0,SETVAL,0);if ( status < 0 ) perror ("Setval 0 failed");status=semctl (semid,1,SETVAL,0);if ( status < 0 ) perror ("Setval 1 failed");

    shmkey=IPC_PRIVATE;flag=0660;shmid=shmget (shmkey,SHMSZ,flag);if ( shmid < 0 ) perror ("Shmget failed");/* DEBUG printf ("Shmget worked : SHMID=%d\n",shmid); */shmptr=shmat (shmid,(char *)0,0);if ( shmptr < (char *)0 ) perror ("shmat failed");

    /* Before the first call to the routine, create the server *//* Pass it the semaphore and shared memory id's in ASCII */strcat(semchar,ltoa((long)semid));strcat(shmchar,ltoa((long)shmid));cpid=fork();switch (cpid)

    {case -1:exit(-1);break;

    case 0:status=execl("./addtypes_server","addtypes_server",semchar,shmchar,NULL);if (status

  • 7/31/2019 Mixed Mode

    19/22

    /* Now executing in the main flow in the parent */

    /* Set the data into shared memory by incrementing a pointer by the size *//* of the preceding value. Start from the biggest data type and work *//* down. Then set the semaphore */charptr=(char *)shmptr;/* leave space for a long double - return value */charptr=charptr + sizeof (long double);/* Store the long double in shared memory */*(long double *) charptr=myldouble;charptr=charptr + sizeof (long double);/* Store the double */*(double *) charptr=mydouble;charptr=charptr + sizeof (double);

    /* Store the long */*(long *) charptr=mylong;charptr=charptr + sizeof (long);/* Store the int */*(int *) charptr=myint;charptr=charptr + sizeof (int);/* Store the char */*charptr=mychar;

    /* Set the semaphore values */sops->sem_num=0;sops->sem_op=1;sops->sem_flg=0;status=semop (semid,sops,1);if ( status < 0 ) printf ("Set failed\n");

    /* Wait for the return semaphore */

    sops->sem_num=1;sops->sem_op=-1;sops->sem_flg=0;status=semop (semid,sops,1);if ( status < 0 ) printf ("Get failed\n");/* pick up the returned value from the start of shared memory */result=*(long double *) shmptr;printf ("returned value in stub is %18.1Lf\n",result);

    return (result);}

    /* This routine is called at the termination of the process *//* to release the resources used */void return_resources(){extern pid_t cpid;

    extern int shmid, semid;extern char* shmptr;int status;printf ("Returning resources\n");/* kill the server process */if((kill(cpid,1))

  • 7/31/2019 Mixed Mode

    20/22

    The server code, which picks up the input data out of shared memory, calls the legacy routine with it, places thereturn value back into shared memory, and signals the main program (client) by raising the outbound semaphoreas follows:

    /* addtypes_server.c *//* This is the 'server' side code for the 'addtypes' example *//* It attachs to the shared memory segment and semaphores, *//* then waits on the input semaphore to signal input data is *//* ready for processing. It then takes the data out of shared *//* memory, calls the legacy routine, places the returned *//* value in shared memory, and raises the output semaphore. *//* It then goes back and waits on the input semaphore. *//* It gets the shared memory and semaphore IDs from command *//* line parameters, passed from the client program. */

    #include #include

    main(argc,argv)int argc;char*argv[];{int status, semid, shmid;char *shmptr;char *charptr;struct sembuf sops[1];char mychar;int myint;long mylong;double mydouble;long double myldouble;long double result,addtypes();

    semid=atoi(argv[1]);shmid=atoi(argv[2]);/* DEBUG printf ("semid: %d Shmid %d\n",semid,shmid); */

    /* attach to the shared memory segment */shmptr = shmat (shmid,(char *)0,0);

    /* Loop and wait for input */while (1)

    {printf ("Waiting in client\n");/* Wait on the inbound semaphore */sops[0].sem_num=0;sops[0].sem_op=-1;

    sops[0].sem_flg=0;status=semop (semid,sops,1);if ( status < 0 ) perror ("Wait failed ");

    /* Pick up the input values */charptr=(char *)shmptr;/* Skip over the space for the result */charptr=charptr + sizeof(long double);/* get the long double */myldouble=*(long double *) charptr;charptr=charptr + sizeof(long double);/* get the double */mydouble=*(double *) charptr;charptr=charptr + sizeof(double);/* get the long *//* DEBUG printf ("Address of long: %x \n",charptr); */mylong=*(long *) charptr;

    charptr=charptr + sizeof(long);/* get the int */myint=*(int *) charptr;charptr=charptr + sizeof(int);/* get the char */mychar=*charptr;

    /* Call the legacy routine */result=addtypes (mychar,myint,mylong,mydouble,myldouble);/* Move the returned value to shared amaory */*(long double*)shmptr=result;

    /* Set the outbound semaphore */sops[0].sem_num=1;sops[0].sem_op=1;sops[0].sem_flg=0;status=semop (semid,sops,1);

    Mixed-mode on Itanium-based Platforms

  • 7/31/2019 Mixed Mode

    21/22

    if ( status < 0 ) perror ("Set failed ");}

    exit (0);}

    The other piece of the server process is the legacy routine. It would normally exist in binary form only (thats thewhole problem!), but we show the source here for completeness.

    /* addtypes.c *//* The legacy routine */

    long double addtypes(char mychar,int myint,long mylong,double mydouble,long double myldouble)

    {char cbuff[2];long double result;int mycharint;

    cbuff[0]=mychar;mycharint=atoi(cbuff);result=mycharint+myint+mylong+mydouble+myldouble;printf ("myldouble = %18.1Lf\n",myldouble);printf ("mydouble = %8.1f\n",mydouble);printf ("mylong = %d\n",mylong);printf ("myint = %d\n",myint);printf ("mycharint = %d\n",mycharint);printf ("Result = %18.1Lf\n",result);return (result);

    }

    The final piece is the Makefile. This would exist in two partsone to create the client process on an Itanium-basedplatform, and the other to create the server process on the PA platform. It is shown here in one piece because theexample was built on an Itanium 2-based system for testing, then moved to a PA system for creation of the servercode to run under Aries.

    # Makefile.template## The application name:O_P_L=addtypes

    # The Ansi C compiler was used for this application development

    # (see: /opt/ansic)CC = /opt/ansic/bin/cc

    DEBUG = -gINCENV = -I. -I/usr/includeANSI_FLAGS = -AaHP_FLAGS = -D_HPUX_SOURCE +DD32

    CFLAGS = ${ANSI_FLAGS} ${HP_FLAGS} ${INCENV}LIBS =LDFLAGS = -lm

    PROGRAMS = ${O_P_L}_server ${O_P_L}_clientserver_OFILES = ${O_P_L}_server.o ${O_P_L}.oclient_OFILES = ${O_P_L}_client.o ${O_P_L}_shm.o

    all: objects ${PROGRAMS}

    objects: ${server_OFILES} ${client_OFILES}fresh: clean all

    clean:;rm -f ${server_OFILES} ${client_OFILES} ${PROGRAMS}

    clobber: cleanrm -f a.out core ERRS make.out *~

    ${O_P_L}_server: ${server_OFILES}$(CC) ${LDFLAGS} ${server_OFILES} ${LIBS} -o $@

    ${O_P_L}_client: ${client_OFILES}$(CC) ${LDFLAGS} ${client_OFILES} ${LIBS} -o $@

    Mixed-mode on Itanium-based Platforms

  • 7/31/2019 Mixed Mode

    22/22

    HP-UX 11i release names and release identifiersWith HP-UX 11i, HP delivers a highly available, secure,and manageable operating system that meets thedemands of end-to-end Internet-critical computing. HP-UX 11i supports enterprise, mission-critical, and technicalcomputing environments. HP-UX 11i is available on both PA-RISC systems and Itanium-based systems.

    Each HP-UX 11i release has an associated release name and release identifier. The uname (1) command withthe -r option returns the release identifier. The following table shows the releases available for HP-UX 11i.

    Table 1. HP-UX 11i releases

    Release name Release identifier Supported processor architecture

    HP-UX 11i v1 B.11.11 PA-RISC

    HP-UX 11i v1.5 B.11.20 Intel Itanium

    HP-UX 11i v1.6 B.11.22 Intel Itanium

    HP-UX 11i v2 B.11.23 Intel Itanium

    Copyright 2003 Hewlett-Packard Development Company, L.P.Theinformation contained herein is subject to change without notice and isprovided as is without warranty of any kind.The warranties for HPproductsand servicesare set forth in the express warranty statements accompanyingsuch productsand services. Nothing herein should be construed as constitutingan additional warranty. HP shall not be liable for technical or editorial errorsor omissions contained herein.Intel and Itanium are trademarks or registered trademarks of Intel Corporationin the U.S. and other countries and are used under license.

    5981-7112EN 06/2003