<commit_before>use std;

import core::ctypes::*;
import core::either::{left, right};
import core::option::{some, none};
import core::result::{ok, err};

const PCRE_CASELESS: int          = 0x00000001; // Compile
const PCRE_MULTILINE: int         = 0x00000002; // Compile
const PCRE_DOTALL: int            = 0x00000004; // Compile
const PCRE_EXTENDED: int          = 0x00000008; // Compile
const PCRE_ANCHORED: int          = 0x00000010; // Compile, exec, DFA exec
const PCRE_DOLLAR_ENDONLY: int    = 0x00000020; // Compile
const PCRE_EXTRA: int             = 0x00000040; // Compile
const PCRE_NOTBOL: int            = 0x00000080; // Exec, DFA exec
const PCRE_NOTEOL: int            = 0x00000100; // Exec, DFA exec
const PCRE_UNGREEDY: int          = 0x00000200; // Compile
const PCRE_NOTEMPTY: int          = 0x00000400; // Exec, DFA exec
const PCRE_UTF8: int              = 0x00000800; // Compile
const PCRE_NO_AUTO_CAPTURE: int   = 0x00001000; // Compile
const PCRE_NO_UTF8_CHECK: int     = 0x00002000; // Compile, exec, DFA exec
const PCRE_AUTO_CALLOUT: int      = 0x00004000; // Compile
const PCRE_PARTIAL_SOFT: int      = 0x00008000; // Exec, DFA exec
const PCRE_PARTIAL: int           = 0x00008000; // Backwards compatible synonym
const PCRE_DFA_SHORTEST: int      = 0x00010000; // DFA exec
const PCRE_DFA_RESTART: int       = 0x00020000; // DFA exec
const PCRE_FIRSTLINE: int         = 0x00040000; // Compile
const PCRE_DUPNAMES: int          = 0x00080000; // Compile
const PCRE_NEWLINE_CR: int        = 0x00100000; // Compile, exec, DFA exec
const PCRE_NEWLINE_LF: int        = 0x00200000; // Compile, exec, DFA exec
const PCRE_NEWLINE_CRLF: int      = 0x00300000; // Compile, exec, DFA exec
const PCRE_NEWLINE_ANY: int       = 0x00400000; // Compile, exec, DFA exec
const PCRE_NEWLINE_ANYCRLF: int   = 0x00500000; // Compile, exec, DFA exec
const PCRE_BSR_ANYCRLF: int       = 0x00800000; // Compile, exec, DFA exec
const PCRE_BSR_UNICODE: int       = 0x01000000; // Compile, exec, DFA exec
const PCRE_JAVASCRIPT_COMPAT: int = 0x02000000; // Compile
const PCRE_NO_START_OPTIMIZE: int = 0x04000000; // Compile, exec, DFA exec
const PCRE_NO_START_OPTIMISE: int = 0x04000000; // Synonym
const PCRE_PARTIAL_HARD: int      = 0x08000000; // Exec, DFA exec
const PCRE_NOTEMPTY_ATSTART: int  = 0x10000000; // Exec, DFA exec
const PCRE_UCP: int               = 0x20000000; // Compile

enum pcre {}
enum pcre_extra {}
resource pcre_res(p: *pcre) {
    c::free(p as *void);
}

/*
Type: exec_result

The result type of <exec>.
*/
type exec_result = result::t<match, match_err>;

/*
Type: match_result

The result type of <match>.
*/
type match_result = result::t<match, either::t<compile_err, match_err>>;

/*
Type: compile_result

The result type of <compile>.
*/
type compile_result = result::t<@pcre_res, compile_err>;

/*
Type: match_err

The type that represents match error.
*/
type match_err = int;

/*
Type: compile_err

The type that represents compile error.
*/
type compile_err = {
    code: int,
    reason: str,
    offset: uint,
};

#[nolink]
#[abi = "cdecl"]
native mod c {
    fn free(p: *void);
}

#[abi = "cdecl"]
native mod pcre {
    fn pcre_compile2(pattern: *c_char, options: c_int,
                     errorcodeptr: *c_int,
                     errptr: **c_char, erroffset: *c_int,
                     tableptr: *c_char) -> *pcre;
    fn pcre_exec(code: *pcre, extra: *pcre_extra,
                 subject: *c_char, length: c_int, startoffset: c_int,
                 options: c_int, ovector: * c_int, ovecsize: c_int) -> c_int;
    fn pcre_fullinfo(code: *pcre, extra: *pcre_extra,
                     what: c_int, where: *c_int) -> c_int;
}

fn compile(pattern: str, options: int) -> compile_result unsafe {
    let options = options | PCRE_NO_UTF8_CHECK; // str is always valid
    let errcode = 0 as c_int;
    let errreason: *c_char = ptr::null();
    let erroffset = 0 as c_int;
    let p = str::as_buf(pattern) {|pat|
        pcre::pcre_compile2(pat as *c_char,
                            options as c_int,
                            ptr::addr_of(errcode),
                            ptr::addr_of(errreason),
                            ptr::addr_of(erroffset),
                            ptr::null())
    };
    if p == ptr::null() {
        let offset = char_offset_from_byte_offset(pattern, erroffset as uint);
        ret err({code: errcode as int,
                 reason: str::from_cstr(errreason as *u8),
                 offset: offset});
    }
    ret ok(@pcre_res(p));
}

fn exec(pcre_res: @pcre_res,
        subject: str, offset: uint,
        options: int, count_FIXME: int) -> exec_result unsafe {
    // FIXME: Weirdly pcre_fullinfo() doesn't work inside exec().
    //        It yields 0, which means success, but the 4th arg doesn't updated.
    //let count = 0 as c_int;
    //pcre::pcre_fullinfo(**pcre_res, ptr::null(),
    //                    2 as c_int /* PCRE_INFO_CAPTURECOUNT */,
    //                    ptr::addr_of(count));
    let count = count_FIXME + 1 as c_int;

    let offset = byte_offset_from_char_offset(subject, offset);

    let ovec = vec::init_elt((count as uint) * 3u, 0u as c_int);
    let ret_code = str::as_buf(subject) {|s|
        pcre::pcre_exec(**pcre_res, ptr::null(),
                        s as *c_char, str::byte_len(subject) as c_int,
                        offset as c_int, options as c_int,
                        vec::to_ptr(ovec) as *c_int, count * (3 as c_int)) as int
    };

    if ret_code < 0 { ret err(ret_code as match_err); }

    // cut off the working space
    vec::unsafe::set_len(ovec, count as uint * 2u);

    let captures = if sys::size_of::<c_int>() == sys::size_of::<uint>() {
        unsafe::reinterpret_cast::<[c_int], [uint]>(ovec)
    } else {
        vec::map(ovec) {|i| i as uint }
    };
    let captures = vec::map(captures) {|o| char_offset_from_byte_offset(subject, o) };

    ret ok({subject: subject, _pcre_res: pcre_res, _captures: captures});
}

type match = {
    subject: str,
    _pcre_res: @pcre_res,
    _captures: [uint],
    // FIXME: we may cache these values for reuse
    // mutable _substrs: option<[str]>,
    // mutable _names: option<std::map<str, uint>>,
};

iface match_like {
    fn noop();
}

impl of match_like for match {
    fn noop() {}
}

iface pattern_like {
    fn compile() -> compile_result;
}

impl of pattern_like for str {
    fn compile() -> compile_result { compile(self, 0) }
}

impl of pattern_like for @pcre_res {
    fn compile() -> compile_result { ok(self) }
}

impl of pattern_like for compile_result {
    fn compile() -> compile_result { self }
}

fn match_from<T: pattern_like>(pattern: T, subject: str, offset: uint, options: int) -> match_result {
    let c = pattern.compile();
    alt c {
      ok(p) {
        // FIXME: see exec()
        let count_FIXME = 0 as c_int;
        pcre::pcre_fullinfo(**p, ptr::null(),
                            2 as c_int /* PCRE_INFO_CAPTURECOUNT */,
                            ptr::addr_of(count_FIXME));
        let e = exec(p, subject, offset, options, count_FIXME as int);
        alt e {
          ok(match) {
            ret ok(match);
          }
          err(match_err) {
            ret err(right(match_err));
          }
        }
      }
      err(compile_err) {
          ret err(left(compile_err));
      }
    }
}

fn match<T: pattern_like>(pattern: T, subject: str, options: int) -> match_result {
    ret match_from(pattern, subject, 0u, options);
}

fn fmt_compile_err(e: compile_err) -> str {
    ret #fmt("error %d: %s at offset %u", e.code, e.reason, e.offset);
}

fn char_offset_from_byte_offset(s: str, byte_offset: uint) -> uint {
    if byte_offset == 0u { ret 0u; }
    let v = str::bytes(s);
    let subv = vec::slice(v, 0u, byte_offset);
    let subs = str::from_bytes(subv);
    ret str::char_len(subs);
}

fn byte_offset_from_char_offset(s: str, char_offset: uint) -> uint {
    if char_offset == 0u { ret 0u; }
    let subs = str::slice(s, 0u, char_offset);
    let v = str::bytes(subs);
    ret vec::len(v);
}

// FIXME: better name?
fn substrs(m: match) -> [str] {
    let v: [str] = [];
    let len = vec::len(m._captures);
    let i = 2u; // skip the first capture since it contains the whole subject
    while i < len {
        vec::push(v, str::slice(m.subject, m._captures[i], m._captures[i+1u]));
        i += 2u;
    }
    ret v;
}

pure fn is_nomatch(mr: match_result) -> bool {
    ret alt mr {
      err(right(-1)) { true }
      _ { false }
    };
}

#[test]
mod test {
    import result::*;

    #[test]
    fn test_compile() {
        import result::*;

        let p = compile("foo", 0);
        assert success(p);

        let p = compile("foo(", 0);
        alt p {
          err(e) {
            assert e.code == 14;
            assert e.reason == "missing )";
            assert e.offset == 4u;
          }
          _ { fail; }
        }
    }

    #[test]
    fn test_match() {
        let p = match("(foo)bar", "foobar", 0);
        assert success(p);

        let c = compile("(foo)bar", 0);
        let p = match(c, "foobar", 0);
        assert success(p);

        let p = match("foo(", "foobar", 0);
        alt p {
          err(left(e)) {
            assert e.code == 14;
            assert e.reason == "missing )";
            assert e.offset == 4u;
          }
          _ { fail; }
        }

        let p = match("(foo)bar", "baz", 0);
        assert is_nomatch(p);
    }

    #[test]
    fn test_substrs() {
        let p = match("(foo)bar(baz)", "foobarbaz", 0);
        alt p {
          ok(m) { assert vec::all2(substrs(m), ["foo", "baz"]) {|s, t| s == t }; }
          _ { fail; }
        }
    }
}

<commit_msg>exec() does not check UTF-8 validity<commit_after>use std;

import core::ctypes::*;
import core::either::{left, right};
import core::option::{some, none};
import core::result::{ok, err};

const PCRE_CASELESS: int          = 0x00000001; // Compile
const PCRE_MULTILINE: int         = 0x00000002; // Compile
const PCRE_DOTALL: int            = 0x00000004; // Compile
const PCRE_EXTENDED: int          = 0x00000008; // Compile
const PCRE_ANCHORED: int          = 0x00000010; // Compile, exec, DFA exec
const PCRE_DOLLAR_ENDONLY: int    = 0x00000020; // Compile
const PCRE_EXTRA: int             = 0x00000040; // Compile
const PCRE_NOTBOL: int            = 0x00000080; // Exec, DFA exec
const PCRE_NOTEOL: int            = 0x00000100; // Exec, DFA exec
const PCRE_UNGREEDY: int          = 0x00000200; // Compile
const PCRE_NOTEMPTY: int          = 0x00000400; // Exec, DFA exec
const PCRE_UTF8: int              = 0x00000800; // Compile
const PCRE_NO_AUTO_CAPTURE: int   = 0x00001000; // Compile
const PCRE_NO_UTF8_CHECK: int     = 0x00002000; // Compile, exec, DFA exec
const PCRE_AUTO_CALLOUT: int      = 0x00004000; // Compile
const PCRE_PARTIAL_SOFT: int      = 0x00008000; // Exec, DFA exec
const PCRE_PARTIAL: int           = 0x00008000; // Backwards compatible synonym
const PCRE_DFA_SHORTEST: int      = 0x00010000; // DFA exec
const PCRE_DFA_RESTART: int       = 0x00020000; // DFA exec
const PCRE_FIRSTLINE: int         = 0x00040000; // Compile
const PCRE_DUPNAMES: int          = 0x00080000; // Compile
const PCRE_NEWLINE_CR: int        = 0x00100000; // Compile, exec, DFA exec
const PCRE_NEWLINE_LF: int        = 0x00200000; // Compile, exec, DFA exec
const PCRE_NEWLINE_CRLF: int      = 0x00300000; // Compile, exec, DFA exec
const PCRE_NEWLINE_ANY: int       = 0x00400000; // Compile, exec, DFA exec
const PCRE_NEWLINE_ANYCRLF: int   = 0x00500000; // Compile, exec, DFA exec
const PCRE_BSR_ANYCRLF: int       = 0x00800000; // Compile, exec, DFA exec
const PCRE_BSR_UNICODE: int       = 0x01000000; // Compile, exec, DFA exec
const PCRE_JAVASCRIPT_COMPAT: int = 0x02000000; // Compile
const PCRE_NO_START_OPTIMIZE: int = 0x04000000; // Compile, exec, DFA exec
const PCRE_NO_START_OPTIMISE: int = 0x04000000; // Synonym
const PCRE_PARTIAL_HARD: int      = 0x08000000; // Exec, DFA exec
const PCRE_NOTEMPTY_ATSTART: int  = 0x10000000; // Exec, DFA exec
const PCRE_UCP: int               = 0x20000000; // Compile

enum pcre {}
enum pcre_extra {}
resource pcre_res(p: *pcre) {
    c::free(p as *void);
}

/*
Type: exec_result

The result type of <exec>.
*/
type exec_result = result::t<match, match_err>;

/*
Type: match_result

The result type of <match>.
*/
type match_result = result::t<match, either::t<compile_err, match_err>>;

/*
Type: compile_result

The result type of <compile>.
*/
type compile_result = result::t<@pcre_res, compile_err>;

/*
Type: match_err

The type that represents match error.
*/
type match_err = int;

/*
Type: compile_err

The type that represents compile error.
*/
type compile_err = {
    code: int,
    reason: str,
    offset: uint,
};

#[nolink]
#[abi = "cdecl"]
native mod c {
    fn free(p: *void);
}

#[abi = "cdecl"]
native mod pcre {
    fn pcre_compile2(pattern: *c_char, options: c_int,
                     errorcodeptr: *c_int,
                     errptr: **c_char, erroffset: *c_int,
                     tableptr: *c_char) -> *pcre;
    fn pcre_exec(code: *pcre, extra: *pcre_extra,
                 subject: *c_char, length: c_int, startoffset: c_int,
                 options: c_int, ovector: * c_int, ovecsize: c_int) -> c_int;
    fn pcre_fullinfo(code: *pcre, extra: *pcre_extra,
                     what: c_int, where: *c_int) -> c_int;
}

fn compile(pattern: str, options: int) -> compile_result unsafe {
    let options = options | PCRE_NO_UTF8_CHECK; // str is always valid
    let errcode = 0 as c_int;
    let errreason: *c_char = ptr::null();
    let erroffset = 0 as c_int;
    let p = str::as_buf(pattern) {|pat|
        pcre::pcre_compile2(pat as *c_char,
                            options as c_int,
                            ptr::addr_of(errcode),
                            ptr::addr_of(errreason),
                            ptr::addr_of(erroffset),
                            ptr::null())
    };
    if p == ptr::null() {
        let offset = char_offset_from_byte_offset(pattern, erroffset as uint);
        ret err({code: errcode as int,
                 reason: str::from_cstr(errreason as *u8),
                 offset: offset});
    }
    ret ok(@pcre_res(p));
}

fn exec(pcre_res: @pcre_res,
        subject: str, offset: uint,
        options: int, count_FIXME: int) -> exec_result unsafe {
    // FIXME: Weirdly pcre_fullinfo() doesn't work inside exec().
    //        It yields 0, which means success, but the 4th arg doesn't updated.
    //let count = 0 as c_int;
    //pcre::pcre_fullinfo(**pcre_res, ptr::null(),
    //                    2 as c_int /* PCRE_INFO_CAPTURECOUNT */,
    //                    ptr::addr_of(count));
    let count = count_FIXME + 1 as c_int;

    let offset = byte_offset_from_char_offset(subject, offset);
    let options = options | PCRE_NO_UTF8_CHECK; // str is always valid

    let ovec = vec::init_elt((count as uint) * 3u, 0u as c_int);
    let ret_code = str::as_buf(subject) {|s|
        pcre::pcre_exec(**pcre_res, ptr::null(),
                        s as *c_char, str::byte_len(subject) as c_int,
                        offset as c_int, options as c_int,
                        vec::to_ptr(ovec) as *c_int, count * (3 as c_int)) as int
    };

    if ret_code < 0 { ret err(ret_code as match_err); }

    // cut off the working space
    vec::unsafe::set_len(ovec, count as uint * 2u);

    let captures = if sys::size_of::<c_int>() == sys::size_of::<uint>() {
        unsafe::reinterpret_cast::<[c_int], [uint]>(ovec)
    } else {
        vec::map(ovec) {|i| i as uint }
    };
    let captures = vec::map(captures) {|o| char_offset_from_byte_offset(subject, o) };

    ret ok({subject: subject, _pcre_res: pcre_res, _captures: captures});
}

type match = {
    subject: str,
    _pcre_res: @pcre_res,
    _captures: [uint],
    // FIXME: we may cache these values for reuse
    // mutable _substrs: option<[str]>,
    // mutable _names: option<std::map<str, uint>>,
};

iface match_like {
    fn noop();
}

impl of match_like for match {
    fn noop() {}
}

iface pattern_like {
    fn compile() -> compile_result;
}

impl of pattern_like for str {
    fn compile() -> compile_result { compile(self, 0) }
}

impl of pattern_like for @pcre_res {
    fn compile() -> compile_result { ok(self) }
}

impl of pattern_like for compile_result {
    fn compile() -> compile_result { self }
}

fn match_from<T: pattern_like>(pattern: T, subject: str, offset: uint, options: int) -> match_result {
    let c = pattern.compile();
    alt c {
      ok(p) {
        // FIXME: see exec()
        let count_FIXME = 0 as c_int;
        pcre::pcre_fullinfo(**p, ptr::null(),
                            2 as c_int /* PCRE_INFO_CAPTURECOUNT */,
                            ptr::addr_of(count_FIXME));
        let e = exec(p, subject, offset, options, count_FIXME as int);
        alt e {
          ok(match) {
            ret ok(match);
          }
          err(match_err) {
            ret err(right(match_err));
          }
        }
      }
      err(compile_err) {
          ret err(left(compile_err));
      }
    }
}

fn match<T: pattern_like>(pattern: T, subject: str, options: int) -> match_result {
    ret match_from(pattern, subject, 0u, options);
}

fn fmt_compile_err(e: compile_err) -> str {
    ret #fmt("error %d: %s at offset %u", e.code, e.reason, e.offset);
}

fn char_offset_from_byte_offset(s: str, byte_offset: uint) -> uint {
    if byte_offset == 0u { ret 0u; }
    let v = str::bytes(s);
    let subv = vec::slice(v, 0u, byte_offset);
    let subs = str::from_bytes(subv);
    ret str::char_len(subs);
}

fn byte_offset_from_char_offset(s: str, char_offset: uint) -> uint {
    if char_offset == 0u { ret 0u; }
    let subs = str::slice(s, 0u, char_offset);
    let v = str::bytes(subs);
    ret vec::len(v);
}

// FIXME: better name?
fn substrs(m: match) -> [str] {
    let v: [str] = [];
    let len = vec::len(m._captures);
    let i = 2u; // skip the first capture since it contains the whole subject
    while i < len {
        vec::push(v, str::slice(m.subject, m._captures[i], m._captures[i+1u]));
        i += 2u;
    }
    ret v;
}

pure fn is_nomatch(mr: match_result) -> bool {
    ret alt mr {
      err(right(-1)) { true }
      _ { false }
    };
}

#[test]
mod test {
    import result::*;

    #[test]
    fn test_compile() {
        import result::*;

        let p = compile("foo", 0);
        assert success(p);

        let p = compile("foo(", 0);
        alt p {
          err(e) {
            assert e.code == 14;
            assert e.reason == "missing )";
            assert e.offset == 4u;
          }
          _ { fail; }
        }
    }

    #[test]
    fn test_match() {
        let p = match("(foo)bar", "foobar", 0);
        assert success(p);

        let c = compile("(foo)bar", 0);
        let p = match(c, "foobar", 0);
        assert success(p);

        let p = match("foo(", "foobar", 0);
        alt p {
          err(left(e)) {
            assert e.code == 14;
            assert e.reason == "missing )";
            assert e.offset == 4u;
          }
          _ { fail; }
        }

        let p = match("(foo)bar", "baz", 0);
        assert is_nomatch(p);
    }

    #[test]
    fn test_substrs() {
        let p = match("(foo)bar(baz)", "foobarbaz", 0);
        alt p {
          ok(m) { assert vec::all2(substrs(m), ["foo", "baz"]) {|s, t| s == t }; }
          _ { fail; }
        }
    }
}

<|endoftext|>


<commit_before>use super::scheduler_thread::*;
use super::job_queue::*;
use super::queue_state::*;
use super::wake_queue::*;

use std::sync::*;
use std::collections::vec_deque::*;

use futures::task;
use futures::task::{Context};

///
/// The scheduler core contains the internal data used by the scheduler
///
pub (super) struct SchedulerCore {
    /// The queues that are active in the scheduler
    pub (super) schedule: Arc<Mutex<VecDeque<Arc<JobQueue>>>>,

    /// Active threads and whether or not they're busy
    pub (super) threads: Mutex<Vec<(Arc<Mutex<bool>>, SchedulerThread)>>,

    /// The maximum number of threads permitted in this scheduler
    pub (super) max_threads: Mutex<usize>
}

impl SchedulerCore {
    ///
    /// Wakes a thread to run a dormant queue. Returns true if a thread was woken up
    ///
    pub (super) fn schedule_thread(&self, core: Arc<SchedulerCore>) -> bool {
        // Find a dormant thread and activate it
        let schedule = self.schedule.clone();

        // Schedule work on this dormant thread
        let work_core   = Arc::clone(&core);
        let do_work     = move |work: Arc<JobQueue>| {
            let waker       = Arc::new(WakeQueue(Arc::clone(&work), Arc::clone(&work_core)));
            let waker       = task::waker_ref(&waker);
            let mut context = Context::from_waker(&waker);

            work.drain(&mut context)
        };

        if !self.schedule_dormant(move || Self::next_to_run(&schedule), do_work) {
            // Try to create a new thread
            if self.spawn_thread_if_less_than_maximum() {
                // Try harder to schedule this task if a thread was created
                self.schedule_thread(core)
            } else {
                // Couldn't schedule on an existing thread or create a new one
                false
            }
        } else {
            // Successfully scheduled
            true
        }
    }

    ///
    /// If a queue is idle and has pending jobs, places it in the schedule
    ///
    pub (super) fn reschedule_queue(&self, queue: &Arc<JobQueue>, core: Arc<SchedulerCore>) {
        let reschedule = {
            let mut core = queue.core.lock().expect("JobQueue core lock");

            match core.state {
                QueueState::Idle => {
                    // Schedule a thread to restart the queue if more things were queued
                    if core.queue.len() > 0 {
                        // Need to schedule the queue after this event
                        core.state = QueueState::Pending;
                        true
                    } else {
                        // Queue is empty and can go back to idle
                        core.state = QueueState::Idle;
                        false
                    }
                },

                QueueState::WaitingForPoll(_) => {
                    // If the target thread gets stuck and stops draining the queue, race it to reschedule it on one of our threads if we can
                    true
                },

                _ => {
                    // Not scheduled
                    false
                }
            }
        };

        if reschedule {
            self.schedule.lock().expect("Schedule lock").push_back(queue.clone());
            self.schedule_thread(core);
        }
    }

    ///
    /// Finds the next queue that should be run. If this returns successfully, the queue will
    /// be marked as running.
    ///
    pub (super) fn next_to_run(schedule: &Arc<Mutex<VecDeque<Arc<JobQueue>>>>) -> Option<Arc<JobQueue>> {
        // Search the queues...
        let mut schedule = schedule.lock().expect("Schedule lock");

        // Find a queue where the state is pending
        while let Some(q) = schedule.pop_front() {
            let mut core = q.core.lock().expect("JobQueue core lock");

            match core.state {
                QueueState::Pending |
                QueueState::WaitingForPoll(_) => {
                    // Queue is ready to run. Mark it as running and return it
                    core.state = QueueState::Running;
                    return Some(q.clone());
                }

                _ => {
                    // Move to the next queue in the schedule
                }
            }
        }

        None
    }

    ///
    /// Attempts to schedule a task on a dormant thread
    ///
    pub (super) fn schedule_dormant<NextJob, RunJob, JobData>(&self, next_job: NextJob, job: RunJob) -> bool
    where
        RunJob:     'static + Send + Fn(JobData) -> (),
        NextJob:    'static + Send + Fn() -> Option<JobData>,
    {
        let mut threads = self.threads.lock().expect("Scheduler threads lock");

        threads.retain(|(_busy, thread)| !thread.is_finished());

        // Find the first thread that is not marked as busy and schedule this task on it
        for &(ref busy_rc, ref thread) in threads.iter() {
            if let Ok(mut busy) = busy_rc.try_lock() {
                // If the busy lock is held, then we consider the thread to be busy
                if !*busy {
                    // Clone the busy mutex so we can return this thread to readiness
                    let also_busy =  busy_rc.clone();

                    // This thread is busy
                    *busy = true;
                    thread.run(move || {
                        let mut done = false;

                        while !done {
                            // Obtain the next job. The thread is not busy once there are no longer any jobs
                            // We hold the mutex while this is going on to avoid a race condition when a thread is going dormant
                            let job_data = {
                                let mut busy = also_busy.lock().expect("Thread busy lock");
                                let job_data = next_job();

                                // If there's no next job, then this thread is no longer busy
                                if job_data.is_none() {
                                    *busy = false;
                                }

                                job_data
                            };

                            // Run the job if there is one, stop the thread if there is not
                            if let Some(job_data) = job_data {
                                job(job_data);
                            } else {
                                done = true;
                            }
                        }
                    });

                    return true;
                }
            }
        }

        // No dormant threads were found
        false
    }

    ///
    /// If we're running fewer than the maximum number of threads, try to spawn a new one
    ///
    pub (super) fn spawn_thread_if_less_than_maximum(&self) -> bool {
        let max_threads = { *self.max_threads.lock().expect("Max threads lock") };
        let mut threads = self.threads.lock().expect("Scheduler threads lock");

        if threads.len() < max_threads {
            // Create a new thread
            let is_busy     = Arc::new(Mutex::new(false));
            let new_thread  = SchedulerThread::new();
            threads.push((is_busy, new_thread));

            true
        } else {
            // Can't spawn a new thread
            false
        }
    }
}
<commit_msg>Actually despawn the threads when they fail so panics get sent somewhere<commit_after>use super::scheduler_thread::*;
use super::job_queue::*;
use super::queue_state::*;
use super::wake_queue::*;

use std::sync::*;
use std::collections::vec_deque::*;

use futures::task;
use futures::task::{Context};

///
/// The scheduler core contains the internal data used by the scheduler
///
pub (super) struct SchedulerCore {
    /// The queues that are active in the scheduler
    pub (super) schedule: Arc<Mutex<VecDeque<Arc<JobQueue>>>>,

    /// Active threads and whether or not they're busy
    pub (super) threads: Mutex<Vec<(Arc<Mutex<bool>>, SchedulerThread)>>,

    /// The maximum number of threads permitted in this scheduler
    pub (super) max_threads: Mutex<usize>
}

impl SchedulerCore {
    ///
    /// Wakes a thread to run a dormant queue. Returns true if a thread was woken up
    ///
    pub (super) fn schedule_thread(&self, core: Arc<SchedulerCore>) -> bool {
        // Find a dormant thread and activate it
        let schedule = self.schedule.clone();

        // Schedule work on this dormant thread
        let work_core   = Arc::clone(&core);
        let do_work     = move |work: Arc<JobQueue>| {
            let waker       = Arc::new(WakeQueue(Arc::clone(&work), Arc::clone(&work_core)));
            let waker       = task::waker_ref(&waker);
            let mut context = Context::from_waker(&waker);

            work.drain(&mut context)
        };

        if !self.schedule_dormant(move || Self::next_to_run(&schedule), do_work) {
            // Try to create a new thread
            if self.spawn_thread_if_less_than_maximum() {
                // Try harder to schedule this task if a thread was created
                self.schedule_thread(core)
            } else {
                // Couldn't schedule on an existing thread or create a new one
                false
            }
        } else {
            // Successfully scheduled
            true
        }
    }

    ///
    /// If a queue is idle and has pending jobs, places it in the schedule
    ///
    pub (super) fn reschedule_queue(&self, queue: &Arc<JobQueue>, core: Arc<SchedulerCore>) {
        let reschedule = {
            let mut core = queue.core.lock().expect("JobQueue core lock");

            match core.state {
                QueueState::Idle => {
                    // Schedule a thread to restart the queue if more things were queued
                    if core.queue.len() > 0 {
                        // Need to schedule the queue after this event
                        core.state = QueueState::Pending;
                        true
                    } else {
                        // Queue is empty and can go back to idle
                        core.state = QueueState::Idle;
                        false
                    }
                },

                QueueState::WaitingForPoll(_) => {
                    // If the target thread gets stuck and stops draining the queue, race it to reschedule it on one of our threads if we can
                    true
                },

                _ => {
                    // Not scheduled
                    false
                }
            }
        };

        if reschedule {
            self.schedule.lock().expect("Schedule lock").push_back(queue.clone());
            self.schedule_thread(core);
        }
    }

    ///
    /// Finds the next queue that should be run. If this returns successfully, the queue will
    /// be marked as running.
    ///
    pub (super) fn next_to_run(schedule: &Arc<Mutex<VecDeque<Arc<JobQueue>>>>) -> Option<Arc<JobQueue>> {
        // Search the queues...
        let mut schedule = schedule.lock().expect("Schedule lock");

        // Find a queue where the state is pending
        while let Some(q) = schedule.pop_front() {
            let mut core = q.core.lock().expect("JobQueue core lock");

            match core.state {
                QueueState::Pending |
                QueueState::WaitingForPoll(_) => {
                    // Queue is ready to run. Mark it as running and return it
                    core.state = QueueState::Running;
                    return Some(q.clone());
                }

                _ => {
                    // Move to the next queue in the schedule
                }
            }
        }

        None
    }

    ///
    /// If any of the scheduler threads have finished (which generally means they panicked), despawn them
    ///
    pub (super) fn remove_finished_threads(&self) {
        let mut dead_threads = vec![];

        // Collate the dead threads into a vec
        {
            // Find busy threads
            let mut threads = self.threads.lock().expect("Scheduler threads lock");

            // TODO: retain doesn't return the removed elements. Really want drain_filter but it's been in nightly for 5 years so I guess it's never getting released?
            for thread_num in 0..threads.len() {
                let (_, thread) = &threads[thread_num];

                if thread.is_finished() {
                    let (is_busy, dead_thread) = threads.remove(thread_num);
                    dead_threads.push((is_busy, dead_thread));
                }
            }
        }

        // Despawn the dead threads (which might panic a bit)
        for (is_busy, dead_thread) in dead_threads {
            // Join with the thread in case it's mid-panic
            dead_thread.despawn().join().unwrap();

            // The busy flag should always be unset after a thread is despawned
            let busy = is_busy.lock().unwrap();
            if *busy {
                panic!("Thread despawned while busy");
            }
        }
    }

    ///
    /// Attempts to schedule a task on a dormant thread
    ///
    pub (super) fn schedule_dormant<NextJob, RunJob, JobData>(&self, next_job: NextJob, job: RunJob) -> bool
    where
        RunJob:     'static + Send + Fn(JobData) -> (),
        NextJob:    'static + Send + Fn() -> Option<JobData>,
    {
        // Try to despawn any threads that have finished since the last time we were called
        self.remove_finished_threads();

        // Find busy threads
        let threads = self.threads.lock().expect("Scheduler threads lock");

        // Find the first thread that is not marked as busy and schedule this task on it
        for &(ref busy_rc, ref thread) in threads.iter() {
            if let Ok(mut busy) = busy_rc.try_lock() {
                // If the busy lock is held, then we consider the thread to be busy
                if !*busy {
                    // Clone the busy mutex so we can return this thread to readiness
                    let also_busy =  busy_rc.clone();

                    // This thread is busy
                    *busy = true;
                    thread.run(move || {
                        let mut done = false;

                        while !done {
                            // Obtain the next job. The thread is not busy once there are no longer any jobs
                            // We hold the mutex while this is going on to avoid a race condition when a thread is going dormant
                            let job_data = {
                                let mut busy = also_busy.lock().expect("Thread busy lock");
                                let job_data = next_job();

                                // If there's no next job, then this thread is no longer busy
                                if job_data.is_none() {
                                    *busy = false;
                                }

                                job_data
                            };

                            // Run the job if there is one, stop the thread if there is not
                            if let Some(job_data) = job_data {
                                job(job_data);
                            } else {
                                done = true;
                            }
                        }
                    });

                    return true;
                }
            }
        }

        // No dormant threads were found
        false
    }

    ///
    /// If we're running fewer than the maximum number of threads, try to spawn a new one
    ///
    pub (super) fn spawn_thread_if_less_than_maximum(&self) -> bool {
        let max_threads = { *self.max_threads.lock().expect("Max threads lock") };
        let mut threads = self.threads.lock().expect("Scheduler threads lock");

        if threads.len() < max_threads {
            // Create a new thread
            let is_busy     = Arc::new(Mutex::new(false));
            let new_thread  = SchedulerThread::new();
            threads.push((is_busy, new_thread));

            true
        } else {
            // Can't spawn a new thread
            false
        }
    }
}
<|endoftext|>


<commit_before>//
//  SOS: the Stupid Operating System
//  by Hawk Weisman (hi@hawkweisman.me)
//
//  Copyright (c) 2015 Hawk Weisman
//  Released under the terms of the MIT license. See `LICENSE` in the root
//  directory of this repository for more information.
//
//! `x86_64` architecture-specific implementation.
// pub mod cpu;
pub mod drivers;
pub mod interrupts;

#[path = "../x86_all/bda.rs"] pub mod bda;
#[path = "../x86_all/multiboot2.rs"] pub mod multiboot2;

use memory::PAddr;
use params::InitParams;
use ::kernel_init;

pub const ARCH_BITS: u8 = 64;

/// Trampoline to ensure we have a correct stack frame for calling [`arch_init`]
///
/// I have no idea why this works, but it does.
///
/// [`arch_init`]: fn.arch_init
#[naked]
#[no_mangle]
pub unsafe extern "C" fn long_mode_init() {
    asm!("movabsq $$(stack_top), %rsp");
    asm!("mov ax, 0
          mov ss, ax
          mov ds, ax
          mov es, ax
          mov fs, ax
          mov gs, ax
          call arch_init"
        :::: "intel");

}

/// Entry point for architecture-specific kernel init
///
/// This expects to be passed the address of a valid
/// Multiboot 2 info struct. It's the bootloader's responsibility to ensure
/// that this is passed in the correct register as expected by the calling
/// convention (`edi` on x86). If this isn't there, you can expect to have a
/// bad problem and not go to space today.
#[no_mangle]
pub extern "C" fn arch_init(multiboot_addr: PAddr) {
    use memory::arch::{HEAP_BASE, HEAP_TOP};

    ::io::term::CONSOLE.lock().clear();
    ::logger::initialize()
        .expect("Could not initialize logger!");

    kinfoln!("in arch_init");

    // -- Unpack multiboot tag ------------------------------------------------
    kinfoln!( dots: " . "
            , "trying to unpack multiboot info at {:?}"
            , multiboot_addr);

    let boot_info
        = unsafe { multiboot2::Info::from(multiboot_addr)
                    .expect("Could not unpack multiboot2 information!") };
    // Extract the memory map tag from the multiboot info
    let mem_map = boot_info.mem_map()
                           .expect("Memory map tag required!");

    kinfoln!(dots: " . ", "Detected memory areas:");
    for area in mem_map {
        kinfoln!( dots: " . . ", "{}", area);
        // TODO: add memory map to init params here
    }

    // Extract ELF sections tag from the multiboot info
    let elf_sections_tag
        = boot_info.elf_sections()
                   .expect("ELF sections tag required!");

    kinfoln!(dots: " . ", "Detecting kernel ELF sections:");

    // Extract kernel ELF sections from  multiboot info
    let kernel_begin
        = elf_sections_tag.sections()
            .map(|s| {
                kinfoln!( dots: " . . ", "{}, flags: {:?}", s, s.flags() );
                s.addr() })
            .min()
            .expect("Could not find kernel start section!\
                    \nSomething is deeply wrong.");

    let mut n_elf_sections = 0;
    let kernel_end
        = elf_sections_tag.sections()
            .map(|s| { n_elf_sections += 1; s.addr() })
            .max()
            .expect("Could not find kernel end section!\
                    \nSomething is deeply wrong.");

    kinfoln!( dots: " . ", "Detected {} kernel ELF sections.", n_elf_sections);
    kinfoln!(dots: " . . ", "Kernel begins at {:#x} and ends at {:#x}."
             , kernel_begin, kernel_end );

    let multiboot_end = multiboot_addr + boot_info.length as u64;

    kinfoln!(dots: " . . ", "Multiboot info begins at {:#x} and ends at {:#x}."
             , multiboot_addr, multiboot_end);

    let params = InitParams { kernel_base: kernel_begin
                            , kernel_top:  kernel_end
                            , heap_base:   unsafe { PAddr::from(HEAP_BASE) }
                            , heap_top:    unsafe { PAddr::from(HEAP_TOP) }
                            };
    kernel_init(params);
}
<commit_msg>refac(x86_64): nicer formatting of ELF section flags in arch_init<commit_after>//
//  SOS: the Stupid Operating System
//  by Hawk Weisman (hi@hawkweisman.me)
//
//  Copyright (c) 2015 Hawk Weisman
//  Released under the terms of the MIT license. See `LICENSE` in the root
//  directory of this repository for more information.
//
//! `x86_64` architecture-specific implementation.
// pub mod cpu;
pub mod drivers;
pub mod interrupts;

#[path = "../x86_all/bda.rs"] pub mod bda;
#[path = "../x86_all/multiboot2.rs"] pub mod multiboot2;

use memory::PAddr;
use params::InitParams;
use ::kernel_init;

pub const ARCH_BITS: u8 = 64;

/// Trampoline to ensure we have a correct stack frame for calling [`arch_init`]
///
/// I have no idea why this works, but it does.
///
/// [`arch_init`]: fn.arch_init
#[naked]
#[no_mangle]
pub unsafe extern "C" fn long_mode_init() {
    asm!("movabsq $$(stack_top), %rsp");
    asm!("mov ax, 0
          mov ss, ax
          mov ds, ax
          mov es, ax
          mov fs, ax
          mov gs, ax
          call arch_init"
        :::: "intel");

}

/// Entry point for architecture-specific kernel init
///
/// This expects to be passed the address of a valid
/// Multiboot 2 info struct. It's the bootloader's responsibility to ensure
/// that this is passed in the correct register as expected by the calling
/// convention (`edi` on x86). If this isn't there, you can expect to have a
/// bad problem and not go to space today.
#[no_mangle]
pub extern "C" fn arch_init(multiboot_addr: PAddr) {
    use memory::arch::{HEAP_BASE, HEAP_TOP};

    ::io::term::CONSOLE.lock().clear();
    ::logger::initialize()
        .expect("Could not initialize logger!");

    kinfoln!("in arch_init");

    // -- Unpack multiboot tag ------------------------------------------------
    kinfoln!( dots: " . "
            , "trying to unpack multiboot info at {:?}"
            , multiboot_addr);

    let boot_info
        = unsafe { multiboot2::Info::from(multiboot_addr)
                    .expect("Could not unpack multiboot2 information!") };
    // Extract the memory map tag from the multiboot info
    let mem_map = boot_info.mem_map()
                           .expect("Memory map tag required!");

    kinfoln!(dots: " . ", "Detected memory areas:");
    for area in mem_map {
        kinfoln!( dots: " . . ", "{}", area);
        // TODO: add memory map to init params here
    }

    // Extract ELF sections tag from the multiboot info
    let elf_sections_tag
        = boot_info.elf_sections()
                   .expect("ELF sections tag required!");

    kinfoln!(dots: " . ", "Detecting kernel ELF sections:");

    // Extract kernel ELF sections from  multiboot info
    let kernel_begin
        = elf_sections_tag.sections()
            .map(|s| {
                kinfoln!( dots: " . . ", "{}", s );
                kinfoln!( dots: " . . . ", "flags: [ {:?} ]", s.flags());
                s.addr() })
            .min()
            .expect("Could not find kernel start section!\
                    \nSomething is deeply wrong.");

    let mut n_elf_sections = 0;
    let kernel_end
        = elf_sections_tag.sections()
            .map(|s| { n_elf_sections += 1; s.addr() })
            .max()
            .expect("Could not find kernel end section!\
                    \nSomething is deeply wrong.");

    kinfoln!( dots: " . ", "Detected {} kernel ELF sections.", n_elf_sections);
    kinfoln!(dots: " . . ", "Kernel begins at {:#x} and ends at {:#x}."
             , kernel_begin, kernel_end );

    let multiboot_end = multiboot_addr + boot_info.length as u64;

    kinfoln!(dots: " . . ", "Multiboot info begins at {:#x} and ends at {:#x}."
             , multiboot_addr, multiboot_end);

    let params = InitParams { kernel_base: kernel_begin
                            , kernel_top:  kernel_end
                            , heap_base:   unsafe { PAddr::from(HEAP_BASE) }
                            , heap_top:    unsafe { PAddr::from(HEAP_TOP) }
                            };
    kernel_init(params);
}
<|endoftext|>


<commit_before>
use std::fmt;

use assembler::source_file_location::SourceFileLocation;

#[derive(PartialEq, Debug, Clone)]
pub enum Token<'a> {
  /// A single-line comment. Value includes ';' but not the newline.
  SingleLineComment(&'a str, SourceFileLocation<'a>),
  /// A period.
  DirectiveMarker(SourceFileLocation<'a>),
  /// An identifier (starts with an _ or a letter, is an underscore or alphanumeric).
  Identifier(&'a str, SourceFileLocation<'a>),
  /// A colon.
  LabelMarker(SourceFileLocation<'a>),
  /// A string literal, contained in double-quotes. Quotes are not included in the value.
  StringLiteral(&'a str, SourceFileLocation<'a>),
  /// A numeric literal value.
  NumericLiteral(usize, SourceFileLocation<'a>),
  /// List separator token ','.
  Comma(SourceFileLocation<'a>),
  /// Newline, a \n character.
  Newline(SourceFileLocation<'a>),
  /// An including the reason that the tokenization failed.
  Error(String, SourceFileLocation<'a>)
}

impl<'a> Token<'a> {
  /**
   @return A reference to the source file location corresponding to any variant of Token.
   */
  pub fn location(&self) -> &SourceFileLocation<'a> {
    match *self {
      Token::SingleLineComment(_, ref loc)  => loc,
      Token::DirectiveMarker(ref loc)       => loc,
      Token::Identifier(_, ref loc)         => loc,
      Token::LabelMarker(ref loc)           => loc,
      Token::StringLiteral(_, ref loc)      => loc,
      Token::NumericLiteral(_, ref loc)     => loc,
      Token::Comma(ref loc)                 => loc,
      Token::Newline(ref loc)               => loc,
      Token::Error(_, ref loc)              => loc
    }
  }
}

impl<'a> fmt::Display for Token<'a> {
  /**
   Formats the receiver for display purposes. This includes the associated value if any
   while omitting the source file location component.
   @param f Formatter to write into.
   @return A result representing the formatted receiver or a failure to write into the Formatter.
   */
  fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
    match *self {
      Token::SingleLineComment(_, _)        => write!(f, "single-line comment"),
      Token::DirectiveMarker(_)             => write!(f, "directive marker"),
      Token::Identifier(ref value, _)       => write!(f, "identifier ({})", value),
      Token::LabelMarker(_)                 => write!(f, "label marker"),
      Token::StringLiteral(ref value, _)    => write!(f, "string literal (\"{}\")", value),
      Token::NumericLiteral(ref value, _)   => write!(f, "numeric literal (\"{}\")", value),
      Token::Comma(_)                       => write!(f, "comma"),
      Token::Newline(_)                     => write!(f, "newline"),
      Token::Error(ref reason, _)           => write!(f, "{}", reason)
    }
  }
}
<commit_msg>Add tests for token Display formatting.<commit_after>
use std::fmt;

use assembler::source_file_location::SourceFileLocation;

#[derive(PartialEq, Debug, Clone)]
pub enum Token<'a> {
  /// A single-line comment. Value includes ';' but not the newline.
  SingleLineComment(&'a str, SourceFileLocation<'a>),
  /// A period.
  DirectiveMarker(SourceFileLocation<'a>),
  /// An identifier (starts with an _ or a letter, is an underscore or alphanumeric).
  Identifier(&'a str, SourceFileLocation<'a>),
  /// A colon.
  LabelMarker(SourceFileLocation<'a>),
  /// A string literal, contained in double-quotes. Quotes are not included in the value.
  StringLiteral(&'a str, SourceFileLocation<'a>),
  /// A numeric literal value.
  NumericLiteral(usize, SourceFileLocation<'a>),
  /// List separator token ','.
  Comma(SourceFileLocation<'a>),
  /// Newline, a \n character.
  Newline(SourceFileLocation<'a>),
  /// An including the reason that the tokenization failed.
  Error(String, SourceFileLocation<'a>)
}

impl<'a> Token<'a> {
  /**
   @return A reference to the source file location corresponding to any variant of Token.
   */
  pub fn location(&self) -> &SourceFileLocation<'a> {
    match *self {
      Token::SingleLineComment(_, ref loc)  => loc,
      Token::DirectiveMarker(ref loc)       => loc,
      Token::Identifier(_, ref loc)         => loc,
      Token::LabelMarker(ref loc)           => loc,
      Token::StringLiteral(_, ref loc)      => loc,
      Token::NumericLiteral(_, ref loc)     => loc,
      Token::Comma(ref loc)                 => loc,
      Token::Newline(ref loc)               => loc,
      Token::Error(_, ref loc)              => loc
    }
  }
}

impl<'a> fmt::Display for Token<'a> {
  /**
   Formats the receiver for display purposes. This includes the associated value if any
   while omitting the source file location component. Names are lower-case.
   @param f Formatter to write into.
   @return A result representing the formatted receiver or a failure to write into the Formatter.
   */
  fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
    match *self {
      Token::SingleLineComment(_, _)        => write!(f, "single-line comment"),
      Token::DirectiveMarker(_)             => write!(f, "directive marker"),
      Token::Identifier(ref value, _)       => write!(f, "identifier ({})", value),
      Token::LabelMarker(_)                 => write!(f, "label marker"),
      Token::StringLiteral(ref value, _)    => write!(f, "string literal (\"{}\")", value),
      Token::NumericLiteral(ref value, _)   => write!(f, "numeric literal ({})", value),
      Token::Comma(_)                       => write!(f, "comma"),
      Token::Newline(_)                     => write!(f, "newline"),
      Token::Error(ref reason, _)           => write!(f, "{}", reason)
    }
  }
}

#[cfg(test)]
mod tests {

  use super::*;

  use assembler::source_file_location::SourceFileLocation;

  #[test]
  fn test_display_fmt() {
    let location = SourceFileLocation::new("test_file.s", 1, 1, 1);
    assert_eq!(format!("{}", Token::SingleLineComment("; Hello", location.clone())), "single-line comment");
    assert_eq!(format!("{}", Token::DirectiveMarker(location.clone())), "directive marker");
    assert_eq!(format!("{}", Token::Identifier("test_id", location.clone())), "identifier (test_id)");
    assert_eq!(format!("{}", Token::LabelMarker(location.clone())), "label marker");
    assert_eq!(format!("{}", Token::StringLiteral("Hello", location.clone())), "string literal (\"Hello\")");
    assert_eq!(format!("{}", Token::NumericLiteral(12, location.clone())), "numeric literal (12)");
    assert_eq!(format!("{}", Token::Comma(location.clone())), "comma");
    assert_eq!(format!("{}", Token::Newline(location.clone())), "newline");
    assert_eq!(format!("{}", Token::Error("error_reason".to_string(), location.clone())), "error_reason");
  }

}
<|endoftext|>


<commit_before>// Cooperative optimization solver
use std::collections::BinaryHeap;
use std::io::Write;
extern crate rand;

#[macro_use(max)]
extern crate gelpia_utils;
extern crate ga;
extern crate gr;

use ga::{ea, Individual};

use gelpia_utils::{Quple, INF, NINF, Flt, Parameters};

use gr::{GI, width_box, split_box, midpoint_box, eps_tol};

use std::sync::{Barrier, RwLock, Arc};

use std::sync::atomic::{AtomicBool, Ordering};

use std::thread;

use std::time::Duration;

extern crate function;
use function::FuncObj;

extern crate args;
use args::{process_args};

extern crate time;

// Returns the upper bound, the domain where this bound occurs and a status
// flag indicating whether the answer is complete for the problem.
fn ibba(x_0: Vec<GI>, e_x: Flt, e_f: Flt,
        f_bestag: Arc<RwLock<Flt>>,
        f_best_shared: Arc<RwLock<Flt>>,
        x_bestbb: Arc<RwLock<Vec<GI>>>,
        b1: Arc<Barrier>, b2: Arc<Barrier>,
        q: Arc<RwLock<BinaryHeap<Quple>>>,
        sync: Arc<AtomicBool>, stop: Arc<AtomicBool>,
        f: FuncObj)
        -> (Flt, Vec<GI>, bool) {
    let mut f_best_high = NINF;
    let mut f_best_low  = NINF;
    let mut best_x = x_0.clone();

    let mut i: u32 = 0;//binade_presplit(&f, &q, &x_0, e_x);
    q.write().unwrap().push(Quple{p: INF, pf: 0, data: x_0.clone(), fdata: f.call(&x_0)});

    while q.read().unwrap().len() != 0 && !stop.load(Ordering::Acquire) {
        if sync.load(Ordering::Acquire) {
            // Ugly: Update the update thread's view of the best branch bound.
            *f_best_shared.write().unwrap() = f_best_low;
            b1.wait();
            b2.wait();
        }
        // Take q as writable during an iteration
        let mut q = q.write().unwrap();

        f_best_low = max!(f_best_low, *f_bestag.read().unwrap());

        let (ref x, fx) =
            match q.pop() {
                Some(y) => (y.data, y.fdata),
                None    => unreachable!()
            };

        //let fx = f.call(x);

        if fx.upper() < f_best_low ||
            width_box(x, e_x) ||
            eps_tol(fx, e_f) {
                if f_best_high < fx.upper() {
                    f_best_high = fx.upper();
                    best_x = x.clone();
                }
                continue;
            }
        else {
            let x_s = split_box(&x);
            for sx in x_s {
                let mid = midpoint_box(&sx);
                let est_m = f.call(&mid);
                let fsx = f.call(&sx);
                let est_max = if est_m.lower() > fsx.lower() {est_m} else {fsx};
                if f_best_low < est_max.lower()  {
                    f_best_low = est_max.lower();
                    *x_bestbb.write().unwrap() = sx.clone();
                }
                i += 1;
                q.push(Quple{p: est_max.upper(),
                             pf: i,
                             data: sx,
                             fdata: fsx});
            }
        }
    }
    if !stop.load(Ordering::Acquire) {
        // Exiting normally
        // Tell GA thread to stop
        stop.store(true, Ordering::Release);
        (f_best_high, best_x, true)
    }
    else {
        // Exiting by some other condition
        (f_best_high, best_x, false)
    }
}

fn distance(p: &Vec<GI>, x: &Vec<GI>) -> Flt {
    let mut result = 0.0;
    for i in 0..x.len() {
        let dx = max!(x[i].lower() - p[i].lower(),
                      0.0, &p[i].lower() - x[i].upper());
        result += dx*dx;
    }
    result.sqrt()
}

fn update(q: Arc<RwLock<BinaryHeap<Quple>>>, population: Arc<RwLock<Vec<Individual>>>,
          f_best_shared: Arc<RwLock<Flt>>,
          stop: Arc<AtomicBool>, sync: Arc<AtomicBool>,
          b1: Arc<Barrier>, b2: Arc<Barrier>,
          f: FuncObj,
          upd_interval: u32,
          timeout: u32) {
    let start = time::get_time();

    'out: while !stop.load(Ordering::Acquire) {
        // Timer code...
        let last_update = time::get_time();
        while (time::get_time() - last_update).num_seconds() <= upd_interval as i64 {
            thread::sleep(Duration::new(1, 0));
            if timeout > 0 && (time::get_time() - start).num_seconds() >= timeout as i64
                && !stop.load(Ordering::Acquire) { // Check if we've already stopped
                    let _ = writeln!(&mut std::io::stderr(), "Stopping early...");
                    stop.store(true, Ordering::Release);
                    break 'out;
                }
        }
        // Signal EA and IBBA threads.
        sync.store(true, Ordering::Release);

        // Wait for EA and IBBA threads to stop.
        b1.wait();                                                               // Dead lock here?
        // Do update bizness.
        let mut q_u = q.write().unwrap();
        let mut q = Vec::new();
        for qi in q_u.iter() {
            q.push(qi.clone());
        }
        let mut pop = population.write().unwrap();
        let fbest = f_best_shared.read().unwrap();

        for i in 0..pop.len() {
            let mut d_min = INF;
            let mut j = 0;
            let mut x: Vec<GI>;
            let px: Flt = NINF;
            let mut x_c: Vec<GI> = q[0].data.clone();
            while j < q.len() && d_min != 0.0 {
                x = q[j].data.clone();
                if f.call(&x).upper() < *fbest {
                    q.remove(j);
                    continue;
                }
                let d = distance(&pop[i].solution, &x);

                if d == 0.0 {d_min = 0.0; continue;}
                else {
                    if d < d_min {d_min = d; x_c = x.clone();}
                }
                j += 1;
            }
            if d_min == 0.0 {
                let fp = f.call(&pop[i].solution).lower();
                if px < fp {
                    q[j] = Quple{p: fp, pf: q[j].pf,
                                 data: q[j].data.clone(),
                                 fdata: q[j].fdata }.clone();
                }
            }
            else {
                // Individual is outside the search region.
                // Project it back into the nearest current search space.
                project(&mut pop[i], &x_c, f.clone());
            }
        }
        // Restore the q for the ibba thread.
        (*q_u) = BinaryHeap::from(q);
        // Clear sync flag.
        sync.store(false, Ordering::SeqCst);

        // Resume EA and IBBA threads.
        b2.wait();                                                               // Dead lock here?
    }
}

/* Projects the box x into the box x_c */
fn project(p: &mut Individual, x_c: &Vec<GI>, f: FuncObj) {
    for i in 0..x_c.len() {
        if p.solution[i].lower() < x_c[i].lower()
            || p.solution[i].lower() > x_c[i].upper() {
                if x_c[i].upper() < p.solution[i].lower()
                {p.solution[i] = GI::new_d(x_c[i].upper(),
                                           x_c[i].upper());}
                else {p.solution[i] = GI::new_d(x_c[i].lower(),
                                                x_c[i].lower());}
            }
    }
    p.fitness = f.call(&p.solution).lower();
}

fn main() {
    let args = process_args();

    let ref x_0 = args.domain;
    let ref fo = args.function;
    let x_err = args.x_error;
    let y_err = args.y_error;

    // Early out if there are no input variables...
    if x_0.len() == 0 {
        let result = fo.call(&x_0);
        println!("[{}, {{}}]", result.upper());
        return
    }

    let q_inner: BinaryHeap<Quple> = BinaryHeap::new();
    let q = Arc::new(RwLock::new(q_inner));

    let population_inner: Vec<Individual> = Vec::new();
    let population = Arc::new(RwLock::new(population_inner));

    let b1 = Arc::new(Barrier::new(3));
    let b2 = Arc::new(Barrier::new(3));

    let sync = Arc::new(AtomicBool::new(false));
    let stop = Arc::new(AtomicBool::new(false));

    let f_bestag: Arc<RwLock<Flt>> = Arc::new(RwLock::new(NINF));
    let f_best_shared: Arc<RwLock<Flt>> = Arc::new(RwLock::new(NINF));

    let x_e = x_0.clone();
    let x_i = x_0.clone();

    let x_bestbb = Arc::new(RwLock::new(x_0.clone()));

    let ibba_thread =
    {
        let q = q.clone();
        let b1 = b1.clone();
        let b2 = b2.clone();
        let f_bestag = f_bestag.clone();
        let f_best_shared = f_best_shared.clone();
        let x_bestbb = x_bestbb.clone();
        let sync = sync.clone();
        let stop = stop.clone();
        let fo_c = fo.clone();
        thread::Builder::new().name("IBBA".to_string()).spawn(move || {
            ibba(x_i, x_err, y_err,
                 f_bestag, f_best_shared,
                 x_bestbb,
                 b1, b2, q, sync, stop, fo_c)
        })};

    let ea_thread =
    {
        let population = population.clone();
        let f_bestag = f_bestag.clone();
        let x_bestbb = x_bestbb.clone();
        let sync = sync.clone();
        let stop = stop.clone();
        let b1 = b1.clone();
        let b2 = b2.clone();
        let fo_c = fo.clone();
        thread::Builder::new().name("EA".to_string()).spawn(move || {
            ea(x_e, Parameters{population: 2000, //1000,
                               selection: 8, //4,
                               elitism: 5, //2,
                               mutation: 0.4_f64,//0.3_f64,
                               crossover: 0.3_f64 // 0.5_f64
            },
               population,
               f_bestag,
               x_bestbb,
               b1, b2,
               stop, sync, fo_c)
        })};

    // pending finding out how to kill threads
    //let update_thread =
    {
        let q = q.clone();
        let population = population.clone();
        let f_best_shared = f_best_shared.clone();
        let sync = sync.clone();
        let stop = stop.clone();
        let b1 = b1.clone();
        let b2 = b2.clone();
        let fo_c = fo.clone();
        let to = args.timeout.clone();
        let ui = args.update_interval.clone();
        let _ = thread::Builder::new().name("Update".to_string()).spawn(move || {
            update(q, population, f_best_shared,
                   stop, sync, b1, b2, fo_c, ui, to)
        });};

    let result = ibba_thread.unwrap().join();
    let ea_result = ea_thread.unwrap().join();
    if !ea_result.is_ok() {
        unreachable!();
    }

    // Join EA and Update here pending stop signaling.
    if result.is_ok() {
        let (mut max, mut interval, completed) = result.unwrap();
        if !completed {
            // Go through all remaining intervals from IBBA to find the true
            // max
            let mut lq = q.write().unwrap();
            while lq.len() != 0 {
                let v = lq.pop().unwrap();
                let ref l_data = &v.data;
                let ub = fo.call(l_data).upper();
                if ub > max {
                    max = ub;
                    interval =v.data.clone();
                }
            }
        }
        println!("[{}, {{", max);
        for i in 0..args.names.len() {
            println!("'{}' : {},", args.names[i], interval[i].to_string());
        }
        println!("}}]");

    }
    else {println!("error")}
}
<commit_msg>Fixed a deadlock<commit_after>// Cooperative optimization solver
use std::collections::BinaryHeap;
use std::io::Write;
extern crate rand;

#[macro_use(max)]
extern crate gelpia_utils;
extern crate ga;
extern crate gr;

use ga::{ea, Individual};

use gelpia_utils::{Quple, INF, NINF, Flt, Parameters};

use gr::{GI, width_box, split_box, midpoint_box, eps_tol};

use std::sync::{Barrier, RwLock, Arc};

use std::sync::atomic::{AtomicBool, Ordering};

use std::thread;

use std::time::Duration;

extern crate function;
use function::FuncObj;

extern crate args;
use args::{process_args};

extern crate time;

// Returns the upper bound, the domain where this bound occurs and a status
// flag indicating whether the answer is complete for the problem.
fn ibba(x_0: Vec<GI>, e_x: Flt, e_f: Flt,
        f_bestag: Arc<RwLock<Flt>>,
        f_best_shared: Arc<RwLock<Flt>>,
        x_bestbb: Arc<RwLock<Vec<GI>>>,
        b1: Arc<Barrier>, b2: Arc<Barrier>,
        q: Arc<RwLock<BinaryHeap<Quple>>>,
        sync: Arc<AtomicBool>, stop: Arc<AtomicBool>,
        f: FuncObj)
        -> (Flt, Vec<GI>, bool) {
    let mut f_best_high = NINF;
    let mut f_best_low  = NINF;
    let mut best_x = x_0.clone();

    let mut i: u32 = 0;//binade_presplit(&f, &q, &x_0, e_x);
    q.write().unwrap().push(Quple{p: INF, pf: 0, data: x_0.clone(), fdata: f.call(&x_0)});

    while q.read().unwrap().len() != 0 && !stop.load(Ordering::Acquire) {
        if sync.load(Ordering::Acquire) {
            // Ugly: Update the update thread's view of the best branch bound.
            *f_best_shared.write().unwrap() = f_best_low;
            b1.wait();
            b2.wait();
        }
        // Take q as writable during an iteration
        let mut q = q.write().unwrap();

        f_best_low = max!(f_best_low, *f_bestag.read().unwrap());

        let (ref x, fx) =
            match q.pop() {
                Some(y) => (y.data, y.fdata),
                None    => unreachable!()
            };

        //let fx = f.call(x);

        if fx.upper() < f_best_low ||
            width_box(x, e_x) ||
            eps_tol(fx, e_f) {
                if f_best_high < fx.upper() {
                    f_best_high = fx.upper();
                    best_x = x.clone();
                }
                continue;
            }
        else {
            let x_s = split_box(&x);
            for sx in x_s {
                let mid = midpoint_box(&sx);
                let est_m = f.call(&mid);
                let fsx = f.call(&sx);
                let est_max = if est_m.lower() > fsx.lower() {est_m} else {fsx};
                if f_best_low < est_max.lower()  {
                    f_best_low = est_max.lower();
                    *x_bestbb.write().unwrap() = sx.clone();
                }
                i += 1;
                q.push(Quple{p: est_max.upper(),
                             pf: i,
                             data: sx,
                             fdata: fsx});
            }
        }
    }
    if !stop.load(Ordering::Acquire) {
        // Exiting normally
        // Tell GA thread to stop
        stop.store(true, Ordering::Release);
        (f_best_high, best_x, true)
    }
    else {
        // Exiting by some other condition
        (f_best_high, best_x, false)
    }
}

fn distance(p: &Vec<GI>, x: &Vec<GI>) -> Flt {
    let mut result = 0.0;
    for i in 0..x.len() {
        let dx = max!(x[i].lower() - p[i].lower(),
                      0.0, &p[i].lower() - x[i].upper());
        result += dx*dx;
    }
    result.sqrt()
}

fn update(q: Arc<RwLock<BinaryHeap<Quple>>>, population: Arc<RwLock<Vec<Individual>>>,
          f_best_shared: Arc<RwLock<Flt>>,
          stop: Arc<AtomicBool>, sync: Arc<AtomicBool>,
          b1: Arc<Barrier>, b2: Arc<Barrier>,
          f: FuncObj,
          upd_interval: u32,
          timeout: u32) {
    let start = time::get_time();

    'out: while !stop.load(Ordering::Acquire) {
        // Timer code...
        let last_update = time::get_time();
        while (time::get_time() - last_update).num_seconds() <= upd_interval as i64 {
            thread::sleep(Duration::new(1, 0));
            if timeout > 0 &&
                (time::get_time() - start).num_seconds() >= timeout as i64 {
                    let _ = writeln!(&mut std::io::stderr(), "Stopping early...");
                    stop.store(true, Ordering::Release);
                    break 'out;
                }
            if stop.load(Ordering::Acquire) { // Check if we've already stopped
                break 'out;
            }
        }
        // Signal EA and IBBA threads.
        sync.store(true, Ordering::Release);

        // Wait for EA and IBBA threads to stop.
        b1.wait();                                                               // Dead lock here?
        // Do update bizness.
        let mut q_u = q.write().unwrap();
        let mut q = Vec::new();
        for qi in q_u.iter() {
            q.push(qi.clone());
        }
        let mut pop = population.write().unwrap();
        let fbest = f_best_shared.read().unwrap();

        for i in 0..pop.len() {
            let mut d_min = INF;
            let mut j = 0;
            let mut x: Vec<GI>;
            let px: Flt = NINF;
            let mut x_c: Vec<GI> = q[0].data.clone();
            while j < q.len() && d_min != 0.0 {
                x = q[j].data.clone();
                if f.call(&x).upper() < *fbest {
                    q.remove(j);
                    continue;
                }
                let d = distance(&pop[i].solution, &x);

                if d == 0.0 {d_min = 0.0; continue;}
                else {
                    if d < d_min {d_min = d; x_c = x.clone();}
                }
                j += 1;
            }
            if d_min == 0.0 {
                let fp = f.call(&pop[i].solution).lower();
                if px < fp {
                    q[j] = Quple{p: fp, pf: q[j].pf,
                                 data: q[j].data.clone(),
                                 fdata: q[j].fdata }.clone();
                }
            }
            else {
                // Individual is outside the search region.
                // Project it back into the nearest current search space.
                project(&mut pop[i], &x_c, f.clone());
            }
        }
        // Restore the q for the ibba thread.
        (*q_u) = BinaryHeap::from(q);
        // Clear sync flag.
        sync.store(false, Ordering::SeqCst);

        // Resume EA and IBBA threads.
        b2.wait();                                                               // Dead lock here?
    }
}

/* Projects the box x into the box x_c */
fn project(p: &mut Individual, x_c: &Vec<GI>, f: FuncObj) {
    for i in 0..x_c.len() {
        if p.solution[i].lower() < x_c[i].lower()
            || p.solution[i].lower() > x_c[i].upper() {
                if x_c[i].upper() < p.solution[i].lower()
                {p.solution[i] = GI::new_d(x_c[i].upper(),
                                           x_c[i].upper());}
                else {p.solution[i] = GI::new_d(x_c[i].lower(),
                                                x_c[i].lower());}
            }
    }
    p.fitness = f.call(&p.solution).lower();
}

fn main() {
    let args = process_args();

    let ref x_0 = args.domain;
    let ref fo = args.function;
    let x_err = args.x_error;
    let y_err = args.y_error;

    // Early out if there are no input variables...
    if x_0.len() == 0 {
        let result = fo.call(&x_0);
        println!("[{}, {{}}]", result.upper());
        return
    }

    let q_inner: BinaryHeap<Quple> = BinaryHeap::new();
    let q = Arc::new(RwLock::new(q_inner));

    let population_inner: Vec<Individual> = Vec::new();
    let population = Arc::new(RwLock::new(population_inner));

    let b1 = Arc::new(Barrier::new(3));
    let b2 = Arc::new(Barrier::new(3));

    let sync = Arc::new(AtomicBool::new(false));
    let stop = Arc::new(AtomicBool::new(false));

    let f_bestag: Arc<RwLock<Flt>> = Arc::new(RwLock::new(NINF));
    let f_best_shared: Arc<RwLock<Flt>> = Arc::new(RwLock::new(NINF));

    let x_e = x_0.clone();
    let x_i = x_0.clone();

    let x_bestbb = Arc::new(RwLock::new(x_0.clone()));

    let ibba_thread =
    {
        let q = q.clone();
        let b1 = b1.clone();
        let b2 = b2.clone();
        let f_bestag = f_bestag.clone();
        let f_best_shared = f_best_shared.clone();
        let x_bestbb = x_bestbb.clone();
        let sync = sync.clone();
        let stop = stop.clone();
        let fo_c = fo.clone();
        thread::Builder::new().name("IBBA".to_string()).spawn(move || {
            ibba(x_i, x_err, y_err,
                 f_bestag, f_best_shared,
                 x_bestbb,
                 b1, b2, q, sync, stop, fo_c)
        })};

    let ea_thread =
    {
        let population = population.clone();
        let f_bestag = f_bestag.clone();
        let x_bestbb = x_bestbb.clone();
        let sync = sync.clone();
        let stop = stop.clone();
        let b1 = b1.clone();
        let b2 = b2.clone();
        let fo_c = fo.clone();
        thread::Builder::new().name("EA".to_string()).spawn(move || {
            ea(x_e, Parameters{population: 2000, //1000,
                               selection: 8, //4,
                               elitism: 5, //2,
                               mutation: 0.4_f64,//0.3_f64,
                               crossover: 0.3_f64 // 0.5_f64
            },
               population,
               f_bestag,
               x_bestbb,
               b1, b2,
               stop, sync, fo_c)
        })};

    // pending finding out how to kill threads
    //let update_thread =
    {
        let q = q.clone();
        let population = population.clone();
        let f_best_shared = f_best_shared.clone();
        let sync = sync.clone();
        let stop = stop.clone();
        let b1 = b1.clone();
        let b2 = b2.clone();
        let fo_c = fo.clone();
        let to = args.timeout.clone();
        let ui = args.update_interval.clone();
        let _ = thread::Builder::new().name("Update".to_string()).spawn(move || {
            update(q, population, f_best_shared,
                   stop, sync, b1, b2, fo_c, ui, to)
        });};

    let result = ibba_thread.unwrap().join();
    let ea_result = ea_thread.unwrap().join();
    if !ea_result.is_ok() {
        unreachable!();
    }

    // Join EA and Update here pending stop signaling.
    if result.is_ok() {
        let (mut max, mut interval, completed) = result.unwrap();
        if !completed {
            // Go through all remaining intervals from IBBA to find the true
            // max
            let mut lq = q.write().unwrap();
            while lq.len() != 0 {
                let v = lq.pop().unwrap();
                let ref l_data = &v.data;
                let ub = fo.call(l_data).upper();
                if ub > max {
                    max = ub;
                    interval =v.data.clone();
                }
            }
        }
        println!("[{}, {{", max);
        for i in 0..args.names.len() {
            println!("'{}' : {},", args.names[i], interval[i].to_string());
        }
        println!("}}]");

    }
    else {println!("error")}
}
<|endoftext|>


<commit_before>//#![feature(stmt_expr_attributes)]
extern crate mysilva ;
extern crate chrono ;
extern crate bit_vec ;
extern crate itertools ;

use std::io;
use bit_vec::BitVec ;
use mysilva::* ;
use chrono::* ;
use itertools::Itertools ;

const SIGNBIT : i32 = 1<<31;
const SUBSTITUTE : usize = 4 ;

fn main() {
'foo : loop {
println!("Please enter an integer from 1 to 17. The program will count the exact number of primes below this power of 10: ");
let mut exponent = String::new()  ;
io::stdin().read_line(&mut exponent).ok().expect("Failed to read line");
let exponent : u32 = exponent.trim().parse().ok().expect("Please enter an integer") ;
match exponent {
	1...17 => (),
	_ => {println!("Not a valid input: integer between 1 and 17"); return ;},
	}
let start: DateTime<Local> = Local::now();
println!("{:?}",start.format("%a %e %b %T ").to_string()) ;
let m = 10u64.pow(exponent) ;
let mut beta = 0.00087 ;
//    if exponent = 18 then  beta:= 0.0033; also needs posssibly quite extensive re-typing and takes over an hour
if exponent <= 7 { beta = 0.001 ; }
let alpha = beta * (exponent as f64 *10.0_f64.ln()).powi(3);
let n = (alpha * (m as f64).cbrt()+0.5).floor() as usize;
let z = (10.0_f64.powf(exponent as f64 * 2.0 / 3.0) / alpha).floor() as usize + 1 ;
if n > z {
    println!("adjust beta");
    return;
}
let mut ll = (n+1) >> 1 ;
if exponent <= 5 { ll = (m as usize - 1) >> 1; }
let mut primes : Vec<usize> = vec!(1;ll+1) ;
let mut mu : Vec<isize> = vec![1;ll + 1];
let mut pi : Vec<usize> = vec![0;ll + 1];
let pix = initialize_arrays(ll,&mut mu,&mut pi, &mut primes) ;
if exponent <= 5 {
 println!("prime count = {} ", pix) ;
let end: DateTime<Local> = Local::now();
println!("{:?}",end - start) ;
 continue;
 }
primes.truncate(pix+1) ;
let a = pi[(n + 1) >> 1];
let astar = pi[(int_sqrt(n) + 1) >> 1];
let lc = (n as f64).log2().floor() as u8 ;
let  interval_length = (1 << lc) as usize ;
let  num_intervals = (z / interval_length ) + 1 ;
let mut interval_boundaries : Vec<usize> = vec![1;num_intervals + 1];
let mut initial : Vec<i32> = vec![0;interval_length];
let mut m1 : Vec<usize> = vec![n;astar ];
let mut phi : Vec<u64> = vec![0;a + 1];
let mut t : Vec<usize> = vec![0;a-1];
let mut tt : Vec<u8> = vec![0;a-1];
let mut d2 : Vec<usize> = vec![0;a-1];
let mut offsets : Vec<usize> = vec![0;a + 1];
let mut block : BitVec = BitVec::from_elem(n+3,false);
let mut switch : Vec<bool> = vec![false;a + 1];
(1..num_intervals).foreach(|i| { interval_boundaries[i] = 1 + (i * interval_length); }) ;
interval_boundaries[num_intervals] = z;
let mut  phi2 = (a as i64* (a as i64 - 1)) >> 1;
let mut u = match exponent % 2 {
 0 =>  10usize.pow(exponent/2) - 1,
 _  => 10.0_f64.powf(exponent as f64 / 2.0).floor() as usize,};
if u % 2 == 0 { u -= 1;}
let mut v = a;
let mut w = u + 1;
let mut  count = a as i64 - 1;
count += ordinary_leaves(n,&mu,m);
(0..SUBSTITUTE+1).foreach(|index|
 	count -= special_leaves_type_1_substitute(index,&primes,n,&mu,m) )    ;
(astar..a - 1).foreach(|index| {
    special_leaves_type_2_initialize(index,primes[index + 1],m,&mut t,n,&pi,a,&mut d2,&mut count) ;
    special_leaves_type_2(index,0,&mut d2,m,&primes,&mut tt,n,&mut switch,&interval_boundaries,&mut count,&initial,&pi); } ) ;
initial.iter_mut().into_rc().enumerate().foreach( |(i,e)| {*e = (i as i32 +1) & !(i as i32) } ) ;
// start of main loop
(0..num_intervals).foreach( |interval| {
let mut	 counter = &mut initial.clone() ;
(1..a + 1).foreach( |index| {   interval_clear(index,&mut offsets,&mut counter,interval_length,primes[index]) ;
if index < astar && index > SUBSTITUTE { special_leaves_type_1(index,interval,&mut m1,n,primes[index + 1],m,&interval_boundaries,&mu,&mut count,&phi,&counter) ; }
if index >= astar  && switch[index]
{  	let	s2bprimes = special_leaves_type_2(index,interval,&mut d2,m,&primes,&mut tt,n,&mut switch,&interval_boundaries,&mut count,&counter,&pi);
 		count += (s2bprimes as u64 * phi[index]) as i64 ;    }
if !switch[index] && index >=astar && index < a-1 { return;}
if index == a {
	let p2primes = p2(interval,&mut u,&mut v,n,&mut w,&mut block,&primes,m,&interval_boundaries,&mut phi2,&counter,a)  ;
phi2 += phi[index] as i64 * p2primes as i64; }
phi[index] += (counter[interval_length - 1] & !SIGNBIT) as u64; } ) ;  } );
//end of main loop
println!("prime count for 10 ^ {} = {} ",exponent,count - phi2) ;
let end: DateTime<Local> = Local::now();
println!("{} seconds {} milliseconds",(end-start).num_milliseconds()/1000, (end-start).num_milliseconds()-(end-start).num_seconds()*1000) ;
continue 'foo ;
}
}
<commit_msg>better formatting of timing of program<commit_after>//#![feature(stmt_expr_attributes)]
extern crate mysilva ;
extern crate chrono ;
extern crate bit_vec ;
extern crate itertools ;

use std::io;
use bit_vec::BitVec ;
use mysilva::* ;
use chrono::* ;
use itertools::Itertools ;

const SIGNBIT : i32 = 1<<31;
const SUBSTITUTE : usize = 4 ;

fn main() {
'foo : loop {
println!("Please enter an integer from 1 to 17. The program will count the exact number of primes below this power of 10: ");
let mut exponent = String::new()  ;
io::stdin().read_line(&mut exponent).ok().expect("Failed to read line");
let exponent : u32 = exponent.trim().parse().ok().expect("Please enter an integer") ;
match exponent {
	1...17 => (),
	_ => {println!("Not a valid input: integer between 1 and 17"); return ;},
	}
let start: DateTime<Local> = Local::now();
println!("{:?}",start.format("%a %e %b %T ").to_string()) ;
let m = 10u64.pow(exponent) ;
let mut beta = 0.00087 ;
//    if exponent = 18 then  beta:= 0.0033; also needs posssibly quite extensive re-typing and takes over an hour
if exponent <= 7 { beta = 0.001 ; }
let alpha = beta * (exponent as f64 *10.0_f64.ln()).powi(3);
let n = (alpha * (m as f64).cbrt()+0.5).floor() as usize;
let z = (10.0_f64.powf(exponent as f64 * 2.0 / 3.0) / alpha).floor() as usize + 1 ;
if n > z {
    println!("adjust beta");
    return;
}
let mut ll = (n+1) >> 1 ;
if exponent <= 5 { ll = (m as usize - 1) >> 1; }
let mut primes : Vec<usize> = vec!(1;ll+1) ;
let mut mu : Vec<isize> = vec![1;ll + 1];
let mut pi : Vec<usize> = vec![0;ll + 1];
let pix = initialize_arrays(ll,&mut mu,&mut pi, &mut primes) ;
if exponent <= 5 {
 println!("prime count = {} ", pix) ;
let end: DateTime<Local> = Local::now();
println!("{:?}",end - start) ;
 continue;
 }
primes.truncate(pix+1) ;
let a = pi[(n + 1) >> 1];
let astar = pi[(int_sqrt(n) + 1) >> 1];
let lc = (n as f64).log2().floor() as u8 ;
let  interval_length = (1 << lc) as usize ;
let  num_intervals = (z / interval_length ) + 1 ;
let mut interval_boundaries : Vec<usize> = vec![1;num_intervals + 1];
let mut initial : Vec<i32> = vec![0;interval_length];
let mut m1 : Vec<usize> = vec![n;astar ];
let mut phi : Vec<u64> = vec![0;a + 1];
let mut t : Vec<usize> = vec![0;a-1];
let mut tt : Vec<u8> = vec![0;a-1];
let mut d2 : Vec<usize> = vec![0;a-1];
let mut offsets : Vec<usize> = vec![0;a + 1];
let mut block : BitVec = BitVec::from_elem(n+3,false);
let mut switch : Vec<bool> = vec![false;a + 1];
(1..num_intervals).foreach(|i| { interval_boundaries[i] = 1 + (i * interval_length); }) ;
interval_boundaries[num_intervals] = z;
let mut  phi2 = (a as i64* (a as i64 - 1)) >> 1;
let mut u = match exponent % 2 {
 0 =>  10usize.pow(exponent/2) - 1,
 _  => 10.0_f64.powf(exponent as f64 / 2.0).floor() as usize,};
if u % 2 == 0 { u -= 1;}
let mut v = a;
let mut w = u + 1;
let mut  count = a as i64 - 1;
count += ordinary_leaves(n,&mu,m);
(0..SUBSTITUTE+1).foreach(|index|
 	count -= special_leaves_type_1_substitute(index,&primes,n,&mu,m) )    ;
(astar..a - 1).foreach(|index| {
    special_leaves_type_2_initialize(index,primes[index + 1],m,&mut t,n,&pi,a,&mut d2,&mut count) ;
    special_leaves_type_2(index,0,&mut d2,m,&primes,&mut tt,n,&mut switch,&interval_boundaries,&mut count,&initial,&pi); } ) ;
initial.iter_mut().into_rc().enumerate().foreach( |(i,e)| {*e = (i as i32 +1) & !(i as i32) } ) ;
// start of main loop
(0..num_intervals).foreach( |interval| {
let mut	 counter = &mut initial.clone() ;
(1..a + 1).foreach( |index| {   interval_clear(index,&mut offsets,&mut counter,interval_length,primes[index]) ;
if index < astar && index > SUBSTITUTE { special_leaves_type_1(index,interval,&mut m1,n,primes[index + 1],m,&interval_boundaries,&mu,&mut count,&phi,&counter) ; }
if index >= astar  && switch[index]
{  	let	s2bprimes = special_leaves_type_2(index,interval,&mut d2,m,&primes,&mut tt,n,&mut switch,&interval_boundaries,&mut count,&counter,&pi);
 		count += (s2bprimes as u64 * phi[index]) as i64 ;    }
if !switch[index] && index >=astar && index < a-1 { return;}
if index == a {
	let p2primes = p2(interval,&mut u,&mut v,n,&mut w,&mut block,&primes,m,&interval_boundaries,&mut phi2,&counter,a)  ;
phi2 += phi[index] as i64 * p2primes as i64; }
phi[index] += (counter[interval_length - 1] & !SIGNBIT) as u64; } ) ;  } );
//end of main loop
println!("prime count for 10 ^ {} = {} ",exponent,count - phi2) ;
let end: DateTime<Local> = Local::now(); let elapsed = end-start ;
println!("{} minutes {} seconds {} milliseconds",elapsed.num_minutes(),elapsed.num_seconds()-elapsed.num_minutes()*60, elapsed.num_milliseconds()-elapsed.num_seconds()*1000) ;
continue 'foo ;
}
}
<|endoftext|>


<commit_before>mod particles;
use self::particles::{Particle, ParticleVec, ParticleRef};

#[test]
fn test_usize() {
    let mut aos = Vec::new();
    let mut soa = ParticleVec::new();

    let particle = Particle::new(String::from("Na"), 56.0);
    aos.push(particle.clone());
    soa.push(particle.clone());

    // SoaIndex
    assert_eq!(soa.get(0).unwrap().name, &aos.get(0).unwrap().name);
    assert_eq!(soa.get(0).unwrap().mass, &aos.get(0).unwrap().mass);
    assert_eq!(aos.get(1), None);
    assert_eq!(soa.get(1), None);

    unsafe {
        assert_eq!(soa.get_unchecked(0).name, &aos.get_unchecked(0).name);
        assert_eq!(soa.get_unchecked(0).mass, &aos.get_unchecked(0).mass);
    }

    assert_eq!(soa.index(0).name, &aos[0].name);
    assert_eq!(soa.index(0).mass, &aos[0].mass);

    // SoaIndexMut
    assert_eq!(soa.get_mut(0).unwrap().name, &aos.get_mut(0).unwrap().name);
    assert_eq!(soa.get_mut(0).unwrap().mass, &aos.get_mut(0).unwrap().mass);
    assert_eq!(aos.get_mut(1), None);
    assert_eq!(soa.get_mut(1), None);

    unsafe {
        assert_eq!(soa.get_unchecked_mut(0).name, &aos.get_unchecked_mut(0).name);
        assert_eq!(soa.get_unchecked_mut(0).mass, &aos.get_unchecked_mut(0).mass);
    }

    assert_eq!(soa.index_mut(0).name, &aos[0].name);
    assert_eq!(soa.index_mut(0).mass, &aos[0].mass);

    *soa.index_mut(0).mass -= 1.;
    assert_eq!(soa.get(0).map(|p| *p.mass), Some(particle.mass - 1.));

    *soa.get_mut(0).unwrap().mass += 1.;
    assert_eq!(soa.get(0).map(|p| *p.mass), Some(particle.mass));
}

fn eq_its<'a, I1, I2>(i1: I1, i2: I2)
where
    I1: Iterator<Item = ParticleRef<'a>>,
    I2: Iterator<Item = &'a Particle>,
{
    for (p1, p2) in i1.zip(i2) {
        assert_eq!(*p1.mass, p2.mass);
    }
}

#[test]
fn test_ranges() {
    let mut particles = Vec::new();
    particles.push(Particle::new(String::from("Cl"), 1.0));
    particles.push(Particle::new(String::from("Na"), 2.0));
    particles.push(Particle::new(String::from("Br"), 3.0));
    particles.push(Particle::new(String::from("Zn"), 4.0));

    let mut soa = ParticleVec::new();

    for particle in particles.iter() {
        soa.push(particle.clone());
    }

    eq_its(soa.iter(), particles.iter());

    // All tests from here are the same only changing the range

    let range = 0..1;
    eq_its(soa.get(range.clone()).unwrap().iter(), particles.get(range.clone()).unwrap().iter());
    unsafe { eq_its(soa.get_unchecked(range.clone()).iter(), particles.get_unchecked(range.clone()).iter()); }
    eq_its(soa.index(range.clone()).iter(), particles[range.clone()].iter());
    eq_its(soa.get_mut(range.clone()).unwrap().iter(), particles.get(range.clone()).unwrap().iter());
    unsafe { eq_its(soa.get_unchecked_mut(range.clone()).iter(), particles.get_unchecked(range.clone()).iter()); }
    eq_its(soa.index_mut(range.clone()).iter(), particles[range.clone()].iter());

    let range = ..3;
    eq_its(soa.get(range.clone()).unwrap().iter(), particles.get(range.clone()).unwrap().iter());
    unsafe { eq_its(soa.get_unchecked(range.clone()).iter(), particles.get_unchecked(range.clone()).iter()); }
    eq_its(soa.index(range.clone()).iter(), particles[range.clone()].iter());
    eq_its(soa.get_mut(range.clone()).unwrap().iter(), particles.get(range.clone()).unwrap().iter());
    unsafe { eq_its(soa.get_unchecked_mut(range.clone()).iter(), particles.get_unchecked(range.clone()).iter()); }
    eq_its(soa.index_mut(range.clone()).iter(), particles[range.clone()].iter());

    let range = 1..;
    eq_its(soa.get(range.clone()).unwrap().iter(), particles.get(range.clone()).unwrap().iter());
    unsafe { eq_its(soa.get_unchecked(range.clone()).iter(), particles.get_unchecked(range.clone()).iter()); }
    eq_its(soa.index(range.clone()).iter(), particles[range.clone()].iter());
    eq_its(soa.get_mut(range.clone()).unwrap().iter(), particles.get(range.clone()).unwrap().iter());
    unsafe { eq_its(soa.get_unchecked_mut(range.clone()).iter(), particles.get_unchecked(range.clone()).iter()); }
    eq_its(soa.index_mut(range.clone()).iter(), particles[range.clone()].iter());

    let range = ..;
    eq_its(soa.get(range.clone()).unwrap().iter(), particles.get(range.clone()).unwrap().iter());
    unsafe { eq_its(soa.get_unchecked(range.clone()).iter(), particles.get_unchecked(range.clone()).iter()); }
    eq_its(soa.index(range.clone()).iter(), particles[range.clone()].iter());
    eq_its(soa.get_mut(range.clone()).unwrap().iter(), particles.get(range.clone()).unwrap().iter());
    unsafe { eq_its(soa.get_unchecked_mut(range.clone()).iter(), particles.get_unchecked(range.clone()).iter()); }
    eq_its(soa.index_mut(range.clone()).iter(), particles[range.clone()].iter());

    let range = 0..=1;
    eq_its(soa.get(range.clone()).unwrap().iter(), particles.get(range.clone()).unwrap().iter());
    unsafe { eq_its(soa.get_unchecked(range.clone()).iter(), particles.get_unchecked(range.clone()).iter()); }
    eq_its(soa.index(range.clone()).iter(), particles[range.clone()].iter());
    eq_its(soa.get_mut(range.clone()).unwrap().iter(), particles.get(range.clone()).unwrap().iter());
    unsafe { eq_its(soa.get_unchecked_mut(range.clone()).iter(), particles.get_unchecked(range.clone()).iter()); }
    eq_its(soa.index_mut(range.clone()).iter(), particles[range.clone()].iter());

    let range = ..=2;
    eq_its(soa.get(range.clone()).unwrap().iter(), particles.get(range.clone()).unwrap().iter());
    unsafe { eq_its(soa.get_unchecked(range.clone()).iter(), particles.get_unchecked(range.clone()).iter()); }
    eq_its(soa.index(range.clone()).iter(), particles[range.clone()].iter());
    eq_its(soa.get_mut(range.clone()).unwrap().iter(), particles.get(range.clone()).unwrap().iter());
    unsafe { eq_its(soa.get_unchecked_mut(range.clone()).iter(), particles.get_unchecked(range.clone()).iter()); }
    eq_its(soa.index_mut(range.clone()).iter(), particles[range.clone()].iter());

}<commit_msg>Prepare tests to add slice indexing methods' tests<commit_after>mod particles;
use self::particles::{Particle, ParticleVec, ParticleRef};

/// Helper function to assert that two iterators (one of SoA and another of AoS) are equal.
fn eq_its<'a, I1, I2>(i1: I1, i2: I2)
where
    I1: Iterator<Item = ParticleRef<'a>>,
    I2: Iterator<Item = &'a Particle>,
{
    for (p1, p2) in i1.zip(i2) {
        assert_eq!(p1.name, &p2.name);
        assert_eq!(*p1.mass, p2.mass);
    }
}

#[test]
fn test_vec_usize() {
    let mut aos = Vec::new();
    let mut soa = ParticleVec::new();

    let particle = Particle::new(String::from("Na"), 56.0);
    aos.push(particle.clone());
    soa.push(particle.clone());

    // SoaIndex
    assert_eq!(soa.get(0).unwrap().name, &aos.get(0).unwrap().name);
    assert_eq!(soa.get(0).unwrap().mass, &aos.get(0).unwrap().mass);
    assert_eq!(aos.get(1), None);
    assert_eq!(soa.get(1), None);

    unsafe {
        assert_eq!(soa.get_unchecked(0).name, &aos.get_unchecked(0).name);
        assert_eq!(soa.get_unchecked(0).mass, &aos.get_unchecked(0).mass);
    }

    assert_eq!(soa.index(0).name, &aos[0].name);
    assert_eq!(soa.index(0).mass, &aos[0].mass);

    // SoaIndexMut
    assert_eq!(soa.get_mut(0).unwrap().name, &aos.get_mut(0).unwrap().name);
    assert_eq!(soa.get_mut(0).unwrap().mass, &aos.get_mut(0).unwrap().mass);
    assert_eq!(aos.get_mut(1), None);
    assert_eq!(soa.get_mut(1), None);

    unsafe {
        assert_eq!(soa.get_unchecked_mut(0).name, &aos.get_unchecked_mut(0).name);
        assert_eq!(soa.get_unchecked_mut(0).mass, &aos.get_unchecked_mut(0).mass);
    }

    assert_eq!(soa.index_mut(0).name, &aos[0].name);
    assert_eq!(soa.index_mut(0).mass, &aos[0].mass);

    *soa.index_mut(0).mass -= 1.;
    assert_eq!(soa.get(0).map(|p| *p.mass), Some(particle.mass - 1.));

    *soa.get_mut(0).unwrap().mass += 1.;
    assert_eq!(soa.get(0).map(|p| *p.mass), Some(particle.mass));
}

#[test]
fn test_vec_ranges() {
    let mut particles = Vec::new();
    particles.push(Particle::new(String::from("Cl"), 1.0));
    particles.push(Particle::new(String::from("Na"), 2.0));
    particles.push(Particle::new(String::from("Br"), 3.0));
    particles.push(Particle::new(String::from("Zn"), 4.0));

    let mut soa = ParticleVec::new();

    for particle in particles.iter() {
        soa.push(particle.clone());
    }

    eq_its(soa.iter(), particles.iter());

    // All tests from here are the same only changing the range

    let range = 0..1;
    eq_its(soa.get(range.clone()).unwrap().iter(), particles.get(range.clone()).unwrap().iter());
    unsafe { eq_its(soa.get_unchecked(range.clone()).iter(), particles.get_unchecked(range.clone()).iter()); }
    eq_its(soa.index(range.clone()).iter(), particles[range.clone()].iter());
    eq_its(soa.get_mut(range.clone()).unwrap().iter(), particles.get(range.clone()).unwrap().iter());
    unsafe { eq_its(soa.get_unchecked_mut(range.clone()).iter(), particles.get_unchecked(range.clone()).iter()); }
    eq_its(soa.index_mut(range.clone()).iter(), particles[range.clone()].iter());

    let range = ..3;
    eq_its(soa.get(range.clone()).unwrap().iter(), particles.get(range.clone()).unwrap().iter());
    unsafe { eq_its(soa.get_unchecked(range.clone()).iter(), particles.get_unchecked(range.clone()).iter()); }
    eq_its(soa.index(range.clone()).iter(), particles[range.clone()].iter());
    eq_its(soa.get_mut(range.clone()).unwrap().iter(), particles.get(range.clone()).unwrap().iter());
    unsafe { eq_its(soa.get_unchecked_mut(range.clone()).iter(), particles.get_unchecked(range.clone()).iter()); }
    eq_its(soa.index_mut(range.clone()).iter(), particles[range.clone()].iter());

    let range = 1..;
    eq_its(soa.get(range.clone()).unwrap().iter(), particles.get(range.clone()).unwrap().iter());
    unsafe { eq_its(soa.get_unchecked(range.clone()).iter(), particles.get_unchecked(range.clone()).iter()); }
    eq_its(soa.index(range.clone()).iter(), particles[range.clone()].iter());
    eq_its(soa.get_mut(range.clone()).unwrap().iter(), particles.get(range.clone()).unwrap().iter());
    unsafe { eq_its(soa.get_unchecked_mut(range.clone()).iter(), particles.get_unchecked(range.clone()).iter()); }
    eq_its(soa.index_mut(range.clone()).iter(), particles[range.clone()].iter());

    let range = ..;
    eq_its(soa.get(range.clone()).unwrap().iter(), particles.get(range.clone()).unwrap().iter());
    unsafe { eq_its(soa.get_unchecked(range.clone()).iter(), particles.get_unchecked(range.clone()).iter()); }
    eq_its(soa.index(range.clone()).iter(), particles[range.clone()].iter());
    eq_its(soa.get_mut(range.clone()).unwrap().iter(), particles.get(range.clone()).unwrap().iter());
    unsafe { eq_its(soa.get_unchecked_mut(range.clone()).iter(), particles.get_unchecked(range.clone()).iter()); }
    eq_its(soa.index_mut(range.clone()).iter(), particles[range.clone()].iter());

    let range = 0..=1;
    eq_its(soa.get(range.clone()).unwrap().iter(), particles.get(range.clone()).unwrap().iter());
    unsafe { eq_its(soa.get_unchecked(range.clone()).iter(), particles.get_unchecked(range.clone()).iter()); }
    eq_its(soa.index(range.clone()).iter(), particles[range.clone()].iter());
    eq_its(soa.get_mut(range.clone()).unwrap().iter(), particles.get(range.clone()).unwrap().iter());
    unsafe { eq_its(soa.get_unchecked_mut(range.clone()).iter(), particles.get_unchecked(range.clone()).iter()); }
    eq_its(soa.index_mut(range.clone()).iter(), particles[range.clone()].iter());

    let range = ..=2;
    eq_its(soa.get(range.clone()).unwrap().iter(), particles.get(range.clone()).unwrap().iter());
    unsafe { eq_its(soa.get_unchecked(range.clone()).iter(), particles.get_unchecked(range.clone()).iter()); }
    eq_its(soa.index(range.clone()).iter(), particles[range.clone()].iter());
    eq_its(soa.get_mut(range.clone()).unwrap().iter(), particles.get(range.clone()).unwrap().iter());
    unsafe { eq_its(soa.get_unchecked_mut(range.clone()).iter(), particles.get_unchecked(range.clone()).iter()); }
    eq_its(soa.index_mut(range.clone()).iter(), particles[range.clone()].iter());

}<|endoftext|>