I also made a CLI for consulting the syscall API when I originally released the website. I think I can tidy up the code and make it public too. It uses a embedded dataset so it does not have to query the API endpoint all the time
Good catch, thanks! Since 5.14 (I think?) the kernel only reads eax (before that it used all of rax and returned ENOSYS if the upper half wasn't zero), so I'm adding a note about it to the x64 and x32 conventions
This is really great resource, didn't know about it. But one question not related to the website above - why the syscalls vary per architecture if the linux API is the same?
Or is it I am confusing it with the C standard library/POSIX and assuming that it should be the same everywhere?
The Linux kernel API is the same everywhere, but the syscall ABI (numbers, calling convention, entry paths) is specific to a architecture, while it's the C library that wraps those details into the portable POSIX API we code against
Also newer archs (riscv) don't support certain syscalls (open, fork) they are still functions you can call under your standard musl,glibc but they inernally call openat, clone.
I wouldn't call any of them similar, except for 'pread' maybe. Each one has a lot of subtle semantics. Either way, it's syscall.tbl that determines whether they are distinct syscalls, not the author's page
The number of Linux syscalls depends on the architecture and on x86-64 there are over 450 Linux syscalls.
Nonetheless, about one third of those syscalls are obsolete (being replaced by newer improved syscalls), even if a large number of programs are still using them, and about one other third of them are rarely used in the environments familiar to most Linux users, like personal computers and small servers.
The obsolete syscalls inflate a lot the number of Linux syscalls, because there are a lot of syscalls that were originally defined with an inadequate set of parameters, then they were fixed by adding parameters or changing the meaning of the existing parameters. There are many syscalls were even 3 or 4 attempts were needed until reaching an acceptable definition for their parameters.
New programs should use only the newest improved syscalls, but the documentation of the Linux syscalls in various places is usually not up-to-date itself, so a lot of people are still using older syscalls, without being aware that they are suboptimal. So the obsolete syscalls will have to be supported forever by the Linux kernels (though in most cases when an obsolete syscall is invoked it just fills the parameters with adjusted values and then it jumps to the current syscall).
Well, there really is about 400 syscall numbers allocated, and each has its own entrypoint in the kernel. That's an entirely objective criterion as opposed to arguing "well, sbrk and mmap (or recv and read) are kinda similar, maybe we should count them as just one syscall instead of two", because in the end we can might as well say "well, technically there is only one syscall, it just has an additional seventh argument that serves as the 'function denominator', like the ioctl's request parameter, you know".
Uh, sorry, what? Trying to measure similarity between syscalls is a) impossible, b) pointless, so obviously I'd really like to understand why someone would want to do something like this — but I'd rather not speculate about what and why you think and believe, and instead to just straight hear from you.
If you're interested in why I think what I think — there's a sibling comment where I tried to articulate my position. I'd like to hear about yours, if you don't mind.
P.S. You didn't actually offer any argument, logical (?) or technical (?!), in your original comment, and I think you're actually have the meaning of those words reversed: "logical argument" appeals to logical relations between the abstract concepts, while "technical argument" appeals to the underlying technology (the kernel implementation in our case) and tries to deal with particularities of reality. So if anything, my argument was the logical (semantical?) one, not that it really matters.
I think the number is mostly meaningless even if we ignore whether they're distinct or not. Consider ioctl() - it's a single syscall but if I remember correctly the number of subcommands is in the thousands.
Yes, the ioctl has been notorious for sneaking in arbitrary amount of functionality into the kernel space, and serving generally as a kitchen sink: "You can rarely convince Linus to make a new syscall, but making a new ioctl is much easier". That's still one syscall though.
And how do you even compare how the distinct the syscalls are (e.g., pipe() and open() are about 70% similar)? And after that, what do you do with this metrics? How do you sum it up? Again, pipe() and open() are 70% similar — does that mean we have 1.3 syscalls instead of 2?
I would count "pipe" and "open" together as 0 (useful) syscalls, because both have been obsolete for a very long time (even if they occupy 2 slots in the syscall table and those 2 slots will remain occupied forever).
These 2 syscalls have a history typical for Linux syscalls, where frequently new syscall variants make completely obsolete their predecessors, but the old syscalls must still remain supported forever by the newer Linux kernels, to allow running legacy programs.
"pipe" has been obsoleted by "pipe2" (on 2008-10-09), which in turn has been obsoleted by "IORING_OP_PIPE".
"open" has been obsoleted by "openat", which in turn has been obsoleted by "IORING_OP_OPENAT".
Most users do not invoke Linux syscalls directly, but they use the standard C library, which has frequently shielded the end user from the evolution of the Linux syscalls. For instance, you might use the functions "open()" and "pipe()" in your C program, but the C library might invoke instead of those the more modern syscalls "openat" and "pipe2", after adjusting their parameters.
I think you're missing the point I'm trying to make. Both pipe2 and openat has about 70% similar functionality (and so do the IORING_OP_PIPE and IORING_OP_OPENAT operations) — really, the only difference is that pipe2 returns two new fds instead of just one, and that the file opened is not a regular file. So, are those 2 syscalls or 1.3? What about triples or quadruples of syscalls with overlapping functionality, do we go full inclusion-exclusion formula on them? What about that 70% similarity estimation — how do establish that? Do you count the similarity/overlap of the underlying implementations? Only of the user-facing functionality? Both, somehow? Something else entirely?
Or, you know, we can instead not engage in this subjective quagmire and look at the actual, factual number that undeniably exists. It may not be very useful for any practical purpose except for pointless dick-measuring between OSes with radically different APIs and internal architectures — but neither is this trying to measure syscall similarity, really.
Moreover, for a large number of traditional Linux syscalls (including the many variants of read/write/send/recv) there are now better alternatives that are invoked as subcommands of a single syscall: io_uring_enter.
However, I am bit skeptical as to whether io-uring will ever support all Linux syscalls.
At this point I am convinced that io-uring primarily supports I/O API / syscalls. That would mean syscalls relating to disk and network I/O. While this covers a lot of syscalls it most definitely doesn't cover all.
Though, to give some credit her, it does also cover to syscalls relating to kernel features like futex but yeah, for the most part it doesn't cover much that doesn't have to do with I/O.
Which is obviously not a problem but raises the question of whether it ever will support other kernel features.
There's a "Same syscall on other architectures" section already, maybe I could add the Similar section next to it. Edit: but this means it needs a way to actually know they are similar apart from only their names
[1] https://lore.kernel.org/all/20210518191303.4135296-5-hpa@zyt...
Or is it I am confusing it with the C standard library/POSIX and assuming that it should be the same everywhere?
Does it still make sense to term or classify them as two distinct syscalls?
But, anyways, not like it matters that much but still.
400 distinct syscalls is a very large number of syscalls if you generally presume they're entirely distinct.
Nonetheless, about one third of those syscalls are obsolete (being replaced by newer improved syscalls), even if a large number of programs are still using them, and about one other third of them are rarely used in the environments familiar to most Linux users, like personal computers and small servers.
The obsolete syscalls inflate a lot the number of Linux syscalls, because there are a lot of syscalls that were originally defined with an inadequate set of parameters, then they were fixed by adding parameters or changing the meaning of the existing parameters. There are many syscalls were even 3 or 4 attempts were needed until reaching an acceptable definition for their parameters.
New programs should use only the newest improved syscalls, but the documentation of the Linux syscalls in various places is usually not up-to-date itself, so a lot of people are still using older syscalls, without being aware that they are suboptimal. So the obsolete syscalls will have to be supported forever by the Linux kernels (though in most cases when an obsolete syscall is invoked it just fills the parameters with adjusted values and then it jumps to the current syscall).
Trying to counter a logical argument with a technical argument is pretty lame and doesn't make for a healthy conversation.
If you're interested in why I think what I think — there's a sibling comment where I tried to articulate my position. I'd like to hear about yours, if you don't mind.
P.S. You didn't actually offer any argument, logical (?) or technical (?!), in your original comment, and I think you're actually have the meaning of those words reversed: "logical argument" appeals to logical relations between the abstract concepts, while "technical argument" appeals to the underlying technology (the kernel implementation in our case) and tries to deal with particularities of reality. So if anything, my argument was the logical (semantical?) one, not that it really matters.
And how do you even compare how the distinct the syscalls are (e.g., pipe() and open() are about 70% similar)? And after that, what do you do with this metrics? How do you sum it up? Again, pipe() and open() are 70% similar — does that mean we have 1.3 syscalls instead of 2?
These 2 syscalls have a history typical for Linux syscalls, where frequently new syscall variants make completely obsolete their predecessors, but the old syscalls must still remain supported forever by the newer Linux kernels, to allow running legacy programs.
"pipe" has been obsoleted by "pipe2" (on 2008-10-09), which in turn has been obsoleted by "IORING_OP_PIPE".
"open" has been obsoleted by "openat", which in turn has been obsoleted by "IORING_OP_OPENAT".
Most users do not invoke Linux syscalls directly, but they use the standard C library, which has frequently shielded the end user from the evolution of the Linux syscalls. For instance, you might use the functions "open()" and "pipe()" in your C program, but the C library might invoke instead of those the more modern syscalls "openat" and "pipe2", after adjusting their parameters.
Or, you know, we can instead not engage in this subjective quagmire and look at the actual, factual number that undeniably exists. It may not be very useful for any practical purpose except for pointless dick-measuring between OSes with radically different APIs and internal architectures — but neither is this trying to measure syscall similarity, really.
Moreover, for a large number of traditional Linux syscalls (including the many variants of read/write/send/recv) there are now better alternatives that are invoked as subcommands of a single syscall: io_uring_enter.
However, I am bit skeptical as to whether io-uring will ever support all Linux syscalls.
At this point I am convinced that io-uring primarily supports I/O API / syscalls. That would mean syscalls relating to disk and network I/O. While this covers a lot of syscalls it most definitely doesn't cover all.
Though, to give some credit her, it does also cover to syscalls relating to kernel features like futex but yeah, for the most part it doesn't cover much that doesn't have to do with I/O.
Which is obviously not a problem but raises the question of whether it ever will support other kernel features.