Fix for Golang runtime memory corruption bug
go-review.googlesource.com
go-review.googlesource.com
I see this habit in a lot of commit messages and while it is important to convey intent, there are better ways to document your code (either inline, or in this particular case, a wiki page).
- sellock(scases, lockorder)
+ systemstack(func() {
+ sellock(scases, lockorder)
+ })
The rest of the patch is adding/changing comments explaining everything.This bug exists because they wanted to reinvent threading so you could have millions of threads, except when you actually use millions of threads for anything non-trivial it doesn't actually work out so well. To do that they couldn't use the standard since-1970 fixed stacks so they needed movable/growable stacks. They reinvented exceptions in a way that broke selinux. They reinvented the memory allocator in a way that breaks ulimit. They reinvented a javadoc/doxygen that's less useful.
It's great to try to improve things, but a lot of times there's actually very good reasons for the old ways.
I get what your saying but it's apples to oranges. They are in effect similar though.
I'm not saying this is in any way empirically superior, in fact I think Go's approach owes a lot to Sun's original vision with JavaDoc. Some just prefer it and feel it's approach benefits them, and it's a preference that is often factored in when making the choice to use it.
My original point was that Sun's approach is now so commonplace it's an 'apples and oranges' argument. Golang has made a legitimate step forward (I think), in how a language treats and encourages it's documentation: As a first class citizen from day 0, rather than a convenient afterthought. The parity of experience between godoc.org & `go doc` demonstrates this with ample effect.
It's not that simple. I think there's a reasonable first-principles argument to be made that scheduling belongs in the kernel, which has a global view of the system and is better equipped to make those decisions.
Maybe the kernel scheduler would do a better job, but is it realistic to run 1M OS threads? It feels like the overhead per green thread is much lower, and the potential for being interrupted in a critical section is also much lower: An OS thread may be paused while holding a (vm internal) lock, but the vm scheduler would not preempt a green thread in the middle of doing something that requires a lock (ex: Delivering a message to another green thread)
What kind of overhead do OS thread have that green thread doesn't ? I'm aware of the stack size, but is there something else ?
If the stack size is the only culprit here, what prevents the admin from manually setting a small stack size that will be enough for most operation (in practice, I don't know how useful the ability to grow dynamically the stack size in languages with green threads).
> An OS thread may be paused while holding a (vm internal) lock, but the vm scheduler would not preempt a green thread in the middle of doing something that requires a lock (ex: Delivering a message to another green thread)
That's an interesting point.
Real context switches (with cache invalidation) to switch between, system call (with context switch to kernel) to create/dispose, probably kernel bits that will explode with huge thread lists: I wouldn't be surprised if listing all threads with ps or top also locks the thread lists: not a big deal if you have a reasonable number of threads, but could block thread creation in a 1M thread case.
Not context switching is even faster.
How fast is really fast, how modern is modern? some results from 2010 [1] show at least 1000 nanoseconds per context switch (even with optimizations for the kernel switching between threads of the same process). That's not that slow, but it is a lot of time you could be doing something else.
[1] http://blog.tsunanet.net/2010/11/how-long-does-it-take-to-ma...
[1] http://blog.tsunanet.net/2010/11/how-long-does-it-take-to-ma...
And yes, the dynamic stack growth is an extremely important part of it. Without it, you'd just have small stacks. Take an arbitrary pthreads program and restrict its stacks to a few kb. You won't have much fun. The code really needs to be written such that it can cope with small stacks. That can be tedious, so you don't want to do it for run-of-the-mill userspace code. Dynamically-sized stacks give you the best of both worlds.
Dynamically sized stacks are a property of GC, not userland threads. This is a common misconception.
We gave up on this already, as multithreading is not even a little bit decent model for concurrency.
It supports millions of co-routines, not threads. There's typically one thread per CPU or so. The key insight is a lot of server type workloads primarily are constrained on I/O and multiplexing virtually unlimited co-routines on a thread automatically by the runtime makes for much simpler concurrent server code.
Implementing high concurrency server code in almost any other mainstream language is non-trivial. Indeed I originally switched from Python to Go primarily because of that.
I think there was some issue with runtime code generation (used with closures IIRC) very early on but that's ancient history by now.
i'd be curious to see the impact on benchmarks for parallelization.
The best (worst?) one is where you'll see a series of major changes with the following commit messages:
- Add feature X (no explanation of what it does)
- Fix feature X
- Really fix feature X
- Fix feature X for real
- Finally fixed X
- Fix test environment
If so, it's going to take some effort for this bug to be weeded out in every single deployment around the world...
This is not a unique occurrence.
It's also possibly a subtle dig at go, because unlike other languages go does not use dynamic linking, meaning bugs in libraries require recompilation (has positive effects too).
It just isn't the default compilation mode, you have to explicitly enable it.
"This bug has existed since Go 1.4. Until then the select code was implemented in C, 'done uint32' was a C stack variable 'uint32 done', and C stacks never moved."
It'll affect probably most running jobs out there, as Go 1.4 was released on Dec 10, 2014.
Just try searching for go in the otherwise excellent Algolia HN search engine:
Without quotes:
http://i.imgur.com/8ztH48u.png
With quotes: