/rautor/common/Threaded.pm

https://github.com/kangelos/Rautor-and-friends · Perl · 157 lines · 91 code · 47 blank · 19 comment · 10 complexity · 71c82e2c5dcbc92150a5bfbb51354443 MD5 · raw file

  1. package HTTP::Proxy::Engine::Threaded;
  2. use strict;
  3. use POSIX 'WNOHANG';
  4. use HTTP::Proxy;
  5. use threads;
  6. our @ISA = qw( HTTP::Proxy::Engine );
  7. our %defaults = (
  8. max_clients => 120,
  9. );
  10. __PACKAGE__->make_accessors( qw( kids select ), keys %defaults );
  11. sub start {
  12. my $self = shift;
  13. $self->kids( [] );
  14. $self->select( IO::Select->new( $self->proxy->daemon ) );
  15. }
  16. sub run {
  17. my $self = shift;
  18. my $proxy = $self->proxy;
  19. my $kids = $self->kids;
  20. # check for new connections
  21. my @ready = $self->select->can_read(1);
  22. for my $fh (@ready) { # there's only one, anyway
  23. # single-process proxy (useful for debugging)
  24. # accept the new connection
  25. my $conn = $fh->accept;
  26. my $child=threads->new(\&worker,$proxy,$conn);
  27. if ( !defined $child ) {
  28. $conn->close;
  29. $proxy->log( HTTP::Proxy::ERROR, "PROCESS", "Cannot start" );
  30. next;
  31. }
  32. $child->detach();
  33. # # the parent process
  34. # if ($child) {
  35. # $conn->close;
  36. # $proxy->log( HTTP::Proxy::PROCESS, "PROCESS", "Forked child process $child" );
  37. # push @$kids, $child;
  38. # }
  39. #
  40. # the child process handles the whole connection
  41. # else {
  42. # $SIG{INT} = 'DEFAULT';
  43. # $proxy->serve_connections($conn);
  44. # exit; # let's die!
  45. # }
  46. }
  47. }
  48. sub stop {
  49. my $self = shift;
  50. my $kids = $self->kids;
  51. # wait for remaining children
  52. # EOLOOP
  53. kill INT => @$kids;
  54. $self->reap_zombies while @$kids;
  55. }
  56. sub worker {
  57. my $proxy=shift;
  58. my $conn=shift;
  59. $proxy->serve_connections($conn);
  60. $conn->close();
  61. return;
  62. }
  63. # private reaper sub
  64. sub reap_zombies {
  65. my $self = shift;
  66. my $kids = $self->kids;
  67. my $proxy = $self->proxy;
  68. while (1) {
  69. my $pid = waitpid( -1, WNOHANG );
  70. last if $pid == 0 || $pid == -1; # AS/Win32 returns negative PIDs
  71. @$kids = grep { $_ != $pid } @$kids;
  72. $proxy->{conn}++; # Cannot use the interface for RO attributes
  73. $proxy->log( HTTP::Proxy::PROCESS, "PROCESS", "Reaped child process $pid" );
  74. $proxy->log( HTTP::Proxy::PROCESS, "PROCESS", @$kids . " remaining kids: @$kids" );
  75. }
  76. }
  77. 1;
  78. __END__
  79. =head1 NAME
  80. HTTP::Proxy::Engine::Legacy - The "older" HTTP::Proxy engine
  81. =head1 SYNOPSIS
  82. my $proxy = HTTP::Proxy->new( engine => 'Legacy' );
  83. =head1 DESCRIPTION
  84. This engine reproduces the older child creation algorithm of HTTP::Proxy.
  85. =head1 METHODS
  86. The module defines the following methods, used by HTTP::Proxy main loop:
  87. =over
  88. =item start()
  89. Initialise the engine.
  90. =item run()
  91. Implements the forking logic: a new process is forked for each new
  92. incoming TCP connection.
  93. =item stop()
  94. Reap remaining child processes.
  95. =back
  96. The following method is used by the engine internally:
  97. =over 4
  98. =item reap_zombies()
  99. Process the dead child processes.
  100. =back
  101. =head1 SEE ALSO
  102. L<HTTP::Proxy>, L<HTTP::Proxy::Engine>.
  103. =head1 AUTHOR
  104. Philippe "BooK" Bruhat, C<< <book@cpan.org> >>.
  105. =head1 COPYRIGHT
  106. Copyright 2005, Philippe Bruhat.
  107. =head1 LICENSE
  108. This module is free software; you can redistribute it or modify it under
  109. the same terms as Perl itself.
  110. =cut