public inbox for linux-kernel@vger.kernel.org
 help / color / mirror / Atom feed
From: Olivier Croquette <ocroquette@free.fr>
To: linux-kernel@vger.kernel.org
Cc: roland@frob.com, alexn@dsv.su.se, mingo@elte.hu
Subject: Re: Scheduler: SIGSTOP on multi threaded processes
Date: Tue, 10 May 2005 22:59:33 +0200	[thread overview]
Message-ID: <428120B5.5060403@free.fr> (raw)
In-Reply-To: <Pine.LNX.4.61.0505050814340.24130@chaos.analogic.com>


Hi all


I worked on my problem in the last days, and I came to these main 2 
questions:

- Can a SIGSTOP be in a pending state in Linux?

- If kill(SIGSTOP,...) returns, does that mean that the corresponding 
process is completly suspended?


I thought until now that SIGSTOP was so special that it could never be
pending, and that as soon as:
signal(SIGSTOP,pid)
returned, then it was assured that the corresponding process (and all
its threads) were suspended.

This would make sense in my opinion, but apparently it is not always the
case, and the POSIX norm do not say anything about that.

Any hint?


I did also some experiments, with one program which fork()s into:

- a child which potentially starts threads and does some stuff

- a parent which regularly sends SIGSTOP to the child and check if the 
activity really stopped, and then send SIGCONT again

You will find the source code below.

I tried that with different scheduling policies (SCHED_OTHER and 
SCHED_RR) and different number of threads:
- 0: no thread started (ie. mono threaded child)
- 1: 1 thread started, and the main task just pthread_join() it
- 2: 2 threads started, and the main task pthread_join() them

I came to the following results:

    Policy   OTHER   RR
Threads
0           OK      OK
1           FAIL    OK
2           FAIL    FAIL(1)


- the answer to my 2 questions (see above) see to be No and Yes 
respectively when no thread is started

- (1) For RR with 2 threads, there are 2 observed behaviour, apparently 
happening randomly:

  * either the parent call always stop instantaneously all threads (like 
when no thread is started), and that for a long time

  * or right at the beginning, we can observe that the parent can not do 
that

I find this behaviour really strange.

Any idea?

Can one rely on the fact that the SIGSTOP operates instantaneously for 
non-threaded applications?

Would it be possible to provide that for all applications?




#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sched.h>
#include <sys/time.h>

#include <sys/types.h>
#include <sys/wait.h>
#include <sys/ipc.h>
#include <sys/shm.h>


#include <pthread.h>


int set_process_sched(pid_t pid, int policy, int priority) {
   struct sched_param p;

   p.sched_priority = priority;

   if ( 1 || policy != sched_getscheduler(pid) ) {
     if ( sched_setscheduler(pid,policy,&p) ) {
       perror("sched_setscheduler()");
       return 1;
     }
   }

   return 0;
}

unsigned long long gettime(void ) {

   struct timeval tv;

   if ( gettimeofday(&tv, NULL) ) {
     perror("gettimeofday()");
     return 0;
   }

   return (tv.tv_usec + tv.tv_sec * 1000000LL);
}

typedef struct {
   int         thread_nb; /* id defined by us */
   pthread_t   thread_id; /* system id of the thread */
} thread_data;


int   cont_main_loop = 1;


void sigterm_handler(int dummy) {
   printf("sigterm_handler\n");
   return;
}


/* We use a shared memory to communicate between the parent and the child
    They all only work in the first few bytes
*/
int     shmid;
unsigned long long int     *shared_array;
#define SHM_SIZE 1024

static inline void conf_shmem(void ) {

   shmid = shmget(IPC_PRIVATE, SHM_SIZE, 0666 | IPC_CREAT);
   if (shmid == -1) {
     perror("shmget()");
     exit(0);
   }

   shared_array = (long long int *) shmat(shmid, 0, 0);
   if (! shared_array ) {
     perror("shmat()");
     exit(0);
   }
}


void loop(int marker) {
   unsigned long long int begin = gettime();
   /* run for 2 minutes at max
      (useful in case we end up with a busy loop in SCHED_RR... */
   while ( gettime() - begin < 120000000LL ) {
     /* write in the shared memory */
     shared_array[0] = marker;
   }
}

void *go_thread(void *dummy) {
   thread_data *data = (thread_data *) dummy;
   loop(data->thread_nb);
   fprintf(stderr,"%llu\tQuitting!\n",gettime());
   return NULL;
}


#define MAX_THREADS 100

int main(int argc, char **argv)
{
   int pid;
   int test_failed = 0;
   unsigned long long exec_begin = gettime();
   int nb_threads = 0;


   conf_shmem();
   shared_array[0] = 0;

   if ( argc > 1 )
     nb_threads = atoi(argv[1]);
   if ( nb_threads > MAX_THREADS )
     nb_threads = MAX_THREADS;

   pid = fork();

   switch ( pid ) {

     case 0: /* child */
     {
       int thread;
       thread_data threads[MAX_THREADS];

       if ( nb_threads == 0 ) {
         /* no multi threading */
         loop(1);
         break;
       }

       /* start the threads */
       for ( thread = 0 ; thread < nb_threads ; thread ++) {
         threads[thread].thread_nb = thread + 1;
         if ( pthread_create (  & threads[thread].thread_id,
                           NULL,
                           go_thread,
                           (void *)&threads[thread]) )
           perror("pthread_create");

       }

       {
         int thread;
         for ( thread = 0 ; thread < nb_threads ; thread ++) {
           pthread_join (  threads[thread].thread_id, NULL);
         }
       }
       exit(0);
     }

     default: /* parent */
     {
       unsigned long long begin = gettime();

       /* depending whether we set the priorities or not,
          we get different results.
       */

       set_process_sched(0, SCHED_RR, 65);
       set_process_sched(pid, SCHED_RR, 60);


       /* run for 10s */
       while ( gettime() - begin < 10000000 ) {
         unsigned long long int b_stop, a_stop;

         /* let the child run a little bit */
         usleep(1000);

         /* stop it */
         kill(pid, SIGSTOP);

         /* Reset our flag */
         shared_array[0] = 0;

         /* Wait to see if someone dare overwriting our nice zero */
         usleep(1000);
         if ( shared_array[0] > 0 ) {
           test_failed = shared_array[0];
           break;
         }
         kill(pid, SIGCONT);
       }
       kill(pid, SIGKILL);
       break;
     }

     case -1:
       perror("fork()");
       exit(0);
   }

   system("uname -a");
   printf("%d thread(s)\n",nb_threads);
   if ( ! test_failed )
     printf("test passed");
   else
     printf("test FAILED (%d)",test_failed);
   printf(" after %f s\n\n", ( gettime() - exec_begin) / 1000000.0 );

   return 0;
}



  parent reply	other threads:[~2005-05-10 21:06 UTC|newest]

Thread overview: 19+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2005-05-04 17:37 Scheduler: SIGSTOP on multi threaded processes Olivier Croquette
2005-05-04 18:16 ` Richard B. Johnson
2005-05-04 19:16   ` Daniel Jacobowitz
2005-05-04 21:06     ` Alex Riesen
2005-05-05  0:42       ` Richard B. Johnson
2005-05-05  0:33     ` Richard B. Johnson
2005-05-05  0:45       ` Richard B. Johnson
2005-05-05 12:24       ` Richard B. Johnson
2005-05-05 13:14         ` Denis Vlasenko
2005-05-05 13:30         ` Andreas Schwab
2005-05-05 22:04         ` Miquel van Smoorenburg
2005-05-06 23:15           ` Problem while stopping many threads within a module Yuly Finkelberg
2006-04-20  8:43             ` shikha
2005-05-10 20:59         ` Olivier Croquette [this message]
2005-05-10 21:12           ` Scheduler: SIGSTOP on multi threaded processes Roland McGrath
2005-05-11 18:58             ` Olivier Croquette
2005-05-10 23:05           ` Alex Riesen
2005-05-05  1:04   ` Andy Isaacson
2005-05-04 19:10 ` Alexander Nyberg

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=428120B5.5060403@free.fr \
    --to=ocroquette@free.fr \
    --cc=alexn@dsv.su.se \
    --cc=linux-kernel@vger.kernel.org \
    --cc=mingo@elte.hu \
    --cc=roland@frob.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox