using the sendfile system call on Darwin

Michael Allman msa at allman.ms
Thu Jan 28 00:14:15 PST 2010


On Wed, 27 Jan 2010, Greg Lewis wrote:

> On Tue, Jan 26, 2010 at 01:33:06AM -0800, Michael Allman wrote:
>> I would like to update jdk/src/solaris/native/sun/nio/ch/FileChannelImpl.c
>> so that the Java_sun_nio_ch_FileChannelImpl_transferTo0 function calls the
>> sendfile system call on Darwin.  I have a few questions:
>>
>> 1.  Is there a cpp #define for Darwin?  If not, how do I tell cpp whether
>> the system is Darwin or not?
>
> The rest of the code uses
>
> #ifdef __APPLE__

Ok.  Thanks.

>> 2.  Are there tests that exercise
>> Java_sun_nio_ch_FileChannelImpl_transferTo0 or the java method
>> FileChannel.transferTo?
>
> Some of the tests in jdk/test/java/nio/channels/FileChannel/ may be useful,
> I haven't looked them over though.

Oh yeah.  I remember these.  I have have an old copy on my machine.  I 
just forgot.

>> 3.  Why doesn't the existing BSD code just return IOS_UNSUPPORTED?  For
>> instance, look at lines 223 and 224.  If there's no sendfile function on
>> Solaris, the function just returns IOS_UNSUPPORTED.  The caller handles
>> that return value gracefully.  The existing BSD code looks needlessly
>> complex to me.
>
> All of the BSDs have sendfile, its just limited to only sending the file to
> a stream socket rather than any file descriptor, which Solaris and Linux
> allow.  It's fairly easy to implement code that will do that though, so
> that's what was done rather than throwing errors when a non-socket file
> descriptor was used.
>
> Note that MacOS X seems to have the same limitations as all the other BSDs
> in terms of what type of file descriptor can be used as the destination:
>
> http://developer.apple.com/Mac/library/documentation/Darwin/Reference/ManPages/man2/sendfile.2.html

I think sun.nio.ch.FileChannelImpl can handle this limitation gracefully. 
The new Java_sun_nio_ch_FileChannelImpl_transferTo0 method will look 
something like this: (starting at _ALLBSD_SOURCE_)


------------------------------------------------------------

#ifdef _ALLBSD_SOURCE
#ifdef __APPLE__
   int result;

   result = sendfile(srcFD, dstFD, position, &count);

   if (result == 0)
     return count;

   if (errno == ENOTSOCK)
     return IOS_UNSUPPORTED_CASE;
   /* Handle more errno's here... */

   /* Return of last resort */
   JNU_ThrowIOExceptionWithLastError(env, "Transfer failed");
     return IOS_THROWN;
#endif

   return IOS_UNSUPPORTED;
#endif

------------------------------------------------------


That's it.

FileChannelImpl's transferToDirectly method tries 
Java_sun_nio_ch_FileChannelImpl_transferTo0 at least once.  If 
Java_sun_nio_ch_FileChannelImpl_transferTo0 returns IOS_UNSUPPORTED, it 
won't call it again.  If Java_sun_nio_ch_FileChannelImpl_transferTo0 
returns IOS_UNSUPPORTED_CASE and the destination file descriptor is a 
file, then transferToDirectly just won't call 
Java_sun_nio_ch_FileChannelImpl_transferTo0 again for transfers to files. 
But it will still call it for transfers to sockets.  The details are in 
the FileChannelImpl.java source code.

Using this approach, we can still take advantage of BSDs' support for 
file->socket transfer without emulating support for file->file transfer.

Also, though this patch will be targeted at Darwin only, I believe it will 
be easily adaptable to other BSD systems.  I just looked up FreeBSD's 
sendfile call and it looks very similar.

> If NIO in general interests you, then a project we really need someone to
> work on is porting NIO2 to BSD.  None of the BSDs have the epoll mechanism
> used on Linux or whatever Solaris uses (which I can't recall off the top of
> my head right now).  The suggestion is to use kqueue(2) on BSD.

A kqueue-based selector would be nice for NIO 1.  Both of these would be 
cool projects.

I might be able to do the Java side of this effort if a kqueue developer 
does the native side.  I don't have the C/C++ programming skills to do the 
latter.

Cheers,

Michael



More information about the bsd-port-dev mailing list