Table of Contents NMS Glossary Previous Page Next Page Version


Chapter 8

Service Implementation


8.1 Introduction
8.2 Implementing Service Functions
8.2.1 Arguments to Service Implementation Functions
8.2.2 Handling Service Parameters as Function Arguments
8.3 Processing Events from the Managed Resource
8.4 Generating Trace Records

8.1 IntroductionTop of Page

The service implementation should provide (but is not limited to) the following functions:

The following files should be created when implementing the service:

File

Description

xxxcmd.c

File implementing the service functions that interface to the managed resource.

xxxsys.h

Header file containing internal data structures, function prototypes, and definitions.

Additional files can be created as required by the service. For example, the sample TIK service contains tikutils.c and tikcomms.c.

8.2 Implementing Service FunctionsTop of Page

For each service API call there must be an associated service implementation function. When the service manager function xxxProcessCommand receives the command from the dispatcher, it determines the associated service implementation function to call.


chap80.gif

Figure 31. Service Command


The service implementation functions perform whatever processing needs to be done. The service can call dispatcher functions and binding functions if necessary. Typical dispatcher functions invoked are:

If a service needs to invoke the functionality of another service, it does so via the service's SPI functions.

8.2.1 Arguments to Service Implementation FunctionsTop of Page

The service implementation function receives the DISP_COMMAND message buffer. It unmarshals the function arguments and performs the processing required for the command.

Once the processing is complete, values for any out or inout arguments must be marshalled back into the DISP_COMMAND message buffer and the proper return code set.

If there are no out or inout arguments and successful completion occurred, return SUCCESS. If there are out or inout arguments and successful completion occurred, return SUCCESS_RESPONSE. If there is an error, return the appropriate error code.

Note: A return code of SUCCESS_RESPONSE will be converted to SUCCESS by dispSendCommand.

8.2.2 Handling Service Parameters as Function ArgumentsTop of Page

Applications use ctaGetParms to retrieve default parameter structures to pass to API functions. Applications may modify the defaults retrieved and pass the new structure to the API or they may pass NULL to tell the service that it should use the context defaults.

If a service implementation function is passed a NULL value for the parameter value, call dispGetParms to retrieve the context default values. If a service needs to call another service via its SPI, it may use any parameter passed to it from its SPI/API to determine how to call the next service's SPI. It may also require a call to dispGetParms to retrieve the defaults and modify the values before calling the SPI, or it may elect to pass a NULL pointer so that the next service will retrieve its own default parameters.

Note: When retrieving and directly modifying parameter structure values to be passed to another service's SPI, the modification is only valid for the current SPI call. To modify parameter defaults permanently, call dispSetParmByName.

Default values are only set the first time that a service is defined for an entire system. If two services with the same service interface, but different service implementations, are registered with the dispatcher, only the defaults of the first service to be registered are used.

Services with the same service ID must have the same standard parameter descriptors. They must define the same structures including the fields, formats and units. The dispatcher will verify that matching services register the same standard parameters. An error returns if this is not the case.


chap81.gif
tik service

<<<< excerpt from tikcmd.c >>>>

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

tikCmdStartTimer

- Implementation function for tikStartTimer

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

DWORD tikCmdStartTimer( TIK_CHANNEL_OBJECT *ptikChannel, DISP_COMMAND* m )

{

TIK_CMD_COM_OBJ cmd = { 0 };

TIK_START_PARMS start;

DWORD ret = SUCCESS;

if ( ptikChannel == NULL || m == NULL )

{

return CTAERR_BAD_ARGUMENT;

}

/* Check channel owner. */

if ( ptikChannel->owner != CTA_NULL_SVCID &&

ptikChannel->owner != m->addr.source )

{

return TIKERR_OWNER_CONFLICT;

}

/* channel state must be either IDLE or STARTED. */

if ( !(ptikChannel->state == CHANNEL_TIMER_IDLE ||

ptikChannel->state == CHANNEL_TIMER_STARTED) )

{

return CTAERR_INVALID_SEQUENCE;

}

/* Check if this function call included explicit TIK_START_PARMS

* structure.

* - If present, use passed in structure

* - If not present (i.e., NULL passed), get the default

* TIK_START_PARMS structure via dispGetParms and use it.

*/

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

{

if( (ret=

dispGetParms( ptikChannel->ctahd,

TIK_START_PARMID,

&start,

sizeof(TIK_START_PARMS) )) != SUCCESS )

{

return ret;

}

}

else

{

DWORD size = ( m->size1 < sizeof(TIK_START_PARMS) )

? m->size1

: sizeof(TIK_START_PARMS);

memcpy( &start, m->dataptr1, size );

}

/* Prepare command (message buffer) to send to TICK server. */

cmd.size = sizeof( TIK_CMD_COM_OBJ );

cmd.timestamp = time(NULL);

cmd.client_id = ptikChannel->channelId;

cmd.command = TIKSVR_START;

cmd.data1 = ptikChannel->channelId;

cmd.data2 = start.Frequency;

cmd.data3 = start.NumTicks;

/* Update channel_info structure. */

ptikChannel->ChannelInfo.requested += cmd.data3;

/* If CTA_TRACEMASK_DEBUG_BIT0 is enabled,

* log state transition information.

*/

if ( TRACEMASK_BIT0_SET(ptikChannel->tracemask) )

{

ret = tikLogStateTransition( ptikChannel,

ptikChannel->state,

CHANNEL_TIMER_STARTED,

"tikCmdStartTimer" );

}

/* Set channel state to STARTED. */

ptikChannel->state = CHANNEL_TIMER_STARTED;

/* Set channel owner. Also used as reply address. */

if ( ptikChannel->owner == CTA_NULL_SVCID )

{

ptikChannel->owner = m->addr.source;

}

if( (ret=

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

{

return ret;

}

/* Expecting ticks, queue an asynchronous read request. */

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

{

return ret;

}

ptikChannel->ChannelInfo.calls++;

return SUCCESS;

} /* end tikCmdStartTimer() */

8.3 Processing Events from the Managed ResourceTop of Page

By convention, xxxFetchAndProcess is the name for the managed resource event handler in a service implementation. This function is a callback function that is invoked via the dispatcher when the associated wait object fires.

The event handling initialization takes place in either xxxAttachServiceManager (for multiplexed managed resources) or xxxOpenServiceManager (non-multiplexed managed resources). During initialization, an operating system specific wait object is registered along with a pointer to xxxFetchAndProcess and a pointer to a data structure that can be used to identify and process the incoming event. xxxFetchAndProcess is where an incoming raw event from the managed resource may be consumed or forwarded (either to another Natural Access service or to a Natural Access application). Section 4.2, Understanding the Managed Resource discusses how best to determine which events should be consumed and which should be forwarded (or translated and forwarded).

As part of identifying the event, xxxFetchAndProcess must first use the wait object to retrieve the actual raw event. It must then analyze the contents of the event and perform the appropriate processing.


chap83.gif
tik service

Note that tikFetchAndProcess gets the raw event, and checks it to determine event type. It then calls the correct helper function to process that event. Note that since the TICK Server is a multiplexed managed resource, it demultiplexes the event by using the client id value embedded in the event.

<<<< excerpt from tikutils.c >>>>

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

Event Processing from TICK Server

- Callbak invoked when a corresponding registered wait object is

signalled.

ctaqueuehd: Queue on which event are to be queued.

waitobj: Pointer to wait object that was signalled.

arg: Pointer to DEVICE object (which was registered by

tikAttachServiceManager as a "queuecontext").

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

DWORD NMSAPI tikFetchAndProcess( CTAQUEUEHD ctaqueuehd,

CTA_WAITOBJ *waitobj,

void *arg )

{

TIK_DEVICE_OBJECT *ptikDevice = (TIK_DEVICE_OBJECT *) arg;

TIK_CHANNEL_OBJECT *ptikChannel = NULL;

TIK_RSP_COM_OBJ *rsp = &ptikDevice->response;

TSIIPC_COMMAND_STATUS status = { 0 };

DWORD ret = SUCCESS;

/* Complete IPC read. */

if ( tikCompleteReadServerResponse( ptikDevice )

!= SUCCESS )

{

return ret;

}

/* Get Channel object pointer by indexing into the channelTbl array

* using the client_id field.

*/

if( rsp->client_id < 0 || rsp->client_id > 9 ||

(ptikChannel=ptikDevice->channelTbl[rsp->client_id]) == NULL )

{

return TIKERR_UNKNOWN_SERVER_RESPONSE;

}

/* Log trace for server response if requested. */

if ( *tikTracePointer & CTA_TRACEMASK_DRIVER_EVENTS )

{

if( (ret=dispLogTrace( ptikChannel->ctahd,

TIK_SVCID,

CTA_TRACE_SEVERITY_INFO,

TIK_TRACETAG_RSP,

(void *)(rsp),

sizeof(TIK_RSP_COM_OBJ) )) != SUCCESS )

{

return( ret );

}

}

/* Process incoming message from TICK Server.*/

switch ( rsp->response )

{

case TIKSVR_OPEN_CHANNEL_RSP:

{

ret = tikProcessOpenChannelResponse( ptikChannel );

break;

}

case TIKSVR_STOP_TIMER_RSP:

{

ret = tikProcessStopTimerResponse( ptikChannel );

break;

}

case TIKSVR_TICK_RSP:

{

ret = tikProcessTickResponse( ptikChannel );

break;

}

default:

{

/* Unknown server response. */

ASSERT(FALSE);

break;

}

}

return ret;

} /* end tikFetchAndProcess() */

If it is required that you must forward (or translate and forward) the raw event to another Natural Access Service or to the Natural Access application, use either dispMakeAndQueueEvent or dispQueueEvent.


chap84.gif
tik service

Tthis is just one of the event processing functions called by tikFetchAndProcess. For convenience, we have chosen to use dispMakeAndQueueEvent.

<<<< excerpt from tikutils.c >>>>

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

DWORD tikProcessOpenChannelResponse( TIK_CHANNEL_OBJECT *ptikChannel )

{

TIK_RSP_COM_OBJ *rsp = &(ptikChannel->ptikDevice->response);

DWORD prev_state = ptikChannel->state;

DWORD reason;

DWORD ret;

ptikChannel->ChannelInfo.calls = 0;

ptikChannel->ChannelInfo.ticked = 0;

ptikChannel->ChannelInfo.requested = 0;

ptikChannel->ChannelInfo.remaining = 0;

ptikChannel->ChannelInfo.ms = 0;

strcpy( ptikChannel->ChannelInfo.tick_string, "" );

/* Translate reason code from incoming message to

* associated CT Access reason.

*/

switch ( rsp->reason )

{

case TIKSVR_CHANNEL_OPENED:

{

ptikChannel->state = CHANNEL_TIMER_IDLE;

reason = CTA_REASON_FINISHED;

break;

}

case TIKSVR_CHANNEL_ACTIVE:

{

ptikChannel->state = CHANNEL_NOT_ALIVE;

reason = TIK_REASON_CHANNEL_ACTIVE;

break;

}

case TIKSVR_CHANNEL_INVALID:

{

ptikChannel->state = CHANNEL_NOT_ALIVE;

reason = TIK_REASON_INVALID_CHANNEL;

break;

}

default:

{

ptikChannel->state = CHANNEL_NOT_ALIVE;

reason = TIK_REASON_UNKNOWN_SERVER_REASON;

break;

}

}

/* If CTA_TRACEMASK_DEBUG_BIT0 is enabled,

* log state transition information.

*/

if ( TRACEMASK_BIT0_SET(ptikChannel->tracemask) )

{

char txt[128] = "TIKSVR_OPEN_CHANNEL_RSP : ";

char *reasontxt = tikTranslateCmdRsp( rsp->reason );

strcat( txt, reasontxt );

if ( (ret=tikLogStateTransition( ptikChannel,

prev_state,

ptikChannel->state,

txt )) != SUCCESS )

{

return ret;

}

}

/* Create and enqueue open service DONE event. */

ret = dispMakeAndQueueEvent( ptikChannel->ctahd,

CTAEVN_DISP_OPEN_SERVICE_DONE,

reason,

TIK_SVCID,

CTA_SYS_SVCID);

return( ret );

} /* end tikProcessOpenChannelResponse() */

8.4 Generating Trace RecordsTop of Page

In the service implementation functions, the local and global tracemasks are checked to see what trace record categories are active. For active trace record categories, a trace record is generated and logged by invoking dispLogTrace with the following arguments:

  • The tracetag.

    
    
  • A buffer containing trace data. The trace data can be anything that is useful to be presented to a developer during a debug session. The trace data can be in binary or ASCII - there are no restrictions. It is up to the xxxFormatTraceBuffer function to convert this portion of the trace record to human readable (ASCII) format.

    
    
  • The size of the buffer.

    
    
    To determine whether or not to invoke dispLogTrace, check both the global and local tracemasks to see if the appropriate category is set. If so, invoke dispLogTrace.


    chap82.gif
    tik service

    One of the things being traced is the set of commands being sent from the TIK service to the TICK server (when the tracemask has the CTA_TRACEMASK_DRIVER_COMMANDS category set).

    <<<< exceprt from tikcomms .c >>>>

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

    Utility function to send a command via IPC synchronously.

    A CT Access error code is returned to indicate success status.

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

    DWORD tikSendClientCommand( TIK_CHANNEL_OBJECT *ptikChannel,

    TIK_CMD_COM_OBJ *cmd )

    {

    int cnt;

    DWORD ret;

    TSIIPC_COMMAND_STATUS status = {0};

    if ( cmd == NULL || ptikChannel == NULL )

    {

    return CTAERR_BAD_ARGUMENT;

    }

    /* Log trace if requested. Both the global tracemask must be checked as

    * as well as the local, per mgrcontext, tracemask.*/

    if ( *tikTracePointer & CTA_TRACEMASK_DRIVER_COMMANDS ||

    ptikChannel->tracemask & CTA_TRACEMASK_DRIVER_COMMANDS )

    {

    if( (ret=dispLogTrace( ptikChannel->ctahd,

    TIK_SVCID,

    CTA_TRACE_SEVERITY_INFO,

    TIK_TRACETAG_CMD,

    (void *)cmd,

    sizeof(TIK_CMD_COM_OBJ) )) != SUCCESS )

    {

    return ret;

    }

    }

    ...

    }



  • 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.