This function registers a function to be called when the current thread enters a particular state.
void cciRegisterForThreadStateChange(
int *returnCode,
CciThreadContext *threadContext,
CciDataContext *userContext,
CciRegCallback callback,
CciCallbackType type);
The input node for the current thread is actively polling for data from the input source, but no data is available. Messages are not propagated through the message flow until data becomes available for the input node.
The input node for the current thread has stopped polling for data and the thread has been released. The thread is dispatched again either by the same input node or by another input node in the same message flow. This state is entered when additional instances, which have been deployed for a message flow, have been configured to cope with an influx of input data that has now ceased. The input node continues to poll for input data on a single thread, and the other threads are released.
The current thread is ending. This action can happen when the broker is shut down, the integration server process is ending in a controlled manner, or when the message flow is being deleted. This state can occur after all nodes and parsers in the flow are deleted.
Alternatively, the type parameter can be the result of a bit-wise OR operation on two or more of these values. In this case, the specified function is called when the thread enters the relevant state for each individual type value.
None. If an error occurs, the returnCode parameter indicates the reason for the error.
Declaring the struct and function:
typedef struct {
int id;
}MyContext;
static int registered=0;
CciRegCallbackStatus switchThreadStateChange(
CciDataContext *context, CciCallbackType type)
{
char traceText[256];
char* typeStr=0;
MyContext* myContext = (MyContext*)context;
if (type==CCI_THREAD_STATE_IDLE){
typeStr = "idle";
}else if(type==CCI_THREAD_STATE_INSTANCE_END){
typeStr = "instance end";
}else if (type==CCI_THREAD_STATE_TERMINATION){
typeStr = "termination";
}else{
typeStr = "unknown";
}
memset(traceText,0,256);
sprintf(traceText,"switchThreadStateChange: context id = %d, thread state %s",myContext->id,typeStr);
cciServiceTrace(NULL,
NULL,
traceText);
return CCI_THREAD_STATE_REGISTRATION_RETAIN;
}
Place the following code into the _Switch_evaluate function in the samples to enable you to read service trace, and to see when the message processing thread changes state:
/*register for thread state change*/
CciMessageContext* messageContext = cniGetMessageContext(NULL,message);
CciThreadContext* threadContext = cniGetThreadContext(NULL,messageContext);
static MyContext myContext={1};
if(registered==0){
cciRegisterForThreadStateChange(
NULL,
threadContext,
& myContext,
switchThreadStateChange,
CCI_THREAD_STATE_IDLE |
CCI_THREAD_STATE_INSTANCE_END |
CCI_THREAD_STATE_TERMINATION);
registered=1;
}
This example registers only on the first thread that receives a message. If it is necessary to register every thread that receives a message, the user-defined extensions must remember on which threads they have registered.
By using the userContext parameter, you can see how data is passed from the code where the callback is registered to the actual callback function.
When registering the callback, a pointer to an instance of the MyContext struct is passed in. This pointer is the same pointer as is passed back to the callback. To ensure that the pointer is still valid when it is passed back to the callback, an instance of the struct is declared as static. Another technique to ensure that the pointer is valid is to allocate storage on the heap.
In the callback function, the userContext parameter can be cast to a (MyContext*). The original MyContext struct can be referenced through this address. This technique permits the passing of data from the code where the callback is registered to the callback function.