interrupted syscalls run asyncs before throwing syserror
[bpt/guile.git] / libguile / error.c
CommitLineData
93003b16 1/* Copyright (C) 1995,1996,1997,1998,2000,2001, 2004, 2006, 2010 Free Software Foundation, Inc.
0f2d19dd 2 *
73be1d9e 3 * This library is free software; you can redistribute it and/or
53befeb7
NJ
4 * modify it under the terms of the GNU Lesser General Public License
5 * as published by the Free Software Foundation; either version 3 of
6 * the License, or (at your option) any later version.
0f2d19dd 7 *
53befeb7
NJ
8 * This library is distributed in the hope that it will be useful, but
9 * WITHOUT ANY WARRANTY; without even the implied warranty of
73be1d9e
MV
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
11 * Lesser General Public License for more details.
0f2d19dd 12 *
73be1d9e
MV
13 * You should have received a copy of the GNU Lesser General Public
14 * License along with this library; if not, write to the Free Software
53befeb7
NJ
15 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
16 * 02110-1301 USA
73be1d9e 17 */
1bbd0b84 18
1bbd0b84 19
0f2d19dd
JB
20\f
21
dbb605f5 22#ifdef HAVE_CONFIG_H
4600886f
RB
23# include <config.h>
24#endif
25
93003b16 26#include <stdlib.h>
0f2d19dd 27#include <stdio.h>
e6e2e95a 28#include <errno.h>
bd9e24b3 29
a0599745 30#include "libguile/_scm.h"
4af3c6f1 31#include "libguile/dynwind.h"
a0599745
MD
32#include "libguile/pairs.h"
33#include "libguile/strings.h"
34#include "libguile/throw.h"
20e6290e 35
a0599745
MD
36#include "libguile/validate.h"
37#include "libguile/error.h"
0f2d19dd 38
bd9e24b3
GH
39#ifdef HAVE_STRING_H
40#include <string.h>
41#endif
95b88819
GH
42#ifdef HAVE_UNISTD_H
43#include <unistd.h>
44#endif
7beabedb
MG
45
46/* For Windows... */
47#ifdef HAVE_IO_H
48#include <io.h>
49#endif
0f2d19dd
JB
50\f
51
0f2d19dd
JB
52/* {Errors and Exceptional Conditions}
53 */
54
0f2d19dd 55
24d1f171 56/* Scheme interface to scm_error_scm. */
7cb1d4d3 57void
1bbd0b84 58scm_error (SCM key, const char *subr, const char *message, SCM args, SCM rest)
7cb1d4d3 59{
24d1f171
MV
60 scm_error_scm
61 (key,
62 (subr == NULL) ? SCM_BOOL_F : scm_from_locale_string (subr),
63 (message == NULL) ? SCM_BOOL_F : scm_from_locale_string (message),
64 args, rest);
7cb1d4d3 65}
0f2d19dd 66
24d1f171 67/* All errors should pass through here. */
3b3b36dd 68SCM_DEFINE (scm_error_scm, "scm-error", 5, 0, 0,
1e6808ea
MG
69 (SCM key, SCM subr, SCM message, SCM args, SCM data),
70 "Raise an error with key @var{key}. @var{subr} can be a string\n"
71 "naming the procedure associated with the error, or @code{#f}.\n"
72 "@var{message} is the error message string, possibly containing\n"
73 "@code{~S} and @code{~A} escapes. When an error is reported,\n"
74 "these are replaced by formatting the corresponding members of\n"
75 "@var{args}: @code{~A} (was @code{%s} in older versions of\n"
76 "Guile) formats using @code{display} and @code{~S} (was\n"
77 "@code{%S}) formats using @code{write}. @var{data} is a list or\n"
78 "@code{#f} depending on @var{key}: if @var{key} is\n"
79 "@code{system-error} then it should be a list containing the\n"
80 "Unix @code{errno} value; If @var{key} is @code{signal} then it\n"
cdd8c091
MV
81 "should be a list containing the Unix signal number; If\n"
82 "@var{key} is @code{out-of-range} or @code{wrong-type-arg},\n"
83 "it is a list containing the bad value; otherwise\n"
1e6808ea 84 "it will usually be @code{#f}.")
1bbd0b84 85#define FUNC_NAME s_scm_error_scm
c37e0e55 86{
24d1f171 87 if (scm_gc_running_p)
a6d9e5ab 88 {
24d1f171
MV
89 /* The error occured during GC --- abort */
90 fprintf (stderr, "Guile: error during GC.\n"),
91 abort ();
a6d9e5ab 92 }
89958ad0 93
24d1f171
MV
94 scm_ithrow (key, scm_list_4 (subr, message, args, data), 1);
95
96 /* No return, but just in case: */
97 fprintf (stderr, "Guile scm_ithrow returned!\n");
93003b16 98 exit (EXIT_FAILURE);
c37e0e55 99}
1bbd0b84 100#undef FUNC_NAME
c37e0e55 101
b4e15479
SJ
102#ifdef __MINGW32__
103# include "win32-socket.h"
104# define SCM_I_STRERROR(err) \
105 ((err >= WSABASEERR) ? scm_i_socket_strerror (err) : strerror (err))
106# define SCM_I_ERRNO() \
107 (errno ? errno : scm_i_socket_errno ())
108#else
109# define SCM_I_STRERROR(err) strerror (err)
110# define SCM_I_ERRNO() errno
111#endif /* __MINGW32__ */
112
4af3c6f1
KR
113/* strerror may not be thread safe, for instance in glibc (version 2.3.2) an
114 error number not among the known values results in a string like "Unknown
115 error 9999" formed in a static buffer, which will be overwritten by a
116 similar call in another thread. A test program running two threads with
117 different unknown error numbers can trip this fairly quickly.
118
119 Some systems don't do what glibc does, instead just giving a single
120 "Unknown error" for unrecognised numbers. It doesn't seem worth trying
121 to tell if that's the case, a mutex is reasonably fast, and strerror
122 isn't needed very often.
123
124 strerror_r (when available) could be used, it might be a touch faster
125 than a frame and a mutex, though there's probably not much
126 difference. */
127
a1ec6916 128SCM_DEFINE (scm_strerror, "strerror", 1, 0, 0,
1bbd0b84 129 (SCM err),
1e6808ea
MG
130 "Return the Unix error message corresponding to @var{err}, which\n"
131 "must be an integer value.")
1bbd0b84 132#define FUNC_NAME s_scm_strerror
efb997f5 133{
4af3c6f1 134 SCM ret;
661ae7ab
MV
135 scm_dynwind_begin (0);
136 scm_i_dynwind_pthread_mutex_lock (&scm_i_misc_mutex);
4af3c6f1 137
468e87a7 138 ret = scm_from_locale_string (SCM_I_STRERROR (scm_to_int (err)));
4af3c6f1 139
661ae7ab 140 scm_dynwind_end ();
4af3c6f1 141 return ret;
efb997f5 142}
1bbd0b84 143#undef FUNC_NAME
efb997f5 144
a7f54aed 145SCM_GLOBAL_SYMBOL (scm_system_error_key, "system-error");
52859adf 146void
1bbd0b84 147scm_syserror (const char *subr)
52859adf 148{
4af3c6f1 149 SCM err = scm_from_int (SCM_I_ERRNO ());
41e82649
AW
150
151 /* It could be that we're getting here because the syscall was
152 interrupted by a signal. In that case a signal handler might have
153 been queued to run. The signal handler probably throws an
154 exception.
155
156 If we don't try to run the signal handler now, it will run later,
157 which would result in two exceptions being thrown: this syserror,
158 and then at some later time the exception thrown by the async
159 signal handler.
160
161 The problem is that we don't know if handling the signal caused an
162 async to be queued. By this time scmsigs.c:take_signal will have
163 written a byte on the fd, but we don't know if the signal-handling
164 thread has read it off and queued an async.
165
166 Ideally we need some API like scm_i_ensure_signals_delivered() to
167 catch up signal delivery. Barring that, we just cross our digits
168 and pray; it could be that we handle the signal in time, and just
169 throw once, or it could be that we miss the deadline and throw
170 twice.
171 */
172#ifdef EINTR
173 if (scm_to_int (err) == EINTR)
174 SCM_ASYNC_TICK;
175#endif
176
01f61221 177 scm_error (scm_system_error_key,
52859adf 178 subr,
70d63753 179 "~A",
4af3c6f1
KR
180 scm_cons (scm_strerror (err), SCM_EOL),
181 scm_cons (err, SCM_EOL));
52859adf
GH
182}
183
184void
1bbd0b84 185scm_syserror_msg (const char *subr, const char *message, SCM args, int eno)
52859adf 186{
41e82649
AW
187 /* See above note about the EINTR signal handling race. */
188#ifdef EINTR
189 if (eno == EINTR)
190 SCM_ASYNC_TICK;
191#endif
01f61221 192 scm_error (scm_system_error_key,
52859adf
GH
193 subr,
194 message,
195 args,
7888309b 196 scm_cons (scm_from_int (eno), SCM_EOL));
52859adf
GH
197}
198
a7f54aed 199SCM_GLOBAL_SYMBOL (scm_num_overflow_key, "numerical-overflow");
52859adf 200void
1bbd0b84 201scm_num_overflow (const char *subr)
52859adf 202{
01f61221 203 scm_error (scm_num_overflow_key,
52859adf
GH
204 subr,
205 "Numerical overflow",
206 SCM_BOOL_F,
207 SCM_BOOL_F);
208}
209
a7f54aed 210SCM_GLOBAL_SYMBOL (scm_out_of_range_key, "out-of-range");
52859adf 211void
1bbd0b84 212scm_out_of_range (const char *subr, SCM bad_value)
52859adf 213{
01f61221 214 scm_error (scm_out_of_range_key,
52859adf 215 subr,
cdd8c091 216 "Value out of range: ~S",
1afff620 217 scm_list_1 (bad_value),
cdd8c091 218 scm_list_1 (bad_value));
52859adf 219}
f5bf2977 220
1e76143f
GB
221void
222scm_out_of_range_pos (const char *subr, SCM bad_value, SCM pos)
223{
224 scm_error (scm_out_of_range_key,
225 subr,
cdd8c091 226 "Argument ~A out of range: ~S",
34d19ef6 227 scm_list_2 (pos, bad_value),
cdd8c091 228 scm_list_1 (bad_value));
1e76143f
GB
229}
230
231
a7f54aed 232SCM_GLOBAL_SYMBOL (scm_args_number_key, "wrong-number-of-args");
0f2d19dd 233void
1bbd0b84 234scm_wrong_num_args (SCM proc)
f5bf2977 235{
01f61221 236 scm_error (scm_args_number_key,
f5bf2977 237 NULL,
70d63753 238 "Wrong number of arguments to ~A",
1afff620 239 scm_list_1 (proc),
f5bf2977
GH
240 SCM_BOOL_F);
241}
242
9f40cd87
DH
243
244void
245scm_error_num_args_subr (const char *subr)
246{
247 scm_error (scm_args_number_key,
248 NULL,
249 "Wrong number of arguments to ~A",
468e87a7 250 scm_list_1 (scm_from_locale_string (subr)),
9f40cd87
DH
251 SCM_BOOL_F);
252}
253
254
a7f54aed 255SCM_GLOBAL_SYMBOL (scm_arg_type_key, "wrong-type-arg");
f5bf2977 256void
1bbd0b84 257scm_wrong_type_arg (const char *subr, int pos, SCM bad_value)
f5bf2977 258{
01f61221 259 scm_error (scm_arg_type_key,
f5bf2977 260 subr,
83e1ab6d 261 (pos == 0) ? "Wrong type: ~S"
70d63753 262 : "Wrong type argument in position ~A: ~S",
1afff620 263 (pos == 0) ? scm_list_1 (bad_value)
e11e83f3 264 : scm_list_2 (scm_from_int (pos), bad_value),
cdd8c091 265 scm_list_1 (bad_value));
f5bf2977
GH
266}
267
0193377d
MG
268void
269scm_i_wrong_type_arg_symbol (SCM symbol, int pos, SCM bad_value)
270{
271 scm_error_scm (scm_arg_type_key,
272 scm_symbol_to_string (symbol),
273 (pos == 0) ? scm_from_locale_string ("Wrong type: ~S")
274 : scm_from_locale_string ("Wrong type argument in position ~A: ~S"),
275 (pos == 0) ? scm_list_1 (bad_value)
276 : scm_list_2 (scm_from_int (pos), bad_value),
277 scm_list_1 (bad_value));
278 scm_remember_upto_here_2 (symbol, bad_value);
279}
280
b6791b2e
GB
281void
282scm_wrong_type_arg_msg (const char *subr, int pos, SCM bad_value, const char *szMessage)
283{
468e87a7 284 SCM msg = scm_from_locale_string (szMessage);
cdd8c091
MV
285 if (pos == 0)
286 {
287 scm_error (scm_arg_type_key,
288 subr, "Wrong type (expecting ~A): ~S",
289 scm_list_2 (msg, bad_value),
290 scm_list_1 (bad_value));
291 }
292 else
293 {
294 scm_error (scm_arg_type_key,
295 subr,
296 "Wrong type argument in position ~A (expecting ~A): ~S",
297 scm_list_3 (scm_from_int (pos), msg, bad_value),
298 scm_list_1 (bad_value));
299 }
b6791b2e
GB
300}
301
302
a7f54aed 303SCM_GLOBAL_SYMBOL (scm_memory_alloc_key, "memory-allocation-error");
f5bf2977 304void
1bbd0b84 305scm_memory_error (const char *subr)
f5bf2977 306{
468e87a7
MV
307 fprintf (stderr, "FATAL: memory error in %s\n", subr);
308 abort ();
f5bf2977
GH
309}
310
a7f54aed 311SCM_GLOBAL_SYMBOL (scm_misc_error_key, "misc-error");
523f5266 312void
1bbd0b84 313scm_misc_error (const char *subr, const char *message, SCM args)
523f5266
GH
314{
315 scm_error (scm_misc_error_key, subr, message, args, SCM_BOOL_F);
316}
317
0f2d19dd
JB
318void
319scm_init_error ()
0f2d19dd 320{
648da032 321#include "libguile/cpp-E.c"
a0599745 322#include "libguile/error.x"
0f2d19dd
JB
323}
324
89e00824
ML
325
326/*
327 Local Variables:
328 c-file-style: "gnu"
329 End:
330*/