#! /bin/sh /usr/share/dpatch/dpatch-run
## 360-rad_check_ts_waitpid.dpatch by  <joe@nameserver3.ttec.com>
##
## All lines beginning with `## DP:' are a description of the patch.
## DP: No description.

@DPATCH@
diff -urNad freeradius-2.0.0~/src/main/threads.c freeradius-2.0.0/src/main/threads.c
--- freeradius-2.0.0~/src/main/threads.c	2007-01-17 09:00:25.000000000 -0500
+++ freeradius-2.0.0/src/main/threads.c	2007-01-17 09:02:37.000000000 -0500
@@ -113,10 +113,12 @@
 	RAD_REQUEST_FUNP  fun;
 } request_queue_t;
 
+#define MAX_WAITERS	1024
 typedef struct thread_fork_t {
 	pid_t		pid;
 	int		status;
 	int		exited;
+	int		reaper_created;
 } thread_fork_t;
 
 
@@ -257,10 +259,10 @@
 	pid_t pid;
 	int status;
 	thread_fork_t mytf, *tf;
-
-	if (lrad_hash_table_num_elements(thread_pool.waiters) == 0) return;
-
-	pthread_mutex_lock(&thread_pool.wait_mutex);
+	int num_waiters = lrad_hash_table_num_elements(thread_pool.waiters);
+	
+	if (!num_waiters)
+		return;
 
 	while (1) {
 		pid = waitpid(0, &status, WNOHANG);
@@ -268,12 +270,26 @@
 
 		mytf.pid = pid;
 		tf = lrad_hash_table_finddata(thread_pool.waiters, &mytf);
-		if (!tf) continue;
-		
-		tf->status = status;
+		if (!tf)
+		{
+			tf = rad_malloc(sizeof(*tf));
+			memset(tf, 0, sizeof(*tf));
+			tf->pid = pid;
+			tf->status = status;
+			tf->exited = 1;
+			tf->reaper_created = 1;
+			if (!lrad_hash_table_insert(thread_pool.waiters, tf))
+			{
+				free(tf);
+				tf = NULL;
+			}
+			if (++num_waiters >= MAX_WAITERS)
+				break;
+			continue;
+		}
 		tf->exited = 1;
+		tf->status = status;
 	}
-
 	pthread_mutex_unlock(&thread_pool.wait_mutex);
 }
 
@@ -1049,16 +1065,29 @@
 /*
  *	Thread wrapper for fork().
  */
+static int reap_reaper_children(void * context, void * data)
+{
+	thread_fork_t *tf = data;
+	if (tf->reaper_created)
+		lrad_hash_table_delete(thread_pool.waiters, tf);
+	return 0;
+}
+
 pid_t rad_fork(int exec_wait)
 {
 	pid_t child_pid;
+	int num_waiters;
 
 	if (exec_wait) return fork();
 
 	reap_children();	/* be nice to non-wait thingies */
 
-	if (lrad_hash_table_num_elements(thread_pool.waiters) >= 1024) {
-		return -1;
+	if (lrad_hash_table_num_elements(thread_pool.waiters) >= MAX_WAITERS) {
+		lrad_hash_table_walk(thread_pool.waiters, reap_reaper_children, NULL);
+		if ((num_waiters = lrad_hash_table_num_elements(thread_pool.waiters)) >= MAX_WAITERS) {
+			radlog(L_ERR, "too many child waiters: %d", num_waiters);
+			return -1;
+		}
 	}
 
 	/*
@@ -1104,8 +1133,8 @@
 pid_t rad_waitpid(pid_t pid, int *status, int options)
 {
 	thread_fork_t mytf, *tf;
+	pid_t child_pid = 0;
 
-	reap_children();	/* be nice to non-wait thingies */
 
 	if (pid <= 0) return -1;
 
@@ -1117,22 +1146,21 @@
 	tf = lrad_hash_table_finddata(thread_pool.waiters, &mytf);
 
 	if (!tf) {		/* not found.  It's a problem... */
-		pthread_mutex_unlock(&thread_pool.wait_mutex);
-		return waitpid(pid, status, options);
+		child_pid = waitpid(pid, status, options);
 	}
-
-	if (tf->exited) {
+	else if (tf->exited) {
 		*status = tf->status;
 		lrad_hash_table_delete(thread_pool.waiters, &mytf);
-		pthread_mutex_unlock(&thread_pool.wait_mutex);
-		return pid;
+		child_pid = pid;
 	}
-	
 	/*
-	 *	Don't wait, and it hasn't exited.  Return.
+	 * else {
+	 *	Don't wait, and it hasn't exited.  Return 0.
+	 * }
 	 */
+	reap_children();	/* be nice to non-wait thingies */
 	pthread_mutex_unlock(&thread_pool.wait_mutex);
-	return 0;
+	return child_pid;
 }
 
 #else /* HAVE_PTHREAD_H */
