Table of Contents NMS Glossary Previous Page Next Page Version


Chapter 7

Implementing the Service Manager


7.1 Introduction
7.2 Binding Function Overview
7.3 Life Cycle Binding Functions
7.4 Service Registration
7.4.1 xxxInitializeManager
Registering Binding Functions
Version and Compatibility Information
Specifying Version and Compatibility Levels
Initializing Global and Local Tracemasks
xxxInitializeManager Example
7.4.2 xxxDefineService
7.5 Initializing Managed Resource Event Handling
7.6 Service Startup
7.6.1 xxxOpenServiceManager
7.6.2 xxxOpenService
7.7 Event Handling Shutdown
7.8 Service Shutdown
7.8.1 xxxCloseService
7.8.2 xxxCloseServiceManager
7.9 Runtime Binding Functions
7.9.1 Command Processing
7.9.2 Error Handling
xxxGetText
xxxFormatMessage
7.9.3 Trace Handling
Setting Local TraceMask
Converting Trace Records to ASCII
7.9.4 Event Processing
7.10 Additional Binding Functions

7.1 IntroductionTop of Page

The service manager provides the "glue code" (i.e., the set of binding functions) that connects the service implementation to the Natural Access infrastructure.

Binding functions are called by the dispatcher. Each service has a unique set of binding functions. Binding functions are named xxxFunctionName, where xxx is the service acronym.

A service must implement a subset of the binding functions. For example, each service must implement the binding function to process API commands (i.e., xxxProcessCommand). Optional binding functions need only be implemented if required by the service (e.g., xxxSetTraceLevel).

One binding function is known by the dispatcher, xxxInitializeManager. The remaining binding function names are registered with the dispatcher during service initialization.

The following files are created or modified when implementing the service manager binding functions:

File

Description

xxxbnd.c

Contains the service manager binding functions.

xxxdef.h

Contains version IDs and compatibility levels of the service.

xxxsys.h

Contains trace tag codes.

7.2 Binding Function OverviewTop of Page

The binding functions in the service manager are divided into two groups:

The life cycle binding functions are called during service startup and shutdown. These binding functions initialize the service and handle any service specific operations required when creating and destroying Natural Access queues and contexts.

The runtime binding functions are the functions which are called while the application is running. These functions include processing API commands and handling errors and events.


chap73.gif

Figure 24. Service Manager Binding Functions

7.3 Life Cycle Binding FunctionsTop of Page

The life cycle binding functions are the service specific functions called by Natural Access to perform:

The life cycle binding functions are invoked by the dispatcher in response to application calls of the Natural Access API. The life cycle binding functions can return SUCCESS, SUCCESS_RESPONSE, or an error. Figure 25 shows the binding functions called in response to Natural Access application startup:


chap77.gif

Figure 25. Life Cycle Binding Functions


The following tables list the life cycle binding functions and gives an overview of each function including the key dispatcher functions and data structures:

Life Cycle Binding Functions - Registration

xxxInitializeManager

Description:

· Acts as an entry point into service manager for service manager and service registration.

· Declares version numbers for service manager.

· Declares compatibility levels for service manager.

· Declares service manager binding functions.

· Acquires global tracemask pointer managed by ctdaemon (if active).

Behavior:

Synchronous

Dispatcher Functions Called:

dispRegisterServiceManager
dispGetTracePointer

Important Data Structure:

CTAINTREV

Returns:

SUCCESS or an error.

Initiated via Natural Access API:

ctaInitialize

Required?

Must be implemented.

xxxDefineService

Description:

· Declares version numbers for service.

· Declares compatibility levels for service.

· Declares needed API compatibility levels of related services.

· Declares the parameter descriptor tables.

Behavior:

Synchronous

Dispatcher Functions Called:

dispRegisterService

Important Data Structures:

CTAINTREV
CTAPARM_DESC
CTAREQ_SVC

Returns:

SUCCESS or an error.

Initiated via Natural Access API:

ctaInitialize

Required?

Must be implemented.

Life Cycle Binding Functions - Event Handling

xxxAttachServiceManager

Description:

· Declares wait objects (if interacting with a multiplexed managed resource).

· Initializes communications with managed resource.

· Allocates queuecontext object for processing incoming events.

Behavior:

Synchronous

Dispatcher Functions Called:

dispRegisterWaitObject

Important Data Structure:

Managed resource specific queuecontext.

Returns:

SUCCESS or an error.

Initiated via Natural Access API:

ctaCreateQueue

Required?

Optional, required if managed resource is multiplexed.

xxxDetachServiceManager

Description:

Deallocates all data structures allocated with xxxAttachServiceManager.

Behavior:

Synchronous

Dispatcher Functions Called:

dispUnregisterWaitObject

Important Data Structure:

Managed resource specific queuecontext.

Returns:

SUCCESS or an error.

Initiated via Natural Access API:

ctaDestroyQueue

Required?

Must be implemented if xxxAttachServiceManager is implemented.

Life Cycle Binding Functions - Service Startup

xxxOpenServiceManager

Description:

· Allocates mgrcontext object which contains data pertaining to the managed resource but is specific to a context.

· Declares wait objects (if interacting with a non-multiplexed managed resource).

Behavior:

Synchronous

Dispatcher Functions Called:

dispRegisterWaitObject
dispGetQueueHandle

Important Data Structure:

Managed resource specific mgrcontext.

Returns:

SUCCESS or an error.

Initiated via Natural Access API:

ctaOpenServices

Required?

Must be implemented.

xxxOpenService

Description:

Initializes the managed resource by requesting resources to support a client (i.e., a context).

Behavior:

Asynchronous

Dispatcher Functions Called:

dispQueueEvent
dispMakeAndQueueEvent

Important Data Structures:

CTA_MVIP_ADDR
CTA_SERVICE_ARGS

Returns:

SUCCESS or an error.

Initiated via Natural Access API:

ctaOpenServices

Required?

Optional

xxxCloseServiceManager

Description:

Deallocates all data structures allocated with xxxOpenServiceManager.

Behavior:

Synchronous

Dispatcher Functions Called:

dispUnregisterWaitObject

Important Data Structure:

Managed resource specific mgrcontext.

Returns:

SUCCESS or an error.

Initiated via Natural Access API:

ctaCloseServices

Required?

Must be implemented.

xxxCloseService

Description:

· Releases resources from managed resource for that context.

· Operates asynchronously.

Behavior:

Synchronous

Dispatcher Functions Called:

dispQueueEvent
dispMakeAndQueueEvent

Important Data Structure:

None

Returns:

SUCCESS or an error.

Initiated via Natural Access API:

ctaCloseServices

Required?

Must be implemented if xxxOpenService is implemented.

7.4 Service RegistrationTop of Page

Service registration occurs when the application calls ctaInitialize. Two binding functions are called during initialization, xxxInitializeManager and xxxDefineService.


chap75.gif

Figure 26. Service Registration


ctaInitialize can only be called once per process; therefore the call will be thread-safe. xxxInitializeManager and xxxDefineService need not be coded to be reentrant since ctaInitialize can only be called once per process (and only from one thread within that process).

If the service manager is not loaded, ctaInitialize loads it into memory. Each service manager must reside in its own DLL or library which conforms to the naming convention xxxmgr.dll (e.g., tikmgr.dll) or libxxxmgr.so in UNIX.

The dispatcher then calls the service manager entry point xxxInitializeManager.

7.4.1 xxxInitializeManagerTop of Page

xxxInitializeManager is the only required exported function from a service manager DLL or shared library. xxxInitializeManager performs the following functions:

Registering Binding FunctionsTop of Page

The binding function names are registered with the dispatcher during service initialization. This registration makes the binding functions of the service manager available to the dispatcher so they can be invoked by the dispatcher when needed. Binding functions are declared in the CTASVCMGR_FNS function pointer table. A NULL entry in the table indicates that the default implementation for that function should be used (i.e., no service-specific implementation of the binding function is required). The following table lists the default implementation of each binding function:

Binding Function

Default Implementation

xxxDefineService

Return SUCCESS

xxxAttachServiceManager

Return SUCCESS

xxxDetachServiceManager

Return SUCCESS

xxxOpenServiceManager

Return SUCCESS

xxxCloseServiceManager

Return SUCCESS

xxxOpenService

Enqueue CTAEVN_DISP_OPEN_SERVICE_DONE event, reason CTA_REASON_FINISHED

xxxCloseService

Enqueue CTAEVN_DISP_CLOSE_SERVICE_DONE event, reason CTA_REASON_FINISHED

xxxProcessEvent

Return SUCCESS

xxxProcessCommand

Return SUCCESS

xxxAddRTC

Return SUCCESS

xxxRemoveRTC

Return SUCCESS

xxxGetText

Return NULL

xxxFormatMessage

Format event or command by printing the IDs

xxxSetTraceLevel

Return SUCCESS

xxxFormatTraceBuffer

Return SUCCESS

xxxGetFunctionPointer

Return NULL


chap79.gif
tik service

<<<< excerpt from tikbnd.c >>>>

STATIC CTASVCMGR_FNS tikSvcmgrFns =

{

sizeof(CTASVCMGR_FNS),

tikDefineService, /* xxxDefineService() */

tikAttachServiceManager, /* xxxAttachServiceManager() */

tikDetachServiceManager, /* xxxDetachServiceManager() */

tikOpenServiceManager, /* xxxOpenServiceManager() */

tikCloseServiceManager, /* xxxCloseServiceManager() */

tikOpenService, /* xxxOpenService() */

tikCloseService, /* xxxCloseService() */

NULL, /* xxxProcessEvent() */

tikProcessCommand, /* xxxProcessCommand() */

NULL, /* xxxAddRTC() -future */

NULL, /* xxxRemoveRTC() -future */

tikGetText, /* xxxGetText() */

tikFormatMessage, /* xxxFormatMessage() */

tikSetTraceLevel, /* xxxSetTraceLevel() */

tikFormatTraceBuffer, /* xxxFormatTraceBuffer() */

NULL, /* xxxGetFunctionPointer() -future */

};

Version and Compatibility InformationTop of Page

There are two types of version information for a Natural Access service:

The version ID consists of revision information which is intended to be for "human readable" identification purposes. The version information consists of a revision number and a build date.

The revision number is reported in the format major_rev.minor_rev (e.g., 2.2). The major revision number is typically incremented when a major change in functionality is released. The minor revision number is typically incremented when small changes (e.g., bug fixes) are released. Typically, the minor revision number is reset to zero when the major revision number is incremented.

The build date is in mm dd yyyy format. It is typically encoded using the __DATE__ compiler built-in.

Compatibility levels are used for runtime interoperability checking between a target software module and a caller of that software module. For example, the compatibility level of the dispatcher (acting as the target software module) may be checked by a Natural Access service (acting as a caller).

A compatibility level consists of a 1-based integer that is assigned to a target software module. This level is incremented when the software module is modified such that it is no longer compatible with existing clients. Examples of such modifications include:

There are three interoperability scenarios to consider when writing a Natural Access service:

The following table describes processing aspects of these scenarios:

Target Software Module

Client

Assigning a Compatibility Level

Requesting a Compatibility Level

Comparing Assigned vs. Requested Compatibility Levels

Dispatcher

Natural Access service

Done internally by Natural Access; transparent to service writer.

Use the DISP_COMPATLEVEL macro as the value for reqdisplevel in CTAINTREV_INFO structure

dispRegisterServiceManager compares the internal value of the dispatcher with the value in reqdisplevel. If they are equal, processing continues. Otherwise, processing aborts.

Natural Access service API

Natural Access application

Set the exapilevel field of the CTAINTREV_INFO structure.

Get the XXXAPI_COMPATLEVEL macro from the target's xxxdef.h file.

Write an application function to call ctaGetServiceVersion for the target service. Compare XXXAPI_COMPATLEVEL with the compatlevel field returned in the CTA_REV_INFO structure.

Natural Access service SPI

Another Natural Access service

Set the exspilevel field of the CTAINTREV_INFO structure.

Get the XXXSPI_COMPATLEVEL macro from the target's xxxdef.h file. In the client's xxxDefineService function, create a CTAREQSVC_INFO structure and set the target reqspilevel field to the target's XXXSPI_COMPATLEVEL.

dispRegisterService compares the client's reqspilevel with the targets exspilevel. If they are equal, processing continues. Otherwise, processing aborts.

Specifying Version and Compatibility LevelsTop of Page

To specify compatibility levels and version IDs for a service:

The CTAINTREV_INFO structure is defined as follows:

typedef struct        /* CTA internal revision info structure           */
{
DWORD size; /* Size of the returned structure */
DWORD majorrev; /* Major revision of service/manager */
DWORD minorrev; /* Minor revision of service/manager */
char builddate [12]; /* Build date, "Mmm dd yyyy\0" */
DWORD reqdisplevel; /* Required compat level of Dispatcher */
DWORD expapilevel; /* Exported compat level of Service API */
DWORD expspilevel; /* Exported compat level of Service SPI */
} CTAINTREV_INFO;

chap71.gif
tik service

<<<< excerpt from tikdef.h >>>>

/*--------------------------------------------------------------

TIK Version IDs

- These ID's are used to identify the revision level of this service.

------------------------------------------------------------*/

#define TIK_MAJORREV 1

#define TIK_MINORREV 0

/*--------------------------------------------------------------

TIK Compatibility Level IDs

- These ID's are used to determine runtime compatibility between
the installed TIK service and clients of the TIK service.

- The API_COMPATLEVEL is used by CT Access application
developers who want to check the "hard coded" value in
their application against the "hard coded" value in the
installed TIK service

- The SPI_COMPATLEVEL is useful to CT Access service writers
who want to check the "hard coded" value in their client
service against the "hard coded" value in the installed
TIK service.

-------------------------------------------------------------*/

#define TIKAPI_COMPATLEVEL 1

#define TIKSPI_COMPATLEVEL 1

Initializing Global and Local TracemasksTop of Page

Tracing is controlled in one of two ways. The first way is via the ctdaemon where a tracemask can be set via the ctdaemon command processor. The second way is via an internal, service-specific tracemask that can be set within an application.

By allowing two mechanisms to control tracing, an application developer is able to:

To determine whether to generate a trace record associated with a trace category, the service must check both the global tracemask and the local (service-specific) tracemask.

To check the global tracemask, the service, upon initialization, must first call dispGetTracePointer to acquire a pointer to the global tracemask. It then stores this pointer so it can be accessed via all service manager and service implementation functions:


chap725.gif
tik service

<<<< excerpt from tikbnd.c >>>>

/* ---------------------------------------------

Global service trace mask

-----------------------------------------------*/

volatile DWORD *tikTracePointer;

To define a local tracemask, define a tracemask on a per context basis. A tracemask is defined as a DWORD.


chap76.gif
tik service

<<<< excerpt from tikdef.h >>>>

/* ----------------------------------------------------------

A DWORD tracemask is included in the definition of a
TIK_CHANNEL_OBJECT since it is allocated (as a mgrcontext) on a
per CTA context basis.

----------------------------------------------------------*/

typedef struct _TIK_CHAN

{

DWORD size; /* Size of this structure */

DWORD timestamp; /* Context creation timestamp. */

CTAHD ctahd; /* Opening CTA context handle */

DWORD channelId; /* Opened channel number. */

DWORD state; /* current state of channel. */

DWORD owner; /* Current owner of channel. */

DWORD tracemask; /* Context specific tracemask */

TIK_DEVICE_OBJECT *ptikDevice; /* pointer to "tick device" */

/* object. */

TIK_CONTEXT_INFO context_info; /* Application context info .*/

} TIK_CHANNEL_OBJECT;

xxxInitializeManager ExampleTop of Page


chap70.gif
tik service

<<<< excerpt from tikbnd.c >>>>

DWORD NMSAPI tikInitializeManager( void )

{

DWORD ret;

CTABEGIN("tikInitializeManager");

static BOOL initialized = FALSE;

if (initialized)

{

return CTALOGERROR(NULL_CTAHD, CTAERR_ALREADY_INITIALIZED, TIK_SVCID);

}

/* Set manager revision information. */

tikMgrRevInfo.size = sizeof(CTAINTREV_INFO);

tikMgrRevInfo.majorrev = TIK_MAJORREV;

tikMgrRevInfo.minorrev = TIK_MINORREV;

strcpy (tikMgrRevInfo.builddate, tikBuildDate);

tikMgrRevInfo.expapilevel = TIKAPI_COMPATLEVEL;

tikMgrRevInfo.expspilevel = TIKSPI_COMPATLEVEL;

tikMgrRevInfo.reqdisplevel = DISP_COMPATLEVEL;

dispGetTracePointer(&tikTracePointer);

ret = dispRegisterServiceManager("TIKMGR", &tikSvcmgrFns,

&tikMgrRevInfo);

if (ret != SUCCESS)

{

return CTALOGERROR(NULL_CTAHD, ret, TIK_SVCID);

}

initialized = TRUE;

return SUCCESS;

}

7.4.2 xxxDefineServiceTop of Page

After initializing a service manager and its binding functions, services are initialized. Each service specified in the call to ctaInitialize is initialized by the dispatcher by invoking the appropriate xxxDefineService binding function.

xxxDefineService should perform the following tasks:

The dispatcher manages parameters for registered services. During service registration (during the call to ctaInitialize), the service must pass the pointer to the parameter description table defined in xxxparm.c to the dispatcher via dispRegisterService.

After the parameter table is registered with the dispatcher, it must not be modified. Each individual parameter descriptor must remain valid and unmodified. All dynamic changes to parameter descriptor tables and their contents must take place before service registration.


chap74.gif
tik service

<<<< excerpt from tikbnd.c >>>>

STATIC DWORD NMSAPI tikDefineService( char* svcname )

{

DWORD ret;

/*

* Needed by CT Access provided error logging service

*/

CTABEGIN("tikDefineService");

/* Set service revision info. */

tikSvcRevInfo.size = sizeof(CTAINTREV_INFO);

tikSvcRevInfo.majorrev = TIK_MAJORREv;

tikSvcRevInfo.minorrev = TIK_MINORREV;

tikSvcRevInfo.expapilevel = TIKAPI_COMPATLEVEL;

tikSvcRevInfo.expspilevel = TIKSPI_COMPATLEVEL;

tikSvcRevInfo.reqdisplevel = DISP_COMPATLEVEL;

strcpy(tikSvcRevInfo.builddate, __DATE__);

/* The most important phase of initializing a service! */

ret = (dispRegisterService("TIK",

TIK_SVCID,

"TIKMGR",

&tikSvcRevInfo,

NULL,

0,

_tikParmDescTable,

NULL));

if ( ret != SUCCESS )

{

return CTALOGERROR(NULL_CTAHD, ret, TIK_SVCID);

}

return SUCCESS;

}

7.5 Initializing Managed Resource Event HandlingTop of Page

xxxAttachServiceManager should be implemented for a service that handles events from a multiplexed managed resource. If the managed resource is not multiplexed, use xxxOpenServiceManager to initialize event handling on a per context basis (see Section 7.6, Service Startup).


chap726.gif

Figure 27. Event Handling Initialization


In xxxAttachServiceManager, the following actions should take place:

  1. Define and allocate a data structure containing:

    • Information about the managed resource as a whole (as discussed in Section 4.2, Understanding the Managed Resource).

      
      
    • Demultiplexing information to ensure that the event is processed on behalf of the correct context.

      
      Once this data structure is allocated, a pointer to it is returned to Natural Access as a (void *)queuecontext. This queuecontext is then passed to other binding functions as appropriate. It is cast to (void *) to allow developers to create any data structure deemed appropriate and have Natural Access pass it around transparently to other binding functions (see Figure 28). 
      
       
      chap724.gif
      Figure 28. Device Specific Data Objects

      
       
      

      chap723.gif
      tik service

      Since the TICK server is a multiplexed managed resource, the following queuecontext is defined and allocated.

      <<<< excerpt from tiksys.h >>>>

      /*-------------------------------------------------------------

      "TICK DEVICE" Object

      - Used as a "queuecontext"

      - refers to an instance of a "ticker" which can support

      up to 10 logical channels

      -----------------------------------------------------------*/

      struct _TIK_CHAN;

      typedef struct

      {

      DWORD size; /* Size of this structure */

      TSIIPC_STREAM_HD connector; /* Client side IPC handle. */

      BOOL pendingread; /* Flag for pending IPC read */

      unsigned readcount; /* Outstanding requested */

      /* read count */

      TIK_RSP_COM_OBJ response; /* Server response via */

      /* comm channel */

      struct _TIK_CHAN *channelTbl[10]; /* Array of logical */

      /* channels for this device */

      }

    • A single wait object is allocated and registered with the dispatcher (within the newly created Natural Access event queue) via dispRegisterWaitObject. This wait object will fire whenever any message is received from the managed resource. The arguments to dispRegisterWaitObject include the queuecontext and a function pointer to the event handler callback function (xxxFetchAndProcess) that performs event demultiplexing and processing (initiated by the call to ctaWaitEvent). Wait objects are operating system specific entities.

      
      The following table identifies the appropriate wait object per operating system:
      Operating System

      Native "wait" object

      Windows NT

      Manual reset event object

      UNIX

      pollfd structure


      chap72.gif
      tik service

      <<<< excerpt from tikbnd.c >>>>

      /*--------------------------------------------------------------

      tikAttachServiceManager

      - Declare Wait object

      - Allocate "Device" object which represents the "tick device".

      - Register the wait object with CT Access via dispRegisterWaitObject

      - Set the device object to the "queuecontext" since demultiplexing

      of events is done a per "tick device" basis.

      ------------------------------------------------------------*/

      STATIC DWORD NMSAPI tikAttachServiceManager
      CTAQUEUEHD ctaqueuehd,
      unsigned mode,
      void **queuecontext)

      {

      TIK_DEVICE_OBJECT *ptikDevice = NULL;

      TSIIPC_WAIT_OBJ_HD waitobj;

      CTA_WAITOBJ *ctawaitobj;

      DWORD ret;

      /* Needed by CT Access provided error logging service */

      CTABEGIN("tikAttachServiceManager");

      /* Initialize queuecontext */

      *queuecontext = NULL;

      /* Create Tick "device" object. */

      if ( (ptikDevice=tikCreateDeviceObject()) == NULL )

      {

      return CTALOGERROR( NULL_CTAHD, CTAERR_OUT_OF_MEMORY, TIK_SVCID );

      }

      /* Establish IPC connection. */

      /* In the process of establishing IPC connection,

      * OS specific server-to-client communication

      * wait object is created within NMS tsi library.

      * Under NT: wait object(manual reset event) is created via

      * Window Socket API(WSACreateEvent).

      * Under UNIX : wait object(pollfd structure) is allocated via

      * alloc().

      */

      else if ( (ret=tikSetupIPC( ptikDevice )) != SUCCESS )

      {

      tikDestroyDeviceObject( ptikDevice );

      return CTALOGERROR( NULL_CTAHD, ret, TIK_SVCID );

      }

      /* Get tsi library created waitobject to register with CT Access. */

      else if ( tsiIPCGetWaitObject(ptikDevice->readhd, &waitobj) != SUCCESS )

      {

      tikDestroyDeviceObject( ptikDevice );

      return CTALOGERROR( NULL_CTAHD, CTAERR_OS_INTERNAL_ERROR, TIK_SVCID );

      }

      /* Register created waitobject with CT Access. */

      else if ( (ret=dispRegisterWaitObject( ctaqueuehd,

      (CTA_WAITOBJ *)waitobj,

      tikFetchAndProcess,

      (void *)ptikDevice )) != SUCCESS )

      {

      tikDestroyDeviceObject( ptikDevice );

      return CTALOGERROR( NULL_CTAHD, ret, TIK_SVCID );

      }

      /* The follow two function calls(dispFindWaitObject,

      * tsiIPCRegisterWaitObjectCopy) are required in order to

      * make use of NMS's abstracted IPC communications layer.

      */

      /* Acquire registered CTA WaitObject to register with TSIIPC. */

      else if ( (ret=dispFindWaitObject( ctaqueuehd,

      (CTA_WAITOBJ *)waitobj,

      &ctawaitobj) ) != SUCCESS )

      {

      tikDestroyDeviceObject( ptikDevice );

      return CTALOGERROR( NULL_CTAHD, ret, TIK_SVCID );

      }

      /* Register CTA WaitObject with TSIIPC. */

      else if ( (ret=tsiIPCRegisterWaitObjectCopy(ptikDevice->readhd,

      (TSIIPC_WAIT_OBJ_HD)ctawaitobj )

      ) != SUCCESS )

      {

      tikDestroyDeviceObject( ptikDevice );

      return CTALOGERROR( NULL_CTAHD, TIKERR_CAN_NOT_CONNECT, TIK_SVCID );

      }

      /* Assign the device object to the "queuecontext" so that event

      * handling can be performed on a "device" basis.

      * Using CT Access terminology,"Mux Handling will be on a per queue basis

      * (as opposed to a per context basis)".

      */

      else

      *queuecontext = (void *)ptikDevice;

      return SUCCESS;

      } /* end tikAttachServiceManager() */

    7.6 Service StartupTop of Page

    Service startup occurs when the application calls ctaOpenServices. Two binding functions are called during service startup, xxxOpenServiceManager and xxxOpenService.


    chap78.gif

    Figure 29. Service Startup

    7.6.1 xxxOpenServiceManagerTop of Page

    xxxOpenServiceManager accomplishes the following tasks:

    1. Defines and allocates a data structure containing information pertaining to a client (context) of the managed resource (as discussed in Section 4.2, Understanding the Managed Resource).

      
      Once this data structure is allocated, a pointer to it is returned to Natural Access as a (void *) mgrcontext. This mgrcontext is then passed to other binding functions as appropriate. It is cast to (void *) to allow developers to create any data structure deemed appropriate and to enable Natural Access to pass it around transparently to other binding functions (see Figure 28). 
      
        
      

      chap710.gif
      tik service

      <<<< excerpt from tiksys.h >>>>

      /*-----------------------------------------------------------------------

      "TICK CHANNEL" Object

      - used as a "mgrcontext"

      - only one TICK CHANNEL object per CTA context (ctahd)

      - a TICK CHANNEL is one of the up to 10 logical channels supported by

      a TICK DEVICE

      ---------------------------------------------------------------------*/

      typedef struct _TIK_CHAN

      {

      DWORD size; /* Size of this structure */

      DWORD timestamp; /* Context creation timestamp. */

      CTAHD ctahd; /* Opening CT Access context handle */

      DWORD channelId; /* Opened channel number. */

      DWORD state; /* current state of channel. */

      DWORD owner; /* Current owner of this channel. */

      DWORD tracemask; /* Context specific tracemask */

      TIK_DEVICE_OBJECT *ptikDevice; /* pointer to "tick device" object */

      TIK_CONTEXT_INFO context_info; /* App. context information */

      } TIK_CHANNEL_OBJECT;

    2. If the managed resource is not a multiplexed managed resource, xxxOpenServiceManager must also allocate a wait object and register it with the dispatcher via dispRegisterWaitObject. This wait object will fire only for those messages received from the managed resource that are destined for this specific context. The arguments to dispRegisterWaitObject include the mgrcontext and a function pointer to the event handler callback function (xxxFetchAndProcess) that performs event processing. No demultiplexing processing is required. Wait objects are operating system specific entities. The following table identifies the appropriate wait object per operating system:

      
       
      
      Operating System

      Native "wait" object

      Windows NT

      manual reset event object

      UNIX

      pollfd struct

      Note: In this case, a wait object is created and registered with the dispatcher for every context that is created on this service. This may be problematic for those operating systems with a limited number of wait objects available for general use.

      chap714.gif
      tik service

      <<<< excerpt from tikbnd.c >>>>

      /*-----------------------------------------------------------------------

      tikOpenServiceManager

      - Allocate Service Manager specific data (a manager context)

      - In this case, a manager context corresponds to a Tick CHANNEL object.

      ---------------------------------------------------------------------*/

      STATIC DWORD NMSAPI tikOpenServiceManager( CTAHD ctahd,

      void *queuecontext,

      void **mgrcontext )

      {

      TIK_DEVICE_OBJECT *ptikDevice = (TIK_DEVICE_OBJECT *)queuecontext;

      TIK_CHANNEL_OBJECT *ptikChannel = NULL;

      /* Needed by CT Access provided error logging service */

      CTABEGIN("tikOpenServiceManager");

      if ( (ptikChannel=tikCreateChannelObject(ctahd, ptikDevice)) == NULL)

      {

      *mgrcontext = NULL;

      return CTALOGERROR( NULL_CTAHD, CTAERR_OUT_OF_MEMORY, TIK_SVCID );

      }

      /* Assign mgrcontext to be the Channel Object.

      * A "manager context" is supposed to be data that is

      * specific to a single instance of a CT Access context (ctahd);

      * a Channel Object is just that.

      */

      else

      *mgrcontext = (void *)ptikChannel;

      return SUCCESS;

      } /* end tikOpenServiceManager() */

    7.6.2 xxxOpenServiceTop of Page

    The xxxOpenService binding function performs any asynchronous interaction with the managed resource that is necessary to initialize the service and make it ready to accept and process commands on behalf of a client. xxxOpenService and xxxCloseService are the only asynchronous binding functions. Since they are asynchronous, they must return an event to the dispatcher, and ultimately to the application, when they complete their operation.

    The asynchronous open service routine must have a way to be notified asynchronously via an event that the initialization has been completed. If the service manages a device, then this event usually comes through the wait object and wait function registered with the dispatcher at xxxAttachServiceManager, or xxxOpenServiceManager time. The wait function is responsible for processing the event inside the service, possibly executing other initialization commands and finally passing the DONE event to the dispatcher so that the service can be placed in the opened state.

    xxxOpenService must place an event, such as CTAEVN_DISP_OPEN_SERVICE_DONE, in the Natural Access queue to notify the dispatcher that the service has completed its initialization and is ready to process commands. xxxOpenService calls dispMakeAndQueueEvent when it has been notified that the initialization is complete. The service must pass the service ID (the svcid argument passed to xxxOpenService) as the source argument, and CTA_SYS_SVCID as the destination. The DISP_EVENT structure will be processed into the Natural Access event that gets passed up to the application.

    Services that do not require asynchronous open service processing must queue the CTAEVN_DISP_OPEN_SERVICE_DONE completion event using dispQueueEvent.


    chap715.gif
    tik service

    <<<< excerpt from tikbnd.c >>>>

    /*------------------------------------------------------------------

    tikOpenService

    - Initialize any dedicated resources (typically on a per CT Access

    Context basis)

    - For the Tik Service, this means allocating a logical channel on the

    "physical" TICK Device.

    ------------------------------------------------------------------*/

    STATIC DWORD NMSAPI tikOpenService( CTAHD ctahd,

    void *mgrcontext,

    char *svcname,

    unsigned svcid,

    CTA_MVIP_ADDR *mvipaddr,

    CTA_SERVICE_ARGS *svcargs )

    {

    TIK_CHANNEL_OBJECT *ptikChannel = (TIK_CHANNEL_OBJECT *)mgrcontext;

    TIK_CMD_COM_OBJ cmd = { 0 };

    DWORD ret;

    /* Needed by CT Access provided error logging service */

    CTABEGIN("tikOpenService");

    ASSERT( tsiStricmp(svcname, "TIK") == 0 );

    ASSERT( svcid == TIK_SVCID );

    /* svcargs->args[0] contain logical number to use in server. */

    ptikChannel->channelId = svcargs->args[0];

    if( ptikChannel->channelId < 0 || ptikChannel->channelId > 9 )

    {

    return( CTALOGERROR( NULL_CTAHD, CTAERR_BAD_ARGUMENT, TIK_SVCID ));

    }

    else

    ptikChannel->ptikDevice->channelTbl[ptikChannel->channelId] =

    ptikChannel;

    /* If CTA_TRACEMASK_DEBUG_BIT0 is enabled,

    * log state transition information.

    */

    if ( TRACEMASK_BIT0_SET(ptikChannel->tracemask) )

    {

    ret = tikLogStateTransition( ptikChannel,

    ptikChannel->state,

    CHANNEL_OPENING,

    "ctaOpenServices" );

    if ( ret != SUCCESS )

    {

    return CTALOGERROR( NULL_CTAHD, ret, TIK_SVCID );

    }

    }

    ptikChannel->state = CHANNEL_OPENING;

    /* Send TIKSVR_OPEN_CHANNEL request. */

    cmd.size = sizeof( TIK_CMD_COM_OBJ );

    cmd.timestamp = time(NULL);

    cmd.client_id = ptikChannel->channelId;

    cmd.command = TIKSVR_OPEN_CHANNEL;

    cmd.data1 = ptikChannel->channelId;

    cmd.data2 = 0;

    cmd.data3 = 0;

    if( (ret=tikSendClientCommand( ptikChannel, &cmd )) != SUCCESS )

    {

    tikDestroyChannelObject( ptikChannel );

    return CTALOGERROR( NULL_CTAHD, ret, TIK_SVCID );

    }

    else if( (ret=tikReadServerResponse( ptikChannel )) != SUCCESS )

    {

    tikDestroyChannelObject( ptikChannel );

    return CTALOGERROR( NULL_CTAHD, ret, TIK_SVCID );

    }

    return SUCCESS;

    } /* end tikOpenService() */

    7.7 Event Handling ShutdownTop of Page

    The xxxDetachServiceManager binding function is invoked when the queue is destroyed via ctaDestroyQueue. It is a synchronous function and must return to the dispatcher when detach processing is completed.

    Detaching a service manager involves cleaning up all that was done when attaching the service manager to the queue. If memory was allocated during attach, this memory should be freed during detach processing. If a wait object was registered during attach, then it must be unregistered using dispUnregisterWaitObject during detach processing.

    The queue specific data passed back to the dispatcher by xxxAttachServiceManager (the queuecontext argument) will be passed into xxxDetachServiceManager so that the service manager can clean up these allocated and registered objects.


    chap713.gif
    tik service

    <<<< excerpt from tikbnd.c >>>>

    /*-------------------------------------------------------------------

    tikDetachServiceManager

    - Undeclare Wait object

    - Deallocate Resource object

    -----------------------------------------------------------------*/

    STATIC DWORD NMSAPI tikDetachServiceManager( CTAQUEUEHD ctaqueuehd,

    void *queuecontext)

    {

    TIK_DEVICE_OBJECT *ptikDevice = (TIK_DEVICE_OBJECT *)queuecontext;

    TSIIPC_WAIT_OBJ_HD waitobj;

    DWORD ret;

    /* Needed by CT Access provided error logging service */

    CTABEGIN("tikDetachServiceManager");

    /* Get IPC waitobject to un-register. */

    if ( tsiIPCGetWaitObject( ptikDevice->connector, &waitobj ) != SUCCESS )

    {

    tikDestroyDevice( ptikDevice );

    return CTALOGERROR( NULL_CTAHD, CTAERR_OS_INTERNAL_ERROR, TIK_SVCID);

    }

    /* Unregister waitobject with CT Access. */

    else if ( (ret=dispUnregisterWaitObject(

    ctaqueuehd, (CTA_WAITOBJ *)&waitobj)) != SUCCESS)

    {

    tikDestroyDevice( ptikDevice );

    return CTALOGERROR( NULL_CTAHD, ret, TIK_SVCID );

    }

    /* Teardown IPC connection. */

    else if ( (ret=tikTeardownIPC( ptikDevice )) != SUCCESS )

    {

    tikDestroyDevice( ptikDevice );

    return CTALOGERROR( NULL_CTAHD, ret, TIK_SVCID );

    }

    /* Destroy created service manager object. */

    else

    tikDestroyDevice( ptikDevice );

    return SUCCESS;

    } /* end tikDetachServiceManager() */

    7.8 Service ShutdownTop of Page

    Service shutdown occurs when ctaCloseServices is called. The xxxCloseService and xxxCloseServiceManager binding functions are called.

    7.8.1 xxxCloseServiceTop of Page

    The xxxCloseService binding function is invoked when a service is closed on a context. This function may shut down the managed resource.


    chap720.gif
    tik service

    <<<< excerpt from tikbnd.c >>>>

    /*-------------------------------------------------------------------

    tikCloseService

    - shut down the managed resource

    ------------------------------------------------------------------*/

    STATIC DWORD NMSAPI tikCloseService ( CTAHD ctahd,

    void *mgrcontext,

    char *svcname,

    unsigned svcid )

    {

    TIK_CHANNEL_OBJECT *ptikChannel = (TIK_CHANNEL_OBJECT*)mgrcontext;

    DWORD ret;

    /* Needed by CT Access provided error logging service */

    CTABEGIN("tikCloseService");

    ASSERT( svcid == TIK_SVCID );

    /* Perform graceful unwinding prior to service close. */

    if( (ret=tikHandleCloseService( ptikChannel )) != SUCCESS )

    {

    return CTALOGERROR( ctahd, ret, TIK_SVCID );

    }

    return SUCCESS;

    } /* end tikCloseService() */

    7.8.2 xxxCloseServiceManagerTop of Page

    Closing a service manager involves cleaning up all that was done when opening the service manager to the queue. If memory was allocated during the open, this memory should be freed during close processing. If a wait object was registered during open, then it must be unregistered using dispUnregisterWaitObject.


    chap719.gif
    tik service

    <<<< excerpt from tikbnd.c >>>>

    /*-------------------------------------------------------------------

    tikCloseServiceManager

    - Deallocate Service Manager specific data (a manager context)

    ------------------------------------------------------------------*/

    STATIC DWORD NMSAPI tikCloseServiceManager( CTAHD ctahd,

    void *mgrcontext )

    {

    TIK_CHANNEL_OBJECT *ptikChannel = (TIK_CHANNEL_OBJECT *)mgrcontext;

    tikDestroyChannel( ptikChannel );

    return SUCCESS;

    } /* end tikCloseServiceManager() */

    7.9 Runtime Binding FunctionsTop of Page

    The runtime binding functions include functions for:

    Except for xxxProcessCommand, all the runtime binding functions can return either SUCCESS or an error. xxxProcessCommand can return SUCCESS, SUCCESS_RESPONSE, or an error.

    The following table lists the runtime binding functions:

    Runtime Binding Functions

    xxxProcessCommand

    Description:

    Defines table of function pointers to API implementation functions.

    Performs lookup based on command code within the DISP_COMMAND message buffer.

    Performs upcall to appropriate function.

    Behavior:

    Synchronous

    Important Data Structure:

    Array of function pointers to implementation functions in ascending order by command code.

    Dispatcher Functions Called:

    None.

    Returns:

    SUCCESS, SUCCESS_RESPONSE, or an error.

    Access Through Natural Access API:

    Service API calls.

    Required?

    Must be implemented.

    xxxGetText

    Description:

    · Converts error codes, event codes, reason codes, and/or command codes to associated macro tag.

    · Uses ANSI C #param preprocessor directive.

    Behavior:

    Synchronous

    Important Data Structure:

    None

    Dispatcher Functions Called:

    None

    Returns:

    SUCCESS or an error.

    Access Through Natural Access API:

    ctaGetText

    Required?

    Must be implemented.

    xxxFormatMessage

    Description:

    · Generates ASCII message using information from xxxGetText.

    · Translates dispatcher commands and events to ASCII.

    Behavior:

    Synchronous

    Important Data Structure:

    DISP_MESSAGE

    Dispatcher Functions Called:

    None

    Returns:

    SUCCESS or an error.

    Access Through Natural Access API:

    ctaFormatEvent

    Required?

    Optional (but recommended).

    xxxSetTraceLevel

    Description:

    Sets tracemask value in mgrcontext to a new value.

    Behavior:

    Synchronous

    Important Data Structure:

    None

    Dispatcher Functions Called:

    None

    Returns:

    SUCCESS or an error.

    Access Through Natural Access API:

    ctaSetTraceLevel

    Required?

    Optional

    xxxFormatTraceBuffer

    Description:

    Converts binary trace messages to ASCII based on unique trace tags defined for service.

    Behavior:

    Synchronous

    Important Data Structure:

    None

    Dispatcher Functions Called:

    None

    Returns:

    SUCCESS or an error.

    Access Through Natural Access API:

    Not accessible through Natural Access API.

    Required?

    Optional

    xxxProcessEvent

    Description:

    · Handles events from other services by identifying and processing the event.

    · Optionally generates a new event and passes it to the application.

    Behavior:

    Synchronous

    Important Data Structure:

    DISP_EVENT

    Dispatcher Functions Called:

    dispMakeAndQueueEvent
    dispQueueEvent

    Returns:

    SUCCESS or an error.

    Access Through Natural Access API:

    Not accessible through Natural Access API.

    Required?

    Optional

    7.9.1 Command ProcessingTop of Page

    When the application invokes a service function, the API function calls the corresponding SPI function which marshals the arguments into a DISP_COMMAND message buffer and passes the message to the dispatcher via dispSendCommand. The dispatcher then invokes the binding function xxxProcessCommand which performs an upcall to the appropriate implementation function based on the command code stored within the DISP_COMMAND message buffer.


    chap711.gif

    Figure 30. Command Processing

    
    
    To write a xxxProcessCommand binding function, create an array of function pointers to implementation functions indexed by the sequence number portion of the command code.

    The mgrcontext that was allocated when the service manager was opened is passed in as an argument as well as a pointer to the DISP_COMMAND message buffer. These arguments should be passed to the implementation function where unmarshalling will occur.


    chap718.gif
    tik service

    <<<< excerpt from tikbnd.c >>>>

    /*-------------------------------------------------------------------

    tikProcessCommand

    - declare table of function pointers to implementation functions

    - perform lookup based on incoming ID

    - perform upcall to appropriate implementation function

    -----------------------------------------------------------------*/

    STATIC DWORD NMSAPI tikProcessCommand( CTAHD ctahd,

    void *mgrcontext,

    DISP_COMMAND *ctacmd )

    {

    typedef DWORD (*TIK_CMD_FCN) ( TIK_CHANNEL_OBJECT *, DISP_COMMAND *);

    static const TIK_CMD_FCN tikCmdFcnTbl[]=

    {

    /* 0x00 */ tikCmdStartTimer,

    /* 0x01 */ tikCmdStopTimer,

    /* 0x02 */ tikCmdGetContextInfo,

    };

    TIK_CHANNEL_OBJECT *ptikChannel = (TIK_CHANNEL_OBJECT *)mgrcontext;

    DWORD ret;

    /* Needed by CT Access provided error logging service */

    CTABEGIN("tikProcessCommand");

    /* Make sure command is defined, before invoking the appropriate cmd.

    */

    if ((ctacmd->id & 0xfff) < sizeof(tikCmdFcnTbl)/sizeof(tikCmdFcnTbl[0]))

    {

    ret = ((*tikCmdFcnTbl[ ctacmd->id & 0xfff ]) (ptikChannel, ctacmd));

    if ( ret != SUCCESS && ret != SUCCESS_RESPONSE )

    {

    return CTALOGERROR( ctahd, ret, TIK_SVCID );

    }

    }

    else

    {

    return CTALOGERROR( ctahd, CTAERR_NOT_IMPLEMENTED, TIK_SVCID );

    }

    return SUCCESS;

    } /* end tikProcessCommand() */

    7.9.2 Error HandlingTop of Page

    Two binding functions, xxxGetText and xxxFormatMessage, are used to convert binary codes and trace records to ASCII.

    xxxGetTextTop of Page

    The binding function xxxGetText provides a way for the service to translate any service-specific error, reason, event, or command codes into a character string representation. xxxGetText is invoked by the dispatcher when the application calls ctaGetText. It is also invoked internally via xxxFormatMessage and dispGetText.

    Errors, events, and commands should use the exact ASCII representation of the symbolic define used to define the code (e.g., use the string "ADIEVN_PLAY_DONE" for the ADIEVN_PLAY_DONE event). Reasons, which are only applicable in the value field of a DONE event, may be translated in any way that makes it more readable during formatting. For example, CTA_REASON_FINISHED is translated to "Finished."

    It is recommended that services create a macro that expands all the error, reason, event, and command codes so that only one file needs to be updated when a code is added or modified. The macros expand into multiple case statements.


    chap716.gif
    tik service

    <<<< excerpt from tikbnd.c >>>>

    /*-------------------------------------------------------------------

    tikGetText

    - convert error, event, reason, and/or command codes to associated

    ASCII macro identifier

    ------------------------------------------------------------------*/

    STATIC const char* NMSAPI tikGetText( unsigned code )

    {

    switch (code)

    {

    CTA_GENERIC_ERRORS(); /* see ctaerr.h */

    CTA_GENERIC_REASONS(); /* see ctaerr.h */

    TIK_ERRORS(); /* see tiksys.h */

    TIK_REASONS(); /* see tiksys.h */

    TIK_EVENTS(); /* see tiksys.h */

    TIK_COMMANDS(); /* see tiksys.h */

    default: return NULL ;

    }

    } /* end tikGetText() */


    chap717.gif
    tik service

    The macro for TIK errors are shown below. Additional macros exist for reasons, events, and commands.

    <<<< excerpt from tiksys.c >>>>

    /*-------------------------------------------------------------------

    tikGetText() Macros.

    - These macros convert TIK Service command, event, error, and reason

    codes to their corresponding ASCII macro identifier.

    -----------------------------------------------------------------*/

    #define TEXTCASE(e) case e: return #e

    #define TIK_ERRORS() \

    TEXTCASE(TIKERR_COMM_FAILURE); \

    TEXTCASE(TIKERR_CHANNEL_NOT_OPENED); \

    TEXTCASE(TIKERR_OWNER_CONFLICT); \

    TEXTCASE(TIKERR_UNKNOWN_SERVER_RESPONSE); \

    TEXTCASE(TIKERR_CAN_NOT_CONNECT); \

    xxxFormatMessageTop of Page

    The binding function xxxFormatMessage formats commands and events that are specific to the service. The binding function is invoked by the dispatcher when the application calls ctaFormatEvent.

    xxxFormatMessage is passed a command or event, a buffer, buffer size, and an indent character. xxxFormatMessage converts the command or event to ASCII and places the ASCII string into the supplied buffer. The indent character is prepended to each line of the ASCII string.

    The binding function formats the command or event appropriately.


    chap721.gif
    tik service

    <<<< excerpt from tikbnd.c >>>>

    /*-------------------------------------------------------------------

    tikFormatMessage

    - translate commands and events to ASCII

    - use tikGetText to help in the translation

    ------------------------------------------------------------------*/

    STATIC DWORD NMSAPI tikFormatMessage( DISP_MESSAGE *pmsg,

    char *s,

    unsigned size,

    char *indent)

    {

    char *text;

    char tmp[1024] = "";

    DWORD cnt;

    /* Needed by CT Access provided error logging service */

    CTABEGIN ("tikFormatMessage");

    ASSERT ( s != NULL && size != 0 );

    /* Switch statement returns pointer to static text. */

    text = (char*)tikGetText(pmsg->id);

    if (CTA_IS_EVENT(pmsg->id))

    {

    if( text == NULL )

    {

    sprintf( tmp, "%sUnknown TIK Event: *** (%08X)",

    indent, pmsg->id );

    }

    else

    {

    DISP_EVENT *evt = (DISP_EVENT *)pmsg;

    char *reason = (char *)tikGetText(evt->value);

    sprintf( tmp, "%sEvent: %s *** (%08X) Reason: %s *** (%08X)\n",

    indent, text, pmsg->id, reason, evt->value );

    }

    }

    else /* command */

    {

    if( text == NULL )

    {

    sprintf( tmp, "%sUnknown TIK Command: *** (%08X)\n",

    indent, pmsg->id );

    }

    else

    {

    DISP_COMMAND *cmd = (DISP_COMMAND *)pmsg;

    sprintf( tmp, "%sCommand: %s *** (%08X) ",

    indent, text, pmsg->id );

    switch ( pmsg->id )

    {

    case TIKCMD_START:

    {

    TIK_START_PARMS start;

    DWORD ret;

    char buffer[128];

    /* Get user specified start pararmeters. */

    if ( cmd->size1 == 0 && cmd->dataptr1 == NULL )

    {

    /* Command is using system default start parameter.

    * Get system default start parameter.

    */

    strcat( tmp, "(System defaults) " );

    ret = dispGetParms( pmsg->ctahd, TIK_START_PARMID,

    &start, sizeof(TIK_START_PARMS) );

    if ( ret != SUCCESS )

    {

    return ret;

    }

    }

    else

    {

    /* Get application specified start parameters. */

    start = *(TIK_START_PARMS *)(cmd->dataptr1);

    }

    sprintf(buffer, "NumTicks = %d, Frequency = %d.\n",

    start.NumTicks, start.Frequency );

    strcpy( tmp, buffer );

    break;

    }

    case TIKCMD_STOP:

    case TIKCMD_GET_CONTEXT_INFO:

    default:

    {

    strcat( tmp, "\n" );

    break;

    }

    } /* end switch */

    } /* end if text != NULL */

    } /* end command processing */

    cnt = ( (strlen( tmp )+1) > (size)) ? (size) : (strlen( tmp ) + 1);

    strncpy( s, tmp, cnt );

    s[cnt-1] = '\0';

    return SUCCESS;

    } /* end tikFormatMessage() */

    7.9.3 Trace HandlingTop of Page

    In the service manager binding functions, support for trace handling involves:

    Setting Local TraceMaskTop of Page

    A local tracemask is set by an application via a call to ctaSetTraceLevel. As part of the call to ctaSetTraceLevel, an application specifies:

    The dispatcher invokes xxxSetTraceLevel for the service based upon the service name and context handle. The implementation of xxxSetTraceLevel simply sets the tracemask associated with the context handle to the passed in value.


    chap712.gif
    tik service

    excerpt from <<<< tikbnd.c >>>>

    /*-------------------------------------------------------------------

    tikSetTraceLevel - update local tracemask

    ------------------------------------------------------------------*/

    STATIC DWORD NMSAPI tikSetTraceLevel( CTAHD ctahd,

    void *mgrcontext, unsigned svcid, unsigned tracemask )

    {

    TIK_CHANNEL_OBJECT *ptikChannel = (TIK_CHANNEL_OBJECT *)NULL;

    /* Needed by CT Access provided error logging service */

    CTABEGIN("tikSetTraceLevel");

    ASSERT( svcid == TIK_SVCID );

    /* Set service context specific tracemask. */

    ptikChannel->tracemask = tracemask;

    return SUCCESS;

    } /* end tikSetTraceMask() */

    Converting Trace Records to ASCIITop of Page

    Each trace record logged by the dispatcher or by a Natural Access service is logged in binary format. In order for the ctdaemon to print out a human readable string corresponding to a trace record, xxxFormatTraceBuffer is called to convert the binary trace record to an ASCII equivalent. This binding function is called via the ctdaemon for display purposes. It is not called in a Natural Access application.

    xxxFormatTraceBuffer uses the trace tags to determine which trace record to generate. See Section 4.8.2, Defining Trace Tags for information about defining trace tags.


    chap722.gif
    tik service

    <<<< excerpt from tikbnd.c >>>>

    /*-------------------------------------------------------------------

    tikFormatTraceBuffer

    - convert binary trace messages to ASCII

    - note that only TIK specific trace buffers will be converted!

    ------------------------------------------------------------------*/

    STATIC DWORD NMSAPI tikFormatTraceBuffer( unsigned tracetag,

    void *inbuffer,

    unsigned insize,

    char *outbuffer,

    unsigned outsize )

    {

    DWORD ret = SUCCESS;

    DWORD size;

    char tmp[512] = "";

    /* Needed by CT Access provided error logging service */

    CTABEGIN("tikFormatTraceBuffer");

    switch (tracetag)

    {

    case TIK_TRACETAG_CMD:

    {

    TIK_CMD_COM_OBJ *cmd = (TIK_CMD_COM_OBJ *)inbuffer ;

    ASSERT( insize >= sizeof(TIK_CMD_COM_OBJ) );

    sprintf( tmp,

    "TIK Service ClientID(0x%08x) Command:(%s) Data1=(%d) "

    "Data2=(%d) Data3=(%d) TimeStamp=(0x%08X).\n", cmd->client_id,

    tikTranslateCmdRsp(cmd->command), cmd->data1, cmd->data2,

    cmd->data3, cmd->timestamp );

    break;

    case TIK_TRACETAG_RSP:

    {

    TIK_RSP_COM_OBJ *rsp = (TIK_RSP_COM_OBJ *)inbuffer ;

    ASSERT(insize >= sizeof(TIK_RSP_COM_OBJ));

    sprintf( tmp,

    "TIK Service ClientID(0x%08X) Response:(%s) Reason=(%s) "

    "Channel=(%d) TikSeq=(%d) SvrMsg=(%s)"

    " TimeStamp=(%x).\n", rsp->client_id,

    tikTranslateCmdRsp( rsp->response ),

    tikTranslateCmdRsp( rsp->reason ), rsp->channel, rsp->seq,

    rsp->msg, rsp->timestamp );

    break;

    }

    case TIK_TRACETAG_BIT0:

    {

    STATE_TRAN_CTCX *statectcx = (STATE_TRAN_CTCX *)inbuffer;

    ASSERT( statectcx->size >= sizeof(STATE_TRAN_CTCX) );

    sprintf( tmp,

    "TIK Service ClientID(0x%08X) PrevState:(%s) CurrentState(%s) "

    "Agent(%s).\n", statectcx->ptikChannel, statectcx->prev_state,

    statectcx->curr_state, statectcx->agent );

    break;

    }

    default:

    {

    ret = CTAERR_NOT_IMPLEMENTED;

    break;

    }

    } /* end switch */

    size = (strlen( tmp ) + 1);

    if ( outsize < size )

    {

    strncpy(outbuffer, tmp, (outsize));

    outbuffer[outsize - 1] = '\0';

    }

    else

    {

    strcpy( outbuffer, tmp );

    }

    return ret;

    } /* end tikFormatTraceBuffer() */

    7.9.4 Event ProcessingTop of Page

    The xxxProcessEvent binding function processes events from other services, not events from the managed resource. (Managed resource events are handled via xxxFetchAndProcess.) Events are processed by:

    xxxProcessEvent is executed when dispQueueEvent is called by another service.

    7.10 Additional Binding FunctionsTop of Page

    The following functions are placeholder binding functions for future Natural Access enhancements:

    Function

    Description

    xxxAddRTC

    Initializes run time control.

    xxxRemoveRTC

    Shuts down runtime control.

    xxxGetFunctionPtr

    Gets a pointer to a new binding function.

    The entries for these functions in the CTASVCMGR_FNS data structure should be set to NULL.



    Table of Contents NMS Glossary Previous Page Next Page Version


    Want to send us feedback on our documentation? Email: Tech_Pubs@nmss.com
    Copyright © 2001, Natural MicroSystems, Inc. All rights reserved.