From 0f9ab936423cfc427ff30e87efc7ca794fec8bcf Mon Sep 17 00:00:00 2001 From: Brian Anderson Date: Sun, 11 Aug 2013 18:54:23 -0700 Subject: [PATCH] std: Restore dynamic borrow tracking --- src/libstd/cleanup.rs | 5 ----- src/libstd/rt/borrowck.rs | 28 ++++++++++++++++++++-------- src/libstd/rt/env.rs | 9 +++++++++ src/libstd/rt/task.rs | 18 ++++++++++++++---- 4 files changed, 43 insertions(+), 17 deletions(-) diff --git a/src/libstd/cleanup.rs b/src/libstd/cleanup.rs index 7c2348a3533..6a6ba12bae3 100644 --- a/src/libstd/cleanup.rs +++ b/src/libstd/cleanup.rs @@ -71,7 +71,6 @@ pub unsafe fn annihilate() { use io::WriterUtil; use io; use libc; - use rt::borrowck; use sys; use managed; @@ -81,10 +80,6 @@ pub unsafe fn annihilate() { n_bytes_freed: 0 }; - // Quick hack: we need to free this list upon task exit, and this - // is a convenient place to do it. - borrowck::clear_task_borrow_list(); - // Pass 1: Make all boxes immortal. // // In this pass, nothing gets freed, so it does not matter whether diff --git a/src/libstd/rt/borrowck.rs b/src/libstd/rt/borrowck.rs index 6400c1b660d..cbac43f27c7 100644 --- a/src/libstd/rt/borrowck.rs +++ b/src/libstd/rt/borrowck.rs @@ -8,6 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +use cell::Cell; use c_str::ToCStr; use cast::transmute; use libc::{c_char, size_t, STDERR_FILENO}; @@ -15,6 +16,9 @@ use io; use io::{Writer, WriterUtil}; use option::{Option, None, Some}; use uint; +use rt::env; +use rt::local::Local; +use rt::task::Task; use str; use str::{OwnedStr, StrSlice}; use sys; @@ -26,22 +30,31 @@ pub static MUT_BIT: uint = 1 << (uint::bits - 2); static ALL_BITS: uint = FROZEN_BIT | MUT_BIT; #[deriving(Eq)] -struct BorrowRecord { +pub struct BorrowRecord { box: *mut raw::Box<()>, file: *c_char, line: size_t } fn try_take_task_borrow_list() -> Option<~[BorrowRecord]> { - // XXX - None + do Local::borrow::> |task| { + task.borrow_list.take() + } } -fn swap_task_borrow_list(_f: &fn(~[BorrowRecord]) -> ~[BorrowRecord]) { - // XXX +fn swap_task_borrow_list(f: &fn(~[BorrowRecord]) -> ~[BorrowRecord]) { + let borrows = match try_take_task_borrow_list() { + Some(l) => l, + None => ~[] + }; + let borrows = f(borrows); + let borrows = Cell::new(borrows); + do Local::borrow:: |task| { + task.borrow_list = Some(borrows.take()); + } } -pub unsafe fn clear_task_borrow_list() { +pub fn clear_task_borrow_list() { // pub because it is used by the box annihilator. let _ = try_take_task_borrow_list(); } @@ -89,8 +102,7 @@ unsafe fn debug_borrow(tag: &'static str, //! A useful debugging function that prints a pointer + tag + newline //! without allocating memory. - // XXX - if false { + if ENABLE_DEBUG && env::debug_borrow() { debug_borrow_slow(tag, p, old_bits, new_bits, filename, line); } diff --git a/src/libstd/rt/env.rs b/src/libstd/rt/env.rs index 3ca39acbfcd..5b840655120 100644 --- a/src/libstd/rt/env.rs +++ b/src/libstd/rt/env.rs @@ -18,6 +18,7 @@ use os; // They are expected to be initialized once then left alone. static mut MIN_STACK: uint = 2000000; +static mut DEBUG_BORROW: bool = false; pub fn init() { unsafe { @@ -28,9 +29,17 @@ pub fn init() { }, None => () } + match os::getenv("RUST_DEBUG_BORROW") { + Some(_) => DEBUG_BORROW = true, + None => () + } } } pub fn min_stack() -> uint { unsafe { MIN_STACK } } + +pub fn debug_borrow() -> bool { + unsafe { DEBUG_BORROW } +} diff --git a/src/libstd/rt/task.rs b/src/libstd/rt/task.rs index 22d26005078..95d60c11df6 100644 --- a/src/libstd/rt/task.rs +++ b/src/libstd/rt/task.rs @@ -20,6 +20,8 @@ use libc::{c_void, uintptr_t}; use ptr; use prelude::*; use option::{Option, Some, None}; +use rt::borrowck; +use rt::borrowck::BorrowRecord; use rt::env; use rt::kill::Death; use rt::local::Local; @@ -51,7 +53,9 @@ pub struct Task { name: Option<~str>, coroutine: Option, sched: Option<~Scheduler>, - task_type: TaskType + task_type: TaskType, + // Dynamic borrowck debugging info + borrow_list: Option<~[BorrowRecord]> } pub enum TaskType { @@ -135,7 +139,8 @@ impl Task { coroutine: Some(Coroutine::empty()), name: None, sched: None, - task_type: SchedTask + task_type: SchedTask, + borrow_list: None } } @@ -168,7 +173,8 @@ impl Task { name: None, coroutine: Some(Coroutine::new(stack_pool, stack_size, start)), sched: None, - task_type: GreenTask(Some(~home)) + task_type: GreenTask(Some(~home)), + borrow_list: None } } @@ -190,7 +196,8 @@ impl Task { name: None, coroutine: Some(Coroutine::new(stack_pool, stack_size, start)), sched: None, - task_type: GreenTask(Some(~home)) + task_type: GreenTask(Some(~home)), + borrow_list: None } } @@ -253,6 +260,9 @@ impl Task { } } + // Cleanup the dynamic borrowck debugging info + borrowck::clear_task_borrow_list(); + // NB. We pass the taskgroup into death so that it can be dropped while // the unkillable counter is set. This is necessary for when the // taskgroup destruction code drops references on KillHandles, which