mirror of
https://github.com/puma/puma.git
synced 2022-11-09 13:48:40 -05:00
Replaced Spawn/Terminate functions with experimental ConsoleProcess Class.
Small tweaks to Rakefile for new gem release. git-svn-id: svn+ssh://rubyforge.org/var/svn/mongrel/trunk@621 19e92222-5c0b-0410-8929-a290d50e31e9
This commit is contained in:
parent
5a948694ba
commit
4cf7422cd9
7 changed files with 130 additions and 504 deletions
|
@ -1,26 +1,17 @@
|
|||
* SVN *
|
||||
|
||||
* Properly display package/gem version for mongrel_service. Closes #13823.
|
||||
|
||||
* Updated ServiceFB to r80 to solve issue when compiling with FB > 0.17.
|
||||
|
||||
* 0.3.2 *
|
||||
|
||||
* Solved detection of parent process at ServiceFB level
|
||||
(solves the x64 Windows issues).
|
||||
|
||||
* Upgraded to ServiceFB 'trunk' (but pistoned it, just in case).
|
||||
|
||||
* Fixed problems with ruby installations outside PATH or inside folders with spaces.
|
||||
|
||||
* Activate FB pedantic warnings by default (is really useful).
|
||||
|
||||
* 0.3.1 *
|
||||
|
||||
* Single Service (SingleMongrel) object type implemented.
|
||||
|
||||
* Updated Rakefile to reflect the new building steps.
|
||||
|
||||
* Removed SendSignal, too hackish for my taste, replaced with complete FB solution.
|
||||
|
||||
* Added basic Process monitoring and re-spawning.
|
||||
|
||||
v0.3.3.
|
||||
Properly display package/gem version for mongrel_service; Closes #13823.
|
||||
Updated ServiceFB to r80 to solve issue when compiling with FB > 0.17.
|
||||
Replaced Spawn/Terminate functions with experimental ConsoleProcess Class.
|
||||
|
||||
v0.3.2.
|
||||
Solved detection of parent process at ServiceFB level (solves the x64 Windows issues).
|
||||
Upgraded to ServiceFB 'trunk' (but pistoned it, just in case).
|
||||
Fixed problems with ruby installations outside PATH or inside folders with spaces.
|
||||
Activate FB pedantic warnings by default (is really useful).
|
||||
|
||||
v0.3.1.
|
||||
Single Service (SingleMongrel) object type implemented.
|
||||
Updated Rakefile to reflect the new building steps.
|
||||
Removed SendSignal, too hackish for my taste, replaced with complete FB solution.
|
||||
Added basic Process monitoring and re-spawning.
|
||||
|
|
|
@ -3,10 +3,10 @@ tools/freebasic.rb
|
|||
TODO
|
||||
resources/defaults.yaml
|
||||
README
|
||||
native/process.bi
|
||||
native/process.bas
|
||||
native/mongrel_service.bi
|
||||
native/mongrel_service.bas
|
||||
native/console_process.bi
|
||||
native/console_process.bas
|
||||
native/_debug.bi
|
||||
LICENSE
|
||||
lib/ServiceFB/ServiceFB_Utils.bi
|
||||
|
|
|
@ -1,92 +1,87 @@
|
|||
|
||||
require 'echoe'
|
||||
require 'tools/freebasic'
|
||||
|
||||
echoe_spec = Echoe.new("mongrel_service") do |p|
|
||||
p.summary = "Mongrel Native Win32 Service Plugin for Rails"
|
||||
p.summary += " (debug build)" unless ENV['RELEASE']
|
||||
p.description = "This plugin offer native win32 services for rails, powered by Mongrel."
|
||||
p.author = "Luis Lavena"
|
||||
p.platform = Gem::Platform::WIN32
|
||||
p.dependencies = ['gem_plugin >=0.2.1', 'mongrel >=0.3.12.4', 'win32-service >=0.5.0']
|
||||
|
||||
p.need_tar_gz = false
|
||||
p.need_zip = true
|
||||
p.certificate_chain = ['/Users/eweaver/p/configuration/gem_certificates/mongrel/mongrel-public_cert.pem',
|
||||
'/Users/eweaver/p/configuration/gem_certificates/evan_weaver-mongrel-public_cert.pem']
|
||||
p.require_signed = true
|
||||
end
|
||||
|
||||
desc "Compile native code"
|
||||
task :compile => [:native_lib, :native_service]
|
||||
|
||||
task :"bin/mongrel_service.exe" => [:clean, :compile]
|
||||
|
||||
# global options shared by all the project in this Rakefile
|
||||
OPTIONS = {
|
||||
:debug => false,
|
||||
:profile => false,
|
||||
:errorchecking => :ex,
|
||||
:mt => true,
|
||||
:pedantic => true }
|
||||
|
||||
OPTIONS[:debug] = true if ENV['DEBUG']
|
||||
OPTIONS[:profile] = true if ENV['PROFILE']
|
||||
OPTIONS[:errorchecking] = :exx if ENV['EXX']
|
||||
OPTIONS[:pedantic] = false if ENV['NOPEDANTIC']
|
||||
|
||||
# ServiceFB namespace (lib)
|
||||
namespace :lib do
|
||||
project_task 'servicefb' do
|
||||
lib 'ServiceFB'
|
||||
build_to 'lib'
|
||||
|
||||
define 'SERVICEFB_DEBUG_LOG' unless ENV['RELEASE']
|
||||
source 'lib/ServiceFB/ServiceFB.bas'
|
||||
|
||||
option OPTIONS
|
||||
end
|
||||
|
||||
project_task 'servicefb_utils' do
|
||||
lib 'ServiceFB_Utils'
|
||||
build_to 'lib'
|
||||
|
||||
define 'SERVICEFB_DEBUG_LOG' unless ENV['RELEASE']
|
||||
source 'lib/ServiceFB/ServiceFB_Utils.bas'
|
||||
|
||||
option OPTIONS
|
||||
end
|
||||
end
|
||||
# add lib namespace to global tasks
|
||||
#include_projects_of :lib
|
||||
task :native_lib => "lib:build"
|
||||
task :clean => "lib:clobber"
|
||||
|
||||
# mongrel_service (native)
|
||||
namespace :native do
|
||||
project_task 'mongrel_service' do
|
||||
executable 'mongrel_service'
|
||||
build_to 'bin'
|
||||
|
||||
define 'DEBUG_LOG' unless ENV['RELEASE']
|
||||
define "GEM_VERSION=#{echoe_spec.version}"
|
||||
|
||||
main 'native/mongrel_service.bas'
|
||||
source 'native/process.bas'
|
||||
|
||||
# including the precompiled file show warnings when linking with
|
||||
# ld, due pial m$ directives in the obj file
|
||||
# will solve that later, when migrate the asm part of code to gcc
|
||||
# source 'native/send_signal.o'
|
||||
|
||||
lib_path 'lib'
|
||||
library 'ServiceFB', 'ServiceFB_Utils'
|
||||
library 'user32', 'advapi32', 'psapi'
|
||||
|
||||
option OPTIONS
|
||||
end
|
||||
end
|
||||
#include_projects_of :native
|
||||
task :native_service => "native:build"
|
||||
task :clean => "native:clobber"
|
||||
|
||||
require 'echoe'
|
||||
require 'tools/freebasic'
|
||||
|
||||
echoe_spec = Echoe.new("mongrel_service", "0.3.3") do |p|
|
||||
p.summary = "Mongrel Native Win32 Service Plugin for Rails"
|
||||
p.summary += " (debug build)" unless ENV['RELEASE']
|
||||
p.description = "This plugin offer native win32 services for rails, powered by Mongrel."
|
||||
p.author = "Luis Lavena"
|
||||
p.platform = Gem::Platform::WIN32
|
||||
p.dependencies = ['gem_plugin >=0.2.2', 'mongrel >=1.0.1', 'win32-service >=0.5.0']
|
||||
|
||||
p.need_tar_gz = false
|
||||
p.need_zip = true
|
||||
p.certificate_chain = ['~/gem_certificates/mongrel-public_cert.pem',
|
||||
'~/gem_certificates/luislavena-mongrel-public_cert.pem']
|
||||
p.require_signed = true
|
||||
end
|
||||
|
||||
desc "Compile native code"
|
||||
task :compile => [:native_lib, :native_service]
|
||||
|
||||
#task :"bin/mongrel_service.exe" => [:clean, :compile]
|
||||
|
||||
# global options shared by all the project in this Rakefile
|
||||
OPTIONS = {
|
||||
:debug => false,
|
||||
:profile => false,
|
||||
:errorchecking => :ex,
|
||||
:mt => true,
|
||||
:pedantic => true }
|
||||
|
||||
OPTIONS[:debug] = true if ENV['DEBUG']
|
||||
OPTIONS[:profile] = true if ENV['PROFILE']
|
||||
OPTIONS[:errorchecking] = :exx if ENV['EXX']
|
||||
OPTIONS[:pedantic] = false if ENV['NOPEDANTIC']
|
||||
|
||||
# ServiceFB namespace (lib)
|
||||
namespace :lib do
|
||||
project_task 'servicefb' do
|
||||
lib 'ServiceFB'
|
||||
build_to 'lib'
|
||||
|
||||
define 'SERVICEFB_DEBUG_LOG' unless ENV['RELEASE']
|
||||
source 'lib/ServiceFB/ServiceFB.bas'
|
||||
|
||||
option OPTIONS
|
||||
end
|
||||
|
||||
project_task 'servicefb_utils' do
|
||||
lib 'ServiceFB_Utils'
|
||||
build_to 'lib'
|
||||
|
||||
define 'SERVICEFB_DEBUG_LOG' unless ENV['RELEASE']
|
||||
source 'lib/ServiceFB/ServiceFB_Utils.bas'
|
||||
|
||||
option OPTIONS
|
||||
end
|
||||
end
|
||||
|
||||
# add lib namespace to global tasks
|
||||
#include_projects_of :lib
|
||||
task :native_lib => "lib:build"
|
||||
task :clean => "lib:clobber"
|
||||
|
||||
# mongrel_service (native)
|
||||
namespace :native do
|
||||
project_task 'mongrel_service' do
|
||||
executable 'mongrel_service'
|
||||
build_to 'bin'
|
||||
|
||||
define 'DEBUG_LOG' unless ENV['RELEASE']
|
||||
define "GEM_VERSION=#{echoe_spec.version}"
|
||||
|
||||
main 'native/mongrel_service.bas'
|
||||
source 'native/console_process.bas'
|
||||
|
||||
lib_path 'lib'
|
||||
library 'ServiceFB', 'ServiceFB_Utils'
|
||||
library 'user32', 'advapi32', 'psapi'
|
||||
|
||||
option OPTIONS
|
||||
end
|
||||
end
|
||||
|
||||
#include_projects_of :native
|
||||
task :native_service => "native:build"
|
||||
task :clean => "native:clobber"
|
||||
|
|
|
@ -14,7 +14,7 @@
|
|||
|
||||
'##################################################################
|
||||
'# Requirements:
|
||||
'# - FreeBASIC 0.17, Win32 CVS Build (as for November 09, 2006).
|
||||
'# - FreeBASIC 0.18
|
||||
'#
|
||||
'##################################################################
|
||||
|
||||
|
@ -23,9 +23,9 @@
|
|||
#include once "_debug.bi"
|
||||
|
||||
namespace mongrel_service
|
||||
using fb.process
|
||||
|
||||
constructor SingleMongrel()
|
||||
dim redirect_file as string
|
||||
|
||||
with this.__service
|
||||
.name = "single"
|
||||
.description = "Mongrel Single Process service"
|
||||
|
@ -39,6 +39,12 @@ namespace mongrel_service
|
|||
.onStop = @single_onStop
|
||||
end with
|
||||
|
||||
with this.__console
|
||||
redirect_file = EXEPATH + "\mongrel.log"
|
||||
debug("redirecting to: " + redirect_file)
|
||||
.redirect(ProcessStdBoth, redirect_file)
|
||||
end with
|
||||
|
||||
'# TODO: fix inheritance here
|
||||
single_mongrel_ref = @this
|
||||
end constructor
|
||||
|
@ -64,6 +70,10 @@ namespace mongrel_service
|
|||
'# SingleMongrel instance. now we should call StillAlive
|
||||
self.StillAlive()
|
||||
if (len(self.commandline) > 0) then
|
||||
'# assign the program
|
||||
single_mongrel_ref->__console.filename = mongrel_cmd
|
||||
single_mongrel_ref->__console.arguments = self.commandline
|
||||
|
||||
'# fix commandline, it currently contains params to be passed to
|
||||
'# mongrel_rails, and not ruby.exe nor the script to be run.
|
||||
self.commandline = mongrel_cmd + " " + self.commandline
|
||||
|
@ -71,7 +81,9 @@ namespace mongrel_service
|
|||
'# now launch the child process
|
||||
debug("starting child process with cmdline: " + self.commandline)
|
||||
single_mongrel_ref->__child_pid = 0
|
||||
single_mongrel_ref->__child_pid = Spawn(self.commandline)
|
||||
if (single_mongrel_ref->__console.start() = true) then
|
||||
single_mongrel_ref->__child_pid = single_mongrel_ref->__console.pid
|
||||
end if
|
||||
self.StillAlive()
|
||||
|
||||
'# check if pid is valid
|
||||
|
@ -96,13 +108,15 @@ namespace mongrel_service
|
|||
do while (self.state = Running) or (self.state = Paused)
|
||||
'# instead of sitting idle here, we must monitor the pid
|
||||
'# and re-spawn a new process if needed
|
||||
if not (Status(single_mongrel_ref->__child_pid) = ProcessStillActive) then
|
||||
if not (single_mongrel_ref->__console.running = true) then
|
||||
'# check if we aren't terminating
|
||||
if (self.state = Running) or (self.state = Paused) then
|
||||
debug("child process terminated!, re-spawning a new one")
|
||||
|
||||
single_mongrel_ref->__child_pid = 0
|
||||
single_mongrel_ref->__child_pid = Spawn(self.commandline)
|
||||
if (single_mongrel_ref->__console.start() = true) then
|
||||
single_mongrel_ref->__child_pid = single_mongrel_ref->__console.pid
|
||||
end if
|
||||
|
||||
if (single_mongrel_ref->__child_pid > 0) then
|
||||
debug("new child process pid: " + str(single_mongrel_ref->__child_pid))
|
||||
|
@ -123,8 +137,7 @@ namespace mongrel_service
|
|||
'# now terminates the child process
|
||||
if not (single_mongrel_ref->__child_pid = 0) then
|
||||
debug("trying to kill pid: " + str(single_mongrel_ref->__child_pid))
|
||||
'if not (send_break(single_mongrel_ref->__child_pid) = 0) then
|
||||
if not (Terminate(single_mongrel_ref->__child_pid) = TRUE) then
|
||||
if not (single_mongrel_ref->__console.terminate() = true) then
|
||||
debug("Terminate() reported a problem when terminating process " + str(single_mongrel_ref->__child_pid))
|
||||
else
|
||||
debug("child process terminated with success.")
|
||||
|
|
|
@ -14,13 +14,13 @@
|
|||
|
||||
'##################################################################
|
||||
'# Requirements:
|
||||
'# - FreeBASIC 0.17, Win32 CVS Build (as for November 09, 2006).
|
||||
'# - FreeBASIC 0.18.
|
||||
'#
|
||||
'##################################################################
|
||||
|
||||
#define SERVICEFB_INCLUDE_UTILS
|
||||
#include once "lib/ServiceFB/ServiceFB.bi"
|
||||
#include once "process.bi"
|
||||
#include once "console_process.bi"
|
||||
|
||||
'# use for debug versions
|
||||
#if not defined(GEM_VERSION)
|
||||
|
@ -52,6 +52,7 @@ namespace mongrel_service
|
|||
'declare sub onStop()
|
||||
|
||||
__service as ServiceProcess
|
||||
__console as ConsoleProcess
|
||||
__child_pid as uinteger
|
||||
end type
|
||||
|
||||
|
|
|
@ -1,316 +0,0 @@
|
|||
'##################################################################
|
||||
'#
|
||||
'# mongrel_service: Win32 native implementation for mongrel
|
||||
'# (using ServiceFB and FreeBASIC)
|
||||
'#
|
||||
'# Copyright (c) 2006 Multimedia systems
|
||||
'# (c) and code by Luis Lavena
|
||||
'#
|
||||
'# mongrel_service (native) and mongrel_service gem_pluing are licensed
|
||||
'# in the same terms as mongrel, please review the mongrel license at
|
||||
'# http://mongrel.rubyforge.org/license.html
|
||||
'#
|
||||
'##################################################################
|
||||
|
||||
'##################################################################
|
||||
'# Requirements:
|
||||
'# - FreeBASIC 0.17, Win32 CVS Build (as for November 09, 2006).
|
||||
'#
|
||||
'##################################################################
|
||||
|
||||
#include once "process.bi"
|
||||
#define DEBUG_LOG_FILE EXEPATH + "\mongrel_service.log"
|
||||
#include once "_debug.bi"
|
||||
|
||||
namespace fb
|
||||
namespace process
|
||||
'# Spawn(cmdline) will try to create a new process, monitor
|
||||
'# if it launched successfuly (5 seconds) and then return the
|
||||
'# new children PID (Process IDentification) or 0 in case of problems
|
||||
function Spawn(byref cmdline as string) as uinteger
|
||||
dim result as uinteger
|
||||
dim success as BOOL
|
||||
|
||||
'# New Process resources
|
||||
dim child as PROCESS_INFORMATION
|
||||
dim context as STARTUPINFO
|
||||
dim child_sa as SECURITY_ATTRIBUTES = type(sizeof(SECURITY_ATTRIBUTES), NULL, TRUE)
|
||||
dim wait_code as DWORD
|
||||
|
||||
'# StdIn, StdOut, StdErr Read and Write Pipes.
|
||||
dim as HANDLE StdInRd, StdOutRd, StdErrRd
|
||||
dim as HANDLE StdInWr, StdOutWr, StdErrWr
|
||||
|
||||
debug("Spawn() init")
|
||||
|
||||
'# to ensure everything will work, we must allocate a console
|
||||
'# using AllocConsole, even if it fails.
|
||||
'# This solve the problems when running as service.
|
||||
if (AllocConsole() = 0) then
|
||||
debug("Success in AllocConsole()")
|
||||
else
|
||||
debug("AllocConsole failed, maybe already allocated, safely to discart.")
|
||||
end if
|
||||
|
||||
'# presume all worked
|
||||
success = TRUE
|
||||
|
||||
'# Create the pipes
|
||||
'# StdIn
|
||||
if (CreatePipe( @StdInRd, @StdInWr, @child_sa, 0 ) = 0) then
|
||||
debug("Error creating StdIn pipes.")
|
||||
success = FALSE
|
||||
end if
|
||||
|
||||
'# StdOut
|
||||
if (CreatePipe( @StdOutRd, @StdOutWr, @child_sa, 0 ) = 0) then
|
||||
debug("Error creating StdOut pipes.")
|
||||
success = FALSE
|
||||
end if
|
||||
|
||||
'# StdErr
|
||||
if (CreatePipe( @StdErrRd, @StdErrWr, @child_sa, 0 ) = 0) then
|
||||
debug("Error creating StdErr pipes.")
|
||||
success = FALSE
|
||||
end if
|
||||
|
||||
'# Ensure the handles to the pipe are not inherited.
|
||||
if (SetHandleInformation( StdInWr, HANDLE_FLAG_INHERIT, 0) = 0) then
|
||||
debug("Error disabling StdInWr handle.")
|
||||
success = FALSE
|
||||
end if
|
||||
|
||||
if (SetHandleInformation( StdOutRd, HANDLE_FLAG_INHERIT, 0) = 0) then
|
||||
debug("Error disabling StdOutRd handle.")
|
||||
success = FALSE
|
||||
end if
|
||||
|
||||
if (SetHandleInformation( StdErrRd, HANDLE_FLAG_INHERIT, 0) = 0) then
|
||||
debug("Error disabling StdErrRd handle.")
|
||||
success = FALSE
|
||||
end if
|
||||
|
||||
'# without the pipes, we shouldn't continue!
|
||||
if (success = TRUE) then
|
||||
'# Set the Std* handles ;-)
|
||||
with context
|
||||
.cb = sizeof( context )
|
||||
.hStdError = StdErrWr
|
||||
.hStdOutput = StdOutWr
|
||||
.hStdInput = StdInRd
|
||||
.dwFlags = STARTF_USESTDHANDLES
|
||||
end with
|
||||
|
||||
'# now creates the process
|
||||
debug("Creating child process with cmdline: " + cmdline)
|
||||
if (CreateProcess(NULL, _
|
||||
strptr(cmdline), _
|
||||
NULL, _
|
||||
NULL, _
|
||||
TRUE, _
|
||||
0, _
|
||||
NULL, _
|
||||
NULL, _
|
||||
@context, _
|
||||
@child) = 0) then
|
||||
|
||||
debug("Error creating child process, error #" + str(GetLastError()))
|
||||
result = 0
|
||||
else
|
||||
'# close the Std* handles
|
||||
debug("Closing handles.")
|
||||
CloseHandle(StdInRd)
|
||||
CloseHandle(StdInWr)
|
||||
CloseHandle(StdOutRd)
|
||||
CloseHandle(StdOutWr)
|
||||
CloseHandle(StdErrRd)
|
||||
CloseHandle(StdErrWr)
|
||||
|
||||
'# close children main Thread handle
|
||||
if (CloseHandle(child.hThread) = 0) then
|
||||
debug("Problem closing children main thread.")
|
||||
end if
|
||||
|
||||
'# now wait 2 seconds if the children process unexpectly quits
|
||||
wait_code = WaitForSingleObject(child.hProcess, 2000)
|
||||
debug("wait_code: " + str(wait_code))
|
||||
if (wait_code = WAIT_TIMEOUT) then
|
||||
'# the process is still running, we are good
|
||||
'# save a reference to the pid
|
||||
result = child.dwProcessId
|
||||
debug("New children PID: " + str(result))
|
||||
|
||||
'# now close the handle
|
||||
CloseHandle(child.hProcess)
|
||||
else
|
||||
'# the process failed or terminated earlier
|
||||
debug("failed, the process terminate earlier.")
|
||||
result = 0
|
||||
end if '# (wait_code = WAIT_OBJECT_0)
|
||||
end if '# (CreateProcess() = 0)
|
||||
else
|
||||
debug("problem preparing environment for child process, no success")
|
||||
result = 0
|
||||
end if '# (success = TRUE)
|
||||
|
||||
debug("Spawn() done")
|
||||
return result
|
||||
end function
|
||||
|
||||
|
||||
'# Terminate(PID) will hook the special console handler (_child_console_handler)
|
||||
'# and try sending CTRL_C_EVENT, CTRL_BREAK_EVENT and TerminateProcess
|
||||
'# in case of the first two fails.
|
||||
function Terminate(byval pid as uinteger) as BOOL
|
||||
dim result as BOOL
|
||||
dim success as BOOL
|
||||
dim exit_code as DWORD
|
||||
dim wait_code as DWORD
|
||||
|
||||
'# process resources
|
||||
dim child as HANDLE
|
||||
|
||||
debug("Terminate() init")
|
||||
|
||||
'# is pid valid?
|
||||
if (pid > 0) then
|
||||
'# hook our custom console handler
|
||||
debug("hooking console handler")
|
||||
if (SetConsoleCtrlHandler(@_child_console_handler, TRUE) = 0) then
|
||||
debug("error hooking our custom error handler")
|
||||
end if
|
||||
|
||||
'# get a handle to Process
|
||||
debug("OpenProcess() with Terminate and Query flags")
|
||||
child = OpenProcess(PROCESS_QUERY_INFORMATION or PROCESS_TERMINATE or SYNCHRONIZE, FALSE, pid)
|
||||
if not (child = NULL) then
|
||||
'# process is valid, perform actions
|
||||
success = FALSE
|
||||
|
||||
'# send CTRL_C_EVENT and wait for result
|
||||
debug("sending Ctrl-C to child pid " + str(pid))
|
||||
if not (GenerateConsoleCtrlEvent(CTRL_C_EVENT, 0) = 0) then
|
||||
'# it worked, wait 5 seconds terminates.
|
||||
debug("send worked, waiting 5 seconds to terminate...")
|
||||
wait_code = WaitForSingleObject(child, 5000)
|
||||
debug("wait_code: " + str(wait_code))
|
||||
if not (wait_code = WAIT_TIMEOUT) then
|
||||
debug("child process terminated properly.")
|
||||
success = TRUE
|
||||
end if
|
||||
else
|
||||
debug("cannot generate event, error " + str(GetLastError()))
|
||||
success = FALSE
|
||||
end if
|
||||
|
||||
'# Ctrl-C didn't work, try Ctrl-Break
|
||||
if (success = FALSE) then
|
||||
'# send CTRL_BREAK_EVENT and wait for result
|
||||
debug("sending Ctrl-Break to child pid " + str(pid))
|
||||
if not (GenerateConsoleCtrlEvent(CTRL_BREAK_EVENT, 0) = 0) then
|
||||
'# it worked, wait 5 seconds terminates.
|
||||
debug("send worked, waiting 5 seconds to terminate...")
|
||||
wait_code = WaitForSingleObject(child, 5000)
|
||||
debug("wait_code: " + str(wait_code))
|
||||
if not (wait_code = WAIT_TIMEOUT) then
|
||||
debug("child process terminated properly.")
|
||||
success = TRUE
|
||||
end if
|
||||
else
|
||||
debug("cannot generate event, error " + str(GetLastError()))
|
||||
success = FALSE
|
||||
end if
|
||||
end if
|
||||
|
||||
'# still no luck? we should do a hard kill then
|
||||
if (success = FALSE) then
|
||||
debug("doing kill using TerminateProcess")
|
||||
if (TerminateProcess(child, 3) = 0) then
|
||||
debug("TerminateProcess failed, error " + str(GetLastError()))
|
||||
else
|
||||
success = TRUE
|
||||
end if
|
||||
end if
|
||||
|
||||
'# now get process exit code
|
||||
if not (GetExitCodeProcess(child, @exit_code) = 0) then
|
||||
debug("getting child process exit code: " + str(exit_code))
|
||||
if (exit_code = 0) then
|
||||
debug("process terminated ok.")
|
||||
result = TRUE
|
||||
elseif (exit_code = STILL_ACTIVE) then
|
||||
debug("process still active")
|
||||
result = FALSE
|
||||
else
|
||||
debug("process terminated with exit_code: " + str(exit_code))
|
||||
result = TRUE
|
||||
end if
|
||||
else
|
||||
debug("error getting child process exit code, value: " + str(exit_code) + ", error " + str(GetLastError()))
|
||||
result = FALSE
|
||||
end if
|
||||
else
|
||||
'# invalid process handler
|
||||
result = FALSE
|
||||
end if
|
||||
|
||||
'# remove hooks
|
||||
SetConsoleCtrlhandler(@_child_console_handler, FALSE)
|
||||
|
||||
'# clean up all open handles
|
||||
CloseHandle(child)
|
||||
end if '# (pid > 0)
|
||||
|
||||
return result
|
||||
end function
|
||||
|
||||
|
||||
'# StillActive(PID) will return FALSE (0) in case the process no longer
|
||||
'# exist of get terminated with error.
|
||||
function Status(byval pid as uinteger) as ProcessStateEnum
|
||||
dim result as ProcessStateEnum
|
||||
dim exit_code as DWORD
|
||||
|
||||
'# process reference
|
||||
dim child as HANDLE
|
||||
|
||||
'# presume error?
|
||||
result = ProcessQueryError
|
||||
|
||||
'# is pid valid?
|
||||
if (pid > 0) then
|
||||
'# try getting a handler to the process
|
||||
child = OpenProcess(PROCESS_QUERY_INFORMATION or SYNCHRONIZE, FALSE, pid)
|
||||
if not (child = NULL) then
|
||||
'# the process reference is valid, get the exit_code
|
||||
if not (GetExitCodeProcess(child, @exit_code) = 0) then
|
||||
'# no error in the query, get result
|
||||
if (exit_code = STILL_ACTIVE) then
|
||||
result = ProcessStillActive
|
||||
end if '# (exit_code = STILL_ACTIVE)
|
||||
end if '# not (GetExitCodeProcess())
|
||||
|
||||
'# closes the process handle
|
||||
CloseHandle(child)
|
||||
end if '# not (child = NULL)
|
||||
end if '# (pid > 0)
|
||||
|
||||
return result
|
||||
end function
|
||||
|
||||
'# Special hook used to avoid the process calling Terminate()
|
||||
'# respond to CTRL_*_EVENTS when terminating child process
|
||||
private function _child_console_handler(byval dwCtrlType as DWORD) as BOOL
|
||||
dim result as BOOL
|
||||
|
||||
debug("_child_console_handler, dwCtrlType: " + str(dwCtrlType))
|
||||
if (dwCtrlType = CTRL_C_EVENT) then
|
||||
result = TRUE
|
||||
elseif (dwCtrlType = CTRL_BREAK_EVENT) then
|
||||
result = TRUE
|
||||
end if
|
||||
|
||||
return result
|
||||
end function
|
||||
end namespace '# fb.process
|
||||
end namespace '# fb
|
|
@ -1,58 +0,0 @@
|
|||
'##################################################################
|
||||
'#
|
||||
'# mongrel_service: Win32 native implementation for mongrel
|
||||
'# (using ServiceFB and FreeBASIC)
|
||||
'#
|
||||
'# Copyright (c) 2006 Multimedia systems
|
||||
'# (c) and code by Luis Lavena
|
||||
'#
|
||||
'# mongrel_service (native) and mongrel_service gem_pluing are licensed
|
||||
'# in the same terms as mongrel, please review the mongrel license at
|
||||
'# http://mongrel.rubyforge.org/license.html
|
||||
'#
|
||||
'##################################################################
|
||||
|
||||
'##################################################################
|
||||
'# Requirements:
|
||||
'# - FreeBASIC 0.17, Win32 CVS Build (as for November 09, 2006).
|
||||
'#
|
||||
'##################################################################
|
||||
|
||||
#ifndef __Process_bi__
|
||||
#define __Process_bi__
|
||||
|
||||
#include once "windows.bi"
|
||||
|
||||
namespace fb
|
||||
namespace process
|
||||
'# fb.process functions that allow creation/graceful termination
|
||||
'# of child process.
|
||||
|
||||
'# Process Status Enum
|
||||
enum ProcessStateEnum
|
||||
ProcessQueryError = 0
|
||||
ProcessStillActive = STILL_ACTIVE
|
||||
end enum
|
||||
|
||||
|
||||
'# Spawn(cmdline) will try to create a new process, monitor
|
||||
'# if it launched successfuly (5 seconds) and then return the
|
||||
'# new children PID (Process IDentification) or 0 in case of problems
|
||||
declare function Spawn(byref as string) as uinteger
|
||||
|
||||
'# Terminate(PID) will hook the special console handler (_child_console_handler)
|
||||
'# and try sending CTRL_C_EVENT, CTRL_BREAK_EVENT and TerminateProcess
|
||||
'# in case of the first two fails.
|
||||
declare function Terminate(byval as uinteger) as BOOL
|
||||
|
||||
'# StillActive(PID) will return FALSE (0) in case the process no longer
|
||||
'# exist of get terminated with error.
|
||||
declare function Status(byval as uinteger) as ProcessStateEnum
|
||||
|
||||
'# Special hook used to avoid the process calling Terminate()
|
||||
'# respond to CTRL_*_EVENTS when terminating child process
|
||||
declare function _child_console_handler(byval as DWORD) as BOOL
|
||||
end namespace '# fb.process
|
||||
end namespace '# fb
|
||||
|
||||
#endif '# __Process_bi__
|
Loading…
Reference in a new issue