2010-02-06 5 views
3

Мой вопрос очень прост. Почему приведенный ниже код работает на linux и не работает в Mac OS X.AIO на OS X vs Linux - почему он не работает на Mac OS X

Чтобы скомпилировать файл в файл aio.cc и скомпилировать его с помощью g ++ aio.cc -o aio -lrt в Linux и g ++ aio .cc -o aio на Mac OS X. Я использую Mac OS X 10.6.2 для тестирования на Mac и Linux 2.6 для тестирования на Linux.

Ошибка, которую я вижу в OS X, - это aio_write с -1 и устанавливает errno в EAGAIN, что просто означает «Ресурс временно недоступен». Почему это?

extern "C" { 
#include <aio.h> 
#include <sys/types.h> 
#include <sys/socket.h> 
#include <sys/types.h> 
#include <arpa/inet.h> 
#include <netinet/in.h> 
#include <errno.h> 
#include <signal.h> 
} 
#include <cassert> 
#include <string> 
#include <iostream> 

using namespace std; 

static void 
aio_completion_handler(int signo, siginfo_t *info, void *context) 
{ 
    using namespace std; 
    cout << "BLAH" << endl; 
} 


int main() 
{ 
    int err; 

    struct sockaddr_in sin; 
    memset(&sin, 0, sizeof(sin)); 

    sin.sin_port = htons(1234); 
    sin.sin_addr.s_addr = inet_addr("127.0.0.1"); 
    sin.sin_family = PF_INET; 

    int sd = ::socket(PF_INET, SOCK_STREAM, IPPROTO_TCP); 
    if (sd == -1) { 
    assert(!"socket() failed"); 
    } 

    const struct sockaddr *saddr = reinterpret_cast<const struct sockaddr *>(&sin); 
    err = ::connect(sd, saddr, sizeof(struct sockaddr)); 
    if (err == -1) { 
    perror(NULL); 
    assert(!"connect() failed"); 
    } 

    struct aiocb *aio = new aiocb(); 
    memset(aio, 0, sizeof(struct aiocb)); 

    char *buf = new char[3]; 
    buf[0] = 'a'; 
    buf[1] = 'b'; 
    buf[2] = 'c'; 
    aio->aio_fildes = sd; 
    aio->aio_buf = buf; 
    aio->aio_nbytes = 3; 

    aio->aio_sigevent.sigev_notify = SIGEV_SIGNAL; 
    aio->aio_sigevent.sigev_signo = SIGIO; 
    aio->aio_sigevent.sigev_value.sival_ptr = &aio; 

    struct sigaction sig_act; 

    sigemptyset(&sig_act.sa_mask); 
    sig_act.sa_flags = SA_SIGINFO; 
    sig_act.sa_sigaction = aio_completion_handler; 

    sigaction(SIGIO, &sig_act, NULL); 

    errno = 0; 
    int ret = aio_write(aio); 
    if (ret == -1) { 
    perror(NULL); 
    } 
    assert(ret != -1); 
} 

UPDATE: OSX не Suppport AIO на патрубках вообще. Вот досада!

+0

Что такое aio? Ссылка? – dmckee

+0

вы можете посмотреть, что случилось? – ggiroux

ответ

1

У меня есть код, очень похожий на ваш, на 10.6.2 (но запись в файл) работает без проблем - так что вы можете делать то, что пытаетесь.

Просто из любопытства, какое значение вы используете для постоянной SIGIO? Я обнаружил, что недопустимое значение здесь, в OS X, приведет к ошибке aio_write - так Я всегда передаю SIGUSR1.

Возможно, проверьте возвращаемое значение sigaction(), чтобы проверить данные сигнала?

+0

Значение SIGIO я использую (от Sys/signal.h) является #if (! Определен (_POSIX_C_SOURCE) || определена (_DARWIN_C_SOURCE)) #define SIGIO 23/* вход/выход возможный сигнал */#endif Я думаю, что он может не поддерживаться для сокетов. Я тоже попробую с SIGUSR1. – invalidopcode

+0

Эти две ссылки отвечают на вопрос. http://lists.apple.com/archives/Macnetworkprog/2009/Aug/msg00016.html http://lists.apple.com/archives/Macnetworkprog/2009/Aug/msg00017.html – invalidopcode

1

Точки, поднятые в ваших ссылках, указывают на другой метод для получения уведомлений о завершении io (например, kqueue, который является специфическим для BSD механизма), но на самом деле не отвечает на ваш вопрос re POSIX-методы для async io. и работают ли они на Дарвине.

Мир UNIX действительно является решением для этого решения, и было бы очень хорошо, если бы был один проверенный и проверенный solutiom, который работал на всех платформах, увы, в настоящее время нет - POSIX - это тот, который предназначен для большинство согласованности.

Это немного удара в темноте, но это может быть также полезно установить блокирующий на сокете ручке (т.е. набор гнездо опции O_NONBLOCK), а также с использованием SIGUSR1

Если я получаю какое-то время I «Я буду работать с вашим образцом сокета и посмотреть, могу ли я получить что-нибудь из этого.

Удачи.

+0

Я пробовал установка O_NONBLOCK, а также O_ASYNC через fcntl, но это тоже не помогло. Мне также придется исследовать, помогает ли F_SETOWN, но я уверен, что aio_ {read, write} api не поддерживается для сокетов на OS X, что грустно, если честно. – invalidopcode

+0

http://lists.apple.com/archives/Macnetworkprog/2009/Aug/msg00016.html говорит: «ли OS X поддержка асинхронного ввода-вывода на патрубках Когда я называю aio_write() я получаю ошибку ESPIPE?. Тот же код работает в Linux, и если я использую дескриптор файла вместо сокета, он также работает в OS X (10.5.7). Похоже, что есть дополнительный шаг, необходимый для сокетов + aio на Mac, m просто пытается сделать что-то, что еще не поддерживается. Любая помощь очень ценится ». http://lists.apple.com/archives/Macnetworkprog/2009/Aug/msg00017.html отвечает: "? Есть ли поддержка OS X асинхронного ввода-вывода на патрубках No." – invalidopcode

+0

Технически POSIX AIO обеспечивает стандартный способ обработки различных способов уведомления о завершении. Конечно, Linux не очень хорошо реализует этот API. –

1

OSX Позволяет использовать сокеты через RunLoop (CF). Или получить обратные вызовы из runloop. Это самый элегантный способ, который я нашел для использования async IO на Mac. Вы можете использовать существующий сокет и сделать CFSocketCreateWithNative. И зарегистрируйте обратные вызовы на вашей runloop.

Вот небольшой фрагмент кода, который показывает, как он может быть установлен, неполными, так как я сократить исходный файл ...

// This will setup a readCallback 
void SocketClass::setupCFCallback() { 
CFSocketContext  context = { 0, this, NULL, NULL, NULL }; 

if (CFSocketRef macMulticastSocketRef = CFSocketCreateWithNative(NULL, socketHandle_, kCFSocketReadCallBack,readCallBack, &context)) { 
    if (CFRunLoopSourceRef macRunLoopSrc = CFSocketCreateRunLoopSource(NULL, macMulticastSocketRef, 0)) { 
     if (!CFRunLoopContainsSource(CFRunLoopGetCurrent(), macRunLoopSrc, kCFRunLoopDefaultMode)) { 
      CFRunLoopAddSource(CFRunLoopGetCurrent(), macRunLoopSrc, kCFRunLoopDefaultMode); 
      macRunLoopSrc_ = macRunLoopSrc; 
     } 
     else 
      CFRelease(macRunLoopSrc); 
    } 
    else 
     CFSocketInvalidate(macMulticastSocketRef); 
    CFRelease(macMulticastSocketRef); 
} 
} 



void SocketClass::readCallBack(CFSocketRef inref, CFSocketCallBackType type,CFDataRef , const void *, void *info) { 
if (SocketClass* socket_ptr = reinterpret_cast<SocketClass*>(info)) 
    socket_ptr->receive(); // do stuff with your socket 

} 
1

Представленный код был протестирован на Mountain Lion 10.8.2 , Он работает с небольшой коррекцией. Линия
"aio-> aio_fildes = sd;"

следует изменить, например, на:
aio-> aio_fildes = open ("/ dev/null", O_RDWR);

для получения ожидаемого результата.

см. Руководство пользователя. «Функция aio_write() позволяет вызывающему процессу выполнять асинхронную запись в ранее открытый файл».

 Смежные вопросы

  • Нет связанных вопросов^_^