diff options
| author | Philipp Stephani | 2019-01-02 22:04:56 +0100 |
|---|---|---|
| committer | Philipp Stephani | 2019-02-24 22:43:07 +0100 |
| commit | 72ec233f2a1b8a6a9574e61588d0467caf41755c (patch) | |
| tree | 725add4413feb9cb7789576294099096e63d3044 /test/data | |
| parent | 5653b76d0bacf1edfc3d962c0bb991344cd80f6f (diff) | |
| download | emacs-72ec233f2a1b8a6a9574e61588d0467caf41755c.tar.gz emacs-72ec233f2a1b8a6a9574e61588d0467caf41755c.zip | |
Ignore pending_signals when checking for quits.
pending_signals is often set if no quit is pending. This results in
bugs in module code if the module returns but no quit is actually
pending.
As a better alternative, add a new process_input environment function
for Emacs 27. That function processes signals (like maybe_quit).
* configure.ac: Add module snippet for Emacs 27.
* src/module-env-27.h: New file.
* src/emacs-module.h.in: Add process_input function to environment
interface.
* src/emacs-module.c (module_should_quit): Use QUITP macro to check
whether the caller should quit.
(module_process_input): New function.
(initialize_environment): Use it.
* src/eval.c: Remove obsolete comment.
* test/data/emacs-module/mod-test.c (signal_wrong_type_argument)
(signal_errno): New helper functions.
(Fmod_test_sleep_until): New test module function.
* test/src/emacs-module-tests.el (mod-test-sleep-until): New unit
test.
* doc/lispref/internals.texi (Module Misc): Document process_input.
Diffstat (limited to 'test/data')
| -rw-r--r-- | test/data/emacs-module/mod-test.c | 69 |
1 files changed, 68 insertions, 1 deletions
diff --git a/test/data/emacs-module/mod-test.c b/test/data/emacs-module/mod-test.c index 98242e85baf..47ea159d0e7 100644 --- a/test/data/emacs-module/mod-test.c +++ b/test/data/emacs-module/mod-test.c | |||
| @@ -17,12 +17,20 @@ GNU General Public License for more details. | |||
| 17 | You should have received a copy of the GNU General Public License | 17 | You should have received a copy of the GNU General Public License |
| 18 | along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>. */ | 18 | along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>. */ |
| 19 | 19 | ||
| 20 | #include "config.h" | ||
| 21 | |||
| 20 | #include <assert.h> | 22 | #include <assert.h> |
| 23 | #include <errno.h> | ||
| 24 | #include <limits.h> | ||
| 21 | #include <stdio.h> | 25 | #include <stdio.h> |
| 22 | #include <stdlib.h> | 26 | #include <stdlib.h> |
| 23 | #include <limits.h> | 27 | #include <string.h> |
| 28 | #include <time.h> | ||
| 29 | |||
| 24 | #include <emacs-module.h> | 30 | #include <emacs-module.h> |
| 25 | 31 | ||
| 32 | #include "timespec.h" | ||
| 33 | |||
| 26 | int plugin_is_GPL_compatible; | 34 | int plugin_is_GPL_compatible; |
| 27 | 35 | ||
| 28 | #if INTPTR_MAX <= 0 | 36 | #if INTPTR_MAX <= 0 |
| @@ -299,6 +307,64 @@ Fmod_test_invalid_finalizer (emacs_env *env, ptrdiff_t nargs, emacs_value *args, | |||
| 299 | return env->funcall (env, env->intern (env, "garbage-collect"), 0, NULL); | 307 | return env->funcall (env, env->intern (env, "garbage-collect"), 0, NULL); |
| 300 | } | 308 | } |
| 301 | 309 | ||
| 310 | static void | ||
| 311 | signal_wrong_type_argument (emacs_env *env, const char *predicate, | ||
| 312 | emacs_value arg) | ||
| 313 | { | ||
| 314 | emacs_value symbol = env->intern (env, "wrong-type-argument"); | ||
| 315 | emacs_value elements[2] = {env->intern (env, predicate), arg}; | ||
| 316 | emacs_value data = env->funcall (env, env->intern (env, "list"), 2, elements); | ||
| 317 | env->non_local_exit_signal (env, symbol, data); | ||
| 318 | } | ||
| 319 | |||
| 320 | static void | ||
| 321 | signal_errno (emacs_env *env, const char *function) | ||
| 322 | { | ||
| 323 | const char *message = strerror (errno); | ||
| 324 | emacs_value message_value = env->make_string (env, message, strlen (message)); | ||
| 325 | emacs_value symbol = env->intern (env, "file-error"); | ||
| 326 | emacs_value elements[2] | ||
| 327 | = {env->make_string (env, function, strlen (function)), message_value}; | ||
| 328 | emacs_value data = env->funcall (env, env->intern (env, "list"), 2, elements); | ||
| 329 | env->non_local_exit_signal (env, symbol, data); | ||
| 330 | } | ||
| 331 | |||
| 332 | /* A long-running operation that occasionally calls `should_quit' or | ||
| 333 | `process_input'. */ | ||
| 334 | |||
| 335 | static emacs_value | ||
| 336 | Fmod_test_sleep_until (emacs_env *env, ptrdiff_t nargs, emacs_value *args, | ||
| 337 | void *data) | ||
| 338 | { | ||
| 339 | assert (nargs == 2); | ||
| 340 | const double until_seconds = env->extract_float (env, args[0]); | ||
| 341 | if (env->non_local_exit_check (env)) | ||
| 342 | return NULL; | ||
| 343 | if (until_seconds <= 0) | ||
| 344 | { | ||
| 345 | signal_wrong_type_argument (env, "cl-plusp", args[0]); | ||
| 346 | return NULL; | ||
| 347 | } | ||
| 348 | const bool process_input = env->is_not_nil (env, args[1]); | ||
| 349 | const struct timespec until = dtotimespec (until_seconds); | ||
| 350 | const struct timespec amount = make_timespec(0, 10000000); | ||
| 351 | while (true) | ||
| 352 | { | ||
| 353 | const struct timespec now = current_timespec (); | ||
| 354 | if (timespec_cmp (now, until) >= 0) | ||
| 355 | break; | ||
| 356 | if (nanosleep (&amount, NULL) && errno != EINTR) | ||
| 357 | { | ||
| 358 | signal_errno (env, "nanosleep"); | ||
| 359 | return NULL; | ||
| 360 | } | ||
| 361 | if ((process_input | ||
| 362 | && env->process_input (env) == emacs_process_input_quit) | ||
| 363 | || env->should_quit (env)) | ||
| 364 | return NULL; | ||
| 365 | } | ||
| 366 | return env->intern (env, "finished"); | ||
| 367 | } | ||
| 302 | 368 | ||
| 303 | /* Lisp utilities for easier readability (simple wrappers). */ | 369 | /* Lisp utilities for easier readability (simple wrappers). */ |
| 304 | 370 | ||
| @@ -367,6 +433,7 @@ emacs_module_init (struct emacs_runtime *ert) | |||
| 367 | DEFUN ("mod-test-invalid-load", Fmod_test_invalid_load, 0, 0, NULL, NULL); | 433 | DEFUN ("mod-test-invalid-load", Fmod_test_invalid_load, 0, 0, NULL, NULL); |
| 368 | DEFUN ("mod-test-invalid-finalizer", Fmod_test_invalid_finalizer, 0, 0, | 434 | DEFUN ("mod-test-invalid-finalizer", Fmod_test_invalid_finalizer, 0, 0, |
| 369 | NULL, NULL); | 435 | NULL, NULL); |
| 436 | DEFUN ("mod-test-sleep-until", Fmod_test_sleep_until, 2, 2, NULL, NULL); | ||
| 370 | 437 | ||
| 371 | #undef DEFUN | 438 | #undef DEFUN |
| 372 | 439 | ||