I was asked about system calls , what they are, which mode are they used in and if read(), getchar() and sqrt() uses or not system calls.
For the first part I answered that system calls provide a interface between a process and the OS and these are used in kernel mode.
The thing that is bothering me is the fact that for me the only function that uses system calls of those 3 is read().
Am I right? or getchar() and sqrt() also use system calls?
(NOTE: read() from unistd.h getchar() from stdio.h and sqrt() from math.h)
The difference between a system and a regular call is that a system call has to issue a trap to the operating system whereas a regular call just calls another user level subroutine. You're right in saying that the difference is in what mode the calls are executed in.
Sqrt is not a system call. All it does is perform a simple calculation. If I remember correctly, both read() and getchar() are system calls because the operating system is the one who handles input/output operations.
Related
There is the C library function pipe(3) and the kernel (system call) pipe(2).
Both have the same signature and should be used like this (same include header):
#include <unistd.h>
int fds[2];
pipe(fds);
Will this code call pipe(3) or pipe(2)?
How can I decide whether I want to use libc or a system call?
If pipe(3) and pipe(2) are the same, how do I know that?
Will this code call pipe(3) or pipe(2)?
It will call pipe(3).
There is no way to call the system call directly from C, you either
have to call libc wrapper for such system call (if one is provided), or
use syscall(2) to "stuff" the right arguments into the right registers before executing architecture-appropriate system call instruction, or
provide your own assembly wrapper which will do the same, or
use inline __asm__ to do the same.
I think you're making a distinction where there isn't one. Your code will call the pipe library function, which is just a wrapper around the pipe system call. It's not an either/or. The section 3 manual page is from the POSIX programmer's manual, and the section 2 manual page is Linux-specific.
In linux, For all read and write operations we use read() and write() system calls. The same we can do with ioctl() system call also, then why we still need read() and write() system calls?
Is there any security or fast performance while using read() and write() system calls rather than ioctl() ?
Theoretically everything could be done using ioctl(). But the purpose of ioctl() is to provide a way to perform miscellaneous, device-specific operations. When there are operations that most devices implement, it's better to use a more specific function. This allows the compiler to perform argument type checking. A generic function like ioctl() can't check that you've provided parameters appropriate to that operation.
If we removed read() and write() then the system would no longer be posix compliant (and much existing software would break). Likewise, if we rely exclusively on linux ioctl system calls then our code is no longer portable to other systems.
I wrote a simple C program which just calls the exit() function, however strace says that the binary is actually calling exit_group, is exit() a exit_group() wrapper? Are these two functions equivalent? If so why would the compiler choose exit_group() over exit()?
The Linux and glibc man pages document all of this (See especially the "C library/kernel differences" in the NOTES section).
_exit(2): In glibc 2.3 and later, this wrapper function actually uses the Linux SYS_exit_group system call to exit all threads. Before glibc2.3, it was a wrapper for SYS_exit to exit just the current thread.
exit_group(2): glibc wrapper for SYS_exit_group, which exits all threads.
exit(3): The ISO C89 function which flushes buffers and then exits the whole process. (It always uses exit_group() because there's no benefit to checking if the process was single-threaded and deciding to use SYS_exit vs. SYS_exit_group). As #Matteo points out, recent ISO C / POSIX standards are thread-aware and one or both probably require this behaviour.
But apparently exit(3) itself is not thread-safe (in the C library cleanup parts), so I guess don't call it from multiple threads at once.
syscall / int 0x80 with SYS_exit: terminates just the current thread, leaving others running. AFAIK, modern glibc has no thin wrapper function for this Linux system call, but I think pthread_exit() uses it if this isn't the last thread. (Otherwise exit(3) -> exit_group(2).)
Only exit(), not _exit() or exit_group(), flushes stdout, leading to "printf doesn't print anything" problems in newbie asm programs if writing to a pipe (which makes stdout full-buffered instead of line-buffered), or if you forgot the \n in the format string. For example, How come _exit(0) (exiting by syscall) prevents me from receiving any stdout content?. If you use any buffered I/O functions, or at_exit, or anything like that, it's usually a good idea to call the libc exit(3) function instead of the system call directly. But of course you can call fflush before SYS_exit_group.
(Also related: On x64 Linux, what is the difference between syscall, int 0x80 and ret to exit a program? - ret from main is equivalent to calling exit(3))
It's not of course the compiler that chose anything, it's libc. When you include headers and write read(fd, buf, 123) or exit(1), the C compiler just sees an ordinary function call.
Some C libraries (e.g. musl, but not glibc) may use inline asm to inline a syscall instruction into your binary, but still the headers are part of the C library, not the compiler.
This question already has answers here:
How is the system call in Linux implemented?
(6 answers)
Closed 8 years ago.
How does system calls work ?
What are the operations happen during system call?
There are various system call like open , read, write, socket etc. I would like to know how do they work in general ?
In short, here's how a system call works:
First, the user application program sets up the arguments for the system call.
After the arguments are all set up, the program executes the "system call" instruction.
This instruction causes an exception: an event that causes the processor to jump to a new address and start executing the code there.
The instructions at the new address save your user program's state, figure out what system call you want, call the function in the kernel that implements that system call, restores your user program state, and returns control back to the user program.
A visual explanation of a user application invoking the open() system call:
It should be noted that the system call interface (it serves as the link to system calls made available by the operating system) invokes intended system call in OS kernel and returns status of the system call and any return values. The caller need know nothing about how the system call is implemented or what it does during execution.
Another example: A C program invoking printf() library call, which calls write() system call
For more detailed explanation read section 1.5.1 in CH-1 and Section 2.3 in CH-2 from Operating System Concepts.
The man page for atexit(3) says the following:
POSIX.1-2001 says that the result of calling exit(3) more than once (i.e., calling exit(3) within a function registered using atexit()) is undefined. On some systems (but not Linux), this can result in an infinite recursion; portable programs should not invoke exit(3) inside a function registered using atexit().
However, I'm interested in modifying the exit code in a finalizer for my program. The only way I've managed to do this is by calling exit() from within my finalization function, but the man page explicitly warns against that.
Is there any practical danger against doing this? Are there any implementations where that approach might cause problems? Even better, is there another way of doing this?
You can call _exit() instead.
Within the Notes section of the man page:
The function _exit() is like exit(), but does not call any functions registered with atexit() or on_exit().
This should avoid the "recursive" issue that is being warned about in the POSIX spec. If you are somehow able to guarantee that your "exit code changing" exit handler runs last, this should work perfectly, modulo the caveats also listed in the Notes:
Whether it flushes standard I/O buffers and removes temporary files created with tmpfile(3) is implementation-dependent. On the other hand, _exit() does close open file descriptors, and this may cause an unknown delay, waiting for pending output to finish. If the delay is undesired, it may be useful to call functions like tcflush(3) before calling _exit(). Whether any pending I/O is canceled, and which pending I/O may be canceled upon _exit(), is implementation-dependent.