1/* Complete Context Control
2 Copyright (C) 1991-2022 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. */
25static volatile int expired;
26
27/* The contexts. */
28static ucontext_t uc[3];
29
30/* We do only a certain number of switches. */
31static 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. */
36static void
37f (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 (c: '.');
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 (format: "\nswitching from %d to %d\n", n, 3 - n);
57 expired = 0;
58 /* Switch to the other context, saving the current one. */
59 swapcontext (oucp: &uc[n], ucp: &uc[3 - n]);
60 }
61 }
62}
63
64/* This is the signal handler which simply set the variable. */
65void
66handler (int signal)
67{
68 expired = 1;
69}
70
71
72int
73main (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, act: &sa, NULL) < 0
90 || setitimer (ITIMER_PROF, new: &it, NULL) < 0
91 || getcontext (ucp: &uc[1]) == -1
92 || getcontext (ucp: &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 (ucp: &uc[1], func: (void (*) (void)) f, argc: 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 (ucp: &uc[2], func: (void (*) (void)) f, argc: 1, 2);
110
111 /* Start running. */
112 swapcontext (oucp: &uc[0], ucp: &uc[1]);
113 putchar (c: '\n');
114
115 return 0;
116}
117

source code of glibc/manual/examples/swapcontext.c