1

I have a program that have many threads. Some threads are TCP servers... Each server fires new threads to handle any new connections.

Inside one of the threads that handles a single client, I call fork(). The child process calls setpgid() (to create a new group) and then system() (the function of C/C++ standard library). The parent process keeps taking naps (usleep() function) and checking a time limit. If the time limit is exceeded before child process returns from system(), the parent SIGKILLs the child.

I'm using: Linux (Ubuntu), pthreads, etc. Nothing but C/C++ standard library!

My questions: what happens with all the threads and TCP sockets on the child process? Are these things inherited from the parent process? Will both child and parent run all these threads and TCP servers simultaneously? It would make no sense to me... And when parent SIGKILLs child, will the sockets be closed only inside child, or also in the parent?

Currently, I'm actually using exec() to clean the whole image of the child process, but I'd rather call system() directly if it's safe.

3
  • Or prevent them from being inherited, if you have that ioctl() option available to you. Commented Sep 3, 2015 at 2:47
  • @AndrewMedico, the child image has only one running thread. Commented Sep 3, 2015 at 13:44
  • Just to clarify @EJP's remark, ioctl(FIOCLEX) (or its more portable cousin, fcntl(FD_CLOEXEC)) will close descriptors across exec but not across a fork. In the case where your child program system()s, the child itself would still have open fds inherited from the parent. Commented Sep 3, 2015 at 14:13

1 Answer 1

3

File descriptors (a.k.a. fds) such as TCP sockets are inherited across a fork. The file or device "behind" them generally remains open and serviceable until the last file descriptor to it is closed or dismissed at process termination. Thus SIGKILL'ing the child won't affect the TCP sockets shared with the parent.

Only the fork()ing thread is executing in the child, however. The other threads of control are not copied. Your situation looks something like this:

+-- PID 100 -------------+ # parent | fds: 0, 1, 2, 3 ... N | # fds: stdin, stdout, stderr, socket ... socket | threads: | | 0 (main) | | 1 (tcp server) | | 2 (forky) ---------(fork(2))-+ | ... | | | N (tcp server) | | +------------------------+ | | | +-- PID 101 -------------+ # child | fds: 0, 1, 2, 3 ... N | # fds: inherited | threads: | | 0 (copy of forky) | # will exec() ? +------------------------+ 

Calling exec will replace the PID 101 process image with some text's main() (and close any file descriptors marked FD_CLOEXEC). Calling system("whatever"), by contrast, would probably spawn at least two more processes: a (grand)child /bin/sh and a (great) grandchild "whatever".

It's very easy to confound yourself mixing threads, forks, and shared resources, especially if old, old interfaces like system() are thrown into the mix. Go slowly, explicitly discard resources you don't need when you don't need them, and troubleshoot one thing at a time.

Sign up to request clarification or add additional context in comments.

3 Comments

What happens when Linux receives a TCP segment? It forwards to both PID 100 and PID 101? If only "copy of forky" is running on PID 101, PID 101 won't be able to catch any data from any TCP sockets, right? But, could it? If, for instance, "copy of forky" has the file descriptor, coult it call accept() and successfully handle a TCP connection? Like, two processes handling the same TCP server! Oh my god!
But, is it okay if I don't touch any descriptors or any network syscalls or whatever inside PID 101? My system is working well... I'm just afraid of future problems. PID 101 only exists to call system() and then die immediately.
That's why I call exit(system(cmd)), hahaha.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.