If multiple fibers finished one after in an unexpected way there would be a memory leak because `delete_me` would get overwritten. There was an assertion in place to prevent this scenario, and a case was discovered which triggers this condition. It was actually quite hard to hit because the coroutine pool masks this issue very well. The issue was fixed by deleting dead coroutines as soon as possible, instead of at the next call to run() Closes gh-16
By getting rid of the Fiber.current getter and just resetting it every time it changes we can drastically speed up access to that property, since it saves a trip out of the v8 engine. In most cases it seems like people will be using Fiber.current, so this is a good change to make.
This started off as a diff to keep a Locker active for each coroutine even while not in use by v8, which would save the once-per-thread cost. Turns out that cost isn't very high, and clearing out the threads is better for garbage collection anyway. But the code cleaning up here was pretty good so I'm putting this in.
This simplifies initialization into a clear 2-phase dichotomy. The first phase runs before malloc is ready, and the second phase is in regular initialization. This incidentally plugs a hole where thread-specific keys were getting lost early in initialization. I think there's still a condition where you could lose data, but OS X and Linux aren't hitting it so it's ok for now.
I was giving v8 the top of the stack instead of the bottom of the stack so it couldn't figure out where to stop. This change fixes that. I tested this using an infinite recussion function with really small stacks (8kb) and large ones (512k) and I'm getting reasonable results. Now the hard part is picking the right stack size. I'm going to go with 64k as it's the default stack node picked for libeio threads.
Put FLS in the Coroutine object instead of with the thread in a vector. This technically means we are no longer calling destructors on outstanding keys when the keys are deleted, but that was already the case with multiple threads. The up side is that no one really deletes TLS keys unless the program is terminating anyway.
It seems that if you have v8 compiled as a shared library instead of a static library sometimes it can get initialized before coroutines.so, even with LD_PRELOAD. I'm not really sure why this is the case, but this means we need to run the hooks much earlier. So now everything that goes through pthread_getspecific is fiber-local, instead of the way it used to be where only keys created after coroutine.cc is initialized were fiber-specific.
If you attempt to run() a fiber that's already running from inside another fiber you would get a segfault. This is because even though the fiber isn't running, it hasn't yielded either. Thus where to resume execution is unclear. This should throw an exception. Closes gh-8