I try to make this piece of code works in Ruby Shoes, but I can't succeed to kill the thread named "airodump". Each time I click on the "stop scanning" button, it doesn't do anything :s
Thanks
button "scan networks" do
airodump = Thread.new do
`sudo airodump-ng --write tuto wlan0`
end
Thread.new do
button "Stop scanning" do
Thread.kill(airodump)
end
end
end
Thread killing (in any language) is a pretty limited operation. In your case, the thread is stuck in a blocking call - the call to the subshell - and therefore cannot be killed.
What you would need to do is kill the subprocess first. I don't know how to get the PID out of the backtick operator, so you would need to rather use Process.spawn (on ruby 1.9), gey the PID of the subprocess, and call Process.kill
I think the main problem is that you should use class variables so define
#airodump=Thread.new do
...
end
And than kill it by:
Thread.kill(#airodump)
Related
This is my code snippet
def execution_start
puts "About to start"
system("appium")
puts "Done!!"
end
When executing this I see the output About to start, and appium server is launched. But after that, I do not see anything happening. It's stuck forever. Any idea?
system blocks until the command it runs has completed. To run a command and return immediately, use Process#spawn:
def execution_start
puts "About to start"
pid = Process.spawn("appium")
puts "Done!!"
end
You can then use the returned PID to monitor whether the process has finished executing, and with what exit code, later in your program.
(Note that, per the documentation, you need to Process#wait the PID eventually, or at least register disinterest using Process#detach to prevent the subprocess from becoming a zombie.)
I have a main script in Ruby 1.9.3 running on Windows. It's will start another Ruby script that runs as a daemon, do its own stuff, then end the daemon by sending an "INT" signal. The main script and daemon don't otherwise do any data exchange.
The daemon itself can run as a standalone, and we terminate it with Ctrl-C. Here's the part that prepares it for the signal:
def setup_ctrl_c_to_quit
Thread.new do
trap("INT") do
puts "got INT signal"
exit
end
while true
sleep 1
end
end
end
I am currently having trouble having the main script launching and terminating the daemon. Currently, I can start the daemon through spawn and detach as such:
def startDaemon
#daemonPID = spawn("ruby c:/some_folder/daemon.rb", :new_pgroup=>true, :err=>:out)
puts "DaemonPID #{#daemonPID}"
daemonDetatch = Process.detach(#daemonPID)
puts "Detached Daemon . Entering sleep...."
sleep 15
puts "Is daemon detached thread alive? => #{daemonDetatch.alive?}"
puts "Attempt to kill daemon...."
Process.kill( "INT", #daemonPID )
sleep 5
puts "Is daemon detached thread still alive? => #{daemonDetatch.alive?}"
end
Ideally, the last puts statement should show daemonDetatch.alive? to be false. In reality, not only does daemonDetatch.alive? still ended up being true by the end, the daemon also can be found as still running in both the Task Manager and other 3rd party apps such as Process Explorer.
The first question I have is with the spawn(...) function. The official documentation said that :new_pgroup "is necessary for Process.kill(:SIGINT, pid) on the subprocess" send it determines whether the subprocess becomes a new group or not. I've toggled with this paramter, but it didn't seem to make a difference.
Also, I am planning to give this solution a try, which involves using the win32-process gem. I am just wondering if there are other solutions out there.
[Edit]
I have validated the PID of the daemon obtained in the main script, the daemon itself (with $$), and Process Explore, and they are all the same.
I have gotten suggestion from many others to just use "taskkill /f" to terminate the daemon. That will indeed end the daemon, but the daemon cannot trap the "TERM" or "KILL" signals the same way it traps "INT", meaning it will be unable to run its clean-up/quit routine.
I was just thinking about how great it would be to be able to run a program and then hit a keystroke to invoke pry and debug. Maybe there is a gem out there that injects binding.pry dynamically during runtime that I don't know about. If there isn't, how would you make a keystroke that inserts binding.pry before the next line of ruby script that is about to execute?
Assuming a POSIX OS, you could try adding a signal handler in your ruby program. The ruby documentation even gives an example of your use case:
.. your process may trap the USR1 signal and use it to toggle debugging (http://www.ruby-doc.org/core-2.1.3/Signal.html)
Signal.trap('USR1') do
binding.pry
end
Then, to send the signal:
kill -s SIGUSR1 [pid]
Edit: A more complete example: application.rb
My naïve suggestion above will fail with a ThreadError: current thread not owner. Here's a better example using a global $debug flag.
#!/usr/bin/env ruby
require 'pry'
$debug = false
Signal.trap('USR1') do
puts 'trapped USR1'
$debug = true
end
class Application
def run
while true
print '.'
sleep 5
binding.pry if $debug
end
end
end
Application.new.run
This seems to work best when application.rb is running in the foreground in one shell, and you send the SIGUSR1 signal from a separate shell.
Tested in Mac OS 10.9.5. YMMV.
While writing a ruby script on Windows (ruby -v outputs ruby 1.9.3p545) I encountered an interesting and rather specific problem. I was attempting to close an opened file if a user terminates execution. For example,
begin
f = File.open("monkeys.txt", "w+")
#stuff with the file
rescue Exception => e #I know this is a bad idea
puts e.backtrace
ensure
f.close
end
Now, this works if I terminate execution via Ctrl+C while running this in cmd. However, when I hit the "X" on the cmd prompt window, the code in the ensure block doesn't run. I tried something like...
at_exit do
f.close if !f.closed?
end
...but that still doesn't execute the code I want it to when the X button is hit.
So, what do I do in order to force "ensure" code in Ruby if it's closed via that X button?
Well, I don't really program for windows, so I might get lost on the details, but let me try to shed some light with this workaround for Linux:
#ppid = Process.ppid
pid = fork do
loop do
sleep(1)
begin
Process.getsid(#ppid)
rescue Errno::ESRCH
File.new("process_down.txt", "a+")
exit(1)
end
end
end
Process.detach(pid)
puts "Process detached"
What this does is it creates a forked process, detaches it from the main process and keeps listening for when the main process is killed (it'll throw Errno::ESRCH on Process.getsid if the #ppid is no longer there), so it'll create a .txt file and exit. I don't know how to handle forking and pids in windows, but that's just to try and show you some possibilities =]
Here's a simplified version of some code I wrote:
class InfiniteLoop
def run
trap('SIGTERM') do
puts 'exiting'
exit
end
loop {}
end
end
If I run:
InfiniteLoop.new.run
I can ctrl+c and get:
exiting
However, when I do this:
t = Thread.new { InfiniteLoop.new.run }
sleep 1
t.terminate
I don't see:
exiting
Can someone point me in the right direction here? I'd like to have the same behavior when terminating the thread.
If you are not sending a SIGTERM signal (via ctrl+c) the trap block is not executed.
See also the Kernel method:
at_exit { puts 'exiting' }
trap('SIGTERM') will only respond to the signals sent from OS land.
Thread#terminate is ruby code that will kill the thread.
I don't know of a way to specify behavior for a thread to take before it is killed. That might be interesting. But I don't think it exists, because the semantics of Thread#kill/terminate/join wouldn't really allow that.
Try trap("EXIT"). SIGTERM is sent by ctrl-C or a kill command. From the ruby docs:
The special signal name “EXIT” or signal number zero will be invoked just prior to program termination.