-
Notifications
You must be signed in to change notification settings - Fork 0
/
pth_uctx.c
202 lines (169 loc) · 6.29 KB
/
pth_uctx.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
/*
** GNU Pth - The GNU Portable Threads
** Copyright (c) 1999-2006 Ralf S. Engelschall <[email protected]>
**
** This file is part of GNU Pth, a non-preemptive thread scheduling
** library which can be found at http://www.gnu.org/software/pth/.
**
** This library is free software; you can redistribute it and/or
** modify it under the terms of the GNU Lesser General Public
** License as published by the Free Software Foundation; either
** version 2.1 of the License, or (at your option) any later version.
**
** This library is distributed in the hope that it will be useful,
** but WITHOUT ANY WARRANTY; without even the implied warranty of
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
** Lesser General Public License for more details.
**
** You should have received a copy of the GNU Lesser General Public
** License along with this library; if not, write to the Free Software
** Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
** USA, or contact Ralf S. Engelschall <[email protected]>.
**
** pth_uctx.c: Pth user-space context handling (stand-alone sub-API)
*/
/* ``It worries me however, to realize
how tough an ass-hole I have had to
be, in order to get to stick to the
principle of doing things right,
rather than "just hack it in".''
-- Poul-Henning Kamp <[email protected]> */
#include "pth_p.h"
/* user-space context structure */
struct pth_uctx_st {
int uc_stack_own; /* whether stack were allocated by us */
char *uc_stack_ptr; /* pointer to start address of stack area */
size_t uc_stack_len; /* size of stack area */
int uc_mctx_set; /* whether uc_mctx is set */
pth_mctx_t uc_mctx; /* saved underlying machine context */
};
/* create user-space context structure */
int
pth_uctx_create(
pth_uctx_t *puctx)
{
pth_uctx_t uctx;
/* argument sanity checking */
if (puctx == NULL)
return pth_error(FALSE, EINVAL);
/* allocate the context structure */
if ((uctx = (pth_uctx_t)malloc(sizeof(struct pth_uctx_st))) == NULL)
return pth_error(FALSE, errno);
/* initialize the context structure */
uctx->uc_stack_own = FALSE;
uctx->uc_stack_ptr = NULL;
uctx->uc_stack_len = 0;
uctx->uc_mctx_set = FALSE;
memset((void *)&uctx->uc_mctx, 0, sizeof(pth_mctx_t));
/* pass result to caller */
*puctx = uctx;
return TRUE;
}
/* trampoline context */
typedef struct {
pth_mctx_t *mctx_parent;
pth_uctx_t uctx_this;
pth_uctx_t uctx_after;
void (*start_func)(void *);
void *start_arg;
} pth_uctx_trampoline_t;
pth_uctx_trampoline_t pth_uctx_trampoline_ctx;
/* trampoline function for pth_uctx_make() */
static void pth_uctx_trampoline(void)
{
volatile pth_uctx_trampoline_t ctx;
/* move context information from global to local storage */
ctx.mctx_parent = pth_uctx_trampoline_ctx.mctx_parent;
ctx.uctx_this = pth_uctx_trampoline_ctx.uctx_this;
ctx.uctx_after = pth_uctx_trampoline_ctx.uctx_after;
ctx.start_func = pth_uctx_trampoline_ctx.start_func;
ctx.start_arg = pth_uctx_trampoline_ctx.start_arg;
/* switch back to parent */
pth_mctx_switch(&(ctx.uctx_this->uc_mctx), ctx.mctx_parent);
/* enter start function */
(*ctx.start_func)(ctx.start_arg);
/* switch to successor user-space context */
if (ctx.uctx_after != NULL)
pth_mctx_restore(&(ctx.uctx_after->uc_mctx));
/* terminate process (the only reasonable thing to do here) */
exit(0);
/* NOTREACHED */
return;
}
/* make setup of user-space context structure */
int
pth_uctx_make(
pth_uctx_t uctx,
char *sk_addr, size_t sk_size,
const sigset_t *sigmask,
void (*start_func)(void *), void *start_arg,
pth_uctx_t uctx_after)
{
pth_mctx_t mctx_parent;
sigset_t ss;
/* argument sanity checking */
if (uctx == NULL || start_func == NULL || sk_size < 16*1024)
return pth_error(FALSE, EINVAL);
/* configure run-time stack */
if (sk_addr == NULL) {
if ((sk_addr = (char *)malloc(sk_size)) == NULL)
return pth_error(FALSE, errno);
uctx->uc_stack_own = TRUE;
}
else
uctx->uc_stack_own = FALSE;
uctx->uc_stack_ptr = sk_addr;
uctx->uc_stack_len = sk_size;
/* configure the underlying machine context */
if (!pth_mctx_set(&uctx->uc_mctx, pth_uctx_trampoline,
uctx->uc_stack_ptr, uctx->uc_stack_ptr+uctx->uc_stack_len))
return pth_error(FALSE, errno);
/* move context information into global storage for the trampoline jump */
pth_uctx_trampoline_ctx.mctx_parent = &mctx_parent;
pth_uctx_trampoline_ctx.uctx_this = uctx;
pth_uctx_trampoline_ctx.uctx_after = uctx_after;
pth_uctx_trampoline_ctx.start_func = start_func;
pth_uctx_trampoline_ctx.start_arg = start_arg;
/* optionally establish temporary signal mask */
if (sigmask != NULL)
sigprocmask(SIG_SETMASK, sigmask, &ss);
/* perform the trampoline step */
pth_mctx_switch(&mctx_parent, &(uctx->uc_mctx));
/* optionally restore original signal mask */
if (sigmask != NULL)
sigprocmask(SIG_SETMASK, &ss, NULL);
/* finally flag that the context is now configured */
uctx->uc_mctx_set = TRUE;
return TRUE;
}
/* switch from current to other user-space context */
int
pth_uctx_switch(
pth_uctx_t uctx_from,
pth_uctx_t uctx_to)
{
/* argument sanity checking */
if (uctx_from == NULL || uctx_to == NULL)
return pth_error(FALSE, EINVAL);
if (!(uctx_to->uc_mctx_set))
return pth_error(FALSE, EPERM);
/* switch underlying machine context */
uctx_from->uc_mctx_set = TRUE;
pth_mctx_switch(&(uctx_from->uc_mctx), &(uctx_to->uc_mctx));
return TRUE;
}
/* destroy user-space context structure */
int
pth_uctx_destroy(
pth_uctx_t uctx)
{
/* argument sanity checking */
if (uctx == NULL)
return pth_error(FALSE, EINVAL);
/* deallocate dynamically allocated stack */
if (uctx->uc_stack_own && uctx->uc_stack_ptr != NULL)
free(uctx->uc_stack_ptr);
/* deallocate context structure */
free(uctx);
return TRUE;
}