perl-modperl mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From Joshua Chamas <jos...@chamas.com>
Subject Apache::SizeLimit MAX UNSHARED patch
Date Sat, 03 Feb 2001 01:51:52 GMT
Hey,

Per Perrin Harkin's advice, and my client's consent, I hacked 
up Apache::SizeLimit to support MAX_PROCESS_UNSHARED_SIZE config, 
where instead of limiting by the apparent process size, one limits 
by the amount of unshared memory being used.  Unshared memory is the 
effective process size, in terms of how much of your machine's RAM 
its eating.   It rewards you for pre-loading modules and pre-compiling
scripts in your parent httpd.

The patch is below, and only supports this config on linux.
My development was on a linux 2.2 kernel, a relies on the format
in /proc/self/statm staying the same.

As Perrin's tells it in a previous thread, this is apparently
a better method of limiting your processes, than 
Apache::GTopLimit's MIN_PROCESS_SHARED_SIZE, and further
does not require installation of libgtop.

Please mail me for the full file, if this diff is too unwieldy.

--Josh


--- SizeLimit.pm~	Fri Feb  2 11:36:43 2001
+++ SizeLimit.pm	Fri Feb  2 13:52:39 2001
@@ -14,6 +14,9 @@
     use Apache::SizeLimit;
     $Apache::SizeLimit::MAX_PROCESS_SIZE = 10000; # in KB, so this is 10MB
 
+    # in KB, so this is 10MB, only supported under linux currently
+    $Apache::SizeLimit::MAX_PROCESS_UNSHARED_SIZE = 10000; 
+
     # in your httpd.conf:
     PerlFixupHandler Apache::SizeLimit
     # you can set this up as any Perl*Handler that handles part of the
@@ -26,6 +29,7 @@
     # in your CGI:
     use Apache::SizeLimit;
     &Apache::SizeLimit::setmax(10000);	# Max Process Size in KB
+    &Apache::SizeLimit::setmax_unshared(10000); # Max Unshared RAM Size in KB
 
 Since checking the process size can take a few system calls on some
 platforms (e.g. linux), you may want to only check the process size every
@@ -83,6 +87,9 @@
 (with the C<setmax> function), and see if the CHECK_EVERY_N_REQUESTS
 option is of benefit.
 
+Currently, linux is the only platform that supports the 
+MAX_PROCESS_UNSHARED_SIZE and setmax_unshared() settings.
+
 =item solaris 2.6
 
 For solaris we simply retrieve the size of /proc/self/as, which
@@ -120,12 +127,14 @@
 use Apache::Constants qw(:common);
 use Config;
 use strict;
-use vars qw($VERSION $HOW_BIG_IS_IT $MAX_PROCESS_SIZE
-	    $REQUEST_COUNT $CHECK_EVERY_N_REQUESTS);
+use vars qw($VERSION $HOW_BIG_IS_IT $HOW_UNSHARED_IS_IT 
+	    $MAX_PROCESS_SIZE $MAX_PROCESS_UNSHARED_SIZE
+	    $REQUEST_COUNT $CHECK_EVERY_N_REQUESTS $CHECK_TOTAL);
 
-$VERSION = '0.03';
+$VERSION = '0.05';
 $CHECK_EVERY_N_REQUESTS = 1;
 $REQUEST_COUNT = 1;
+$CHECK_TOTAL = 0;
 
 BEGIN {
     # decide at compile time how to check for a process' memory size.
@@ -134,6 +143,7 @@
 	$HOW_BIG_IS_IT = \&solaris_2_6_size_check;
     } elsif ($Config{'osname'} eq 'linux') {
 	$HOW_BIG_IS_IT = \&linux_size_check;
+	$HOW_UNSHARED_IS_IT = \&linux_unshared_size_check;
     } elsif ($Config{'osname'} =~ /(bsd|aix)/i) {
 	# will getrusage work on all BSDs?  I should hope so.
 	if (eval("require BSD::Resource;")) {
@@ -159,6 +169,24 @@
     return($size);
 }
 
+sub linux_unshared_size_check {
+    my $unshared_size = 0;
+    local(*FH);
+    if (open(FH, "</proc/self/statm")) {
+	my $data = <FH>;
+	close(FH);
+	my($size, $resident, $shared) = split(/\s+/, $data);
+	if($resident && $shared) {
+	    $unshared_size = 4 * ($resident - $shared); # 4KB pages listed
+	} else {
+	    &error_log("Fatal Error: /proc/self/statm not right format, got: $data");
+	}
+    } else {
+	&error_log("Fatal Error: couldn't access /proc/self/statm: $!");
+    }
+    return($unshared_size);
+}
+
 sub solaris_2_6_size_check {
     my $size = -s "/proc/self/as" or
 	&error_log("Fatal Error: /proc/self/as doesn't exist or is empty");
@@ -171,6 +199,7 @@
 }
 
 sub exit_if_too_big {
+    $CHECK_TOTAL++;
     return if ($REQUEST_COUNT++ < $CHECK_EVERY_N_REQUESTS);
     $REQUEST_COUNT = 1;
     if (defined($MAX_PROCESS_SIZE)) {
@@ -184,8 +213,25 @@
 		&error_log("main process too big, SIZE=$size KB");
 	    }
 	}
+    } elsif (defined($MAX_PROCESS_UNSHARED_SIZE)) {
+	if($HOW_UNSHARED_IS_IT) {
+	    my $size = &$HOW_UNSHARED_IS_IT();
+	    if($size > $MAX_PROCESS_UNSHARED_SIZE) {
+		if(getppid > 1) { # this is a child httpd
+		    &error_log("httpd process too unshared, exiting at UNSHARED SIZE=$size KB, after
$CHECK_TOTAL checks");
+		    &Apache::exit(-2);
+		} else {
+		    # don't do anything for main httpd
+		}
+	    } else {
+		# don't do anything
+	    }
+	} else {
+	    &error_log("no MAX_PROCESS_UNSHARED_SIZE handler for this platform $^O, ".
+		       "currently only linux supported");
+	}
     } else {
-	&error_log("you didn't set \$Apache::SizeLimit::MAX_PROCESS_SIZE");
+	&error_log("you didn't set \$Apache::SizeLimit::MAX_PROCESS_SIZE or MAX_PROCESS_UNSHARED_SIZE");
     }
 }
 
@@ -194,6 +240,11 @@
 sub setmax {
     $MAX_PROCESS_SIZE = shift;
     Apache->request->post_connection(\&exit_if_too_big);
+}
+
+sub setmax_unshared {
+    $MAX_PROCESS_UNSHARED_SIZE = shift;
+    Apache->request->post_cleanup(\&exit_if_too_big);
 }
 
 sub handler {

Mime
View raw message