summaryrefslogtreecommitdiff
path: root/lang/ruby18/files/patch-gc.c
blob: 971b52e2ab9b0bfeb486b966ea7a039e0358fca9 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
--- gc.c.orig	2009-12-24 00:28:08.000000000 -0800
+++ gc.c	2010-01-05 18:02:16.000000000 -0800
@@ -30,6 +30,10 @@
 #include <sys/resource.h>
 #endif
 
+#if defined(HAVE_PTHREAD_NP_H)
+#include <pthread_np.h>
+#endif
+
 #if defined _WIN32 || defined __CYGWIN__
 #include <windows.h>
 #endif
@@ -75,6 +79,7 @@
 static void run_final();
 static VALUE nomem_error;
 static void garbage_collect();
+static void set_stack_limit();
 
 int ruby_gc_stress = 0;
 
@@ -485,6 +490,8 @@
 # define STACK_LEVEL_MAX 655300
 #endif
 
+VALUE *stack_bottom_addr = 0x0;
+
 #ifdef C_ALLOCA
 # define SET_STACK_END VALUE stack_end; alloca(0);
 # define STACK_END (&stack_end)
@@ -534,9 +541,22 @@
 
 #define GC_WATER_MARK 512
 
-#define CHECK_STACK(ret) do {\
+#define CHECK_STACK(ret, prev) do {\
     SET_STACK_END;\
-    (ret) = (STACK_LENGTH > STACK_LEVEL_MAX + GC_WATER_MARK);\
+    ssize_t avail;\
+    if (stack_bottom_addr != 0) {\
+	if (STACK_UPPER(&avail, 1, -1) > 0)\
+	    avail = stack_bottom_addr - STACK_END;\
+	else\
+	    avail = STACK_END - stack_bottom_addr;\
+    } else {\
+	avail = STACK_LEVEL_MAX + GC_WATER_MARK - STACK_LENGTH;\
+    }\
+    if (avail <= 0 || (prev != 0 && (prev - avail) > avail))\
+	(ret) = 1;\
+    else\
+	(ret) = 0;\
+    (prev) = avail;\
 } while (0)
 
 size_t
@@ -552,8 +572,9 @@
 ruby_stack_check()
 {
     int ret;
+    static ssize_t prev = 0;
 
-    CHECK_STACK(ret);
+    CHECK_STACK(ret, prev);
     return ret;
 }
 
@@ -1607,18 +1628,72 @@
     }
     rb_gc_stack_start = addr;
 #endif
+    set_stack_limit();
+}
+
+static void set_stack_limit()
+{
+	size_t stacksize = 0;
+
 #ifdef HAVE_GETRLIMIT
     {
 	struct rlimit rlim;
 
-	if (getrlimit(RLIMIT_STACK, &rlim) == 0) {
-	    unsigned int space = rlim.rlim_cur/5;
+	if (getrlimit(RLIMIT_STACK, &rlim) == 0)
+	    stacksize = rlim.rlim_cur;
+    }
+#elif defined _WIN32
+    {
+	MEMORY_BASIC_INFORMATION mi;
 
-	    if (space > 1024*1024) space = 1024*1024;
-	    STACK_LEVEL_MAX = (rlim.rlim_cur - space) / sizeof(VALUE);
+	if (VirtualQuery(&mi, &mi, sizeof(mi))) {
+	    stacksize = (char *)mi.BaseAddress - (char *)mi.AllocationBase;
+	}
+    }
+#endif
+#if defined(_THREAD_SAFE) && defined(HAVE_PTHREAD_NP_H)
+    {
+	pthread_attr_t  attr;
+	size_t          size;
+	void		*addr;
+
+	pthread_attr_init(&attr);
+	if (pthread_attr_get_np(pthread_self(), &attr) == 0) {
+	    pthread_attr_getstack(&attr, &addr, &size);
+	    if (stacksize == 0 || size < stacksize)
+		stacksize = size;
+            stack_bottom_addr = addr;
+	}
+	pthread_attr_destroy(&attr);
+    }
+#endif
+    if (stacksize) {
+	unsigned int space = stacksize / 5;
+
+	if (space > 1024*1024)
+	    space = 1024*1024;
+	STACK_LEVEL_MAX = (stacksize - space) / sizeof(VALUE);
+#if defined(__FreeBSD__)
+#include <sys/sysctl.h>
+    if (stack_bottom_addr == 0) {
+	size_t len;
+	void *usrstack;
+	int mib[2];
+	int error;
+
+	len = sizeof(usrstack);
+	mib[0] = CTL_KERN;
+	mib[1] = KERN_USRSTACK;
+	error = sysctl(mib, 2, &usrstack, &len, NULL, 0);
+	if (error == 0) {
+	    if (STACK_UPPER(&avail, 1, -1) > 0)
+		stack_bottom_addr = usrstack + (stacksize - space);
+	    else
+		stack_bottom_addr = usrstack - (stacksize - space);
 	}
     }
 #endif
+    }
 }
 
 void ruby_init_stack(VALUE *addr
@@ -1639,31 +1714,7 @@
         rb_gc_register_stack_start = (VALUE*)bsp;
     }
 #endif
-#ifdef HAVE_GETRLIMIT
-    {
-        struct rlimit rlim;
-
-        if (getrlimit(RLIMIT_STACK, &rlim) == 0) {
-            unsigned int space = rlim.rlim_cur/5;
-
-            if (space > 1024*1024) space = 1024*1024;
-            STACK_LEVEL_MAX = (rlim.rlim_cur - space) / sizeof(VALUE);
-        }
-    }
-#elif defined _WIN32
-    {
-	MEMORY_BASIC_INFORMATION mi;
-	DWORD size;
-	DWORD space;
-
-	if (VirtualQuery(&mi, &mi, sizeof(mi))) {
-	    size = (char *)mi.BaseAddress - (char *)mi.AllocationBase;
-	    space = size / 5;
-	    if (space > 1024*1024) space = 1024*1024;
-	    STACK_LEVEL_MAX = (size - space) / sizeof(VALUE);
-	}
-    }
-#endif
+    set_stack_limit();
 }
 
 /*