diff options
| author | Andrea Corallo | 2020-07-26 09:40:02 +0200 |
|---|---|---|
| committer | Andrea Corallo | 2020-07-26 09:40:02 +0200 |
| commit | 7a161dc688f0eeee64e307a55efbc7d11bab3627 (patch) | |
| tree | 127cd6d6257e8e484a7021b12790610d308f7594 /src | |
| parent | 79ed90380547128b9919d407901a886fed0306b7 (diff) | |
| parent | 9f01ce6327af886f26399924a9aadf16cdd4fd9f (diff) | |
| download | emacs-7a161dc688f0eeee64e307a55efbc7d11bab3627.tar.gz emacs-7a161dc688f0eeee64e307a55efbc7d11bab3627.zip | |
Merge remote-tracking branch 'savahnna/master' into HEAD
Diffstat (limited to 'src')
| -rw-r--r-- | src/emacs-module.c | 108 | ||||
| -rw-r--r-- | src/emacs.c | 2 | ||||
| -rw-r--r-- | src/w32proc.c | 10 |
3 files changed, 86 insertions, 34 deletions
diff --git a/src/emacs-module.c b/src/emacs-module.c index 3d1827c7dad..e4e7da088d7 100644 --- a/src/emacs-module.c +++ b/src/emacs-module.c | |||
| @@ -78,6 +78,7 @@ To add a new module function, proceed as follows: | |||
| 78 | #include "emacs-module.h" | 78 | #include "emacs-module.h" |
| 79 | 79 | ||
| 80 | #include <stdarg.h> | 80 | #include <stdarg.h> |
| 81 | #include <stdbool.h> | ||
| 81 | #include <stddef.h> | 82 | #include <stddef.h> |
| 82 | #include <stdint.h> | 83 | #include <stdint.h> |
| 83 | #include <stdlib.h> | 84 | #include <stdlib.h> |
| @@ -154,11 +155,11 @@ struct emacs_value_frame | |||
| 154 | /* A structure that holds an initial frame (so that the first local | 155 | /* A structure that holds an initial frame (so that the first local |
| 155 | values require no dynamic allocation) and keeps track of the | 156 | values require no dynamic allocation) and keeps track of the |
| 156 | current frame. */ | 157 | current frame. */ |
| 157 | static struct emacs_value_storage | 158 | struct emacs_value_storage |
| 158 | { | 159 | { |
| 159 | struct emacs_value_frame initial; | 160 | struct emacs_value_frame initial; |
| 160 | struct emacs_value_frame *current; | 161 | struct emacs_value_frame *current; |
| 161 | } global_storage; | 162 | }; |
| 162 | 163 | ||
| 163 | 164 | ||
| 164 | /* Private runtime and environment members. */ | 165 | /* Private runtime and environment members. */ |
| @@ -371,10 +372,57 @@ module_get_environment (struct emacs_runtime *runtime) | |||
| 371 | } | 372 | } |
| 372 | 373 | ||
| 373 | /* To make global refs (GC-protected global values) keep a hash that | 374 | /* To make global refs (GC-protected global values) keep a hash that |
| 374 | maps global Lisp objects to reference counts. */ | 375 | maps global Lisp objects to 'struct module_global_reference' |
| 376 | objects. We store the 'emacs_value' in the hash table so that it | ||
| 377 | is automatically garbage-collected (Bug#42482). */ | ||
| 375 | 378 | ||
| 376 | static Lisp_Object Vmodule_refs_hash; | 379 | static Lisp_Object Vmodule_refs_hash; |
| 377 | 380 | ||
| 381 | /* Pseudovector type for global references. The pseudovector tag is | ||
| 382 | PVEC_OTHER since these values are never printed and don't need to | ||
| 383 | be special-cased for garbage collection. */ | ||
| 384 | |||
| 385 | struct module_global_reference { | ||
| 386 | /* Pseudovector header, must come first. */ | ||
| 387 | union vectorlike_header header; | ||
| 388 | |||
| 389 | /* Holds the emacs_value for the object. The Lisp_Object stored | ||
| 390 | therein must be the same as the hash key. */ | ||
| 391 | struct emacs_value_tag value; | ||
| 392 | |||
| 393 | /* Reference count, always positive. */ | ||
| 394 | ptrdiff_t refcount; | ||
| 395 | }; | ||
| 396 | |||
| 397 | static struct module_global_reference * | ||
| 398 | XMODULE_GLOBAL_REFERENCE (Lisp_Object o) | ||
| 399 | { | ||
| 400 | eassert (PSEUDOVECTORP (o, PVEC_OTHER)); | ||
| 401 | return XUNTAG (o, Lisp_Vectorlike, struct module_global_reference); | ||
| 402 | } | ||
| 403 | |||
| 404 | /* Returns whether V is a global reference. Only used to check module | ||
| 405 | assertions. If V is not a global reference, increment *N by the | ||
| 406 | number of global references (for debugging output). */ | ||
| 407 | |||
| 408 | static bool | ||
| 409 | module_global_reference_p (emacs_value v, ptrdiff_t *n) | ||
| 410 | { | ||
| 411 | struct Lisp_Hash_Table *h = XHASH_TABLE (Vmodule_refs_hash); | ||
| 412 | /* Note that we can't use `hash_lookup' because V might be a local | ||
| 413 | reference that's identical to some global reference. */ | ||
| 414 | for (ptrdiff_t i = 0; i < HASH_TABLE_SIZE (h); ++i) | ||
| 415 | { | ||
| 416 | if (!EQ (HASH_KEY (h, i), Qunbound) | ||
| 417 | && &XMODULE_GLOBAL_REFERENCE (HASH_VALUE (h, i))->value == v) | ||
| 418 | return true; | ||
| 419 | } | ||
| 420 | /* Only used for debugging, so we don't care about overflow, just | ||
| 421 | make sure the operation is defined. */ | ||
| 422 | INT_ADD_WRAPV (*n, h->count, n); | ||
| 423 | return false; | ||
| 424 | } | ||
| 425 | |||
| 378 | static emacs_value | 426 | static emacs_value |
| 379 | module_make_global_ref (emacs_env *env, emacs_value value) | 427 | module_make_global_ref (emacs_env *env, emacs_value value) |
| 380 | { | 428 | { |
| @@ -383,21 +431,30 @@ module_make_global_ref (emacs_env *env, emacs_value value) | |||
| 383 | Lisp_Object new_obj = value_to_lisp (value), hashcode; | 431 | Lisp_Object new_obj = value_to_lisp (value), hashcode; |
| 384 | ptrdiff_t i = hash_lookup (h, new_obj, &hashcode); | 432 | ptrdiff_t i = hash_lookup (h, new_obj, &hashcode); |
| 385 | 433 | ||
| 434 | /* Note: This approach requires the garbage collector to never move | ||
| 435 | objects. */ | ||
| 436 | |||
| 386 | if (i >= 0) | 437 | if (i >= 0) |
| 387 | { | 438 | { |
| 388 | Lisp_Object value = HASH_VALUE (h, i); | 439 | Lisp_Object value = HASH_VALUE (h, i); |
| 389 | EMACS_INT refcount = XFIXNAT (value) + 1; | 440 | struct module_global_reference *ref = XMODULE_GLOBAL_REFERENCE (value); |
| 390 | if (MOST_POSITIVE_FIXNUM < refcount) | 441 | bool overflow = INT_ADD_WRAPV (ref->refcount, 1, &ref->refcount); |
| 442 | if (overflow) | ||
| 391 | overflow_error (); | 443 | overflow_error (); |
| 392 | value = make_fixed_natnum (refcount); | 444 | return &ref->value; |
| 393 | set_hash_value_slot (h, i, value); | ||
| 394 | } | 445 | } |
| 395 | else | 446 | else |
| 396 | { | 447 | { |
| 397 | hash_put (h, new_obj, make_fixed_natnum (1), hashcode); | 448 | struct module_global_reference *ref |
| 449 | = ALLOCATE_PLAIN_PSEUDOVECTOR (struct module_global_reference, | ||
| 450 | PVEC_OTHER); | ||
| 451 | ref->value.v = new_obj; | ||
| 452 | ref->refcount = 1; | ||
| 453 | Lisp_Object value; | ||
| 454 | XSETPSEUDOVECTOR (value, ref, PVEC_OTHER); | ||
| 455 | hash_put (h, new_obj, value, hashcode); | ||
| 456 | return &ref->value; | ||
| 398 | } | 457 | } |
| 399 | |||
| 400 | return allocate_emacs_value (env, &global_storage, new_obj); | ||
| 401 | } | 458 | } |
| 402 | 459 | ||
| 403 | static void | 460 | static void |
| @@ -411,25 +468,21 @@ module_free_global_ref (emacs_env *env, emacs_value global_value) | |||
| 411 | Lisp_Object obj = value_to_lisp (global_value); | 468 | Lisp_Object obj = value_to_lisp (global_value); |
| 412 | ptrdiff_t i = hash_lookup (h, obj, NULL); | 469 | ptrdiff_t i = hash_lookup (h, obj, NULL); |
| 413 | 470 | ||
| 414 | if (i >= 0) | 471 | if (module_assertions) |
| 415 | { | 472 | { |
| 416 | EMACS_INT refcount = XFIXNAT (HASH_VALUE (h, i)) - 1; | 473 | ptrdiff_t n = 0; |
| 417 | if (refcount > 0) | 474 | if (! module_global_reference_p (global_value, &n)) |
| 418 | set_hash_value_slot (h, i, make_fixed_natnum (refcount)); | 475 | module_abort ("Global value was not found in list of %"pD"d globals", |
| 419 | else | 476 | n); |
| 420 | { | ||
| 421 | eassert (refcount == 0); | ||
| 422 | hash_remove_from_table (h, obj); | ||
| 423 | } | ||
| 424 | } | 477 | } |
| 425 | 478 | ||
| 426 | if (module_assertions) | 479 | if (i >= 0) |
| 427 | { | 480 | { |
| 428 | ptrdiff_t count = 0; | 481 | Lisp_Object value = HASH_VALUE (h, i); |
| 429 | if (value_storage_contains_p (&global_storage, global_value, &count)) | 482 | struct module_global_reference *ref = XMODULE_GLOBAL_REFERENCE (value); |
| 430 | return; | 483 | eassert (0 < ref->refcount); |
| 431 | module_abort ("Global value was not found in list of %"pD"d globals", | 484 | if (--ref->refcount == 0) |
| 432 | count); | 485 | hash_remove_from_table (h, obj); |
| 433 | } | 486 | } |
| 434 | } | 487 | } |
| 435 | 488 | ||
| @@ -1250,7 +1303,7 @@ value_to_lisp (emacs_value v) | |||
| 1250 | ++num_environments; | 1303 | ++num_environments; |
| 1251 | } | 1304 | } |
| 1252 | /* Also check global values. */ | 1305 | /* Also check global values. */ |
| 1253 | if (value_storage_contains_p (&global_storage, v, &num_values)) | 1306 | if (module_global_reference_p (v, &num_values)) |
| 1254 | goto ok; | 1307 | goto ok; |
| 1255 | module_abort (("Emacs value not found in %"pD"d values " | 1308 | module_abort (("Emacs value not found in %"pD"d values " |
| 1256 | "of %"pD"d environments"), | 1309 | "of %"pD"d environments"), |
| @@ -1467,10 +1520,7 @@ module_handle_nonlocal_exit (emacs_env *env, enum nonlocal_exit type, | |||
| 1467 | void | 1520 | void |
| 1468 | init_module_assertions (bool enable) | 1521 | init_module_assertions (bool enable) |
| 1469 | { | 1522 | { |
| 1470 | /* If enabling module assertions, use a hidden environment for | ||
| 1471 | storing the globals. This environment is never freed. */ | ||
| 1472 | module_assertions = enable; | 1523 | module_assertions = enable; |
| 1473 | initialize_storage (&global_storage); | ||
| 1474 | } | 1524 | } |
| 1475 | 1525 | ||
| 1476 | /* Return whether STORAGE contains VALUE. Used to check module | 1526 | /* Return whether STORAGE contains VALUE. Used to check module |
diff --git a/src/emacs.c b/src/emacs.c index 228ac293370..34717cdae2f 100644 --- a/src/emacs.c +++ b/src/emacs.c | |||
| @@ -2356,6 +2356,8 @@ DEFUN ("kill-emacs", Fkill_emacs, Skill_emacs, 0, 1, "P", | |||
| 2356 | doc: /* Exit the Emacs job and kill it. | 2356 | doc: /* Exit the Emacs job and kill it. |
| 2357 | If ARG is an integer, return ARG as the exit program code. | 2357 | If ARG is an integer, return ARG as the exit program code. |
| 2358 | If ARG is a string, stuff it as keyboard input. | 2358 | If ARG is a string, stuff it as keyboard input. |
| 2359 | Any other value of ARG, or ARG omitted, means return an | ||
| 2360 | exit code that indicates successful program termination. | ||
| 2359 | 2361 | ||
| 2360 | This function is called upon receipt of the signals SIGTERM | 2362 | This function is called upon receipt of the signals SIGTERM |
| 2361 | or SIGHUP, and upon SIGINT in batch mode. | 2363 | or SIGHUP, and upon SIGINT in batch mode. |
diff --git a/src/w32proc.c b/src/w32proc.c index 16e32e4c58d..c50f246a454 100644 --- a/src/w32proc.c +++ b/src/w32proc.c | |||
| @@ -2790,11 +2790,11 @@ sys_kill (pid_t pid, int sig) | |||
| 2790 | /* Set the foreground window to the child. */ | 2790 | /* Set the foreground window to the child. */ |
| 2791 | if (SetForegroundWindow (cp->hwnd)) | 2791 | if (SetForegroundWindow (cp->hwnd)) |
| 2792 | { | 2792 | { |
| 2793 | /* Record the state of the Ctrl key: the user could | 2793 | /* Record the state of the left Ctrl key: the user |
| 2794 | have it depressed while we are simulating Ctrl-C, | 2794 | could have it depressed while we are simulating |
| 2795 | in which case we will have to leave the state of | 2795 | Ctrl-C, in which case we will have to leave the |
| 2796 | Ctrl depressed when we are done. */ | 2796 | state of that Ctrl depressed when we are done. */ |
| 2797 | short ctrl_state = GetKeyState (VK_CONTROL) & 0x8000; | 2797 | short ctrl_state = GetKeyState (VK_LCONTROL) & 0x8000; |
| 2798 | 2798 | ||
| 2799 | /* Generate keystrokes as if user had typed Ctrl-Break or | 2799 | /* Generate keystrokes as if user had typed Ctrl-Break or |
| 2800 | Ctrl-C. */ | 2800 | Ctrl-C. */ |