Class: Seccomp::Notify::Supervisor
- Inherits:
-
Object
- Object
- Seccomp::Notify::Supervisor
- Defined in:
- lib/seccomp/notify/supervisor.rb
Constant Summary collapse
- USER_OPTIONS =
%i[poll_interval default_errno timeout concurrency features].freeze
- EXPECTED_SIZES =
{notif: Structs::NOTIF_SIZE, resp: Structs::RESPONSE_SIZE, data: 64}.freeze
Instance Attribute Summary collapse
-
#listener ⇒ Object
readonly
Returns the value of attribute listener.
-
#target_pid ⇒ Object
readonly
Returns the value of attribute target_pid.
Class Method Summary collapse
Instance Method Summary collapse
-
#initialize(listener, target_pid: nil, target_child: nil, poll_interval: 0.1, default_errno: Errno::EPERM, timeout: nil, concurrency: 1, features: Notify.features, health_writer: nil) ⇒ Supervisor
constructor
A new instance of Supervisor.
-
#on(syscall) {|request| ... } ⇒ Supervisor
Registers a handler for a notified syscall.
-
#on_error {|error, request| ... } ⇒ Supervisor
Registers an exception callback.
-
#on_unknown {|request| ... } ⇒ Supervisor
Registers the fallback handler for unregistered syscalls.
-
#run ⇒ Process::Status?
Runs until the target exits and returns its process status when available.
- #stop ⇒ Object
Constructor Details
#initialize(listener, target_pid: nil, target_child: nil, poll_interval: 0.1, default_errno: Errno::EPERM, timeout: nil, concurrency: 1, features: Notify.features, health_writer: nil) ⇒ Supervisor
Returns a new instance of Supervisor.
37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 |
# File 'lib/seccomp/notify/supervisor.rb', line 37 def initialize(listener, target_pid: nil, target_child: nil, poll_interval: 0.1, default_errno: Errno::EPERM, timeout: nil, concurrency: 1, features: Notify.features, health_writer: nil) self.class.(poll_interval:, default_errno:, timeout:, concurrency:, features:) @listener = listener @target_pid = target_pid @target_child = target_child @poll_interval = poll_interval @default_errno = default_errno @timeout = timeout @concurrency = concurrency @features = features @health_writer = health_writer @sizes = Notify.notif_sizes raise NotSupportedError, "unsupported kernel notification sizes: #{@sizes.inspect}" unless @sizes == EXPECTED_SIZES @handlers = {} @unknown_handler = ->(request) { request.error!(@default_errno) } @error_handler = ->(error, _request) { warn("seccomp-notify supervisor: #{error.(highlight: false, order: :top)}") } @receive_mutex = Mutex.new @stop = false @listener_closed = false end |
Instance Attribute Details
#listener ⇒ Object (readonly)
Returns the value of attribute listener.
11 12 13 |
# File 'lib/seccomp/notify/supervisor.rb', line 11 def listener @listener end |
#target_pid ⇒ Object (readonly)
Returns the value of attribute target_pid.
11 12 13 |
# File 'lib/seccomp/notify/supervisor.rb', line 11 def target_pid @target_pid end |
Class Method Details
.valid_duration?(value, allow_zero:) ⇒ Boolean
33 34 35 |
# File 'lib/seccomp/notify/supervisor.rb', line 33 def self.valid_duration?(value, allow_zero:) value.is_a?(Numeric) && value.real? && value.finite? && (allow_zero ? !value.negative? : value.positive?) end |
.validate_options!(options) ⇒ Object
13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 |
# File 'lib/seccomp/notify/supervisor.rb', line 13 def self.() unknown = .keys - USER_OPTIONS raise ArgumentError, "unknown supervisor options: #{unknown.join(", ")}" unless unknown.empty? if .key?(:concurrency) && (![:concurrency].is_a?(Integer) || ![:concurrency].positive?) raise ArgumentError, "concurrency must be a positive integer" end if .key?(:poll_interval) && !valid_duration?([:poll_interval], allow_zero: true) raise ArgumentError, "poll_interval must be non-negative" end if [:timeout] && !valid_duration?([:timeout], allow_zero: false) raise ArgumentError, "timeout must be positive" end if .key?(:features) && ![:features].is_a?(Hash) raise ArgumentError, "features must be a hash" end return unless .key?(:default_errno) Constants.errno_number([:default_errno]) end |
Instance Method Details
#on(syscall) {|request| ... } ⇒ Supervisor
Registers a handler for a notified syscall.
65 66 67 68 69 70 |
# File 'lib/seccomp/notify/supervisor.rb', line 65 def on(syscall, &handler) raise ArgumentError, "handler block is required" unless handler @handlers[syscall.to_sym] = handler self end |
#on_error {|error, request| ... } ⇒ Supervisor
Registers an exception callback.
86 87 88 89 90 91 |
# File 'lib/seccomp/notify/supervisor.rb', line 86 def on_error(&handler) raise ArgumentError, "handler block is required" unless handler @error_handler = handler self end |
#on_unknown {|request| ... } ⇒ Supervisor
Registers the fallback handler for unregistered syscalls.
75 76 77 78 79 80 |
# File 'lib/seccomp/notify/supervisor.rb', line 75 def on_unknown(&handler) raise ArgumentError, "handler block is required" unless handler @unknown_handler = handler self end |
#run ⇒ Process::Status?
Runs until the target exits and returns its process status when available.
95 96 97 98 99 100 101 102 103 104 105 106 |
# File 'lib/seccomp/notify/supervisor.rb', line 95 def run workers = Array.new(@concurrency) { Thread.new { event_loop } } status = wait_for_target wait_until_listener_closes if @target_pid && !@stop @stop = true workers.each(&:join) status ensure @stop = true @listener.close unless @listener.closed? @health_writer&.close unless @health_writer&.closed? end |
#stop ⇒ Object
108 109 110 |
# File 'lib/seccomp/notify/supervisor.rb', line 108 def stop @stop = true end |