AIO on OS X vs. Linux - why it doesn't work on Mac OS X 10.6

My question is very simple. Why the code below works on Linux and does not work on Mac OS X 10.6.2 Snow Leopard.

To compile a file into aio.cc file and compile it with g++ aio.cc -o aio -lrtLinux and g++ aio.cc -o aioMac OS X. I use Mac OS X 10.6.2 for testing on Mac and the Linux kernel 2.6 for testing on Linux.

The crash that I see in OS X is aio_write with an error of -1 and sets errno to EAGAIN, which simply means "Resource is temporarily unavailable." Why is this?

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 (February 2010): OSX does not support AIO on sockets at all. What a nuisance!

+3
source share
4 answers

Mountain Lion 10.8.2. .
   "aio- > aio_fildes = sd;"

, , :
   aio- > aio_fildes = open ( "/dev/null", O_RDWR);

.

. . " aio_write() ."

+2

10.6.2 ( ), - , .

, SIGIO? , , OS X, aio_write, SIGUSR1.

, sigaction(), ?

+1

, , io (, kqueue, BSD ), re POSIX- async io. .

UNIX , , solutiom, , , - POSIX - , .

, (.. O_NONBLOCK), SIGUSR1

- , , - .

Good luck.

+1
source

OSX Allows the use of sockets through RunLoop (CF). Or get callbacks from runloop. This is the most elegant way I've found using async IO for Mac. You can use an existing socket and do CFSocketCreateWithNative. And register callbacks on your runloop.

Here is a small piece of code that shows how it can be installed, incomplete, since I cut the source file ...

// 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
source

Source: https://habr.com/ru/post/1731643/


All Articles