Tcl 开发中指针类型的转换

风行水上 @ 2013-10-13 15:04:41
标签:

    利用Tcl C API开发过程中,为了访问C中的资源(resouce),需要传递该资源的指针给Tcl命令。

    使用全局变量自然是最容易的方法。

    如果始终只需要一个资源指针,则利用Tcl API中的ClientData是一个不错的办法。

    gearman_client_st client;
    
    
    int TclObjCmd_gearman_client(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *const objv[]) {
      gearman_client_st &client = *(gearman_client_st *)clientData;
    
      return TCL_OK;
    }
    int Tclgearman_Init(Tcl_Interp *interp) {
      Tcl_CreateObjCommand(interp, "gearman::client", TclObjCmd_gearman_worker, &client, NULL);
      return TCL_OK;
    }
    

    ClientData本质上是一个void类型的指针。

    当需要区分多个不同的指针实例的时候,问题就开始变得复杂。比如典型的例子:

    set client1 [gearman::client create]
    $client2 submit "reverse" "data 1"
    
    set client2 [gearman::client create]
    $client2 submit "reverse" "data 2"
    

    这时TclObjCmd_gearman_client函数就需要使用不同的client指针。无论具体如何实现,都可以确定的是TclObjCmd_gearman_client一定都必须拿到一个Tcl_Obj对象以作为不同实例的区分。

    这个Tcl_Obj对象可以代表一个Tcl Command,也可以代表一个Tcl Variable参数。

    如果是Tcl Command,则可以借助ClientData存储对象指针。

    如果是Tcl Variable,则需要在Tcl Variable和pointer之间进行转换。

    利用Tcl Command实现指针传递

    主要是处理命令的删除。

    利用Tcl Variable实现指针转换

    定义新的变量类型。

    指针和字符串之间的转换。(主要问题是没法自动实现资源的释放)

    借助TclX中的Tcl_Allocate实现指针转换

    关键概念:entry即保存指针——确切说是用户数据结构——的地方。

    /*--------------------------------------------------------------*/
    /* User Part                                                    */
    /*--------------------------------------------------------------*/
    
    struct HandleEntry {
      void *pointer;
    };
    
    void *userPtr;  // pointer to user data structure
    
    #include <tclExtend.h>
    
    /*--------------------------------------------------------------*/
    /* Init the table                                               */
    /*--------------------------------------------------------------*/
    
    //# void_pt Tcl_HandleTblInit (const char *handleBase, int entrySize, int initEntries);
    
    void_pt headerPtr = Tcl_HandleTblInit("ptr", sizeof(HandleEntry), 24);
    
    /*--------------------------------------------------------------*/
    /* Register the pointer                                         */
    /*--------------------------------------------------------------*/
    
    char handlePtr[64];
    //# void_pt Tcl_HandleAlloc (void_pt headerPtr, char *handlePtr);
    void_pt entryPtr = Tcl_HandleAlloc(headerPtr, handlePtr);
    
    ((HandleEntry *)entryPtr)->pointer = userPtr;
    
    /*--------------------------------------------------------------*/
    /* Access the pointer                                           */
    /*--------------------------------------------------------------*/
    
    //# void_pt Tcl_HandleXlate (Tcl_Interp *interp, void_pt headerPtr, const char *handle);
    void_pt entryPtr = Tcl_HandleXlate(interp, headerPtr, handlePtr);
    userPtr = ((HandleEntry *)entryPtr)->pointer;
    
    /*--------------------------------------------------------------*/
    /* Traverse the table                                           */
    /*--------------------------------------------------------------*/
    
    int walkKey = -1;
    while(1){
      void_pt entryPtr = Tcl_HandleWalk(headerPtr, &walkKey);  // get the entry
      if(entryPtr==NULL) break; // come to the end
    
      char handlePtr[64];
      Tcl_WalkKeyToHandle(headerPtr, handlePtr); // get the handler
    
      Tcl_HandleFree(headerPtr, entryPtr);       // delete the entry
      Tcl_HandleTblRelease(headerPtr);           // release the table when goes to zero
    }
    

    网络资源

    • TclGearman - A Tcl implementation of Gearman Client/Work/Admin interface
    标签:

      分享到:
      comments powered by Disqus

      29/32ms