ffi 1.17.0.rc1-aarch64-linux-musl
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/CHANGELOG.md +442 -0
- data/COPYING +49 -0
- data/Gemfile +21 -0
- data/LICENSE +24 -0
- data/LICENSE.SPECS +22 -0
- data/README.md +137 -0
- data/Rakefile +206 -0
- data/ffi.gemspec +42 -0
- data/lib/2.5/ffi_c.so +0 -0
- data/lib/2.6/ffi_c.so +0 -0
- data/lib/2.7/ffi_c.so +0 -0
- data/lib/3.0/ffi_c.so +0 -0
- data/lib/3.1/ffi_c.so +0 -0
- data/lib/3.2/ffi_c.so +0 -0
- data/lib/3.3/ffi_c.so +0 -0
- data/lib/ffi/abstract_memory.rb +44 -0
- data/lib/ffi/autopointer.rb +188 -0
- data/lib/ffi/buffer.rb +4 -0
- data/lib/ffi/callback.rb +4 -0
- data/lib/ffi/compat.rb +43 -0
- data/lib/ffi/data_converter.rb +67 -0
- data/lib/ffi/dynamic_library.rb +118 -0
- data/lib/ffi/enum.rb +302 -0
- data/lib/ffi/errno.rb +43 -0
- data/lib/ffi/ffi.rb +50 -0
- data/lib/ffi/function.rb +71 -0
- data/lib/ffi/io.rb +62 -0
- data/lib/ffi/library.rb +576 -0
- data/lib/ffi/library_path.rb +109 -0
- data/lib/ffi/managedstruct.rb +84 -0
- data/lib/ffi/memorypointer.rb +1 -0
- data/lib/ffi/platform/aarch64-darwin/types.conf +130 -0
- data/lib/ffi/platform/aarch64-freebsd/types.conf +128 -0
- data/lib/ffi/platform/aarch64-freebsd12/types.conf +181 -0
- data/lib/ffi/platform/aarch64-linux/types.conf +175 -0
- data/lib/ffi/platform/aarch64-openbsd/types.conf +134 -0
- data/lib/ffi/platform/aarch64-windows/types.conf +52 -0
- data/lib/ffi/platform/arm-freebsd/types.conf +152 -0
- data/lib/ffi/platform/arm-freebsd12/types.conf +152 -0
- data/lib/ffi/platform/arm-linux/types.conf +132 -0
- data/lib/ffi/platform/hppa1.1-linux/types.conf +178 -0
- data/lib/ffi/platform/hppa2.0-linux/types.conf +178 -0
- data/lib/ffi/platform/i386-cygwin/types.conf +3 -0
- data/lib/ffi/platform/i386-darwin/types.conf +100 -0
- data/lib/ffi/platform/i386-freebsd/types.conf +152 -0
- data/lib/ffi/platform/i386-freebsd12/types.conf +152 -0
- data/lib/ffi/platform/i386-gnu/types.conf +107 -0
- data/lib/ffi/platform/i386-linux/types.conf +103 -0
- data/lib/ffi/platform/i386-netbsd/types.conf +126 -0
- data/lib/ffi/platform/i386-openbsd/types.conf +128 -0
- data/lib/ffi/platform/i386-solaris/types.conf +122 -0
- data/lib/ffi/platform/i386-windows/types.conf +52 -0
- data/lib/ffi/platform/ia64-linux/types.conf +104 -0
- data/lib/ffi/platform/loongarch64-linux/types.conf +141 -0
- data/lib/ffi/platform/mips-linux/types.conf +102 -0
- data/lib/ffi/platform/mips64-linux/types.conf +104 -0
- data/lib/ffi/platform/mips64el-linux/types.conf +104 -0
- data/lib/ffi/platform/mipsel-linux/types.conf +102 -0
- data/lib/ffi/platform/mipsisa32r6-linux/types.conf +102 -0
- data/lib/ffi/platform/mipsisa32r6el-linux/types.conf +102 -0
- data/lib/ffi/platform/mipsisa64r6-linux/types.conf +104 -0
- data/lib/ffi/platform/mipsisa64r6el-linux/types.conf +104 -0
- data/lib/ffi/platform/powerpc-aix/types.conf +180 -0
- data/lib/ffi/platform/powerpc-darwin/types.conf +100 -0
- data/lib/ffi/platform/powerpc-linux/types.conf +130 -0
- data/lib/ffi/platform/powerpc-openbsd/types.conf +156 -0
- data/lib/ffi/platform/powerpc64-linux/types.conf +104 -0
- data/lib/ffi/platform/powerpc64le-linux/types.conf +100 -0
- data/lib/ffi/platform/riscv64-linux/types.conf +104 -0
- data/lib/ffi/platform/s390-linux/types.conf +102 -0
- data/lib/ffi/platform/s390x-linux/types.conf +102 -0
- data/lib/ffi/platform/sparc-linux/types.conf +102 -0
- data/lib/ffi/platform/sparc-solaris/types.conf +128 -0
- data/lib/ffi/platform/sparcv9-linux/types.conf +102 -0
- data/lib/ffi/platform/sparcv9-openbsd/types.conf +156 -0
- data/lib/ffi/platform/sparcv9-solaris/types.conf +128 -0
- data/lib/ffi/platform/sw_64-linux/types.conf +141 -0
- data/lib/ffi/platform/x86_64-cygwin/types.conf +3 -0
- data/lib/ffi/platform/x86_64-darwin/types.conf +130 -0
- data/lib/ffi/platform/x86_64-dragonflybsd/types.conf +130 -0
- data/lib/ffi/platform/x86_64-freebsd/types.conf +128 -0
- data/lib/ffi/platform/x86_64-freebsd12/types.conf +158 -0
- data/lib/ffi/platform/x86_64-haiku/types.conf +117 -0
- data/lib/ffi/platform/x86_64-linux/types.conf +132 -0
- data/lib/ffi/platform/x86_64-msys/types.conf +119 -0
- data/lib/ffi/platform/x86_64-netbsd/types.conf +128 -0
- data/lib/ffi/platform/x86_64-openbsd/types.conf +134 -0
- data/lib/ffi/platform/x86_64-solaris/types.conf +122 -0
- data/lib/ffi/platform/x86_64-windows/types.conf +52 -0
- data/lib/ffi/platform.rb +187 -0
- data/lib/ffi/pointer.rb +167 -0
- data/lib/ffi/struct.rb +317 -0
- data/lib/ffi/struct_by_reference.rb +72 -0
- data/lib/ffi/struct_layout.rb +96 -0
- data/lib/ffi/struct_layout_builder.rb +227 -0
- data/lib/ffi/tools/const_generator.rb +232 -0
- data/lib/ffi/tools/generator.rb +105 -0
- data/lib/ffi/tools/generator_task.rb +32 -0
- data/lib/ffi/tools/struct_generator.rb +195 -0
- data/lib/ffi/tools/types_generator.rb +137 -0
- data/lib/ffi/types.rb +222 -0
- data/lib/ffi/union.rb +43 -0
- data/lib/ffi/variadic.rb +80 -0
- data/lib/ffi/version.rb +3 -0
- data/lib/ffi.rb +27 -0
- data/rakelib/ffi_gem_helper.rb +65 -0
- data/samples/getlogin.rb +8 -0
- data/samples/getpid.rb +8 -0
- data/samples/gettimeofday.rb +18 -0
- data/samples/hello.rb +8 -0
- data/samples/hello_ractor.rb +11 -0
- data/samples/inotify.rb +60 -0
- data/samples/pty.rb +75 -0
- data/samples/qsort.rb +20 -0
- data/samples/qsort_ractor.rb +28 -0
- data/sig/ffi/abstract_memory.rbs +164 -0
- data/sig/ffi/auto_pointer.rbs +27 -0
- data/sig/ffi/buffer.rbs +18 -0
- data/sig/ffi/data_converter.rbs +10 -0
- data/sig/ffi/dynamic_library.rbs +9 -0
- data/sig/ffi/enum.rbs +38 -0
- data/sig/ffi/function.rbs +39 -0
- data/sig/ffi/library.rbs +42 -0
- data/sig/ffi/native_type.rbs +86 -0
- data/sig/ffi/pointer.rbs +42 -0
- data/sig/ffi/struct.rbs +76 -0
- data/sig/ffi/struct_by_reference.rbs +11 -0
- data/sig/ffi/struct_by_value.rbs +7 -0
- data/sig/ffi/struct_layout.rbs +9 -0
- data/sig/ffi/struct_layout_builder.rbs +5 -0
- data/sig/ffi/type.rbs +39 -0
- data/sig/ffi.rbs +26 -0
- metadata +244 -0
data/lib/ffi/union.rb
ADDED
@@ -0,0 +1,43 @@
|
|
1
|
+
#
|
2
|
+
# Copyright (C) 2009 Andrea Fazzi <andrea.fazzi@alcacoop.it>
|
3
|
+
#
|
4
|
+
# This file is part of ruby-ffi.
|
5
|
+
#
|
6
|
+
# All rights reserved.
|
7
|
+
#
|
8
|
+
# Redistribution and use in source and binary forms, with or without
|
9
|
+
# modification, are permitted provided that the following conditions are met:
|
10
|
+
#
|
11
|
+
# * Redistributions of source code must retain the above copyright notice, this
|
12
|
+
# list of conditions and the following disclaimer.
|
13
|
+
# * Redistributions in binary form must reproduce the above copyright notice
|
14
|
+
# this list of conditions and the following disclaimer in the documentation
|
15
|
+
# and/or other materials provided with the distribution.
|
16
|
+
# * Neither the name of the Ruby FFI project nor the names of its contributors
|
17
|
+
# may be used to endorse or promote products derived from this software
|
18
|
+
# without specific prior written permission.
|
19
|
+
#
|
20
|
+
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
21
|
+
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
22
|
+
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
23
|
+
# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE
|
24
|
+
# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
25
|
+
# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
26
|
+
# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
27
|
+
# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
28
|
+
# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
29
|
+
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
30
|
+
#
|
31
|
+
|
32
|
+
require 'ffi/struct'
|
33
|
+
|
34
|
+
module FFI
|
35
|
+
|
36
|
+
class Union < FFI::Struct
|
37
|
+
def self.builder
|
38
|
+
b = StructLayoutBuilder.new
|
39
|
+
b.union = true
|
40
|
+
b
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
data/lib/ffi/variadic.rb
ADDED
@@ -0,0 +1,80 @@
|
|
1
|
+
#
|
2
|
+
# Copyright (C) 2008, 2009 Wayne Meissner
|
3
|
+
# Copyright (C) 2009 Luc Heinrich
|
4
|
+
#
|
5
|
+
# This file is part of ruby-ffi.
|
6
|
+
#
|
7
|
+
# All rights reserved.
|
8
|
+
#
|
9
|
+
# Redistribution and use in source and binary forms, with or without
|
10
|
+
# modification, are permitted provided that the following conditions are met:
|
11
|
+
#
|
12
|
+
# * Redistributions of source code must retain the above copyright notice, this
|
13
|
+
# list of conditions and the following disclaimer.
|
14
|
+
# * Redistributions in binary form must reproduce the above copyright notice
|
15
|
+
# this list of conditions and the following disclaimer in the documentation
|
16
|
+
# and/or other materials provided with the distribution.
|
17
|
+
# * Neither the name of the Ruby FFI project nor the names of its contributors
|
18
|
+
# may be used to endorse or promote products derived from this software
|
19
|
+
# without specific prior written permission.
|
20
|
+
#
|
21
|
+
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
22
|
+
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
23
|
+
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
24
|
+
# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE
|
25
|
+
# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
26
|
+
# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
27
|
+
# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
28
|
+
# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
29
|
+
# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
30
|
+
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
31
|
+
#
|
32
|
+
|
33
|
+
module FFI
|
34
|
+
class VariadicInvoker
|
35
|
+
def call(*args, &block)
|
36
|
+
param_types = Array.new(@fixed)
|
37
|
+
param_values = Array.new
|
38
|
+
@fixed.each_with_index do |t, i|
|
39
|
+
param_values << args[i]
|
40
|
+
end
|
41
|
+
i = @fixed.length
|
42
|
+
while i < args.length
|
43
|
+
param_types << FFI.find_type(args[i], @type_map)
|
44
|
+
param_values << args[i + 1]
|
45
|
+
i += 2
|
46
|
+
end
|
47
|
+
invoke(param_types, param_values, &block)
|
48
|
+
end
|
49
|
+
|
50
|
+
#
|
51
|
+
# Attach the invoker to module +mod+ as +mname+
|
52
|
+
#
|
53
|
+
def attach(mod, mname)
|
54
|
+
invoker = self
|
55
|
+
params = "*args"
|
56
|
+
call = "call"
|
57
|
+
mname = mname.to_sym
|
58
|
+
mod.module_eval <<-code, __FILE__, __LINE__
|
59
|
+
@ffi_functions = {} unless defined?(@ffi_functions)
|
60
|
+
@ffi_functions[#{mname.inspect}] = invoker
|
61
|
+
|
62
|
+
def self.#{mname}(#{params})
|
63
|
+
@ffi_functions[#{mname.inspect}].#{call}(#{params})
|
64
|
+
end
|
65
|
+
|
66
|
+
define_method(#{mname.inspect}, &method(#{mname.inspect}))
|
67
|
+
code
|
68
|
+
invoker
|
69
|
+
end
|
70
|
+
|
71
|
+
# Retrieve Array of parameter types
|
72
|
+
#
|
73
|
+
# This method returns an Array of FFI types accepted as function parameters.
|
74
|
+
#
|
75
|
+
# @return [Array<FFI::Type>]
|
76
|
+
def param_types
|
77
|
+
[*@fixed, Type::Builtin::VARARGS]
|
78
|
+
end
|
79
|
+
end
|
80
|
+
end
|
data/lib/ffi/version.rb
ADDED
data/lib/ffi.rb
ADDED
@@ -0,0 +1,27 @@
|
|
1
|
+
if RUBY_ENGINE == 'ruby'
|
2
|
+
begin
|
3
|
+
require RUBY_VERSION.split('.')[0, 2].join('.') + '/ffi_c'
|
4
|
+
rescue Exception
|
5
|
+
require 'ffi_c'
|
6
|
+
end
|
7
|
+
|
8
|
+
require 'ffi/ffi'
|
9
|
+
|
10
|
+
elsif RUBY_ENGINE == 'jruby' && (RUBY_ENGINE_VERSION.split('.').map(&:to_i) <=> [9, 2, 20]) >= 0
|
11
|
+
JRuby::Util.load_ext("org.jruby.ext.ffi.FFIService")
|
12
|
+
require 'ffi/ffi'
|
13
|
+
|
14
|
+
elsif RUBY_ENGINE == 'truffleruby' && (RUBY_ENGINE_VERSION.split('.').map(&:to_i) <=> [20, 1, 0]) >= 0
|
15
|
+
require 'truffleruby/ffi_backend'
|
16
|
+
require 'ffi/ffi'
|
17
|
+
|
18
|
+
else
|
19
|
+
# Remove the ffi gem dir from the load path, then reload the internal ffi implementation
|
20
|
+
$LOAD_PATH.delete(File.dirname(__FILE__))
|
21
|
+
$LOAD_PATH.delete(File.join(File.dirname(__FILE__), 'ffi'))
|
22
|
+
unless $LOADED_FEATURES.nil?
|
23
|
+
$LOADED_FEATURES.delete(__FILE__)
|
24
|
+
$LOADED_FEATURES.delete('ffi.rb')
|
25
|
+
end
|
26
|
+
require 'ffi.rb'
|
27
|
+
end
|
@@ -0,0 +1,65 @@
|
|
1
|
+
require 'bundler'
|
2
|
+
require 'bundler/gem_helper'
|
3
|
+
|
4
|
+
class FfiGemHelper < Bundler::GemHelper
|
5
|
+
attr_accessor :cross_platforms
|
6
|
+
|
7
|
+
def install
|
8
|
+
super
|
9
|
+
|
10
|
+
task "release:guard_clean" => ["release:update_history"]
|
11
|
+
|
12
|
+
task "release:update_history" do
|
13
|
+
update_history
|
14
|
+
end
|
15
|
+
|
16
|
+
task "release:rubygem_push" => ["gem:native", "gem:java"]
|
17
|
+
end
|
18
|
+
|
19
|
+
def hfile
|
20
|
+
"CHANGELOG.md"
|
21
|
+
end
|
22
|
+
|
23
|
+
def headline
|
24
|
+
'([^\w]*)(\d+\.\d+\.\d+(?:\.\w+)?)([^\w]+)([2Y][0Y][0-9Y][0-9Y]-[0-1M][0-9M]-[0-3D][0-9D])([^\w]*|$)'
|
25
|
+
end
|
26
|
+
|
27
|
+
def reldate
|
28
|
+
Time.now.strftime("%Y-%m-%d")
|
29
|
+
end
|
30
|
+
|
31
|
+
def update_history
|
32
|
+
hin = File.read(hfile)
|
33
|
+
hout = hin.sub(/#{headline}/) do
|
34
|
+
raise "#{hfile} isn't up-to-date for version #{version}" unless $2==version.to_s
|
35
|
+
$1 + $2 + $3 + reldate + $5
|
36
|
+
end
|
37
|
+
if hout != hin
|
38
|
+
Bundler.ui.confirm "Updating #{hfile} for release."
|
39
|
+
File.write(hfile, hout)
|
40
|
+
Rake::FileUtilsExt.sh "git", "commit", hfile, "-m", "Update release date in #{hfile}"
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
def tag_version
|
45
|
+
Bundler.ui.confirm "Tag release with annotation:"
|
46
|
+
m = File.read(hfile).match(/(?<annotation>#{headline}.*?)#{headline}/m) || raise("Unable to find release notes in #{hfile}")
|
47
|
+
Bundler.ui.info(m[:annotation].gsub(/^/, " "))
|
48
|
+
IO.popen(["git", "tag", "--file=-", version_tag], "w") do |fd|
|
49
|
+
fd.write m[:annotation]
|
50
|
+
end
|
51
|
+
yield if block_given?
|
52
|
+
rescue
|
53
|
+
Bundler.ui.error "Untagging #{version_tag} due to error."
|
54
|
+
sh_with_code "git tag -d #{version_tag}"
|
55
|
+
raise
|
56
|
+
end
|
57
|
+
|
58
|
+
def rubygem_push(path)
|
59
|
+
cross_platforms.each do |ruby_platform|
|
60
|
+
super(path.gsub(/\.gem\z/, "-#{ruby_platform}.gem"))
|
61
|
+
end
|
62
|
+
super(path.gsub(/\.gem\z/, "-java.gem"))
|
63
|
+
super(path)
|
64
|
+
end
|
65
|
+
end
|
data/samples/getlogin.rb
ADDED
data/samples/getpid.rb
ADDED
@@ -0,0 +1,18 @@
|
|
1
|
+
require 'ffi'
|
2
|
+
require 'rbconfig'
|
3
|
+
|
4
|
+
class Timeval < FFI::Struct
|
5
|
+
layout tv_sec: :ulong, tv_usec: :ulong
|
6
|
+
end
|
7
|
+
module LibC
|
8
|
+
extend FFI::Library
|
9
|
+
if FFI::Platform.windows?
|
10
|
+
ffi_lib RbConfig::CONFIG["LIBRUBY_SO"]
|
11
|
+
else
|
12
|
+
ffi_lib FFI::Library::LIBC
|
13
|
+
end
|
14
|
+
attach_function :gettimeofday, [ :pointer, :pointer ], :int
|
15
|
+
end
|
16
|
+
t = Timeval.new
|
17
|
+
LibC.gettimeofday(t.pointer, nil)
|
18
|
+
puts "t.tv_sec=#{t[:tv_sec]} t.tv_usec=#{t[:tv_usec]}"
|
data/samples/hello.rb
ADDED
data/samples/inotify.rb
ADDED
@@ -0,0 +1,60 @@
|
|
1
|
+
require 'ffi'
|
2
|
+
|
3
|
+
module Inotify
|
4
|
+
extend FFI::Library
|
5
|
+
ffi_lib FFI::Library::LIBC
|
6
|
+
class Event < FFI::Struct
|
7
|
+
layout \
|
8
|
+
:wd, :int,
|
9
|
+
:mask, :uint,
|
10
|
+
:cookie, :uint,
|
11
|
+
:len, :uint
|
12
|
+
end
|
13
|
+
attach_function :init, :inotify_init, [ ], :int
|
14
|
+
attach_function :add_watch, :inotify_add_watch, [ :int, :string, :uint ], :int
|
15
|
+
attach_function :rm_watch, :inotify_rm_watch, [ :int, :uint ], :int
|
16
|
+
attach_function :read, [ :int, :buffer_out, :uint ], :int
|
17
|
+
IN_ACCESS=0x00000001
|
18
|
+
IN_MODIFY=0x00000002
|
19
|
+
IN_ATTRIB=0x00000004
|
20
|
+
IN_CLOSE_WRITE=0x00000008
|
21
|
+
IN_CLOSE_NOWRITE=0x00000010
|
22
|
+
IN_CLOSE=(IN_CLOSE_WRITE | IN_CLOSE_NOWRITE)
|
23
|
+
IN_OPEN=0x00000020
|
24
|
+
IN_MOVED_FROM=0x00000040
|
25
|
+
IN_MOVED_TO=0x00000080
|
26
|
+
IN_MOVE= (IN_MOVED_FROM | IN_MOVED_TO)
|
27
|
+
IN_CREATE=0x00000100
|
28
|
+
IN_DELETE=0x00000200
|
29
|
+
IN_DELETE_SELF=0x00000400
|
30
|
+
IN_MOVE_SELF=0x00000800
|
31
|
+
# Events sent by the kernel.
|
32
|
+
IN_UNMOUNT=0x00002000
|
33
|
+
IN_Q_OVERFLOW=0x00004000
|
34
|
+
IN_IGNORED=0x00008000
|
35
|
+
IN_ONLYDIR=0x01000000
|
36
|
+
IN_DONT_FOLLOW=0x02000000
|
37
|
+
IN_MASK_ADD=0x20000000
|
38
|
+
IN_ISDIR=0x40000000
|
39
|
+
IN_ONESHOT=0x80000000
|
40
|
+
IN_ALL_EVENTS=(IN_ACCESS | IN_MODIFY | IN_ATTRIB | IN_CLOSE_WRITE \
|
41
|
+
| IN_CLOSE_NOWRITE | IN_OPEN | IN_MOVED_FROM \
|
42
|
+
| IN_MOVED_TO | IN_CREATE | IN_DELETE \
|
43
|
+
| IN_DELETE_SELF | IN_MOVE_SELF)
|
44
|
+
|
45
|
+
end
|
46
|
+
if $0 == __FILE__
|
47
|
+
fd = Inotify.init
|
48
|
+
puts "fd=#{fd}"
|
49
|
+
wd = Inotify.add_watch(fd, "/tmp/", Inotify::IN_ALL_EVENTS)
|
50
|
+
fp = FFI::IO.for_fd(fd)
|
51
|
+
puts "wfp=#{fp}"
|
52
|
+
while true
|
53
|
+
buf = FFI::Buffer.alloc_out(Inotify::Event.size + 4096, 1, false)
|
54
|
+
ev = Inotify::Event.new buf
|
55
|
+
ready = IO.select([ fp ], nil, nil, nil)
|
56
|
+
n = Inotify.read(fd, buf, buf.total)
|
57
|
+
puts "Read #{n} bytes from inotify fd"
|
58
|
+
puts "event.wd=#{ev[:wd]} mask=#{ev[:mask]} len=#{ev[:len]} name=#{ev[:len] > 0 ? buf.get_string(16) : 'unknown'}"
|
59
|
+
end
|
60
|
+
end
|
data/samples/pty.rb
ADDED
@@ -0,0 +1,75 @@
|
|
1
|
+
require 'ffi'
|
2
|
+
|
3
|
+
module PTY
|
4
|
+
private
|
5
|
+
module LibC
|
6
|
+
extend FFI::Library
|
7
|
+
ffi_lib FFI::Library::LIBC
|
8
|
+
attach_function :forkpty, [ :buffer_out, :buffer_out, :buffer_in, :buffer_in ], :int
|
9
|
+
attach_function :openpty, [ :buffer_out, :buffer_out, :buffer_out, :buffer_in, :buffer_in ], :int
|
10
|
+
attach_function :login_tty, [ :int ], :int
|
11
|
+
attach_function :close, [ :int ], :int
|
12
|
+
attach_function :strerror, [ :int ], :string
|
13
|
+
attach_function :fork, [], :int
|
14
|
+
attach_function :execv, [ :string, :buffer_in ], :int
|
15
|
+
attach_function :execvp, [ :string, :buffer_in ], :int
|
16
|
+
attach_function :dup2, [ :int, :int ], :int
|
17
|
+
attach_function :dup, [ :int ], :int
|
18
|
+
end
|
19
|
+
Buffer = FFI::Buffer
|
20
|
+
def self.build_args(args)
|
21
|
+
cmd = args.shift
|
22
|
+
cmd_args = args.map do |arg|
|
23
|
+
MemoryPointer.from_string(arg)
|
24
|
+
end
|
25
|
+
exec_args = MemoryPointer.new(:pointer, 1 + cmd_args.length + 1)
|
26
|
+
exec_cmd = MemoryPointer.from_string(cmd)
|
27
|
+
exec_args[0].put_pointer(0, exec_cmd)
|
28
|
+
cmd_args.each_with_index do |arg, i|
|
29
|
+
exec_args[i + 1].put_pointer(0, arg)
|
30
|
+
end
|
31
|
+
[ cmd, exec_args ]
|
32
|
+
end
|
33
|
+
public
|
34
|
+
def self.getpty(*args)
|
35
|
+
mfdp = Buffer.new :int
|
36
|
+
name = Buffer.new 1024
|
37
|
+
#
|
38
|
+
# All the execv setup is done in the parent, since doing anything other than
|
39
|
+
# execv in the child after fork is really flakey
|
40
|
+
#
|
41
|
+
exec_cmd, exec_args = build_args(args)
|
42
|
+
pid = LibC.forkpty(mfdp, name, nil, nil)
|
43
|
+
raise "forkpty failed: #{LibC.strerror(FFI.errno)}" if pid < 0
|
44
|
+
if pid == 0
|
45
|
+
LibC.execvp(exec_cmd, exec_args)
|
46
|
+
exit 1
|
47
|
+
end
|
48
|
+
masterfd = mfdp.get_int(0)
|
49
|
+
rfp = FFI::IO.for_fd(masterfd, "r")
|
50
|
+
wfp = FFI::IO.for_fd(LibC.dup(masterfd), "w")
|
51
|
+
if block_given?
|
52
|
+
yield rfp, wfp, pid
|
53
|
+
rfp.close unless rfp.closed?
|
54
|
+
wfp.close unless wfp.closed?
|
55
|
+
else
|
56
|
+
[ rfp, wfp, pid ]
|
57
|
+
end
|
58
|
+
end
|
59
|
+
def self.spawn(*args, &block)
|
60
|
+
self.getpty("/bin/sh", "-c", args[0], &block)
|
61
|
+
end
|
62
|
+
end
|
63
|
+
module LibC
|
64
|
+
extend FFI::Library
|
65
|
+
attach_function :close, [ :int ], :int
|
66
|
+
attach_function :write, [ :int, :buffer_in, :ulong ], :long
|
67
|
+
attach_function :read, [ :int, :buffer_out, :ulong ], :long
|
68
|
+
end
|
69
|
+
PTY.getpty("/bin/ls", "-alR", "/") { |rfd, wfd, pid|
|
70
|
+
#PTY.spawn("ls -laR /") { |rfd, wfd, pid|
|
71
|
+
puts "child pid=#{pid}"
|
72
|
+
while !rfd.eof? && (buf = rfd.gets)
|
73
|
+
puts "child: '#{buf.strip}'"
|
74
|
+
end
|
75
|
+
}
|
data/samples/qsort.rb
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
require 'ffi'
|
2
|
+
|
3
|
+
module LibC
|
4
|
+
extend FFI::Library
|
5
|
+
ffi_lib FFI::Library::LIBC
|
6
|
+
callback :qsort_cmp, [ :pointer, :pointer ], :int
|
7
|
+
attach_function :qsort, [ :pointer, :ulong, :ulong, :qsort_cmp ], :int
|
8
|
+
end
|
9
|
+
|
10
|
+
p = FFI::MemoryPointer.new(:int, 2)
|
11
|
+
p.put_array_of_int32(0, [ 2, 1 ])
|
12
|
+
puts "ptr=#{p.inspect}"
|
13
|
+
puts "Before qsort #{p.get_array_of_int32(0, 2).join(', ')}"
|
14
|
+
LibC.qsort(p, 2, 4) do |p1, p2|
|
15
|
+
i1 = p1.get_int32(0)
|
16
|
+
i2 = p2.get_int32(0)
|
17
|
+
puts "In block: comparing #{i1} and #{i2}"
|
18
|
+
i1 < i2 ? -1 : i1 > i2 ? 1 : 0
|
19
|
+
end
|
20
|
+
puts "After qsort #{p.get_array_of_int32(0, 2).join(', ')}"
|
@@ -0,0 +1,28 @@
|
|
1
|
+
require 'ffi'
|
2
|
+
|
3
|
+
module LibC
|
4
|
+
extend FFI::Library
|
5
|
+
ffi_lib FFI::Library::LIBC
|
6
|
+
callback :qsort_cmp, [ :pointer, :pointer ], :int
|
7
|
+
attach_function :qsort, [ :pointer, :ulong, :ulong, :qsort_cmp ], :int
|
8
|
+
|
9
|
+
freeze # Freeze the module variables, so that it can be shared across ractors.
|
10
|
+
end
|
11
|
+
|
12
|
+
p = FFI::MemoryPointer.new(:int, 3)
|
13
|
+
p.put_array_of_int32(0, [ 2, 3, 1 ]) # Write some unsorted data into the memory
|
14
|
+
# Ractor.make_shareable(p) # freeze the pointer to be shared between ractors instead of copied
|
15
|
+
puts "main -ptr=#{p.inspect}"
|
16
|
+
res = Ractor.new(p) do |p|
|
17
|
+
puts "ractor-ptr=#{p.inspect}"
|
18
|
+
puts "Before qsort #{p.get_array_of_int32(0, 3).join(', ')}"
|
19
|
+
LibC.qsort(p, 3, 4) do |p1, p2|
|
20
|
+
i1 = p1.get_int32(0)
|
21
|
+
i2 = p2.get_int32(0)
|
22
|
+
puts "In block: comparing #{i1} and #{i2}"
|
23
|
+
i1 < i2 ? -1 : i1 > i2 ? 1 : 0
|
24
|
+
end
|
25
|
+
puts "After qsort #{p.get_array_of_int32(0, 3).join(', ')}"
|
26
|
+
end.take
|
27
|
+
|
28
|
+
puts "After ractor termination #{p.get_array_of_int32(0, 3).join(', ')}"
|
@@ -0,0 +1,164 @@
|
|
1
|
+
module FFI
|
2
|
+
class AbstractMemory
|
3
|
+
interface _Size
|
4
|
+
def size: () -> Integer
|
5
|
+
end
|
6
|
+
include _Size
|
7
|
+
type type_size = Integer | _Size | Symbol
|
8
|
+
|
9
|
+
type order_out = :big | :little
|
10
|
+
type order_in = order_out | :network
|
11
|
+
|
12
|
+
def []: (Integer idx) -> instance
|
13
|
+
def clear: () -> self
|
14
|
+
def freeze: ...
|
15
|
+
def get: (ffi_type type, Integer offset) -> top
|
16
|
+
def put: (ffi_type type, Integer offset, top value) -> nil
|
17
|
+
def size_limit?: () -> bool
|
18
|
+
def type_size: () -> Integer
|
19
|
+
alias total size
|
20
|
+
|
21
|
+
def get_int8: (Integer offset) -> Integer
|
22
|
+
def get_int16: (Integer offset) -> Integer
|
23
|
+
def get_int32: (Integer offset) -> Integer
|
24
|
+
def get_int64: (Integer offset) -> Integer
|
25
|
+
def get_uint8: (Integer offset) -> Integer
|
26
|
+
def get_uint16: (Integer offset) -> Integer
|
27
|
+
def get_uint32: (Integer offset) -> Integer
|
28
|
+
def get_uint64: (Integer offset) -> Integer
|
29
|
+
def get_char: (Integer offset) -> Integer
|
30
|
+
def get_short: (Integer offset) -> Integer
|
31
|
+
def get_int: (Integer offset) -> Integer
|
32
|
+
def get_long_long: (Integer offset) -> Integer
|
33
|
+
def get_float32: (Integer offset) -> Float
|
34
|
+
def get_float64: (Integer offset) -> Float
|
35
|
+
def get_pointer: (Integer offset) -> Pointer
|
36
|
+
def get_bytes: (Integer offset, Integer length) -> String
|
37
|
+
def get_string: (Integer offset, ?Integer? length) -> String
|
38
|
+
alias get_float get_float32
|
39
|
+
alias get_double get_float64
|
40
|
+
|
41
|
+
def put_int8: (Integer offset, int value) -> self
|
42
|
+
def put_int16: (Integer offset, int value) -> self
|
43
|
+
def put_int32: (Integer offset, int value) -> self
|
44
|
+
def put_int64: (Integer offset, int value) -> self
|
45
|
+
def put_uint8: (Integer offset, int value) -> self
|
46
|
+
def put_uint16: (Integer offset, int value) -> self
|
47
|
+
def put_uint32: (Integer offset, int value) -> self
|
48
|
+
def put_uint64: (Integer offset, int value) -> self
|
49
|
+
def put_char: (Integer offset, int value) -> self
|
50
|
+
def put_short: (Integer offset, int value) -> self
|
51
|
+
def put_int: (Integer offset, int value) -> self
|
52
|
+
def put_long_long: (Integer offset, int value) -> self
|
53
|
+
def put_float32: (Integer offset, Numeric value) -> self
|
54
|
+
def put_float64: (Integer offset, Numeric value) -> self
|
55
|
+
def put_pointer: (Integer offset, pointer value) -> self
|
56
|
+
def put_bytes: (Integer offset, String str, ?Integer index, ?Integer? length) -> self
|
57
|
+
def put_string: (Integer offset, String value) -> self
|
58
|
+
alias put_float put_float32
|
59
|
+
alias put_double put_float64
|
60
|
+
|
61
|
+
def read_int8: () -> Integer
|
62
|
+
def read_int16: () -> Integer
|
63
|
+
def read_int32: () -> Integer
|
64
|
+
def read_int64: () -> Integer
|
65
|
+
def read_uint8: () -> Integer
|
66
|
+
def read_uint16: () -> Integer
|
67
|
+
def read_uint32: () -> Integer
|
68
|
+
def read_uint64: () -> Integer
|
69
|
+
def read_char: () -> Integer
|
70
|
+
def read_short: () -> Integer
|
71
|
+
def read_int: () -> Integer
|
72
|
+
def read_long_long: () -> Integer
|
73
|
+
def read_float: () -> Float
|
74
|
+
def read_double: () -> Float
|
75
|
+
def read_pointer: () -> Pointer
|
76
|
+
def read_bytes: (Integer length) -> String
|
77
|
+
|
78
|
+
def write_int8: (int value) -> self
|
79
|
+
def write_int16: (int value) -> self
|
80
|
+
def write_int32: (int value) -> self
|
81
|
+
def write_int64: (int value) -> self
|
82
|
+
def write_uint8: (int value) -> self
|
83
|
+
def write_uint16: (int value) -> self
|
84
|
+
def write_uint32: (int value) -> self
|
85
|
+
def write_uint64: (int value) -> self
|
86
|
+
def write_char: (int value) -> self
|
87
|
+
def write_short: (int value) -> self
|
88
|
+
def write_int: (int value) -> self
|
89
|
+
def write_long_long: (int value) -> self
|
90
|
+
def write_float: (Numeric value) -> self
|
91
|
+
def write_double: (Numeric value) -> self
|
92
|
+
def write_pointer: (pointer value) -> self
|
93
|
+
def write_bytes: (String str, ?Integer index, ?Integer? length) -> self
|
94
|
+
|
95
|
+
def get_array_of_int8: (Integer offset, Integer length) -> Array[Integer]
|
96
|
+
def get_array_of_int16: (Integer offset, Integer length) -> Array[Integer]
|
97
|
+
def get_array_of_int32: (Integer offset, Integer length) -> Array[Integer]
|
98
|
+
def get_array_of_int64: (Integer offset, Integer length) -> Array[Integer]
|
99
|
+
def get_array_of_uint8: (Integer offset, Integer length) -> Array[Integer]
|
100
|
+
def get_array_of_uint16: (Integer offset, Integer length) -> Array[Integer]
|
101
|
+
def get_array_of_uint32: (Integer offset, Integer length) -> Array[Integer]
|
102
|
+
def get_array_of_uint64: (Integer offset, Integer length) -> Array[Integer]
|
103
|
+
def get_array_of_char: (Integer offset, Integer length) -> Array[Integer]
|
104
|
+
def get_array_of_short: (Integer offset, Integer length) -> Array[Integer]
|
105
|
+
def get_array_of_int: (Integer offset, Integer length) -> Array[Integer]
|
106
|
+
def get_array_of_long_long: (Integer offset, Integer length) -> Array[Integer]
|
107
|
+
def get_array_of_float32: (Integer offset, Integer length) -> Array[Float]
|
108
|
+
def get_array_of_float64: (Integer offset, Integer length) -> Array[Float]
|
109
|
+
def get_array_of_pointer: (Integer offset, Integer length) -> Array[Pointer]
|
110
|
+
def get_array_of_string: (Integer offset, ?Integer? count) -> Array[String?]
|
111
|
+
alias get_array_of_float get_array_of_float32
|
112
|
+
alias get_array_of_double get_array_of_float64
|
113
|
+
|
114
|
+
def put_array_of_int8: (Integer offset, Array[int] ary) -> self
|
115
|
+
def put_array_of_int16: (Integer offset, Array[int] ary) -> self
|
116
|
+
def put_array_of_int32: (Integer offset, Array[int] ary) -> self
|
117
|
+
def put_array_of_int64: (Integer offset, Array[int] ary) -> self
|
118
|
+
def put_array_of_uint8: (Integer offset, Array[int] ary) -> self
|
119
|
+
def put_array_of_uint16: (Integer offset, Array[int] ary) -> self
|
120
|
+
def put_array_of_uint32: (Integer offset, Array[int] ary) -> self
|
121
|
+
def put_array_of_uint64: (Integer offset, Array[int] ary) -> self
|
122
|
+
def put_array_of_char: (Integer offset, Array[int] ary) -> self
|
123
|
+
def put_array_of_short: (Integer offset, Array[int] ary) -> self
|
124
|
+
def put_array_of_int: (Integer offset, Array[int] ary) -> self
|
125
|
+
def put_array_of_long_long: (Integer offset, Array[int] ary) -> self
|
126
|
+
def put_array_of_float32: (Integer offset, Array[Numeric] ary) -> self
|
127
|
+
def put_array_of_float64: (Integer offset, Array[Numeric] ary) -> self
|
128
|
+
def put_array_of_pointer: (Integer offset, Array[pointer] ary) -> self
|
129
|
+
alias put_array_of_float put_array_of_float32
|
130
|
+
alias put_array_of_double put_array_of_float64
|
131
|
+
|
132
|
+
def read_array_of_int8: (Integer length) -> Array[Integer]
|
133
|
+
def read_array_of_int16: (Integer length) -> Array[Integer]
|
134
|
+
def read_array_of_int32: (Integer length) -> Array[Integer]
|
135
|
+
def read_array_of_int64: (Integer length) -> Array[Integer]
|
136
|
+
def read_array_of_uint8: (Integer length) -> Array[Integer]
|
137
|
+
def read_array_of_uint16: (Integer length) -> Array[Integer]
|
138
|
+
def read_array_of_uint32: (Integer length) -> Array[Integer]
|
139
|
+
def read_array_of_uint64: (Integer length) -> Array[Integer]
|
140
|
+
def read_array_of_char: (Integer length) -> Array[Integer]
|
141
|
+
def read_array_of_short: (Integer length) -> Array[Integer]
|
142
|
+
def read_array_of_int: (Integer length) -> Array[Integer]
|
143
|
+
def read_array_of_long_long: (Integer length) -> Array[Integer]
|
144
|
+
def read_array_of_float: (Integer length) -> Array[Float]
|
145
|
+
def read_array_of_double: (Integer length) -> Array[Float]
|
146
|
+
def read_array_of_pointer: (Integer length) -> Array[Pointer]
|
147
|
+
|
148
|
+
def write_array_of_int8: (Array[int] ary) -> self
|
149
|
+
def write_array_of_int16: (Array[int] ary) -> self
|
150
|
+
def write_array_of_int32: (Array[int] ary) -> self
|
151
|
+
def write_array_of_int64: (Array[int] ary) -> self
|
152
|
+
def write_array_of_uint8: (Array[int] ary) -> self
|
153
|
+
def write_array_of_uint16: (Array[int] ary) -> self
|
154
|
+
def write_array_of_uint32: (Array[int] ary) -> self
|
155
|
+
def write_array_of_uint64: (Array[int] ary) -> self
|
156
|
+
def write_array_of_char: (Array[int] ary) -> self
|
157
|
+
def write_array_of_short: (Array[int] ary) -> self
|
158
|
+
def write_array_of_int: (Array[int] ary) -> self
|
159
|
+
def write_array_of_long_long: (Array[int] ary) -> self
|
160
|
+
def write_array_of_float: (Array[Numeric] ary) -> self
|
161
|
+
def write_array_of_double: (Array[Numeric] ary) -> self
|
162
|
+
def write_array_of_pointer: (Array[pointer] ary) -> self
|
163
|
+
end
|
164
|
+
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
module FFI
|
2
|
+
class AutoPointer < Pointer
|
3
|
+
class Releaser
|
4
|
+
attr_accessor autorelease: boolish
|
5
|
+
interface _Proc[P < Pointer]
|
6
|
+
def call: (P) -> void
|
7
|
+
end
|
8
|
+
def initialize: [P < Pointer] (P ptr, _Proc[P] proc) -> void
|
9
|
+
|
10
|
+
def call: (*untyped) -> void
|
11
|
+
def free: () -> nil
|
12
|
+
def release: (Pointer ptr) -> void
|
13
|
+
end
|
14
|
+
|
15
|
+
def initialize: (Pointer pointer, Method | ^(self) -> void | Releaser::_Proc[self] callable) -> self
|
16
|
+
# | (Pointer pointer) { (self) -> void } -> self # https://github.com/ffi/ffi/issues/1071
|
17
|
+
| (Pointer pointer) -> self # where class < `def self.release: (instance pointer) -> void`
|
18
|
+
|
19
|
+
extend DataConverter[Pointer, instance, nil]
|
20
|
+
def self.from_native: ...
|
21
|
+
def self.native_type: () -> Type::Builtin
|
22
|
+
|
23
|
+
def autorelease?: ...
|
24
|
+
def autorelease=: ...
|
25
|
+
def free: () -> nil
|
26
|
+
end
|
27
|
+
end
|
data/sig/ffi/buffer.rbs
ADDED
@@ -0,0 +1,18 @@
|
|
1
|
+
module FFI
|
2
|
+
class Buffer < AbstractMemory
|
3
|
+
def initialize: (AbstractMemory::type_size, ?Integer count, boolish clear) -> self
|
4
|
+
alias self.alloc_inout self.new
|
5
|
+
alias self.new_inout self.alloc_inout
|
6
|
+
alias self.alloc_in self.alloc_inout
|
7
|
+
alias self.new_in self.alloc_in
|
8
|
+
alias self.alloc_out self.alloc_inout
|
9
|
+
alias self.new_out self.alloc_out
|
10
|
+
|
11
|
+
def +: (Integer) -> Buffer
|
12
|
+
def inspect: ...
|
13
|
+
def order: () -> AbstractMemory::order_out
|
14
|
+
| (AbstractMemory::order_in order) -> Buffer
|
15
|
+
| (untyped order) -> (self | Buffer)
|
16
|
+
def slice: (Integer offset, Integer length) -> Buffer
|
17
|
+
end
|
18
|
+
end
|