Back to index

glibc  2.9
swapcontext.c
Go to the documentation of this file.
00001 #include <signal.h>
00002 #include <stdio.h>
00003 #include <stdlib.h>
00004 #include <ucontext.h>
00005 #include <sys/time.h>
00006 
00007 /* Set by the signal handler.  */
00008 static volatile int expired;
00009 
00010 /* The contexts.  */
00011 static ucontext_t uc[3];
00012 
00013 /* We do only a certain number of switches.  */
00014 static int switches;
00015 
00016 
00017 /* This is the function doing the work.  It is just a
00018    skeleton, real code has to be filled in.  */
00019 static void
00020 f (int n)
00021 {
00022   int m = 0;
00023   while (1)
00024     {
00025       /* This is where the work would be done.  */
00026       if (++m % 100 == 0)
00027         {
00028           putchar ('.');
00029           fflush (stdout);
00030         }
00031 
00032       /* Regularly the @var{expire} variable must be checked.  */
00033       if (expired)
00034         {
00035           /* We do not want the program to run forever.  */
00036           if (++switches == 20)
00037             return;
00038 
00039           printf ("\nswitching from %d to %d\n", n, 3 - n);
00040           expired = 0;
00041           /* Switch to the other context, saving the current one.  */
00042           swapcontext (&uc[n], &uc[3 - n]);
00043         }
00044     }
00045 }
00046 
00047 /* This is the signal handler which simply set the variable.  */
00048 void
00049 handler (int signal)
00050 {
00051   expired = 1;
00052 }
00053 
00054 
00055 int
00056 main (void)
00057 {
00058   struct sigaction sa;
00059   struct itimerval it;
00060   char st1[8192];
00061   char st2[8192];
00062 
00063   /* Initialize the data structures for the interval timer.  */
00064   sa.sa_flags = SA_RESTART;
00065   sigfillset (&sa.sa_mask);
00066   sa.sa_handler = handler;
00067   it.it_interval.tv_sec = 0;
00068   it.it_interval.tv_usec = 1;
00069   it.it_value = it.it_interval;
00070 
00071   /* Install the timer and get the context we can manipulate.  */
00072   if (sigaction (SIGPROF, &sa, NULL) < 0
00073       || setitimer (ITIMER_PROF, &it, NULL) < 0
00074       || getcontext (&uc[1]) == -1
00075       || getcontext (&uc[2]) == -1)
00076     abort ();
00077 
00078   /* Create a context with a separate stack which causes the
00079      function @code{f} to be call with the parameter @code{1}.
00080      Note that the @code{uc_link} points to the main context
00081      which will cause the program to terminate once the function
00082      return.  */
00083   uc[1].uc_link = &uc[0];
00084   uc[1].uc_stack.ss_sp = st1;
00085   uc[1].uc_stack.ss_size = sizeof st1;
00086   makecontext (&uc[1], (void (*) (void)) f, 1, 1);
00087 
00088   /* Similarly, but @code{2} is passed as the parameter to @code{f}.  */
00089   uc[2].uc_link = &uc[0];
00090   uc[2].uc_stack.ss_sp = st2;
00091   uc[2].uc_stack.ss_size = sizeof st2;
00092   makecontext (&uc[2], (void (*) (void)) f, 1, 2);
00093 
00094   /* Start running.  */
00095   swapcontext (&uc[0], &uc[1]);
00096   putchar ('\n');
00097 
00098   return 0;
00099 }