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. */
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
f(int n)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
handler(int signal)66 handler (int signal)
67 {
68 expired = 1;
69 }
70
71
72 int
main(void)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 }
117