3 ms·
It's not necessary to allocate a large stack, there is always one available because threads have their own stack, and you can switch to it at all times because
by 4ad 11y ago
It's not necessary to allocate a large stack, there is always one available because threads have their own stack, and you can switch to it at all times because goroutine threading is cooperative. In other words, if you are scheduled to run on a thread, you and only you have access to that thread stack.
Stack switching doesn't take more than a few machine instructions.
The problem with tcsetattr is that it's a library function, so you (generally[1]) need the target library in order to create a program that calls it. This is bad because in Go we value cross-compiling a lot, so we can't depend on having other people's shared libraries available in the build environment.
Syscalls, however, we know how to do them and we know what they are, so we don't need any special target library in order to generate programs for the target.
[1] On platforms like Solaris and Windows, where we are forced to use target shared libraries, we cheat a little and encode the target symbol names that we need, and we rely on standardized ELF/PE symbol resolution mechanism creating a scheme that's essentially equivalent to having import libraries available. But this is very complicated and takes a lot of code in the linker, so it's not at all unexpected that we avoid it whenever possible.
- pcwalton 11y ago> Stack switching doesn't take more than a few machine instructions. In Rust we found that stack switching was really slow, even when fully optimized to that scheme. CPUs really don't like it. We thought "it was only a few instructions; how bad can it be"; turns out that any function call overhead can quickly add up to 2x or more overall performance penalties in some programs. See the performance numbers in this thread for cgo (using the same technique) [1]. According to the first benchmark, calling the function via cgo is 16x slower. You're at 161ns for a no-op function call. Consider that the cost of a syscall can be below 100ns [2]. The overhead can add up quite a bit! [1]: https://groups.google.com/forum/#!topic/golang-nuts/RTtMsgZi88Q https://groups.google.com/forum/#!topic/golang-nuts/RTtMsgZi... [2]: http://forum.osdev.org/viewtopic.php?p=209429&sid=9bcec5b68408721f24121699cc7d99f1#p209429 http://forum.osdev.org/viewtopic.php?p=209429&sid=9bcec5b684...
- tedunangst 11y agoThere's theory and there's practice. Saying that using ioctl is the right choice because it helps cross compilation rings a little hollow when the cross compiled binary obviously won't run due to the target system not having said syscall.
- 4ad 11y agoI'm sorry, but what? If the system call doesn't exist, then the program won't compile, because the system call stub won't be defined for that platform. If the system call is ioctl, and the user tries to call with an request that doesn't exist, the program won't compile because the request will not be defined. But we don't even export ioctl! First of all, it's not type safe. We only expose ioctl wrappers that are type-safe and use requests defined by the target platform, not arbitrary integers passed by the users. Of course if the user does an indirect system call, and mucks with unsafe, and passes it arbitrary data, than that's a user problem, not a Go problem. Using ioctl internally by Go is the right thing. Users indirectly calling ioctl and breaking type-safety with unsafe is just bad code, but that doesn't have anything to do with Go. Go won't prevent you if you want to shoot yourself like that.
- tedunangst 11y agoWhat is the linked post about if not code that could have been portable but wasn't? I'm having a hard time determining if you're saying the code in question was right or not.
- 4ad 11y agoWell the code in the linked post doesn't compile on Solaris because SYS_IOCTL is not defined on Solaris. So that was my point. You don't get code that compiles but doesn't work, unless you try really hard. But the code is bad. If you have to call system calls through the indirect system calls and use unsafe to pass parameters, you either do something wrong, or we did something wrong. In this case the author of that code is excusable. It was our fault. We didn't expose the necessary type-safe wrappers, so the authors was forced to write code like that. This is changing however, just yesterday I committed support for termio-related stuff for Solaris. I assume Linux, BSDs and the other systems will follow very soon.