ffi 1.17.0.rc1-x86_64-darwin

Sign up to get free protection for your applications and to get access to all the features.
Files changed (134) hide show
  1. checksums.yaml +7 -0
  2. data/CHANGELOG.md +442 -0
  3. data/COPYING +49 -0
  4. data/Gemfile +21 -0
  5. data/LICENSE +24 -0
  6. data/LICENSE.SPECS +22 -0
  7. data/README.md +137 -0
  8. data/Rakefile +206 -0
  9. data/ffi.gemspec +42 -0
  10. data/lib/2.5/ffi_c.bundle +0 -0
  11. data/lib/2.6/ffi_c.bundle +0 -0
  12. data/lib/2.7/ffi_c.bundle +0 -0
  13. data/lib/3.0/ffi_c.bundle +0 -0
  14. data/lib/3.1/ffi_c.bundle +0 -0
  15. data/lib/3.2/ffi_c.bundle +0 -0
  16. data/lib/3.3/ffi_c.bundle +0 -0
  17. data/lib/ffi/abstract_memory.rb +44 -0
  18. data/lib/ffi/autopointer.rb +188 -0
  19. data/lib/ffi/buffer.rb +4 -0
  20. data/lib/ffi/callback.rb +4 -0
  21. data/lib/ffi/compat.rb +43 -0
  22. data/lib/ffi/data_converter.rb +67 -0
  23. data/lib/ffi/dynamic_library.rb +118 -0
  24. data/lib/ffi/enum.rb +302 -0
  25. data/lib/ffi/errno.rb +43 -0
  26. data/lib/ffi/ffi.rb +50 -0
  27. data/lib/ffi/function.rb +71 -0
  28. data/lib/ffi/io.rb +62 -0
  29. data/lib/ffi/library.rb +576 -0
  30. data/lib/ffi/library_path.rb +109 -0
  31. data/lib/ffi/managedstruct.rb +84 -0
  32. data/lib/ffi/memorypointer.rb +1 -0
  33. data/lib/ffi/platform/aarch64-darwin/types.conf +130 -0
  34. data/lib/ffi/platform/aarch64-freebsd/types.conf +128 -0
  35. data/lib/ffi/platform/aarch64-freebsd12/types.conf +181 -0
  36. data/lib/ffi/platform/aarch64-linux/types.conf +175 -0
  37. data/lib/ffi/platform/aarch64-openbsd/types.conf +134 -0
  38. data/lib/ffi/platform/aarch64-windows/types.conf +52 -0
  39. data/lib/ffi/platform/arm-freebsd/types.conf +152 -0
  40. data/lib/ffi/platform/arm-freebsd12/types.conf +152 -0
  41. data/lib/ffi/platform/arm-linux/types.conf +132 -0
  42. data/lib/ffi/platform/hppa1.1-linux/types.conf +178 -0
  43. data/lib/ffi/platform/hppa2.0-linux/types.conf +178 -0
  44. data/lib/ffi/platform/i386-cygwin/types.conf +3 -0
  45. data/lib/ffi/platform/i386-darwin/types.conf +100 -0
  46. data/lib/ffi/platform/i386-freebsd/types.conf +152 -0
  47. data/lib/ffi/platform/i386-freebsd12/types.conf +152 -0
  48. data/lib/ffi/platform/i386-gnu/types.conf +107 -0
  49. data/lib/ffi/platform/i386-linux/types.conf +103 -0
  50. data/lib/ffi/platform/i386-netbsd/types.conf +126 -0
  51. data/lib/ffi/platform/i386-openbsd/types.conf +128 -0
  52. data/lib/ffi/platform/i386-solaris/types.conf +122 -0
  53. data/lib/ffi/platform/i386-windows/types.conf +52 -0
  54. data/lib/ffi/platform/ia64-linux/types.conf +104 -0
  55. data/lib/ffi/platform/loongarch64-linux/types.conf +141 -0
  56. data/lib/ffi/platform/mips-linux/types.conf +102 -0
  57. data/lib/ffi/platform/mips64-linux/types.conf +104 -0
  58. data/lib/ffi/platform/mips64el-linux/types.conf +104 -0
  59. data/lib/ffi/platform/mipsel-linux/types.conf +102 -0
  60. data/lib/ffi/platform/mipsisa32r6-linux/types.conf +102 -0
  61. data/lib/ffi/platform/mipsisa32r6el-linux/types.conf +102 -0
  62. data/lib/ffi/platform/mipsisa64r6-linux/types.conf +104 -0
  63. data/lib/ffi/platform/mipsisa64r6el-linux/types.conf +104 -0
  64. data/lib/ffi/platform/powerpc-aix/types.conf +180 -0
  65. data/lib/ffi/platform/powerpc-darwin/types.conf +100 -0
  66. data/lib/ffi/platform/powerpc-linux/types.conf +130 -0
  67. data/lib/ffi/platform/powerpc-openbsd/types.conf +156 -0
  68. data/lib/ffi/platform/powerpc64-linux/types.conf +104 -0
  69. data/lib/ffi/platform/powerpc64le-linux/types.conf +100 -0
  70. data/lib/ffi/platform/riscv64-linux/types.conf +104 -0
  71. data/lib/ffi/platform/s390-linux/types.conf +102 -0
  72. data/lib/ffi/platform/s390x-linux/types.conf +102 -0
  73. data/lib/ffi/platform/sparc-linux/types.conf +102 -0
  74. data/lib/ffi/platform/sparc-solaris/types.conf +128 -0
  75. data/lib/ffi/platform/sparcv9-linux/types.conf +102 -0
  76. data/lib/ffi/platform/sparcv9-openbsd/types.conf +156 -0
  77. data/lib/ffi/platform/sparcv9-solaris/types.conf +128 -0
  78. data/lib/ffi/platform/sw_64-linux/types.conf +141 -0
  79. data/lib/ffi/platform/x86_64-cygwin/types.conf +3 -0
  80. data/lib/ffi/platform/x86_64-darwin/types.conf +130 -0
  81. data/lib/ffi/platform/x86_64-dragonflybsd/types.conf +130 -0
  82. data/lib/ffi/platform/x86_64-freebsd/types.conf +128 -0
  83. data/lib/ffi/platform/x86_64-freebsd12/types.conf +158 -0
  84. data/lib/ffi/platform/x86_64-haiku/types.conf +117 -0
  85. data/lib/ffi/platform/x86_64-linux/types.conf +132 -0
  86. data/lib/ffi/platform/x86_64-msys/types.conf +119 -0
  87. data/lib/ffi/platform/x86_64-netbsd/types.conf +128 -0
  88. data/lib/ffi/platform/x86_64-openbsd/types.conf +134 -0
  89. data/lib/ffi/platform/x86_64-solaris/types.conf +122 -0
  90. data/lib/ffi/platform/x86_64-windows/types.conf +52 -0
  91. data/lib/ffi/platform.rb +187 -0
  92. data/lib/ffi/pointer.rb +167 -0
  93. data/lib/ffi/struct.rb +317 -0
  94. data/lib/ffi/struct_by_reference.rb +72 -0
  95. data/lib/ffi/struct_layout.rb +96 -0
  96. data/lib/ffi/struct_layout_builder.rb +227 -0
  97. data/lib/ffi/tools/const_generator.rb +232 -0
  98. data/lib/ffi/tools/generator.rb +105 -0
  99. data/lib/ffi/tools/generator_task.rb +32 -0
  100. data/lib/ffi/tools/struct_generator.rb +195 -0
  101. data/lib/ffi/tools/types_generator.rb +137 -0
  102. data/lib/ffi/types.rb +222 -0
  103. data/lib/ffi/union.rb +43 -0
  104. data/lib/ffi/variadic.rb +80 -0
  105. data/lib/ffi/version.rb +3 -0
  106. data/lib/ffi.rb +27 -0
  107. data/rakelib/ffi_gem_helper.rb +65 -0
  108. data/samples/getlogin.rb +8 -0
  109. data/samples/getpid.rb +8 -0
  110. data/samples/gettimeofday.rb +18 -0
  111. data/samples/hello.rb +8 -0
  112. data/samples/hello_ractor.rb +11 -0
  113. data/samples/inotify.rb +60 -0
  114. data/samples/pty.rb +75 -0
  115. data/samples/qsort.rb +20 -0
  116. data/samples/qsort_ractor.rb +28 -0
  117. data/sig/ffi/abstract_memory.rbs +164 -0
  118. data/sig/ffi/auto_pointer.rbs +27 -0
  119. data/sig/ffi/buffer.rbs +18 -0
  120. data/sig/ffi/data_converter.rbs +10 -0
  121. data/sig/ffi/dynamic_library.rbs +9 -0
  122. data/sig/ffi/enum.rbs +38 -0
  123. data/sig/ffi/function.rbs +39 -0
  124. data/sig/ffi/library.rbs +42 -0
  125. data/sig/ffi/native_type.rbs +86 -0
  126. data/sig/ffi/pointer.rbs +42 -0
  127. data/sig/ffi/struct.rbs +76 -0
  128. data/sig/ffi/struct_by_reference.rbs +11 -0
  129. data/sig/ffi/struct_by_value.rbs +7 -0
  130. data/sig/ffi/struct_layout.rbs +9 -0
  131. data/sig/ffi/struct_layout_builder.rbs +5 -0
  132. data/sig/ffi/type.rbs +39 -0
  133. data/sig/ffi.rbs +26 -0
  134. metadata +241 -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
@@ -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
@@ -0,0 +1,3 @@
1
+ module FFI
2
+ VERSION = '1.17.0.rc1'
3
+ end
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
@@ -0,0 +1,8 @@
1
+ require 'ffi'
2
+
3
+ module Foo
4
+ extend FFI::Library
5
+ ffi_lib FFI::Library::LIBC
6
+ attach_function :getlogin, [ ], :string
7
+ end
8
+ puts "getlogin=#{Foo.getlogin}"
data/samples/getpid.rb ADDED
@@ -0,0 +1,8 @@
1
+ require 'ffi'
2
+
3
+ module Foo
4
+ extend FFI::Library
5
+ ffi_lib FFI::Library::LIBC
6
+ attach_function :getpid, [ ], :int
7
+ end
8
+ puts "My pid=#{Foo.getpid}"
@@ -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
@@ -0,0 +1,8 @@
1
+ require 'ffi'
2
+
3
+ module Foo
4
+ extend FFI::Library
5
+ ffi_lib FFI::Library::LIBC
6
+ attach_function("cputs", "puts", [ :string ], :int)
7
+ end
8
+ Foo.cputs("Hello, World via libc puts using FFI on MRI ruby")
@@ -0,0 +1,11 @@
1
+ require 'ffi'
2
+
3
+ module Foo
4
+ extend FFI::Library
5
+ ffi_lib FFI::Library::LIBC
6
+ attach_function("cputs", "puts", [ :string ], :int)
7
+ freeze
8
+ end
9
+ Ractor.new do
10
+ Foo.cputs("Hello, World via libc puts using FFI in a Ractor")
11
+ end.take
@@ -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
@@ -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