Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Foolproof forking?

Tags:

c

fork

my C class consists of implementing a very small shell.

Our shell checks the user's input line for internal commands (such as cd or exit), if none are found, it forks() and execs() the input line.

I would wish to implement a foolproof forking (this is way beyond the call of duty for this class, please don't ask me to do my own homework, this is more of a personal research in order to understand more of linux' internals). My current approach is this:

t = fork();             
if (t < 0) {            
  if (errno == ENOSYS) {                                
    printf("fork() is not supported on this platform. Minishell will not work.");
    break;
  }
  else if (errno == ENOMEM) {   
    printf("No free kernel memory. Minishell will exit.");
    break;
  }
  else {        
    int try = 0;
    while (t < 0 && try < 10) {
      try++;
      t = fork();
    }
  }
  continue;
}

My understanding is that ENOSYS does not allow forking, therefore we exit, that ENOMEM denotes kernel memory trouble - way over my paygrade (I ain't paid, I am a student ;) ), therefore we also exit. Remains EAGAIN which comes in two flavours, both of which might be solved by waiting and calling fork() again.

In a previous exercise, we had initiated ten thousand forks, and, if I remember correctly, about 1500 failed, until we implemented a counter like my while above. How could I proceed if I wanted to implement this thing in a less naive way? In particular the hard-coded ten tries are kinda stupid, I suppose.

Thanks.

like image 403
pouzzler Avatar asked Mar 22 '23 17:03

pouzzler


1 Answers

I think that your current approach with the retries is misunderstanding the meaning of the EAGAIN errors for fork. From the Linux man page:

EAGAIN fork() cannot allocate sufficient memory to copy the parent's page tables and allocate a task structure for the child.

EAGAIN It was not possible to create a new process because the caller's RLIMIT_NPROC resource limit was encountered. To exceed this limit, the process must have either the CAP_SYS_ADMIN or the CAP_SYS_RESOURCE capability.

The first is pretty much equivalent to ENOMEM, and the second is an issue of reaching the process cap. Unless you expect your minishell to have children processes dying all the time, trying 10 times in quick succession will probably do nothing.

I'd suggest also making EAGAIN a fatal error for your fork code.

However, if there's something that your program could do to alleviate memory pressure (free your programs caches, etc.), you can do it and try again once.

It's worth saying though that the conditions that would make a fork fail are almost nonexistent on any modern system under normal load.

like image 79
Linuxios Avatar answered Apr 01 '23 13:04

Linuxios