Skip to content

Commit 2fba2fe

Browse files
committed
auto merge of #12705 : alexcrichton/rust/issue-12692, r=brson
Details are in the commit messages, but this closes a few issues seen with `libnative` recently.
2 parents 2153293 + 9668ab5 commit 2fba2fe

File tree

12 files changed

+136
-45
lines changed

12 files changed

+136
-45
lines changed

src/libnative/io/file_unix.rs

+11-5
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ use std::libc;
1919
use std::mem;
2020
use std::rt::rtio;
2121
use std::vec;
22+
use std::vec_ng::Vec;
2223

2324
use io::{IoResult, retry, keep_going};
2425

@@ -341,7 +342,7 @@ pub fn mkdir(p: &CString, mode: io::FilePermission) -> IoResult<()> {
341342

342343
pub fn readdir(p: &CString) -> IoResult<~[Path]> {
343344
use std::libc::{dirent_t};
344-
use std::libc::{opendir, readdir, closedir};
345+
use std::libc::{opendir, readdir_r, closedir};
345346

346347
fn prune(root: &CString, dirs: ~[Path]) -> ~[Path] {
347348
let root = unsafe { CString::new(root.with_ref(|p| p), false) };
@@ -353,23 +354,28 @@ pub fn readdir(p: &CString) -> IoResult<~[Path]> {
353354
}
354355

355356
extern {
356-
fn rust_list_dir_val(ptr: *dirent_t) -> *libc::c_char;
357+
fn rust_dirent_t_size() -> libc::c_int;
358+
fn rust_list_dir_val(ptr: *mut dirent_t) -> *libc::c_char;
357359
}
358360

361+
let size = unsafe { rust_dirent_t_size() };
362+
let mut buf = Vec::<u8>::with_capacity(size as uint);
363+
let ptr = buf.as_mut_slice().as_mut_ptr() as *mut dirent_t;
364+
359365
debug!("os::list_dir -- BEFORE OPENDIR");
360366

361367
let dir_ptr = p.with_ref(|buf| unsafe { opendir(buf) });
362368

363369
if dir_ptr as uint != 0 {
364370
let mut paths = ~[];
365371
debug!("os::list_dir -- opendir() SUCCESS");
366-
let mut entry_ptr = unsafe { readdir(dir_ptr) };
367-
while entry_ptr as uint != 0 {
372+
let mut entry_ptr = 0 as *mut dirent_t;
373+
while unsafe { readdir_r(dir_ptr, ptr, &mut entry_ptr) == 0 } {
374+
if entry_ptr.is_null() { break }
368375
let cstr = unsafe {
369376
CString::new(rust_list_dir_val(entry_ptr), false)
370377
};
371378
paths.push(Path::new(cstr));
372-
entry_ptr = unsafe { readdir(dir_ptr) };
373379
}
374380
assert_eq!(unsafe { closedir(dir_ptr) }, 0);
375381
Ok(prune(p, paths))

src/libnative/io/timer_helper.rs

+12-11
Original file line numberDiff line numberDiff line change
@@ -21,10 +21,10 @@
2121
//! time.
2222
2323
use std::cast;
24+
use std::rt::bookkeeping;
2425
use std::rt;
2526
use std::unstable::mutex::{StaticNativeMutex, NATIVE_MUTEX_INIT};
2627

27-
use bookkeeping;
2828
use io::timer::{Req, Shutdown};
2929
use task;
3030

@@ -36,6 +36,8 @@ use task;
3636
static mut HELPER_CHAN: *mut Chan<Req> = 0 as *mut Chan<Req>;
3737
static mut HELPER_SIGNAL: imp::signal = 0 as imp::signal;
3838

39+
static mut TIMER_HELPER_EXIT: StaticNativeMutex = NATIVE_MUTEX_INIT;
40+
3941
pub fn boot(helper: fn(imp::signal, Port<Req>)) {
4042
static mut LOCK: StaticNativeMutex = NATIVE_MUTEX_INIT;
4143
static mut INITIALIZED: bool = false;
@@ -53,6 +55,7 @@ pub fn boot(helper: fn(imp::signal, Port<Req>)) {
5355
task::spawn(proc() {
5456
bookkeeping::decrement();
5557
helper(receive, msgp);
58+
TIMER_HELPER_EXIT.lock().signal()
5659
});
5760

5861
rt::at_exit(proc() { shutdown() });
@@ -70,17 +73,15 @@ pub fn send(req: Req) {
7073
}
7174

7275
fn shutdown() {
73-
// We want to wait for the entire helper task to exit, and in doing so it
74-
// will attempt to decrement the global task count. When the helper was
75-
// created, it decremented the count so it wouldn't count towards preventing
76-
// the program to exit, so here we pair that manual decrement with a manual
77-
// increment. We will then wait for the helper thread to exit by calling
78-
// wait_for_other_tasks.
79-
bookkeeping::increment();
80-
8176
// Request a shutdown, and then wait for the task to exit
82-
send(Shutdown);
83-
bookkeeping::wait_for_other_tasks();
77+
unsafe {
78+
let mut guard = TIMER_HELPER_EXIT.lock();
79+
send(Shutdown);
80+
guard.wait();
81+
drop(guard);
82+
TIMER_HELPER_EXIT.destroy();
83+
}
84+
8485

8586
// Clean up after ther helper thread
8687
unsafe {

src/libnative/io/timer_other.rs

+9-2
Original file line numberDiff line numberDiff line change
@@ -218,8 +218,15 @@ impl Timer {
218218
}
219219

220220
pub fn sleep(ms: u64) {
221-
// FIXME: this can fail because of EINTR, what do do?
222-
let _ = unsafe { libc::usleep((ms * 1000) as libc::c_uint) };
221+
let mut to_sleep = libc::timespec {
222+
tv_sec: (ms / 1000) as libc::time_t,
223+
tv_nsec: ((ms % 1000) * 1000000) as libc::c_long,
224+
};
225+
while unsafe { libc::nanosleep(&to_sleep, &mut to_sleep) } != 0 {
226+
if os::errno() as int != libc::EINTR as int {
227+
fail!("failed to sleep, but not because of EINTR?");
228+
}
229+
}
223230
}
224231

225232
fn inner(&mut self) -> ~Inner {

src/libnative/io/timer_timerfd.rs

+11-4
Original file line numberDiff line numberDiff line change
@@ -23,8 +23,8 @@
2323
//! why).
2424
//!
2525
//! As with timer_other, timers just using sleep() do not use the timerfd at
26-
//! all. They remove the timerfd from the worker thread and then invoke usleep()
27-
//! to block the calling thread.
26+
//! all. They remove the timerfd from the worker thread and then invoke
27+
//! nanosleep() to block the calling thread.
2828
//!
2929
//! As with timer_other, all units in this file are in units of millseconds.
3030
@@ -183,8 +183,15 @@ impl Timer {
183183
}
184184

185185
pub fn sleep(ms: u64) {
186-
// FIXME: this can fail because of EINTR, what do do?
187-
let _ = unsafe { libc::usleep((ms * 1000) as libc::c_uint) };
186+
let mut to_sleep = libc::timespec {
187+
tv_sec: (ms / 1000) as libc::time_t,
188+
tv_nsec: ((ms % 1000) * 1000000) as libc::c_long,
189+
};
190+
while unsafe { libc::nanosleep(&to_sleep, &mut to_sleep) } != 0 {
191+
if os::errno() as int != libc::EINTR as int {
192+
fail!("failed to sleep, but not because of EINTR?");
193+
}
194+
}
188195
}
189196

190197
fn remove(&mut self) {

src/libnative/lib.rs

-2
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,6 @@
5858
use std::os;
5959
use std::rt;
6060

61-
mod bookkeeping;
6261
pub mod io;
6362
pub mod task;
6463

@@ -105,6 +104,5 @@ pub fn start(argc: int, argv: **u8, main: proc()) -> int {
105104
/// number of arguments.
106105
pub fn run(main: proc()) -> int {
107106
main();
108-
bookkeeping::wait_for_other_tasks();
109107
os::get_exit_status()
110108
}

src/libnative/task.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -16,19 +16,19 @@
1616
1717
use std::any::Any;
1818
use std::cast;
19+
use std::rt::bookkeeping;
1920
use std::rt::env;
2021
use std::rt::local::Local;
2122
use std::rt::rtio;
23+
use std::rt::stack;
2224
use std::rt::task::{Task, BlockedTask, SendMessage};
2325
use std::rt::thread::Thread;
2426
use std::rt;
2527
use std::task::TaskOpts;
2628
use std::unstable::mutex::NativeMutex;
27-
use std::rt::stack;
2829

2930
use io;
3031
use task;
31-
use bookkeeping;
3232

3333
/// Creates a new Task which is ready to execute as a 1:1 task.
3434
pub fn new(stack_bounds: (uint, uint)) -> ~Task {

src/libstd/libc.rs

+8-3
Original file line numberDiff line numberDiff line change
@@ -3658,13 +3658,16 @@ pub mod funcs {
36583658
pub unsafe fn opendir(dirname: *c_char) -> *DIR {
36593659
rust_opendir(dirname)
36603660
}
3661-
pub unsafe fn readdir(dirp: *DIR) -> *dirent_t {
3662-
rust_readdir(dirp)
3661+
pub unsafe fn readdir_r(dirp: *DIR,
3662+
entry: *mut dirent_t,
3663+
result: *mut *mut dirent_t) -> c_int {
3664+
rust_readdir_r(dirp, entry, result)
36633665
}
36643666

36653667
extern {
36663668
fn rust_opendir(dirname: *c_char) -> *DIR;
3667-
fn rust_readdir(dirp: *DIR) -> *dirent_t;
3669+
fn rust_readdir_r(dirp: *DIR, entry: *mut dirent_t,
3670+
result: *mut *mut dirent_t) -> c_int;
36683671
}
36693672

36703673
extern {
@@ -3680,6 +3683,7 @@ pub mod funcs {
36803683
use libc::types::common::c95::c_void;
36813684
use libc::types::os::arch::c95::{c_char, c_int, c_long, c_uint};
36823685
use libc::types::os::arch::c95::{size_t};
3686+
use libc::types::os::common::posix01::timespec;
36833687
use libc::types::os::arch::posix01::utimbuf;
36843688
use libc::types::os::arch::posix88::{gid_t, off_t, pid_t};
36853689
use libc::types::os::arch::posix88::{ssize_t, uid_t};
@@ -3729,6 +3733,7 @@ pub mod funcs {
37293733
pub fn setuid(uid: uid_t) -> c_int;
37303734
pub fn sleep(secs: c_uint) -> c_uint;
37313735
pub fn usleep(secs: c_uint) -> c_int;
3736+
pub fn nanosleep(rqtp: *timespec, rmtp: *mut timespec) -> c_int;
37323737
pub fn sysconf(name: c_int) -> c_long;
37333738
pub fn tcgetpgrp(fd: c_int) -> pid_t;
37343739
pub fn ttyname(fd: c_int) -> *c_char;

src/libnative/bookkeeping.rs src/libstd/rt/bookkeeping.rs

+15-13
Original file line numberDiff line numberDiff line change
@@ -8,16 +8,21 @@
88
// option. This file may not be copied, modified, or distributed
99
// except according to those terms.
1010

11-
//! 1:1 Task bookkeeping
11+
//! Task bookkeeping
1212
//!
13-
//! This module keeps track of the number of running 1:1 tasks so that entry
14-
//! points with libnative know when it's possible to exit the program (once all
15-
//! tasks have exited).
13+
//! This module keeps track of the number of running tasks so that entry points
14+
//! with libnative know when it's possible to exit the program (once all tasks
15+
//! have exited).
1616
//!
17-
//! The green counterpart for this is bookkeeping on sched pools.
17+
//! The green counterpart for this is bookkeeping on sched pools, and it's up to
18+
//! each respective runtime to make sure that they call increment() and
19+
//! decrement() manually.
1820
19-
use std::sync::atomics;
20-
use std::unstable::mutex::{StaticNativeMutex, NATIVE_MUTEX_INIT};
21+
#[experimental]; // this is a massive code smell
22+
#[doc(hidden)];
23+
24+
use sync::atomics;
25+
use unstable::mutex::{StaticNativeMutex, NATIVE_MUTEX_INIT};
2126

2227
static mut TASK_COUNT: atomics::AtomicUint = atomics::INIT_ATOMIC_UINT;
2328
static mut TASK_LOCK: StaticNativeMutex = NATIVE_MUTEX_INIT;
@@ -39,12 +44,9 @@ pub fn decrement() {
3944
/// the entry points of native programs
4045
pub fn wait_for_other_tasks() {
4146
unsafe {
42-
{
43-
let mut guard = TASK_LOCK.lock();
44-
while TASK_COUNT.load(atomics::SeqCst) > 0 {
45-
guard.wait();
46-
}
47+
let mut guard = TASK_LOCK.lock();
48+
while TASK_COUNT.load(atomics::SeqCst) > 0 {
49+
guard.wait();
4750
}
48-
TASK_LOCK.destroy();
4951
}
5052
}

src/libstd/rt/mod.rs

+4
Original file line numberDiff line numberDiff line change
@@ -128,6 +128,9 @@ pub mod args;
128128
// Support for running procedures when a program has exited.
129129
mod at_exit_imp;
130130

131+
// Bookkeeping for task counts
132+
pub mod bookkeeping;
133+
131134
// Stack overflow protection
132135
pub mod stack;
133136

@@ -207,6 +210,7 @@ pub fn at_exit(f: proc()) {
207210
/// Invoking cleanup while portions of the runtime are still in use may cause
208211
/// undefined behavior.
209212
pub unsafe fn cleanup() {
213+
bookkeeping::wait_for_other_tasks();
210214
at_exit_imp::run();
211215
args::cleanup();
212216
local_ptr::cleanup();

src/rt/rust_builtin.c

+12-3
Original file line numberDiff line numberDiff line change
@@ -279,9 +279,14 @@ rust_opendir(char *dirname) {
279279
return opendir(dirname);
280280
}
281281

282-
struct dirent*
283-
rust_readdir(DIR *dirp) {
284-
return readdir(dirp);
282+
int
283+
rust_readdir_r(DIR *dirp, struct dirent *entry, struct dirent **result) {
284+
return readdir_r(dirp, entry, result);
285+
}
286+
287+
int
288+
rust_dirent_t_size() {
289+
return sizeof(struct dirent);
285290
}
286291

287292
#else
@@ -294,6 +299,10 @@ void
294299
rust_readdir() {
295300
}
296301

302+
void
303+
rust_dirent_t_size() {
304+
}
305+
297306
#endif
298307

299308
uintptr_t

src/test/run-pass/issue-12684.rs

+28
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
// Copyright 2013-2014 The Rust Project Developers. See the COPYRIGHT
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+
11+
// ignore-fast
12+
13+
extern crate native;
14+
extern crate green;
15+
extern crate rustuv;
16+
17+
#[start]
18+
fn start(argc: int, argv: **u8) -> int { green::start(argc, argv, main) }
19+
20+
fn main() {
21+
native::task::spawn(proc() customtask());
22+
}
23+
24+
fn customtask() {
25+
let mut timer = std::io::timer::Timer::new().unwrap();
26+
let periodic = timer.periodic(10);
27+
periodic.recv();
28+
}

src/test/run-pass/issue-12699.rs

+24
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
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+
11+
// ignore-fast
12+
13+
extern crate native;
14+
15+
use std::io::timer;
16+
17+
#[start]
18+
fn start(argc: int, argv: **u8) -> int {
19+
native::start(argc, argv, main)
20+
}
21+
22+
fn main() {
23+
timer::sleep(250);
24+
}

0 commit comments

Comments
 (0)