diff --git a/src/libcore/pipes.rs b/src/libcore/pipes.rs index b32357e735654..6c7be8a2ae51e 100644 --- a/src/libcore/pipes.rs +++ b/src/libcore/pipes.rs @@ -280,17 +280,23 @@ extern mod rusti { // I get link errors. This is a bug that needs investigated more. #[doc(hidden)] pub fn atomic_xchng_rel(dst: &mut int, src: int) -> int { - rusti::atomic_xchg_rel(dst, src) + unsafe { + rusti::atomic_xchg_rel(dst, src) + } } #[doc(hidden)] pub fn atomic_add_acq(dst: &mut int, src: int) -> int { - rusti::atomic_xadd_acq(dst, src) + unsafe { + rusti::atomic_xadd_acq(dst, src) + } } #[doc(hidden)] pub fn atomic_sub_rel(dst: &mut int, src: int) -> int { - rusti::atomic_xsub_rel(dst, src) + unsafe { + rusti::atomic_xsub_rel(dst, src) + } } #[doc(hidden)] diff --git a/src/libcore/private.rs b/src/libcore/private.rs index 1d6260db1302d..ad27729cc9fa6 100644 --- a/src/libcore/private.rs +++ b/src/libcore/private.rs @@ -93,8 +93,10 @@ type rust_port_id = uint; type GlobalPtr = *libc::uintptr_t; fn compare_and_swap(address: &mut int, oldval: int, newval: int) -> bool { - let old = rusti::atomic_cxchg(address, oldval, newval); - old == oldval + unsafe { + let old = rusti::atomic_cxchg(address, oldval, newval); + old == oldval + } } /** diff --git a/src/libcore/repr.rs b/src/libcore/repr.rs index 39b2e1af363fe..350cdeb1c399c 100644 --- a/src/libcore/repr.rs +++ b/src/libcore/repr.rs @@ -201,10 +201,12 @@ impl ReprVisitor { #[inline(always)] fn visit_ptr_inner(ptr: *c_void, inner: *TyDesc) -> bool { - let mut u = ReprVisitor(ptr, self.writer); - let v = reflect::MovePtrAdaptor(move u); - visit_tydesc(inner, (move v) as @TyVisitor); - true + unsafe { + let mut u = ReprVisitor(ptr, self.writer); + let v = reflect::MovePtrAdaptor(move u); + visit_tydesc(inner, (move v) as @TyVisitor); + true + } } #[inline(always)] @@ -558,11 +560,13 @@ impl ReprVisitor : TyVisitor { } pub fn write_repr(writer: @Writer, object: &T) { - let ptr = ptr::to_unsafe_ptr(object) as *c_void; - let tydesc = intrinsic::get_tydesc::(); - let mut u = ReprVisitor(ptr, writer); - let v = reflect::MovePtrAdaptor(move u); - visit_tydesc(tydesc, (move v) as @TyVisitor) + unsafe { + let ptr = ptr::to_unsafe_ptr(object) as *c_void; + let tydesc = intrinsic::get_tydesc::(); + let mut u = ReprVisitor(ptr, writer); + let v = reflect::MovePtrAdaptor(move u); + visit_tydesc(tydesc, (move v) as @TyVisitor) + } } #[test] diff --git a/src/libcore/task/mod.rs b/src/libcore/task/mod.rs index c6b0491786d7f..a151534aa0694 100644 --- a/src/libcore/task/mod.rs +++ b/src/libcore/task/mod.rs @@ -571,23 +571,29 @@ pub fn try(f: fn~() -> T) -> Result { pub fn yield() { //! Yield control to the task scheduler - let task_ = rt::rust_get_task(); - let killed = rt::rust_task_yield(task_); - if killed && !failing() { - fail ~"killed"; + unsafe { + let task_ = rt::rust_get_task(); + let killed = rt::rust_task_yield(task_); + if killed && !failing() { + fail ~"killed"; + } } } pub fn failing() -> bool { //! True if the running task has failed - rt::rust_task_is_unwinding(rt::rust_get_task()) + unsafe { + rt::rust_task_is_unwinding(rt::rust_get_task()) + } } pub fn get_task() -> Task { //! Get a handle to the running task - TaskHandle(rt::get_task_id()) + unsafe { + TaskHandle(rt::get_task_id()) + } } /** @@ -608,7 +614,11 @@ pub fn get_task() -> Task { pub unsafe fn unkillable(f: fn() -> U) -> U { struct AllowFailure { t: *rust_task, - drop { rt::rust_task_allow_kill(self.t); } + drop { + unsafe { + rt::rust_task_allow_kill(self.t); + } + } } fn AllowFailure(t: *rust_task) -> AllowFailure{ @@ -617,17 +627,23 @@ pub unsafe fn unkillable(f: fn() -> U) -> U { } } - let t = rt::rust_get_task(); - let _allow_failure = AllowFailure(t); - rt::rust_task_inhibit_kill(t); - f() + unsafe { + let t = rt::rust_get_task(); + let _allow_failure = AllowFailure(t); + rt::rust_task_inhibit_kill(t); + f() + } } /// The inverse of unkillable. Only ever to be used nested in unkillable(). pub unsafe fn rekillable(f: fn() -> U) -> U { struct DisallowFailure { t: *rust_task, - drop { rt::rust_task_inhibit_kill(self.t); } + drop { + unsafe { + rt::rust_task_inhibit_kill(self.t); + } + } } fn DisallowFailure(t: *rust_task) -> DisallowFailure { @@ -636,10 +652,12 @@ pub unsafe fn rekillable(f: fn() -> U) -> U { } } - let t = rt::rust_get_task(); - let _allow_failure = DisallowFailure(t); - rt::rust_task_allow_kill(t); - f() + unsafe { + let t = rt::rust_get_task(); + let _allow_failure = DisallowFailure(t); + rt::rust_task_allow_kill(t); + f() + } } /** @@ -650,8 +668,10 @@ pub unsafe fn atomically(f: fn() -> U) -> U { struct DeferInterrupts { t: *rust_task, drop { - rt::rust_task_allow_yield(self.t); - rt::rust_task_allow_kill(self.t); + unsafe { + rt::rust_task_allow_yield(self.t); + rt::rust_task_allow_kill(self.t); + } } } @@ -661,11 +681,13 @@ pub unsafe fn atomically(f: fn() -> U) -> U { } } - let t = rt::rust_get_task(); - let _interrupts = DeferInterrupts(t); - rt::rust_task_inhibit_kill(t); - rt::rust_task_inhibit_yield(t); - f() + unsafe { + let t = rt::rust_get_task(); + let _interrupts = DeferInterrupts(t); + rt::rust_task_inhibit_kill(t); + rt::rust_task_inhibit_yield(t); + f() + } } #[test] #[should_fail] #[ignore(cfg(windows))] diff --git a/src/libcore/task/spawn.rs b/src/libcore/task/spawn.rs index 2411bd896e710..3b4006b16dfd9 100644 --- a/src/libcore/task/spawn.rs +++ b/src/libcore/task/spawn.rs @@ -308,25 +308,28 @@ struct TCB { notifier: Option, // Runs on task exit. drop { - // If we are failing, the whole taskgroup needs to die. - if rt::rust_task_is_unwinding(self.me) { - self.notifier.iter(|x| { x.failed = true; }); - // Take everybody down with us. - do access_group(&self.tasks) |tg| { - kill_taskgroup(tg, self.me, self.is_main); - } - } else { - // Remove ourselves from the group(s). - do access_group(&self.tasks) |tg| { - leave_taskgroup(tg, self.me, true); + unsafe { + // If we are failing, the whole taskgroup needs to die. + if rt::rust_task_is_unwinding(self.me) { + self.notifier.iter(|x| { x.failed = true; }); + // Take everybody down with us. + do access_group(&self.tasks) |tg| { + kill_taskgroup(tg, self.me, self.is_main); + } + } else { + // Remove ourselves from the group(s). + do access_group(&self.tasks) |tg| { + leave_taskgroup(tg, self.me, true); + } } + // It doesn't matter whether this happens before or after dealing + // with our own taskgroup, so long as both happen before we die. + // We remove ourself from every ancestor we can, so no cleanup; no + // break. + for each_ancestor(&mut self.ancestors, None) |ancestor_group| { + leave_taskgroup(ancestor_group, self.me, false); + }; } - // It doesn't matter whether this happens before or after dealing with - // our own taskgroup, so long as both happen before we die. We need to - // remove ourself from every ancestor we can, so no cleanup; no break. - for each_ancestor(&mut self.ancestors, None) |ancestor_group| { - leave_taskgroup(ancestor_group, self.me, false); - }; } } @@ -391,38 +394,41 @@ fn leave_taskgroup(state: TaskGroupInner, me: *rust_task, // NB: Runs in destructor/post-exit context. Can't 'fail'. fn kill_taskgroup(state: TaskGroupInner, me: *rust_task, is_main: bool) { - // NB: We could do the killing iteration outside of the group arc, by - // having "let mut newstate" here, swapping inside, and iterating after. - // But that would let other exiting tasks fall-through and exit while we - // were trying to kill them, causing potential use-after-free. A task's - // presence in the arc guarantees it's alive only while we hold the lock, - // so if we're failing, all concurrently exiting tasks must wait for us. - // To do it differently, we'd have to use the runtime's task refcounting, - // but that could leave task structs around long after their task exited. - let newstate = util::replace(state, None); - // Might already be None, if Somebody is failing simultaneously. - // That's ok; only one task needs to do the dirty work. (Might also - // see 'None' if Somebody already failed and we got a kill signal.) - if newstate.is_some() { - let group = option::unwrap(move newstate); - for taskset_each(&group.members) |sibling| { - // Skip self - killing ourself won't do much good. - if sibling != me { - rt::rust_task_kill_other(sibling); + unsafe { + // NB: We could do the killing iteration outside of the group arc, by + // having "let mut newstate" here, swapping inside, and iterating + // after. But that would let other exiting tasks fall-through and exit + // while we were trying to kill them, causing potential + // use-after-free. A task's presence in the arc guarantees it's alive + // only while we hold the lock, so if we're failing, all concurrently + // exiting tasks must wait for us. To do it differently, we'd have to + // use the runtime's task refcounting, but that could leave task + // structs around long after their task exited. + let newstate = util::replace(state, None); + // Might already be None, if Somebody is failing simultaneously. + // That's ok; only one task needs to do the dirty work. (Might also + // see 'None' if Somebody already failed and we got a kill signal.) + if newstate.is_some() { + let group = option::unwrap(move newstate); + for taskset_each(&group.members) |sibling| { + // Skip self - killing ourself won't do much good. + if sibling != me { + rt::rust_task_kill_other(sibling); + } } + for taskset_each(&group.descendants) |child| { + assert child != me; + rt::rust_task_kill_other(child); + } + // Only one task should ever do this. + if is_main { + rt::rust_task_kill_all(me); + } + // Do NOT restore state to Some(..)! It stays None to indicate + // that the whole taskgroup is failing, to forbid new spawns. } - for taskset_each(&group.descendants) |child| { - assert child != me; - rt::rust_task_kill_other(child); - } - // Only one task should ever do this. - if is_main { - rt::rust_task_kill_all(me); - } - // Do NOT restore state to Some(..)! It stays None to indicate - // that the whole taskgroup is failing, to forbid new spawns. + // (note: multiple tasks may reach this point) } - // (note: multiple tasks may reach this point) } // FIXME (#2912): Work around core-vs-coretest function duplication. Can't use @@ -434,68 +440,72 @@ macro_rules! taskgroup_key ( fn gen_child_taskgroup(linked: bool, supervised: bool) -> (TaskGroupArc, AncestorList, bool) { - let spawner = rt::rust_get_task(); - /*######################################################################* - * Step 1. Get spawner's taskgroup info. - *######################################################################*/ - let spawner_group = match unsafe { local_get(spawner, - taskgroup_key!()) } { - None => { - // Main task, doing first spawn ever. Lazily initialise here. - let mut members = new_taskset(); - taskset_insert(&mut members, spawner); - let tasks = - private::exclusive(Some({ mut members: move members, - mut descendants: new_taskset() })); - // Main task/group has no ancestors, no notifier, etc. - let group = - @TCB(spawner, move tasks, AncestorList(None), true, None); - unsafe { + unsafe { + let spawner = rt::rust_get_task(); + /*##################################################################* + * Step 1. Get spawner's taskgroup info. + *##################################################################*/ + let spawner_group = match local_get(spawner, taskgroup_key!()) { + None => { + // Main task, doing first spawn ever. Lazily initialise here. + let mut members = new_taskset(); + taskset_insert(&mut members, spawner); + let tasks = + private::exclusive(Some({ + mut members: move members, + mut descendants: new_taskset() + })); + // Main task/group has no ancestors, no notifier, etc. + let group = + @TCB(spawner, move tasks, AncestorList(None), true, None); local_set(spawner, taskgroup_key!(), group); + group } - group - } - Some(group) => group - }; - /*######################################################################* - * Step 2. Process spawn options for child. - *######################################################################*/ - return if linked { - // Child is in the same group as spawner. - let g = spawner_group.tasks.clone(); - // Child's ancestors are spawner's ancestors. - let a = share_ancestors(&mut spawner_group.ancestors); - // Propagate main-ness. - (move g, move a, spawner_group.is_main) - } else { - // Child is in a separate group from spawner. - let g = private::exclusive(Some({ mut members: new_taskset(), - mut descendants: new_taskset() })); - let a = if supervised { - // Child's ancestors start with the spawner. - let old_ancestors = share_ancestors(&mut spawner_group.ancestors); - // FIXME(#3068) - The generation counter is only used for a debug - // assertion, but initialising it requires locking a mutex. Hence - // it should be enabled only in debug builds. - let new_generation = - match *old_ancestors { - Some(ref arc) => { - access_ancestors(arc, |a| a.generation+1) - } - None => 0 // the actual value doesn't really matter. - }; - assert new_generation < uint::max_value; - // Build a new node in the ancestor list. - AncestorList(Some(private::exclusive( - { generation: new_generation, - mut parent_group: Some(spawner_group.tasks.clone()), - mut ancestors: move old_ancestors }))) + Some(group) => group + }; + /*##################################################################* + * Step 2. Process spawn options for child. + *##################################################################*/ + return if linked { + // Child is in the same group as spawner. + let g = spawner_group.tasks.clone(); + // Child's ancestors are spawner's ancestors. + let a = share_ancestors(&mut spawner_group.ancestors); + // Propagate main-ness. + (move g, move a, spawner_group.is_main) } else { - // Child has no ancestors. - AncestorList(None) + // Child is in a separate group from spawner. + let g = private::exclusive(Some({ + mut members: new_taskset(), + mut descendants: new_taskset() + })); + let a = if supervised { + // Child's ancestors start with the spawner. + let old_ancestors = + share_ancestors(&mut spawner_group.ancestors); + // FIXME(#3068) - The generation counter is only used for a + // debug assertion, but initialising it requires locking a + // mutex. Hence it should be enabled only in debug builds. + let new_generation = + match *old_ancestors { + Some(ref arc) => { + access_ancestors(arc, |a| a.generation+1) + } + None => 0 // the actual value doesn't really matter. + }; + assert new_generation < uint::max_value; + // Build a new node in the ancestor list. + AncestorList(Some(private::exclusive( + { generation: new_generation, + mut parent_group: Some(spawner_group.tasks.clone()), + mut ancestors: move old_ancestors }))) + } else { + // Child has no ancestors. + AncestorList(None) + }; + (move g, move a, false) }; - (move g, move a, false) - }; + } fn share_ancestors(ancestors: &mut AncestorList) -> AncestorList { // Appease the borrow-checker. Really this wants to be written as: @@ -632,31 +642,33 @@ pub fn spawn_raw(opts: TaskOpts, f: fn~()) { } fn new_task_in_new_sched(opts: SchedOpts) -> *rust_task { - if opts.foreign_stack_size != None { - fail ~"foreign_stack_size scheduler option unimplemented"; - } - - let num_threads = match opts.mode { - SingleThreaded => 1u, - ThreadPerCore => rt::rust_num_threads(), - ThreadPerTask => { - fail ~"ThreadPerTask scheduling mode unimplemented" - } - ManualThreads(threads) => { - if threads == 0u { - fail ~"can not create a scheduler with no threads"; + unsafe { + if opts.foreign_stack_size != None { + fail ~"foreign_stack_size scheduler option unimplemented"; } - threads - } - PlatformThread => 0u /* Won't be used */ - }; - let sched_id = if opts.mode != PlatformThread { - rt::rust_new_sched(num_threads) - } else { - rt::rust_osmain_sched_id() - }; - rt::rust_new_task_in_sched(sched_id) + let num_threads = match opts.mode { + SingleThreaded => 1u, + ThreadPerCore => rt::rust_num_threads(), + ThreadPerTask => { + fail ~"ThreadPerTask scheduling mode unimplemented" + } + ManualThreads(threads) => { + if threads == 0u { + fail ~"can not create a scheduler with no threads"; + } + threads + } + PlatformThread => 0u /* Won't be used */ + }; + + let sched_id = if opts.mode != PlatformThread { + rt::rust_new_sched(num_threads) + } else { + rt::rust_osmain_sched_id() + }; + rt::rust_new_task_in_sched(sched_id) + } } } diff --git a/src/librustc/front/intrinsic.rs b/src/librustc/front/intrinsic.rs index 8703e60474449..6657e6fcf0fee 100644 --- a/src/librustc/front/intrinsic.rs +++ b/src/librustc/front/intrinsic.rs @@ -19,7 +19,9 @@ mod intrinsic { // FIXME (#3727): remove this when the interface has settled and the // version in sys is no longer present. pub fn get_tydesc() -> *TyDesc { - rusti::get_tydesc::() as *TyDesc + unsafe { + rusti::get_tydesc::() as *TyDesc + } } pub enum TyDesc = { diff --git a/src/librustc/middle/resolve.rs b/src/librustc/middle/resolve.rs index c023a24eceafd..9c1ee2a2307cf 100644 --- a/src/librustc/middle/resolve.rs +++ b/src/librustc/middle/resolve.rs @@ -55,6 +55,7 @@ use syntax::ast::{type_value_ns, ty_param_bound, unnamed_field}; use syntax::ast::{variant, view_item, view_item_export, view_item_import}; use syntax::ast::{view_item_use, view_path_glob, view_path_list}; use syntax::ast::{view_path_simple, visibility, anonymous, named, not}; +use syntax::ast::{unsafe_fn}; use syntax::ast_util::{def_id_of_def, dummy_sp, local_def}; use syntax::ast_util::{path_to_ident, walk_pat, trait_method_to_ty_method}; use syntax::ast_util::{Privacy, Public, Private, visibility_to_privacy}; @@ -1642,8 +1643,8 @@ impl Resolver { foreign_item.span); match /*bad*/copy foreign_item.node { - foreign_item_fn(_, purity, type_parameters) => { - let def = def_fn(local_def(foreign_item.id), purity); + foreign_item_fn(_, _, type_parameters) => { + let def = def_fn(local_def(foreign_item.id), unsafe_fn); (*name_bindings).define_value(Public, def, foreign_item.span); do self.with_type_parameter_rib diff --git a/src/librustc/middle/typeck/check/mod.rs b/src/librustc/middle/typeck/check/mod.rs index 6f2f56846c88c..4f52699ec28e8 100644 --- a/src/librustc/middle/typeck/check/mod.rs +++ b/src/librustc/middle/typeck/check/mod.rs @@ -3324,7 +3324,7 @@ fn check_intrinsic_type(ccx: @crate_ctxt, it: @ast::foreign_item) { } }; let fty = ty::mk_fn(tcx, FnTyBase { - meta: FnMeta {purity: ast::impure_fn, + meta: FnMeta {purity: ast::unsafe_fn, proto: ast::ProtoBare, onceness: ast::Many, region: ty::re_static, diff --git a/src/librustc/middle/typeck/collect.rs b/src/librustc/middle/typeck/collect.rs index 98f3c0f8b0802..ba34846ca97ce 100644 --- a/src/librustc/middle/typeck/collect.rs +++ b/src/librustc/middle/typeck/collect.rs @@ -889,9 +889,8 @@ fn ty_of_item(ccx: @crate_ctxt, it: @ast::item) fn ty_of_foreign_item(ccx: @crate_ctxt, it: @ast::foreign_item) -> ty::ty_param_bounds_and_ty { match /*bad*/copy it.node { - ast::foreign_item_fn(fn_decl, purity, params) => { - return ty_of_foreign_fn_decl(ccx, fn_decl, purity, params, - local_def(it.id)); + ast::foreign_item_fn(fn_decl, _, params) => { + return ty_of_foreign_fn_decl(ccx, fn_decl, params, local_def(it.id)); } ast::foreign_item_const(t) => { let rb = in_binding_rscope(empty_rscope); @@ -962,7 +961,6 @@ fn ty_param_bounds(ccx: @crate_ctxt, fn ty_of_foreign_fn_decl(ccx: @crate_ctxt, decl: ast::fn_decl, - purity: ast::purity, +ty_params: ~[ast::ty_param], def_id: ast::def_id) -> ty::ty_param_bounds_and_ty { let bounds = ty_param_bounds(ccx, ty_params); @@ -971,7 +969,7 @@ fn ty_of_foreign_fn_decl(ccx: @crate_ctxt, let output_ty = ast_ty_to_ty(ccx, rb, decl.output); let t_fn = ty::mk_fn(ccx.tcx, FnTyBase { - meta: FnMeta {purity: purity, + meta: FnMeta {purity: ast::unsafe_fn, onceness: ast::Many, proto: ast::ProtoBare, bounds: @~[], diff --git a/src/libstd/arena.rs b/src/libstd/arena.rs index a669adc6dc8a4..7ac11ecc5cc50 100644 --- a/src/libstd/arena.rs +++ b/src/libstd/arena.rs @@ -254,9 +254,13 @@ impl &Arena { // The external interface #[inline(always)] fn alloc(op: fn() -> T) -> &self/T { - if !rusti::needs_drop::() { - self.alloc_pod(op) - } else { self.alloc_nonpod(op) } + unsafe { + if !rusti::needs_drop::() { + self.alloc_pod(op) + } else { + self.alloc_nonpod(op) + } + } } }