class Object

Constants

ThreadProc

Public Class Methods

mainloop() click to toggle source

This is a shortcut for Daemon.new + Daemon#mainloop.

# File lib/win32/daemon.rb, line 210
def self.mainloop
  new.mainloop
end

Public Instance Methods

mainloop() click to toggle source

This is the method that actually puts your code into a loop and allows it to run as a service. The code that is actually run while in the mainloop is what you defined in your own Daemon#service_main method.

# File lib/win32/daemon.rb, line 218
def mainloop
  @@waiting_control_code = IDLE_CONTROL_CODE
  @@dwServiceState = 0

  # Redirect STDIN, STDOUT and STDERR to the NUL device if they're still
  # associated with a tty. This helps newbs avoid Errno::EBADF errors.
  STDIN.reopen("NUL") if STDIN.isatty
  STDOUT.reopen("NUL") if STDOUT.isatty
  STDERR.reopen("NUL") if STDERR.isatty

  # Calling init here so that init failures never even tries to start the
  # service. Of course that means that init methods must be very quick
  # because the SCM will be receiving no START_PENDING messages while
  # init's running.
  #
  # TODO: Fix?
  service_init if respond_to?("service_init")

  # Create the event to signal the service to start.
  @@hStartEvent = CreateEvent(nil, 1, 0, nil)

  if @@hStartEvent == 0
    raise SystemCallError.new("CreateEvent", FFI.errno)
  end

  # Create the event to signal the service to stop.
  @@hStopEvent = CreateEvent(nil, 1, 0, nil)

  if @@hStopEvent == 0
    raise SystemCallError.new("CreateEvent", FFI.errno)
  end

  # Create the event to signal the service that stop has completed
  @@hStopCompletedEvent = CreateEvent(nil, 1, 0, nil)

  if @@hStopCompletedEvent == 0
    raise SystemCallError.new("CreateEvent", FFI.errno)
  end

  hThread = CreateThread(nil, 0, ThreadProc, Service_Main, 0, nil)

  if hThread == 0
    raise SystemCallError.new("CreateThread", FFI.errno)
  end

  events = FFI::MemoryPointer.new(:pointer, 2)
  events.put_pointer(0, FFI::Pointer.new(hThread))
  events.put_pointer(FFI::Pointer.size, FFI::Pointer.new(@@hStartEvent))

  while (index = WaitForMultipleObjects(2, events, 0, 1000)) == WAIT_TIMEOUT
  end

  if index == WAIT_FAILED
    raise SystemCallError.new("WaitForMultipleObjects", FFI.errno)
  end

  # The thread exited, so the show is off.
  if index == WAIT_OBJECT_0
    raise "Service_Main thread exited abnormally"
  end

  thr = Thread.new do
    begin
      while WaitForSingleObject(@@hStopEvent, 1000) == WAIT_TIMEOUT
        # Check to see if anything interesting has been signaled
        case @@waiting_control_code
          when SERVICE_CONTROL_PAUSE
            service_pause if respond_to?("service_pause")
          when SERVICE_CONTROL_CONTINUE
            service_resume if respond_to?("service_resume")
          when SERVICE_CONTROL_INTERROGATE
            service_interrogate if respond_to?("service_interrogate")
          when SERVICE_CONTROL_SHUTDOWN
            service_shutdown if respond_to?("service_shutdown")
          when SERVICE_CONTROL_PARAMCHANGE
            service_paramchange if respond_to?("service_paramchange")
          when SERVICE_CONTROL_NETBINDADD
            service_netbindadd if respond_to?("service_netbindadd")
          when SERVICE_CONTROL_NETBINDREMOVE
            service_netbindremove if respond_to?("service_netbindremove")
          when SERVICE_CONTROL_NETBINDENABLE
            service_netbindenable if respond_to?("service_netbindenable")
          when SERVICE_CONTROL_NETBINDDISABLE
            service_netbinddisable if respond_to?("service_netbinddisable")
        end

        # handle user defined control codes
        if @@waiting_control_code >= 128 && @@waiting_control_code <= 255
          if respond_to?("service_user_defined_control")
            service_user_defined_control(@@waiting_control_code)
          end
        end

        @@waiting_control_code = IDLE_CONTROL_CODE
      end

      service_stop if respond_to?("service_stop")
    ensure
      SetEvent(@@hStopCompletedEvent)
    end
  end

  if respond_to?("service_main")
    service_main(*@@Argv)
  end

  thr.join
end
running?() click to toggle source

Returns whether or not the service is in a running state, i.e. the service status is either RUNNING, PAUSED or IDLE.

This is typically used within your service_main method to setup the main loop. For example:

class MyDaemon < Daemon
   def service_main
      while running?
         # Your main loop here
      end
   end
end
# File lib/win32/daemon.rb, line 362
def running?
  [SERVICE_RUNNING, SERVICE_PAUSED, 0].include?(@@dwServiceState)
end
state() click to toggle source

Returns the state of the service (as an constant integer) which can be any of the service status constants, e.g. RUNNING, PAUSED, etc.

This method is typically used within your service_main method to setup the loop. For example:

class MyDaemon < Daemon
  def service_main
    while state == RUNNING || state == PAUSED || state == IDLE
      # Your main loop here
    end
  end
end

See the Daemon#running? method for an abstraction of the above code.

# File lib/win32/daemon.rb, line 343
def state
  @@dwServiceState
end