1 |
mysql is not accounting for the "guard page" when setting thread stack size |
2 |
requests. This is fatal on PPC systems, which may use guard pages as large |
3 |
as 64K. This patch also documents the IA64 situation a bit better. |
4 |
|
5 |
Note: there are quite a few other setstacksize calls besides the two in |
6 |
mysqld.cc; is it important to fix any of the others? |
7 |
|
8 |
Filed upstream at http://bugs.mysql.com/bug.php?id=35019 |
9 |
Filed upstream at https://bugs.launchpad.net/maria/+bug/886368 |
10 |
|
11 |
|
12 |
diff -Naur 5.5_orig/sql/mysqld.cc 5.5/sql/mysqld.cc |
13 |
--- 5.5_orig/sql/mysqld.cc 2011-11-01 16:20:49.000000000 +0100 |
14 |
+++ 5.5/sql/mysqld.cc 2011-11-04 22:31:16.802088023 +0100 |
15 |
@@ -3010,6 +3010,70 @@ |
16 |
} |
17 |
|
18 |
|
19 |
+/* pthread_attr_setstacksize without so much platform-dependency */ |
20 |
+/* returns the actual stack size if possible */ |
21 |
+static size_t my_setstacksize(pthread_attr_t *attr, size_t stacksize) |
22 |
+{ |
23 |
+ size_t guard_size = 0; |
24 |
+ |
25 |
+#if defined(__ia64__) || defined(__ia64) |
26 |
+ /* |
27 |
+ On IA64, half of the requested stack size is used for "normal stack" |
28 |
+ and half for "register stack". The space measured by check_stack_overrun |
29 |
+ is the "normal stack", so double the request to make sure we have the |
30 |
+ caller-expected amount of normal stack. |
31 |
+ |
32 |
+ NOTE: there is no guarantee that the register stack can't grow faster |
33 |
+ than normal stack, so it's very unclear that we won't dump core due to |
34 |
+ stack overrun despite check_stack_overrun's efforts. Experimentation |
35 |
+ shows that in the execution_constants test, the register stack grows |
36 |
+ less than half as fast as normal stack, but perhaps other scenarios are |
37 |
+ less forgiving. If it turns out that more space is needed for the |
38 |
+ register stack, that could be forced (rather inefficiently) by using a |
39 |
+ multiplier higher than 2 here. |
40 |
+ */ |
41 |
+ stacksize *= 2; |
42 |
+#endif |
43 |
+ |
44 |
+ /* |
45 |
+ On many machines, the "guard space" is subtracted from the requested |
46 |
+ stack size, and that space is quite large on some platforms. So add |
47 |
+ it to our request, if we can find out what it is. |
48 |
+ |
49 |
+ FIXME: autoconfiscate use of pthread_attr_getguardsize |
50 |
+ */ |
51 |
+ if (pthread_attr_getguardsize(attr, &guard_size)) |
52 |
+ guard_size = 0; /* if can't find it out, treat as 0 */ |
53 |
+ |
54 |
+ pthread_attr_setstacksize(attr, stacksize + guard_size); |
55 |
+ |
56 |
+ /* Retrieve actual stack size if possible */ |
57 |
+#ifdef HAVE_PTHREAD_ATTR_GETSTACKSIZE |
58 |
+ { |
59 |
+ size_t real_stack_size= 0; |
60 |
+ /* We must ignore real_stack_size = 0 as Solaris 2.9 can return 0 here */ |
61 |
+ if (pthread_attr_getstacksize(attr, &real_stack_size) == 0 && |
62 |
+ real_stack_size > guard_size) |
63 |
+ { |
64 |
+ real_stack_size -= guard_size; |
65 |
+ if (real_stack_size < stacksize) |
66 |
+ { |
67 |
+ if (global_system_variables.log_warnings) |
68 |
+ sql_print_warning("Asked for %ld thread stack, but got %ld", |
69 |
+ (long) stacksize, (long) real_stack_size); |
70 |
+ stacksize= real_stack_size; |
71 |
+ } |
72 |
+ } |
73 |
+ } |
74 |
+#endif |
75 |
+ |
76 |
+#if defined(__ia64__) || defined(__ia64) |
77 |
+ stacksize /= 2; |
78 |
+#endif |
79 |
+ return stacksize; |
80 |
+} |
81 |
+ |
82 |
+ |
83 |
static void start_signal_handler(void) |
84 |
{ |
85 |
int error; |
86 |
@@ -3020,15 +3084,7 @@ |
87 |
#if !defined(HAVE_DEC_3_2_THREADS) |
88 |
pthread_attr_setscope(&thr_attr,PTHREAD_SCOPE_SYSTEM); |
89 |
(void) pthread_attr_setdetachstate(&thr_attr,PTHREAD_CREATE_DETACHED); |
90 |
-#if defined(__ia64__) || defined(__ia64) |
91 |
- /* |
92 |
- Peculiar things with ia64 platforms - it seems we only have half the |
93 |
- stack size in reality, so we have to double it here |
94 |
- */ |
95 |
- pthread_attr_setstacksize(&thr_attr,my_thread_stack_size*2); |
96 |
-#else |
97 |
- pthread_attr_setstacksize(&thr_attr,my_thread_stack_size); |
98 |
-#endif |
99 |
+ (void) my_setstacksize(&thr_attr,my_thread_stack_size); |
100 |
#endif |
101 |
|
102 |
mysql_mutex_lock(&LOCK_thread_count); |
103 |
@@ -4845,36 +4901,8 @@ |
104 |
unireg_abort(1); // Will do exit |
105 |
|
106 |
init_signals(); |
107 |
-#if defined(__ia64__) || defined(__ia64) |
108 |
- /* |
109 |
- Peculiar things with ia64 platforms - it seems we only have half the |
110 |
- stack size in reality, so we have to double it here |
111 |
- */ |
112 |
- pthread_attr_setstacksize(&connection_attrib,my_thread_stack_size*2); |
113 |
-#else |
114 |
- pthread_attr_setstacksize(&connection_attrib,my_thread_stack_size); |
115 |
-#endif |
116 |
#ifdef HAVE_PTHREAD_ATTR_GETSTACKSIZE |
117 |
- { |
118 |
- /* Retrieve used stack size; Needed for checking stack overflows */ |
119 |
- size_t stack_size= 0; |
120 |
- pthread_attr_getstacksize(&connection_attrib, &stack_size); |
121 |
-#if defined(__ia64__) || defined(__ia64) |
122 |
- stack_size/= 2; |
123 |
-#endif |
124 |
- /* We must check if stack_size = 0 as Solaris 2.9 can return 0 here */ |
125 |
- if (stack_size && stack_size < my_thread_stack_size) |
126 |
- { |
127 |
- if (global_system_variables.log_warnings) |
128 |
- sql_print_warning("Asked for %lu thread stack, but got %ld", |
129 |
- my_thread_stack_size, (long) stack_size); |
130 |
-#if defined(__ia64__) || defined(__ia64) |
131 |
- my_thread_stack_size= stack_size*2; |
132 |
-#else |
133 |
- my_thread_stack_size= stack_size; |
134 |
-#endif |
135 |
- } |
136 |
- } |
137 |
+ my_thread_stack_size = my_setstacksize(&connection_attrib,my_thread_stack_size); |
138 |
#endif |
139 |
|
140 |
(void) thr_setconcurrency(concurrency); // 10 by default |