POSIX AIO的aio_write()和lio_listio()在写入操作中无法正常工作

时间:2019-02-06 09:05:56

标签: c linux posix aio

我正在设置一个异步编写器,并希望以此来保证文件上的操作顺序。我在另一个读取pcap文件的程序中将其用作编写器。考虑到我已经尝试在代码中分别使用linux-aio和POSIX aio来在磁盘上写入pcap文件。我需要知道POSIX AIO的aio_write()和lio_listio()是否保证按顺序执行?

在linux-aio中,我使用iocb结构表示写入操作的单个请求。完成固定次数的单个操作后,io_getevents会阻塞,直到完成固定次数报告为止。

struct iocb io_cb;
memset(&io_cb, 0, sizeof(io_cb));
io_cb.aio_fildes = file_descriptor;
io_cb.aio_lio_opcode = IOCB_CMD_PWRITE;
io_cb.aio_reqprio = 0;
io_cb.aio_buf = (__u64)(buffer);
io_cb.aio_nbytes = size;
io_cb.aio_offset = 0;
struct iocb* io_cb_pointer = &io_cb;
static int32_t BLOCKS_COUNT = 1;
syscall(SYS_io_submit, io_context, BLOCKS_COUNT, &io_cb_pointer) 
write_count++;
 if ((write_count == MAX_EVENT_COUNT) || flush == true)//flush is to flush before exit program.
    {
        struct io_event* events = (struct io_event *)malloc((write_count) * sizeof(struct io_event));
        syscall(SYS_io_getevents, io_context, write_count / 2, MAX_EVENT_COUNT, events, NULL)
    }

上面编写负责任的代码会导致Wireshark可以打开正确的pcap输出。

但是我的问题是POSIX aio,它似乎不能保证执行顺序。这段代码如下所示:

    aiocb_array = calloc(MAX_EVENT_COUNT, sizeof (struct aiocb*));
    aiocb_element = calloc(MAX_EVENT_COUNT, sizeof (struct aiocb));
...
    struct aiocb** aiocb_array;
    struct aiocb* aiocb_element;
...
    static size_t pre_nbytes = 0;
    static __off_t pre_offset = 24;//Due to pcap header file length
    aiocb_element[write_count].aio_fildes = file_descriptor;
    aiocb_element[write_count].aio_lio_opcode = LIO_WRITE;
    aiocb_element[write_count].aio_reqprio = 0;
    aiocb_element[write_count].aio_buf = (void *)(buffer);
    aiocb_element[write_count].aio_nbytes = size;
    aiocb_element[write_count].aio_offset = pre_nbytes + pre_offset;

    pre_nbytes = size;
    pre_offset = aiocb_element[write_count].aio_offset;

    aiocb_array[write_count] = &aiocb_element[write_count];
    write_count++;
        if ((write_count == MAX_EVENT_COUNT) || flush == true )//flush is to flush before exit program.
    {
        if(flush)
        {
            if(lio_listio(LIO_WAIT, aiocb_array, write_count, NULL) != 0)
            {
                 printf("Flush lio_listio errno :%d\n", errno);
                 input->error_code = errno;
                 return false;
            }
        }
        else
        {
            if(lio_listio(LIO_NOWAIT, aiocb_array, write_count, NULL) != 0)
            {
                 printf("lio_listio errno :%d\n", errno);
                 input->error_code = errno;
                 return false;
            }
        }

        if(write_count == MAX_EVENT_COUNT)
            write_count = 0;
    }

如上面的代码所示,我准备了aiocb结构的写请求并为其分配了偏移量,因为用于写的文件是在没有附加模式的情况下打开的。该代码段生成的pcap文件具有与输入pcap相同的字节,但是不幸的是,Wireshark无法打开它并显示错误,表明:“捕获文件似乎已损坏或损坏。(pcap:文件具有...... 。字节数据包,大于最大0f 65535)”。但是,当我以LIO_WAIT模式调用lio_listio并将MAX_EVENT_COUNT设置为1时,它将生成正确的pcap输出,可以由Wireshark正确打开。

此外,当我用POSIX的aio_write函数替换lio_listio时,它再次产生损坏的文件。 根据提到的导致正确输出pcap的条件,看来POSIX执行顺序的lio_listio和aio_write函数与程序提交顺序不同!!! 是否以任意顺序执行操作?如果答案是肯定的,为什么它会忽略偏移值并且无法生成正确的输出?为什么linux-aio保证并保持操作顺序? 如果答案是否定的,那么我的代码和逻辑问题是什么?

任何帮助将不胜感激。

0 个答案:

没有答案