0

I have a client app implemented with OpenMP. This program terminate when it receives a SIGINT signal, but in that case it should first send a message to the server indicating that the user logged out. I have implemented the messaging successfully, but I have been unable to make the program terminate afterward.

Here is the parallel section of my code:

#pragma omp parallel num_threads(4)
{
    #pragma omp sections
    {
        #pragma omp section
        {
            while(1)
            {
                char pom[1000];
                fgets(pom, 1000, stdin);
                if (strlen(pom) != 1)
                {
                    char * buffer;
                    buffer = message(username, pom);
                    if (send(client_socket, buffer, strlen(buffer), 0) < 0)
                    {
                        callError("ERROR: cannot send socked");
                    }
                    bzero(pom, 1000);
                    free(buffer);
                }
            }
        }
        #pragma omp section
        {   
            char buffer[4096];
            char * data;
            ssize_t length;
            int received = 0;
            int data_cap = 4096;
            while(1)
            {
                data = calloc(BUFFER_LEN, sizeof(char));
                while ((length = read(client_socket, buffer, BUFFER_LEN)) > 0)
                {
                    received += length;
                    if (received > data_cap)
                    {
                         data = realloc(data, sizeof(char) * data_cap * 2);
                         data_cap = data_cap * 2;
                    }
                    strcat(data, buffer); 
                    if (!isEnough(data))
                    {
                        break;
                    }
                }
                printf("%s", data);
                free(data);
                bzero(buffer, BUFFER_LEN);
                data_cap = 4096;
                received = 0;
                length = 0;
            }
        }
        #pragma omp section
        {
            void sig_handler(int signo)
            {
                char * welcome1 = calloc(strlen(username) + 13, sizeof(char));
                strcat(welcome1, username);
                strcat(welcome1, " logged out\r\n");
                if (send(client_socket, welcome1, strlen(welcome1), 0) < 0)
                {
                    callError("ERROR: cannot send socked");
                }
                free(welcome1);
            }

            while (1)
            {
                if (signal(SIGINT, sig_handler) == SIG_ERR)
                    printf("\ncan't catch SIGINT\n");
                while (1)
                    sleep(1);
            }
        }
    }

How can I make the program terminate after catching the signal?

John Bollinger
  • 160,171
  • 8
  • 81
  • 157
krakra
  • 35
  • 8

2 Answers2

0

Your program has several serious problems.

In the first place, you're trying to define the signal handler function as a nested function. C does not have nested functions. That your code compiles at all must mean that you're relying on a language extension, and it seems especially unwise to juxtapose that with signal handling.

You call a function callError() from inside your signal handler. It is unclear whether this function is async-signal-safe. You call functions calloc(), strcat(), and free() from inside your signal handler. These definitely are not async-signal-safe, and must not be called from inside a signal handler.

You recruit four threads to your parallel construct, but provide only three sections to be run.

You put all of your parallel sections into infinite loops (so of course the program does not terminate upon catching a signal for which you have installed a handler).

You do not consistently check the return values of your function calls.


Your overall strategy seems confused. Generally speaking, performing a clean asynchronous shutdown -- i.e. causing a thread to terminate operations in response to an action by a different thread or a signal handler -- involves setting a shared flag that the thread(s) to be shut down periodically check to determine whether to continue or exit. You can safely set such a flag from a signal handler, provided that its type is volatile sig_atomic_t.

Furthermore, signal handlers ought to perform as little work as possible, and the system functions they are permitted to call are limited to those designated async-signal-safe. Furthermore, they may operate with a small stack, which you should be careful not to risk exhausting.

Additionally, there is no advantage whatever to waiting to install the signal handler until after entering the OMP parallel block, and no advantage to having the signal handler send the termination message to the server itself.

Since you seem perfectly content to dedicate a thread to signal handling, I suggest that you use it to accept SIGINT synchronously, via sigwait() or one of its related functions. That thread can then trigger OMP's cancellation feature -- see the cancel-var ICV and the cancel construct. The other threads will need to cooperate -- see the cancellation point construct. Since you provide no other way to exit the parallel section, you can send the logout message to the server from normal (not signal-handler) code, immediately following the parallel region.

John Bollinger
  • 160,171
  • 8
  • 81
  • 157
0

I just rewrite my code and it works fine but i know that exit whole program in on thread is bad idea. It wokrs fine but valgrind is calling possible mem leak and it constantly free less that this program alocates total heap usage: 40 allocs, 34 frees i really doesn't understand how to exit this program optionally i did this:

#pragma omp parallel num_threads(2)
{
     #pragma omp sections
    {
        #pragma omp section
        {
            static volatile int keepRunning = 1;
            void intHandler(int dummy) 
            {
               keepRunning = 0;
               char * welcome1 = calloc(strlen(username)+13,sizeof(char));
               strcat(welcome1,username);
               strcat(welcome1," logged out\r\n");
               if(send(client_socket,welcome1,strlen(welcome1),0) < 0)
               {
                    callError("ERROR: cannot send socked");
               }
               free(welcome1);
               exit(130);
            }
            signal(SIGINT, intHandler);
            char *str, c;
            int i = 0, j = 1;
            char * buffer;
            while(keepRunning)
            {
                str = (char*)malloc(sizeof(char));
                while((c = getc(stdin)) != '\n'){

                    str = (char*)realloc(str, j * sizeof(char));
                    str[i] = c;
                    i++;
                    j++;
                }
                str = (char*)realloc(str, j * sizeof(char));
                str[i] = '\0';
                if(strlen(str)!=0)
                {
                    buffer = message(username,str);
                    if(send(client_socket,buffer,strlen(buffer),0) < 0)
                    {
                        callError("ERROR: cannot send socked");
                    }
                    free(buffer);
                }
                free(str); i = 0; j = 1; 
            }
        }
        #pragma omp section
        {   
            static volatile int keepRunning = 1;
            void intHandler(int dummy) {
                keepRunning = 0;
                char * welcome1 = calloc(strlen(username)+14,sizeof(char));
                strcat(welcome1,username);
                strcat(welcome1," logged out\r\n");
                if(send(client_socket,welcome1,strlen(welcome1),0) < 0)
                {
                    callError("ERROR: cannot send socked");
                }
                free(welcome1);
                exit(130);
            }
            char buffer[4096];
            char * data;
            ssize_t length;
            int received = 0;
            int data_cap = 4096;
            signal(SIGINT, intHandler);
            while(keepRunning)
            {
                data = calloc(BUFFER_LEN,sizeof(char));
                while ((length = read(client_socket, buffer, BUFFER_LEN)) > 0)
                {
                    received += length;
                    if (received > data_cap)
                    {
                         data = realloc(data,sizeof(char) * data_cap * 2);
                         data_cap = data_cap * 2;
                    }
                    strcat(data, buffer); 
                    if(!isEnough(data))
                    {
                        break;
                    }
                }
                printf("%s", data);
                free(data); bzero(buffer,BUFFER_LEN); data_cap = 4096; received = 0; length = 0;
            }
        }
    }
}
krakra
  • 35
  • 8