Class: Win32::Daemon
- Inherits:
-
Object
- Object
- Win32::Daemon
- Defined in:
- ext/win32/daemon.c
Defined Under Namespace
Classes: Error
Constant Summary collapse
- VERSION =
The version of this library
0.7.2
- CONTINUE_PENDING =
Service has received a signal to resume but is not yet running
INT2NUM(SERVICE_CONTINUE_PENDING)
- PAUSE_PENDING =
Service has received a signal to pause but is not yet paused
INT2NUM(SERVICE_PAUSE_PENDING)
- PAUSED =
Service is in a paused state
INT2NUM(SERVICE_PAUSED)
- RUNNING =
Service is running
INT2NUM(SERVICE_RUNNING)
- START_PENDING =
Service has received a signal to start but is not yet running
INT2NUM(SERVICE_START_PENDING)
- STOP_PENDING =
Service has received a signal to stop but has not yet stopped
INT2NUM(SERVICE_STOP_PENDING)
- STOPPED =
Service is stopped.
INT2NUM(SERVICE_STOPPED)
- IDLE =
Service is in an idle state
INT2NUM(0)
Class Method Summary collapse
-
.mainloop ⇒ Object
This is a shortcut for Daemon.new + Daemon#mainloop.
Instance Method Summary collapse
-
#mainloop ⇒ Object
This is the method that actually puts your code into a loop and allows it to run as a service.
-
#running? ⇒ Boolean
Returns whether or not the service is in a running state, i.e.
-
#state ⇒ Object
Returns the state of the service (as an constant integer) which can be any of the service status constants, e.g.
Class Method Details
.mainloop ⇒ Object
This is a shortcut for Daemon.new + Daemon#mainloop.
554 555 556 557 558 |
# File 'ext/win32/daemon.c', line 554 static VALUE daemon_c_mainloop(VALUE klass){ VALUE v_args[1]; VALUE v_daemon = rb_class_new_instance(0, v_args, klass); return rb_funcall(v_daemon, rb_intern("mainloop"), 0, 0); } |
Instance Method Details
#mainloop ⇒ Object
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.
352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 |
# File 'ext/win32/daemon.c', line 352
static VALUE daemon_mainloop(VALUE self)
{
DWORD ThreadId;
HANDLE events[2];
DWORD index;
VALUE result, EventHookHash;
int status = 0;
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.
if(rb_funcall(rb_stdin, rb_intern("isatty"), 0) == Qtrue)
rb_funcall(rb_stdin, rb_intern("reopen"), 1, rb_str_new2("NUL"));
if(rb_funcall(rb_stdout, rb_intern("isatty"), 0) == Qtrue)
rb_funcall(rb_stdout, rb_intern("reopen"), 1, rb_str_new2("NUL"));
if(rb_funcall(rb_stderr, rb_intern("isatty"), 0) == Qtrue)
rb_funcall(rb_stderr, rb_intern("reopen"), 1, rb_str_new2("NUL"));
// Use a markable instance variable to prevent the garbage collector
// from freeing the hash before Ruby_Service_Ctrl exits, or just
// at any ole time while running the service
EventHookHash = rb_hash_new();
rb_ivar_set(self, rb_intern("@event_hooks"), EventHookHash);
// Event hooks
if(rb_respond_to(self, rb_intern("service_stop"))){
rb_hash_aset(EventHookHash, INT2NUM(SERVICE_CONTROL_STOP),
rb_ary_new3(2, self, INT2NUM(rb_intern("service_stop"))));
}
if(rb_respond_to(self, rb_intern("service_pause"))){
rb_hash_aset(EventHookHash, INT2NUM(SERVICE_CONTROL_PAUSE),
rb_ary_new3(2, self, INT2NUM(rb_intern("service_pause"))));
}
if(rb_respond_to(self, rb_intern("service_resume"))){
rb_hash_aset(EventHookHash, INT2NUM(SERVICE_CONTROL_CONTINUE),
rb_ary_new3(2, self, INT2NUM(rb_intern("service_resume"))));
}
if(rb_respond_to(self, rb_intern("service_interrogate"))){
rb_hash_aset(EventHookHash, INT2NUM(SERVICE_CONTROL_INTERROGATE),
rb_ary_new3(2, self, INT2NUM(rb_intern("service_interrogate"))));
}
if(rb_respond_to(self, rb_intern("service_shutdown"))){
rb_hash_aset(EventHookHash, INT2NUM(SERVICE_CONTROL_SHUTDOWN),
rb_ary_new3(2, self, INT2NUM(rb_intern("service_shutdown"))));
}
#ifdef SERVICE_CONTROL_PARAMCHANGE
if(rb_respond_to(self, rb_intern("service_paramchange"))){
rb_hash_aset(EventHookHash, INT2NUM(SERVICE_CONTROL_PARAMCHANGE),
rb_ary_new3(2, self, INT2NUM(rb_intern("service_paramchange"))));
}
#endif
#ifdef SERVICE_CONTROL_NETBINDADD
if(rb_respond_to(self, rb_intern("service_netbindadd"))){
rb_hash_aset(EventHookHash, INT2NUM(SERVICE_CONTROL_NETBINDADD),
rb_ary_new3(2, self, INT2NUM(rb_intern("service_netbindadd"))));
}
#endif
#ifdef SERVICE_CONTROL_NETBINDREMOVE
if(rb_respond_to(self, rb_intern("service_netbindremove"))){
rb_hash_aset(EventHookHash, INT2NUM(SERVICE_CONTROL_NETBINDREMOVE),
rb_ary_new3(2, self, INT2NUM(rb_intern("service_netbindremove"))));
}
#endif
#ifdef SERVICE_CONTROL_NETBINDENABLE
if(rb_respond_to(self, rb_intern("service_netbindenable"))){
rb_hash_aset(EventHookHash, INT2NUM(SERVICE_CONTROL_NETBINDENABLE),
rb_ary_new3(2, self, INT2NUM(rb_intern("service_netbindenable"))));
}
#endif
#ifdef SERVICE_CONTROL_NETBINDDISABLE
if(rb_respond_to(self, rb_intern("service_netbinddisable"))){
rb_hash_aset(EventHookHash, INT2NUM(SERVICE_CONTROL_NETBINDDISABLE),
rb_ary_new3(2, self, INT2NUM(rb_intern("service_netbinddisable"))));
}
#endif
// 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 - I may fix this
// later
if(rb_respond_to(self, rb_intern("service_init")))
rb_funcall(self, rb_intern("service_init"),0);
// Create the event to signal the service to start.
hStartEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
if(hStartEvent == NULL)
rb_raise(cDaemonError, ErrorDescription(GetLastError()));
// Create the event to signal the service to stop.
hStopEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
if(hStopEvent == NULL)
rb_raise(cDaemonError, ErrorDescription(GetLastError()));
// Create the event to signal the service that stop has completed
hStopCompletedEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
if(hStopCompletedEvent == NULL)
rb_raise(cDaemonError, ErrorDescription(GetLastError()));
// Create Thread for service main
hThread = CreateThread(NULL, 0, ThreadProc, 0, 0, &ThreadId);
if(hThread == INVALID_HANDLE_VALUE)
rb_raise(cDaemonError, ErrorDescription(GetLastError()));
events[0] = hThread;
events[1] = hStartEvent;
// wait for Service_Main function to either start the service OR terminate
while((index = WaitForMultipleObjects(2,events,FALSE,1000)) == WAIT_TIMEOUT)
{
}
// thread exited, so the show is off
if(index == WAIT_OBJECT_0)
rb_raise(cDaemonError, "Service_Main thread exited abnormally");
// from this point onward, stopevent must be triggered!
// Create the green thread to poll for Service_Ctrl events
rb_thread_create(Ruby_Service_Ctrl, (void *)self);
result = rb_protect(daemon_mainloop_protect, self, &status);
// service_main raised an exception
if(status){
daemon_mainloop_ensure(self);
rb_jump_tag(status);
}
// service_main exited cleanly
return daemon_mainloop_ensure(self);
}
|
#running? ⇒ Boolean
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
537 538 539 540 541 542 543 544 545 546 547 548 549 |
# File 'ext/win32/daemon.c', line 537
static VALUE daemon_is_running(VALUE self){
VALUE v_bool = Qfalse;
if(
(dwServiceState == SERVICE_RUNNING) ||
(dwServiceState == SERVICE_PAUSED) ||
(dwServiceState == 0)
){
v_bool = Qtrue;
}
return v_bool;
}
|
#state ⇒ Object
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.
518 519 520 |
# File 'ext/win32/daemon.c', line 518 static VALUE daemon_state(VALUE self){ return UINT2NUM(dwServiceState); } |