C / interrupted system call / fork vs. thread

I found a problem with the implementation of threads, this is strange for me. Maybe some of you can explain this to me, it would be great.

I am working on a proxy server, a program (on different machines) that receives packets through eth0 and sends it through ath0 (wireless) to another machine that does the same. Actually, I'm not at all sure what causes my problem, because I'm new to Linux and programming.

I run two threads

  • one listens (socket) on eth0 for incoming packets and sends it through ath0 (also socket)
  • and another thread listens on ath0 and sends through eth0.

If I use streams, I get this error:

sh-2.05b# ./socketex Failed to send network header packet. : Interrupted system call 

If I use fork (), the program works as expected. Can someone explain this behavior to me?

Just to show the sender implementation, here is a snippet of code:

 while(keep_going) { memset(&buffer[0], '\0', sizeof(buffer)); recvlen = recvfrom(sockfd_in, buffer, BUFLEN, 0, (struct sockaddr *) &incoming, &ilen); if(recvlen < 0) { perror("something went wrong / incoming\n"); exit(-1); } strcpy(msg, buffer); buflen = strlen(msg); sentlen = ath_sendto(sfd, &btpinfo, &addrnwh, &nwh, buflen, msg, &selpv2, &depv); if(sentlen == E_ERR) { perror("Failed to send network header packet.\n"); exit(-1); } } 

UPDATE : my main file, starting a thread or processes (fork)

 int main(void) { port_config pConfig; memset(&pConfig, 0, sizeof(pConfig)); pConfig.inPort = 2002; pConfig.outPort = 2003; pid_t retval = fork(); if(retval == 0) { // child process pc2wsuThread((void *) &pConfig); } else if (retval < 0) { perror("fork not successful\n"); } else { // parent process wsu2pcThread((void *) &pConfig); } /* wint8 rc1, rc2 = 0; pthread_t pc2wsu; pthread_t wsu2pc; rc1 = pthread_create(&pc2wsu, NULL, pc2wsuThread, (void *) &pConfig); rc2 = pthread_create(&wsu2pc, NULL, wsu2pcThread, (void *) &pConfig); if(rc1) { printf("error: pthread_create() is %d\n", rc1); return(-1); } if(rc2) { printf("error: pthread_create() is %d\n", rc2); return(-1); } pthread_join(pc2wsu, NULL); pthread_join(wsu2pc, NULL); */ return 0; } 

Does it help?

update 05/30/2011

 -sh-2.05b# ./wsuproxy 192.168.1.100 mgmtsrvc mgmtsrvc Failed to send network header packet. : Interrupted system call 13.254158,75.165482,DATAAAAAAmgmtsrvc mgmtsrvc mgmtsrvc 

Still get the interrupted system call, as you can see above. I blocked all signals as follows:

 sigset_t signal_mask; sigfillset(&signal_mask); sigprocmask(SIG_BLOCK, &signal_mask, NULL); 

Two threads work on the same interfaces, but on different ports. It seems that the problem remains in the same place (please find it in the first code snippet). I cannot go further and not enough to know how to solve this problem. Maybe some of you can help me here again.

Thanks in advance.

+4
source share
2 answers

EINTR alone does not indicate an error. This means that your process received a signal when it was in syscall sendto , and that syscall has not yet sent any data (which is important).

You can retry sending in this case, but it would be nice to find out which signal caused the interrupt. If this is reproducible, try using strace .

If you are the one who sends the signal, well, you know what to do :-)

Note that on linux you can get the EINTR on sendto (and some other functions) even if you yourself did not install the handler. This can happen if:

the process stops (for example, via SIGSTOP) and restarts (with SIGCONT) you set the send timeout to the socket (via SO_SNDTIMEO)

See the signal(7) man page (at the bottom) for more information.

So, if you “pause” your service (or something else), EINTR is expected, and you must restart the call.

+6
source

Keep in mind, if you use streams with signals that this signal, when it is delivered to the process, can be delivered to any stream whose signal mask does not block the signal. This means that if you blocked incoming signals in one thread, and not in another, a non-blocking thread will receive a signal, and if there is no signal handler setting for the signal, you will get the default behavior of this signal for the whole process (i.e. all threads, both signal blocking streams and non-signal streams). For example, if the default behavior for the signal was to terminate the process, a single thread that caught this signal and executes its default behavior will terminate the entire process for all threads, although some threads may mask the signal. Also, if you have two threads that do not block the signal, it is not determined which thread will process the signal. Therefore, it usually happens that mixing signals and streams is not a good idea, but there are exceptions to the rule.

One thing you can try is that the signal mask for the generated stream is inherited from the generating stream, is to create a daemon stream for signal processing, where at the beginning of your program you block all incoming signals (or at least not all important signals), and then create your threads. Now these spawned threads will ignore any incoming signals in the mask of the blocked signal of the parent stream. If you need to process some specific signals, you can still make these signals part of a blocked signal mask for the main process, and then spawn your threads. But when you create threads, leave one thread (it might even be the main thread of the process after it spawned all the worker threads) as a daemon thread waiting for these specific incoming (and now blocked) signals using sigwait() . Then this thread sends any functions necessary when a given signal is received by the process. This will allow you to avoid signals from interrupting system calls in your other workflows, but still allow you to process the signals.

The reason your forked version may not have a problem is because if a signal comes in one parent process, it does not apply to any child processes. Therefore, I would try, if possible, to see what signal this will stop your system call, and in your streaming version block this signal, and if you need to process it, create a daemon thread that will process this signal arrival, and the rest of the streams will block this signal.

Finally, if you do not have access to any external libraries or debuggers, etc., to see what signals are coming in, you can set up a simple procedure to see which signals can arrive. You can try this code:

 #include <signal.h> #include <stdio.h> int main() { //block all incoming signals sigset_t signal_mask; sigfillset(&signal_mask); sigprocmask(SIG_BLOCK, &signal_mask, NULL); //... spawn your threads here ... //... now wait for signals to arrive and see what comes in ... int arrived_signal; while(1) //you can change this condition to whatever to exit the loop { sigwait(&signal_mask, &arrived_signal); switch(arrived_signal) { case SIGABRT: fprintf(stderr, "SIGABRT signal arrived\n"); break; case SIGALRM: fprintf(stderr, "SIGALRM signal arrived\n"); break; //continue for the rest of the signals defined in signal.h ... default: fprintf(stderr, "Unrecognized signal arrived\n"); } } //clean-up your threads and anything else needing clean-up return 0; } 
+3
source

All Articles