2015-11-07 94 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