4 #include <machine/stackframe.h>
13 void ctx_start(void (*)(void), int, ...);
15 /*===========================================================================*
17 *===========================================================================*/
18 int setuctx(const ucontext_t
*ucp
)
27 if (!(ucp
->uc_flags
& UCF_IGNSIGM
)) {
29 if ((r
= sigprocmask(SIG_SETMASK
, &ucp
->uc_sigmask
, NULL
)) == -1)
33 if (!(ucp
->uc_flags
& UCF_IGNFPU
)) {
34 if ((r
= setmcontext(&(ucp
->uc_mcontext
))) == -1)
42 /*===========================================================================*
44 *===========================================================================*/
45 int getuctx(ucontext_t
*ucp
)
54 if (!(ucp
->uc_flags
& UCF_IGNSIGM
)) {
56 if ((r
= sigprocmask(0, NULL
, &ucp
->uc_sigmask
)) == -1)
60 if (!(ucp
->uc_flags
& UCF_IGNFPU
)) {
61 if ((r
= getmcontext(&(ucp
->uc_mcontext
))) != 0)
69 /*===========================================================================*
71 *===========================================================================*/
72 void makecontext(ucontext_t
*ucp
, void (*func
)(void), int argc
, ...)
75 unsigned int *stack_top
;
77 /* There are a number of situations that are erroneous, but we can't actually
78 tell the caller something is wrong, because this is a void function.
79 Instead, mcontext_t contains a magic field that has to be set
80 properly before it can be used. */
83 } else if ((ucp
->uc_stack
.ss_sp
== NULL
) ||
84 (ucp
->uc_stack
.ss_size
< MINSIGSTKSZ
)) {
85 ucp
->uc_mcontext
.mc_magic
= 0;
86 ucp
->uc_mcontext
.mc_p_reg
.sp
= 0;
90 if (ucp
->uc_mcontext
.mc_magic
== MCF_MAGIC
) {
91 #if (_MINIX_CHIP == _CHIP_INTEL)
92 /* The caller provides a pointer to a stack that we can use to run our
93 context on. When the context starts, control is given to a wrapped
94 start routine, which calls a function and cleans up the stack
95 afterwards. The wrapper needs the address of that function on the
97 The stack will be prepared as follows:
98 func() - start routine
102 ucp - context, esp points here when `func' returns
103 _ctx_start pops the address of `func' from the stack and calls it.
104 The stack will then be setup with all arguments for `func'. When
105 `func' returns, _ctx_start cleans up the stack such that ucp is at
106 the top of the stack, ready to be used by resumecontext.
107 Resumecontext, in turn, checks whether another context is ready to
108 be executed (i.e., uc_link != NULL) or exit(2)s the process. */
110 /* Find the top of the stack from which we grow downwards. */
111 stack_top
= (unsigned int *) ((uintptr_t ) ucp
->uc_stack
.ss_sp
+
112 ucp
->uc_stack
.ss_size
);
114 /* Align the arguments to 16 bytes (we might lose a few bytes of stack
116 stack_top
= (unsigned int *) ((uintptr_t) stack_top
& ~0xf);
118 /* Make room for 'func', the `func' routine arguments, and ucp. */
119 stack_top
-= (1 + argc
+ 1);
121 /* Adjust the machine context to point to the top of this stack and the
122 program counter to the context start wrapper. */
123 ucp
->uc_mcontext
.mc_p_reg
.fp
= 0; /* Clear frame pointer */
124 ucp
->uc_mcontext
.mc_p_reg
.sp
= (reg_t
) stack_top
;
125 ucp
->uc_mcontext
.mc_p_reg
.pc
= (reg_t
) ctx_start
;
127 *stack_top
++ = (uintptr_t) func
;
129 /* Copy arguments to the stack. */
132 *stack_top
++ = va_arg(ap
, uintptr_t);
136 /* Store ucp on the stack */
137 *stack_top
= (uintptr_t) ucp
;
139 /* Set ESI to point to the base of the stack where ucp is stored, so
140 that the wrapper function knows how to clean up the stack after
141 calling `func' (i.e., how to adjust ESP). */
142 ucp
->uc_mcontext
.mc_p_reg
.si
= (reg_t
) stack_top
;
145 /* If we ran out of stack space, invalidate stack pointer. Eventually,
146 swapcontext will choke on this and return ENOMEM. */
147 if (stack_top
== ucp
->uc_stack
.ss_sp
)
148 ucp
->uc_mcontext
.mc_p_reg
.sp
= 0;
151 # error "Unsupported platform"
157 /*===========================================================================*
159 *===========================================================================*/
160 int swapcontext(ucontext_t
*oucp
, const ucontext_t
*ucp
)
164 if ((oucp
== NULL
) || (ucp
== NULL
)) {
169 if (ucp
->uc_mcontext
.mc_p_reg
.sp
== 0) {
170 /* No stack space. Bail out. */
175 oucp
->uc_flags
&= ~UCF_SWAPPED
;
176 r
= getcontext(oucp
);
177 if ((r
== 0) && !(oucp
->uc_flags
& UCF_SWAPPED
)) {
178 oucp
->uc_flags
|= UCF_SWAPPED
;
186 /*===========================================================================*
188 *===========================================================================*/
189 void resumecontext(ucontext_t
*ucp
)
191 if (ucp
->uc_link
== NULL
) exit(0);
193 /* Error handling? Where should the error go to? */
194 (void) setcontext((const ucontext_t
*) ucp
->uc_link
);
196 exit(1); /* Never reached */