(index<- )        ./libstd/task/mod.rs

    1  // Copyright 2012-2013 The Rust Project Developers. See the COPYRIGHT
    2  // file at the top-level directory of this distribution and at
    3  // http://rust-lang.org/COPYRIGHT.
    4  //
    5  // Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
    6  // http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
    7  // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
    8  // option. This file may not be copied, modified, or distributed
    9  // except according to those terms.
   10  
   11  /*!
   12   * Task management.
   13   *
   14   * An executing Rust program consists of a tree of tasks, each with their own
   15   * stack, and sole ownership of their allocated heap data. Tasks communicate
   16   * with each other using ports and channels (see std::rt::comm for more info
   17   * about how communication works).
   18   *
   19   * Tasks can be spawned in 3 different modes.
   20   *
   21   *  * Bidirectionally linked: This is the default mode and it's what ```spawn``` does.
   22   *  Failures will be propagated from parent to child and vice versa.
   23   *
   24   *  * Unidirectionally linked (parent->child): This type of task can be created with
   25   *  ```spawn_supervised```. In this case, failures are propagated from parent to child
   26   *  but not the other way around.
   27   *
   28   *  * Unlinked: Tasks can be completely unlinked. These tasks can be created by using
   29   *  ```spawn_unlinked```. In this case failures are not propagated at all.
   30   *
   31   * Tasks' failure modes can be further configured. For instance, parent tasks can (un)watch
   32   * children failures. Please, refer to TaskBuilder's documentation bellow for more information.
   33   *
   34   * When a (bi|uni)directionally linked task fails, its failure will be propagated to all tasks
   35   * linked to it, this will cause such tasks to fail by a `linked failure`.
   36   *
   37   * Task Scheduling:
   38   *
   39   * By default, every task is created in the same scheduler as its parent, where it
   40   * is scheduled cooperatively with all other tasks in that scheduler. Some specialized
   41   * applications may want more control over their scheduling, in which case they can be
   42   * spawned into a new scheduler with the specific properties required. See TaskBuilder's
   43   * documentation bellow for more information.
   44   *
   45   * # Example
   46   *
   47   * ```
   48   * do spawn {
   49   *     log(error, "Hello, World!");
   50   * }
   51   * ```
   52   */
   53  
   54  #[allow(missing_doc)];
   55  
   56  use prelude::*;
   57  
   58  use cell::Cell;
   59  use comm::{stream, Chan, GenericChan, GenericPort, Port};
   60  use result::Result;
   61  use result;
   62  use rt::in_green_task_context;
   63  use rt::local::Local;
   64  use unstable::finally::Finally;
   65  use util;
   66  use send_str::{SendStr, IntoSendStr};
   67  
   68  #[cfg(test)] use cast;
   69  #[cfg(test)] use comm::SharedChan;
   70  #[cfg(test)] use comm;
   71  #[cfg(test)] use ptr;
   72  #[cfg(test)] use task;
   73  
   74  pub mod spawn;
   75  
   76  /**
   77   * Indicates the manner in which a task exited.
   78   *
   79   * A task that completes without failing is considered to exit successfully.
   80   * Supervised ancestors and linked siblings may yet fail after this task
   81   * succeeds. Also note that in such a case, it may be nondeterministic whether
   82   * linked failure or successful exit happen first.
   83   *
   84   * If you wish for this result's delivery to block until all linked and/or
   85   * children tasks complete, recommend using a result future.
   86   */
   87  #[deriving(Eq)]
   88  pub enum TaskResult {
   89      Success,
   90      Failure,
   91  }
   92  
   93  /// Scheduler modes
   94  #[deriving(Eq)]
   95  pub enum SchedMode {
   96      /// Run task on the default scheduler
   97      DefaultScheduler,
   98      /// All tasks run in the same OS thread
   99      SingleThreaded,
  100  }
  101  
  102  /**
  103   * Scheduler configuration options
  104   *
  105   * # Fields
  106   *
  107   * * sched_mode - The operating mode of the scheduler
  108   *
  109   */
  110  pub struct SchedOpts {
  111      mode: SchedMode,
  112  }
  113  
  114  /**
  115   * Task configuration options
  116   *
  117   * # Fields
  118   *
  119   * * linked - Propagate failure bidirectionally between child and parent.
  120   *            True by default. If both this and 'supervised' are false, then
  121   *            either task's failure will not affect the other ("unlinked").
  122   *
  123   * * supervised - Propagate failure unidirectionally from parent to child,
  124   *                but not from child to parent. False by default.
  125   *
  126   * * watched - Make parent task collect exit status notifications from child
  127   *             before reporting its own exit status. (This delays the parent
  128   *             task's death and cleanup until after all transitively watched
  129   *             children also exit.) True by default.
  130   *
  131   * * indestructible - Configures the task to ignore kill signals received from
  132   *                    linked failure. This may cause process hangs during
  133   *                    failure if not used carefully, but causes task blocking
  134   *                    code paths (e.g. port recv() calls) to be faster by 2
  135   *                    atomic operations. False by default.
  136   *
  137   * * notify_chan - Enable lifecycle notifications on the given channel
  138   *
  139   * * name - A name for the task-to-be, for identification in failure messages.
  140   *
  141   * * sched - Specify the configuration of a new scheduler to create the task
  142   *           in. This is of particular importance for libraries which want to call
  143   *           into foreign code that blocks. Without doing so in a different
  144   *           scheduler other tasks will be impeded or even blocked indefinitely.
  145   */
  146  pub struct TaskOpts {
  147      linked: bool,
  148      supervised: bool,
  149      watched: bool,
  150      indestructible: bool,
  151      notify_chan: Option<Chan<TaskResult>>,
  152      name: Option<SendStr>,
  153      sched: SchedOpts,
  154      stack_size: Option<uint>
  155  }
  156  
  157  /**
  158   * The task builder type.
  159   *
  160   * Provides detailed control over the properties and behavior of new tasks.
  161   */
  162  // NB: Builders are designed to be single-use because they do stateful
  163  // things that get weird when reusing - e.g. if you create a result future
  164  // it only applies to a single task, so then you have to maintain Some
  165  // potentially tricky state to ensure that everything behaves correctly
  166  // when you try to reuse the builder to spawn a new task. We'll just
  167  // sidestep that whole issue by making builders uncopyable and making
  168  // the run function move them in.
  169  
  170  // FIXME (#3724): Replace the 'consumed' bit with move mode on self
  171  pub struct TaskBuilder {
  172      opts: TaskOpts,
  173      gen_body: Option<~fn(v: ~fn()) -> ~fn()>,
  174      can_not_copy: Option<util::NonCopyable>,
  175      consumed: bool,
  176  }
  177  
  178  /**
  179   * Generate the base configuration for spawning a task, off of which more
  180   * configuration methods can be chained.
  181   * For example, task().unlinked().spawn is equivalent to spawn_unlinked.
  182   */
  183  pub fn task() -> TaskBuilder {
  184      TaskBuilder {
  185          opts: default_task_opts(),
  186          gen_body: None,
  187          can_not_copy: None,
  188          consumed: false,
  189      }
  190  }
  191  
  192  impl TaskBuilder {
  193      fn consume(&mut self) -> TaskBuilder {
  194          if self.consumed {
  195              fail2!("Cannot copy a task_builder"); // Fake move mode on self
  196          }
  197          self.consumed = true;
  198          let gen_body = self.gen_body.take();
  199          let notify_chan = self.opts.notify_chan.take();
  200          let name = self.opts.name.take();
  201          TaskBuilder {
  202              opts: TaskOpts {
  203                  linked: self.opts.linked,
  204                  supervised: self.opts.supervised,
  205                  watched: self.opts.watched,
  206                  indestructible: self.opts.indestructible,
  207                  notify_chan: notify_chan,
  208                  name: name,
  209                  sched: self.opts.sched,
  210                  stack_size: self.opts.stack_size
  211              },
  212              gen_body: gen_body,
  213              can_not_copy: None,
  214              consumed: false
  215          }
  216      }
  217  
  218      /// Decouple the child task's failure from the parent's. If either fails,
  219      /// the other will not be killed.
  220      pub fn unlinked(&mut self) {
  221          self.opts.linked = false;
  222          self.opts.watched = false;
  223      }
  224  
  225      /// Unidirectionally link the child task's failure with the parent's. The
  226      /// child's failure will not kill the parent, but the parent's will kill
  227      /// the child.
  228      pub fn supervised(&mut self) {
  229          self.opts.supervised = true;
  230          self.opts.linked = false;
  231          self.opts.watched = false;
  232      }
  233  
  234      /// Link the child task's and parent task's failures. If either fails, the
  235      /// other will be killed.
  236      pub fn linked(&mut self) {
  237          self.opts.linked = true;
  238          self.opts.supervised = false;
  239          self.opts.watched = true;
  240      }
  241  
  242      /// Cause the parent task to collect the child's exit status (and that of
  243      /// all transitively-watched grandchildren) before reporting its own.
  244      pub fn watched(&mut self) {
  245          self.opts.watched = true;
  246      }
  247  
  248      /// Allow the child task to outlive the parent task, at the possible cost
  249      /// of the parent reporting success even if the child task fails later.
  250      pub fn unwatched(&mut self) {
  251          self.opts.watched = false;
  252      }
  253  
  254      /// Cause the child task to ignore any kill signals received from linked
  255      /// failure. This optimizes context switching, at the possible expense of
  256      /// process hangs in the case of unexpected failure.
  257      pub fn indestructible(&mut self) {
  258          self.opts.indestructible = true;
  259      }
  260  
  261      /**
  262       * Get a future representing the exit status of the task.
  263       *
  264       * Taking the value of the future will block until the child task
  265       * terminates. The future-receiving callback specified will be called
  266       * *before* the task is spawned; as such, do not invoke .get() within the
  267       * closure; rather, store it in an outer variable/list for later use.
  268       *
  269       * Note that the future returning by this function is only useful for
  270       * obtaining the value of the next task to be spawning with the
  271       * builder. If additional tasks are spawned with the same builder
  272       * then a new result future must be obtained prior to spawning each
  273       * task.
  274       *
  275       * # Failure
  276       * Fails if a future_result was already set for this task.
  277       */
  278      pub fn future_result(&mut self, blk&fn(v: Port<TaskResult>)) {
  279          // FIXME (#3725): Once linked failure and notification are
  280          // handled in the library, I can imagine implementing this by just
  281          // registering an arbitrary number of task::on_exit handlers and
  282          // sending out messages.
  283  
  284          if self.opts.notify_chan.is_some() {
  285              fail2!("Can't set multiple future_results for one task!");
  286          }
  287  
  288          // Construct the future and give it to the caller.
  289          let (notify_pipe_po, notify_pipe_ch) = stream::<TaskResult>();
  290  
  291          blk(notify_pipe_po);
  292  
  293          // Reconfigure self to use a notify channel.
  294          self.opts.notify_chan = Some(notify_pipe_ch);
  295      }
  296  
  297      /// Name the task-to-be. Currently the name is used for identification
  298      /// only in failure messages.
  299      pub fn name<S: IntoSendStr>(&mut self, nameS) {
  300          self.opts.name = Some(name.into_send_str());
  301      }
  302  
  303      /// Configure a custom scheduler mode for the task.
  304      pub fn sched_mode(&mut self, modeSchedMode) {
  305          self.opts.sched.mode = mode;
  306      }
  307  
  308      /**
  309       * Add a wrapper to the body of the spawned task.
  310       *
  311       * Before the task is spawned it is passed through a 'body generator'
  312       * function that may perform local setup operations as well as wrap
  313       * the task body in remote setup operations. With this the behavior
  314       * of tasks can be extended in simple ways.
  315       *
  316       * This function augments the current body generator with a new body
  317       * generator by applying the task body which results from the
  318       * existing body generator to the new body generator.
  319       */
  320      pub fn add_wrapper(&mut self, wrapper~fn(v: ~fn()) -> ~fn()) {
  321          let prev_gen_body = self.gen_body.take();
  322          let prev_gen_body = match prev_gen_body {
  323              Some(gen) => gen,
  324              None => {
  325                  let f~fn(~fn()) -> ~fn() = |body| body;
  326                  f
  327              }
  328          };
  329          let prev_gen_body = Cell::new(prev_gen_body);
  330          let next_gen_body = {
  331              let f~fn(~fn()) -> ~fn() = |body| {
  332                  let prev_gen_body = prev_gen_body.take();
  333                  wrapper(prev_gen_body(body))
  334              };
  335              f
  336          };
  337          self.gen_body = Some(next_gen_body);
  338      }
  339  
  340      /**
  341       * Creates and executes a new child task
  342       *
  343       * Sets up a new task with its own call stack and schedules it to run
  344       * the provided unique closure. The task has the properties and behavior
  345       * specified by the task_builder.
  346       *
  347       * # Failure
  348       *
  349       * When spawning into a new scheduler, the number of threads requested
  350       * must be greater than zero.
  351       */
  352      pub fn spawn(&mut self, f~fn()) {
  353          let gen_body = self.gen_body.take();
  354          let notify_chan = self.opts.notify_chan.take();
  355          let name = self.opts.name.take();
  356          let x = self.consume();
  357          let opts = TaskOpts {
  358              linked: x.opts.linked,
  359              supervised: x.opts.supervised,
  360              watched: x.opts.watched,
  361              indestructible: x.opts.indestructible,
  362              notify_chan: notify_chan,
  363              name: name,
  364              sched: x.opts.sched,
  365              stack_size: x.opts.stack_size
  366          };
  367          let f = match gen_body {
  368              Some(gen) => {
  369                  gen(f)
  370              }
  371              None => {
  372                  f
  373              }
  374          };
  375          spawn::spawn_raw(opts, f);
  376      }
  377  
  378      /// Runs a task, while transferring ownership of one argument to the child.
  379      pub fn spawn_with<A:Send>(&mut self, argA, f~fn(v: A)) {
  380          let arg = Cell::new(arg);
  381          do self.spawn {
  382              f(arg.take());
  383          }
  384      }
  385  
  386      /**
  387       * Execute a function in another task and return either the return value
  388       * of the function or result::err.
  389       *
  390       * # Return value
  391       *
  392       * If the function executed successfully then try returns result::ok
  393       * containing the value returned by the function. If the function fails
  394       * then try returns result::err containing nil.
  395       *
  396       * # Failure
  397       * Fails if a future_result was already set for this task.
  398       */
  399      pub fn try<T:Send>(&mut self, f~fn() -> T) -> Result<T,()> {
  400          let (po, ch) = stream::<T>();
  401          let mut result = None;
  402  
  403          self.future_result(|r| { result = Some(r); });
  404  
  405          do self.spawn {
  406              ch.send(f());
  407          }
  408  
  409          match result.unwrap().recv() {
  410              Success => result::Ok(po.recv()),
  411              Failure => result::Err(())
  412          }
  413      }
  414  }
  415  
  416  
  417  /* Task construction */
  418  
  419  pub fn default_task_opts() -> TaskOpts {
  420      /*!
  421       * The default task options
  422       *
  423       * By default all tasks are supervised by their parent, are spawned
  424       * into the same scheduler, and do not post lifecycle notifications.
  425       */
  426  
  427      TaskOpts {
  428          linked: true,
  429          supervised: false,
  430          watched: true,
  431          indestructible: false,
  432          notify_chan: None,
  433          name: None,
  434          sched: SchedOpts {
  435              mode: DefaultScheduler,
  436          },
  437          stack_size: None
  438      }
  439  }
  440  
  441  /* Spawn convenience functions */
  442  
  443  /// Creates and executes a new child task
  444  ///
  445  /// Sets up a new task with its own call stack and schedules it to run
  446  /// the provided unique closure.
  447  ///
  448  /// This function is equivalent to `task().spawn(f)`.
  449  pub fn spawn(f~fn()) {
  450      let mut task = task();
  451      task.spawn(f)
  452  }
  453  
  454  /// Creates a child task unlinked from the current one. If either this
  455  /// task or the child task fails, the other will not be killed.
  456  pub fn spawn_unlinked(f~fn()) {
  457      let mut task = task();
  458      task.unlinked();
  459      task.spawn(f)
  460  }
  461  
  462  pub fn spawn_supervised(f~fn()) {
  463      /*!
  464       * Creates a child task supervised by the current one. If the child
  465       * task fails, the parent will not be killed, but if the parent fails,
  466       * the child will be killed.
  467       */
  468  
  469      let mut task = task();
  470      task.supervised();
  471      task.spawn(f)
  472  }
  473  
  474  /// Creates a child task that cannot be killed by linked failure. This causes
  475  /// its context-switch path to be faster by 2 atomic swap operations.
  476  /// (Note that this convenience wrapper still uses linked-failure, so the
  477  /// child's children will still be killable by the parent. For the fastest
  478  /// possible spawn mode, use task::task().unlinked().indestructible().spawn.)
  479  pub fn spawn_indestructible(f~fn()) {
  480      let mut task = task();
  481      task.indestructible();
  482      task.spawn(f)
  483  }
  484  
  485  pub fn spawn_with<A:Send>(argA, f~fn(v: A)) {
  486      /*!
  487       * Runs a task, while transferring ownership of one argument to the
  488       * child.
  489       *
  490       * This is useful for transferring ownership of noncopyables to
  491       * another task.
  492       *
  493       * This function is equivalent to `task().spawn_with(arg, f)`.
  494       */
  495  
  496      let mut task = task();
  497      task.spawn_with(arg, f)
  498  }
  499  
  500  pub fn spawn_sched(modeSchedMode, f~fn()) {
  501      /*!
  502       * Creates a new task on a new or existing scheduler
  503  
  504       * When there are no more tasks to execute the
  505       * scheduler terminates.
  506       *
  507       * # Failure
  508       *
  509       * In manual threads mode the number of threads requested must be
  510       * greater than zero.
  511       */
  512  
  513      let mut task = task();
  514      task.sched_mode(mode);
  515      task.spawn(f)
  516  }
  517  
  518  pub fn try<T:Send>(f~fn() -> T) -> Result<T,()> {
  519      /*!
  520       * Execute a function in another task and return either the return value
  521       * of the function or result::err.
  522       *
  523       * This is equivalent to task().supervised().try.
  524       */
  525  
  526      let mut task = task();
  527      task.supervised();
  528      task.try(f)
  529  }
  530  
  531  
  532  /* Lifecycle functions */
  533  
  534  /// Read the name of the current task.
  535  pub fn with_task_name<U>(blk&fn(Option<&str>) -> U) -> U {
  536      use rt::task::Task;
  537  
  538      if in_green_task_context() {
  539          do Local::borrow |task&mut Task{
  540              match task.name {
  541                  Some(ref name) => blk(Some(name.as_slice())),
  542                  None => blk(None)
  543              }
  544          }
  545      } else {
  546          fail2!("no task name exists in non-green task context")
  547      }
  548  }
  549  
  550  pub fn deschedule() {
  551      //! Yield control to the task scheduler
  552  
  553      use rt::local::Local;
  554      use rt::shouldnt_be_public::Scheduler;
  555  
  556      // FIXME(#7544): Optimize this, since we know we won't block.
  557      let sched~Scheduler = Local::take();
  558      sched.yield_now();
  559  }
  560  
  561  pub fn failing() -> bool {
  562      //! True if the running task has failed
  563  
  564      use rt::task::Task;
  565  
  566      do Local::borrow |local&mut Task{
  567          local.unwinder.unwinding
  568      }
  569  }
  570  
  571  /**
  572   * Temporarily make the task unkillable
  573   *
  574   * # Example
  575   *
  576   * ```
  577   * do task::unkillable {
  578   *     // detach / deschedule / destroy must all be called together
  579   *     rustrt::rust_port_detach(po);
  580   *     // This must not result in the current task being killed
  581   *     task::deschedule();
  582   *     rustrt::rust_port_destroy(po);
  583   * }
  584   * ```
  585   */
  586  pub fn unkillable<U>(f&fn() -> U) -> U {
  587      use rt::task::Task;
  588  
  589      unsafe {
  590          if in_green_task_context() {
  591              // The inhibits/allows might fail and need to borrow the task.
  592              let t*mut Task = Local::unsafe_borrow();
  593              do (|| {
  594                  (*t).death.inhibit_kill((*t).unwinder.unwinding);
  595                  f()
  596              }).finally {
  597                  (*t).death.allow_kill((*t).unwinder.unwinding);
  598              }
  599          } else {
  600              // FIXME(#3095): This should be an rtabort as soon as the scheduler
  601              // no longer uses a workqueue implemented with an Exclusive.
  602              f()
  603          }
  604      }
  605  }
  606  
  607  /**
  608   * Makes killable a task marked as unkillable. This
  609   * is meant to be used only nested in unkillable.
  610   *
  611   * # Example
  612   *
  613   * ```
  614   * do task::unkillable {
  615   *     do task::rekillable {
  616   *          // Task is killable
  617   *     }
  618   *    // Task is unkillable again
  619   * }
  620   */
  621  pub fn rekillable<U>(f&fn() -> U) -> U {
  622      use rt::task::Task;
  623  
  624      unsafe {
  625          if in_green_task_context() {
  626              let t*mut Task = Local::unsafe_borrow();
  627              do (|| {
  628                  (*t).death.allow_kill((*t).unwinder.unwinding);
  629                  f()
  630              }).finally {
  631                  (*t).death.inhibit_kill((*t).unwinder.unwinding);
  632              }
  633          } else {
  634              // FIXME(#3095): As in unkillable().
  635              f()
  636          }
  637      }
  638  }
  639  
  640  #[ignore(reason = "linked failure")]
  641  #[test]
  642  fn test_kill_unkillable_task() {
  643      use rt::test::*;
  644  
  645      // Attempt to test that when a kill signal is received at the start of an
  646      // unkillable section, 'unkillable' unwinds correctly. This is actually
  647      // quite a difficult race to expose, as the kill has to happen on a second
  648      // CPU, *after* the spawner is already switched-back-to (and passes the
  649      // killed check at the start of its timeslice). As far as I know, it's not
  650      // possible to make this race deterministic, or even more likely to happen.
  651      do run_in_newsched_task {
  652          do task::try {
  653              do task::spawn {
  654                  fail2!();
  655              }
  656              do task::unkillable { }
  657          };
  658      }
  659  }
  660  
  661  #[test]
  662  #[ignore(cfg(windows))]
  663  fn test_kill_rekillable_task() {
  664      use rt::test::*;
  665  
  666      // Tests that when a kill signal is received, 'rekillable' and
  667      // 'unkillable' unwind correctly in conjunction with each other.
  668      do run_in_newsched_task {
  669          do task::try {
  670              do task::unkillable {
  671                  do task::rekillable {
  672                      do task::spawn {
  673                          fail2!();
  674                      }
  675                  }
  676              }
  677          };
  678      }
  679  }
  680  
  681  #[test]
  682  #[should_fail]
  683  #[ignore(cfg(windows))]
  684  fn test_rekillable_not_nested() {
  685      do rekillable {
  686          // This should fail before
  687          // receiving anything since
  688          // this block should be nested
  689          // into a unkillable block.
  690          deschedule();
  691      }
  692  }
  693  
  694  
  695  #[test]
  696  #[ignore(cfg(windows))]
  697  fn test_rekillable_nested_failure() {
  698  
  699      let result = do task::try {
  700          do unkillable {
  701              do rekillable {
  702                  let (port,chan) = comm::stream();
  703                  do task::spawn { chan.send(()); fail2!(); }
  704                  port.recv(); // wait for child to exist
  705                  port.recv(); // block forever, expect to get killed.
  706              }
  707          }
  708      };
  709      assert!(result.is_err());
  710  }
  711  
  712  
  713  #[test] #[should_fail] #[ignore(cfg(windows))]
  714  fn test_cant_dup_task_builder() {
  715      let mut builder = task();
  716      builder.unlinked();
  717      do builder.spawn {}
  718      // FIXME(#3724): For now, this is a -runtime- failure, because we haven't
  719      // got move mode on self. When 3724 is fixed, this test should fail to
  720      // compile instead, and should go in tests/compile-fail.
  721      do builder.spawn {} // b should have been consumed by the previous call
  722  }
  723  
  724  // The following 8 tests test the following 2^3 combinations:
  725  // {un,}linked {un,}supervised failure propagation {up,down}wards.
  726  
  727  // !!! These tests are dangerous. If Something is buggy, they will hang, !!!
  728  // !!! instead of exiting cleanly. This might wedge the buildbots.       !!!
  729  
  730  #[cfg(test)]
  731  fn block_forever() { let (po, _ch) = stream::<()>(); po.recv(); }
  732  
  733  #[ignore(reason = "linked failure")]
  734  #[test]
  735  fn test_spawn_unlinked_unsup_no_fail_down() { // grandchild sends on a port
  736      use rt::test::run_in_newsched_task;
  737      do run_in_newsched_task {
  738          let (po, ch) = stream();
  739          let ch = SharedChan::new(ch);
  740          do spawn_unlinked {
  741              let ch = ch.clone();
  742              do spawn_unlinked {
  743                  // Give middle task a chance to fail-but-not-kill-us.
  744                  do 16.times { task::deschedule(); }
  745                  ch.send(()); // If killed first, grandparent hangs.
  746              }
  747              fail2!(); // Shouldn't kill either (grand)parent or (grand)child.
  748          }
  749          po.recv();
  750      }
  751  }
  752  #[ignore(reason = "linked failure")]
  753  #[test]
  754  fn test_spawn_unlinked_unsup_no_fail_up() { // child unlinked fails
  755      use rt::test::run_in_newsched_task;
  756      do run_in_newsched_task {
  757          do spawn_unlinked { fail2!(); }
  758      }
  759  }
  760  #[ignore(reason = "linked failure")]
  761  #[test]
  762  fn test_spawn_unlinked_sup_no_fail_up() { // child unlinked fails
  763      use rt::test::run_in_newsched_task;
  764      do run_in_newsched_task {
  765          do spawn_supervised { fail2!(); }
  766          // Give child a chance to fail-but-not-kill-us.
  767          do 16.times { task::deschedule(); }
  768      }
  769  }
  770  #[ignore(reason = "linked failure")]
  771  #[test]
  772  fn test_spawn_unlinked_sup_fail_down() {
  773      use rt::test::run_in_newsched_task;
  774      do run_in_newsched_task {
  775          let result: Result<(),()> = do try {
  776              do spawn_supervised { block_forever(); }
  777              fail2!(); // Shouldn't leave a child hanging around.
  778          };
  779          assert!(result.is_err());
  780      }
  781  }
  782  
  783  #[ignore(reason = "linked failure")]
  784  #[test]
  785  fn test_spawn_linked_sup_fail_up() { // child fails; parent fails
  786      use rt::test::run_in_newsched_task;
  787      do run_in_newsched_task {
  788          let result: Result<(),()> = do try {
  789              // Unidirectional "parenting" shouldn't override bidirectional linked.
  790              // We have to cheat with opts - the interface doesn't support them because
  791              // they don't make sense (redundant with task().supervised()).
  792              let mut b0 = task();
  793              b0.opts.linked = true;
  794              b0.opts.supervised = true;
  795  
  796              do b0.spawn {
  797                  fail2!();
  798              }
  799              block_forever(); // We should get punted awake
  800          };
  801          assert!(result.is_err());
  802      }
  803  }
  804  #[ignore(reason = "linked failure")]
  805  #[test]
  806  fn test_spawn_linked_sup_fail_down() { // parent fails; child fails
  807      use rt::test::run_in_newsched_task;
  808      do run_in_newsched_task {
  809          let result: Result<(),()> = do try {
  810              // We have to cheat with opts - the interface doesn't support them because
  811              // they don't make sense (redundant with task().supervised()).
  812              let mut b0 = task();
  813              b0.opts.linked = true;
  814              b0.opts.supervised = true;
  815              do b0.spawn { block_forever(); }
  816              fail2!(); // *both* mechanisms would be wrong if this didn't kill the child
  817          };
  818          assert!(result.is_err());
  819      }
  820  }
  821  #[ignore(reason = "linked failure")]
  822  #[test]
  823  fn test_spawn_linked_unsup_fail_up() { // child fails; parent fails
  824      use rt::test::run_in_newsched_task;
  825      do run_in_newsched_task {
  826          let result: Result<(),()> = do try {
  827              // Default options are to spawn linked & unsupervised.
  828              do spawn { fail2!(); }
  829              block_forever(); // We should get punted awake
  830          };
  831          assert!(result.is_err());
  832      }
  833  }
  834  #[ignore(reason = "linked failure")]
  835  #[test]
  836  fn test_spawn_linked_unsup_fail_down() { // parent fails; child fails
  837      use rt::test::run_in_newsched_task;
  838      do run_in_newsched_task {
  839          let result: Result<(),()> = do try {
  840              // Default options are to spawn linked & unsupervised.
  841              do spawn { block_forever(); }
  842              fail2!();
  843          };
  844          assert!(result.is_err());
  845      }
  846  }
  847  #[ignore(reason = "linked failure")]
  848  #[test]
  849  fn test_spawn_linked_unsup_default_opts() { // parent fails; child fails
  850      use rt::test::run_in_newsched_task;
  851      do run_in_newsched_task {
  852          let result: Result<(),()> = do try {
  853              // Make sure the above test is the same as this one.
  854              let mut builder = task();
  855              builder.linked();
  856              do builder.spawn { block_forever(); }
  857              fail2!();
  858          };
  859          assert!(result.is_err());
  860      }
  861  }
  862  
  863  // A couple bonus linked failure tests - testing for failure propagation even
  864  // when the middle task exits successfully early before kill signals are sent.
  865  
  866  #[ignore(reason = "linked failure")]
  867  #[test]
  868  fn test_spawn_failure_propagate_grandchild() {
  869      use rt::test::run_in_newsched_task;
  870      do run_in_newsched_task {
  871          let result: Result<(),()> = do try {
  872              // Middle task exits; does grandparent's failure propagate across the gap?
  873              do spawn_supervised {
  874                  do spawn_supervised { block_forever(); }
  875              }
  876              do 16.times { task::deschedule(); }
  877              fail2!();
  878          };
  879          assert!(result.is_err());
  880      }
  881  }
  882  
  883  #[ignore(reason = "linked failure")]
  884  #[test]
  885  fn test_spawn_failure_propagate_secondborn() {
  886      use rt::test::run_in_newsched_task;
  887      do run_in_newsched_task {
  888          let result: Result<(),()> = do try {
  889              // First-born child exits; does parent's failure propagate to sibling?
  890              do spawn_supervised {
  891                  do spawn { block_forever(); } // linked
  892              }
  893              do 16.times { task::deschedule(); }
  894              fail2!();
  895          };
  896          assert!(result.is_err());
  897      }
  898  }
  899  
  900  #[ignore(reason = "linked failure")]
  901  #[test]
  902  fn test_spawn_failure_propagate_nephew_or_niece() {
  903      use rt::test::run_in_newsched_task;
  904      do run_in_newsched_task {
  905          let result: Result<(),()> = do try {
  906              // Our sibling exits; does our failure propagate to sibling's child?
  907              do spawn { // linked
  908                  do spawn_supervised { block_forever(); }
  909              }
  910              do 16.times { task::deschedule(); }
  911              fail2!();
  912          };
  913          assert!(result.is_err());
  914      }
  915  }
  916  
  917  #[ignore(reason = "linked failure")]
  918  #[test]
  919  fn test_spawn_linked_sup_propagate_sibling() {
  920      use rt::test::run_in_newsched_task;
  921      do run_in_newsched_task {
  922          let result: Result<(),()> = do try {
  923              // Middle sibling exits - does eldest's failure propagate to youngest?
  924              do spawn { // linked
  925                  do spawn { block_forever(); } // linked
  926              }
  927              do 16.times { task::deschedule(); }
  928              fail2!();
  929          };
  930          assert!(result.is_err());
  931      }
  932  }
  933  
  934  #[test]
  935  fn test_unnamed_task() {
  936      use rt::test::run_in_newsched_task;
  937  
  938      do run_in_newsched_task {
  939          do spawn {
  940              do with_task_name |name| {
  941                  assert!(name.is_none());
  942              }
  943          }
  944      }
  945  }
  946  
  947  #[test]
  948  fn test_owned_named_task() {
  949      use rt::test::run_in_newsched_task;
  950  
  951      do run_in_newsched_task {
  952          let mut t = task();
  953          t.name(~"ada lovelace");
  954          do t.spawn {
  955              do with_task_name |name| {
  956                  assert!(name.unwrap() == "ada lovelace");
  957              }
  958          }
  959      }
  960  }
  961  
  962  #[test]
  963  fn test_static_named_task() {
  964      use rt::test::run_in_newsched_task;
  965  
  966      do run_in_newsched_task {
  967          let mut t = task();
  968          t.name("ada lovelace");
  969          do t.spawn {
  970              do with_task_name |name| {
  971                  assert!(name.unwrap() == "ada lovelace");
  972              }
  973          }
  974      }
  975  }
  976  
  977  #[test]
  978  fn test_send_named_task() {
  979      use rt::test::run_in_newsched_task;
  980  
  981      do run_in_newsched_task {
  982          let mut t = task();
  983          t.name("ada lovelace".into_send_str());
  984          do t.spawn {
  985              do with_task_name |name| {
  986                  assert!(name.unwrap() == "ada lovelace");
  987              }
  988          }
  989      }
  990  }
  991  
  992  #[test]
  993  fn test_run_basic() {
  994      let (po, ch) = stream::<()>();
  995      let mut builder = task();
  996      do builder.spawn {
  997          ch.send(());
  998      }
  999      po.recv();
 1000  }
 1001  
 1002  #[cfg(test)]
 1003  struct Wrapper {
 1004      f: Option<Chan<()>>
 1005  }
 1006  
 1007  #[test]
 1008  fn test_add_wrapper() {
 1009      let (po, ch) = stream::<()>();
 1010      let mut b0 = task();
 1011      let ch = Cell::new(ch);
 1012      do b0.add_wrapper |body| {
 1013          let ch = Cell::new(ch.take());
 1014          let result: ~fn() = || {
 1015              let ch = ch.take();
 1016              body();
 1017              ch.send(());
 1018          };
 1019          result
 1020      };
 1021      do b0.spawn { }
 1022      po.recv();
 1023  }
 1024  
 1025  #[test]
 1026  fn test_future_result() {
 1027      let mut result = None;
 1028      let mut builder = task();
 1029      builder.future_result(|r| result = Some(r));
 1030      do builder.spawn {}
 1031      assert_eq!(result.unwrap().recv(), Success);
 1032  
 1033      result = None;
 1034      let mut builder = task();
 1035      builder.future_result(|r| result = Some(r));
 1036      builder.unlinked();
 1037      do builder.spawn {
 1038          fail2!();
 1039      }
 1040      assert_eq!(result.unwrap().recv(), Failure);
 1041  }
 1042  
 1043  #[test] #[should_fail]
 1044  fn test_back_to_the_future_result() {
 1045      let mut builder = task();
 1046      builder.future_result(util::ignore);
 1047      builder.future_result(util::ignore);
 1048  }
 1049  
 1050  #[test]
 1051  fn test_try_success() {
 1052      match do try {
 1053          ~"Success!"
 1054      } {
 1055          result::Ok(~"Success!") => (),
 1056          _ => fail2!()
 1057      }
 1058  }
 1059  
 1060  #[test]
 1061  fn test_try_fail() {
 1062      match do try {
 1063          fail2!()
 1064      } {
 1065          result::Err(()) => (),
 1066          result::Ok(()) => fail2!()
 1067      }
 1068  }
 1069  
 1070  #[cfg(test)]
 1071  fn get_sched_id() -> int {
 1072      do Local::borrow |sched: &mut ::rt::shouldnt_be_public::Scheduler| {
 1073          sched.sched_id() as int
 1074      }
 1075  }
 1076  
 1077  #[test]
 1078  fn test_spawn_sched() {
 1079      let (po, ch) = stream::<()>();
 1080      let ch = SharedChan::new(ch);
 1081  
 1082      fn f(i: int, ch: SharedChan<()>) {
 1083          let parent_sched_id = get_sched_id();
 1084  
 1085          do spawn_sched(SingleThreaded) {
 1086              let child_sched_id = get_sched_id();
 1087              assert!(parent_sched_id != child_sched_id);
 1088  
 1089              if (i == 0) {
 1090                  ch.send(());
 1091              } else {
 1092                  f(i - 1, ch.clone());
 1093              }
 1094          };
 1095  
 1096      }
 1097      f(10, ch);
 1098      po.recv();
 1099  }
 1100  
 1101  #[test]
 1102  fn test_spawn_sched_childs_on_default_sched() {
 1103      let (po, ch) = stream();
 1104  
 1105      // Assuming tests run on the default scheduler
 1106      let default_id = get_sched_id();
 1107  
 1108      let ch = Cell::new(ch);
 1109      do spawn_sched(SingleThreaded) {
 1110          let parent_sched_id = get_sched_id();
 1111          let ch = Cell::new(ch.take());
 1112          do spawn {
 1113              let ch = ch.take();
 1114              let child_sched_id = get_sched_id();
 1115              assert!(parent_sched_id != child_sched_id);
 1116              assert_eq!(child_sched_id, default_id);
 1117              ch.send(());
 1118          };
 1119      };
 1120  
 1121      po.recv();
 1122  }
 1123  
 1124  #[cfg(test)]
 1125  mod testrt {
 1126      use libc;
 1127  
 1128      externfn!(fn rust_dbg_lock_create() -> *libc::c_void)
 1129      externfn!(fn rust_dbg_lock_destroy(lock: *libc::c_void))
 1130      externfn!(fn rust_dbg_lock_lock(lock: *libc::c_void))
 1131      externfn!(fn rust_dbg_lock_unlock(lock: *libc::c_void))
 1132      externfn!(fn rust_dbg_lock_wait(lock: *libc::c_void))
 1133      externfn!(fn rust_dbg_lock_signal(lock: *libc::c_void))
 1134  }
 1135  
 1136  #[test]
 1137  fn test_spawn_sched_blocking() {
 1138      unsafe {
 1139  
 1140          // Testing that a task in one scheduler can block in foreign code
 1141          // without affecting other schedulers
 1142          do 20u.times {
 1143              let (start_po, start_ch) = stream();
 1144              let (fin_po, fin_ch) = stream();
 1145  
 1146              let lock = testrt::rust_dbg_lock_create();
 1147  
 1148              do spawn_sched(SingleThreaded) {
 1149                  testrt::rust_dbg_lock_lock(lock);
 1150  
 1151                  start_ch.send(());
 1152  
 1153                  // Block the scheduler thread
 1154                  testrt::rust_dbg_lock_wait(lock);
 1155                  testrt::rust_dbg_lock_unlock(lock);
 1156  
 1157                  fin_ch.send(());
 1158              };
 1159  
 1160              // Wait until the other task has its lock
 1161              start_po.recv();
 1162  
 1163              fn pingpong(po: &Port<int>, ch: &Chan<int>) {
 1164                  let mut val = 20;
 1165                  while val > 0 {
 1166                      val = po.recv();
 1167                      ch.send(val - 1);
 1168                  }
 1169              }
 1170  
 1171              let (setup_po, setup_ch) = stream();
 1172              let (parent_po, parent_ch) = stream();
 1173              do spawn {
 1174                  let (child_po, child_ch) = stream();
 1175                  setup_ch.send(child_ch);
 1176                  pingpong(&child_po, &parent_ch);
 1177              };
 1178  
 1179              let child_ch = setup_po.recv();
 1180              child_ch.send(20);
 1181              pingpong(&parent_po, &child_ch);
 1182              testrt::rust_dbg_lock_lock(lock);
 1183              testrt::rust_dbg_lock_signal(lock);
 1184              testrt::rust_dbg_lock_unlock(lock);
 1185              fin_po.recv();
 1186              testrt::rust_dbg_lock_destroy(lock);
 1187          }
 1188      }
 1189  }
 1190  
 1191  #[cfg(test)]
 1192  fn avoid_copying_the_body(spawnfn: &fn(v: ~fn())) {
 1193      let (p, ch) = stream::<uint>();
 1194  
 1195      let x = ~1;
 1196      let x_in_parent = ptr::to_unsafe_ptr(&*x) as uint;
 1197  
 1198      do spawnfn || {
 1199          let x_in_child = ptr::to_unsafe_ptr(&*x) as uint;
 1200          ch.send(x_in_child);
 1201      }
 1202  
 1203      let x_in_child = p.recv();
 1204      assert_eq!(x_in_parent, x_in_child);
 1205  }
 1206  
 1207  #[test]
 1208  fn test_avoid_copying_the_body_spawn() {
 1209      avoid_copying_the_body(spawn);
 1210  }
 1211  
 1212  #[test]
 1213  fn test_avoid_copying_the_body_task_spawn() {
 1214      do avoid_copying_the_body |f| {
 1215          let mut builder = task();
 1216          do builder.spawn || {
 1217              f();
 1218          }
 1219      }
 1220  }
 1221  
 1222  #[test]
 1223  fn test_avoid_copying_the_body_try() {
 1224      do avoid_copying_the_body |f| {
 1225          do try || {
 1226              f()
 1227          };
 1228      }
 1229  }
 1230  
 1231  #[test]
 1232  fn test_avoid_copying_the_body_unlinked() {
 1233      do avoid_copying_the_body |f| {
 1234          do spawn_unlinked || {
 1235              f();
 1236          }
 1237      }
 1238  }
 1239  
 1240  #[ignore(reason = "linked failure")]
 1241  #[test]
 1242  #[should_fail]
 1243  fn test_unkillable() {
 1244      let (po, ch) = stream();
 1245  
 1246      // We want to do this after failing
 1247      do spawn_unlinked {
 1248          do 10.times { deschedule() }
 1249          ch.send(());
 1250      }
 1251  
 1252      do spawn {
 1253          deschedule();
 1254          // We want to fail after the unkillable task
 1255          // blocks on recv
 1256          fail2!();
 1257      }
 1258  
 1259      unsafe {
 1260          do unkillable {
 1261              let p = ~0;
 1262              let pp: *uint = cast::transmute(p);
 1263  
 1264              // If we are killed here then the box will leak
 1265              po.recv();
 1266  
 1267              let _p: ~int = cast::transmute(pp);
 1268          }
 1269      }
 1270  
 1271      // Now we can be killed
 1272      po.recv();
 1273  }
 1274  
 1275  #[ignore(reason = "linked failure")]
 1276  #[test]
 1277  #[should_fail]
 1278  fn test_unkillable_nested() {
 1279      let (po, ch) = comm::stream();
 1280  
 1281      // We want to do this after failing
 1282      do spawn_unlinked || {
 1283          do 10.times { deschedule() }
 1284          ch.send(());
 1285      }
 1286  
 1287      do spawn {
 1288          deschedule();
 1289          // We want to fail after the unkillable task
 1290          // blocks on recv
 1291          fail2!();
 1292      }
 1293  
 1294      unsafe {
 1295          do unkillable {
 1296              do unkillable {} // Here's the difference from the previous test.
 1297              let p = ~0;
 1298              let pp: *uint = cast::transmute(p);
 1299  
 1300              // If we are killed here then the box will leak
 1301              po.recv();
 1302  
 1303              let _p: ~int = cast::transmute(pp);
 1304          }
 1305      }
 1306  
 1307      // Now we can be killed
 1308      po.recv();
 1309  }
 1310  
 1311  #[test]
 1312  fn test_child_doesnt_ref_parent() {
 1313      // If the child refcounts the parent task, this will stack overflow when
 1314      // climbing the task tree to dereference each ancestor. (See #1789)
 1315      // (well, it would if the constant were 8000+ - I lowered it to be more
 1316      // valgrind-friendly. try this at home, instead..!)
 1317      static generations: uint = 16;
 1318      fn child_no(x: uint) -> ~fn() {
 1319          return || {
 1320              if x < generations {
 1321                  let mut t = task();
 1322                  t.unwatched();
 1323                  t.spawn(child_no(x+1));
 1324              }
 1325          }
 1326      }
 1327      let mut t = task();
 1328      t.unwatched();
 1329      t.spawn(child_no(0));
 1330  }
 1331  
 1332  #[test]
 1333  fn test_simple_newsched_spawn() {
 1334      use rt::test::run_in_newsched_task;
 1335  
 1336      do run_in_newsched_task {
 1337          spawn(||())
 1338      }
 1339  }
 1340  
 1341  #[ignore(reason = "linked failure")]
 1342  #[test]
 1343  fn test_spawn_watched() {
 1344      use rt::test::run_in_newsched_task;
 1345      do run_in_newsched_task {
 1346          let result = do try {
 1347              let mut t = task();
 1348              t.unlinked();
 1349              t.watched();
 1350              do t.spawn {
 1351                  let mut t = task();
 1352                  t.unlinked();
 1353                  t.watched();
 1354                  do t.spawn {
 1355                      task::deschedule();
 1356                      fail2!();
 1357                  }
 1358              }
 1359          };
 1360          assert!(result.is_err());
 1361      }
 1362  }
 1363  
 1364  #[ignore(reason = "linked failure")]
 1365  #[test]
 1366  fn test_indestructible() {
 1367      use rt::test::run_in_newsched_task;
 1368      do run_in_newsched_task {
 1369          let result = do try {
 1370              let mut t = task();
 1371              t.watched();
 1372              t.supervised();
 1373              t.indestructible();
 1374              do t.spawn {
 1375                  let (p1, _c1) = stream::<()>();
 1376                  let (p2, c2) = stream::<()>();
 1377                  let (p3, c3) = stream::<()>();
 1378                  let mut t = task();
 1379                  t.unwatched();
 1380                  do t.spawn {
 1381                      do (|| {
 1382                          p1.recv(); // would deadlock if not killed
 1383                      }).finally {
 1384                          c2.send(());
 1385                      };
 1386                  }
 1387                  let mut t = task();
 1388                  t.unwatched();
 1389                  do t.spawn {
 1390                      p3.recv();
 1391                      task::deschedule();
 1392                      fail2!();
 1393                  }
 1394                  c3.send(());
 1395                  p2.recv();
 1396              }
 1397          };
 1398          assert!(result.is_ok());
 1399      }
 1400  }

libstd/task/mod.rs:585:4-585:4 -fn- definition:
 */
pub fn unkillable<U>(f: &fn() -> U) -> U {
references:-
libstd/task/spawn.rs:
585:                 do unkillable { f() }
libstd/select.rs:
84:         do task::unkillable { p.take().recv(); }
libstd/unstable/sync.rs:
243:                         do task::unkillable {
118:         do task::unkillable {
libstd/rt/uv/uvio.rs:
622:         do task::unkillable { // FIXME(#8674)
504:                 do task::unkillable { // FIXME(#8674)
710:         do task::unkillable { // FIXME(#8674)
93:         do task::unkillable { // FIXME(#8674)
456:         do task::unkillable { // FIXME(#8674)
67:         do task::unkillable { // FIXME(#8674)
578:         do task::unkillable { // FIXME(#8674)
126:         let a = do task::unkillable { // FIXME(#8674)
527:                 do task::unkillable { // FIXME(#8674)
664:         do task::unkillable { // FIXME(#8674)
424:     do task::unkillable { // FIXME(#8674)


libstd/task/mod.rs:418:1-418:1 -fn- definition:

pub fn default_task_opts() -> TaskOpts {
references:-
185:         opts: default_task_opts(),


libstd/task/mod.rs:109:4-109:4 -struct- definition:
 */
pub struct SchedOpts {
references:-
434:         sched: SchedOpts {
153:     sched: SchedOpts,


libstd/task/mod.rs:182:4-182:4 -fn- definition:
 */
pub fn task() -> TaskBuilder {
references:-
526:     let mut task = task();
450:     let mut task = task();
513:     let mut task = task();
469:     let mut task = task();
480:     let mut task = task();
496:     let mut task = task();
457:     let mut task = task();


libstd/task/mod.rs:94:16-94:16 -enum- definition:
#[deriving(Eq)]
pub enum SchedMode {
references:-
94: #[deriving(Eq)]
111:     mode: SchedMode,
94: #[deriving(Eq)]
304:     pub fn sched_mode(&mut self, mode: SchedMode) {
94: #[deriving(Eq)]
500: pub fn spawn_sched(mode: SchedMode, f: ~fn()) {


libstd/task/mod.rs:170:68-170:68 -struct- definition:
// FIXME (#3724): Replace the 'consumed' bit with move mode on self
pub struct TaskBuilder {
references:-
183: pub fn task() -> TaskBuilder {
201:         TaskBuilder {
192: impl TaskBuilder {
193:     fn consume(&mut self) -> TaskBuilder {
184:     TaskBuilder {


libstd/task/mod.rs:87:16-87:16 -enum- definition:
#[deriving(Eq)]
pub enum TaskResult {
references:-
87: #[deriving(Eq)]
87: #[deriving(Eq)]
151:     notify_chan: Option<Chan<TaskResult>>,
87: #[deriving(Eq)]
278:     pub fn future_result(&mut self, blk: &fn(v: Port<TaskResult>)) {
289:         let (notify_pipe_po, notify_pipe_ch) = stream::<TaskResult>();
libstd/task/spawn.rs:
367:     notify_chan: Chan<TaskResult>,
378: fn AutoNotify(chan: Chan<TaskResult>) -> AutoNotify {


libstd/task/mod.rs:145:4-145:4 -struct- definition:
 */
pub struct TaskOpts {
references:-
419: pub fn default_task_opts() -> TaskOpts {
172:     opts: TaskOpts,
357:         let opts = TaskOpts {
427:     TaskOpts {
202:             opts: TaskOpts {
libstd/task/spawn.rs:
555: pub fn spawn_raw(mut opts: TaskOpts, f: ~fn()) {


libstd/task/mod.rs:499:1-499:1 -fn- definition:

pub fn spawn_sched(mode: SchedMode, f: ~fn()) {
references:-
libstd/run.rs:
219:         do task::spawn_sched(task::SingleThreaded) {
213:         do task::spawn_sched(task::SingleThreaded) {
libstd/unstable/mod.rs:
47:     do task::spawn_sched(task::SingleThreaded) {


libstd/task/mod.rs:620:4-620:4 -fn- definition:
 */
pub fn rekillable<U>(f: &fn() -> U) -> U {
references:-
libstd/unstable/sync.rs:
149:                             do task::rekillable { p1.take().recv(); }


libstd/task/mod.rs:560:1-560:1 -fn- definition:

pub fn failing() -> bool {
references:-
libstd/unstable/sync.rs:
159:                             if task::failing() {