1 /* @(#)handlecond.c 1.25 07/05/23 Copyright 1985-2004 J. Schilling */
2 /*
3 * setup/clear a condition handler for a software signal
4 */
5 /*
6 * The contents of this file are subject to the terms of the
7 * Common Development and Distribution License, Version 1.0 only
8 * (the "License"). You may not use this file except in compliance
9 * with the License.
10 *
11 * See the file CDDL.Schily.txt in this distribution for details.
12 * A copy of the CDDL is also available via the Internet at
13 * http://www.opensource.org/licenses/cddl1.txt
14 *
15 * When distributing Covered Code, include this CDDL HEADER in each
16 * file and include the License file CDDL.Schily.txt from this distribution.
17 */
18 /*
19 * A procedure frame is marked to have handlers if the
20 * previous freme pointer for this procedure is odd.
21 * The even base value, in this case actually points to a SIGBLK which
22 * holds the saved "real" frame pointer.
23 * The SIGBLK mentioned above may me the start of a chain of SIGBLK's,
24 * containing different handlers.
25 *
26 * This will work on processors which support a frame pointer chain
27 * on the stack.
28 * On a processor which doesn't support this I think of a method
29 * where handlecond() has an own chain of frames, holding chains of
30 * SIGBLK's.
31 * In this case, a parameter has to be added to handlecond() and
32 * unhandlecond(). This parameter will be an opaque cookie which is zero
33 * on the first call to handlecond() in a procedure.
34 * A new cookie will be returned by handlecond() which must be used on
35 * each subsequent call to handlecond() and unhandlecond() in the same
36 * procedure.
37 *
38 * Copyright (c) 1985-2004 J. Schilling
39 */
40 #include <schily/mconfig.h>
41 #include <schily/sigblk.h>
42 #include <schily/standard.h>
43 #include <schily/stdlib.h>
44 #include <schily/string.h>
45 #include <schily/avoffset.h>
46 #include <schily/utypes.h>
47 #include <schily/schily.h>
48
49 #if !defined(AV_OFFSET) || !defined(FP_INDIR)
50 # ifdef HAVE_SCANSTACK
51 # undef HAVE_SCANSTACK
52 # endif
53 #endif
54
55 #ifdef HAVE_SCANSTACK
56 #include <schily/stkframe.h>
57 #else
58 extern SIGBLK *__roothandle;
59 #endif /* HAVE_SCANSTACK */
60
61 #define is_even(p) ((((long)(p)) & 1) == 0)
62 #define even(p) (((long)(p)) & ~1L)
63 #if defined(__sun) && (defined(__i386) || defined(__amd64))
64 /*
65 * Solaris x86 has a broken frame.h which defines the frame ptr to int.
66 */
67 #define odd(p) (((Intptr_t)(p)) | 1)
68 #else
69 #define odd(p) (void *)(((Intptr_t)(p)) | 1)
70 #endif
71
72 #ifdef __future__
73 #define even(p) (((long)(p)) - 1) /* will this work with 64 bit ?? */
74 #endif
75
76 EXPORT void starthandlecond __PR((SIGBLK *sp));
77
78 #ifdef PROTOTYPES
79 EXPORT void
handlecond(const char * signame,register SIGBLK * sp,int (* func)(const char *,long,long),long arg1)80 handlecond(const char *signame,
81 register SIGBLK *sp,
82 int (*func)(const char *, long, long),
83 long arg1)
84 #else
85 EXPORT void
86 handlecond(signame, sp, func, arg1)
87 char *signame;
88 register SIGBLK *sp;
89 BOOL (*func)();
90 long arg1;
91 #endif
92 {
93 register SIGBLK *this;
94 register SIGBLK *last = (SIGBLK *)NULL;
95 #ifdef HAVE_SCANSTACK
96 struct frame *fp = (struct frame *)NULL;
97 #endif
98 int slen;
99
100 if (signame == NULL || (slen = strlen(signame)) == 0) {
101 raisecond("handle_bad_name", (long)signame);
102 abort();
103 }
104
105 #ifdef HAVE_SCANSTACK
106 fp = (struct frame *)getfp();
107 fp = (struct frame *)fp->fr_savfp; /* point to frame of caller */
108 if (is_even(fp->fr_savfp)) {
109 /*
110 * Easy case: no handlers yet
111 * save real framepointer in sp->sb_savfp
112 */
113 sp->sb_savfp = (long **)fp->fr_savfp;
114 this = (SIGBLK *)NULL;
115 } else {
116 this = (SIGBLK *)even(fp->fr_savfp);
117 }
118 #else
119 this = __roothandle;
120 #endif
121
122 for (; this; this = this->sb_signext) {
123 if (this == sp) {
124 /*
125 * If a SIGBLK is reused, the name must not change.
126 */
127 if (this->sb_signame != NULL &&
128 !streql(this->sb_signame, signame)) {
129 raisecond("handle_reused_block", (long)signame);
130 abort();
131 }
132 sp->sb_sigfun = func;
133 sp->sb_sigarg = arg1;
134 return;
135 }
136 if (this->sb_signame != NULL &&
137 streql(this->sb_signame, signame)) {
138 if (last == (SIGBLK *)NULL) {
139 /*
140 * 'this' is the first entry in chain
141 */
142 if (this->sb_signext == (SIGBLK *)NULL) {
143 /*
144 * only 'this' entry is in chain, copy
145 * saved real frame pointer into new sp
146 */
147 sp->sb_savfp = this->sb_savfp;
148 } else {
149 #ifdef HAVE_SCANSTACK
150 /*
151 * make second entry first link in chain
152 */
153 this->sb_signext->sb_savfp =
154 this->sb_savfp;
155 fp->fr_savfp = odd(this->sb_signext);
156 #else
157 /*
158 * Cannot happen if scanning the stack
159 * is not possible...
160 */
161 raisecond("handle_is_empty", (long)0);
162 abort();
163 #endif
164 }
165 continue; /* don't trash 'last' ptr */
166 } else {
167 last->sb_signext = this->sb_signext;
168 }
169 }
170 last = this;
171 }
172 sp->sb_signext = (SIGBLK *)NULL;
173 sp->sb_signame = signame;
174 sp->sb_siglen = slen;
175 sp->sb_sigfun = func;
176 sp->sb_sigarg = arg1;
177 /*
178 * If there is a chain append to end of the chain, else make it first
179 */
180 if (last)
181 last->sb_signext = sp;
182 #ifdef HAVE_SCANSTACK
183 else
184 fp->fr_savfp = odd(sp);
185 #else
186 /*
187 * Cannot happen if scanning the stack is not possible...
188 */
189 else {
190 raisecond("handle_is_empty", (long)0);
191 abort();
192 }
193 #endif
194 }
195
196 EXPORT void
starthandlecond(sp)197 starthandlecond(sp)
198 register SIGBLK *sp;
199 {
200 #ifdef HAVE_SCANSTACK
201 struct frame *fp = NULL;
202
203 /*
204 * As the SCO OpenServer C-Compiler has a bug that may cause
205 * the first function call to getfp() been done before the
206 * new stack frame is created, we call getfp() twice.
207 */
208 (void) getfp();
209 #endif
210
211 sp->sb_signext = (SIGBLK *)NULL;
212 sp->sb_signame = NULL;
213 sp->sb_siglen = 0;
214 sp->sb_sigfun = (handlefunc_t)NULL;
215 sp->sb_sigarg = 0;
216
217 #ifdef HAVE_SCANSTACK
218 fp = (struct frame *)getfp();
219 fp = (struct frame *)fp->fr_savfp; /* point to frame of caller */
220
221 if (is_even(fp->fr_savfp)) {
222 /*
223 * Easy case: no handlers yet
224 * save real framepointer in sp
225 */
226 sp->sb_savfp = (long **)fp->fr_savfp;
227 fp->fr_savfp = odd(sp);
228 } else {
229 raisecond("handle_not_empty", (long)0);
230 abort();
231 }
232 #else
233 sp->sb_savfp = (long **)__roothandle;
234 __roothandle = sp;
235 #endif
236 }
237
238 EXPORT void
unhandlecond(sp)239 unhandlecond(sp)
240 register SIGBLK *sp;
241 {
242 #ifdef HAVE_SCANSTACK
243 register struct frame *fp;
244 register SIGBLK *sps;
245
246 /*
247 * As the SCO OpenServer C-Compiler has a bug that may cause
248 * the first function call to getfp() been done before the
249 * new stack frame is created, we call getfp() twice.
250 */
251 (void) getfp();
252 fp = (struct frame *)getfp();
253 fp = (struct frame *)fp->fr_savfp; /* point to frame of caller */
254
255 if (!is_even(fp->fr_savfp)) { /* if handlers */
256 sps = (SIGBLK *)even(fp->fr_savfp); /* point to SIGBLK */
257 /* real framepointer */
258 #if defined(__sun) && (defined(__i386) || defined(__amd64))
259 fp->fr_savfp = (intptr_t)sps->sb_savfp;
260 #else
261 fp->fr_savfp = (struct frame *)sps->sb_savfp;
262 #endif
263 }
264 #else
265 if (__roothandle == NULL) {
266 raisecond("handle_is_empty", (long)0);
267 abort();
268 }
269 /*
270 * Pop top level handler chain.
271 */
272 __roothandle = (SIGBLK *)__roothandle->sb_savfp;
273 #endif
274 }
275