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 tables list the runtime binding functions:
|
Description: |
|
|
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: |
Service API calls. |
|
Required? |
Must be implemented. |
|
Description: |
|
|
Behavior: |
Synchronous |
|
Important data structure: |
None |
|
Dispatcher functions called: |
None |
|
Returns: |
SUCCESS or an error. |
|
Access Through Natural Access: |
ctaGetText |
|
Required? |
Must be implemented. |
|
Description: |
|
|
Behavior: |
Synchronous |
|
Important data structure: |
DISP_MESSAGE |
|
Dispatcher functions called: |
None |
|
Returns: |
SUCCESS or an error. |
|
Access Through Natural Access: |
ctaFormatEvent |
|
Required? |
Optional (but recommended). |
|
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: |
ctaSetTraceLevel |
|
Required? |
Optional |
|
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: |
Not accessible through Natural Access functions. |
|
Required? |
Optional |
|
Description: |
|
|
Behavior: |
Synchronous |
|
Important data structure: |
DISP_EVENT |
|
Dispatcher functions called: |
|
|
Returns: |
SUCCESS or an error. |
|
Access Through Natural Access: |
Not accessible through Natural Access functions. |
|
Required? |
Optional |
When the application invokes a service function, the function calls the corresponding SPI function, which marshals the arguments into a DISP_COMMAND message buffer and passes the message to the dispatcher using 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.
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 are passed to the implementation function where unmarshalling occurs.
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 Natural 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() */
Use the binding functions xxxGetText and xxxFormatMessage to convert binary codes and trace records to ASCII.
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 by xxxFormatMessage and dispGetText.
Errors, events, and commands should use the exact ASCII representation of the symbolic define used to define the code (for example, 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, can 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.
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() */
The macros for tik errors are shown. 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); \
The binding function xxxFormatMessage formats commands and events that are specific to the service. The dispatcher invokes the binding function 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.
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 Natural 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 parameters. */
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() */
In the service manager binding functions, support for trace handling involves:
Setting the local tracemask
Converting trace records to ASCII
An application sets the local tracemask with a call to ctaSetTraceLevel. As part of the call to ctaSetTraceLevel, an application specifies:
The context handle
The service name of the specific service whose local tracemask is to be set
The tracemask value itself (for example, CTA_TRACEMASK_DRIVER_CMDS)
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.
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 Natural Access provided error logging service */
CTABEGIN("tikSetTraceLevel");
ASSERT( svcid == TIK_SVCID );
/* Set service context specific tracemask. */
ptikChannel->tracemask = tracemask;
return SUCCESS;
} /* end tikSetTraceMask() */
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 with 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 Defining trace tags for information about defining trace tags.
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 Natural 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() */
The xxxProcessEvent binding function processes events from other services, not events from the managed resource. (Managed resource events are handled with xxxFetchAndProcess.) Events are processed by:
Identifying the event
Processing the event
Generating a new event to send to client application
xxxProcessEvent is executed when dispQueueEvent is called by another service.