|
|
(5 intermediate revisions by 3 users not shown) |
Line 1: |
Line 1: |
− | ==Developing Application Components in OpenClovis SAFplus Platform Environment==
| |
| | | |
− | ===Eonization===
| |
− |
| |
− | '''Eonization''' is a mechanism that enables the user application to communicate with OpenClovis SAFplus Platform. The name eonization derives from the word 'EO' or execution object. The end product of eonization is an EO that is able to communicate with other EOs in the SAFplus Platform environment.
| |
− |
| |
− | Eonization enables an application to :
| |
− | # Invoke services exposed by the other EOs.
| |
− | # Expose services so that other EOs can invoke the same.
| |
− | # Provide some callbacks so that its lifecycle can be monitored by the SAFplus Platform.
| |
− | # Use the manageability features provided by the SAFplus Platform.
| |
− | # Integrate it with the AMF so that the application becomes highly available.
| |
− |
| |
− | ====Significance of Eonization====
| |
− |
| |
− | The two most common software entities which are provided and managed (rather primitively) by many operating systems are '''processes''' and the '''threads'''. In most systems, processes are isolated from each other, whereas threads share same address space and hence error/failure in one of the threads can lead to errors/failures in other threads also.
| |
− |
| |
− | In UNIX, the interaction between the OS and a process is passive. The OS starts up the process, sets up its environment and executes its main function. This enables the process to execute without any direct interference from the OS. It can either enter into an infinite loop or choose to intermittently request for services from the OS. Since the OS is unaware of the process' internals, it reacts only when it receives service requests from the process. The only mechanism for pro-actively sending information to the process is using signals.
| |
− |
| |
− | But this model of OS to process communication is insufficient for middleware systems in carrier grade system, where the OS needs more fine grained control over the processes it creates and manages them over time. So we have two possible approaches in as far as the OS to process communication models are concerned in carrier grade system :
| |
− | * Write an OS from scratch, which will periodically invoke specific set of callbacks in the context of processes that it creates, to manage the component. or
| |
− | * Create a wrapper over a normal application and make the application register some callbacks when initializing, which is called by the SAFplus Platform middleware to manage the application. This approach requires some work from applications side like providing those callbacks and registering them etc.
| |
− |
| |
− | The OpenClovis SAFplus Platform follows the second approach and this process of "wrapping the component and it registering the callbacks which will be invoked by the middleware" is called '''Eonization'''. So the life cycle of a typical application will be :
| |
− | * Register the callbacks with the SAFplus Platform.
| |
− | * The callbacks will be invoked asynchronously by the SAFplus Platform, to manage the application.
| |
− |
| |
− | The above model is similar to the life cycle of an X window client application, which registers set of callbacks to be invoked whenever there is a key press event or button press event etc. and the X server asynchronously invoking the corresponding callback in the context of the X window client application.
| |
− |
| |
− | It is important to realize that this eonization provided by the OpenClovis EO infrastructure is much more general than one required to support programming models such as SAF programming model. Not only does it support AMF managing the component through invoking callbacks for a particular component, it allows any component to invoke callbacks provided by any other component, thus allowing for a much more powerful and generic programming model.
| |
− |
| |
− | ===Steps involved in developing application components===
| |
− |
| |
− | <br>[[File:OpenClovis_Note.png]]Using the OpenClovis IDE to build a model and generate the corresponding code automates the steps outlined in this section. For more information regarding the OpenClovis IDE see the ''OpenClovis Sample Application Tutorial'' and the ''OpenClovis IDE User Guide''.
| |
− | * [[#Step 1: Defining the Skeleton of a Component | Step 1: Defining the Skeleton of a Component]] <br>Define the skeleton of a component and describe its lifecycle functions and interface functions. Assign a unique IOC communication port to the component that identifies the execution object.
| |
− | * [[#Step 2: Defining clEoBasicLibs | Step 2: Defining <code>clEoBasicLibs</code>]] <br>Define the set of OpenClovis SAFplus Platform libraries required by the component.
| |
− | * [[#Step 3: Initializing the CPM Library | Step 3: Initializing the CPM Library]] <br>Initialize the CPM client library.
| |
− | * [[#Step 4: Registering the CPM | Step 4: Registering the CPM]] <br>Register the component with CPM infrastructure.
| |
− | * [[#Step 5: Un-registering the CPM Library | Step 5: Un-registering the CPM Library]] <br>Un-register the application from CPM Infrastructure, on exit of the application.
| |
− | * [[#Step 6: Finalizing the CPM Library | Step 6: Finalizing the CPM Library]] <br>Finalize the CPM client library when the component exits.
| |
− |
| |
− | <span id="Step 1: Defining the Skeleton of a Component"></span>
| |
− | '''Step 1: Defining the Skeleton of a Component'''
| |
− |
| |
− | Using OpenClovis IDE, define a structure with the name as <code>'''clEoConfig'''</code> with the following fields initialized appropriately:
| |
− | * Component lifecycle management parameters
| |
− | * Number of worker threads
| |
− | * Unique communication port Id associated with the component for communication within the SAFplus Platform infrastructure.
| |
− |
| |
− | <code><pre>
| |
− | # define COMP_EO_NUM_THREAD 3
| |
− | # define COMP_IOC_PORT 0
| |
− |
| |
− | ClEoConfigT clEoConfig = {
| |
− | COMP_EO_NAME, /* EO Name */
| |
− | COMP_EO_THREAD_PRIORITY, /* EO Thread Priority */
| |
− | COMP_EO_NUM_THREAD, /* No of EO thread needed */
| |
− | COMP_IOC_PORT, /* Required IOC Port */
| |
− | COMP_EO_USER_CLIENT_ID, /* Client table ID*/
| |
− | COMP_EO_USE_THREAD_MODEL, /* Whether to use main thread for EO
| |
− | * receive or not */
| |
− | clCompAppInitialize, /* Function callback to initialize the
| |
− | * application */
| |
− | clCompAppFinalize, /* Function callback to terminate the
| |
− | * application */
| |
− | clCompAppStateChange, /* Function callback to change the
| |
− | * application state */
| |
− | clCompAppHealthCheck, /* Function callback to check the
| |
− | * application health */
| |
− | };
| |
− | </pre></code>
| |
− |
| |
− | Where,
| |
− | <ul>
| |
− | <li><code>'''COMP_EO_NAME'''</code> is the name of the component, also called as the Execution Object (EO).
| |
− |
| |
− | <li><code>'''COMP_EO_THREAD_PRIORITY'''</code> is the priority of the EO thread.
| |
− |
| |
− | <li><code>'''COMP_EO_NUM_THREAD'''</code> is the count of worker threads for RMD message processing. This must be greater than or equal to 1.
| |
− |
| |
− | <li><code>'''COMP_IOC_PORT'''</code> is the unique IOC communication port associated with every component.
| |
− |
| |
− | <li><code>'''COMP_EO_USER_CLIENT_ID'''</code> is the maximum number of clients that can exist for a given component. The default value that can be used for this is <code>COMP_EO_USER_CLIENT_ID_START</code>.
| |
− |
| |
− | <li><code>'''COMP_EO_USE_THREAD_MODEL'''</code> indicates whether the application should block the main thread or not.
| |
− |
| |
− | <li><code>'''clCompAppInitialize'''</code> is invoked by the OpenClovis SAFplus Platform infrastructure when an eonized application is started. It is similar to the main() function of a typical C program. The application should do all its application specific initialization in this function. For SA-aware components, after the application has done its initialization, it informs AMF that it is ready to provide services using <code>clCpmComponentRegister</code> API.
| |
− |
| |
− | <li><code>'''clCompAppFinalize'''</code> is being deprecated and must be NULL.
| |
− |
| |
− | <li><code>'''clCompAppStateChange'''</code> is called whenever the application state needs to be changed to <code>SUSPEND</code> or <code>RESUME</code>.
| |
− |
| |
− | <li><code>'''clCompAppHealthCheck'''</code> is called periodically by Component Manager to check the health of an eonized application, if the heart beating is enabled. In response to this callback, the application is supposed to check if it is in a state of providing service and if so provide appropriate feedback to CPM saying so.
| |
− | </ul>
| |
− |
| |
− | {{internal-begin}}
| |
− |
| |
− | <span id='Illustration of the usage of application type'></span>[[File:SDK_UsageofApplicationType_70.png|frame|center| '''Illustration of the usage of application type''' ]]
| |
− |
| |
− | {{internal-end}}
| |
− |
| |
− | [[File:OpenClovis_Note.png]]The application must consider the following while defining the <code>'''clEoConfig'''</code> structure:
| |
− | * If you select <code>'''COMP_EO_USE_THREAD_MODEL'''</code> as <code>'''CL_EO_USE_THREAD_FOR_RECV'''</code>, the main thread '''must not be''' blocked in the <code>'''clCompAppInitialize'''</code>. It must return after the library is initialized. Later, the main thread will be used for RMD message receive function.
| |
− | * If you select <code>'''COMP_EO_USE_THREAD_MODEL'''</code> as <code>'''CL_EO_USE_THREAD_FOR_APP'''</code>, the main thread '''must be''' blocked in the <code>'''ClEoAppCreateCallbackT'''</code> or used by the application. It must return only when the <code>'''ClCpmTerminateCallbackT'''</code> is called.
| |
− |
| |
− | <span id="Step 2: Defining clEoBasicLibs"></span>
| |
− | '''Step 2: Defining <code>clEoBasicLibs</code>'''
| |
− |
| |
− | This structure contains the basic OpenClovis SAFplus Platform libraries required by the component. The first six libraries must always be set to <code>'''CL_TRUE'''</code> ; the remaining can be made <code> '''CL_TRUE'''</code> only if the corresponding services are required by the application. If set to <code>'''CL_TRUE'''</code>, the corresponding libraries will automatically get initialized during component initialization.
| |
− | <code><pre>
| |
− | ClUint8T clEoBasicLibs[] = {
| |
− | CL_TRUE, /* OSAL */
| |
− | CL_TRUE, /* Timer */
| |
− | CL_TRUE, /* Buffer */
| |
− | CL_TRUE, /* IOC */
| |
− | CL_TRUE, /* RMD */
| |
− | CL_TRUE, /* EO */
| |
− | CL_TRUE, /* OM */
| |
− | CL_FALSE, /* HAL */
| |
− | CL_FALSE, /* DBAL */
| |
− | };
| |
− | </pre></code>
| |
− |
| |
− | '''Step 2.1: Defining <code>clEoClientLibs</code>'''
| |
− |
| |
− | This structure contains a list of client libraries which the components can initialize if they need the corresponding service within the SAFplus Platform infrastructure. All the values in this structure are optional. If set to <code>'''CL_TRUE'''</code>, the corresponding libraries will automatically get initialized during component initialization.
| |
− |
| |
− | <code><pre>
| |
− | ClUint8T clEoClientLibs[] = {
| |
− | CL_TRUE, /* Clovis Object Registry */
| |
− | CL_TRUE, /* Chassis Manager */
| |
− | CL_TRUE, /* Name Service*/
| |
− | CL_TRUE, /* Log Service*/
| |
− | CL_FALSE, /* Trace Service */
| |
− | CL_FALSE, /* Diagnostic Manager */
| |
− | CL_TRUE, /* Transaction Manager */
| |
− | CL_FALSE, /* NA */
| |
− | CL_TRUE, /* Provisioning Library*/
| |
− | CL_TRUE, /* Alarm Manager */
| |
− | CL_TRUE, /* Debug Service*/
| |
− | CL_FALSE /* Group Membership Service */
| |
− | };
| |
− | </pre></code>
| |
− |
| |
− | When this is defined, the application is eonized. During startup, the stubs generated by OpenClovis IDE does all the necessary things as defined in the above structures.
| |
− |
| |
− | [[File:OpenClovis_Note.png]]OpenClovis SAFplus Platform libraries linked to the user application require three structures to be defined, otherwise, it will lead to compilation failure.
| |
− |
| |
− | <span id="Step 3: Initializing the CPM Library"></span>
| |
− | '''Step 3: Initializing the CPM Library'''
| |
− |
| |
− | From <code>'''clCompAppInitialize'''</code> callback, you need to initialize the CPM library by calling the <code>'''clCpmClientInitialize'''</code> and provide a structure for callback, defined as <code>'''ClCpmCallbacksT'''</code> in <code>'''clCpmApi.h'''</code> file.
| |
− | * <code>'''ClCpmHealthCheckCallbackT'''</code> callback: This callback is not implemented by OpenClovis SAFplus Platform for the current release.
| |
− | * <code>'''ClCpmTerminateCallbackT'''</code> callback: This is called when the application requires to be terminated. In this function callback, the application will clean up its acquired resources.
| |
− | * <code>'''ClCpmCSISetCallbackT'''</code> callback: This is called when AMF assigns the workload to the application.
| |
− | * <code>'''ClCpmCSIRmvCallbackT'''</code> callback: This is called when AMF removes the workload from the application.
| |
− | * <code>'''ClCpmProtectionGroupTrackCallbackT'''</code> callback: This is called when there is a change in the status of the protection group of a particular CSI. The application tracks the status of the CSI using <code>'''clCpmProtectionGroupTrack'''</code> API.
| |
− | * <code>'''ClCpmProxiedComponentInstantiateCallbackT'''</code> callback: This is called when the proxy component instantiates one or more of its proxied components.
| |
− | * <code>'''ClCpmProxiedComponentCleanupCallbackT'''</code> callback: This is called when the proxy component clean up one or more of its proxied components.
| |
− |
| |
− | <span id="Step 4: Registering the CPM"></span>
| |
− | '''Step 4: Registering the CPM'''
| |
− |
| |
− | From <code>'''clCompAppInitialize'''</code> callback, you need to register the component by invoking <code>'''clCpmComponentRegister'''</code> API. The component must be registered only when it is ready to provide the services. After the component is registered, it can either provide some specific service or use the services provided by other components. When AMF decides to terminate the component, it calls the <code>'''ClCpmTerminateCallbackT'''</code> callback provided by the application.
| |
− |
| |
− | <span id="Step 5: Un-registering the CPM Library"></span>
| |
− | '''Step 5: Un-registering the CPM Library'''
| |
− |
| |
− | From <code>'''ClCpmTerminateCallbackT'''</code> callback, you need to un-register the component by invoking <code>'''clCpmComponentUnregister'''</code> API. The component is un-registered when the component is no longer providing the services. You can cleanup all the associated resources.
| |
− |
| |
− | <span id="Step 6: Finalizing the CPM Library"></span>
| |
− | '''Step 6: Finalizing the CPM Library'''
| |
− |
| |
− | From <code>'''ClCpmTerminateCallbackT'''</code> callback, you need to finalize CPM library by calling the <code>'''clCpmClientFinalize'''</code> API.
| |
− |
| |
− | ===Component Characteristics===
| |
− |
| |
− | An application component in OpenClovis SAFplus Platform infrastructure has the following characteristics:
| |
− | * Each component has an associated lifecycle and registers the initialization and termination functions with OpenClovis SAFplus Platform infrastructure.
| |
− | * Each component has a communication port called the IOC port assigned by OpenClovis SAFplus Platform infrastructure to communicate with other components including Event, Checkpoint, Component Manager and so on. IOC manages the IOC port and implements the actual mechanism of sending and receiving messages.
| |
− | * Each component installs the services into the function table indexed by the service id through the <code>'''clEoClientInstall'''</code> API. This function table is contained in the client table identified by the client id namely, <code>'''CL_EO_NATIVE_COMPONENT_TABLE_ID'''</code> . To use any service of the component, you must use the RMD number that uniquely identifies the service.
| |
− | * Each component is associated with one or more worker threads. Every message intended to be delivered to a component, is set in a queue by IOC on the corresponding port. This message is then picked up by the receiver thread in EO and queued in the EO Job Queue. One of the worker threads picks up the message, decodes the RMD number, and executes the appropriate interface function.
| |
− |
| |
− | <span id='A Typical Component in OpenClovis SAFplus Platform Environment'></span>
| |
− | [[File:SDK_ComponentRealization.png|frame|center| '''A Typical Component in OpenClovis SAFplus Platform Environment''' ]]
| |
− |
| |
− | Figure [[#A Typical Component in OpenClovis SAFplus Platform Environment | A Typical Component in OpenClovis SAFplus Platform Environment]] explains the elements of OpenClovis SAFplus Platform component.
| |
− |
| |
− | OpenClovis SAFplus Platform component comprises the following:
| |
− | <ol>
| |
− | <li>The function <code>'''cbfn3'''</code> is a callback function that represents the lifecycle function of the component. The lifecycle functions are registered with distributed infrastructure of OpenClovis SAFplus Platform and helps to initialize, finalize, and check the status of the component. These functions facilitate CPM to manage the lifecycle of the component.
| |
− |
| |
− | <li>The functions <code>'''fn1'''</code> and <code>'''fn2'''</code> are the component interface functions with a unique identifier. These functions are called the service interface of the component and they represent the services that the components can provide.
| |
− | <br>[[File:OpenClovis_Note.png]]The function <code>'''fn3'''</code> is a service interface of the CPM component.
| |
− |
| |
− | <li> <code>'''App2'''</code> can make calls to <code>'''fn1'''</code> and <code>'''fn2'''</code>, component interface function of <code>'''App1'''</code> using RMD of OpenClovis SAFplus Platform distributed infrastructure. The functions <code>'''fn1'''</code> and <code>'''fn2'''</code> are depicted as <code>'''rfn1'''</code> and <code>'''rfn2'''</code> respectively in Figure [[#A Typical Component in OpenClovis SAFplus Platform Environment | A Typical Component in OpenClovis SAFplus Platform Environment]].
| |
− | </ol>
| |
− |
| |
− | The CPM server periodically performs a health check on the component and remotely invokes the CPM client service functionality using RMD. This functionality in turn invokes the health check up callback, illustrated as <code>'''cbfn3'''</code> in Figure [[#A Typical Component in OpenClovis SAFplus Platform Environment | A Typical Component in OpenClovis SAFplus Platform Environment]], of the component and returns the status to the CPM server.
| |
− |
| |
− | ===Component Initialization===
| |
− |
| |
− | OpenClovis SAFplus Platform provides a set of libraries that must be initialized for application manageability, high availability, and pre-defined main function for easy usability.
| |
− |
| |
− | The following are the consequences when a component application is initialized:
| |
− | #It initializes the basic OpenClovis SAFplus Platform libraries to provide operating system or architecture-independent execution context for the component. It also installs the signal handler to handle all the signals that causes the process termination [for example SIGSEGV, SIGFBP, SIGILL, and so on]. Whenever a signal is generated, signal handler receives the stack trace and signal-related information. The stack trace and the signal information are then moved into the shared memory.
| |
− | #It creates the communication link.
| |
− | #It initializes the client libraries so that the component can use the functionality provided by other components of OpenClovis SAFplus Platform. For example, Event, Provisioning and so on.
| |
− | #It passes the control to the initialization callback function provided in the <code>'''clEoConfig'''</code> structure, where it can implement the specific functionalities exposed by the application.
| |
− | #If the application holds the main thread, the execution continues with the application. Otherwise, after the initialization callback returns, the main thread waits in a loop to accept messages.
| |
− | #When OpenClovis SAFplus Platform requires to shutdown a component, based on the policy or during node shutdown, <code>'''ClCpmTerminateCallbackT'''</code> callback is invoked, which requires to follow the steps explained above.
| |
− |
| |
− | <span id='Component Initialization sequence diagram'></span>
| |
− | [[File:SDK_ComponentInitialization.png|frame|center| '''Component Initialization sequence diagram''' ]]
| |
− |
| |
− | [[File:OpenClovis_Note.png]]If you create new threads or tasks, and send messages from the thread context, then <code>'''clEoMyEoObjectSet()'''</code> and <code>'''clEoMyEoIocPortSet()'''</code> must be in the new thread context to set the environment for communication purpose. If not, every RMD returns a failure.
| |
− |
| |
− | ===Using Availability Management Framework (AMF)===
| |
− |
| |
− | Applications can be made highly available by providing certain callbacks specific to AMF. AMF requires applications to provide callbacks for lifecycle operations, work assignment operations, and protect group related operations (optional). AMF decides to instantiate and assign workload to a component. The components can be instantiated by calling the <code>'''clCompAppInitialize'''</code> callback of the component. This callback is an indication to the component to start the process.
| |
− |
| |
− | After the component completes the start process and is ready to receive the work assignments, it informs the AMF framework by invoking the AMF <code>'''clCpmComponentRegister'''</code> API.
| |
− |
| |
− | Registration process is an indication for AMF that the component have been successfully started and can be assigned work by AMF. On receiving the register callback AMF assigns workload to the component with appropriate high availability state using the CSI set callback API registered in the callback function list using <code>'''clCpmClientInitialize'''</code> API.
| |
− |
| |
− | The CSI set API informs the component that a given CSI (workload) have been assigned to the component. The CSI contains information about the name-value pairs and HA state assigned to the component. The name value pairs are the names and values that a component requires to start serving the workloads. For example, a name-value pair can be a configuration filename and its path or location of checkpointed data. The high availability state is assigned by the AMF to the component, for example, ACTIVE or STANDBY. The ACTIVE HA state is an indication that the component will be active for the given CSI. The STANDBY high availability state indicates that the component must prepare itself to takeover in case of failures of the ACTIVE component.
| |
− |
| |
− | After receiving the CSI set request, the component informs the AMF framework after it is completes the processing required for serving the CSI. This response is an indication for the AMF that the component has successfully received the CSI request and is ready to serve the CSI.
| |
− |
| |
− | HA state can have the following values:
| |
− | * '''Active''' - This means the component is ready to serve the CSI.
| |
− | * '''Standby''' - This means that component is on standby for the CSI.
| |
− | * '''Quiescing''' - This means the component must finish the existing operations and must not take any new assignment. After it has completed serving the existing request, it informs the AMF framework by calling <code>'''Quiescing'''</code> complete API. This is an indication to AMF that the component will not take any new assignment for the CSI and the AMF framework can remove the CSI assignments from this component and send it to other components.
| |
− |
| |
− | AMF framework can call the CSI remove callback to remove the CSI assignments from the component. Component's response to this API is an indication for AMF to assign the CSI to other component.
| |
− |
| |
− | AMF also provides API for interested component to track the status of protection group. Protection group comprises all the components that are assigned HA state (Active or Standby) for the CSI. Protection group tracks API allows the interested component to register with the framework indicating the CSI for which it is interested. The AMF framework informs the component whenever there is a change in the protection group by calling the protection group callback.
| |
− |
| |
− | Proxied components can interact with the AMF framework through a proxy component. Proxy component is an SA-aware component that can communicate with the AMF framework directly. The calls to proxied component pass through the proxy component. All the lifecycle operations, workload operations for proxied component are carried through the proxy component.
| |
− |
| |
− | ===Characteristics of a Sample Application===
| |
− |
| |
− | The sample application depicts an application to generate Global Sequence Numbers. The following are the characteristics of this component:
| |
− | * <code>'''clCompAppInitialize'''</code>, <code>'''clCompAppFinalize'''</code>, and <code>'''clCompAppStateChange'''</code> are the lifecycle related functions.
| |
− | * <code>'''clCompAppHealthCheck'''</code> is the functionality related to High Availability.
| |
− |
| |
− | ===Sample Code for developing an application component===
| |
− |
| |
− | <code><pre>
| |
− | ---------------------------------------------------------------
| |
− | clCompAppMain.h
| |
− | ---------------------------------------------------------------
| |
− | #ifndef CL_COMP_APP_MAIN
| |
− | # define CL_COMP_APP_MAIN
| |
− | # include <clCompCfg.h>
| |
− | # ifndef COMP_NAME
| |
− | # error "COMP_NAME is not defined. Bad or missing ./clCompCfg.h"
| |
− | # endif
| |
− | ClRcT clCompAppTerminate
| |
− | (ClInvocationT invocation,
| |
− | const ClNameT *compName);
| |
− | ClRcT clCompAppAMFCSISet
| |
− | (ClInvocationT invocation,
| |
− | const ClNameT *compName,
| |
− | ClAmsHAStateT haState,
| |
− | ClAmsCSIDescriptorT csiDescriptor);
| |
− | ClRcT clCompAppAMFCSIRemove
| |
− | (ClInvocationT invocation,
| |
− | const ClNameT *compName,
| |
− | const ClNameT *csiName,
| |
− | ClAmsCSIFlagsT csiFlags);
| |
− | ClRcT clCompAppInitialize
| |
− | (ClUint32T argc,
| |
− | ClCharT *argv[]);
| |
− | ClRcT clCompAppFinalize();
| |
− | ClRcT clCompAppStateChange
| |
− | (ClEoStateT eoState);
| |
− | ClRcT clCompAppHealthCheck
| |
− | (ClEoSchedFeedBackT *schFeedback);
| |
− | #endif
| |
− | ---------------------------------------------------------------
| |
− | clCompAppMain.c
| |
− | ---------------------------------------------------------------
| |
− | #include <clCommon.h>
| |
− | #include <clOsalApi.h>
| |
− | #include <clIocServices.h>
| |
− |
| |
− | #include <clRmdApi.h>
| |
− | #include <clDebugApi.h>
| |
− | #include <clOmApi.h>
| |
− | #include <clOampRtApi.h>
| |
− | #include <clProvApi.h>
| |
− | #include <clAlarmApi.h>
| |
− |
| |
− | #include <clEoApi.h>
| |
− | #include <clCpmApi.h>
| |
− | #include <clIdlApi.h>
| |
− | #include <string.h>
| |
− | #include "./clCompAppMain.h"
| |
− | #include "clCompA.h"
| |
− | #if HAS_EO_SERVICES
| |
− | extern ClRcT idlClientInstall(void);
| |
− | #endif
| |
− | ClCpmHandleT cpmHandle;
| |
− | ClRcT clCompAppTerminate(ClInvocationT invocation, const ClNameT *compName)
| |
− | {
| |
− | ClRcT rc;
| |
− |
| |
− | COMPA_DBG_PRINT(("Inside %s \n", __FUNCTION__));
| |
− | /*
| |
− | Do the App Finalization
| |
− | */
| |
− | clAppFinalize();
| |
− | COMPA_DBG_PRINT(("Unregister with CPM before Exit .................%s\n",
| |
− | compName->value));
| |
− | rc = clCpmComponentUnregister(cpmHandle, compName, NULL);
| |
− | COMPA_DBG_PRINT(("Finalize before Exit ................. %s\n",
| |
− | compName->value));
| |
− | rc = clCpmClientFinalize(cpmHandle);
| |
− | clCpmResponse(cpmHandle, invocation, CL_OK);
| |
− | return CL_OK;
| |
− | }
| |
− | ClRcT clCompAppAMFCSISet(ClInvocationT invocation, const ClNameT *compName,
| |
− | ClAmsHAStateT haState,
| |
− | ClAmsCSIDescriptorT csiDescriptor)
| |
− | {
| |
− | ClRcT rc = CL_OK;
| |
− | COMPA_DBG_PRINT(("Inside Function %s \n", __FUNCTION__));
| |
− | if (haState == CL_AMS_HA_STATE_QUIESCING)
| |
− | {
| |
− | /*
| |
− | TODO make the quiescing complete call after the work assigned is
| |
− | done
| |
− | */
| |
− | rc = clAppSetQuiescingState(invocation, compName, csiDescriptor);
| |
− | COMPA_DBG_PRINT(("######## before clCpmCSIQuiescingComplete for "
| |
− | "%s ########\n", COMP_EO_NAME));
| |
− | clCpmCSIQuiescingComplete(cpmHandle, invocation, rc);
| |
− | }
| |
− | else if (haState == CL_AMS_HA_STATE_ACTIVE)
| |
− | {
| |
− | rc = clAppSetActiveState(invocation, compName, csiDescriptor);
| |
− | COMPA_DBG_PRINT(("######## before clCpmResponse(ACTIVE) for "
| |
− | "%s########\n", COMP_EO_NAME));
| |
− | clCpmResponse(cpmHandle, invocation, rc);
| |
− | }
| |
− | else if (haState == CL_AMS_HA_STATE_STANDBY)
| |
− | {
| |
− | rc = clAppSetStandbyState(invocation, compName, csiDescriptor);
| |
− | COMPA_DBG_PRINT(("######## before clCpmResponse(STANDBY) for "
| |
− | "%s########\n", COMP_EO_NAME));
| |
− | clCpmResponse(cpmHandle, invocation, rc);
| |
− | }
| |
− | else
| |
− | {
| |
− | COMPA_DBG_PRINT(("######## before clCpmResponse(%d) for %s########\n",
| |
− | haState, COMP_EO_NAME));
| |
− | clCpmResponse(cpmHandle, invocation, CL_OK);
| |
− | }
| |
− | if (CL_OK != rc)
| |
− | {
| |
− | COMPA_DBG_PRINT(("clCompAppAMFCSISet failed with %d for %s\n", rc,
| |
− | COMP_EO_NAME));
| |
− | }
| |
− | return CL_OK;
| |
− | }
| |
− |
| |
− | ClRcT clCompAppAMFCSIRemove(ClInvocationT invocation, const ClNameT *compName,
| |
− | const ClNameT *csiName, ClAmsCSIFlagsT csiFlags)
| |
− | {
| |
− | ClRcT rc = CL_OK;
| |
− | COMPA_DBG_PRINT(("Inside Function %s \n", __FUNCTION__));
| |
− | /*
| |
− | TODO stop the work assigned before making the response done
| |
− | */
| |
− | rc = clAppCSIRemove(invocation, compName, csiName, csiFlags);
| |
− | clCpmResponse(cpmHandle, invocation, rc);
| |
− | return CL_OK;
| |
− | }
| |
− | /*
| |
− | Service Initialization:
| |
− | 1. Initialize your counter and create mutex.
| |
− | 2. Register Name and generate Logical Address
| |
− | 3 Initialize Checkpoint Service
| |
− | */
| |
− | ClRcT clAppInitialize(ClCpmHandleT cpmHandle)
| |
− | {
| |
− | ClRcT rc = CL_OK;
| |
− | ClNameSvcRegisterT nameRegInfo = { {0} };
| |
− | ClEoExecutionObjT *pEoObj = NULL;
| |
− | ClNameT compName = { 0 };
| |
− | clLogWrite(CL_LOG_HANDLE_APP,CL_LOG_DEBUG,COMP_A_SERVICE_NAME,
| |
− | CL_COMPA_LOG_0_INIT_ENTER);
| |
− | gAppGlobal.version.releaseCode = 'B';
| |
− | gAppGlobal.version.majorVersion = 0x01;
| |
− | gAppGlobal.version.minorVersion = 0x01;
| |
− | gAppGlobal.ckptName.length = sizeof(CKPT_NAME);
| |
− | strncpy(gAppGlobal.ckptName.value, CKPT_NAME, strlen(CKPT_NAME));
| |
− | gAppGlobal.cpmHandle = cpmHandle;
| |
− | gAppGlobal.ckptHdl = -1;
| |
− | /*
| |
− | counter is initialized here
| |
− | */
| |
− | gAppGlobal.count = 0;
| |
− | rc = clOsalMutexCreate(&gAppGlobal.mutex);
| |
− | if (rc != CL_OK)
| |
− | {
| |
− | COMPA_DBG_PRINT(("Failure in mutex create [0x %x]", rc));
| |
− | clLogWrite(CL_LOG_HANDLE_APP,CL_LOG_ERROR,COMP_A_SERVICE_NAME,
| |
− | CL_COMPA_LOG_1_MUTEX_CREATE_FAILED, rc);
| |
− | return rc;
| |
− | }
| |
− | /* register your name with Name Service and get the logical address */
| |
− | rc = clCpmComponentNameGet(gAppGlobal.cpmHandle, &compName);
| |
− | if (CL_OK != rc)
| |
− | {
| |
− | COMPA_DBG_PRINT(("Failure in component name get [0x %x]", rc));
| |
− | clLogWrite(CL_LOG_HANDLE_APP,CL_LOG_ERROR,COMP_A_SERVICE_NAME,
| |
− | CL_COMPA_LOG_1_NAME_GET_FAILED, rc);
| |
− | goto mutexCleanup;
| |
− | }
| |
− | rc = clCpmComponentIdGet(gAppGlobal.cpmHandle, &compName,
| |
− | &gAppGlobal.compId);
| |
− | if (CL_OK != rc)
| |
− | {
| |
− | COMPA_DBG_PRINT(("Failed to get the component ID [0x %x]", rc));
| |
− | clLogWrite(CL_LOG_HANDLE_APP,CL_LOG_ERROR,COMP_A_SERVICE_NAME,
| |
− | CL_COMPA_LOG_1_ID_GET_FAILED, rc);
| |
− | goto mutexCleanup;
| |
− | }
| |
− | nameRegInfo.name.length = strlen(COMP_A_SERVICE_NAME);
| |
− | strcpy(nameRegInfo.name.value, COMP_A_SERVICE_NAME);
| |
− | nameRegInfo.compId = gAppGlobal.compId;
| |
− | nameRegInfo.priority = CL_NS_PRIORITY_HIGH;
| |
− | nameRegInfo.attrCount = 0;
| |
− | gAppGlobal.nameObjRef = CL_NS_GET_OBJ_REF;
| |
− | rc = clNameRegister(gAppGlobal.nameCntxId, &nameRegInfo,
| |
− | &(gAppGlobal.nameObjRef));
| |
− | if (rc != CL_OK)
| |
− | {
| |
− | COMPA_DBG_PRINT(("Failed to register with name [0x %x]", rc));
| |
− | clLogWrite(CL_LOG_HANDLE_APP,CL_LOG_ERROR,COMP_A_SERVICE_NAME,
| |
− | CL_COMPA_LOG_1_NAME_REGISTER_FAILED, rc);
| |
− | goto mutexCleanup;
| |
− | }
| |
− | else
| |
− | {
| |
− | clLogWrite(CL_LOG_HANDLE_APP,CL_LOG_DEBUG,COMP_A_SERVICE_NAME,
| |
− | CL_COMPA_LOG_0_NAME_REGISTERED);
| |
− | }
| |
− | /*
| |
− | Initialize the Checkpoint Service
| |
− | */
| |
− | rc = clCkptInitialize(&gAppGlobal.ckptSvcHdl, NULL, &gAppGlobal.version);
| |
− | if (rc != CL_OK)
| |
− | {
| |
− | COMPA_DBG_PRINT(("Failed in checkpoint initialize rc [0x %x]", rc));
| |
− | clLogWrite(CL_LOG_HANDLE_APP,CL_LOG_ERROR,COMP_A_SERVICE_NAME,
| |
− | CL_COMPA_LOG_1_CKPT_INIT_FAILED, rc);
| |
− | goto nameCleanup;
| |
− | }
| |
− | rc = clEoMyEoObjectGet(&pEoObj);
| |
− | if (rc != CL_OK)
| |
− | {
| |
− | COMPA_DBG_PRINT(("Failed to get the EoObject rc [0x %x]", rc));
| |
− | goto ckptCleanup;
| |
− | }
| |
− | gAppGlobal.pEoObj = pEoObj;
| |
− | rc = compADebugRegister(gAppGlobal.pEoObj);
| |
− | if (rc != CL_OK)
| |
− | {
| |
− | COMPA_DBG_PRINT(("Failed to register with debug rc[0x %x]", rc));
| |
− | goto ckptCleanup;
| |
− | }
| |
− | COMPA_DBG_PRINT(("Sucessfully completed initialization\n"));
| |
− | clLogWrite(CL_LOG_HANDLE_APP,CL_LOG_DEBUG,COMP_A_SERVICE_NAME,
| |
− | CL_COMPA_LOG_0_INIT_DONE, rc);
| |
− | return CL_OK;
| |
− | ckptCleanup:
| |
− | clCkptFinalize(gAppGlobal.ckptSvcHdl);
| |
− | nameCleanup:
| |
− | clNameComponentDeregister(gAppGlobal.compId);
| |
− | mutexCleanup:
| |
− | clOsalMutexDelete(gAppGlobal.mutex);
| |
− | return rc;
| |
− | }
| |
− | ClRcT clCompAppInitialize(ClUint32T argc, ClCharT *argv[])
| |
− | {
| |
− | ClNameT appName;
| |
− | ClCpmCallbacksT callbacks;
| |
− | ClVersionT version;
| |
− | ClIocPortT iocPort;
| |
− | ClRcT rc = CL_OK;
| |
− | /*
| |
− | Do the App intialization
| |
− | */
| |
− | /*
| |
− | Do the CPM client init/Register
| |
− | */
| |
− | version.releaseCode = 'B';
| |
− | version.majorVersion = 01;
| |
− | version.minorVersion = 01;
| |
− | callbacks.appHealthCheck = NULL;
| |
− | callbacks.appTerminate = clCompAppTerminate;
| |
− | callbacks.appCSISet = clCompAppAMFCSISet;
| |
− | callbacks.appCSIRmv = clCompAppAMFCSIRemove;
| |
− | callbacks.appProtectionGroupTrack = NULL;
| |
− | callbacks.appProxiedComponentInstantiate = NULL;
| |
− | callbacks.appProxiedComponentCleanup = NULL;
| |
− | clEoMyEoIocPortGet(&iocPort);
| |
− | COMPA_DBG_PRINT(("Application Address 0x%x Port %x\n",
| |
− | clIocLocalAddressGet(), iocPort));
| |
− | rc = clCpmClientInitialize(&cpmHandle, &callbacks, &version);
| |
− | COMPA_DBG_PRINT(("After clCpmClientInitialize %d\t %x\n", cpmHandle, rc));
| |
− | #if HAS_EO_SERVICES
| |
− | idlClientInstall();
| |
− | #endif
| |
− | /*
| |
− | Block and use the main thread if required other wise return
| |
− | */
| |
− | /*
| |
− | TODO: Application code should come here
| |
− | */
| |
− | clAppInitialize(cpmHandle);
| |
− | /*
| |
− | if main thread usage policy == CL_EO_USE_THREAD_FOR_APP return from this
| |
− | function only after app finishes
| |
− | */
| |
− | /*
| |
− | if main thread usage policy == CL_EO_USE_THREAD_FOR_RECV return from
| |
− | this function immediately after doing some application initialize stuff
| |
− | */
| |
− | rc = clCpmComponentNameGet(cpmHandle, &appName);
| |
− | COMPA_DBG_PRINT(("After clCpmComponentNameGet %d\t %s\n", cpmHandle,
| |
− | appName.value));
| |
− | rc = clCpmComponentRegister(cpmHandle, &appName, NULL);
| |
− | COMPA_DBG_PRINT(("After clCpmClientRegister %x\n", rc));
| |
− | return CL_OK;
| |
− | }
| |
− | ClRcT clCompAppFinalize()
| |
− | {
| |
− | return CL_OK;
| |
− | }
| |
− | ClRcT clCompAppStateChange(ClEoStateT eoState)
| |
− | {
| |
− | /*
| |
− | Application state change
| |
− | */
| |
− | return CL_OK;
| |
− | }
| |
− | ClRcT clCompAppHealthCheck(ClEoSchedFeedBackT *schFeedback)
| |
− | {
| |
− | /*
| |
− | Modify following as per App requirement
| |
− | */
| |
− | schFeedback->freq = CL_EO_BUSY_POLL;
| |
− | schFeedback->status = CL_CPM_EO_ALIVE;
| |
− | return CL_OK;
| |
− | }
| |
− | ClEoConfigT clEoConfig = {
| |
− | COMP_EO_NAME, /* EO Name */
| |
− | COMP_EO_THREAD_PRIORITY, /* EO Thread Priority */
| |
− | COMP_EO_NUM_THREAD, /* No of EO thread needed */
| |
− | COMP_IOC_PORT, /* Required Ioc Port */
| |
− | COMP_EO_USER_CLIENT_ID,
| |
− | COMP_EO_USE_THREAD_MODEL, /* Whether to use main thread for
| |
− | eo Recv or not */
| |
− | clCompAppInitialize, /* Function CallBack to initialize
| |
− | the Application */
| |
− | clCompAppFinalize, /* Function Callback to Terminate
| |
− | the Application */
| |
− | clCompAppStateChange, /* Function Callback to change the
| |
− | Application state */
| |
− | clCompAppHealthCheck, /* Function Callback to change the
| |
− | Application state */
| |
− | };
| |
− | /*
| |
− | You may force default libraries here by using CL_TRUE or CL_FALSE or use
| |
− | appropriate configuration generated by ClovisWorks in ./clCompAppMain.h The
| |
− | first 6 basic libraries are mandatory.
| |
− | */
| |
− | ClUint8T clEoBasicLibs[] = {
| |
− | COMP_EO_BASICLIB_OSAL, /* osal */
| |
− | COMP_EO_BASICLIB_TIMER, /* timer */
| |
− | COMP_EO_BASICLIB_BUFFER, /* buffer */
| |
− | COMP_EO_BASICLIB_IOC, /* ioc */
| |
− | COMP_EO_BASICLIB_RMD, /* rmd */
| |
− | COMP_EO_BASICLIB_EO, /* eo */
| |
− | COMP_EO_BASICLIB_OM, /* om */
| |
− | COMP_EO_BASICLIB_HAL, /* hal */
| |
− | COMP_EO_BASICLIB_DBAL, /* dbal */
| |
− | };
| |
− | ClUint8T clEoClientLibs[] = {
| |
− | COMP_EO_CLIENTLIB_COR, /* cor */
| |
− | COMP_EO_CLIENTLIB_CM, /* cm */
| |
− | COMP_EO_CLIENTLIB_NAME, /* name */
| |
− | COMP_EO_CLIENTLIB_LOG, /* log */
| |
− | COMP_EO_CLIENTLIB_TRACE, /* trace */
| |
− | COMP_EO_CLIENTLIB_DIAG, /* diag */
| |
− | COMP_EO_CLIENTLIB_TXN, /* txn */
| |
− | CL_FALSE, /* NA */
| |
− | COMP_EO_CLIENTLIB_PROV, /* Prov */
| |
− | COMP_EO_CLIENTLIB_ALARM, /* alarm */
| |
− | COMP_EO_CLIENTLIB_DEBUG, /* debug */
| |
− | COMP_EO_CLIENTLIB_GMS /* gms */
| |
− | };
| |
− |
| |
− | #########
| |
− | </pre></code>
| |