Permalink
Browse files

Greatly improved memory management

There were a lot of problems with garbage collection before,
particularly with infinite loop generators. The problem is that the
handle to the fiber was always held in a deadlock, since we pass it as
the `this` context to the Fiber entry. So now `yield()` is a global,
to avoid this problem.

Additionally we are now giving v8 proper hints for externally-allocated
memory, so it can handle garbage collection better. Also the coroutine
library can free finished coroutines correctly now.

Incidentally, node-fibers doesn't use any node-specific API's anymore;
if you change the node.h include to be v8.h, it will still compile and
run just fine.
  • Loading branch information...
laverdet committed Jan 17, 2011
1 parent b194567 commit 6a77a260d62e07a2247c4c5e5da7bc687da1a4a6
Showing with 206 additions and 84 deletions.
  1. +20 −9 coroutine.cc
  2. +18 −21 coroutine.h
  3. +168 −54 node-fibers.cc
View
@@ -69,18 +69,18 @@ class Thread {
size_t fiber_ids;
stack<size_t> freed_fiber_ids;
vector<vector<const void*> > fls_data;
-
static vector<pthread_dtor_t> dtors;
public:
pthread_t handle;
Coroutine* current_fiber;
+ Coroutine* delete_me;
static void free(void* that) {
delete static_cast<Thread*>(that);
}
- Thread() : fiber_ids(1), fls_data(1), handle(NULL) {
+ Thread() : fiber_ids(1), fls_data(1), handle(NULL), delete_me(NULL) {
current_fiber = new Coroutine(*this, 0);
}
@@ -89,7 +89,9 @@ class Thread {
}
void fiber_did_finish(Coroutine& fiber) {
- // delete ???
+ freed_fiber_ids.push(fiber.id);
+ assert(delete_me == NULL);
+ delete_me = &fiber;
}
Coroutine& new_fiber(Coroutine::entry_t& entry, void* arg) {
@@ -106,17 +108,17 @@ class Thread {
}
void* get_specific(pthread_key_t key) {
- if (fls_data[current_fiber->getid()].size() <= key) {
+ if (fls_data[current_fiber->id].size() <= key) {
return NULL;
}
- return (void*)fls_data[current_fiber->getid()][key];
+ return (void*)fls_data[current_fiber->id][key];
}
void set_specific(pthread_key_t key, const void* data) {
- if (fls_data[current_fiber->getid()].size() <= key) {
- fls_data[current_fiber->getid()].resize(key + 1);
+ if (fls_data[current_fiber->id].size() <= key) {
+ fls_data[current_fiber->id].resize(key + 1);
}
- fls_data[current_fiber->getid()][key] = data;
+ fls_data[current_fiber->id][key] = data;
}
void key_create(pthread_key_t* key, pthread_dtor_t dtor) {
@@ -150,7 +152,6 @@ const bool Coroutine::is_local_storage_enabled() {
return did_hook_pthreads;
}
-
Coroutine::Coroutine(Thread& t, size_t id) : thread(t), id(id) {}
Coroutine::Coroutine(Thread& t, size_t id, entry_t& entry, void* arg) :
@@ -172,6 +173,12 @@ void Coroutine::run() {
thread.current_fiber = this;
swapcontext(&current.context, &context);
thread.current_fiber = &current;
+ if (thread.delete_me) {
+ // TODO: Why does deleting and then reseting cause seg faults? Bad news..
+ thread.delete_me = NULL;
+ Coroutine* cr = thread.delete_me;
+ delete cr;
+ }
}
Coroutine& Coroutine::new_fiber(entry_t* entry, void* arg) {
@@ -182,6 +189,10 @@ void* Coroutine::bottom() const {
return stack.get() - STACK_SIZE;
}
+size_t Coroutine::size() const {
+ return sizeof(Coroutine) + STACK_SIZE;
+}
+
bool Coroutine::operator==(const Coroutine& that) const {
return this == &that;
}
View
@@ -7,6 +7,7 @@
class Coroutine {
public:
+ friend class Thread;
typedef void(entry_t)(void*);
private:
@@ -16,20 +17,7 @@ class Coroutine {
std::auto_ptr<char> stack;
static void trampoline(Coroutine& that, entry_t& entry, void* arg);
-
- public:
- /**
- * Returns the currently-running fiber.
- */
- static Coroutine& current();
-
- /**
- * Is Coroutine-local storage via pthreads enabled? The Coroutine library should work fine
- * without this, but programs that are not aware of coroutines may panic if they make
- * assumptions about the stack. In order to enable this you must LD_PRELOAD (or equivalent)
- * this library.
- */
- static const bool is_local_storage_enabled();
+ ~Coroutine() {}
/**
* Constructor for currently running "fiber". This is really just original thread, but we
@@ -44,11 +32,19 @@ class Coroutine {
*/
Coroutine(Thread& t, size_t id, entry_t& entry, void* arg);
+ public:
/**
- * Don't delete Coroutines, they will delete themselves.
- * TODO: Actually they don't!
+ * Returns the currently-running fiber.
+ */
+ static Coroutine& current();
+
+ /**
+ * Is Coroutine-local storage via pthreads enabled? The Coroutine library should work fine
+ * without this, but programs that are not aware of coroutines may panic if they make
+ * assumptions about the stack. In order to enable this you must LD_PRELOAD (or equivalent)
+ * this library.
*/
- ~Coroutine();
+ static const bool is_local_storage_enabled();
/**
* Start or resume execution in this fiber. Note there is no explicit yield() function,
@@ -67,10 +63,11 @@ class Coroutine {
*/
void* bottom() const;
+ /**
+ * Returns the size this Coroutine takes up in the heap.
+ */
+ size_t size() const;
+
bool operator==(const Coroutine& that) const;
bool operator==(const Coroutine* that) const;
-
- size_t getid() const {
- return id;
- }
};
Oops, something went wrong.

0 comments on commit 6a77a26

Please sign in to comment.