Skip to content

Instantly share code, notes, and snippets.

@methodmissing
Created June 14, 2009 18:50
Show Gist options
  • Select an option

  • Save methodmissing/129775 to your computer and use it in GitHub Desktop.

Select an option

Save methodmissing/129775 to your computer and use it in GitHub Desktop.
require 'rubygems'
require 'ffi'
module Aio
extend FFI::Library
READ_CALLBACK = Proc.new do |sigval|
req = sigval.sival_ptr
if aio_error( req ) == 0
ret = aio_return( req );
else
FFI.errno
end
end
SIGEV_NONE = 0
SIGEV_SIGNAL = 1
SIGEV_THREAD = 3
SIGIO = 23
AIO_ALLDONE = 0x1
AIO_CANCELED = 0x2
AIO_NOTCANCELED = 0x4
LIO_NOP = 0x0
LIO_READ = 0x1
LIO_WRITE = 0x2
LIO_NOWAIT = 0x1
LIO_WAIT = 0x2
AIO_LISTIO_MAX = 16
O_SYNC = 0x0080
typedef :long, :off_t
typedef :long, :size_t
typedef :long, :ssize_t
typedef :int, :pid_t
typedef :uint, :uid_t
typedef :ulong, :sigset_t
class Sigval < FFI::Union
layout(
:sival_int, :int,
:sival_ptr, :pointer
)
end
callback :sigev_notify_function_cb, [ Sigval ], :void
class Sigevent < FFI::Struct
layout(
:sigev_notify, :int,
:sigev_signo, :int,
:sigev_value, Sigval,
:sigev_notify_function, :sigev_notify_function_cb,
:sigev_notify_attributes, :pointer
)
def sigev_notify_function=(cb)
@sigev_notify_function = cb
self[:sigev_notify_function] = @sigev_notify_function
end
def sigev_notify_function
@sigev_notify_function
end
end
class Siginfo < FFI::Struct
layout(
:si_signo, :int,
:si_errno, :int,
:si_code, :int,
:si_pid, :pid_t,
:si_uid, :uid_t,
:si_status, :int,
:si_addr, :pointer,
:si_value, Sigval,
:si_band, :long,
:__pad, [:ulong, 7]
)
end
callback :sighandler_cb, [ :int ], :void
callback :sigaction_cb, [ :int, :pointer, :pointer ], :void
class SigactionU < FFI::Union
layout(
:__sa_handler, :sighandler_cb,
:__sa_sigaction, :sigaction_cb
)
def __sa_handler=(cb)
@__sa_handler = cb
self[:__sa_handler] = @__sa_handler
end
def __sa_handler
@__sa_handler
end
def __sa_sigaction=(cb)
@__sa_sigaction = cb
self[:__sa_sigaction] = @__sa_sigaction
end
def __sa_sigaction
@__sa_sigaction
end
end
callback :tramp_cb, [ :pointer, :int, :int, :pointer, :pointer ], :void
class Sigaction < FFI::Struct
layout(
:__sigaction_u, SigactionU,
:sa_tramp, :tramp_cb,
:sa_mask, :sigset_t,
:sa_flags, :int
)
def sa_tramp=(cb)
@sa_tramp = cb
self[:sa_tramp] = @sa_tramp
end
def sa_tramp
@sa_tramp
end
end
class Sigaction < FFI::Struct
layout(
:__sigaction_u, SigactionU,
:sa_mask, :sigset_t,
:sa_flags, :int
)
end
callback :sigvec_handler_cb, [ :int ], :void
class Sigvec < FFI::Struct
layout(
:sv_handler, :sigvec_handler_cb,
:sv_mask, :int,
:sv_flags, :int
)
def sv_handler=(cb)
@sv_handler = cb
self[:sv_handler] = @sv_handler
end
def sv_handler
@sv_handler
end
end
class Sigstack < FFI::Struct
layout(
:ss_sp, :pointer,
:ss_onstack, :int
)
def ss_sp=(str)
@ss_sp = FFI::MemoryPointer.from_string(str)
self[:ss_sp] = @ss_sp
end
def ss_sp
@ss_sp.get_string(0)
end
end
class Aiocb < FFI::Struct
layout(
:aio_fildes, :int,
:aio_offset, :off_t,
:aio_buf, :pointer,
:aio_nbytes, :uint,
:aio_reqprio, :int,
:aio_sigevent, Sigevent,
:aio_lio_opcode, :int
)
end
attach_function :aio_cancel, [ :int, :pointer ], :int
attach_function :aio_error, [ :pointer ], :int
attach_function :aio_fsync, [ :int, :pointer ], :int
attach_function :aio_read, [ :pointer ], :int
attach_function :aio_return, [ :pointer ], :ssize_t
#attach_function :aio_suspend, [ a().q(const).p.q(const).struct( aiocb ), :int, :pointer ], :pointer
attach_function :aio_write, [ :pointer ], :int
#attach_function :lio_listio, [ :int, a().q(const).p.struct( aiocb ), :int, :pointer ], :pointer
class ReadScheduleFailure < StandardError
end
class ReadFailure < StandardError
end
class WriteScheduleFailure < StandardError
end
class WriteFailure < StandardError
end
def self.read( path_or_fd, bytes = 4096, offset = 0 )
aio_callback = read_callback( path_or_fd, bytes, offset )
if ( ret = aio_read( aio_callback.pointer ) ) < 0
raise( ReadScheduleFailure, FFI.errno )
end
ret
end
def self.write( path_or_fd, bytes = 4096, buffer = '' )
aio_callback = write_callback( path_or_fd, bytes, buffer )
raise( WriteScheduleFailure ) if aio_write( aio_callback ) < 0
block( aio_callback )
if ((ret = aio_return( aio_callback )) > 0)
ret
else
raise WriteFailure
end
end
def self.to_fd( path_or_fd )
if path_or_fd.respond_to?(:ioctl)
path_or_fd.to_i
else
File.open( path_or_fd ).to_i
end
end
def self.block( aio_callback )
while aio_error( aio_callback ) == Errno::EINPROGRESS
end
end
private
def self.read_callback( path_or_fd, bytes, offset )
r_cb = Aiocb.new
r_cb.clear
r_cb[:aio_buf] = FFI::MemoryPointer.new(:char, bytes + 1)
r_cb[:aio_fildes] = to_fd( path_or_fd )
r_cb[:aio_nbytes] = bytes
r_cb[:aio_offset] = offset
r_cb[:aio_reqprio] = 0
=begin
r_cb[:aio_sigevent][:sigev_notify] = Aio::SIGEV_THREAD
r_cb[:aio_sigevent][:sigev_notify_function] = READ_CALLBACK
r_cb[:aio_sigevent][:sigev_notify_attributes] = nil
r_cb[:aio_sigevent][:sigev_value][:sival_ptr] = r_cb.to_ptr
=end
r_cb
end
def self.write_callback( path_or_fd, bytes, buffer = '' )
w_cb = Aiocb.new
w_cb.clear
w_cb[:aio_buf] = FFI::MemoryPointer.new(:char, bytes + 1)
w_cb[:aio_fildes] = to_fd( path_or_fd )
w_cb[:aio_nbytes] = bytes
w_cb[:aio_buf].write_string( buffer )
w_cb
end
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment