X-Git-Url: https://git.ucc.asn.au/?a=blobdiff_plain;f=KernelLand%2FModules%2FInterfaces%2FUDI%2Fchannels.c;h=a3894bb7391a1e864ec43441eb0cd511063e1410;hb=845b6f9d90bb87b5e760e4d49aa93b0e003ab750;hp=8f96d34101b45da9d7e9abda19fa65ac9aa61268;hpb=c0f20e1d9a03ae5026b345748d1e30b7dc142596;p=tpg%2Facess2.git diff --git a/KernelLand/Modules/Interfaces/UDI/channels.c b/KernelLand/Modules/Interfaces/UDI/channels.c index 8f96d341..a3894bb7 100644 --- a/KernelLand/Modules/Interfaces/UDI/channels.c +++ b/KernelLand/Modules/Interfaces/UDI/channels.c @@ -9,12 +9,27 @@ #include #include #include "udi_internal.h" -#define LOCK_CHANNELS 1 +/* + * LOCK_CHANNELS + * - Prevents multiple non-dispatched operations on one channel + * TODO: This should actually lock the GCB, not the channel + */ +#define LOCK_CHANNELS 0 +/* + * TRACE_ENDPOINTS + * - Emit a log message with names/indexes of both endpoints + */ +#define TRACE_ENDPOINTS 1 + +#define MAX_SPAWN_IDX 6 struct sUDI_ChannelSide { struct sUDI_Channel *BackPtr; + tUDI_DriverInstance *Instance; + udi_index_t RegionIdx; udi_index_t MetaOpsNum; const void *Ops; + void *AllocatedContext; void *Context; }; @@ -23,6 +38,7 @@ typedef struct sUDI_Channel tUDI_MetaLang *MetaLang; bool Locked; struct sUDI_ChannelSide Side[2]; + struct sUDI_Channel *SpawnBinds[MAX_SPAWN_IDX]; } tUDI_Channel; // === CODE === @@ -37,26 +53,48 @@ udi_channel_t UDI_CreateChannel_Blank(tUDI_MetaLang *metalang) return (udi_channel_t)&ret->Side[0].BackPtr; } +udi_channel_t UDI_CreateChannel_Linked(udi_channel_t orig, udi_ubit8_t spawn_idx) +{ + tUDI_Channel *ch = *(tUDI_Channel**)orig; + ASSERT(ch); + ASSERTC(spawn_idx, <, MAX_SPAWN_IDX); + // TODO: mutex + if( ch->SpawnBinds[spawn_idx] ) { + tUDI_Channel *ret = ch->SpawnBinds[spawn_idx]; + ch->SpawnBinds[spawn_idx] = NULL; + // TODO: mutex + return (udi_channel_t)&ret->Side[1].BackPtr; + } + udi_channel_t ret = UDI_CreateChannel_Blank( ch->MetaLang ); + ch->SpawnBinds[spawn_idx] = *(tUDI_Channel**)ret; + // TODO: Mutex + return ret; +} + struct sUDI_ChannelSide *UDI_int_ChannelGetSide(udi_channel_t channel, bool other_side) { tUDI_Channel *ch = *(tUDI_Channel**)channel; if(!ch) return NULL; - - int side_idx = (channel == (udi_channel_t)&ch->Side[0].BackPtr) != other_side; + + int side_idx = (channel == (udi_channel_t)&ch->Side[0].BackPtr) ? 0 : 1; + if( other_side ) + side_idx = 1 - side_idx; return &ch->Side[side_idx]; } -int UDI_BindChannel_Raw(udi_channel_t channel, bool other_side, udi_index_t meta_ops_num, void *context, const void *ops) +int UDI_BindChannel_Raw(udi_channel_t channel, bool other_side, tUDI_DriverInstance *inst, udi_index_t region_idx, udi_index_t meta_ops_num, void *context, const void *ops) { struct sUDI_ChannelSide *side = UDI_int_ChannelGetSide(channel, other_side); + side->Instance = inst; + side->RegionIdx = region_idx; side->Context = context; side->MetaOpsNum = meta_ops_num; side->Ops = ops; return 0; } -int UDI_BindChannel(udi_channel_t channel, bool other_side, tUDI_DriverInstance *inst, udi_index_t ops_idx, udi_index_t region) +int UDI_BindChannel(udi_channel_t channel, bool other_side, tUDI_DriverInstance *inst, udi_index_t ops_idx, udi_index_t region, void *context, bool is_child_bind, udi_ubit32_t child_ID) { tUDI_Channel *ch = *(tUDI_Channel**)channel; @@ -68,26 +106,55 @@ int UDI_BindChannel(udi_channel_t channel, bool other_side, tUDI_DriverInstance return 1; } - tUDI_MetaLang *ops_ml = UDI_int_GetMetaLang(inst, ops->meta_idx); + tUDI_MetaLang *ops_ml = UDI_int_GetMetaLang(inst->Module, ops->meta_idx); if( ops_ml != ch->MetaLang ) { Log_Warning("UDI", "Attempt by %s to bind with mismatched channel '%s' op '%s' channel", inst->Module, ops_ml->Name, ch->MetaLang->Name); return 3; } - void *context; - if( ops->chan_context_size ) { - context = malloc( ops->chan_context_size ); + if( context ) { + // Use provided context pointer + LOG("context = provided %p", context); + } + else if( ops->chan_context_size ) + { + if( is_child_bind ) + ASSERTCR( ops->chan_context_size, >=, sizeof(udi_child_chan_context_t), 4 ); + else + ASSERTCR( ops->chan_context_size, >=, sizeof(udi_chan_context_t), 4 ); + context = calloc( 1, ops->chan_context_size ); ((udi_chan_context_t*)context)->rdata = rgn->InitContext; + if( is_child_bind ) + ((udi_child_chan_context_t*)context)->child_ID = child_ID; + LOG("context = allocated %p", context); + + // TODO: The driver may change the channel context, but this must be freed by the environment + UDI_int_ChannelGetSide(channel, other_side)->AllocatedContext = context; } else { context = rgn->InitContext; + LOG("context = region %p", context); } - UDI_BindChannel_Raw(channel, other_side, ops->meta_ops_num, context, ops->ops_vector); + UDI_BindChannel_Raw(channel, other_side, inst, region, ops->meta_ops_num, context, ops->ops_vector); return 0; } +tUDI_DriverInstance *UDI_int_ChannelGetInstance(udi_cb_t *gcb, bool other_side, udi_index_t *region_idx) +{ + struct sUDI_ChannelSide *side = UDI_int_ChannelGetSide(gcb->channel, other_side); + if(region_idx) + *region_idx = side->RegionIdx; + return side->Instance; +} + +void UDI_int_ChannelSetContext(udi_channel_t channel, void *context) +{ + struct sUDI_ChannelSide *side = UDI_int_ChannelGetSide(channel, false); + side->Context = context; +} + /** * \brief Prepare a cb for a channel call * \param gcb Generic control block for this request @@ -133,6 +200,13 @@ const void *UDI_int_ChannelPrepForCall(udi_cb_t *gcb, tUDI_MetaLang *metalang, u } } + #if TRACE_ENDPOINTS + struct sUDI_ChannelSide *thisside = UDI_int_ChannelGetSide(gcb->channel, false); + Log("%s:%i -> %s:%i", + (thisside->Instance ? thisside->Instance->Module->ModuleName : "MA"), thisside->RegionIdx, + (newside->Instance ? newside->Instance->Module->ModuleName : "MA"), newside->RegionIdx); + #endif + gcb->channel = (udi_channel_t)&newside->BackPtr; gcb->context = newside->Context; if( !newside->Ops ) { @@ -142,12 +216,28 @@ const void *UDI_int_ChannelPrepForCall(udi_cb_t *gcb, tUDI_MetaLang *metalang, u return newside->Ops; } +void UDI_int_ChannelFlip(udi_cb_t *gcb) +{ + ASSERT(gcb); + ASSERT(gcb->channel); + tUDI_Channel *ch = *(tUDI_Channel**)(gcb->channel); + ASSERT(ch); + + struct sUDI_ChannelSide *newside = UDI_int_ChannelGetSide(gcb->channel, true); + + gcb->channel = (udi_channel_t)&newside->BackPtr; + gcb->context = newside->Context; +} + void UDI_int_ChannelReleaseFromCall(udi_cb_t *gcb) { #if LOCK_CHANNELS ASSERT(gcb); ASSERT(gcb->channel); tUDI_Channel *ch = *(tUDI_Channel**)(gcb->channel); + if( !ch ) { + Log_Error("UDI", "Channel pointer of cb %p is NULL", gcb); + } ASSERT(ch); ch->Locked = false;