diff options
| author | Philipp Stephani | 2019-04-19 01:04:55 +0200 |
|---|---|---|
| committer | Philipp Stephani | 2019-04-19 01:04:55 +0200 |
| commit | 23a82cba12380b0905670c34395dc460a4bc9984 (patch) | |
| tree | df001ea84a8173dab9381a3ec75d36d25f6a3650 /src | |
| parent | e712a8fe0929a18eaf3f4ec83b023f475afdc4d4 (diff) | |
| download | emacs-23a82cba12380b0905670c34395dc460a4bc9984.tar.gz emacs-23a82cba12380b0905670c34395dc460a4bc9984.zip | |
Refactoring: have CATCHER_ALL also catch signals.
In all cases where we use a CATCHER_ALL handler we also want to catch
signals. Therefore have 'signal' respect CATCHER_ALL. Adapt internal
interfaces so that handlers can distinguish among the two types of
nonlocal exits in CATCHER_ALL handlers.
* src/lisp.h (enum nonlocal_exit): New enum.
(struct handler): Add member 'nonlocal_exit' to hold the type of
nonlocal exit during stack unwinding.
* src/eval.c (signal_or_quit): Also respect CATCHER_ALL handlers.
(unwind_to_catch): Store nonlocal exit type in catch structure.
(Fthrow, signal_or_quit): Adapt callers.
(internal_catch_all): Install only one handler. Give handler a
nonlocal exit type argument.
(internal_catch_all_1): Remove, no longer needed.
* src/emacs-module.c (MODULE_SETJMP): Install only one handler.
(module_handle_nonlocal_exit): New function to handle all nonlocal
exits.
(MODULE_SETJMP_1): Pass nonlocal exit type to handler function.
(module_handle_signal, module_handle_throw): Remove, no longer needed.
* src/json.c (json_handle_nonlocal_exit): New helper function.
(json_insert_callback): Adapt to change in 'internal_catch_all'.
Diffstat (limited to 'src')
| -rw-r--r-- | src/emacs-module.c | 37 | ||||
| -rw-r--r-- | src/eval.c | 49 | ||||
| -rw-r--r-- | src/json.c | 15 | ||||
| -rw-r--r-- | src/lisp.h | 18 |
4 files changed, 64 insertions, 55 deletions
diff --git a/src/emacs-module.c b/src/emacs-module.c index fd033e8044f..393a4354b88 100644 --- a/src/emacs-module.c +++ b/src/emacs-module.c | |||
| @@ -201,8 +201,8 @@ static emacs_env *initialize_environment (emacs_env *, | |||
| 201 | static void finalize_environment (emacs_env *); | 201 | static void finalize_environment (emacs_env *); |
| 202 | static void finalize_environment_unwind (void *); | 202 | static void finalize_environment_unwind (void *); |
| 203 | static void finalize_runtime_unwind (void *); | 203 | static void finalize_runtime_unwind (void *); |
| 204 | static void module_handle_signal (emacs_env *, Lisp_Object); | 204 | static void module_handle_nonlocal_exit (emacs_env *, enum nonlocal_exit, |
| 205 | static void module_handle_throw (emacs_env *, Lisp_Object); | 205 | Lisp_Object); |
| 206 | static void module_non_local_exit_signal_1 (emacs_env *, | 206 | static void module_non_local_exit_signal_1 (emacs_env *, |
| 207 | Lisp_Object, Lisp_Object); | 207 | Lisp_Object, Lisp_Object); |
| 208 | static void module_non_local_exit_throw_1 (emacs_env *, | 208 | static void module_non_local_exit_throw_1 (emacs_env *, |
| @@ -231,11 +231,8 @@ static bool module_assertions = false; | |||
| 231 | or a pointer to handle non-local exits. The function must have an | 231 | or a pointer to handle non-local exits. The function must have an |
| 232 | ENV parameter. The function will return the specified value if a | 232 | ENV parameter. The function will return the specified value if a |
| 233 | signal or throw is caught. */ | 233 | signal or throw is caught. */ |
| 234 | /* TODO: Have Fsignal check for CATCHER_ALL so we only have to install | ||
| 235 | one handler. */ | ||
| 236 | #define MODULE_HANDLE_NONLOCAL_EXIT(retval) \ | 234 | #define MODULE_HANDLE_NONLOCAL_EXIT(retval) \ |
| 237 | MODULE_SETJMP (CONDITION_CASE, module_handle_signal, retval); \ | 235 | MODULE_SETJMP (CATCHER_ALL, module_handle_nonlocal_exit, retval) |
| 238 | MODULE_SETJMP (CATCHER_ALL, module_handle_throw, retval) | ||
| 239 | 236 | ||
| 240 | #define MODULE_SETJMP(handlertype, handlerfunc, retval) \ | 237 | #define MODULE_SETJMP(handlertype, handlerfunc, retval) \ |
| 241 | MODULE_SETJMP_1 (handlertype, handlerfunc, retval, \ | 238 | MODULE_SETJMP_1 (handlertype, handlerfunc, retval, \ |
| @@ -271,7 +268,7 @@ static bool module_assertions = false; | |||
| 271 | = c0; \ | 268 | = c0; \ |
| 272 | if (sys_setjmp (c->jmp)) \ | 269 | if (sys_setjmp (c->jmp)) \ |
| 273 | { \ | 270 | { \ |
| 274 | (handlerfunc) (env, c->val); \ | 271 | (handlerfunc) (env, c->nonlocal_exit, c->val); \ |
| 275 | return retval; \ | 272 | return retval; \ |
| 276 | } \ | 273 | } \ |
| 277 | do { } while (false) | 274 | do { } while (false) |
| @@ -1183,20 +1180,22 @@ module_reset_handlerlist (struct handler **phandlerlist) | |||
| 1183 | handlerlist = handlerlist->next; | 1180 | handlerlist = handlerlist->next; |
| 1184 | } | 1181 | } |
| 1185 | 1182 | ||
| 1186 | /* Called on `signal'. ERR is a pair (SYMBOL . DATA), which gets | 1183 | /* Called on `signal' and `throw'. DATA is a pair |
| 1187 | stored in the environment. Set the pending non-local exit flag. */ | 1184 | (ERROR-SYMBOL . ERROR-DATA) or (TAG . VALUE), which gets stored in |
| 1185 | the environment. Set the pending non-local exit flag. */ | ||
| 1188 | static void | 1186 | static void |
| 1189 | module_handle_signal (emacs_env *env, Lisp_Object err) | 1187 | module_handle_nonlocal_exit (emacs_env *env, enum nonlocal_exit type, |
| 1188 | Lisp_Object data) | ||
| 1190 | { | 1189 | { |
| 1191 | module_non_local_exit_signal_1 (env, XCAR (err), XCDR (err)); | 1190 | switch (type) |
| 1192 | } | 1191 | { |
| 1193 | 1192 | case NONLOCAL_EXIT_SIGNAL: | |
| 1194 | /* Called on `throw'. TAG_VAL is a pair (TAG . VALUE), which gets | 1193 | module_non_local_exit_signal_1 (env, XCAR (data), XCDR (data)); |
| 1195 | stored in the environment. Set the pending non-local exit flag. */ | 1194 | break; |
| 1196 | static void | 1195 | case NONLOCAL_EXIT_THROW: |
| 1197 | module_handle_throw (emacs_env *env, Lisp_Object tag_val) | 1196 | module_non_local_exit_throw_1 (env, XCAR (data), XCDR (data)); |
| 1198 | { | 1197 | break; |
| 1199 | module_non_local_exit_throw_1 (env, XCAR (tag_val), XCDR (tag_val)); | 1198 | } |
| 1200 | } | 1199 | } |
| 1201 | 1200 | ||
| 1202 | 1201 | ||
diff --git a/src/eval.c b/src/eval.c index c2e996a9474..23fd0efd54a 100644 --- a/src/eval.c +++ b/src/eval.c | |||
| @@ -1134,13 +1134,15 @@ internal_catch (Lisp_Object tag, | |||
| 1134 | This is used for correct unwinding in Fthrow and Fsignal. */ | 1134 | This is used for correct unwinding in Fthrow and Fsignal. */ |
| 1135 | 1135 | ||
| 1136 | static AVOID | 1136 | static AVOID |
| 1137 | unwind_to_catch (struct handler *catch, Lisp_Object value) | 1137 | unwind_to_catch (struct handler *catch, enum nonlocal_exit type, |
| 1138 | Lisp_Object value) | ||
| 1138 | { | 1139 | { |
| 1139 | bool last_time; | 1140 | bool last_time; |
| 1140 | 1141 | ||
| 1141 | eassert (catch->next); | 1142 | eassert (catch->next); |
| 1142 | 1143 | ||
| 1143 | /* Save the value in the tag. */ | 1144 | /* Save the value in the tag. */ |
| 1145 | catch->nonlocal_exit = type; | ||
| 1144 | catch->val = value; | 1146 | catch->val = value; |
| 1145 | 1147 | ||
| 1146 | /* Restore certain special C variables. */ | 1148 | /* Restore certain special C variables. */ |
| @@ -1177,9 +1179,9 @@ Both TAG and VALUE are evalled. */ | |||
| 1177 | for (c = handlerlist; c; c = c->next) | 1179 | for (c = handlerlist; c; c = c->next) |
| 1178 | { | 1180 | { |
| 1179 | if (c->type == CATCHER_ALL) | 1181 | if (c->type == CATCHER_ALL) |
| 1180 | unwind_to_catch (c, Fcons (tag, value)); | 1182 | unwind_to_catch (c, NONLOCAL_EXIT_THROW, Fcons (tag, value)); |
| 1181 | if (c->type == CATCHER && EQ (c->tag_or_ch, tag)) | 1183 | if (c->type == CATCHER && EQ (c->tag_or_ch, tag)) |
| 1182 | unwind_to_catch (c, value); | 1184 | unwind_to_catch (c, NONLOCAL_EXIT_THROW, value); |
| 1183 | } | 1185 | } |
| 1184 | xsignal2 (Qno_catch, tag, value); | 1186 | xsignal2 (Qno_catch, tag, value); |
| 1185 | } | 1187 | } |
| @@ -1427,44 +1429,21 @@ internal_condition_case_n (Lisp_Object (*bfun) (ptrdiff_t, Lisp_Object *), | |||
| 1427 | } | 1429 | } |
| 1428 | } | 1430 | } |
| 1429 | 1431 | ||
| 1430 | static Lisp_Object | ||
| 1431 | internal_catch_all_1 (Lisp_Object (*function) (void *), void *argument) | ||
| 1432 | { | ||
| 1433 | struct handler *c = push_handler_nosignal (Qt, CATCHER_ALL); | ||
| 1434 | if (c == NULL) | ||
| 1435 | return Qcatch_all_memory_full; | ||
| 1436 | |||
| 1437 | if (sys_setjmp (c->jmp) == 0) | ||
| 1438 | { | ||
| 1439 | Lisp_Object val = function (argument); | ||
| 1440 | eassert (handlerlist == c); | ||
| 1441 | handlerlist = c->next; | ||
| 1442 | return val; | ||
| 1443 | } | ||
| 1444 | else | ||
| 1445 | { | ||
| 1446 | eassert (handlerlist == c); | ||
| 1447 | Lisp_Object val = c->val; | ||
| 1448 | handlerlist = c->next; | ||
| 1449 | Fsignal (Qno_catch, val); | ||
| 1450 | } | ||
| 1451 | } | ||
| 1452 | |||
| 1453 | /* Like a combination of internal_condition_case_1 and internal_catch. | 1432 | /* Like a combination of internal_condition_case_1 and internal_catch. |
| 1454 | Catches all signals and throws. Never exits nonlocally; returns | 1433 | Catches all signals and throws. Never exits nonlocally; returns |
| 1455 | Qcatch_all_memory_full if no handler could be allocated. */ | 1434 | Qcatch_all_memory_full if no handler could be allocated. */ |
| 1456 | 1435 | ||
| 1457 | Lisp_Object | 1436 | Lisp_Object |
| 1458 | internal_catch_all (Lisp_Object (*function) (void *), void *argument, | 1437 | internal_catch_all (Lisp_Object (*function) (void *), void *argument, |
| 1459 | Lisp_Object (*handler) (Lisp_Object)) | 1438 | Lisp_Object (*handler) (enum nonlocal_exit, Lisp_Object)) |
| 1460 | { | 1439 | { |
| 1461 | struct handler *c = push_handler_nosignal (Qt, CONDITION_CASE); | 1440 | struct handler *c = push_handler_nosignal (Qt, CATCHER_ALL); |
| 1462 | if (c == NULL) | 1441 | if (c == NULL) |
| 1463 | return Qcatch_all_memory_full; | 1442 | return Qcatch_all_memory_full; |
| 1464 | 1443 | ||
| 1465 | if (sys_setjmp (c->jmp) == 0) | 1444 | if (sys_setjmp (c->jmp) == 0) |
| 1466 | { | 1445 | { |
| 1467 | Lisp_Object val = internal_catch_all_1 (function, argument); | 1446 | Lisp_Object val = function (argument); |
| 1468 | eassert (handlerlist == c); | 1447 | eassert (handlerlist == c); |
| 1469 | handlerlist = c->next; | 1448 | handlerlist = c->next; |
| 1470 | return val; | 1449 | return val; |
| @@ -1472,9 +1451,10 @@ internal_catch_all (Lisp_Object (*function) (void *), void *argument, | |||
| 1472 | else | 1451 | else |
| 1473 | { | 1452 | { |
| 1474 | eassert (handlerlist == c); | 1453 | eassert (handlerlist == c); |
| 1454 | enum nonlocal_exit type = c->nonlocal_exit; | ||
| 1475 | Lisp_Object val = c->val; | 1455 | Lisp_Object val = c->val; |
| 1476 | handlerlist = c->next; | 1456 | handlerlist = c->next; |
| 1477 | return handler (val); | 1457 | return handler (type, val); |
| 1478 | } | 1458 | } |
| 1479 | } | 1459 | } |
| 1480 | 1460 | ||
| @@ -1645,6 +1625,11 @@ signal_or_quit (Lisp_Object error_symbol, Lisp_Object data, bool keyboard_quit) | |||
| 1645 | 1625 | ||
| 1646 | for (h = handlerlist; h; h = h->next) | 1626 | for (h = handlerlist; h; h = h->next) |
| 1647 | { | 1627 | { |
| 1628 | if (h->type == CATCHER_ALL) | ||
| 1629 | { | ||
| 1630 | clause = Qt; | ||
| 1631 | break; | ||
| 1632 | } | ||
| 1648 | if (h->type != CONDITION_CASE) | 1633 | if (h->type != CONDITION_CASE) |
| 1649 | continue; | 1634 | continue; |
| 1650 | clause = find_handler_clause (h->tag_or_ch, conditions); | 1635 | clause = find_handler_clause (h->tag_or_ch, conditions); |
| @@ -1678,7 +1663,7 @@ signal_or_quit (Lisp_Object error_symbol, Lisp_Object data, bool keyboard_quit) | |||
| 1678 | Lisp_Object unwind_data | 1663 | Lisp_Object unwind_data |
| 1679 | = (NILP (error_symbol) ? data : Fcons (error_symbol, data)); | 1664 | = (NILP (error_symbol) ? data : Fcons (error_symbol, data)); |
| 1680 | 1665 | ||
| 1681 | unwind_to_catch (h, unwind_data); | 1666 | unwind_to_catch (h, NONLOCAL_EXIT_SIGNAL, unwind_data); |
| 1682 | } | 1667 | } |
| 1683 | else | 1668 | else |
| 1684 | { | 1669 | { |
diff --git a/src/json.c b/src/json.c index 5917212899e..014ac3e3168 100644 --- a/src/json.c +++ b/src/json.c | |||
| @@ -665,6 +665,18 @@ json_insert (void *data) | |||
| 665 | return Qnil; | 665 | return Qnil; |
| 666 | } | 666 | } |
| 667 | 667 | ||
| 668 | static Lisp_Object | ||
| 669 | json_handle_nonlocal_exit (enum nonlocal_exit type, Lisp_Object data) | ||
| 670 | { | ||
| 671 | switch (type) | ||
| 672 | { | ||
| 673 | case NONLOCAL_EXIT_SIGNAL: | ||
| 674 | return data; | ||
| 675 | case NONLOCAL_EXIT_THROW: | ||
| 676 | return Fcons (Qno_catch, data); | ||
| 677 | } | ||
| 678 | } | ||
| 679 | |||
| 668 | struct json_insert_data | 680 | struct json_insert_data |
| 669 | { | 681 | { |
| 670 | /* This tracks how many bytes were inserted by the callback since | 682 | /* This tracks how many bytes were inserted by the callback since |
| @@ -687,7 +699,8 @@ json_insert_callback (const char *buffer, size_t size, void *data) | |||
| 687 | struct json_insert_data *d = data; | 699 | struct json_insert_data *d = data; |
| 688 | struct json_buffer_and_size buffer_and_size | 700 | struct json_buffer_and_size buffer_and_size |
| 689 | = {.buffer = buffer, .size = size, .inserted_bytes = d->inserted_bytes}; | 701 | = {.buffer = buffer, .size = size, .inserted_bytes = d->inserted_bytes}; |
| 690 | d->error = internal_catch_all (json_insert, &buffer_and_size, Fidentity); | 702 | d->error = internal_catch_all (json_insert, &buffer_and_size, |
| 703 | json_handle_nonlocal_exit); | ||
| 691 | d->inserted_bytes = buffer_and_size.inserted_bytes; | 704 | d->inserted_bytes = buffer_and_size.inserted_bytes; |
| 692 | return NILP (d->error) ? 0 : -1; | 705 | return NILP (d->error) ? 0 : -1; |
| 693 | } | 706 | } |
diff --git a/src/lisp.h b/src/lisp.h index 0da20375228..2aa767b86c2 100644 --- a/src/lisp.h +++ b/src/lisp.h | |||
| @@ -3262,8 +3262,10 @@ SPECPDL_INDEX (void) | |||
| 3262 | member is TAG, and then unbinds to it. The `val' member is used to | 3262 | member is TAG, and then unbinds to it. The `val' member is used to |
| 3263 | hold VAL while the stack is unwound; `val' is returned as the value | 3263 | hold VAL while the stack is unwound; `val' is returned as the value |
| 3264 | of the catch form. If there is a handler of type CATCHER_ALL, it will | 3264 | of the catch form. If there is a handler of type CATCHER_ALL, it will |
| 3265 | be treated as a handler for all invocations of `throw'; in this case | 3265 | be treated as a handler for all invocations of `signal' and `throw'; |
| 3266 | `val' will be set to (TAG . VAL). | 3266 | in this case `val' will be set to (ERROR-SYMBOL . DATA) or (TAG . VAL), |
| 3267 | respectively. During stack unwinding, `nonlocal_exit' is set to | ||
| 3268 | specify the type of nonlocal exit that caused the stack unwinding. | ||
| 3267 | 3269 | ||
| 3268 | All the other members are concerned with restoring the interpreter | 3270 | All the other members are concerned with restoring the interpreter |
| 3269 | state. | 3271 | state. |
| @@ -3273,11 +3275,21 @@ SPECPDL_INDEX (void) | |||
| 3273 | 3275 | ||
| 3274 | enum handlertype { CATCHER, CONDITION_CASE, CATCHER_ALL }; | 3276 | enum handlertype { CATCHER, CONDITION_CASE, CATCHER_ALL }; |
| 3275 | 3277 | ||
| 3278 | enum nonlocal_exit | ||
| 3279 | { | ||
| 3280 | NONLOCAL_EXIT_SIGNAL, | ||
| 3281 | NONLOCAL_EXIT_THROW, | ||
| 3282 | }; | ||
| 3283 | |||
| 3276 | struct handler | 3284 | struct handler |
| 3277 | { | 3285 | { |
| 3278 | enum handlertype type; | 3286 | enum handlertype type; |
| 3279 | Lisp_Object tag_or_ch; | 3287 | Lisp_Object tag_or_ch; |
| 3288 | |||
| 3289 | /* The next two are set by unwind_to_catch. */ | ||
| 3290 | enum nonlocal_exit nonlocal_exit; | ||
| 3280 | Lisp_Object val; | 3291 | Lisp_Object val; |
| 3292 | |||
| 3281 | struct handler *next; | 3293 | struct handler *next; |
| 3282 | struct handler *nextfree; | 3294 | struct handler *nextfree; |
| 3283 | 3295 | ||
| @@ -4129,7 +4141,7 @@ extern Lisp_Object internal_condition_case_2 (Lisp_Object (*) (Lisp_Object, Lisp | |||
| 4129 | extern Lisp_Object internal_condition_case_n | 4141 | extern Lisp_Object internal_condition_case_n |
| 4130 | (Lisp_Object (*) (ptrdiff_t, Lisp_Object *), ptrdiff_t, Lisp_Object *, | 4142 | (Lisp_Object (*) (ptrdiff_t, Lisp_Object *), ptrdiff_t, Lisp_Object *, |
| 4131 | Lisp_Object, Lisp_Object (*) (Lisp_Object, ptrdiff_t, Lisp_Object *)); | 4143 | Lisp_Object, Lisp_Object (*) (Lisp_Object, ptrdiff_t, Lisp_Object *)); |
| 4132 | extern Lisp_Object internal_catch_all (Lisp_Object (*) (void *), void *, Lisp_Object (*) (Lisp_Object)); | 4144 | extern Lisp_Object internal_catch_all (Lisp_Object (*) (void *), void *, Lisp_Object (*) (enum nonlocal_exit, Lisp_Object)); |
| 4133 | extern struct handler *push_handler (Lisp_Object, enum handlertype); | 4145 | extern struct handler *push_handler (Lisp_Object, enum handlertype); |
| 4134 | extern struct handler *push_handler_nosignal (Lisp_Object, enum handlertype); | 4146 | extern struct handler *push_handler_nosignal (Lisp_Object, enum handlertype); |
| 4135 | extern void specbind (Lisp_Object, Lisp_Object); | 4147 | extern void specbind (Lisp_Object, Lisp_Object); |