libcore: Move Cell to core and de-~mut core and std
This commit is contained in:
parent
c483aab4ae
commit
e2f90091cf
|
@ -8,8 +8,8 @@
|
||||||
// option. This file may not be copied, modified, or distributed
|
// option. This file may not be copied, modified, or distributed
|
||||||
// except according to those terms.
|
// except according to those terms.
|
||||||
|
|
||||||
use core::option;
|
use option;
|
||||||
use core::prelude::*;
|
use prelude::*;
|
||||||
|
|
||||||
/// A dynamic, mutable location.
|
/// A dynamic, mutable location.
|
||||||
///
|
///
|
|
@ -143,6 +143,7 @@ pub mod dlist;
|
||||||
#[path="iter-trait.rs"] #[merge = "iter-trait/dlist.rs"]
|
#[path="iter-trait.rs"] #[merge = "iter-trait/dlist.rs"]
|
||||||
pub mod dlist_iter;
|
pub mod dlist_iter;
|
||||||
pub mod hashmap;
|
pub mod hashmap;
|
||||||
|
pub mod cell;
|
||||||
|
|
||||||
|
|
||||||
/* Tasks and communication */
|
/* Tasks and communication */
|
||||||
|
|
|
@ -86,6 +86,7 @@ bounded and unbounded protocols allows for less code duplication.
|
||||||
|
|
||||||
use cmp::Eq;
|
use cmp::Eq;
|
||||||
use cast::{forget, reinterpret_cast, transmute};
|
use cast::{forget, reinterpret_cast, transmute};
|
||||||
|
use cell::Cell;
|
||||||
use either::{Either, Left, Right};
|
use either::{Either, Left, Right};
|
||||||
use kinds::Owned;
|
use kinds::Owned;
|
||||||
use libc;
|
use libc;
|
||||||
|
@ -917,11 +918,9 @@ pub fn spawn_service<T:Owned,Tb:Owned>(
|
||||||
|
|
||||||
// This is some nasty gymnastics required to safely move the pipe
|
// This is some nasty gymnastics required to safely move the pipe
|
||||||
// into a new task.
|
// into a new task.
|
||||||
let server = ~mut Some(server);
|
let server = Cell(server);
|
||||||
do task::spawn || {
|
do task::spawn {
|
||||||
let mut server_ = None;
|
service(server.take());
|
||||||
server_ <-> *server;
|
|
||||||
service(option::unwrap(server_))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
client
|
client
|
||||||
|
@ -941,11 +940,9 @@ pub fn spawn_service_recv<T:Owned,Tb:Owned>(
|
||||||
|
|
||||||
// This is some nasty gymnastics required to safely move the pipe
|
// This is some nasty gymnastics required to safely move the pipe
|
||||||
// into a new task.
|
// into a new task.
|
||||||
let server = ~mut Some(server);
|
let server = Cell(server);
|
||||||
do task::spawn || {
|
do task::spawn {
|
||||||
let mut server_ = None;
|
service(server.take())
|
||||||
server_ <-> *server;
|
|
||||||
service(option::unwrap(server_))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
client
|
client
|
||||||
|
|
|
@ -107,10 +107,14 @@ fn compare_and_swap(address: &mut int, oldval: int, newval: int) -> bool {
|
||||||
* Shared state & exclusive ARC
|
* Shared state & exclusive ARC
|
||||||
****************************************************************************/
|
****************************************************************************/
|
||||||
|
|
||||||
|
struct UnwrapProtoInner {
|
||||||
|
contents: Option<(comm::ChanOne<()>, comm::PortOne<bool>)>,
|
||||||
|
}
|
||||||
|
|
||||||
// An unwrapper uses this protocol to communicate with the "other" task that
|
// An unwrapper uses this protocol to communicate with the "other" task that
|
||||||
// drops the last refcount on an arc. Unfortunately this can't be a proper
|
// drops the last refcount on an arc. Unfortunately this can't be a proper
|
||||||
// pipe protocol because the unwrapper has to access both stages at once.
|
// pipe protocol because the unwrapper has to access both stages at once.
|
||||||
type UnwrapProto = ~mut Option<(comm::ChanOne<()>, comm::PortOne<bool>)>;
|
type UnwrapProto = ~UnwrapProtoInner;
|
||||||
|
|
||||||
struct ArcData<T> {
|
struct ArcData<T> {
|
||||||
mut count: libc::intptr_t,
|
mut count: libc::intptr_t,
|
||||||
|
@ -139,9 +143,10 @@ struct ArcDestruct<T> {
|
||||||
// reference. In effect, being here means we're the only
|
// reference. In effect, being here means we're the only
|
||||||
// *awake* task with the data.
|
// *awake* task with the data.
|
||||||
if data.unwrapper != 0 {
|
if data.unwrapper != 0 {
|
||||||
let p: UnwrapProto =
|
let mut p: UnwrapProto =
|
||||||
cast::reinterpret_cast(&data.unwrapper);
|
cast::reinterpret_cast(&data.unwrapper);
|
||||||
let (message, response) = option::swap_unwrap(p);
|
let (message, response) =
|
||||||
|
option::swap_unwrap(&mut p.contents);
|
||||||
// Send 'ready' and wait for a response.
|
// Send 'ready' and wait for a response.
|
||||||
comm::send_one(message, ());
|
comm::send_one(message, ());
|
||||||
// Unkillable wait. Message guaranteed to come.
|
// Unkillable wait. Message guaranteed to come.
|
||||||
|
@ -196,7 +201,9 @@ pub unsafe fn unwrap_shared_mutable_state<T:Owned>(rc: SharedMutableState<T>)
|
||||||
let ptr: ~ArcData<T> = cast::reinterpret_cast(&rc.data);
|
let ptr: ~ArcData<T> = cast::reinterpret_cast(&rc.data);
|
||||||
let (p1,c1) = comm::oneshot(); // ()
|
let (p1,c1) = comm::oneshot(); // ()
|
||||||
let (p2,c2) = comm::oneshot(); // bool
|
let (p2,c2) = comm::oneshot(); // bool
|
||||||
let server: UnwrapProto = ~mut Some((c1,p2));
|
let mut server: UnwrapProto = ~UnwrapProtoInner {
|
||||||
|
contents: Some((c1,p2))
|
||||||
|
};
|
||||||
let serverp: int = cast::transmute(server);
|
let serverp: int = cast::transmute(server);
|
||||||
// Try to put our server end in the unwrapper slot.
|
// Try to put our server end in the unwrapper slot.
|
||||||
if compare_and_swap(&mut ptr.unwrapper, 0, serverp) {
|
if compare_and_swap(&mut ptr.unwrapper, 0, serverp) {
|
||||||
|
@ -409,8 +416,9 @@ pub fn unwrap_exclusive<T:Owned>(arc: Exclusive<T>) -> T {
|
||||||
pub mod tests {
|
pub mod tests {
|
||||||
use core::option::{None, Some};
|
use core::option::{None, Some};
|
||||||
|
|
||||||
use option;
|
use cell::Cell;
|
||||||
use comm;
|
use comm;
|
||||||
|
use option;
|
||||||
use private::{exclusive, unwrap_exclusive};
|
use private::{exclusive, unwrap_exclusive};
|
||||||
use result;
|
use result;
|
||||||
use task;
|
use task;
|
||||||
|
@ -423,7 +431,7 @@ pub mod tests {
|
||||||
let num_tasks = 10;
|
let num_tasks = 10;
|
||||||
let count = 10;
|
let count = 10;
|
||||||
|
|
||||||
let total = exclusive(~mut 0);
|
let total = exclusive(~0);
|
||||||
|
|
||||||
for uint::range(0, num_tasks) |_i| {
|
for uint::range(0, num_tasks) |_i| {
|
||||||
let total = total.clone();
|
let total = total.clone();
|
||||||
|
@ -472,9 +480,9 @@ pub mod tests {
|
||||||
#[test]
|
#[test]
|
||||||
pub fn exclusive_unwrap_contended() {
|
pub fn exclusive_unwrap_contended() {
|
||||||
let x = exclusive(~~"hello");
|
let x = exclusive(~~"hello");
|
||||||
let x2 = ~mut Some(x.clone());
|
let x2 = Cell(x.clone());
|
||||||
do task::spawn || {
|
do task::spawn {
|
||||||
let x2 = option::swap_unwrap(x2);
|
let x2 = x2.take();
|
||||||
do x2.with |_hello| { }
|
do x2.with |_hello| { }
|
||||||
task::yield();
|
task::yield();
|
||||||
}
|
}
|
||||||
|
@ -482,11 +490,10 @@ pub mod tests {
|
||||||
|
|
||||||
// Now try the same thing, but with the child task blocking.
|
// Now try the same thing, but with the child task blocking.
|
||||||
let x = exclusive(~~"hello");
|
let x = exclusive(~~"hello");
|
||||||
let x2 = ~mut Some(x.clone());
|
let x2 = Cell(x.clone());
|
||||||
let mut res = None;
|
let mut res = None;
|
||||||
do task::task().future_result(|+r| res = Some(r)).spawn
|
do task::task().future_result(|+r| res = Some(r)).spawn {
|
||||||
|| {
|
let x2 = x2.take();
|
||||||
let x2 = option::swap_unwrap(x2);
|
|
||||||
assert unwrap_exclusive(x2) == ~~"hello";
|
assert unwrap_exclusive(x2) == ~~"hello";
|
||||||
}
|
}
|
||||||
// Have to get rid of our reference before blocking.
|
// Have to get rid of our reference before blocking.
|
||||||
|
@ -498,11 +505,10 @@ pub mod tests {
|
||||||
#[test] #[should_fail] #[ignore(cfg(windows))]
|
#[test] #[should_fail] #[ignore(cfg(windows))]
|
||||||
pub fn exclusive_unwrap_conflict() {
|
pub fn exclusive_unwrap_conflict() {
|
||||||
let x = exclusive(~~"hello");
|
let x = exclusive(~~"hello");
|
||||||
let x2 = ~mut Some(x.clone());
|
let x2 = Cell(x.clone());
|
||||||
let mut res = None;
|
let mut res = None;
|
||||||
do task::task().future_result(|+r| res = Some(r)).spawn
|
do task::task().future_result(|+r| res = Some(r)).spawn {
|
||||||
|| {
|
let x2 = x2.take();
|
||||||
let x2 = option::swap_unwrap(x2);
|
|
||||||
assert unwrap_exclusive(x2) == ~~"hello";
|
assert unwrap_exclusive(x2) == ~~"hello";
|
||||||
}
|
}
|
||||||
assert unwrap_exclusive(x) == ~~"hello";
|
assert unwrap_exclusive(x) == ~~"hello";
|
||||||
|
|
|
@ -18,16 +18,17 @@ it is running, sending a notification to the task that the runtime
|
||||||
is trying to shut down.
|
is trying to shut down.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
use option::{Some, None, swap_unwrap};
|
use cell::Cell;
|
||||||
use private::at_exit::at_exit;
|
use comm::{GenericSmartChan, stream};
|
||||||
use private::global::global_data_clone_create;
|
use comm::{Port, Chan, SharedChan, GenericChan, GenericPort};
|
||||||
use private::finally::Finally;
|
|
||||||
use comm::{Port, Chan, SharedChan, GenericChan,
|
|
||||||
GenericPort, GenericSmartChan, stream};
|
|
||||||
use task::{Task, task, spawn};
|
|
||||||
use task::rt::{task_id, get_task_id};
|
|
||||||
use hashmap::linear::LinearMap;
|
use hashmap::linear::LinearMap;
|
||||||
use ops::Drop;
|
use ops::Drop;
|
||||||
|
use option::{Some, None, swap_unwrap};
|
||||||
|
use private::at_exit::at_exit;
|
||||||
|
use private::finally::Finally;
|
||||||
|
use private::global::global_data_clone_create;
|
||||||
|
use task::rt::{task_id, get_task_id};
|
||||||
|
use task::{Task, task, spawn};
|
||||||
|
|
||||||
type ShutdownMsg = ();
|
type ShutdownMsg = ();
|
||||||
|
|
||||||
|
@ -37,14 +38,13 @@ pub unsafe fn weaken_task(f: &fn(Port<ShutdownMsg>)) {
|
||||||
let service = global_data_clone_create(global_data_key,
|
let service = global_data_clone_create(global_data_key,
|
||||||
create_global_service);
|
create_global_service);
|
||||||
let (shutdown_port, shutdown_chan) = stream::<ShutdownMsg>();
|
let (shutdown_port, shutdown_chan) = stream::<ShutdownMsg>();
|
||||||
let shutdown_port = ~mut Some(shutdown_port);
|
let shutdown_port = Cell(shutdown_port);
|
||||||
let task = get_task_id();
|
let task = get_task_id();
|
||||||
// Expect the weak task service to be alive
|
// Expect the weak task service to be alive
|
||||||
assert service.try_send(RegisterWeakTask(task, shutdown_chan));
|
assert service.try_send(RegisterWeakTask(task, shutdown_chan));
|
||||||
unsafe { rust_dec_kernel_live_count(); }
|
unsafe { rust_dec_kernel_live_count(); }
|
||||||
do fn&() {
|
do fn&() {
|
||||||
let shutdown_port = swap_unwrap(&mut *shutdown_port);
|
f(shutdown_port.take())
|
||||||
f(shutdown_port)
|
|
||||||
}.finally || {
|
}.finally || {
|
||||||
unsafe { rust_inc_kernel_live_count(); }
|
unsafe { rust_inc_kernel_live_count(); }
|
||||||
// Service my have already exited
|
// Service my have already exited
|
||||||
|
@ -67,16 +67,15 @@ fn create_global_service() -> ~WeakTaskService {
|
||||||
|
|
||||||
debug!("creating global weak task service");
|
debug!("creating global weak task service");
|
||||||
let (port, chan) = stream::<ServiceMsg>();
|
let (port, chan) = stream::<ServiceMsg>();
|
||||||
let port = ~mut Some(port);
|
let port = Cell(port);
|
||||||
let chan = SharedChan(chan);
|
let chan = SharedChan(chan);
|
||||||
let chan_clone = chan.clone();
|
let chan_clone = chan.clone();
|
||||||
|
|
||||||
do task().unlinked().spawn {
|
do task().unlinked().spawn {
|
||||||
debug!("running global weak task service");
|
debug!("running global weak task service");
|
||||||
let port = swap_unwrap(&mut *port);
|
let port = Cell(port.take());
|
||||||
let port = ~mut Some(port);
|
|
||||||
do fn&() {
|
do fn&() {
|
||||||
let port = swap_unwrap(&mut *port);
|
let port = port.take();
|
||||||
// The weak task service is itself a weak task
|
// The weak task service is itself a weak task
|
||||||
debug!("weakening the weak service task");
|
debug!("weakening the weak service task");
|
||||||
unsafe { rust_dec_kernel_live_count(); }
|
unsafe { rust_dec_kernel_live_count(); }
|
||||||
|
|
|
@ -602,7 +602,6 @@ fn test_repr() {
|
||||||
exact_test(&(@10), "@10");
|
exact_test(&(@10), "@10");
|
||||||
exact_test(&(@mut 10), "@10");
|
exact_test(&(@mut 10), "@10");
|
||||||
exact_test(&(~10), "~10");
|
exact_test(&(~10), "~10");
|
||||||
exact_test(&(~mut 10), "~mut 10");
|
|
||||||
exact_test(&(&10), "&10");
|
exact_test(&(&10), "&10");
|
||||||
let mut x = 10;
|
let mut x = 10;
|
||||||
exact_test(&(&mut x), "&mut 10");
|
exact_test(&(&mut x), "&mut 10");
|
||||||
|
|
|
@ -34,6 +34,7 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
use cast;
|
use cast;
|
||||||
|
use cell::Cell;
|
||||||
use cmp;
|
use cmp;
|
||||||
use cmp::Eq;
|
use cmp::Eq;
|
||||||
use iter;
|
use iter;
|
||||||
|
@ -397,9 +398,9 @@ impl TaskBuilder {
|
||||||
}
|
}
|
||||||
/// Runs a task, while transfering ownership of one argument to the child.
|
/// Runs a task, while transfering ownership of one argument to the child.
|
||||||
fn spawn_with<A:Owned>(arg: A, f: fn~(v: A)) {
|
fn spawn_with<A:Owned>(arg: A, f: fn~(v: A)) {
|
||||||
let arg = ~mut Some(arg);
|
let arg = Cell(arg);
|
||||||
do self.spawn || {
|
do self.spawn {
|
||||||
f(option::swap_unwrap(arg))
|
f(arg.take());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -73,6 +73,7 @@
|
||||||
#[doc(hidden)]; // FIXME #3538
|
#[doc(hidden)]; // FIXME #3538
|
||||||
|
|
||||||
use cast;
|
use cast;
|
||||||
|
use cell::Cell;
|
||||||
use container::Map;
|
use container::Map;
|
||||||
use option;
|
use option;
|
||||||
use comm::{Chan, GenericChan, GenericPort, Port, stream};
|
use comm::{Chan, GenericChan, GenericPort, Port, stream};
|
||||||
|
@ -530,11 +531,11 @@ pub fn spawn_raw(opts: TaskOpts, f: fn~()) {
|
||||||
gen_child_taskgroup(opts.linked, opts.supervised);
|
gen_child_taskgroup(opts.linked, opts.supervised);
|
||||||
|
|
||||||
unsafe {
|
unsafe {
|
||||||
let child_data = ~mut Some((child_tg, ancestors, f));
|
let child_data = Cell((child_tg, ancestors, f));
|
||||||
// Being killed with the unsafe task/closure pointers would leak them.
|
// Being killed with the unsafe task/closure pointers would leak them.
|
||||||
do unkillable {
|
do unkillable {
|
||||||
// Agh. Get move-mode items into the closure. FIXME (#2829)
|
// Agh. Get move-mode items into the closure. FIXME (#2829)
|
||||||
let (child_tg, ancestors, f) = option::swap_unwrap(child_data);
|
let (child_tg, ancestors, f) = child_data.take();
|
||||||
// Create child task.
|
// Create child task.
|
||||||
let new_task = match opts.sched.mode {
|
let new_task = match opts.sched.mode {
|
||||||
DefaultScheduler => rt::new_task(),
|
DefaultScheduler => rt::new_task(),
|
||||||
|
@ -571,10 +572,10 @@ pub fn spawn_raw(opts: TaskOpts, f: fn~()) {
|
||||||
ancestors: AncestorList, is_main: bool,
|
ancestors: AncestorList, is_main: bool,
|
||||||
notify_chan: Option<Chan<TaskResult>>,
|
notify_chan: Option<Chan<TaskResult>>,
|
||||||
f: fn~()) -> fn~() {
|
f: fn~()) -> fn~() {
|
||||||
let child_data = ~mut Some((child_arc, ancestors));
|
let child_data = Cell((child_arc, ancestors));
|
||||||
return fn~() {
|
return fn~() {
|
||||||
// Agh. Get move-mode items into the closure. FIXME (#2829)
|
// Agh. Get move-mode items into the closure. FIXME (#2829)
|
||||||
let mut (child_arc, ancestors) = option::swap_unwrap(child_data);
|
let mut (child_arc, ancestors) = child_data.take();
|
||||||
// Child task runs this code.
|
// Child task runs this code.
|
||||||
|
|
||||||
// Even if the below code fails to kick the child off, we must
|
// Even if the below code fails to kick the child off, we must
|
||||||
|
|
|
@ -549,6 +549,7 @@ use syntax::codemap;
|
||||||
use util::common::indenter;
|
use util::common::indenter;
|
||||||
use util::ppaux::note_and_explain_region;
|
use util::ppaux::note_and_explain_region;
|
||||||
|
|
||||||
|
use core::cell::{Cell, empty_cell};
|
||||||
use core::cmp;
|
use core::cmp;
|
||||||
use core::dvec::DVec;
|
use core::dvec::DVec;
|
||||||
use core::to_bytes;
|
use core::to_bytes;
|
||||||
|
@ -557,7 +558,6 @@ use core::vec;
|
||||||
use result::Result;
|
use result::Result;
|
||||||
use result::{Ok, Err};
|
use result::{Ok, Err};
|
||||||
use std::oldmap::HashMap;
|
use std::oldmap::HashMap;
|
||||||
use std::cell::{Cell, empty_cell};
|
|
||||||
use std::list::{List, Nil, Cons};
|
use std::list::{List, Nil, Cons};
|
||||||
use syntax::codemap::span;
|
use syntax::codemap::span;
|
||||||
use syntax::codemap;
|
use syntax::codemap;
|
||||||
|
|
|
@ -314,8 +314,8 @@ fails without recording a fatal error then we've encountered a compiler
|
||||||
bug and need to present an error.
|
bug and need to present an error.
|
||||||
*/
|
*/
|
||||||
pub fn monitor(+f: fn~(diagnostic::Emitter)) {
|
pub fn monitor(+f: fn~(diagnostic::Emitter)) {
|
||||||
|
use core::cell::Cell;
|
||||||
use core::comm::*;
|
use core::comm::*;
|
||||||
use std::cell::Cell;
|
|
||||||
let (p, ch) = stream();
|
let (p, ch) = stream();
|
||||||
let ch = SharedChan(ch);
|
let ch = SharedChan(ch);
|
||||||
let ch_capture = ch.clone();
|
let ch_capture = ch.clone();
|
||||||
|
|
|
@ -21,8 +21,8 @@ use core::prelude::*;
|
||||||
|
|
||||||
use parse;
|
use parse;
|
||||||
use util;
|
use util;
|
||||||
use std::cell::Cell;
|
|
||||||
|
|
||||||
|
use core::cell::Cell;
|
||||||
use core::comm::{stream, Chan, SharedChan, Port};
|
use core::comm::{stream, Chan, SharedChan, Port};
|
||||||
use core::vec;
|
use core::vec;
|
||||||
use core::ops::Drop;
|
use core::ops::Drop;
|
||||||
|
|
|
@ -10,6 +10,7 @@
|
||||||
|
|
||||||
use core::prelude::*;
|
use core::prelude::*;
|
||||||
|
|
||||||
|
use core::cell::Cell;
|
||||||
use core::cmp;
|
use core::cmp;
|
||||||
use core::os;
|
use core::os;
|
||||||
use core::result;
|
use core::result;
|
||||||
|
@ -18,7 +19,6 @@ use core::run::ProgramOutput;
|
||||||
use core::vec;
|
use core::vec;
|
||||||
use core::result::Result;
|
use core::result::Result;
|
||||||
use std::getopts;
|
use std::getopts;
|
||||||
use std::cell::Cell;
|
|
||||||
|
|
||||||
/// The type of document to output
|
/// The type of document to output
|
||||||
pub enum OutputFormat {
|
pub enum OutputFormat {
|
||||||
|
|
|
@ -34,11 +34,11 @@ use sort_pass;
|
||||||
use trim_pass;
|
use trim_pass;
|
||||||
use unindent_pass;
|
use unindent_pass;
|
||||||
|
|
||||||
|
use core::cell::Cell;
|
||||||
use core::iter;
|
use core::iter;
|
||||||
use core::str;
|
use core::str;
|
||||||
use core::vec;
|
use core::vec;
|
||||||
use std::par;
|
use std::par;
|
||||||
use std::cell::Cell;
|
|
||||||
use syntax;
|
use syntax;
|
||||||
|
|
||||||
pub fn mk_pass(writer_factory: WriterFactory) -> Pass {
|
pub fn mk_pass(writer_factory: WriterFactory) -> Pass {
|
||||||
|
|
|
@ -20,8 +20,8 @@ use fold;
|
||||||
use pass::Pass;
|
use pass::Pass;
|
||||||
use util::NominalOp;
|
use util::NominalOp;
|
||||||
|
|
||||||
|
use core::cell::Cell;
|
||||||
use std::par;
|
use std::par;
|
||||||
use std::cell::Cell;
|
|
||||||
|
|
||||||
pub fn mk_pass(name: ~str, op: @fn(&str) -> ~str) -> Pass {
|
pub fn mk_pass(name: ~str, op: @fn(&str) -> ~str) -> Pass {
|
||||||
let op = Cell(op);
|
let op = Cell(op);
|
||||||
|
|
|
@ -54,7 +54,6 @@ pub mod uv_global_loop;
|
||||||
|
|
||||||
pub mod c_vec;
|
pub mod c_vec;
|
||||||
pub mod timer;
|
pub mod timer;
|
||||||
pub mod cell;
|
|
||||||
pub mod io_util;
|
pub mod io_util;
|
||||||
|
|
||||||
// Concurrency
|
// Concurrency
|
||||||
|
|
Loading…
Reference in New Issue