Starting services

Service startup occurs when the application calls ctaOpenServices. Two binding functions are called during service startup:

Service startup

xxxOpenServiceManager

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

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 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_CHANNEL_INFO  ChannelInfo; /* Channel-specific information   */
} TIK_CHANNEL_OBJECT;

  1. If the managed resource is not a multiplexed managed resource, xxxOpenServiceManager must also allocate a wait object and register it with the dispatcher using dispRegisterWaitObject. This wait object fires 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

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.

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 Natural 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 context
  * (ctahd); a Channel Object is just that.
  */
  else
    *mgrcontext = (void *)ptikChannel;

  return SUCCESS;
} /* end tikOpenServiceManager() */

xxxOpenService

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 by an event that the initialization completed. If the service manages a device, 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 completed its initialization and is ready to process commands. xxxOpenService calls dispMakeAndQueueEvent when is 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 is processed into the Natural Access event that gets passed up to the application.

Note: Even services that do not require asynchronous open service processing must queue the CTAEVN_DISP_OPEN_SERVICE_DONE completion event using dispMakeAndQueueEvent or dispQueueEvent. (dispMakeAndQueueEvent is a wrapper function for dispQueueEvent.)

If your service will use the Natural Access runtime control features (described in the Natural Access runtime control section), invoke dispAddRTC, dispRegisterRTCAlias, or both functions during the execution of xxxOpenService.

tik service

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

/*------------------------------------------------------------
 tikOpenService
 - Initialize any dedicated resources (typically on a per-
   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 Natural 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 );
    }
  }

  p
tikChannel->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;

  i
f( (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() */

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

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;
  }
  /* etc ... */
  /* Process incoming message from tik server.*/
  switch ( rsp->response )
  {
    case TIKSVR_OPEN_CHANNEL_RSP:
    {
       ret = tikProcessOpenChannelResponse( ptikChannel );
       break;
    }
    /* etc ... */
  }
  /* etc ... */
}
 
DWORD tikProcessOpenChannelResponse(TIK_CHANNEL_OBJECT *ptikChannel )
{
  TIK_RSP_COM_OBJ *rsp = &(ptikChannel->ptikDevice->response);
  DWORD reason;
  DWORD ret;
 
  /* etc ... */
 
  /* Translate reason code from incoming message to
  * associated Natural Access reason.
  */
  switch ( rsp->reason )
  {
    case TIKSVR_CHANNEL_OPENED:
    {
       ptikChannel->state = CHANNEL_TIMER_IDLE;
       reason = CTA_REASON_FINISHED;
       break;
    }
    /* etc ... */
  }
  /* etc ... */
 
  /* 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() */