# Initializing managed resource event handling

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 Starting services).

Event handling initialization

Communicate with the managed resource during the xxxOpenServiceManager invocation only if it is possible to guarantee that the resource will be available at this time. Otherwise the application is prevented from creating a queue. If you cannot guarantee that the resource will be available, defer communication with the managed resource until when the service is being opened.

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 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 the following illustration).

Note: Do not communicate with the managed resource when xxxAttachServiceManager is invoked until you are sure that the resource is available. Otherwise, the application cannot create a queue. If you cannot guarantee that the resource is available, defer communication with the resource until the service is opened.

Device specific data objects

tik service

Since the tik 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 */
}

2. A single wait object is allocated and registered with the dispatcher (within the newly created Natural Access event queue) with dispRegisterWaitObject. This wait object fires whenever a 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 | Manual reset event object
UNIX | pollfd structure

tik service

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

/*-------------------------------------------------------------
tikAttachServiceManager
- Declare Wait object
- Allocate "Device" object which represents the "tick device"
- Register the wait object with Natural 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 Natural 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 Windows: 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 Natural Access. */
else if ( tsiIPCGetWaitObject(ptikDevice->readhd, &waitobj)!= SUCCESS )
{
tikDestroyDeviceObject( ptikDevice );
return CTALOGERROR( NULL_CTAHD, CTAERR_OS_INTERNAL_ERROR, TIK_SVCID );
}
/* Register created waitobject with Natural Access. */
else if ( (ret=dispRegisterWaitObject( ctaqueuehd,
(CTA_WAITOBJ *)waitobj,
tikFetchAndProcess,
(void *)ptikDevice )) != SUCCESS )
{
tikDestroyDeviceObject( ptikDevice );
return CTALOGERROR( NULL_CTAHD, ret, TIK_SVCID );
}
/* The following 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 Natural 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() */