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