A non-trivial example of how to use user contexts for trivial scheduling.
[mirrors/Programs.git] / c / context_demo.c
CommitLineData
3278bd05
TM
1#include <ucontext.h>
2#include <sys/types.h>
3#include <sys/time.h>
4#include <signal.h>
5#include <stdio.h>
6#include <unistd.h>
7#include <stdlib.h>
8#include <poll.h>
9
10/* ucontext sample program
11
12 Downloaded from https://gist.github.com/DanGe42/7148946
13 A non-trivial example of how to use user contexts for trivial scheduling.
14
15 by Jon Kaplan and Robert Spier (October 24th, 1999)
16 Updated for 2000 and poll, Robert Spier
17 sigprocmask gaff fixed by Ben Slusky
18 ported to Linux by Eric Cronin
19 $Id: context_demo.c 37 2006-10-12 22:16:59Z ecronin $
20
21 Demonstrates swapping between multiple processor contexts (in a
22 _stable_ way). n-1 contexts do nothing. 1 context accepts input
23 and outputs it.
24*/
25
26
27#define NUMCONTEXTS 10 /* how many contexts to make */
28#define STACKSIZE 4096 /* stack size */
29#define INTERVAL 100 /* timer interval in nanoseconds */
30
31sigset_t set; /* process wide signal mask */
32ucontext_t signal_context; /* the interrupt context */
33void *signal_stack; /* global interrupt stack */
34
35ucontext_t contexts[NUMCONTEXTS]; /* store our context info */
36int curcontext = 0; /* whats the current context? */
37ucontext_t *cur_context; /* a pointer to the current_context */
38
39/* The scheduling algorithm; selects the next context to run, then starts it. */
40void
41scheduler()
42{
43 printf("scheduling out thread %d\n", curcontext);
44
45 curcontext = (curcontext + 1) % NUMCONTEXTS; /* round robin */
46 cur_context = &contexts[curcontext];
47
48 printf("scheduling in thread %d\n", curcontext);
49
50 setcontext(cur_context); /* go */
51}
52
53/*
54 Timer interrupt handler.
55 Creates a new context to run the scheduler in, masks signals, then swaps
56 contexts saving the previously executing thread and jumping to the
57 scheduler.
58*/
59void
60timer_interrupt(int j, siginfo_t *si, void *old_context)
61{
62 /* Create new scheduler context */
63 getcontext(&signal_context);
64 signal_context.uc_stack.ss_sp = signal_stack;
65 signal_context.uc_stack.ss_size = STACKSIZE;
66 signal_context.uc_stack.ss_flags = 0;
67 sigemptyset(&signal_context.uc_sigmask);
68 makecontext(&signal_context, scheduler, 1);
69
70 /* save running thread, jump to scheduler */
71 swapcontext(cur_context,&signal_context);
72}
73
74/* Set up SIGALRM signal handler */
75void
76setup_signals(void)
77{
78 struct sigaction act;
79
80 act.sa_sigaction = timer_interrupt;
81 sigemptyset(&act.sa_mask);
82 act.sa_flags = SA_RESTART | SA_SIGINFO;
83
84 sigemptyset(&set);
85 sigaddset(&set, SIGALRM);
86
87 if(sigaction(SIGALRM, &act, NULL) != 0) {
88 perror("Signal handler");
89 }
90}
91
92
93/* Thread bodies */
94void
95thread1()
96{
97 while(1) {
98 poll(NULL,0,100);
99 }; /* do nothing nicely */
100}
101
102void
103thread2()
104{
105 char buf[1024];
106 /* get a string.. print a string.. ad infinitum */
107 while(1) {
108 fgets(buf, 1024, stdin);
109 printf("[[[[[[%s]]]]]]\n",buf);
110 }
111}
112
113/* helper function to create a context.
114 initialize the context from the current context, setup the new
115 stack, signal mask, and tell it which function to call.
116*/
117void
118mkcontext(ucontext_t *uc, void *function)
119{
120 void * stack;
121
122 getcontext(uc);
123
124 stack = malloc(STACKSIZE);
125 if (stack == NULL) {
126 perror("malloc");
127 exit(1);
128 }
129 /* we need to initialize the ucontext structure, give it a stack,
130 flags, and a sigmask */
131 uc->uc_stack.ss_sp = stack;
132 uc->uc_stack.ss_size = STACKSIZE;
133 uc->uc_stack.ss_flags = 0;
134 if (sigemptyset(&uc->uc_sigmask) < 0){
135 perror("sigemptyset");
136 exit(1);
137 }
138
139 /* setup the function we're going to, and n-1 arguments. */
140 makecontext(uc, function, 1);
141
142 printf("context is %p\n", uc);
143}
144
145
146int
147main()
148{
149 int i;
150 struct itimerval it;
151
152 fprintf(stderr,"Process Id: %d\n", (int)getpid());
153
154 /* allocate the global signal/interrupt stack */
155 signal_stack = malloc(STACKSIZE);
156 if (signal_stack == NULL) {
157 perror("malloc");
158 exit(1);
159 }
160
161 /* make all our contexts */
162 mkcontext(&contexts[0], thread2);
163 for(i=1; i < NUMCONTEXTS; i++)
164 mkcontext(&contexts[i], thread1);
165
166
167 /* initialize the signal handlers */
168 setup_signals();
169
170 /* setup our timer */
171 it.it_interval.tv_sec = 0;
172 it.it_interval.tv_usec = INTERVAL * 1000;
173 it.it_value = it.it_interval;
174 if (setitimer(ITIMER_REAL, &it, NULL) ) perror("setitiimer");
175
176 /* force a swap to the first context */
177 cur_context = &contexts[0];
178 setcontext(&contexts[0]);
179
180 return 0; /* make gcc happy */
181}
This page took 0.271031 seconds and 4 git commands to generate.