Sophie

Sophie

distrib > Fedora > 18 > x86_64 > by-pkgid > a7c79ef25792666232691851203f62e0 > files > 4

perl-Sendmail-PMilter-1.00-8.fc18.src.rpm

--- lib/Sendmail/PMilter.pm
+++ lib/Sendmail/PMilter.pm
@@ -44,6 +44,7 @@
 use Sendmail::Milter 0.18; # get needed constants
 use Socket;
 use Symbol;
+use Time::HiRes 'time';
 use UNIVERSAL;
 
 our $VERSION = '1.00';
@@ -654,6 +655,7 @@
 sub ithread_dispatcher {
 	require threads;
 	require threads::shared;
+	require Thread::Semaphore;
 
 	my $nchildren = 0;
 
@@ -664,6 +666,11 @@
 		my $lsocket = shift;
 		my $handler = shift;
 		my $maxchildren = $this->get_max_interpreters();
+		my $child_sem;
+
+		if ($maxchildren) {
+			$child_sem = Thread::Semaphore->new($maxchildren);
+		}
 
 		my $siginfo = exists($SIG{INFO}) ? 'INFO' : 'USR1';
 		local $SIG{$siginfo} = sub {
@@ -681,6 +688,9 @@
 
 			lock($nchildren);
 			$nchildren--;
+			if ($child_sem) {
+				$child_sem->up();
+			}
 			warn $died if $died;
 		};
 
@@ -690,18 +700,12 @@
 
 			warn "$$: incoming connection\n" if ($DEBUG > 0);
 
-			# If the load's too high, fail and go back to top of loop.
-			if ($maxchildren) {
-				my $cnchildren = $nchildren; # make constant
-
-				if ($cnchildren >= $maxchildren) {
-					warn "load too high: children $cnchildren >= max $maxchildren";
-
-					$socket->autoflush(1);
-					$socket->print(pack('N/a*', 't')); # SMFIR_TEMPFAIL
-					$socket->close();
-					next;
-				}
+			if ($child_sem and ! $child_sem->down_nb()) {
+				warn "pausing for high load: children $nchildren >= max $maxchildren";
+				my $start = time();
+				$child_sem->down();
+				my $end = time();
+				warn sprintf("paused for %.1f seconds due to high load", $end - $start);
 			}
 
 			# scoping block for lock()
@@ -867,6 +871,10 @@
 otherwise mostly idle mail traffic, as the idle-time resource consumption is
 very low.
 
+If the maximum number of interpreters is running when a new connection
+comes in, this dispatcher blocks until a slot becomes available for a
+new interpreter.
+
 =cut
 
 sub postfork_dispatcher () {
@@ -900,17 +908,22 @@
 			warn "$$: incoming connection\n" if ($DEBUG > 0);
 
 			# If the load's too high, fail and go back to top of loop.
-			if ($maxchildren) {
+			my $paused = undef;
+			while ($maxchildren) {
 				my $cnchildren = $nchildren; # make constant
 
 				if ($cnchildren >= $maxchildren) {
-					warn "load too high: children $cnchildren >= max $maxchildren";
-
-					$socket->autoflush(1);
-					$socket->print(pack('N/a*', 't')); # SMFIR_TEMPFAIL
-					$socket->close();
-					next;
+					warn "pausing for high load: children $cnchildren >= max $maxchildren";
+					$paused = time() if (! $paused);
+					pause();
 				}
+				else {
+					last;
+				}
+			}
+
+			if ($paused) {
+				warn sprintf("paused for %.1f seconds due to high load", time() - $paused);
 			}
 
 			my $pid = fork();