tags:

views:

411

answers:

2

My question is really simple. Why the code below does work on linux, and doesn't on Mac OS X.

To compile save the file to aio.cc, and compile with g++ aio.cc -o aio -lrt on Linux, and g++ aio.cc -o aio on Mac OS X. I'm using Mac OS X 10.6.2 for testing on a Mac, and Linux kernel 2.6 for testing on Linux.

The failure I see on OS X is aio_write fails with -1 and sets errno to EAGAIN , which simply means "Resource temporarily unavailable". Why is that?

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 does not suppport AIO on sockets at all. Bummer!

+1  A: 

I have code very similar to yours on 10.6.2 (but writing to a file) working without any problems - so it is possible to do what you're trying.

Just out of curiosity, what value are you using for the SIGIO constant ? I found that an invalid value here in OS X would casue aio_write to fail - so I always pass SIGUSR1.

Maybe check the return value of sigaction() to verify the signal details?

robin demetriades
The SIGIO value I use (from sys/signal.h) is #if (!defined(_POSIX_C_SOURCE) || defined(_DARWIN_C_SOURCE)) #define SIGIO 23 /* input/output possible signal */ #endif I think it might be not supported for sockets. I'll try with SIGUSR1 though too.
mateuszb
These two links answer the question.http://lists.apple.com/archives/Macnetworkprog/2009/Aug/msg00016.htmlhttp://lists.apple.com/archives/Macnetworkprog/2009/Aug/msg00017.html
mateuszb
+1  A: 

The points raised in your links all point to a different method for raising io completion notifications (e.g. kqueue which is a BSD specific mechanism), but doesn't really answer your question re POSIX methods for async io. and whether they work on Darwin.

The UNIX world really is a mish mash of solutions for this, and it would be really good if there was one tried and tested solutiom that worked across all platforms, alas currently there's not - POSIX being the one that aims for the most consistency.

It's a bit of a stab in the dark, but it might be useful as well to set nonblocking on your socket handle ( i.e. set socket option O_NONBLOCK ) as well as using SIGUSR1

If I get some time I'll work with your socket sample and see if I can get anything out of that too.

Best of luck.

robin demetriades
I've tried setting O_NONBLOCK as well as O_ASYNC via fcntl but it did not help either.I'll also have to investigate if using F_SETOWN helps, but I am pretty sure aio_{read,write} api is not supported for sockets on OS X which is sad to be honest.
mateuszb
http://lists.apple.com/archives/Macnetworkprog/2009/Aug/msg00016.html says:"Does OS X support asynchronous IO on sockets? When I call aio_write() I get an ESPIPE error. The same code works in Linux, and if I use a file handle instead of a socket, it also works in OS X (10.5.7). Seems like there's either an extra step required for sockets + aio on the Mac, or I'm just trying to do something that's not supported yet.Any help is greatly appreciated."The http://lists.apple.com/archives/Macnetworkprog/2009/Aug/msg00017.html replies:"Does OS X support asynchronous IO on sockets?No."
mateuszb
Technically, POSIX AIO provides a standard way to handle various methods of completion notification. Of course, Linux doesn't implement that API particularly well.
Christopher Smith