2015-11-07 95 views
2

我得到一个C库,需要一些回调, 他们在一个链表中处理。ctypes回调函数抛出SIGSEGV

蟒蛇调用的是那些:

def callback_exit(): 
    print("exiting.") 
    sys.exit(0) 
    # never reached 
    return c_int(0) 
def hw_print_int(): 
    print("foo") 
    return c_int(0) 

我将它们添加到列表中是这样的:

SFR_COMM=CFUNCTYPE(c_voidp) 

class MyClass: 
    def add_SFR_callback(self,operation_number,callback): 
      all_callbacks=c_voidp.in_dll(self.memlib,"sfr_comms") 
      my_callback=self.memlib.newSFRCommand(c_uint(operation_number),callback) 
      new_all_callbacks=self.memlib.new_SFRCommandHolder(my_callback,all_callbacks) 
      self.memlib.set_sfr_comms(new_all_callbacks) 

my_class_object.add_SFR_callback(0xff,SFR_COMM(callback_exit)) 
my_class_object.add_SFR_callback(0xff,SFR_COMM(hw_print_int)) 

这工作得很好,直到回调被调用,那么我只收到一个SIGSEGV。

重要:在SIGSEGV告诉我,这是一个“UngültigerMaschinenbefehl”(中译:无效处理器指令或类似的东西)

所以我不知道我该如何解决它。

这是C代码:

struct _SFRCommandHolder * sfr_comms; 
#define DEBUG 
unsigned int SpecialFunctionRegister_exec(unsigned int val) 
{ 
    struct _SFRCommandHolder * curr=sfr_comms; 
    unsigned int ret=-1; 
    while (curr!=NULL) 
    { 
      #ifdef DEBUG 
      printf("(%zd => %zd => %zd) %u ?= %u",curr,curr->com,curr->com->funct,curr->com->val,val); 
      #endif 
      if(curr->com->val==val) 
      { 
        #ifdef DEBUG 
        printf("\t\tTRUE\n"); 
        #endif 

        ret=curr->com->funct(); // <= SIGSEGV here 
        #ifdef DEBUG 
        printf("callback done.\n"); 
        #endif 
      } 
      #ifdef DEBUG 
      else 
      { 
        printf("\t\tFALSE\n"); 
      } 
      #endif 
      curr=curr->next; 
    } 
    return ret; 
} 

我不认为,这是sys.exit一个问题,因为它之前就好工作了几提交。

编辑: 调用hw_print_int作品就好了,但callback_exit不起作用。

顺便说一句:如果我不加hw_print_intcallback_exit作品,也

输出:

(13185760 => 13136448 => 139994994819144) 3 ?= 255  FALSE 
(13038864 => 13034576 => 139994994819088) 255 ?= 255  TRUE 
Ungültiger Maschinenbefehl (Speicherabzug geschrieben) 
+0

尝试初始化sfr_comms为NULL。 – cup

+0

@cup不是问题。我的记忆处理是有效的。 (我测试过) – LittleByBlue

回答

1

问题是,蟒蛇垃圾收集删除 没有(强)引用它们的对象。

https://docs.python.org/3/library/ctypes.html#callback-functions

请务必保持引用CFUNCTYPE(),只要它们是由C代码使用的对象。 ctypes不会,如果你不这样做,它们可能会被垃圾收集,在回调时崩溃你的程序。另外,请注意,如果在Python控制之外创建的线程(例如调用回调的外部代码)中调用回调函数,ctypes会在每次调用时创建一个新的虚拟Python线程。这种行为在大多数情况下都是正确的,但这意味着使用threading.local存储的值不会跨越不同的回调,即使这些调用是由同一个C线程创建的。

它似乎是不足以使用struct _SFRCommandHolder *引用他们。

所以添加另一引用是不够的:

class MyClass: 
    def __init__(self,*args): 
     # ... 
     self.refs=[] 
    def add_SFR_callback(self,operation_number,callback): 
     all_callbacks=c_voidp.in_dll(self.memlib,"sfr_comms") 
     my_callback=self.memlib.newSFRCommand(c_uint(operation_number),callback) 
     new_all_callbacks=self.memlib.new_SFRCommandHolder(my_callback,all_callbacks) 
     self.memlib.set_sfr_comms(new_all_callbacks) 
     self.refs.append(callback) 
1

在这里,你已经指向struct _SFRCommandHolder但哪里数据住在哪里?你在哪里分配了struct _SFRCommandHolder

如果响应是“无处”,你的代码有未定义的行为,因为sfr_comms可能有任何值(尤其是非NULL值);这个结果在curr->com几乎每次都会导致分段错误。

+0

'struct _SFRCommandHolder'和回调都是有效的ptrs。 (请参阅:我打印它们)在'new_SFRCommandHolder'中我为'struct _SFRCommandHolder'分配了空间。 AND:如果我打电话给'hw_print_int'就行了。 – LittleByBlue

+0

你确定,sys.exit()可用吗?如果您从回调中删除此呼叫,它是否仍会崩溃? – OznOg

+0

sys.exit不会更改任何内容。 BU是否可以,Python删除我的函数对象? – LittleByBlue