Class: Karafka::Swarm::Pidfd
- Inherits:
 - 
      Object
      
        
- Object
 - Karafka::Swarm::Pidfd
 
 
- Extended by:
 - FFI::Library
 
- Defined in:
 - lib/karafka/swarm/pidfd.rb
 
Overview
Pidfd Linux representation wrapped with Ruby for communication within Swarm It is more stable than using ‘#pid` and `#ppid` + signals and cheaper
Class Method Summary collapse
- 
  
    
      .supported?  ⇒ Boolean 
    
    
  
  
  
  
  
  
  
  
  
    
True if syscall is supported via FFI.
 
Instance Method Summary collapse
- 
  
    
      #alive?  ⇒ Boolean 
    
    
  
  
  
  
  
  
  
  
  
    
True if given process is alive, false if no longer.
 - 
  
    
      #cleanup  ⇒ Object 
    
    
  
  
  
  
  
  
  
  
  
    
Cleans the zombie process.
 - 
  
    
      #initialize(pid)  ⇒ Pidfd 
    
    
  
  
  
    constructor
  
  
  
  
  
  
  
    
A new instance of Pidfd.
 - 
  
    
      #signal(sig_name)  ⇒ Boolean 
    
    
  
  
  
  
  
  
  
  
  
    
Sends given signal to the process using its pidfd.
 
Constructor Details
#initialize(pid) ⇒ Pidfd
Returns a new instance of Pidfd.
      63 64 65 66 67 68 69  | 
    
      # File 'lib/karafka/swarm/pidfd.rb', line 63 def initialize(pid) @mutex = Mutex.new @pid = pid @pidfd = open(pid) @pidfd_io = IO.new(@pidfd) end  | 
  
Class Method Details
.supported? ⇒ Boolean
Returns true if syscall is supported via FFI.
      43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59  | 
    
      # File 'lib/karafka/swarm/pidfd.rb', line 43 def supported? # If we were not even able to load the FFI C lib, it won't be supported return false unless API_SUPPORTED # Won't work on macOS because it does not support pidfd return false if RUBY_DESCRIPTION.include?('darwin') # Won't work on Windows for the same reason as on macOS return false if RUBY_DESCRIPTION.match?(/mswin|ming|cygwin/) # There are some OSes like BSD that will have C lib for FFI bindings but will not support # the needed syscalls. In such cases, we can just try and fail, which will indicate it # won't work. The same applies to using new glibc on an old kernel. new(::Process.pid) true rescue Errors::PidfdOpenFailedError false end  | 
  
Instance Method Details
#alive? ⇒ Boolean
Returns true if given process is alive, false if no longer.
      72 73 74 75 76 77 78 79 80 81 82 83 84 85 86  | 
    
      # File 'lib/karafka/swarm/pidfd.rb', line 72 def alive? @pidfd_select ||= [@pidfd_io] if @mutex.owned? return false if @cleaned IO.select(@pidfd_select, nil, nil, 0).nil? else @mutex.synchronize do return false if @cleaned IO.select(@pidfd_select, nil, nil, 0).nil? end end end  | 
  
#cleanup ⇒ Object
    Note:
    
  
This should run only on processes that exited, otherwise will wait
Cleans the zombie process
      90 91 92 93 94 95 96 97 98 99 100 101 102  | 
    
      # File 'lib/karafka/swarm/pidfd.rb', line 90 def cleanup @mutex.synchronize do return if @cleaned waitid(P_PIDFD, @pidfd, nil, WEXITED) @pidfd_io.close @pidfd_select = nil @pidfd_io = nil @pidfd = nil @cleaned = true end end  | 
  
#signal(sig_name) ⇒ Boolean
    Note:
    
  
It will not send signals to dead processes
Sends given signal to the process using its pidfd
      109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127  | 
    
      # File 'lib/karafka/swarm/pidfd.rb', line 109 def signal(sig_name) @mutex.synchronize do return false if @cleaned # Never signal processes that are dead return false unless alive? result = fdpid_signal( pidfd_signal_syscall, @pidfd, Signal.list.fetch(sig_name), nil, 0 ) return true if result.zero? raise Errors::PidfdSignalFailedError, result end end  |