Blame SOURCES/mysql-stack-guard.patch

6f9931
mysql is not accounting for the "guard page" when setting thread stack size
6f9931
requests.  This is fatal on PPC systems, which may use guard pages as large
6f9931
as 64K.  This patch also documents the IA64 situation a bit better.
6f9931
6f9931
Note: there are quite a few other setstacksize calls besides the two in
6f9931
mysqld.cc; is it important to fix any of the others?
6f9931
6f9931
Filed upstream at http://bugs.mysql.com/bug.php?id=35019
6f9931
6f9931
6f9931
diff -Naur mysql-5.5.8.orig/sql/mysqld.cc mysql-5.5.8/sql/mysqld.cc
6f9931
--- mysql-5.5.8.orig/sql/mysqld.cc	2010-12-03 12:58:26.000000000 -0500
6f9931
+++ mysql-5.5.8/sql/mysqld.cc	2010-12-20 22:01:08.939186906 -0500
015dab
@@ -2608,6 +2608,70 @@
6f9931
 }
6f9931
 
6f9931
 
6f9931
+/* pthread_attr_setstacksize without so much platform-dependency */
6f9931
+/* returns the actual stack size if possible */
6f9931
+static size_t my_setstacksize(pthread_attr_t *attr, size_t stacksize)
6f9931
+{
6f9931
+  size_t guard_size = 0;
6f9931
+
6f9931
+#if defined(__ia64__) || defined(__ia64)
6f9931
+  /*
6f9931
+    On IA64, half of the requested stack size is used for "normal stack"
6f9931
+    and half for "register stack".  The space measured by check_stack_overrun
6f9931
+    is the "normal stack", so double the request to make sure we have the
6f9931
+    caller-expected amount of normal stack.
6f9931
+
6f9931
+    NOTE: there is no guarantee that the register stack can't grow faster
6f9931
+    than normal stack, so it's very unclear that we won't dump core due to
6f9931
+    stack overrun despite check_stack_overrun's efforts.  Experimentation
6f9931
+    shows that in the execution_constants test, the register stack grows
6f9931
+    less than half as fast as normal stack, but perhaps other scenarios are
6f9931
+    less forgiving.  If it turns out that more space is needed for the
6f9931
+    register stack, that could be forced (rather inefficiently) by using a
6f9931
+    multiplier higher than 2 here.
6f9931
+  */
6f9931
+  stacksize *= 2;
6f9931
+#endif
6f9931
+
6f9931
+  /*
6f9931
+    On many machines, the "guard space" is subtracted from the requested
6f9931
+    stack size, and that space is quite large on some platforms.  So add
6f9931
+    it to our request, if we can find out what it is.
6f9931
+
6f9931
+    FIXME: autoconfiscate use of pthread_attr_getguardsize
6f9931
+  */
6f9931
+  if (pthread_attr_getguardsize(attr, &guard_size))
6f9931
+    guard_size = 0;		/* if can't find it out, treat as 0 */
6f9931
+
6f9931
+  pthread_attr_setstacksize(attr, stacksize + guard_size);
6f9931
+
6f9931
+  /* Retrieve actual stack size if possible */
6f9931
+#ifdef HAVE_PTHREAD_ATTR_GETSTACKSIZE
6f9931
+  {
6f9931
+    size_t real_stack_size= 0;
6f9931
+    /* We must ignore real_stack_size = 0 as Solaris 2.9 can return 0 here */
6f9931
+    if (pthread_attr_getstacksize(attr, &real_stack_size) == 0 &&
6f9931
+	real_stack_size > guard_size)
6f9931
+    {
6f9931
+      real_stack_size -= guard_size;
6f9931
+      if (real_stack_size < stacksize)
6f9931
+      {
6f9931
+	if (global_system_variables.log_warnings)
6f9931
+	  sql_print_warning("Asked for %ld thread stack, but got %ld",
6f9931
+			    (long) stacksize, (long) real_stack_size);
6f9931
+	stacksize= real_stack_size;
6f9931
+      }
6f9931
+    }
6f9931
+  }
6f9931
+#endif
6f9931
+
6f9931
+#if defined(__ia64__) || defined(__ia64)
6f9931
+  stacksize /= 2;
6f9931
+#endif
6f9931
+  return stacksize;
6f9931
+}
6f9931
+
6f9931
+
6f9931
 static void start_signal_handler(void)
6f9931
 {
6f9931
   int error;
015dab
@@ -2618,15 +2682,7 @@
6f9931
 #if !defined(HAVE_DEC_3_2_THREADS)
6f9931
   pthread_attr_setscope(&thr_attr,PTHREAD_SCOPE_SYSTEM);
6f9931
   (void) pthread_attr_setdetachstate(&thr_attr,PTHREAD_CREATE_DETACHED);
6f9931
-#if defined(__ia64__) || defined(__ia64)
6f9931
-  /*
6f9931
-    Peculiar things with ia64 platforms - it seems we only have half the
6f9931
-    stack size in reality, so we have to double it here
6f9931
-  */
6f9931
-  pthread_attr_setstacksize(&thr_attr,my_thread_stack_size*2);
6f9931
-#else
6f9931
-  pthread_attr_setstacksize(&thr_attr,my_thread_stack_size);
6f9931
-#endif
6f9931
+  (void) my_setstacksize(&thr_attr,my_thread_stack_size);
6f9931
 #endif
6f9931
 
6f9931
   mysql_mutex_lock(&LOCK_thread_count);
015dab
@@ -4474,36 +4530,8 @@
6f9931
     unireg_abort(1);				// Will do exit
6f9931
 
6f9931
   init_signals();
6f9931
-#if defined(__ia64__) || defined(__ia64)
6f9931
-  /*
6f9931
-    Peculiar things with ia64 platforms - it seems we only have half the
6f9931
-    stack size in reality, so we have to double it here
6f9931
-  */
6f9931
-  pthread_attr_setstacksize(&connection_attrib,my_thread_stack_size*2);
6f9931
-#else
6f9931
-  pthread_attr_setstacksize(&connection_attrib,my_thread_stack_size);
6f9931
-#endif
6f9931
 #ifdef HAVE_PTHREAD_ATTR_GETSTACKSIZE
6f9931
-  {
6f9931
-    /* Retrieve used stack size;  Needed for checking stack overflows */
6f9931
-    size_t stack_size= 0;
6f9931
-    pthread_attr_getstacksize(&connection_attrib, &stack_size);
6f9931
-#if defined(__ia64__) || defined(__ia64)
6f9931
-    stack_size/= 2;
6f9931
-#endif
6f9931
-    /* We must check if stack_size = 0 as Solaris 2.9 can return 0 here */
6f9931
-    if (stack_size && stack_size < my_thread_stack_size)
6f9931
-    {
6f9931
-      if (global_system_variables.log_warnings)
6f9931
-	sql_print_warning("Asked for %lu thread stack, but got %ld",
6f9931
-			  my_thread_stack_size, (long) stack_size);
6f9931
-#if defined(__ia64__) || defined(__ia64)
6f9931
-      my_thread_stack_size= stack_size*2;
6f9931
-#else
6f9931
-      my_thread_stack_size= stack_size;
6f9931
-#endif
6f9931
-    }
6f9931
-  }
6f9931
+  my_thread_stack_size = my_setstacksize(&connection_attrib,my_thread_stack_size);
6f9931
 #endif
6f9931
 
6f9931
   (void) thr_setconcurrency(concurrency);	// 10 by default