Skip to content
This repository
branch: master
Fetching contributors…

Cannot retrieve contributors at this time

file 147 lines (108 sloc) 3.206 kb
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147
#pragma once

#include "uv.h"

#include "Common.h"
#include "Data/Array.h"

namespace magpie
{
  // suspend stuff:
  class ChannelObject;

  class BufferObject;
  class Fiber;
  class FileObject;
  class FunctionObject;
  class Module;
  class Object;

  // Wraps a Fiber that is waiting for an asynchronous event to complete. This
  // is a manually memory managed doubly linked list.
  class Task
  {
    friend class TaskList;

  public:
    virtual ~Task() {}

    gc<Fiber> fiber() { return fiber_; }

    // Gets the main libuv loop this task will run on.
    uv_loop_t* loop();

    virtual void kill() = 0;

    // Completes the task. Removes it from the list of pending tasks and runs
    // the fiber (and any other fibers that are able to be run).
    //
    // This object will be freed at the end of this call. You cannot use it
    // after this returns!
    void complete(gc<Object> returnValue);

    virtual void reach();

  protected:
    // Creates a new task. Note that instantiating a task implicitly adds it
    // to the scheduler's task list.
    Task(gc<Fiber> fiber);

  private:
    gc<Fiber> fiber_;

    Task* prev_;
    Task* next_;
  };

  // A task using a uv_handle_t.
  class HandleTask : public Task
  {
  public:
    HandleTask(gc<Fiber> fiber, uv_handle_t* handle);
    ~HandleTask();
    virtual void kill();

  private:
    uv_handle_t* handle_;
  };

  // A list of pending asynchronous tasks.
  class TaskList
  {
  public:
    TaskList()
    : head_(NULL),
      tail_(NULL)
    {}

    void add(Task* task);

    // Removes [waiting] from this list. Does not free it.
    void remove(Task* task);

    // Cancel all waiting fibers so that the event loop can exit.
    void killAll();

    // Reach all of the waiting fibers so they don't get collected.
    void reach();

  private:
    Task* head_;
    Task* tail_;
  };

  // The Fiber scheduler.
  class Scheduler
  {
    friend class Task;

  public:
    Scheduler(VM& vm);

    uv_loop_t* loop() { return loop_; }

    uv_tty_t* tty() { return &tty_; }

    void run(Array<Module*> modules);

    // TODO(bob): Get this working with libuv!
    gc<Object> runModule(Module* module);

    // Resumes fiber and continues to run resumable fibers until either the
    // main fiber has ended or all fibers are waiting for events.
    gc<Object> run(gc<Fiber> fiber);

    // Spawns a new Fiber to run the given procedure but does not immediately
    // start it.
    void spawn(gc<FunctionObject> function);

    // Spawns a new Fiber to run the given procedure and immediately runs it.
    // This should only be called from libuv callbacks and not from code already
    // within the main scheduler run loop to prevent re-entrancy.
    void run(gc<FunctionObject> function);

    void add(gc<Fiber> fiber);

    void sleep(gc<Fiber> fiber, int ms);
    void reach();

  private:
    void add(Task* task);

    void waitForOSEvents();
    gc<Fiber> getNext();

    VM& vm_;
    uv_loop_t *loop_;
    uv_tty_t tty_;

    // Fibers that are not blocked and can run now.
    Array<gc<Fiber> > ready_;

    // Fibers that are waiting on an OS event to complete.
    TaskList tasks_;

    NO_COPY(Scheduler);
  };
}
Something went wrong with that request. Please try again.