Learn how to a build a cloud-first strategyRegister Now

x
  • Status: Solved
  • Priority: Medium
  • Security: Public
  • Views: 422
  • Last Modified:

Cannot exit process when main thread is in an accept call.

In my multi-threaded application, the main thread sits in a while loop waiting for something to be received on a socket (the app is a TCP/IP server).  I create a new thread whenever I receive data from a socket.  My new thread then looks at the content of the data that came off the socket.  This data may contain an "exit" request.  When I get this request, I simply call exit to terminate the application.  While this was happening, back in the main thread, I have looped back around to wait for the next request.  So essentially, the main thread is sitting in 'accept' at the same time I'm trying to exit the application.  The child thread exits ok, but it does not exit the application, because it cannot interrupt accept.  Is this normal behaviour?  I thought that calling exit would terminate the app immediately.  How can I interrupt the accept call and cause the app to exit?  Thanks.
0
mromeo
Asked:
mromeo
  • 9
  • 4
  • 3
  • +1
1 Solution
 
grg99Commented:
It depends on the OS I think.

This was a long time ago, but IIRC, on Unix:

You could send a signal to the main app.  Any kind of signal.   If the main app was in a system call at the time, what happens is, the system call gets aborted, the signal handler gets called, then the system call returns the generic error "INTERRUPTED_SYSTEM_CALL".  In most cases you want to just repeat the system call, but in your case you want to check some flag that the exiting thread set, end then just exit the main program.    I don't know if other OS's do this the same way, but I suspect so.


0
 
mromeoAuthor Commented:
I'm using HP-UX 11.00.  My exact code works on Linux and Solaris.  Thus far, HP-UX has been a not-so-friendly OS for me.  I'll give your suggestion a try.
0
 
mromeoAuthor Commented:
This doens't work. I tried sending a SIGTERM, but my signal handler never got called.  It works if I put it in a small sample application, but not if I am in my code.  Perhaps it's still not interrupting 'accept.'  I did the following:

In main:

    main(...)
    {
           signal(SIGTERM, term_handler);
     }

    void term_handler(int sig)
    {
         printf("got term signal...\n");
         exit(0);
     }

In some thread:
     kill(getpid(), SIGTERM);



0
VIDEO: THE CONCERTO CLOUD FOR HEALTHCARE

Modern healthcare requires a modern cloud. View this brief video to understand how the Concerto Cloud for Healthcare can help your organization.

 
jkrCommented:
Have you tried to 'pthread_kill()' the thread that is sitting on 'accept()'?
0
 
mromeoAuthor Commented:
Yes, I tried that, too, with no success.  
0
 
grg99Commented:
How about you have the thread close the accept()ing socket?   Dirty, but might work.

0
 
mromeoAuthor Commented:
I'm doing that already.  I don't think it'll close until it becomes unblocked.  
0
 
van_dyCommented:
>>  I tried sending a SIGTERM, but my signal handler never got called.

what is your signal handler supposed to do?
can you post the code for it? the default
action of SIGTERM is to terminate the process.
if that is what you want, why would you install
a handler for SIGTERM (to do cleanup?).
As far as interrupted system calls go, most
operating systems usually restart an interrupted
system call once a signal handler returns.
0
 
mromeoAuthor Commented:
All it does is print a message and then call exit(0).  I just wanted to test that it was happening.  I took that code out when I realized that calling exit from there doesn't work either.  It appears that accept cannot be interrupted, but I'm hoping that I'm wrong about this.
0
 
van_dyCommented:
>>It appears that accept cannot be interrupted
accept() can be interrupted like any other
slow system call(for example recv()).

can you post more of your code, mostly the main()
function(around where you call accept and create the
thread) and function that you call from your thread
to process the input from the socket?
0
 
mromeoAuthor Commented:
Ok, I'll do my best.  Needed to cut out senstive code:

myfunc()
{
  // create socket
   if ((g_brokerSockfd = socket(AF_INET, SOCK_STREAM, 0)) == -1)
   {
      perror("socket");
      exit(1);
   }

   // and set socket options.
   if (setsockopt(g_brokerSockfd,SOL_SOCKET,SO_REUSEADDR,&yes,sizeof(int))==-1)
   {
      perror("setsockopt");
      exit(1);
   }

   // Setup address
   my_addr.sin_family = AF_INET;    // host byte order
   my_addr.sin_port = htons(portNum);  // short, network byte order
   my_addr.sin_addr.s_addr = INADDR_ANY;// automatically fill with my IP
   memset(&(my_addr.sin_zero), '\0', 8); // zero the rest of the struct
   if (bind(g_brokerSockfd, (struct sockaddr *)&my_addr, sizeof(struct sockaddr)) == -1)
   {
      perror("bind");
      exit(1);
   }

   if (listen(g_brokerSockfd, 0 /*BACKLOG*/) == -1)
   {
      perror("listen");
      exit(1);
   }

   sa.sa_handler = sigchld_handler; // reap all dead processes
   sigemptyset(&sa.sa_mask);
   sa.sa_flags = SA_RESTART;
   while(1)    // main accept() loop
   {
      sin_size = sizeof(struct sockaddr_in);
      if ((new_fd = accept(g_brokerSockfd, (struct sockaddr *)&their_addr,
         &sin_size)) == -1)
      {
         perror("accept");
         continue;
      }

      printf("\nSERVER: got connection from IP addr: %s   Port: %d\n",
                     inet_ntoa(their_addr.sin_addr), their_addr.sin_port);

      pthread_t tid;
      int ret;
      pthread_attr_t thAttrs;

      pthread_attr_init(&thAttrs);
      pthread_attr_setdetachstate(&thAttrs, PTHREAD_CREATE_DETACHED);

      // create a new deatched thread which will start executing in
      // the ProcessRequest function.  Creating it detached will free
      // up resource when it exits.

      ret = pthread_create(&tid, &thAttrs, ProcessRequest, (void *)new_fd);

      pthread_attr_destroy(&thAttrs);
}

void *ProcessRequest(void *arg)
{
   char           buf[MAXDATASIZE];
   int            numbytes;
   char           cliUserId[128];
   int            requestNum;
   int            requestParam;
   int            param;
   char           *responseBuf = NULL;
   SOCKET     sock_fd = (int)arg;     // socket's file descriptor
   char           logStr[MAX_STR];

   if ((numbytes = RecvFromSocket(sock_fd, buf, MAXDATASIZE-1)) == -1)
   {
      perror("recv");
      CloseSocket(sock_fd);
      exit(1);
   }

   buf[numbytes] = '\0';
   sprintf(logStr, "Server Received [%s]", buf);
   Log(logStr);

   if (ParseRequest(buf, cliUserId, &requestNum, &requestParam))
   {
      rdtMutex.Lock();     // only allow one request at a time.
      switch(requestNum)
      {
          ///////  ALL OTHER REQUEST TYPES OMITTED.

         // message came from client app other than rdtXlate
         case _SHUTDOWN_SYS:
         {
            willExit = true;
            responseBuf = new char[100];
            Log("Received system shutdown message");
            sprintf(responseBuf, "successfully shutdown.");
            break;
         }
    }

     rdtMutex.Unlock();

      if (responseBuf != NULL)
      {
         if (SendToSocket(sock_fd, responseBuf, strlen(responseBuf)) == -1)
         {
            perror("send");
         }
      }
   }

   CloseSocket(sock_fd);

   if (responseBuf != NULL)
   {
       delete [] responseBuf;
   }

   if (willExit)  // user requested server to exit
   {
      CloseSocket(g_brokerSockfd);
      exit(1);    // exits all threads and process
   }

  pthread_exit(NULL);

}
0
 
grg99Commented:
Dont you want to, if accept() returns an error, and shutdown is happening, do an exit instead of a continue?

0
 
van_dyCommented:
oh well,
grg99 already said it.
may be you should change the part of code

 if ((new_fd = accept(g_brokerSockfd, (struct sockaddr *)&their_addr,
         &sin_size)) == -1)
      {
         perror("accept");
         continue;
      }

to

 if ((new_fd = accept(g_brokerSockfd, (struct sockaddr *)&their_addr,
         &sin_size)) == -1)
      {
         if(errno == EINTR)
              exit(1);      //since we want to exit when interrupted by SIGTERM
         perror("accept");
         continue;
      }
0
 
mromeoAuthor Commented:
That doesn't work either.  I even sent a kill(getpid(), SIGINT) from the ProcessRequest function, and it didn't get interrupted.  Can you give me a small sample as to how that would work?
0
 
van_dyCommented:
there are a few problems with the way you
are sending signal to the parent thread (which
is calling accept()). each thread receives signals
seperately. when u send a signal like
kill(getpid(), SIGTERM);
this sends the signal to the thread itself, not the
parent.

to send the signal to a particullar thread you will
have to use pthread_kill() function. Here is a sample
example as you asked for. the main thread waits on accept()
and spawns a thread every time a connection comes. the spawned
thread receives data on the connected socket and signals the parent
if it receives "exit\n" string. please note the manner in which the parent
thread passes its own thread id to each of the threads it creates, so
that they can send it a signal if required.

example:
-----------------

#include <stdio.h>
#include <pthread.h>
#include <stdlib.h>
#include <signal.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <sys/types.h>
#include <errno.h>

#define TRUE 1
#define MAXDATASIZE 1024

typedef struct {          //this structure is passed as arguement to threads
      int new_fd;
      pthread_t parent;
} data;

void *ProcessRequest(void *arg)
{
      char buf[MAXDATASIZE];
      int numbytes;
//      data *passed = arg;

      if ((numbytes = read(((data *)arg)->new_fd, buf, MAXDATASIZE-1)) == -1){
            perror("read");
            close(((data *)arg)->new_fd);
            exit(1);
      }

      buf[numbytes] = 0;
      printf("server received: %s", buf);

      if(!strcmp(buf, "exit\n")){ //\n because i used netcat to send data to thhis server
            printf("Notifying parent");
            pthread_kill(((data *)arg)->parent, SIGINT); // kill the parent thread
      }
      close(((data *)arg)->new_fd);
      return NULL;;
}

int main(int argc, char **argv)
{
      int listenfd, new_fd;
      struct sockaddr_in my_addr, their_addr;
      int yes = 1;
      short portNum = 5555; //some port u want to listen on
      pthread_t self;
      int sin_size;

      self = pthread_self();
      if((listenfd = socket(PF_INET, SOCK_STREAM, 0)) == -1){
            perror("socket");
            exit(1);
      }

      if (setsockopt(listenfd, SOL_SOCKET,SO_REUSEADDR,&yes,sizeof(int))==-1){
            perror("setsockopt");
            exit(1);
      }

      my_addr.sin_family = AF_INET;
      my_addr.sin_port = htons(portNum);
      my_addr.sin_addr.s_addr = INADDR_ANY;
      memset(&(my_addr.sin_zero), '\0', 8);

      if (bind(listenfd, (struct sockaddr *)&my_addr, sizeof(struct sockaddr)) == -1){
            perror("bind");
            exit(1);
      }

      if (listen(listenfd, 5/*BACKLOG*/) == -1){
            perror("bind");
            exit(1);
      }

      while(TRUE){
            data *passit = malloc(sizeof(data));
            pthread_t tid;
            int ret;
            pthread_attr_t thAttrs;
            if ((passit->new_fd = accept(listenfd, (struct sockaddr *)&their_addr, &sin_size)) == -1){
                  if(errno == EINTR){   //true when some signal SIGINT received
                        exit(1);
                  }
                  continue;
            }

            passit->parent = self;
            pthread_attr_init(&thAttrs);
            pthread_attr_setdetachstate(&thAttrs, PTHREAD_CREATE_DETACHED);
            ret = pthread_create(&tid, &thAttrs, ProcessRequest, (void *)passit);
            pthread_attr_destroy(&thAttrs);
      }

      close(listenfd);
      return 0;
}

hope this helps,
van_dy
0
 
mromeoAuthor Commented:
Perfect!  It works beautifully.   Thanks for your patience.
0
 
mromeoAuthor Commented:
Just as an FYI, the BIG mistake that I was making was that I was closing the main socket (g_brokerSockfd) before I was exiting.  This would cause the app to hang.  If I leave the socket open then call pthread_kill, accept gets interrupted as expected.  
0

Featured Post

Independent Software Vendors: We Want Your Opinion

We value your feedback.

Take our survey and automatically be enter to win anyone of the following:
Yeti Cooler, Amazon eGift Card, and Movie eGift Card!

  • 9
  • 4
  • 3
  • +1
Tackle projects and never again get stuck behind a technical roadblock.
Join Now