Merge branch 'master' of git://git.ucc.asn.au/tpg/acess2
[tpg/acess2.git] / KernelLand / Modules / Interfaces / UDI / channels.c
index 8f96d34..a3894bb 100644 (file)
@@ -9,12 +9,27 @@
 #include <acess.h>
 #include <udi.h>
 #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;

UCC git Repository :: git.ucc.asn.au