fork() is used to create a child process...and you see this call appear in the child process as well. I don't understand what it means when they say that 'calls to fork actually return twice'.
And what does this mean...
if (fork() == 0)
/* the child process's thread executes here*/
else
/*the parent process's thread executes here*/
Is the above code part of parent or child. Can you explain in plain English what's going on?
Also, why use a fork()? It says all processes in unix run by this system call? How do you fork() so other programs can run? Do you specify the name of the program?
It's a bit like this:
Process 1 Process 2
int main() {
...
int x = goo();
...
int y = fork();
// fork() returns... // ... but also here!
// here y = 123 // here y = 0
if (y) { if (y) {
// this happens // false
} else { } else {
// false // this happens
} }
int z = baz(); int z = baz();
... ...
return 0; return 0;
} }
When Process 2 comes to life, the program exists twice, and the second process starts with the return of fork(). Since the program is the same in both processes, the only way to distinguish which process you're in is by the return value of fork().
What the mean when they say it returns twice is that the call returns once in the parent process (which called it), and once in the child process (which didn't, although you could probably argue that the child inherited the act of calling fork from the parent just like it inherited so much else).
The code snippet takes advantage of the fact that get a different return value from fork depending on whether you're the parent process or the child process.
The child process gets zero and the parent process gets the non-zero process ID of the child.
You can also get back -1 if the fork fails for some reason, in which case the child won't be running. That's something you should probably check as well.
And, while fork is used to create new processes, it's the exec family of calls which load new programs into those processes: fork on its own cannot do that.
A good overview of the process can be found here.
Related
I thought, if I didn't call the ev_loop_fork in the child, then the watcher in child wouldn't be triggered.
This is my code, I build the ev_loop with EVBACKEND_EPOLL and EVFLAG_NOENV flags.
So there is no EVFLAG_FORKCHECK flag.
Then I comment the ev_loop_fork call in the child.
If everything goes well, I thought the child will not trigger the timeout callback function.
But actually, the output is something like this:
$ 4980 fork 4981
$ time out at 4980
$ time out at 4981
it seemed that the watchers still has been triggered in the child, it behaved the same as call ev_loop_fork .
So what's the problem, thank you.
#include<ev.h>
#include<stdio.h>
#include<unistd.h>
void timeout_cb(EV_P_ ev_timer *w,int revents)
{
printf("time out at %d\n", getpid());
ev_break(EV_A_ EVBREAK_ONE);
}
int main()
{
int ret;
ev_timer timeout_watcher;
struct ev_loop *loop = ev_default_loop(EVBACKEND_EPOLL | EVFLAG_NOENV);
ev_timer_init(&timeout_watcher,timeout_cb,5.5,0.);
ev_timer_start(loop,&timeout_watcher);
ret = fork();
if(ret>0) printf("%d fork %d\n",getpid(),ret);
else if(ret==0)
{
//ev_loop_fork(EV_DEFAULT);
}
else return -1;
ev_run(loop,0);
return 0;
}
The libev manual does not say that after a fork an event loop will be stopped. All it says is that to be sure that the event loop will properly work in the child, you need to call ev_loop_fork(). What's actually happening depends on the backend.
And technically, timers will even be more resilient against forks in most backends: select(), poll(), epoll(), kqueue all allow for specification of a timeout value after which these functions return in case of no event. libev uses this feature to be able to trigger timeouts when they are supposed to be triggered. So there's no need to re-register any file descriptors for timeouts to work.
I came across a stripped down shell program in Tannenbaum's book on MINIX.
while(1) {
read_command(command, parameters);
if (fork() != 0)
wait(&status); /* parent code */
}
else {
execve(command, parameters, 0); /* child code */
}
}
When the infinite loop executes its first iteration, fork() will return 0 indicating it created a child process, when it executes the second time, wont fork() create a new child process ? How wait(&status) will ever execute?
I am new to understanding how an OS works/is built.
Thanks!
fork creates a new process immediately, so both processes see fork return, but with different return values. In the parent, the return value is the non-zero process ID of the child, so the parent executes wait. In the child, fork returns 0, so the child executes execve.
I've just recently learned about pipes and I would like to emulate the "|" gimmick provided by shells.
In the code below, the parent process spawns 2 child processes, after which they do their piping and get replaced by ls and grep. While that happens the parent process waits patiently. The problem is that the child processes never finish although they manage to send some data though the pipe and onto the screen.
There are other posts regarding pipes on SO, but I've never seen the setup in which the parent process launches 2 children. I've only seen the parent communicating with one child.
int p0[2];
pipe(p0); //creating pipe
if(fork() == 0) { //child 1
dup2(p0[0], STDIN_FILENO);
close(p0[0]); close(p0[1]);
execlp("grep","grep","a",NULL);
}
else { //parent
if(fork() == 0) { //child 2
dup2(p0[1], STDOUT_FILENO);
close(p0[0]); close(p0[1]);
execlp("ls","ls",NULL);
}
else { //parent
wait(NULL);
wait(NULL); //waiting for c1 and c2
close(p0[0]); close(p0[1]);
printf("parent exit\n");
}
}
My questions are: Why don't the child processes finish? Is fork-pipe structure sound or am I doing it completely wrong?
Close the pipe before starting to wait in the last section.
So I've got a problem with my code and it's driving me nuts since I can't seem to figure out what's causing this. Basically, I'm trying to write to a file that I have open, using multiple child processes with fork(). Before I start forking, I can write to it just fine, but once I fork and THEN do an if statement to see if it's the child process, it won't write.
Basically, what I have is this:
FILE *output = NULL;
output = fopen(...); // Done successfully
fprintf(output, "This writes okay\n");
// Fork n processes
for (i = 0; i <= n; n++)
{
pid[i] = fork();
fprintf(output, "We can still write\n");
if (pid[i] == 0) // Child process
{
fprintf(output, "This won't write to output\n");
printf("I can still write and calculate stuff otherwise\n");
...
}
}
Can anyone figure out why it's not able to write after checking to see if it's a child process? There's definitely no error with forking from what I've seen.
Opening a file descriptor and using it in more than one process (for example in both a parent and child process) is a race condition and will most likely cause problems and unpredictable behavior.
I want to implement a scheduler class, which any object can use to schedule timeouts and cancel then if necessary. When a timeout expires, this information will be sent to the timeout setter/owner at that time asynchronously.
So, for this purpose, I have 2 fundamental classes WindowsTimeout and WindowsScheduler.
class WindowsTimeout
{
bool mCancelled;
int mTimerID; // Windows handle to identify the actual timer set.
ITimeoutReceiver* mSetter;
int cancel()
{
mCancelled = true;
if ( timeKillEvent(mTimerID) == SUCCESS) // Line under question # 1
{
delete this; // Timeout instance is self-destroyed.
return 0; // ok. OS Timer resource given back.
}
return 1; // fail. OS Timer resource not given back.
}
WindowsTimeout(ITimeoutReceiver* setter, int timerID)
{
mSetter = setter;
mTimerID = timerID;
}
};
class WindowsScheduler
{
static void CALLBACK timerFunction(UINT uID,UINT uMsg,DWORD dwUser,DWORD dw1,DWORD dw2)
{
WindowsTimeout* timeout = (WindowsTimeout*) uMsg;
if (timeout->mCancelled)
delete timeout;
else
timeout->mDestination->GEN(evTimeout(timeout));
}
WindowsTimeout* schedule(ITimeoutReceiver* setter, TimeUnit t)
{
int timerID = timeSetEvent(...);
if (timerID == SUCCESS)
{
return WindowsTimeout(setter, timerID);
}
return 0;
}
};
My questions are:
Q.1. When a WindowsScheduler::timerFunction() call is made, this call is performed in which context ? It is simply a callback function and I think, it is performed by the OS context, right ? If it is so, does this calling pre-empt any other tasks already running ? I mean do callbacks have higher priority than any other user-task ?
Q.2. When a timeout setter wants to cancel its timeout, it calls WindowsTimeout::cancel().
However, there is always a possibility that timerFunction static call to be callbacked by OS, pre-empting the cancel operation, for example, just after mCancelled = true statement. In such a case, the timeout instance will be deleted by the callback function.
When the pre-empted cancel() function comes again, after the callback function completes execution, will try to access an attribute of the deleted instance (mTimerID), as you can see on the line : "Line under question # 1" in the code.
How can I avoid such a case ?
Please note that, this question is an improved version of the previos one of my own here:
Windows multimedia timer with callback argument
Q1 - I believe it gets called within a thread allocated by the timer API. I'm not sure, but I wouldn't be surprised if the thread ran at a very high priority. (In Windows, that doesn't necessarily mean it will completely preempt other threads, it just means it will get more cycles than other threads).
Q2 - I started to sketch out a solution for this, but then realized it was a bit harder than I thought. Personally, I would maintain a hash table that maps timerIDs to your WindowsTimeout object instances. The hash table could be a simple std::map instance that's guarded by a critical section. When the timer callback occurs, it enters the critical section and tries to obtain the WindowsTimer instance pointer, and then flags the WindowsTimer instance as having been executed, exits the critical section, and then actually executes the callback. In the event that the hash table doesn't contain the WindowsTimer instance, it means the caller has already removed it. Be very careful here.
One subtle bug in your own code above:
WindowsTimeout* schedule(ITimeoutReceiver* setter, TimeUnit t)
{
int timerID = timeSetEvent(...);
if (timerID == SUCCESS)
{
return WindowsTimeout(setter, timerID);
}
return 0;
}
};
In your schedule method, it's entirely possible that the callback scheduled by timeSetEvent will return BEFORE you can create an instance of WindowsTimeout.