]>
Commit | Line | Data |
---|---|---|
532ac7d7 XL |
1 | use crate::cmp; |
2 | use crate::ffi::CStr; | |
3 | use crate::io; | |
4 | use crate::mem; | |
5 | use crate::ptr; | |
ba9703b0 | 6 | use crate::sys::{os, stack_overflow}; |
532ac7d7 XL |
7 | use crate::time::Duration; |
8 | ||
ea8adc8c XL |
9 | #[cfg(not(target_os = "l4re"))] |
10 | pub const DEFAULT_MIN_STACK_SIZE: usize = 2 * 1024 * 1024; | |
11 | #[cfg(target_os = "l4re")] | |
12 | pub const DEFAULT_MIN_STACK_SIZE: usize = 1024 * 1024; | |
13 | ||
d9579d0f AL |
14 | pub struct Thread { |
15 | id: libc::pthread_t, | |
16 | } | |
17 | ||
18 | // Some platforms may have pthread_t as a pointer in which case we still want | |
19 | // a thread to be Send/Sync | |
20 | unsafe impl Send for Thread {} | |
21 | unsafe impl Sync for Thread {} | |
22 | ||
c30ab7b3 SL |
23 | // The pthread_attr_setstacksize symbol doesn't exist in the emscripten libc, |
24 | // so we have to not link to it to satisfy emcc's ERROR_ON_UNDEFINED_SYMBOLS. | |
25 | #[cfg(not(target_os = "emscripten"))] | |
60c5eb7d XL |
26 | unsafe fn pthread_attr_setstacksize( |
27 | attr: *mut libc::pthread_attr_t, | |
28 | stack_size: libc::size_t, | |
29 | ) -> libc::c_int { | |
c30ab7b3 SL |
30 | libc::pthread_attr_setstacksize(attr, stack_size) |
31 | } | |
32 | ||
33 | #[cfg(target_os = "emscripten")] | |
60c5eb7d XL |
34 | unsafe fn pthread_attr_setstacksize( |
35 | _attr: *mut libc::pthread_attr_t, | |
36 | _stack_size: libc::size_t, | |
37 | ) -> libc::c_int { | |
c30ab7b3 SL |
38 | panic!() |
39 | } | |
40 | ||
d9579d0f | 41 | impl Thread { |
0731742a | 42 | // unsafe: see thread::Builder::spawn_unchecked for safety requirements |
60c5eb7d | 43 | pub unsafe fn new(stack: usize, p: Box<dyn FnOnce()>) -> io::Result<Thread> { |
ba9703b0 | 44 | let p = Box::into_raw(box p); |
d9579d0f AL |
45 | let mut native: libc::pthread_t = mem::zeroed(); |
46 | let mut attr: libc::pthread_attr_t = mem::zeroed(); | |
92a42be0 | 47 | assert_eq!(libc::pthread_attr_init(&mut attr), 0); |
d9579d0f | 48 | |
e9174d1e | 49 | let stack_size = cmp::max(stack, min_stack_size(&attr)); |
ea8adc8c | 50 | |
60c5eb7d | 51 | match pthread_attr_setstacksize(&mut attr, stack_size) { |
d9579d0f AL |
52 | 0 => {} |
53 | n => { | |
54 | assert_eq!(n, libc::EINVAL); | |
55 | // EINVAL means |stack_size| is either too small or not a | |
56 | // multiple of the system page size. Because it's definitely | |
57 | // >= PTHREAD_STACK_MIN, it must be an alignment issue. | |
58 | // Round up to the nearest page and try again. | |
59 | let page_size = os::page_size(); | |
60c5eb7d XL |
60 | let stack_size = |
61 | (stack_size + page_size - 1) & (-(page_size as isize - 1) as usize - 1); | |
62 | assert_eq!(libc::pthread_attr_setstacksize(&mut attr, stack_size), 0); | |
d9579d0f AL |
63 | } |
64 | }; | |
65 | ||
ba9703b0 XL |
66 | let ret = libc::pthread_create(&mut native, &attr, thread_start, p as *mut _); |
67 | // Note: if the thread creation fails and this assert fails, then p will | |
68 | // be leaked. However, an alternative design could cause double-free | |
69 | // which is clearly worse. | |
92a42be0 | 70 | assert_eq!(libc::pthread_attr_destroy(&mut attr), 0); |
d9579d0f AL |
71 | |
72 | return if ret != 0 { | |
ba9703b0 XL |
73 | // The thread failed to start and as a result p was not consumed. Therefore, it is |
74 | // safe to reconstruct the box so that it gets deallocated. | |
75 | drop(Box::from_raw(p)); | |
d9579d0f AL |
76 | Err(io::Error::from_raw_os_error(ret)) |
77 | } else { | |
d9579d0f AL |
78 | Ok(Thread { id: native }) |
79 | }; | |
80 | ||
60c5eb7d XL |
81 | extern "C" fn thread_start(main: *mut libc::c_void) -> *mut libc::c_void { |
82 | unsafe { | |
ba9703b0 XL |
83 | // Next, set up our stack overflow handler which may get triggered if we run |
84 | // out of stack. | |
85 | let _handler = stack_overflow::Handler::new(); | |
86 | // Finally, let's run some code. | |
87 | Box::from_raw(main as *mut Box<dyn FnOnce()>)(); | |
60c5eb7d | 88 | } |
e9174d1e | 89 | ptr::null_mut() |
d9579d0f AL |
90 | } |
91 | } | |
92 | ||
93 | pub fn yield_now() { | |
92a42be0 | 94 | let ret = unsafe { libc::sched_yield() }; |
d9579d0f AL |
95 | debug_assert_eq!(ret, 0); |
96 | } | |
97 | ||
60c5eb7d | 98 | #[cfg(any(target_os = "linux", target_os = "android"))] |
54a0048b | 99 | pub fn set_name(name: &CStr) { |
d9579d0f | 100 | const PR_SET_NAME: libc::c_int = 15; |
92a42be0 SL |
101 | // pthread wrapper only appeared in glibc 2.12, so we use syscall |
102 | // directly. | |
d9579d0f | 103 | unsafe { |
54a0048b | 104 | libc::prctl(PR_SET_NAME, name.as_ptr() as libc::c_ulong, 0, 0, 0); |
d9579d0f AL |
105 | } |
106 | } | |
107 | ||
60c5eb7d | 108 | #[cfg(any(target_os = "freebsd", target_os = "dragonfly", target_os = "openbsd"))] |
54a0048b | 109 | pub fn set_name(name: &CStr) { |
d9579d0f | 110 | unsafe { |
54a0048b | 111 | libc::pthread_set_name_np(libc::pthread_self(), name.as_ptr()); |
d9579d0f AL |
112 | } |
113 | } | |
114 | ||
115 | #[cfg(any(target_os = "macos", target_os = "ios"))] | |
54a0048b | 116 | pub fn set_name(name: &CStr) { |
d9579d0f | 117 | unsafe { |
54a0048b | 118 | libc::pthread_setname_np(name.as_ptr()); |
d9579d0f AL |
119 | } |
120 | } | |
121 | ||
b039eaaf | 122 | #[cfg(target_os = "netbsd")] |
54a0048b | 123 | pub fn set_name(name: &CStr) { |
532ac7d7 | 124 | use crate::ffi::CString; |
b039eaaf | 125 | let cname = CString::new(&b"%s"[..]).unwrap(); |
b039eaaf | 126 | unsafe { |
60c5eb7d XL |
127 | libc::pthread_setname_np( |
128 | libc::pthread_self(), | |
129 | cname.as_ptr(), | |
130 | name.as_ptr() as *mut libc::c_void, | |
131 | ); | |
b039eaaf SL |
132 | } |
133 | } | |
416331ca | 134 | |
ba9703b0 | 135 | #[cfg(any(target_os = "solaris", target_os = "illumos"))] |
416331ca XL |
136 | pub fn set_name(name: &CStr) { |
137 | weak! { | |
138 | fn pthread_setname_np( | |
139 | libc::pthread_t, *const libc::c_char | |
140 | ) -> libc::c_int | |
141 | } | |
142 | ||
143 | if let Some(f) = pthread_setname_np.get() { | |
60c5eb7d XL |
144 | unsafe { |
145 | f(libc::pthread_self(), name.as_ptr()); | |
146 | } | |
416331ca XL |
147 | } |
148 | } | |
149 | ||
60c5eb7d XL |
150 | #[cfg(any( |
151 | target_env = "newlib", | |
152 | target_os = "haiku", | |
153 | target_os = "l4re", | |
154 | target_os = "emscripten", | |
155 | target_os = "redox" | |
156 | ))] | |
54a0048b | 157 | pub fn set_name(_name: &CStr) { |
ba9703b0 | 158 | // Newlib, Haiku, and Emscripten have no way to set a thread name. |
92a42be0 | 159 | } |
c30ab7b3 SL |
160 | #[cfg(target_os = "fuchsia")] |
161 | pub fn set_name(_name: &CStr) { | |
162 | // FIXME: determine whether Fuchsia has a way to set a thread name. | |
163 | } | |
b039eaaf | 164 | |
d9579d0f | 165 | pub fn sleep(dur: Duration) { |
3157f602 | 166 | let mut secs = dur.as_secs(); |
abe05a73 | 167 | let mut nsecs = dur.subsec_nanos() as _; |
d9579d0f AL |
168 | |
169 | // If we're awoken with a signal then the return value will be -1 and | |
170 | // nanosleep will fill in `ts` with the remaining time. | |
171 | unsafe { | |
3157f602 XL |
172 | while secs > 0 || nsecs > 0 { |
173 | let mut ts = libc::timespec { | |
f035d41b | 174 | tv_sec: cmp::min(libc::time_t::MAX as u64, secs) as libc::time_t, |
3157f602 XL |
175 | tv_nsec: nsecs, |
176 | }; | |
177 | secs -= ts.tv_sec as u64; | |
178 | if libc::nanosleep(&ts, &mut ts) == -1 { | |
179 | assert_eq!(os::errno(), libc::EINTR); | |
180 | secs += ts.tv_sec as u64; | |
181 | nsecs = ts.tv_nsec; | |
182 | } else { | |
183 | nsecs = 0; | |
184 | } | |
d9579d0f AL |
185 | } |
186 | } | |
187 | } | |
188 | ||
189 | pub fn join(self) { | |
190 | unsafe { | |
92a42be0 | 191 | let ret = libc::pthread_join(self.id, ptr::null_mut()); |
d9579d0f | 192 | mem::forget(self); |
60c5eb7d | 193 | assert!(ret == 0, "failed to join thread: {}", io::Error::from_raw_os_error(ret)); |
d9579d0f AL |
194 | } |
195 | } | |
92a42be0 | 196 | |
60c5eb7d XL |
197 | pub fn id(&self) -> libc::pthread_t { |
198 | self.id | |
199 | } | |
92a42be0 SL |
200 | |
201 | pub fn into_id(self) -> libc::pthread_t { | |
202 | let id = self.id; | |
203 | mem::forget(self); | |
204 | id | |
205 | } | |
d9579d0f AL |
206 | } |
207 | ||
208 | impl Drop for Thread { | |
209 | fn drop(&mut self) { | |
92a42be0 | 210 | let ret = unsafe { libc::pthread_detach(self.id) }; |
d9579d0f AL |
211 | debug_assert_eq!(ret, 0); |
212 | } | |
213 | } | |
1a4d82fc | 214 | |
60c5eb7d XL |
215 | #[cfg(all( |
216 | not(all(target_os = "linux", not(target_env = "musl"))), | |
217 | not(target_os = "freebsd"), | |
218 | not(target_os = "macos"), | |
219 | not(all(target_os = "netbsd", not(target_vendor = "rumprun"))), | |
220 | not(target_os = "openbsd"), | |
221 | not(target_os = "solaris") | |
222 | ))] | |
7453a54e | 223 | #[cfg_attr(test, allow(dead_code))] |
1a4d82fc | 224 | pub mod guard { |
532ac7d7 | 225 | use crate::ops::Range; |
2c00a5a8 | 226 | pub type Guard = Range<usize>; |
60c5eb7d XL |
227 | pub unsafe fn current() -> Option<Guard> { |
228 | None | |
229 | } | |
230 | pub unsafe fn init() -> Option<Guard> { | |
231 | None | |
232 | } | |
1a4d82fc JJ |
233 | } |
234 | ||
60c5eb7d XL |
235 | #[cfg(any( |
236 | all(target_os = "linux", not(target_env = "musl")), | |
237 | target_os = "freebsd", | |
238 | target_os = "macos", | |
239 | all(target_os = "netbsd", not(target_vendor = "rumprun")), | |
240 | target_os = "openbsd", | |
241 | target_os = "solaris" | |
242 | ))] | |
7453a54e | 243 | #[cfg_attr(test, allow(dead_code))] |
1a4d82fc | 244 | pub mod guard { |
83c7162d | 245 | use libc::{mmap, mprotect}; |
60c5eb7d | 246 | use libc::{MAP_ANON, MAP_FAILED, MAP_FIXED, MAP_PRIVATE, PROT_NONE, PROT_READ, PROT_WRITE}; |
532ac7d7 XL |
247 | |
248 | use crate::ops::Range; | |
f035d41b | 249 | use crate::sync::atomic::{AtomicUsize, Ordering}; |
532ac7d7 | 250 | use crate::sys::os; |
1a4d82fc | 251 | |
2c00a5a8 | 252 | // This is initialized in init() and only read from after |
f035d41b | 253 | static PAGE_SIZE: AtomicUsize = AtomicUsize::new(0); |
2c00a5a8 XL |
254 | |
255 | pub type Guard = Range<usize>; | |
256 | ||
257 | #[cfg(target_os = "solaris")] | |
258 | unsafe fn get_stack_start() -> Option<*mut libc::c_void> { | |
532ac7d7 | 259 | let mut current_stack: libc::stack_t = crate::mem::zeroed(); |
2c00a5a8 XL |
260 | assert_eq!(libc::stack_getbounds(&mut current_stack), 0); |
261 | Some(current_stack.ss_sp) | |
262 | } | |
263 | ||
264 | #[cfg(target_os = "macos")] | |
c1a9b12d | 265 | unsafe fn get_stack_start() -> Option<*mut libc::c_void> { |
74b04a01 XL |
266 | let th = libc::pthread_self(); |
267 | let stackaddr = | |
268 | libc::pthread_get_stackaddr_np(th) as usize - libc::pthread_get_stacksize_np(th); | |
2c00a5a8 XL |
269 | Some(stackaddr as *mut libc::c_void) |
270 | } | |
271 | ||
48663c56 | 272 | #[cfg(target_os = "openbsd")] |
2c00a5a8 | 273 | unsafe fn get_stack_start() -> Option<*mut libc::c_void> { |
532ac7d7 | 274 | let mut current_stack: libc::stack_t = crate::mem::zeroed(); |
60c5eb7d | 275 | assert_eq!(libc::pthread_stackseg_np(libc::pthread_self(), &mut current_stack), 0); |
2c00a5a8 | 276 | |
2c00a5a8 XL |
277 | let stackaddr = if libc::pthread_main_np() == 1 { |
278 | // main thread | |
f035d41b | 279 | current_stack.ss_sp as usize - current_stack.ss_size + PAGE_SIZE.load(Ordering::Relaxed) |
2c00a5a8 XL |
280 | } else { |
281 | // new thread | |
282 | current_stack.ss_sp as usize - current_stack.ss_size | |
283 | }; | |
284 | Some(stackaddr as *mut libc::c_void) | |
1a4d82fc JJ |
285 | } |
286 | ||
60c5eb7d XL |
287 | #[cfg(any( |
288 | target_os = "android", | |
289 | target_os = "freebsd", | |
290 | target_os = "linux", | |
291 | target_os = "netbsd", | |
292 | target_os = "l4re" | |
293 | ))] | |
c1a9b12d | 294 | unsafe fn get_stack_start() -> Option<*mut libc::c_void> { |
c1a9b12d | 295 | let mut ret = None; |
532ac7d7 | 296 | let mut attr: libc::pthread_attr_t = crate::mem::zeroed(); |
92a42be0 | 297 | assert_eq!(libc::pthread_attr_init(&mut attr), 0); |
a7813a04 | 298 | #[cfg(target_os = "freebsd")] |
60c5eb7d | 299 | let e = libc::pthread_attr_get_np(libc::pthread_self(), &mut attr); |
a7813a04 | 300 | #[cfg(not(target_os = "freebsd"))] |
60c5eb7d | 301 | let e = libc::pthread_getattr_np(libc::pthread_self(), &mut attr); |
a7813a04 | 302 | if e == 0 { |
532ac7d7 | 303 | let mut stackaddr = crate::ptr::null_mut(); |
c1a9b12d | 304 | let mut stacksize = 0; |
60c5eb7d | 305 | assert_eq!(libc::pthread_attr_getstack(&attr, &mut stackaddr, &mut stacksize), 0); |
c1a9b12d SL |
306 | ret = Some(stackaddr); |
307 | } | |
92a42be0 | 308 | assert_eq!(libc::pthread_attr_destroy(&mut attr), 0); |
c1a9b12d | 309 | ret |
1a4d82fc JJ |
310 | } |
311 | ||
83c7162d XL |
312 | // Precondition: PAGE_SIZE is initialized. |
313 | unsafe fn get_stack_start_aligned() -> Option<*mut libc::c_void> { | |
f035d41b XL |
314 | let page_size = PAGE_SIZE.load(Ordering::Relaxed); |
315 | assert!(page_size != 0); | |
83c7162d | 316 | let stackaddr = get_stack_start()?; |
85aaf69f SL |
317 | |
318 | // Ensure stackaddr is page aligned! A parent process might | |
319 | // have reset RLIMIT_STACK to be non-page aligned. The | |
320 | // pthread_attr_getstack() reports the usable stack area | |
321 | // stackaddr < stackaddr + stacksize, so if stackaddr is not | |
322 | // page-aligned, calculate the fix such that stackaddr < | |
323 | // new_page_aligned_stackaddr < stackaddr + stacksize | |
f035d41b | 324 | let remainder = (stackaddr as usize) % page_size; |
83c7162d XL |
325 | Some(if remainder == 0 { |
326 | stackaddr | |
327 | } else { | |
f035d41b | 328 | ((stackaddr as usize) + page_size - remainder) as *mut libc::c_void |
83c7162d XL |
329 | }) |
330 | } | |
331 | ||
332 | pub unsafe fn init() -> Option<Guard> { | |
f035d41b XL |
333 | let page_size = os::page_size(); |
334 | PAGE_SIZE.store(page_size, Ordering::Relaxed); | |
83c7162d XL |
335 | |
336 | let stackaddr = get_stack_start_aligned()?; | |
1a4d82fc | 337 | |
041b39d2 XL |
338 | if cfg!(target_os = "linux") { |
339 | // Linux doesn't allocate the whole stack right away, and | |
340 | // the kernel has its own stack-guard mechanism to fault | |
341 | // when growing too close to an existing mapping. If we map | |
342 | // our own guard, then the kernel starts enforcing a rather | |
343 | // large gap above that, rendering much of the possible | |
344 | // stack space useless. See #43052. | |
345 | // | |
346 | // Instead, we'll just note where we expect rlimit to start | |
347 | // faulting, so our handler can report "stack overflow", and | |
348 | // trust that the kernel's own stack guard will work. | |
2c00a5a8 | 349 | let stackaddr = stackaddr as usize; |
f035d41b | 350 | Some(stackaddr - page_size..stackaddr) |
a7813a04 | 351 | } else { |
041b39d2 XL |
352 | // Reallocate the last page of the stack. |
353 | // This ensures SIGBUS will be raised on | |
354 | // stack overflow. | |
94b46f34 XL |
355 | // Systems which enforce strict PAX MPROTECT do not allow |
356 | // to mprotect() a mapping with less restrictive permissions | |
357 | // than the initial mmap() used, so we mmap() here with | |
358 | // read/write permissions and only then mprotect() it to | |
359 | // no permissions at all. See issue #50313. | |
60c5eb7d XL |
360 | let result = mmap( |
361 | stackaddr, | |
f035d41b | 362 | page_size, |
60c5eb7d XL |
363 | PROT_READ | PROT_WRITE, |
364 | MAP_PRIVATE | MAP_ANON | MAP_FIXED, | |
365 | -1, | |
366 | 0, | |
367 | ); | |
041b39d2 XL |
368 | if result != stackaddr || result == MAP_FAILED { |
369 | panic!("failed to allocate a guard page"); | |
370 | } | |
371 | ||
f035d41b | 372 | let result = mprotect(stackaddr, page_size, PROT_NONE); |
94b46f34 XL |
373 | if result != 0 { |
374 | panic!("failed to protect the guard page"); | |
375 | } | |
376 | ||
2c00a5a8 | 377 | let guardaddr = stackaddr as usize; |
60c5eb7d | 378 | let offset = if cfg!(target_os = "freebsd") { 2 } else { 1 }; |
1a4d82fc | 379 | |
f035d41b | 380 | Some(guardaddr..guardaddr + offset * page_size) |
041b39d2 | 381 | } |
1a4d82fc JJ |
382 | } |
383 | ||
60c5eb7d | 384 | #[cfg(any(target_os = "macos", target_os = "openbsd", target_os = "solaris"))] |
2c00a5a8 XL |
385 | pub unsafe fn current() -> Option<Guard> { |
386 | let stackaddr = get_stack_start()? as usize; | |
f035d41b | 387 | Some(stackaddr - PAGE_SIZE.load(Ordering::Relaxed)..stackaddr) |
85aaf69f SL |
388 | } |
389 | ||
60c5eb7d XL |
390 | #[cfg(any( |
391 | target_os = "android", | |
392 | target_os = "freebsd", | |
393 | target_os = "linux", | |
394 | target_os = "netbsd", | |
395 | target_os = "l4re" | |
396 | ))] | |
2c00a5a8 | 397 | pub unsafe fn current() -> Option<Guard> { |
c1a9b12d | 398 | let mut ret = None; |
532ac7d7 | 399 | let mut attr: libc::pthread_attr_t = crate::mem::zeroed(); |
92a42be0 | 400 | assert_eq!(libc::pthread_attr_init(&mut attr), 0); |
a7813a04 | 401 | #[cfg(target_os = "freebsd")] |
60c5eb7d | 402 | let e = libc::pthread_attr_get_np(libc::pthread_self(), &mut attr); |
a7813a04 | 403 | #[cfg(not(target_os = "freebsd"))] |
60c5eb7d | 404 | let e = libc::pthread_getattr_np(libc::pthread_self(), &mut attr); |
a7813a04 | 405 | if e == 0 { |
c1a9b12d | 406 | let mut guardsize = 0; |
92a42be0 | 407 | assert_eq!(libc::pthread_attr_getguardsize(&attr, &mut guardsize), 0); |
c1a9b12d SL |
408 | if guardsize == 0 { |
409 | panic!("there is no guard page"); | |
410 | } | |
532ac7d7 | 411 | let mut stackaddr = crate::ptr::null_mut(); |
c1a9b12d | 412 | let mut size = 0; |
60c5eb7d | 413 | assert_eq!(libc::pthread_attr_getstack(&attr, &mut stackaddr, &mut size), 0); |
c1a9b12d | 414 | |
2c00a5a8 | 415 | let stackaddr = stackaddr as usize; |
a7813a04 | 416 | ret = if cfg!(target_os = "freebsd") { |
2c00a5a8 XL |
417 | // FIXME does freebsd really fault *below* the guard addr? |
418 | let guardaddr = stackaddr - guardsize; | |
f035d41b | 419 | Some(guardaddr - PAGE_SIZE.load(Ordering::Relaxed)..guardaddr) |
a7813a04 | 420 | } else if cfg!(target_os = "netbsd") { |
2c00a5a8 XL |
421 | Some(stackaddr - guardsize..stackaddr) |
422 | } else if cfg!(all(target_os = "linux", target_env = "gnu")) { | |
423 | // glibc used to include the guard area within the stack, as noted in the BUGS | |
424 | // section of `man pthread_attr_getguardsize`. This has been corrected starting | |
425 | // with glibc 2.27, and in some distro backports, so the guard is now placed at the | |
426 | // end (below) the stack. There's no easy way for us to know which we have at | |
427 | // runtime, so we'll just match any fault in the range right above or below the | |
428 | // stack base to call that fault a stack overflow. | |
429 | Some(stackaddr - guardsize..stackaddr + guardsize) | |
b039eaaf | 430 | } else { |
2c00a5a8 | 431 | Some(stackaddr..stackaddr + guardsize) |
b039eaaf | 432 | }; |
1a4d82fc | 433 | } |
92a42be0 | 434 | assert_eq!(libc::pthread_attr_destroy(&mut attr), 0); |
e9174d1e | 435 | ret |
c34b1796 | 436 | } |
1a4d82fc JJ |
437 | } |
438 | ||
1a4d82fc | 439 | // glibc >= 2.15 has a __pthread_get_minstack() function that returns |
74b04a01 XL |
440 | // PTHREAD_STACK_MIN plus bytes needed for thread-local storage. |
441 | // We need that information to avoid blowing up when a small stack | |
1a4d82fc JJ |
442 | // is created in an application with big thread-local storage requirements. |
443 | // See #6233 for rationale and details. | |
1a4d82fc | 444 | #[cfg(target_os = "linux")] |
b039eaaf | 445 | #[allow(deprecated)] |
d9579d0f | 446 | fn min_stack_size(attr: *const libc::pthread_attr_t) -> usize { |
7453a54e | 447 | weak!(fn __pthread_get_minstack(*const libc::pthread_attr_t) -> libc::size_t); |
c34b1796 | 448 | |
7453a54e | 449 | match __pthread_get_minstack.get() { |
c30ab7b3 SL |
450 | None => libc::PTHREAD_STACK_MIN, |
451 | Some(f) => unsafe { f(attr) }, | |
1a4d82fc JJ |
452 | } |
453 | } | |
454 | ||
c34b1796 AL |
455 | // No point in looking up __pthread_get_minstack() on non-glibc |
456 | // platforms. | |
60c5eb7d | 457 | #[cfg(all(not(target_os = "linux"), not(target_os = "netbsd")))] |
7453a54e | 458 | fn min_stack_size(_: *const libc::pthread_attr_t) -> usize { |
c30ab7b3 | 459 | libc::PTHREAD_STACK_MIN |
7453a54e SL |
460 | } |
461 | ||
462 | #[cfg(target_os = "netbsd")] | |
d9579d0f | 463 | fn min_stack_size(_: *const libc::pthread_attr_t) -> usize { |
7453a54e | 464 | 2048 // just a guess |
1a4d82fc | 465 | } |