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