Blame manual/examples/swapcontext.c

Packit 6c4009
/* Complete Context Control
Packit 6c4009
   Copyright (C) 1991-2018 Free Software Foundation, Inc.
Packit 6c4009
Packit 6c4009
   This program is free software; you can redistribute it and/or
Packit 6c4009
   modify it under the terms of the GNU General Public License
Packit 6c4009
   as published by the Free Software Foundation; either version 2
Packit 6c4009
   of the License, or (at your option) any later version.
Packit 6c4009
Packit 6c4009
   This program is distributed in the hope that it will be useful,
Packit 6c4009
   but WITHOUT ANY WARRANTY; without even the implied warranty of
Packit 6c4009
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
Packit 6c4009
   GNU General Public License for more details.
Packit 6c4009
Packit 6c4009
   You should have received a copy of the GNU General Public License
Packit 6c4009
   along with this program; if not, if not, see <http://www.gnu.org/licenses/>.
Packit 6c4009
*/
Packit 6c4009
Packit 6c4009
#include <signal.h>
Packit 6c4009
#include <stdio.h>
Packit 6c4009
#include <stdlib.h>
Packit 6c4009
#include <ucontext.h>
Packit 6c4009
#include <sys/time.h>
Packit 6c4009
Packit 6c4009
/* Set by the signal handler.  */
Packit 6c4009
static volatile int expired;
Packit 6c4009
Packit 6c4009
/* The contexts.  */
Packit 6c4009
static ucontext_t uc[3];
Packit 6c4009
Packit 6c4009
/* We do only a certain number of switches.  */
Packit 6c4009
static int switches;
Packit 6c4009
Packit 6c4009
Packit 6c4009
/* This is the function doing the work.  It is just a
Packit 6c4009
   skeleton, real code has to be filled in.  */
Packit 6c4009
static void
Packit 6c4009
f (int n)
Packit 6c4009
{
Packit 6c4009
  int m = 0;
Packit 6c4009
  while (1)
Packit 6c4009
    {
Packit 6c4009
      /* This is where the work would be done.  */
Packit 6c4009
      if (++m % 100 == 0)
Packit 6c4009
        {
Packit 6c4009
          putchar ('.');
Packit 6c4009
          fflush (stdout);
Packit 6c4009
        }
Packit 6c4009
Packit 6c4009
      /* Regularly the @var{expire} variable must be checked.  */
Packit 6c4009
      if (expired)
Packit 6c4009
        {
Packit 6c4009
          /* We do not want the program to run forever.  */
Packit 6c4009
          if (++switches == 20)
Packit 6c4009
            return;
Packit 6c4009
Packit 6c4009
          printf ("\nswitching from %d to %d\n", n, 3 - n);
Packit 6c4009
          expired = 0;
Packit 6c4009
          /* Switch to the other context, saving the current one.  */
Packit 6c4009
          swapcontext (&uc[n], &uc[3 - n]);
Packit 6c4009
        }
Packit 6c4009
    }
Packit 6c4009
}
Packit 6c4009
Packit 6c4009
/* This is the signal handler which simply set the variable.  */
Packit 6c4009
void
Packit 6c4009
handler (int signal)
Packit 6c4009
{
Packit 6c4009
  expired = 1;
Packit 6c4009
}
Packit 6c4009
Packit 6c4009
Packit 6c4009
int
Packit 6c4009
main (void)
Packit 6c4009
{
Packit 6c4009
  struct sigaction sa;
Packit 6c4009
  struct itimerval it;
Packit 6c4009
  char st1[8192];
Packit 6c4009
  char st2[8192];
Packit 6c4009
Packit 6c4009
  /* Initialize the data structures for the interval timer.  */
Packit 6c4009
  sa.sa_flags = SA_RESTART;
Packit 6c4009
  sigfillset (&sa.sa_mask);
Packit 6c4009
  sa.sa_handler = handler;
Packit 6c4009
  it.it_interval.tv_sec = 0;
Packit 6c4009
  it.it_interval.tv_usec = 1;
Packit 6c4009
  it.it_value = it.it_interval;
Packit 6c4009
Packit 6c4009
  /* Install the timer and get the context we can manipulate.  */
Packit 6c4009
  if (sigaction (SIGPROF, &sa, NULL) < 0
Packit 6c4009
      || setitimer (ITIMER_PROF, &it, NULL) < 0
Packit 6c4009
      || getcontext (&uc[1]) == -1
Packit 6c4009
      || getcontext (&uc[2]) == -1)
Packit 6c4009
    abort ();
Packit 6c4009
Packit 6c4009
  /* Create a context with a separate stack which causes the
Packit 6c4009
     function @code{f} to be call with the parameter @code{1}.
Packit 6c4009
     Note that the @code{uc_link} points to the main context
Packit 6c4009
     which will cause the program to terminate once the function
Packit 6c4009
     return.  */
Packit 6c4009
  uc[1].uc_link = &uc[0];
Packit 6c4009
  uc[1].uc_stack.ss_sp = st1;
Packit 6c4009
  uc[1].uc_stack.ss_size = sizeof st1;
Packit 6c4009
  makecontext (&uc[1], (void (*) (void)) f, 1, 1);
Packit 6c4009
Packit 6c4009
  /* Similarly, but @code{2} is passed as the parameter to @code{f}.  */
Packit 6c4009
  uc[2].uc_link = &uc[0];
Packit 6c4009
  uc[2].uc_stack.ss_sp = st2;
Packit 6c4009
  uc[2].uc_stack.ss_size = sizeof st2;
Packit 6c4009
  makecontext (&uc[2], (void (*) (void)) f, 1, 2);
Packit 6c4009
Packit 6c4009
  /* Start running.  */
Packit 6c4009
  swapcontext (&uc[0], &uc[1]);
Packit 6c4009
  putchar ('\n');
Packit 6c4009
Packit 6c4009
  return 0;
Packit 6c4009
}