Note: The following examples document a skeleton subscriber. An example is in the Protosubscriber folder in the Streaming folder.
Initializing a subscriber
Typically a subscriber allocates any global resources it needs, such as subscriber context blocks, during initialization.
The example below shows the initialization procedure from Protosubscriber.c.
Example 1: Initializing a subscriber.
Each subscriber requires different initialization actions. If you create a new subscriber, you should, however, use the initialization paradigm in Example 2 so that other developers familiar with the standard subscribers will find it easier to use it.
/***********************************************************************************
* Routine to initialize the subscriber. Creates the a memory pool for allocating
* subscriber contexts. A context is allocated and a new thread started with
* calls to NewProtoSubscriber().
***********************************************************************************/
long InitProtoSubscriber( void )
{
ADD_PROTO_TRACE_L1( ProtoTraceBufPtr, kTraceInitSubscriber, 0, 0, 0 );
/* Create the memory pool for allocating subscriber
* contexts.
*/
ProtoGlobals.contextPool = CreateMemPool( PR_SUBS_MAX_SUBSCRIPTIONS,
sizeof(ProtoContext) );
if ( ProtoGlobals.contextPool == NULL )
return kDSNoMemErr;
/* Return success */
return kDSNoErr;
}
int32 InitTestSubscriber( void );
In addition to the initialization routine, you also need to provide a routine to deallocate things allocated by one-time initialization in the InitProtoSubscriber()
routine. In the Protosubscriber example application, this is done by the function CloseProtoSubscriber()
.
Creating the subscriber thread
How a new subscriber is created depends on the subscriber. In general, the program has to perform the following actions (see Example 2):
/**********************************************************************************
* Routine to instantiate a new subscriber. Creates the subscriber thread and passes
* the new context (allocated from the global pool) to it. Creates the message port
* through which all subsequent communications between the subscriber and the
* streamer take place, as well as any other necessary per-context resources.
***********************************************************************************/
long NewProtoSubscriber( ProtoContextPtr *pCtx, DSStreamCBPtr streamCBPtr,
long deltaPriority )
{
long status;
ProtoContextPtr ctx;
ulong signalBits;
ADD_PROTO_TRACE_L1( ProtoTraceBufPtr, kTraceNewSubscriber, 0, 0, 0 );
/* Allocate a subscriber context */
ctx = (ProtoContextPtr) AllocPoolMem( ProtoGlobals.contextPool );
if ( ctx == NULL )
return kDSNoMemErr;
/* Allocate a signal to synchronize with the completion of the subscriber's
* initialization. It will signal us with this when it has finished,
* successfully or not, when it is done initializing itself./ */
ctx->creatorTask = CURRENTTASK->t.n_Item; /* see "kernel.h" for this */
ctx->streamCBPtr = streamCBPtr;
ctx->creatorSignal = AllocSignal( 0 );
if ( ctx->creatorSignal == 0 )
{
status = kDSNoSignalErr;
goto CLEANUP;
}
/* Create the thread that will handle all subscriber responsibilities./*/
status = NewThread(
(void *) &ProtoSubscriberThread, /* thread entrypoint */
4096, /* initial stack size */
(long) CURRENT_TASK_PRIORITY + deltaPriority, /* priority */
NULL, /* name */
&ctx->threadStackBlock, /* where to remember stack block addr */
0, /* initial R0 */
ctx ); /* initial R1 */
if ( status <= 0 )
goto CLEANUP;
else
ctx->threadItem = status;
/* Wait here while the subscriber initializes itself. When its done,look at the
* status returned to us in the context block to determine if it was happy.
*/
signalBits = WaitSignal( ctx->creatorSignal );
if ( signalBits != ctx->creatorSignal )
return kDSSignalErr;
/* We're done with this signal, so give it back */
FreeSignal( ctx->creatorSignal );
/* Check the initialization status of the subscriber. If anything
* failed, the 'ctx->creatorStatus' field will be set to a system result
* code. If this is >= 0 then initialization was successful.
*/
status = ctx->creatorStatus;
if ( status >= 0 )
{
*pCtx = ctx; /* give the caller a copy of the context pointer */
return status; /* return 'success' */
}
DisposeProtoSubscriber()
routine.