Live data from Hacker News

Linux Namespaces and Go Don't Mix

weave.works

111–120 of 175 posts

Re: Linux Namespaces and Go Don't Mix

#111

Earlier quoted context omitted.

Historically, much (I would probably argue most) C concurrency has been implemented with fork. Certainly not all, and there are many ways to handle it in C...but fork is really common, and I don't think it's considered all that big of a deal to do so. It is idiomatic (at least historically and across maybe billions of lines of C code), and not much harder to reason about than many kinds of thread implementation in C;…

I mostly agree. Of course, for as cheap as a fork can be (and in Linux it's very cheap), it's not as cheap as a systemcall. When changing namespace happens often in a hot path, forking might not be fast enough. I disagree with Walton that the blame is on the N:M threading. It's really on the Linux kernel that has never made a clean distinction between threads and processes, both in kernel and in the APIs.

I agree. Bestowing certain permissions/properties on a thread doesn't make sense. The thread shouldn't "enter the namespace", an API should retrieve a handle to that namespace that should then be usable from any thread in the process via some appropriate calls.

Re: Linux Namespaces and Go Don't Mix

#112
post #101

Earlier quoted context omitted.

> Can I not write a well designed and correct program in C? We have decades of coredumps and exploits to convince us that nobody can. How many well-known apps can you name that have never blown up randomly? I can't think of a single one. How much more failure until it's reasonable to think that C requires an inhuman level of perfection and almost any alternative would be an improvement? I hear good things about seL4…

GNU ls has never segfaulted or otherwise blown up for me. :)

It has segfaulted for other people though: https://lists.gnu.org/archive/html/bug-coreutils/2006-11/msg...

Re: Linux Namespaces and Go Don't Mix

#113

Earlier quoted context omitted.

No. You can call fork pretty cleanly in a pthread based program. This post is not informed criticism. There is some prep for ugly contingencies(pthread_atfork) but it usually just works. Namespace based code while doing the same is like setting your hair on fire while running through the gasoline forest..but caveat emptor is usually spelled out pretty critically in the API and docs. Oh, btw: Fuck RUST. For once and f…

> There is some prep for ugly contingencies(pthread_atfork) but it usually just works. Actually, that's not true. Perhaps it's theoretically possible, in some cases, to make your threaded code work with fork with the appropriate pthread_atfork() handlers, but in general, it's a total mess. Thread A has a lock, thread B calls fork(), thread B tries to acquire the lock. The lock is held, but thread A is not running in…

> Namespaces + threads are fine, the only problem here is namespaces + M:N threads + no method for pinning a green thread to an OS thread, like forkOS in Haskell.

Not quite. unshare(CLONE_NEWUSER) and setns(fd, CLONE_NEWNS) require your process to be single-threaded. So precise control over threading is needed.

Re: Linux Namespaces and Go Don't Mix

#114
post #111

Earlier quoted context omitted.

I mostly agree. Of course, for as cheap as a fork can be (and in Linux it's very cheap), it's not as cheap as a systemcall. When changing namespace happens often in a hot path, forking might not be fast enough. I disagree with Walton that the blame is on the N:M threading. It's really on the Linux kernel that has never made a clean distinction between threads and processes, both in kernel and in the APIs.

I agree. Bestowing certain permissions/properties on a thread doesn't make sense. The thread shouldn't "enter the namespace", an API should retrieve a handle to that namespace that should then be usable from any thread in the process via some appropriate calls.

On the other hand having individual threads entering namespaces means your broker process does not have to constantly switch namespaces, it can use shared memory between differently privileged threads to do the brokering.

Re: Linux Namespaces and Go Don't Mix

#115

Earlier quoted context omitted.

> Oh, btw: Fuck RUST. For once and for all fuck this tyranny of coercion by potential IP holders. It is a shit language. ... what? I am confused as to what you're saying here.

* Coercion: large down vote/propaganda community against any negative rust idea..evidenced here. * IP Holders, well this is speculative. I can't understand anyone who would compare Rust against C in a positive way without possibly profiting from it. Rust is painful to write, painful to learn and makes you ask yourself: Can I not write a well designed and correct program in C? Of course I can. Why Am I Learning Rust?…

My first thing I wrote in Rust was porting a trivial assignment for a security course in University from C to Rust. It turned out I had an off-by-one buffer overflow that Rust caught.

This clearly showed me the advantage of Rust over C.

Re: Linux Namespaces and Go Don't Mix

#116
post #33

Earlier quoted context omitted.

Sorry, I don't understand what you mean by "Go hijacks control flow". Could you elaborate cases, where Go did not behave as you expected? And where syntactic and semantic correct Go code did not compile?

So, keep in mind that my experience with Go is not at a professional level. Take this example: https://gobyexample.com/channel-buffering As far as my understanding is concerned, channels are a way for goroutines to pass data between one another, correct? Yet in this particular case, the channel `messages` is operating in the same manner as a generator or array. So, am I creating goroutines by passing messages to the…

When I read about channels and various forms of IPC/inter-thread communication in most other languages, and remember the past pain of threads and mutexes in C/C++, I am so happy to be able to send a message in Erlang to another Erlang process (Pid) as easily as this:

    Pid ! {self(), 42}
And in the process identified by Pid, to receive the message:

    receive
        {From, Data} when is_pid(From) ->
            handle_data(From, Data)
    end
And beyond that, the process identified by Pid can be running on a physically separate host system - it's transparent.

Too bad we can't use Erlang for systems programming, but you can't have everything!

Re: Linux Namespaces and Go Don't Mix

#117
post #43

this is just a more complex version of the issue where go can't safely do the daemonize dance for a privileged port

There's a simple-ish workaround for the privileged port issue if you can't just use CAP_NET_ADMIN: http://play.golang.org/p/dXBizm4xl3 The namespace issues are unfortunately a lot tougher to address.

But you also want drop that privilege after using it to get the same effect as the "daemonize dance" GP referred to. And that's also per-thread, just like namespaces.

Re: Linux Namespaces and Go Don't Mix

#118
post #109

Earlier quoted context omitted.

This is what I cannot understand about Go: how did a newly-designed programming language end up as such a muddle?

Because this isn't really a language issue. It's an OS issue. Go assumes that all threads are equal and therefore any Goroutine can run on any thread and threads are all equal. Linux got late to the thread party and its threads are kind of like processes that haven't decided if they want to be processes or threads. It's true the Go runtime could give users more control over goroutine and thread scheduling but that wo…

But linux threads predate go, so go is built on assumptions they knew were not true.

Re: Linux Namespaces and Go Don't Mix

#119
post #109

Earlier quoted context omitted.

This is what I cannot understand about Go: how did a newly-designed programming language end up as such a muddle?

Because this isn't really a language issue. It's an OS issue. Go assumes that all threads are equal and therefore any Goroutine can run on any thread and threads are all equal. Linux got late to the thread party and its threads are kind of like processes that haven't decided if they want to be processes or threads. It's true the Go runtime could give users more control over goroutine and thread scheduling but that wo…

>Go assumes that all threads are equal and therefore any Goroutine can run on any thread and threads are all equal

This isn't true in Linux or Windows so I don't see why Go would make this assumption other than poor design.

>The property should be accessible via a handle that can be shared amongst all threads.

It literally is. The namespace information is shared with all threads in a PID group globally available in the /proc fs.

---

What OP is doing is effectively having 1 program run part of itself in 1 container, and another part outside of that container.

Go isn't a systems programming language so this level of fine grain control isn't possible. Hell its pretty difficult in a C/Rust/C++ environment.

Re: Linux Namespaces and Go Don't Mix

#120
post #109

Earlier quoted context omitted.

Because this isn't really a language issue. It's an OS issue. Go assumes that all threads are equal and therefore any Goroutine can run on any thread and threads are all equal. Linux got late to the thread party and its threads are kind of like processes that haven't decided if they want to be processes or threads. It's true the Go runtime could give users more control over goroutine and thread scheduling but that wo…

>Go assumes that all threads are equal and therefore any Goroutine can run on any thread and threads are all equal This isn't true in Linux or Windows so I don't see why Go would make this assumption other than poor design. >The property should be accessible via a handle that can be shared amongst all threads. It literally is. The namespace information is shared with all threads in a PID group globally available in t…

What's an example of it not being true in Windows?

I think it's mostly true in Linux and the situations where it isn't true are subtle and require expert knowledge in some specific areas. It's not like there's a big sticker on Linux that says threads are generally not symmetric.

I get the bit of half the process being in one space and half in another. I just find it odd. Can half the process run as root and half the process run as another user? Maybe yes? Can a file be open in half the process and not open in the other?

At any rate, I think it's not black and white. Green threads do make sense in general and introducing different thread types and more granular control makes things more complicated.

I think you're missing my point about APIs and handles:

  handle = open_namespace("test")
  syscall(handle, "yes")
if handle can be used across threads then this sequence will run correctly regardless of what thread is executing it, it doesn't rely on anything bestowed on a thread.

(EDIT: thread local storage I guess is an example of asymmetry between threads but it's intentional/clear asymmetry designed for specific purposes and something you don't need to access in Go e.g. because you don't use threads directly).

Post reply on HN