(root)/
glibc-2.38/
manual/
examples/
swapcontext.c
       1  /* Complete Context Control
       2     Copyright (C) 1991-2023 Free Software Foundation, Inc.
       3  
       4     This program is free software; you can redistribute it and/or
       5     modify it under the terms of the GNU General Public License
       6     as published by the Free Software Foundation; either version 2
       7     of the License, or (at your option) any later version.
       8  
       9     This program is distributed in the hope that it will be useful,
      10     but WITHOUT ANY WARRANTY; without even the implied warranty of
      11     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      12     GNU General Public License for more details.
      13  
      14     You should have received a copy of the GNU General Public License
      15     along with this program; if not, see <https://www.gnu.org/licenses/>.
      16  */
      17  
      18  #include <signal.h>
      19  #include <stdio.h>
      20  #include <stdlib.h>
      21  #include <ucontext.h>
      22  #include <sys/time.h>
      23  
      24  /* Set by the signal handler.  */
      25  static volatile int expired;
      26  
      27  /* The contexts.  */
      28  static ucontext_t uc[3];
      29  
      30  /* We do only a certain number of switches.  */
      31  static int switches;
      32  
      33  
      34  /* This is the function doing the work.  It is just a
      35     skeleton, real code has to be filled in.  */
      36  static void
      37  f (int n)
      38  {
      39    int m = 0;
      40    while (1)
      41      {
      42        /* This is where the work would be done.  */
      43        if (++m % 100 == 0)
      44          {
      45            putchar ('.');
      46            fflush (stdout);
      47          }
      48  
      49        /* Regularly the @var{expire} variable must be checked.  */
      50        if (expired)
      51          {
      52            /* We do not want the program to run forever.  */
      53            if (++switches == 20)
      54              return;
      55  
      56            printf ("\nswitching from %d to %d\n", n, 3 - n);
      57            expired = 0;
      58            /* Switch to the other context, saving the current one.  */
      59            swapcontext (&uc[n], &uc[3 - n]);
      60          }
      61      }
      62  }
      63  
      64  /* This is the signal handler which simply set the variable.  */
      65  void
      66  handler (int signal)
      67  {
      68    expired = 1;
      69  }
      70  
      71  
      72  int
      73  main (void)
      74  {
      75    struct sigaction sa;
      76    struct itimerval it;
      77    char st1[8192];
      78    char st2[8192];
      79  
      80    /* Initialize the data structures for the interval timer.  */
      81    sa.sa_flags = SA_RESTART;
      82    sigfillset (&sa.sa_mask);
      83    sa.sa_handler = handler;
      84    it.it_interval.tv_sec = 0;
      85    it.it_interval.tv_usec = 1;
      86    it.it_value = it.it_interval;
      87  
      88    /* Install the timer and get the context we can manipulate.  */
      89    if (sigaction (SIGPROF, &sa, NULL) < 0
      90        || setitimer (ITIMER_PROF, &it, NULL) < 0
      91        || getcontext (&uc[1]) == -1
      92        || getcontext (&uc[2]) == -1)
      93      abort ();
      94  
      95    /* Create a context with a separate stack which causes the
      96       function @code{f} to be call with the parameter @code{1}.
      97       Note that the @code{uc_link} points to the main context
      98       which will cause the program to terminate once the function
      99       return.  */
     100    uc[1].uc_link = &uc[0];
     101    uc[1].uc_stack.ss_sp = st1;
     102    uc[1].uc_stack.ss_size = sizeof st1;
     103    makecontext (&uc[1], (void (*) (void)) f, 1, 1);
     104  
     105    /* Similarly, but @code{2} is passed as the parameter to @code{f}.  */
     106    uc[2].uc_link = &uc[0];
     107    uc[2].uc_stack.ss_sp = st2;
     108    uc[2].uc_stack.ss_size = sizeof st2;
     109    makecontext (&uc[2], (void (*) (void)) f, 1, 2);
     110  
     111    /* Start running.  */
     112    swapcontext (&uc[0], &uc[1]);
     113    putchar ('\n');
     114  
     115    return 0;
     116  }