X-Git-Url: https://git.ucc.asn.au/?a=blobdiff_plain;f=KernelLand%2FModules%2FInterfaces%2FUDI%2Fchannels.c;h=c5ad09675bf470f3ef9aa07b17e9f5363856c3e8;hb=82e814024416fac7949a1e158a4532a5a1ed546f;hp=d232e03472c7d1b6b417393e76414856ba801bb1;hpb=a07af753a21de9deade5e9694863c0daedfafe3f;p=tpg%2Facess2.git diff --git a/KernelLand/Modules/Interfaces/UDI/channels.c b/KernelLand/Modules/Interfaces/UDI/channels.c index d232e034..c5ad0967 100644 --- a/KernelLand/Modules/Interfaces/UDI/channels.c +++ b/KernelLand/Modules/Interfaces/UDI/channels.c @@ -9,57 +9,106 @@ #include #include #include "udi_internal.h" +/* + * LOCK_CHANNELS - Prevents + */ +#define LOCK_CHANNELS 1 struct sUDI_ChannelSide { struct sUDI_Channel *BackPtr; + tUDI_DriverInstance *Instance; + udi_index_t MetaOpsNum; const void *Ops; void *Context; }; typedef struct sUDI_Channel { - enum eUDI_MetaLang MetaLang; - udi_index_t MetaOpsNum; + tUDI_MetaLang *MetaLang; + bool Locked; struct sUDI_ChannelSide Side[2]; } tUDI_Channel; // === CODE === -udi_channel_t UDI_CreateChannel(enum eUDI_MetaLang metalang, udi_index_t meta_ops_num, - tUDI_DriverInstance *ThisEnd, udi_index_t ThisOpsIndex, - tUDI_DriverInstance *OtherEnd, udi_index_t OtherOpsIndex) +udi_channel_t UDI_CreateChannel_Blank(tUDI_MetaLang *metalang) { tUDI_Channel *ret = NEW(tUDI_Channel,); - struct { - tUDI_DriverInstance *inst; - udi_index_t ops_index; - } ends[2] = { - {ThisEnd, ThisOpsIndex}, - {OtherEnd, OtherOpsIndex} - }; + ret->MetaLang = metalang; - ret->MetaOpsNum = meta_ops_num; - for( int i = 0; i < 2; i ++ ) - { - if( !ends[i].inst ) { - continue ; - } - tUDI_DriverModule *mod = ends[i].inst->Module; - ret->Side[i].BackPtr = ret; - udi_ops_init_t *ops = mod->InitInfo->ops_init_list;; - while( ops->ops_idx && ops->ops_idx != ends[i].ops_index ) - ops++; - ASSERTR(ops->ops_idx, NULL); // TODO: Pretty error - ASSERTCR(ops->meta_idx, <, mod->nMetaLangs, NULL); - ASSERTCR(mod->MetaLangs[ops->meta_idx], ==, metalang, NULL); - ASSERTCR(ops->meta_ops_num, ==, meta_ops_num, NULL); - if( ops->chan_context_size ) { - ret->Side[i].Context = malloc(ops->chan_context_size); - } - ret->Side[i].Ops = ops->ops_vector; - } + ret->Side[0].BackPtr = ret; + ret->Side[1].BackPtr = ret; + return (udi_channel_t)&ret->Side[0].BackPtr; } +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) ? 0 : 1; + if( other_side ) + side_idx = 1 - side_idx; + + LOG("side_idx = %i, other_side=%b", side_idx, other_side); + + return &ch->Side[side_idx]; +} + +int UDI_BindChannel_Raw(udi_channel_t channel, bool other_side, tUDI_DriverInstance *inst, 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->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) +{ + tUDI_Channel *ch = *(tUDI_Channel**)channel; + + tUDI_DriverRegion *rgn = inst->Regions[region]; + + udi_ops_init_t *ops = UDI_int_GetOps(inst, ops_idx); + if( !ops ) { + Log_Warning("UDI", "Ops ID invalid for '%s' (%i)", inst->Module, ops_idx); + return 1; + } + + tUDI_MetaLang *ops_ml = UDI_int_GetMetaLang(inst, 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 ); + ((udi_chan_context_t*)context)->rdata = rgn->InitContext; + } + else { + context = rgn->InitContext; + } + + UDI_BindChannel_Raw(channel, other_side, inst, ops->meta_ops_num, context, ops->ops_vector); + return 0; +} + +tUDI_DriverInstance *UDI_int_ChannelGetInstance(udi_cb_t *gcb, bool other_side) +{ + ASSERT(gcb); + ASSERT(gcb->channel); + tUDI_Channel *ch = *(tUDI_Channel**)(gcb->channel); + ASSERT(ch); + + struct sUDI_ChannelSide *side = UDI_int_ChannelGetSide(gcb->channel, other_side); + + return side->Instance; +} + /** * \brief Prepare a cb for a channel call * \param gcb Generic control block for this request @@ -70,16 +119,75 @@ udi_channel_t UDI_CreateChannel(enum eUDI_MetaLang metalang, udi_index_t meta_op * Updates the channel and context fields of the gcb, checks the metalanguage and returns * the handler list for the other end of the channel. */ -const void *UDI_int_ChannelPrepForCall(udi_cb_t *gcb, enum eUDI_MetaLang metalang, udi_index_t meta_ops_num) +const void *UDI_int_ChannelPrepForCall(udi_cb_t *gcb, tUDI_MetaLang *metalang, udi_index_t meta_ops_num) { + ASSERT(gcb); + ASSERT(gcb->channel); tUDI_Channel *ch = *(tUDI_Channel**)(gcb->channel); - ASSERTCR(ch->MetaLang, ==, metalang, NULL); + ASSERT(ch); - struct sUDI_ChannelSide *newside = (gcb->channel == (udi_channel_t)&ch->Side[0].BackPtr ? &ch->Side[1] : &ch->Side[0]); + // TODO: Allow calls without auto-lock + #if LOCK_CHANNELS + if( ch->Locked ) { + Log_Warning("UDI", "Channel %s:%i used while blocked (before handler was fired)", + ch->MetaLang->Name, meta_ops_num); + return NULL; + } + ch->Locked = true; + #endif + + struct sUDI_ChannelSide *newside = UDI_int_ChannelGetSide(gcb->channel, true); + if( metalang == NULL ) + { + if( ch->MetaLang == &cMetaLang_Management ) { + Log_Warning("UDI", "Invalid udi_channel_event_ind on Management metalang"); + return NULL; + } + } + else + { + if( ch->MetaLang != metalang || newside->MetaOpsNum != meta_ops_num ) { + Log_Warning("UDI", "Metalanguage mismatch %s:%i req != %s:%i ch", + metalang->Name, meta_ops_num, + ch->MetaLang->Name, newside->MetaOpsNum); + return NULL; + } + } -// gcb->initiator_context = gcb->context; gcb->channel = (udi_channel_t)&newside->BackPtr; gcb->context = newside->Context; + if( !newside->Ops ) { + Log_Warning("UDI", "Target end of %p(%s:%i) is unbound", + ch, ch->MetaLang->Name, newside->MetaOpsNum); + } 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; + #endif +} +