aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorNicolás Bértolo2020-05-19 15:57:31 -0300
committerAndrea Corallo2020-05-25 09:42:10 +0100
commit1b809f378f6263bc099da45c5e4a42c89fef8d71 (patch)
tree1adfe55b6b0761de4f12bc0830aaab7a3296bc07 /src
parent9daffe9cfe82d3b1e1e9fa8929dbb40cfed60f0f (diff)
downloademacs-1b809f378f6263bc099da45c5e4a42c89fef8d71.tar.gz
emacs-1b809f378f6263bc099da45c5e4a42c89fef8d71.zip
Improve handling of native compilation units still in use in Windows
When closing emacs will inspect all directories from which it loaded native compilation units. If it finds a ".eln.old" file it will try to delete it, if it fails that means that another Emacs instance is using it. When compiling a file we rename the file that was in the output path in case it has been loaded into another Emacs instance. When deleting a package we move any ".eln" or ".eln.old" files in the package folder that we can't delete to `package-user-dir`. Emacs will check that directory when closing and delete them. * lisp/emacs-lisp/comp.el (comp--replace-output-file): Function called from C code to finish the compilation process. It performs renaming of the old file if necessary. * lisp/emacs-lisp/package.el (package--delete-directory): Function to delete a package directory. It moves native compilation units that it can't delete to `package-user-dir'. * src/alloc.c (cleanup_vector): Call dispose_comp_unit(). (garbage_collect): Call finish_delayed_disposal_of_comp_units(). * src/comp.c: Restore the signal mask using unwind-protect. Store loaded native compilation units in a hash table for disposal on close. Store filenames of native compilation units GC'd in a linked list to finish their disposal when the GC is over. (clean_comp_unit_directory): Delete all *.eln.old files in a directory. (clean_package_user_dir_of_old_comp_units): Delete all *.eln.old files in `package-user-dir'. (dispose_all_remaining_comp_units): Dispose of native compilation units that are still loaded. (dispose_comp_unit): Close handle and cleanup directory or arrange for later cleanup if DELAY is true. (finish_delayed_disposal_of_comp_units): Dispose of native compilation units that were GC'd. (register_native_comp_unit): Register native compilation unit for disposal when Emacs closes. * src/comp.h: Introduce cfile member in Lisp_Native_Comp_Unit. Add declarations of functions that: clean directories of unused native compilation units, handle disposal of native compilation units. * src/emacs.c (kill-emacs): Dispose all remaining compilation units right right before calling exit(). * src/eval.c (internal_condition_case_3, internal_condition_case_4): Add functions. * src/lisp.h (internal_condition_case_3, internal_condition_case_4): Add functions. * src/pdumper.c (dump_do_dump_relocation): Set cfile to a copy of the Lisp string specifying the file path.
Diffstat (limited to 'src')
-rw-r--r--src/alloc.c3
-rw-r--r--src/comp.c260
-rw-r--r--src/comp.h34
-rw-r--r--src/emacs.c4
-rw-r--r--src/eval.c55
-rw-r--r--src/lisp.h2
-rw-r--r--src/pdumper.c3
7 files changed, 349 insertions, 12 deletions
diff --git a/src/alloc.c b/src/alloc.c
index 76d49d2efd6..b892022125e 100644
--- a/src/alloc.c
+++ b/src/alloc.c
@@ -3119,8 +3119,7 @@ cleanup_vector (struct Lisp_Vector *vector)
3119 { 3119 {
3120 struct Lisp_Native_Comp_Unit *cu = 3120 struct Lisp_Native_Comp_Unit *cu =
3121 PSEUDOVEC_STRUCT (vector, Lisp_Native_Comp_Unit); 3121 PSEUDOVEC_STRUCT (vector, Lisp_Native_Comp_Unit);
3122 eassert (cu->handle); 3122 dispose_comp_unit (cu, true);
3123 dynlib_close (cu->handle);
3124 } 3123 }
3125} 3124}
3126 3125
diff --git a/src/comp.c b/src/comp.c
index 68ad6d3eb8d..16ad77c74bc 100644
--- a/src/comp.c
+++ b/src/comp.c
@@ -411,6 +411,10 @@ load_gccjit_if_necessary (bool mandatory)
411#define CALL1I(fun, arg) \ 411#define CALL1I(fun, arg) \
412 CALLN (Ffuncall, intern_c_string (STR (fun)), arg) 412 CALLN (Ffuncall, intern_c_string (STR (fun)), arg)
413 413
414/* Like call2 but stringify and intern. */
415#define CALL2I(fun, arg1, arg2) \
416 CALLN (Ffuncall, intern_c_string (STR (fun)), arg1, arg2)
417
414#define DECL_BLOCK(name, func) \ 418#define DECL_BLOCK(name, func) \
415 gcc_jit_block *(name) = \ 419 gcc_jit_block *(name) = \
416 gcc_jit_function_new_block ((func), STR (name)) 420 gcc_jit_function_new_block ((func), STR (name))
@@ -435,6 +439,8 @@ typedef struct {
435 ptrdiff_t size; 439 ptrdiff_t size;
436} f_reloc_t; 440} f_reloc_t;
437 441
442sigset_t saved_sigset;
443
438static f_reloc_t freloc; 444static f_reloc_t freloc;
439 445
440/* C side of the compiler context. */ 446/* C side of the compiler context. */
@@ -3795,6 +3801,13 @@ DEFUN ("comp--release-ctxt", Fcomp__release_ctxt, Scomp__release_ctxt,
3795 return Qt; 3801 return Qt;
3796} 3802}
3797 3803
3804static void
3805restore_sigmask (void)
3806{
3807 pthread_sigmask (SIG_SETMASK, &saved_sigset, 0);
3808 unblock_input ();
3809}
3810
3798DEFUN ("comp--compile-ctxt-to-file", Fcomp__compile_ctxt_to_file, 3811DEFUN ("comp--compile-ctxt-to-file", Fcomp__compile_ctxt_to_file,
3799 Scomp__compile_ctxt_to_file, 3812 Scomp__compile_ctxt_to_file,
3800 1, 1, 0, 3813 1, 1, 0,
@@ -3816,6 +3829,8 @@ DEFUN ("comp--compile-ctxt-to-file", Fcomp__compile_ctxt_to_file,
3816 CALL1I (comp-data-container-idx, CALL1I (comp-ctxt-d-ephemeral, Vcomp_ctxt)); 3829 CALL1I (comp-data-container-idx, CALL1I (comp-ctxt-d-ephemeral, Vcomp_ctxt));
3817 3830
3818 sigset_t oldset; 3831 sigset_t oldset;
3832 ptrdiff_t count = 0;
3833
3819 if (!noninteractive) 3834 if (!noninteractive)
3820 { 3835 {
3821 sigset_t blocked; 3836 sigset_t blocked;
@@ -3828,6 +3843,8 @@ DEFUN ("comp--compile-ctxt-to-file", Fcomp__compile_ctxt_to_file,
3828 sigaddset (&blocked, SIGIO); 3843 sigaddset (&blocked, SIGIO);
3829#endif 3844#endif
3830 pthread_sigmask (SIG_BLOCK, &blocked, &oldset); 3845 pthread_sigmask (SIG_BLOCK, &blocked, &oldset);
3846 count = SPECPDL_INDEX ();
3847 record_unwind_protect_void (restore_sigmask);
3831 } 3848 }
3832 emit_ctxt_code (); 3849 emit_ctxt_code ();
3833 3850
@@ -3866,18 +3883,10 @@ DEFUN ("comp--compile-ctxt-to-file", Fcomp__compile_ctxt_to_file,
3866 GCC_JIT_OUTPUT_KIND_DYNAMIC_LIBRARY, 3883 GCC_JIT_OUTPUT_KIND_DYNAMIC_LIBRARY,
3867 SSDATA (tmp_file)); 3884 SSDATA (tmp_file));
3868 3885
3869 /* Remove the old eln instead of copying the new one into it to get 3886 CALL2I(comp--replace-output-file, out_file, tmp_file);
3870 a new inode and prevent crashes in case the old one is currently
3871 loaded. */
3872 if (!NILP (Ffile_exists_p (out_file)))
3873 Fdelete_file (out_file, Qnil);
3874 Frename_file (tmp_file, out_file, Qnil);
3875 3887
3876 if (!noninteractive) 3888 if (!noninteractive)
3877 { 3889 unbind_to (count, Qnil);
3878 pthread_sigmask (SIG_SETMASK, &oldset, 0);
3879 unblock_input ();
3880 }
3881 3890
3882 return out_file; 3891 return out_file;
3883} 3892}
@@ -3939,6 +3948,223 @@ helper_PSEUDOVECTOR_TYPEP_XUNTAG (Lisp_Object a, enum pvec_type code)
3939} 3948}
3940 3949
3941 3950
3951/*********************************/
3952/* Disposal of compilation units */
3953/*********************************/
3954
3955/*
3956The problem: Windows does not let us delete an .eln file that has been
3957loaded by a process. This has two implications in Emacs:
3958
39591) It is not possible to recompile a lisp file if the corresponding
3960.eln file has been loaded. This is because we'd like to use the same
3961filename, but we can't delete the old .eln file.
3962
39632) It is not possible to delete a package using `package-delete'
3964if an .eln file has been loaded.
3965
3966* General idea
3967
3968The solution to these two problems is to move the foo.eln file
3969somewhere else and have the last Emacs instance using it delete it.
3970To make it easy to find what files need to be removed we use two approaches.
3971
3972In the 1) case we rename foo.eln to fooXXXXXX.eln.old in the same
3973folder. When Emacs is unloading "foo" (either GC'd the native
3974compilation unit or Emacs is closing (see below)) we delete all the
3975.eln.old files in the folder where the original foo.eln was stored.
3976
3977Ideally we'd figure out the new name of foo.eln and delete it if
3978it ends in .eln.old. There is no simple API to do this in
3979Windows. GetModuleFileName() returns the original filename, not the
3980current one. This forces us to put .eln.old files in an agreed upon
3981path. We cannot use %TEMP% because it may be in another drive and then
3982the rename operation would fail.
3983
3984In the 2) case we can't use the same folder where the .eln file
3985resided, as we are trying to completely remove the package. Since we
3986are removing packages we can safely move the .eln.old file to
3987`package-user-dir' as we are sure that that would not mean changing
3988drives.
3989
3990* Implementation details
3991
3992The concept of disposal of a native compilation unit refers to
3993unloading the shared library and deleting all the .eln.old files in
3994the directory. These are two separate steps. We'll call them
3995early-disposal and late-disposal.
3996
3997There are two data structures used:
3998
3999- The `all_loaded_comp_units_h` hashtable.
4000
4001This hashtable is used like an array of weak references to native
4002compilation units. This hash table is filled by load_comp_unit() and
4003dispose_all_remaining_comp_units() iterates over all values that were
4004not disposed by the GC and performs all disposal steps when Emacs is
4005closing.
4006
4007- The `delayed_comp_unit_disposal_list` list.
4008
4009This is were the dispose_comp_unit() function, when called by the GC
4010sweep stage, stores the original filenames of the disposed native
4011compilation units. This is an ad-hoc C structure instead of a Lisp
4012cons because we need to allocate instances of this structure during
4013the GC.
4014
4015The finish_delayed_disposal_of_comp_units() function will iterate over
4016this list and perform the late-disposal step when Emacs is closing.
4017
4018*/
4019
4020#ifdef WINDOWSNT
4021#define OLD_ELN_SUFFIX_REGEXP build_string ("\\.eln\\.old\\'")
4022
4023static Lisp_Object all_loaded_comp_units_h;
4024
4025/* We need to allocate instances of this struct during a GC
4026 * sweep. This is why it can't be transformed into a simple cons.
4027 */
4028struct delayed_comp_unit_disposal
4029{
4030 struct delayed_comp_unit_disposal *next;
4031 char *filename;
4032};
4033
4034struct delayed_comp_unit_disposal *delayed_comp_unit_disposal_list;
4035
4036static Lisp_Object
4037return_nil (Lisp_Object arg)
4038{
4039 return Qnil;
4040}
4041
4042/* Tries to remove all *.eln.old files in DIRNAME.
4043
4044 * Any error is ignored because it may be due to the file being loaded
4045 * in another Emacs instance.
4046 */
4047static void
4048clean_comp_unit_directory (Lisp_Object dirpath)
4049{
4050 if (NILP (dirpath))
4051 return;
4052 Lisp_Object files_in_dir;
4053 files_in_dir = internal_condition_case_4 (Fdirectory_files, dirpath, Qt,
4054 OLD_ELN_SUFFIX_REGEXP, Qnil, Qt,
4055 return_nil);
4056 FOR_EACH_TAIL (files_in_dir) { DeleteFile (SSDATA (XCAR (files_in_dir))); }
4057}
4058
4059/* Tries to remove all *.eln.old files in `package-user-dir'.
4060
4061 * This is called when Emacs is closing to clean any *.eln left from a
4062 * deleted package.
4063 */
4064void
4065clean_package_user_dir_of_old_comp_units (void)
4066{
4067 Lisp_Object package_user_dir
4068 = find_symbol_value (intern ("package-user-dir"));
4069 if (EQ (package_user_dir, Qunbound) || !STRINGP (package_user_dir))
4070 return;
4071
4072 clean_comp_unit_directory (package_user_dir);
4073}
4074
4075/* This function disposes all compilation units that are still loaded.
4076 * It is important that this function is called only right before
4077 * Emacs is closed, otherwise we risk running a subr that is
4078 * implemented in an unloaded dynamic library.
4079 */
4080void
4081dispose_all_remaining_comp_units (void)
4082{
4083 struct Lisp_Hash_Table *h = XHASH_TABLE (all_loaded_comp_units_h);
4084
4085 for (ptrdiff_t i = 0; i < HASH_TABLE_SIZE (h); ++i)
4086 {
4087 Lisp_Object k = HASH_KEY (h, i);
4088 if (!EQ (k, Qunbound))
4089 {
4090 Lisp_Object val = HASH_VALUE (h, i);
4091 struct Lisp_Native_Comp_Unit *cu = XNATIVE_COMP_UNIT (val);
4092 dispose_comp_unit (cu, false);
4093 }
4094 }
4095}
4096
4097/* This function finishes the disposal of compilation units that were
4098 * passed to `dispose_comp_unit` with DELAY == true.
4099 *
4100 * This function is called when Emacs is idle and when it is about to
4101 * close.
4102 */
4103void
4104finish_delayed_disposal_of_comp_units (void)
4105{
4106 for (struct delayed_comp_unit_disposal *item
4107 = delayed_comp_unit_disposal_list;
4108 delayed_comp_unit_disposal_list; item = delayed_comp_unit_disposal_list)
4109 {
4110 delayed_comp_unit_disposal_list = item->next;
4111 Lisp_Object dirname = internal_condition_case_1 (
4112 Ffile_name_directory, build_string (item->filename), Qt, return_nil);
4113 clean_comp_unit_directory (dirname);
4114 xfree (item->filename);
4115 xfree (item);
4116 }
4117}
4118#endif
4119
4120/* This function puts the compilation unit in the
4121 * `all_loaded_comp_units_h` hashmap.
4122 */
4123static void
4124register_native_comp_unit (Lisp_Object comp_u)
4125{
4126#ifdef WINDOWSNT
4127 Fputhash (CALL1I (gensym, Qnil), comp_u, all_loaded_comp_units_h);
4128#endif
4129}
4130
4131/* This function disposes compilation units. It is called during the GC sweep
4132 * stage and when Emacs is closing.
4133
4134 * On Windows the the DELAY parameter specifies whether the native
4135 * compilation file will be deleted right away (if necessary) or put
4136 * on a list. That list will be dealt with by
4137 * `finish_delayed_disposal_of_comp_units`.
4138 */
4139void
4140dispose_comp_unit (struct Lisp_Native_Comp_Unit *comp_handle, bool delay)
4141{
4142 eassert (comp_handle->handle);
4143 dynlib_close (comp_handle->handle);
4144#ifdef WINDOWSNT
4145 if (!delay)
4146 {
4147 Lisp_Object dirname = internal_condition_case_1 (
4148 Ffile_name_directory, build_string (comp_handle->cfile), Qt,
4149 return_nil);
4150 if (!NILP (dirname))
4151 clean_comp_unit_directory (dirname);
4152 xfree (comp_handle->cfile);
4153 comp_handle->cfile = NULL;
4154 }
4155 else
4156 {
4157 struct delayed_comp_unit_disposal *head;
4158 head = xmalloc (sizeof (struct delayed_comp_unit_disposal));
4159 head->next = delayed_comp_unit_disposal_list;
4160 head->filename = comp_handle->cfile;
4161 comp_handle->cfile = NULL;
4162 delayed_comp_unit_disposal_list = head;
4163 }
4164#endif
4165}
4166
4167
3942/***********************************/ 4168/***********************************/
3943/* Deferred compilation mechanism. */ 4169/* Deferred compilation mechanism. */
3944/***********************************/ 4170/***********************************/
@@ -4159,6 +4385,12 @@ load_comp_unit (struct Lisp_Native_Comp_Unit *comp_u, bool loading_dump,
4159 d_vec_len = XFIXNUM (Flength (comp_u->data_impure_vec)); 4385 d_vec_len = XFIXNUM (Flength (comp_u->data_impure_vec));
4160 for (EMACS_INT i = 0; i < d_vec_len; i++) 4386 for (EMACS_INT i = 0; i < d_vec_len; i++)
4161 data_imp_relocs[i] = AREF (comp_u->data_impure_vec, i); 4387 data_imp_relocs[i] = AREF (comp_u->data_impure_vec, i);
4388
4389 /* If we register them while dumping we will get some entries in
4390 the hash table that will be duplicated when pdumper calls
4391 load_comp_unit. */
4392 if (!will_dump_p ())
4393 register_native_comp_unit (comp_u_lisp_obj);
4162 } 4394 }
4163 4395
4164 if (!loading_dump) 4396 if (!loading_dump)
@@ -4316,6 +4548,9 @@ DEFUN ("native-elisp-load", Fnative_elisp_load, Snative_elisp_load, 1, 2, 0,
4316 if (!comp_u->handle) 4548 if (!comp_u->handle)
4317 xsignal2 (Qnative_lisp_load_failed, file, build_string (dynlib_error ())); 4549 xsignal2 (Qnative_lisp_load_failed, file, build_string (dynlib_error ()));
4318 comp_u->file = file; 4550 comp_u->file = file;
4551#ifdef WINDOWSNT
4552 comp_u->cfile = xlispstrdup (file);
4553#endif
4319 comp_u->data_vec = Qnil; 4554 comp_u->data_vec = Qnil;
4320 comp_u->lambda_gc_guard = CALLN (Fmake_hash_table, QCtest, Qeq); 4555 comp_u->lambda_gc_guard = CALLN (Fmake_hash_table, QCtest, Qeq);
4321 comp_u->lambda_c_name_idx_h = CALLN (Fmake_hash_table, QCtest, Qequal); 4556 comp_u->lambda_c_name_idx_h = CALLN (Fmake_hash_table, QCtest, Qequal);
@@ -4464,6 +4699,11 @@ syms_of_comp (void)
4464 staticpro (&delayed_sources); 4699 staticpro (&delayed_sources);
4465 delayed_sources = Qnil; 4700 delayed_sources = Qnil;
4466 4701
4702#ifdef WINDOWSNT
4703 staticpro (&all_loaded_comp_units_h);
4704 all_loaded_comp_units_h = CALLN(Fmake_hash_table, QCweakness, Qvalue);
4705#endif
4706
4467 DEFVAR_LISP ("comp-ctxt", Vcomp_ctxt, 4707 DEFVAR_LISP ("comp-ctxt", Vcomp_ctxt,
4468 doc: /* The compiler context. */); 4708 doc: /* The compiler context. */);
4469 Vcomp_ctxt = Qnil; 4709 Vcomp_ctxt = Qnil;
diff --git a/src/comp.h b/src/comp.h
index 36e7cdf4413..b8e40ceb900 100644
--- a/src/comp.h
+++ b/src/comp.h
@@ -52,7 +52,15 @@ struct Lisp_Native_Comp_Unit
52 /* STUFFS WE DO NOT DUMP!! */ 52 /* STUFFS WE DO NOT DUMP!! */
53 Lisp_Object *data_imp_relocs; 53 Lisp_Object *data_imp_relocs;
54 bool loaded_once; 54 bool loaded_once;
55
55 dynlib_handle_ptr handle; 56 dynlib_handle_ptr handle;
57#ifdef WINDOWSNT
58 /* We need to store a copy of the original file name in memory that
59 is not subject to GC because the function to dispose native
60 compilation units is called by the GC. By that time the `file'
61 string may have been sweeped. */
62 char * cfile;
63#endif
56}; 64};
57 65
58#ifdef HAVE_NATIVE_COMP 66#ifdef HAVE_NATIVE_COMP
@@ -83,6 +91,14 @@ extern void syms_of_comp (void);
83 91
84extern void maybe_defer_native_compilation (Lisp_Object function_name, 92extern void maybe_defer_native_compilation (Lisp_Object function_name,
85 Lisp_Object definition); 93 Lisp_Object definition);
94
95extern void dispose_comp_unit (struct Lisp_Native_Comp_Unit * comp_unit, bool delay);
96
97extern void finish_delayed_disposal_of_comp_units (void);
98
99extern void dispose_all_remaining_comp_units (void);
100
101extern void clean_package_user_dir_of_old_comp_units (void);
86#else 102#else
87 103
88static inline void 104static inline void
@@ -92,6 +108,24 @@ maybe_defer_native_compilation (Lisp_Object function_name,
92 108
93extern void syms_of_comp (void); 109extern void syms_of_comp (void);
94 110
111static inline void
112dispose_comp_unit (struct Lisp_Native_Comp_Unit * comp_handle)
113{
114 eassert (false);
115}
116
117static inline void
118dispose_all_remaining_comp_units (void)
119{}
120
121static inline void
122clean_package_user_dir_of_old_comp_units (void)
123{}
124
125static inline void
126finish_delayed_disposal_of_comp_units (void)
127{}
128
95#endif 129#endif
96 130
97#endif 131#endif
diff --git a/src/emacs.c b/src/emacs.c
index 93a837a44ef..2a7a5257f15 100644
--- a/src/emacs.c
+++ b/src/emacs.c
@@ -2398,6 +2398,10 @@ all of which are called before Emacs is actually killed. */
2398 unlink (SSDATA (listfile)); 2398 unlink (SSDATA (listfile));
2399 } 2399 }
2400 2400
2401 finish_delayed_disposal_of_comp_units ();
2402 dispose_all_remaining_comp_units ();
2403 clean_package_user_dir_of_old_comp_units ();
2404
2401 if (FIXNUMP (arg)) 2405 if (FIXNUMP (arg))
2402 exit_code = (XFIXNUM (arg) < 0 2406 exit_code = (XFIXNUM (arg) < 0
2403 ? XFIXNUM (arg) | INT_MIN 2407 ? XFIXNUM (arg) | INT_MIN
diff --git a/src/eval.c b/src/eval.c
index 37d466f69ed..9e86a185908 100644
--- a/src/eval.c
+++ b/src/eval.c
@@ -1419,6 +1419,61 @@ internal_condition_case_2 (Lisp_Object (*bfun) (Lisp_Object, Lisp_Object),
1419 } 1419 }
1420} 1420}
1421 1421
1422/* Like internal_condition_case_1 but call BFUN with ARG1, ARG2, ARG3 as
1423 its arguments. */
1424
1425Lisp_Object
1426internal_condition_case_3 (Lisp_Object (*bfun) (Lisp_Object, Lisp_Object,
1427 Lisp_Object),
1428 Lisp_Object arg1, Lisp_Object arg2, Lisp_Object arg3,
1429 Lisp_Object handlers,
1430 Lisp_Object (*hfun) (Lisp_Object))
1431{
1432 struct handler *c = push_handler (handlers, CONDITION_CASE);
1433 if (sys_setjmp (c->jmp))
1434 {
1435 Lisp_Object val = handlerlist->val;
1436 clobbered_eassert (handlerlist == c);
1437 handlerlist = handlerlist->next;
1438 return hfun (val);
1439 }
1440 else
1441 {
1442 Lisp_Object val = bfun (arg1, arg2, arg3);
1443 eassert (handlerlist == c);
1444 handlerlist = c->next;
1445 return val;
1446 }
1447}
1448
1449/* Like internal_condition_case_1 but call BFUN with ARG1, ARG2, ARG3, ARG4 as
1450 its arguments. */
1451
1452Lisp_Object
1453internal_condition_case_4 (Lisp_Object (*bfun) (Lisp_Object, Lisp_Object,
1454 Lisp_Object, Lisp_Object),
1455 Lisp_Object arg1, Lisp_Object arg2,
1456 Lisp_Object arg3, Lisp_Object arg4,
1457 Lisp_Object handlers,
1458 Lisp_Object (*hfun) (Lisp_Object))
1459{
1460 struct handler *c = push_handler (handlers, CONDITION_CASE);
1461 if (sys_setjmp (c->jmp))
1462 {
1463 Lisp_Object val = handlerlist->val;
1464 clobbered_eassert (handlerlist == c);
1465 handlerlist = handlerlist->next;
1466 return hfun (val);
1467 }
1468 else
1469 {
1470 Lisp_Object val = bfun (arg1, arg2, arg3, arg4);
1471 eassert (handlerlist == c);
1472 handlerlist = c->next;
1473 return val;
1474 }
1475}
1476
1422/* Like internal_condition_case but call BFUN with NARGS as first, 1477/* Like internal_condition_case but call BFUN with NARGS as first,
1423 and ARGS as second argument. */ 1478 and ARGS as second argument. */
1424 1479
diff --git a/src/lisp.h b/src/lisp.h
index 4c0057b2552..52242791aa5 100644
--- a/src/lisp.h
+++ b/src/lisp.h
@@ -4165,6 +4165,8 @@ extern Lisp_Object internal_lisp_condition_case (Lisp_Object, Lisp_Object, Lisp_
4165extern Lisp_Object internal_condition_case (Lisp_Object (*) (void), Lisp_Object, Lisp_Object (*) (Lisp_Object)); 4165extern Lisp_Object internal_condition_case (Lisp_Object (*) (void), Lisp_Object, Lisp_Object (*) (Lisp_Object));
4166extern Lisp_Object internal_condition_case_1 (Lisp_Object (*) (Lisp_Object), Lisp_Object, Lisp_Object, Lisp_Object (*) (Lisp_Object)); 4166extern Lisp_Object internal_condition_case_1 (Lisp_Object (*) (Lisp_Object), Lisp_Object, Lisp_Object, Lisp_Object (*) (Lisp_Object));
4167extern Lisp_Object internal_condition_case_2 (Lisp_Object (*) (Lisp_Object, Lisp_Object), Lisp_Object, Lisp_Object, Lisp_Object, Lisp_Object (*) (Lisp_Object)); 4167extern Lisp_Object internal_condition_case_2 (Lisp_Object (*) (Lisp_Object, Lisp_Object), Lisp_Object, Lisp_Object, Lisp_Object, Lisp_Object (*) (Lisp_Object));
4168extern Lisp_Object internal_condition_case_3 (Lisp_Object (*) (Lisp_Object, Lisp_Object, Lisp_Object), Lisp_Object, Lisp_Object, Lisp_Object, Lisp_Object, Lisp_Object (*) (Lisp_Object));
4169extern Lisp_Object internal_condition_case_4 (Lisp_Object (*) (Lisp_Object, Lisp_Object, Lisp_Object, Lisp_Object), Lisp_Object, Lisp_Object, Lisp_Object, Lisp_Object, Lisp_Object, Lisp_Object (*) (Lisp_Object));
4168extern Lisp_Object internal_condition_case_n 4170extern Lisp_Object internal_condition_case_n
4169 (Lisp_Object (*) (ptrdiff_t, Lisp_Object *), ptrdiff_t, Lisp_Object *, 4171 (Lisp_Object (*) (ptrdiff_t, Lisp_Object *), ptrdiff_t, Lisp_Object *,
4170 Lisp_Object, Lisp_Object (*) (Lisp_Object, ptrdiff_t, Lisp_Object *)); 4172 Lisp_Object, Lisp_Object (*) (Lisp_Object, ptrdiff_t, Lisp_Object *));
diff --git a/src/pdumper.c b/src/pdumper.c
index a6d12b6ea0c..26480388d59 100644
--- a/src/pdumper.c
+++ b/src/pdumper.c
@@ -5312,6 +5312,9 @@ dump_do_dump_relocation (const uintptr_t dump_base,
5312 concat2 (Vinvocation_directory, 5312 concat2 (Vinvocation_directory,
5313 installation_state == LOCAL_BUILD 5313 installation_state == LOCAL_BUILD
5314 ? XCDR (comp_u->file) : XCAR (comp_u->file)); 5314 ? XCDR (comp_u->file) : XCAR (comp_u->file));
5315#ifdef WINDOWSNT
5316 comp_u->cfile = xlispstrdup(comp_u->file);
5317#endif
5315 comp_u->handle = dynlib_open (SSDATA (comp_u->file)); 5318 comp_u->handle = dynlib_open (SSDATA (comp_u->file));
5316 if (!comp_u->handle) 5319 if (!comp_u->handle)
5317 error ("%s", dynlib_error ()); 5320 error ("%s", dynlib_error ());