secondary cache feature in vm.
[minix.git] / lib / libc / posix / _ucontext.c
blobd7930e6ad8191558189cc8cffa7fca5b1c9d8911
1 #include <lib.h>
2 #include <machine/stackframe.h>
3 #include <ucontext.h>
4 #include <signal.h>
5 #include <stdarg.h>
6 #include <stdlib.h>
7 #include <unistd.h>
8 #include <stdint.h>
9 #include <stdio.h>
11 _PROTOTYPE( void ctx_start, (void (*)(void), int, ...) );
13 /*===========================================================================*
14 * setuctx *
15 *===========================================================================*/
16 PUBLIC int setuctx(const ucontext_t *ucp)
18 int r;
20 if (ucp == NULL) {
21 errno = EFAULT;
22 return(-1);
25 if (!(ucp->uc_flags & UCF_IGNSIGM)) {
26 /* Set signal mask */
27 if ((r = sigprocmask(SIG_SETMASK, &ucp->uc_sigmask, NULL)) == -1)
28 return(r);
31 if (!(ucp->uc_flags & UCF_IGNFPU)) {
32 if ((r = setmcontext(&(ucp->uc_mcontext))) == -1)
33 return(r);
36 return(0);
40 /*===========================================================================*
41 * getuctx *
42 *===========================================================================*/
43 PUBLIC int getuctx(ucontext_t *ucp)
45 int r;
47 if (ucp == NULL) {
48 errno = EFAULT;
49 return(-1);
52 if (!(ucp->uc_flags & UCF_IGNSIGM)) {
53 /* Get signal mask */
54 if ((r = sigprocmask(0, NULL, &ucp->uc_sigmask)) == -1)
55 return(r);
58 if (!(ucp->uc_flags & UCF_IGNFPU)) {
59 if ((r = getmcontext(&(ucp->uc_mcontext))) != 0)
60 return(r);
63 return(0);
67 /*===========================================================================*
68 * makecontext *
69 *===========================================================================*/
70 PUBLIC void makecontext(ucontext_t *ucp, void (*func)(void), int argc, ...)
72 va_list ap;
73 unsigned int *stack_top;
75 /* There are a number of situations that are erroneous, but we can't actually
76 tell the caller something is wrong, because this is a void function.
77 Instead, mcontext_t contains a magic field that has to be set
78 properly before it can be used. */
79 if (ucp == NULL) {
80 return;
81 } else if ((ucp->uc_stack.ss_sp == NULL) ||
82 (ucp->uc_stack.ss_size < MINSIGSTKSZ)) {
83 ucp->uc_mcontext.mc_magic = 0;
84 ucp->uc_mcontext.mc_p_reg.sp = 0;
85 return;
88 if (ucp->uc_mcontext.mc_magic == MCF_MAGIC) {
89 #if (_MINIX_CHIP == _CHIP_INTEL)
90 /* The caller provides a pointer to a stack that we can use to run our
91 context on. When the context starts, control is given to a wrapped
92 start routine, which calls a function and cleans up the stack
93 afterwards. The wrapper needs the address of that function on the
94 stack.
95 The stack will be prepared as follows:
96 func() - start routine
97 arg1 - first argument
98 ...
99 argn - last argument
100 ucp - context, esp points here when `func' returns
101 _ctx_start pops the address of `func' from the stack and calls it.
102 The stack will then be setup with all arguments for `func'. When
103 `func' returns, _ctx_start cleans up the stack such that ucp is at
104 the top of the stack, ready to be used by resumecontext.
105 Resumecontext, in turn, checks whether another context is ready to
106 be executed (i.e., uc_link != NULL) or exit(2)s the process. */
108 /* Find the top of the stack from which we grow downwards. */
109 stack_top = (unsigned int *) ((uintptr_t ) ucp->uc_stack.ss_sp +
110 ucp->uc_stack.ss_size);
112 /* Align the arguments to 16 bytes (we might lose a few bytes of stack
113 space here).*/
114 stack_top = (unsigned int *) ((uintptr_t) stack_top & ~0xf);
116 /* Make room for 'func', the `func' routine arguments, and ucp. */
117 stack_top -= (1 + argc + 1);
119 /* Adjust the machine context to point to the top of this stack and the
120 program counter to the context start wrapper. */
121 ucp->uc_mcontext.mc_p_reg.fp = 0; /* Clear frame pointer */
122 ucp->uc_mcontext.mc_p_reg.sp = (reg_t) stack_top;
123 ucp->uc_mcontext.mc_p_reg.pc = (reg_t) ctx_start;
125 *stack_top++ = (uintptr_t) func;
127 /* Copy arguments to the stack. */
128 va_start(ap, argc);
129 while (argc-- > 0) {
130 *stack_top++ = va_arg(ap, uintptr_t);
132 va_end(ap);
134 /* Store ucp on the stack */
135 *stack_top = (uintptr_t) ucp;
137 /* Set ESI to point to the base of the stack where ucp is stored, so
138 that the wrapper function knows how to clean up the stack after
139 calling `func' (i.e., how to adjust ESP). */
140 ucp->uc_mcontext.mc_p_reg.si = (reg_t) stack_top;
143 /* If we ran out of stack space, invalidate stack pointer. Eventually,
144 swapcontext will choke on this and return ENOMEM. */
145 if (stack_top == ucp->uc_stack.ss_sp)
146 ucp->uc_mcontext.mc_p_reg.sp = 0;
148 #else
149 # error "Unsupported platform"
150 #endif
155 /*===========================================================================*
156 * swapcontext *
157 *===========================================================================*/
158 PUBLIC int swapcontext(ucontext_t *oucp, const ucontext_t *ucp)
160 int r;
162 if ((oucp == NULL) || (ucp == NULL)) {
163 errno = EFAULT;
164 return(-1);
167 if (ucp->uc_mcontext.mc_p_reg.sp == 0) {
168 /* No stack space. Bail out. */
169 errno = ENOMEM;
170 return(-1);
173 oucp->uc_flags &= ~UCF_SWAPPED;
174 r = getcontext(oucp);
175 if ((r == 0) && !(oucp->uc_flags & UCF_SWAPPED)) {
176 oucp->uc_flags |= UCF_SWAPPED;
177 r = setcontext(ucp);
180 return(r);
184 /*===========================================================================*
185 * resumecontext *
186 *===========================================================================*/
187 PUBLIC void resumecontext(ucontext_t *ucp)
189 if (ucp->uc_link == NULL) exit(0);
191 /* Error handling? Where should the error go to? */
192 (void) setcontext((const ucontext_t *) ucp->uc_link);
194 exit(1); /* Never reached */