15 ms·
I don't see how `an_op_syscall(param)` is ‘more complicated’ or requires more calls or state than `a_syscall(OP_NAME, param)`.
by aasasd 6y ago
I don't see how `an_op_syscall(param)` is ‘more complicated’ or requires more calls or state than `a_syscall(OP_NAME, param)`.
- whatshisface 6y agoSince C doesn't have first-class functions, if you needed to dynamically pick between values of OP_NAME you'd be glad it was a parameter. Imagine ten options parameters, which your program needs to choose between depending on the circumstances. That's a huge branch tree. Imagine choosing between two options - you'd need to keep track of function pointers, or at least write your own enum. C makes it far nicer to handle enum values than it is to handle functions, because ints are first-class. I agree that there's no difference between a symbol in the name and a value in the args when your program always needs the same value, but sometimes it needs dynamism.
- aasasd 6y agoYou're talking here about the second half of your previous comment. This reasoning is ok by me, though I have to wonder how often, and why, do programmers need to decide dynamically in mid-flight whether they want to wait instead of wake (or whatever choices futex() offers), or that they need one handle instead of a vector. I'm talking above about the first half of your previous comment, where you say that having operation names in the function names would somehow require multiple calls and break atomicity. I can only understand this if Linux syscalls are parameterized to do one thing and then another thing and something else, in one call—which sounds horrible, but still can be expressed in function names.
- whatshisface 6y ago>I'm talking above about the first half of your previous comment, where you say that having operation names in the function names I was addressing operation names in the function names in the second half of my comment, in the first half I was addressing breaking up specification into a state machine process like OpenGL does. State machines are another way of breaking up big functions with lots of options. They have pseudo default argument support as an advantage, and ease of implementation via static globals as a historical (before multithreading) advantage. State machines are kind of like builder pattern as a way to get named arguments and default arguments in a language that doesn't have either, except instead of the builder being a class it's a singleton (with all the attendant disadvantages.)
- aasasd 6y agoAh, no, that's also contrary to my taste. I love clear function names and I hate state. Immutable return values are way better than builders, in my experience, even if that means many arguments. And static globals are a whole other level of bad.
- whatshisface 6y agoBuilders can be a huge help when you get up to a dozen arguments and above. Seriously, I never want to see foo(13,15,91,39,LIB_YES,LIB_NO,5.0,183.5) ever again haha. Good engineers would comment each argument, good languages support named arguments, but when you have neither it can be a mess unless the library author used builders to force annotation of the values. A close relative of builders are settings struct arguments, which have their own pros and cons. I think Vulkan uses settings structs.
- aasasd 6y agoI think OOP builders can work without extra state if they implement `->addThis()->addThat()` by actually doing functional `addThat(addThis(defaultObj))` and creating immutable values inside. But ultimately there's no good answer to the absence of named arguments, and by now not having them is a pure atrocity. Of course, I'm guessing C programmers would cringe at the prospect of going full COW for such use-cases.
- whatshisface 6y agoThe downside of your second syntax for builders is when you need to add arguments. People will have a hard time remembering whether it's supposed to be addFoo(1,addBar(2)), addFoo(addBar(2),1), or any of the other combinatorially exploding number of possible arrangements as the complexity of the construction is increased. With the OOP design, the values go inside the addFoo(1)->addBar(2) and it's obviously constrained to that one way of writing it. When writing function signatures that are going to be nested I try to keep one type in the arguments and I try to make them commutative (so that it works the same way in any order.) That's not always possible but it helps people remember how to write calls.
- gpderetta 6y agoThere is no direct function calls into the kernel. At the end of the day a function call is an interrupt with the syscall parameters in a bunch of registers. As you do not want to use a different interrupt (as there are only so many interrupts [1]) for each function call, the syscall id is passed as a parameter in a register. On the kernel side the id is used to index in a function pointer table to find and call the actual system function. Turns out this table is actually limited in size so some related syscalls use another level of indirection with additional private tables (I think this is no longer a limitation and these syscall multiplexers are frowned upon for newer syscalls). All of this to say that FUTEX_WAIT and FUTEX_WAKE are just implementation details. A proper syscall wrapper would just expose distinct functions for each operation. But for a very long time glibc did not expose any wrapper for futexes as they were considered linux specific implementation details and one was supoosed to use the portable posix functions. So the futex man pages documented the raw kernel interface. That didn't stop anybody from using futexes of course and I think glibc now has proper wrappers. [1] yes, these days you would use sysenter or similar, but same difference.
- aasasd 6y agoThanks, this actually answers my original question in regard to the kernel's part of it. I'll take a look at what names and signatures libc has, and if they're still like that then the question is readdressed to libc—though I guess the answer then would be “because that's how it is in the kernel”. P.S. Come to think of it, I sorta knew about the interrupt business, and vaguely about the later but fundamentally similar method (but not that there are many interrupts for syscalls, though thinking about eight-bit registers clears this up quickly). Guess I just forgot that libc is kept separate from the kernel, in the Linux world.
- delusional 6y agoI don't see how function pointers are any harder to manage than an enum. Just slap those function pointers into an array or a switch, and away you go.
- whatshisface 6y agoEnum values are type checked based on the sum type you define them with. Function pointers are type checked based only on their signature. Also, C does not support partial application, but it does support partially filling out a struct of enum types.