System() Calls in C++ and Their Roles in Programming

System() calls in C++ and their roles in programming

system("PAUSE") is certainly less than ideal. using a call to system creates a subprocess, which on windows is fairly expensive and in any case not terribly cheap on any operating system. On embedded systems the memory overhead is significant.

If there is any way to do it without much pain natively then do it. In the case of waiting for the user to press a single button, cin.get() will be very hard to beat. In this case, your applications process will just block on stdin, setting only a few flags visible to the kernel, and most importantly, allocates no new memory and creates no new scheduling entities, not even an interrupt handler.

Additionally, it will work the same on all operating systems with all c++ compilers, since it uses only a very basic feature of a very standard part of the language, rather than depend on anything the OS provides.

EDIT: predicting your concern that it doesn't matter if it's expensive because the whole idea is to pause. Well, first off, if its expensive, then it's going to hurt performance for anything else that might be going on. Ever notice (on windows) when one application is launching, other, already open apps become less responsive too? Additionally, your user might not be a live human, but rather another program working on behalf of a human user (Say, a shell script). The script already knows what to do next and can pre-fill stdin with a character to skip over the wait. If you have used a subprocess here, the script will experience a (noticeable to a human) delay. If the script is doing this hundreds (or hundreds of millions!) of times, a script that could take seconds to run now takes days or years.

EDIT2: when to use system(): when you need to do something that another process does, that you can't do easily. system() isn't always the best candidate because it does two things that are somewhat limiting. First, the only way to communicate with the subprocess is by command line arguments as input and return value as output. The second is that the parent process blocks until the child process has completed. These two factors limit the cases in which system is useable.

on unixy systems, most subprocesses happen with fork because it allows the same program to continue in the same place as two separate processes, one as a child of the other (which is hardly noticeable unless you ask for it from the OS). On Linux, this is especially well optimized, and about as cheap as creating a pthread. Even on systems where this is not as fast, it is still very useful (as demonstrated by the apache process-pool methodology) (unavailable on windows/link to unix docs)

other cases (on windows too!) are often handled by popen or exec family of functions. popen creates a subprocess and a brand new pipe connecting to the subprocesses' stdin or stdout. Both parent and child processes can then run concurrently and communicate quite easily. (link to windows docs/link to unix docs)

exec* family of functions (there are several, execl, execv and so on) on the other hand causes the current program to be replaced by the new program. The original program exits invisibly and the new process takes over. When then new process returns, it will return to whatever called the original process, as if that process had returned at that point instead of vanishing. The advantage of this over exit(system("command")) is that no new process is created, saving time and memory (though not always terribly much) (link to windows docs /link to unix docs)

system could plausibly be used by some scripted tool to invoke several steps in some recipe action. For example, at a certain point, a program could use system to invoke a text editor to edit some configuration file. It need not concern itself too much with what happens, but it should certainly wait until the user has saved and closed the editor before continuing. It can then use the return value to find out if the editing session was successful, in the sense that the editor actually opened the requested file (and that the editor itself existed at all!), but will read the actual results of the session from the edited file directly, rather than communicating with the subprocess. (link to windows docs/link to unix docs)

system calls in C

  1. Check the result of system() ALWAYS. Ensure that it executed successfully(ie. returns 0 or whatever is a successful result for 'test')
  2. When system executes it runs through /bin/sh (on unix/linux anyway). However since you're specifying it with './test' make sure that you're operating in the working directory that you THINK you are. Complex systems(and poorly designed ones) change directories like underwear.

Can a system call happen in a C program?

System call background

A system call, according to Wikipedia, is a "programmatic way in which a computer program requests a service from the kernel of the operating system on which it is executed".

Another way of understanding a system call is as a user space program making a request to the operating system kernel to perform some task on behalf of the user space program. The full set of system calls provided by the kernel is analogous (in some ways) to an API provided by the kernel to user space.

As system calls are a low level interface to the kernel, correctly providing their arguments can be error prone or even dangerous. For these reasons, C library authors provide simpler and safer wrapper functions for a significant portion of a kernel's set of system calls.

These wrapper functions take a simplified argument set and then derive the appropriate values to pass on to the kernel so the system call can be executed.

Example

Note: This example is based on compiling and running a C program with gcc on Linux. The system calls, library functions, and output may differ on other POSIX or non-POSIX operating systems.

I will attempt to show how to see when system calls are being made with a simple example.

#include <stdio.h>

int main() {
write(1, "Hello world!\n", 13);
}

Above we have a very simple C program that writes the string Hello world!\n to stdout. If we compile and then execute this program with strace, we see the following (note the output may look different on other computers):

$ strace ./hello > /dev/null
execve("./hello", ["./hello"], 0x7fff083a0630 /* 58 vars */) = 0
<a bunch of output we aren't interested in>
write(1, "Hello world!\n", 13) = 13
exit_group(0) = ?
+++ exited with 0 +++

strace is a Linux program that intercepts and displays all system calls made by a program, as well as the arguments provided to the system calls and their return values.

We can see here that, as expected, the write system call was made with the expected arguments. Nothing strange yet.

Another Linux tracing program is ltrace, which intercepts dynamic library calls made by a program, and displays their arguments and return values.

If we run the same program with ltrace, we see this:

$ ltrace ./hello > /dev/null
write(1, "Hello world!\n", 13) = 13
+++ exited (status 0) +++

This tells us that the write library function was executed. This means that the C code first called the write library function, which then in turn called the write system call.

Suppose now that we want to explicitly make a write system call without calling the write library function. (This is inadvisable in normal use, but useful for illustration.)

Here is the new code:

#include <stdio.h>
#include <unistd.h>
#include <sys/syscall.h>

int main() {
syscall(SYS_write, 1, "Hello world!\n", 13);
}

Here we directly call the syscall library function, telling it we want to execute the write system call.

After recompiling, here is the output of strace:

$ strace ./hello > /dev/null 
execve("./hello", ["./hello"], 0x7ffe3790a660 /* 58 vars */) = 0
<a bunch of output we aren't interested in>
write(1, "Hello world!\n", 13) = 13
exit_group(0) = ?
+++ exited with 0 +++

We can see the write system call is made as before as expected.

If we run ltrace we see the following:

$ ltrace ./hello > /dev/null 
syscall(1, 1, 0x560b30e4d704, 13) = 13
+++ exited (status 0) +++

So the write library function is no longer being called, but we are still making a library function call. Now we are making a call to the syscall library function instead of the write library function.

There may be a way to directly make a system call from a user space C program without calling any library functions, and if there is a way I believe it would be very advanced.

Detecting when a C program makes system calls

In general, nearly every non-trivial C program makes at least one system call. This is because user space does not have direct access to kernel memory or to the computer's hardware. User space programs have indirect access to kernel memory and the hardware through system calls.

To identify if a compiled C program (or any other program on Linux) makes a system call, and to identify which system calls it makes, simply use strace.

Are there compiler options to prevent calling the library wrapper functions for system calls?

You can compile your C program (assuming you are using gcc) with the -nostdlib option. This will prevent linking the C standard library as part of producing your executable. However, then you would need to write your own code to make system calls.

system call in read and write functions

The system calls are expensive, therefore the standard IO library postpones them as much as possible, e.g. by internally buffering the output. When it cannot buffer anymore, it finally invokes a system call.

This buffer is normally associated with the FILE pointer, so the rule of thumb is that the function taking FILE * does buffering, and the function taking the raw int file descriptor does a system call. It is just a convention, no more.

The Posix nomenclature tries to prefix the standard IO routines with f, such as fwrite, whereas the raw system call is write (same for fopen vs open, etc). There is noting special about parameters, it is in a name.

Are there downsides to using calls to system() instead of your programming language's functions?

At the end of the day, on a Linux system, pretty much everything is calling C functions at some point.

To touch on some of the arguments in comments as well as my own thoughts:

  1. Executing shell commands from a c program, especially when using user arguments, is a potential vulnerability. Example would be if you allowed the user to call your program with the argument "foo; rm -rf *"; depending on how you invoke the shell, there's the potential you could effectively call "mkdir foo; rm -rf *" if you wanted to make the directory the user provided. This may or may not be a big deal depending on how you trust your users etc.
  2. Executing shell commands leads to potential race conditions that you can't avoid that might be more easily dealt with using straight system calls that you chain together
  3. Parsing output of commands means dealing with more string operations in C, which is less than fun.
  4. If you really prefer bash, your best bet is to probably implement small programs which wrap discrete portions of your target library's C API. This is the UNIX way(tm) anyways.

EDIT to address Pimgd's comment: Note that race conditions are a pain in the neck and a lot of them aren't necessarily an issue for your particular use case, but are at least worth considering when weighing pro's/con's. Anyways, the specific race-condition instances I was thinking about include (and there are likely other classes):

  1. Security type race conditions. If you create a temp file containing a set of commands and then execute it, there is the possibility that between creation and execution, someone goes in and modifies the file. (There are actually a variety of variations on this theme for things like setting/resetting sym links etc.). Based on your above comments, this is pretty much outside the scope of your project, but is something to be aware of for other applications.
  2. Multi-process race conditions. The simplest example I can think of is what happens if two instances of your program want to set a configuration file and are running at the same time. There are certain OS calls which have certain levels of guarantee on atomicity, but you lose a lot of that if you call a series of shell commands to write to the file. (note that even if you do it from a monolithic C application versus a series of shell commands, you still would need to do something extra to prevent instance 1 from overwriting instance 2's change, but you're at least not likely to run into the case that you end up having changes intermixed. As an example consider:

    FILE *fp = fopen("config.txt","wt");

    fprintf(fp,"Config value 1: %s",config[0]);

    fprintf(fp,"Config value 2: %s",config[1]);

    fflush(fp);

    fclose(fp);

vs.

system("echo Config value 1: `df | awk '{print $1}'` > config.txt");
system("echo Config value 2: `ps | grep foo | awk '{print $2}'` >> config.txt");

Where, if two instances of the program run at close to the exact time, you can end up with e.g. 2 instances of Config value 2 in the config file in the latter case.

When can I call a function in C as a system call

General Information

  • A system call is basically an interface of your application to the OS kernel.
  • System calls are usually wrapped by the wrapper function provided by the platform's standard library.

Sometimes the system call name and the wrapper function names are same, sometimes they are not.

Usually, the wrapper functions provided by the standard library provides some extra feature and/or sanity checking/ error checking for the underlying system call.

system calls are the bare minimum calls that is passed to the kernel, which executes in kernel-mode and returns the required result to the user-space application.

For each kernel versions, there are defined set of system calls available and are usually represented by a number associated with each call. Ready referecnce : arch/i386/kernel/entry.S file (look for sys_call_table)

OTOH, the library functions, provided by standard [or non-standard] libraries are simple APIs which are used to provide access to various functions , including system calls in a bit easy way for the developer. These are used to hide some complex parts, provide some additional checks, some error handling and finally calls the internal function, mostly underlying system calls.


Answer to your question

open() is a system call.

fopen() is a wrapper provided by the standard library [linux glibc, for example].

Check more details in syscalls manual page.

How system function in C works

this is basis of fork

/*previous code*/
if((cpid=fork())<0){
printf("\n\tFORK ERROR");
exit(1);
}

if(cpid==0){ /*SON*/
/*CODE FOR SON-your `execl("./infinite",0);` goes here*/

}else{ /*FATHER*/

/*CODE FOR FATHER-your `printf("In controller End\n\n");` */

}

dont forget that when making a fork memory and variables are copied to the SON pid



Related Topics



Leave a reply



Submit