2010-08-25 94 views
2

我正在嘗試使用python ctypes調用io_submit。 我正在編寫的代碼應該可以在32位和64位Intel/AMD架構上工作,但在這裏我將專注於64位。使用python ctypes在Linux中調用io_submit

我已經定義如下:

def PADDED64(type, name1, name2): 
    return [(name1, type), (name2, type)] 

def PADDEDptr64(type, name1, name2): 
    return [(name1, type)] 

def PADDEDul64(name1, name2): 
    return [(name1, ctypes.c_ulong)] 

class IOVec(ctypes.Structure): 
    _fields_ = [("iov_base", ctypes.c_void_p), ("iov_len", ctypes.c_size_t)] 

class IOCBDataCommon64(ctypes.Structure): 
    _fields_ = PADDEDptr64(ctypes.c_void_p, "buf", "__pad1") + \ 
     PADDEDul64("nbytes", "__pad2") + \ 
     [("offset", ctypes.c_longlong), ("__pad3", ctypes.c_longlong), ("flags", ctypes.c_uint), ("resfd", ctypes.c_uint)] 

class IOCBDataVector(ctypes.Structure): 
    _fields_ = [("vec", ctypes.POINTER(IOVec)), ("nr", ctypes.c_int), ("offset", ctypes.c_longlong)] 

class IOCBDataPoll64(ctypes.Structure): 
    _fields_ = PADDED64(ctypes.c_int, "events", "__pad1") 

class SockAddr(ctypes.Structure): 
    _fields_ = [("sa_family", ctypes.c_ushort), ("sa_data", ctypes.c_char * 14)] 

class IOCBDataSockAddr(ctypes.Structure): 
    _fields_ = [("addr", ctypes.POINTER(SockAddr)), ("len", ctypes.c_int)] 

class IOCBDataUnion64(ctypes.Union): 
    _fields_ = [("c", IOCBDataCommon64), ("v", IOCBDataVector), ("poll", IOCBDataPoll64), ("saddr", IOCBDataSockAddr)] 

class IOCB64(ctypes.Structure): 
    _fields_ = PADDEDptr64(ctypes.c_void_p, "data" , "__pad1") + \ 
     PADDED64(ctypes.c_uint, "key", "__pad2") + \ 
     [("aio_lio_opcode", ctypes.c_short), ("aio_reqprio", ctypes.c_short), ("aio_fildes", ctypes.c_int), ("u", IOCBDataUnion64)] 

class Timespec(ctypes.Structure): 
    _fields_ = [("tv_sec", ctypes.c_long), ("tv_nsec", ctypes.c_long)] 

class IOEvent64(ctypes.Structure): 
    _fields_ = PADDEDptr64(ctypes.c_void_p, "data", "__pad1") + \ 
     PADDEDptr64(ctypes.POINTER(IOCB64), "obj", "__pad2") + \ 
     PADDEDul64("res", "__pad3") + \ 
     PADDEDul64("res2", "__pad4") 

我有一個包裝類叫AIOCommands:

class AIOCommands: 
    def __init__(self, aioCommandList): 
     self.__commandList = aioCommandList 
     self.__iocbs = (IOCB64 * len(self.__commandList))() 
     for i in range(len(self.__commandList)): 
      self.__commandList[i].initialize(self.__iocbs[i]) 
    def size(self): 
     return len(self.__iocbs) 
    def getIOCBArray(self): 
     return self.__iocbs 

我已定義的參數和io_submit的返回值:

class Executor: 
    def __init__(self, aioLibraryPath): 
     self.__aio = ctypes.CDLL(aioLibraryPath) 
     self.__aio.io_submit.argtypes = [self.aio_context_t, ctypes.c_long, ctypes.POINTER(ctypes.POINTER(IOCB64))] 
     self.__aio.io_submit.restype = ctypes.c_long 

現在,Executor.io_submit身體應該是什麼樣子?我想:

def io_submit(self, aioContext, aioCommands): 
    iocbPtr = ctypes.cast(aioCommands.getIOCBArray(), ctypes.POINTER(self.iocb_t)) 
    return self.__aio.io_submit(aioContext, aioCommands.size(), ctypes.byref(iocbPtr)) 

但我得到一個分段錯誤每當aioCommandList的長度大於1 當列表中僅有1命令,代碼工作正常。

這可能是我的結構定義的問題嗎?我試着模仿libaio.h定義(假設只little-endian的架構將得到支持):

#if defined(__i386__) /* little endian, 32 bits */ 
#define PADDED(x, y) x; unsigned y 
#define PADDEDptr(x, y) x; unsigned y 
#define PADDEDul(x, y) unsigned long x; unsigned y 
#elif defined(__ia64__) || defined(__x86_64__) || defined(__alpha__) 
#define PADDED(x, y) x, y 
#define PADDEDptr(x, y) x 
#define PADDEDul(x, y) unsigned long x 
#elif defined(__powerpc64__) /* big endian, 64 bits */ 
#define PADDED(x, y) unsigned y; x 
#define PADDEDptr(x,y) x 
#define PADDEDul(x, y) unsigned long x 
#elif defined(__PPC__) /* big endian, 32 bits */ 
#define PADDED(x, y) unsigned y; x 
#define PADDEDptr(x, y) unsigned y; x 
#define PADDEDul(x, y) unsigned y; unsigned long x 
#elif defined(__s390x__) /* big endian, 64 bits */ 
#define PADDED(x, y) unsigned y; x 
#define PADDEDptr(x,y) x 
#define PADDEDul(x, y) unsigned long x 
#elif defined(__s390__) /* big endian, 32 bits */ 
#define PADDED(x, y) unsigned y; x 
#define PADDEDptr(x, y) unsigned y; x 
#define PADDEDul(x, y) unsigned y; unsigned long x 
#else 
#error endian? 
#endif 

struct io_iocb_poll { 
    PADDED(int events, __pad1); 
}; /* result code is the set of result flags or -'ve errno */ 

struct io_iocb_sockaddr { 
    struct sockaddr *addr; 
    int  len; 
}; /* result code is the length of the sockaddr, or -'ve errno */ 

struct io_iocb_common { 
    PADDEDptr(void *buf, __pad1); 
    PADDEDul(nbytes, __pad2); 
    long long offset; 
    long long __pad3; 
    unsigned flags; 
    unsigned resfd; 
}; /* result code is the amount read or -'ve errno */ 

struct io_iocb_vector { 
    const struct iovec *vec; 
    int   nr; 
    long long  offset; 
}; /* result code is the amount read or -'ve errno */ 

struct iocb { 
    PADDEDptr(void *data, __pad1); /* Return in the io completion event */ 
    PADDED(unsigned key, __pad2); /* For use in identifying io requests */ 

    short  aio_lio_opcode; 
    short  aio_reqprio; 
    int  aio_fildes; 

    union { 
     struct io_iocb_common  c; 
     struct io_iocb_vector  v; 
     struct io_iocb_poll  poll; 
     struct io_iocb_sockaddr saddr; 
    } u; 
}; 

任何幫助,將不勝感激,我一直停留在這幾個小時。

回答

1

我的理解是,io_submit()iocbpp參數是一個指向struct iocb的指針數組。

這似乎與Linux特定的例子在這裏得到加強:http://voinici.ceata.org/~sana/blog/?p=248並通過EINVAL錯誤文件的位置:http://linux.die.net/man/2/io_submit(數組下標優先提領)

您提供給io_submit()什麼是一個參考struct iocb數組。你肯定會得到一個段錯誤,因爲它通過iocbpp數組迭代時取消引用假內存地址。第一個元素(索引0)將正常工作,因爲沒有內存偏移量來訪問它。

編輯 這裏又如:http://www.xmailserver.org/eventfd-aio-test.c

+0

謝謝!我誤解了io_submit的語義。它現在有效 – 2010-08-26 10:21:01