Rework eln deletion strategy for new eln-cache folder structure

When recompiling remove the corresponding stale elns found in the
`comp-eln-load-path'.

When removing a package remove the corresponding elns too.

On Windows both of these are performed only when possible, when it's
not the file is renamed as .eln.old and a last attempt to remove this
is performed closing the Emacs session.  When a file being deleted was
loaded by multiple Emacs sessions the last one being closed should
delete it.

	* lisp/emacs-lisp/comp.el (comp-clean-up-stale-eln): New function.
	(comp-delete-or-replace-file): Rename from
	`comp--replace-output-file' and update so it can be used for
	replacing or deleting shared libs safetly.

	* lisp/emacs-lisp/package.el (package--delete-directory): When
	native compiled just call `comp-clean-up-stale-eln' for each
	eln file we want to clean-up.

	* src/alloc.c (cleanup_vector): Call directly the dynlib_close.

	* src/comp.c (syms_of_comp): Update for comp_u->cfile removal.
	Make 'all_loaded_comp_units_h' key-value weak as now the key will
	be the filename.
	(load_comp_unit): Register the compilation unit only when the load
	is fully completed.
	(register_native_comp_unit): Make the key of
	all_loaded_comp_units_h the load filename.
	(eln_load_path_final_clean_up): New function.
	(dispose_comp_unit)
	(finish_delayed_disposal_of_comp_units)
	(dispose_all_remaining_comp_units)
	(clean_package_user_dir_of_old_comp_units): Remove.
	(Fcomp__compile_ctxt_to_file): Update for
	`comp--replace-output-file' -> `comp-delete-or-replace-file'
	rename.

	* src/comp.h (dispose_comp_unit)
	(finish_delayed_disposal_of_comp_units)
	(dispose_all_remaining_comp_units)
	(clean_package_user_dir_of_old_comp_units): Remove.
	(eln_load_path_final_clean_up): Add.
	(struct Lisp_Native_Comp_Unit): Remove cfile field.

	* src/emacs.c (Fkill_emacs): Call 'eln_load_path_final_clean_up'.

	* src/pdumper.c (dump_do_dump_relocation): Do not set comp_u->cfile.
This commit is contained in:
Andrea Corallo 2020-09-06 18:17:00 +02:00
parent eb87425988
commit a71f54eff8
7 changed files with 75 additions and 293 deletions

View file

@ -2505,31 +2505,52 @@ Prepare every function for final compilation and drive the C back-end."
;; Some entry point support code.
(defun comp--replace-output-file (outfile tmpfile)
"Replace OUTFILE with TMPFILE.
Takes the necessary steps when dealing with shared libraries that
may be loaded into Emacs"
;;;###autoload
(defun comp-clean-up-stale-eln (file)
"Given FILE remove all the .eln files in `comp-eln-load-path'
sharing the original source filename (including FILE)."
(string-match (rx "-" (group-n 1 (1+ hex)) "-" (1+ hex) ".eln" eos) file)
(cl-loop
with filename-hash = (match-string 1 file)
with regexp = (rx-to-string
`(seq "-" ,filename-hash "-" (1+ hex) ".eln" eos))
for dir in (butlast comp-eln-load-path) ; Skip last dir.
do (cl-loop
for f in (directory-files (concat dir comp-native-version-dir) t regexp
t)
do (comp-delete-or-replace-file f))))
(defun comp-delete-or-replace-file (oldfile &optional newfile)
"Replace OLDFILE with NEWFILE.
When NEWFILE is nil just delete OLDFILE.
Takes the necessary steps when dealing with OLDFILE being a
shared libraries that may be currently loaded by a running Emacs
session."
(cond ((eq 'windows-nt system-type)
(ignore-errors (delete-file outfile))
(let ((retry t))
(while retry
(setf retry nil)
(ignore-errors (delete-file oldfile))
(while
(condition-case _
(progn
;; outfile maybe recreated by another Emacs in
;; oldfile maybe recreated by another Emacs in
;; between the following two rename-file calls
(if (file-exists-p outfile)
(rename-file outfile (make-temp-file-internal
(file-name-sans-extension outfile)
(if (file-exists-p oldfile)
(rename-file oldfile (make-temp-file-internal
(file-name-sans-extension oldfile)
nil ".eln.old" nil)
t))
(rename-file tmpfile outfile nil))
(file-already-exists (setf retry t))))))
(when newfile
(rename-file newfile oldfile nil))
;; Keep on trying.
nil)
(file-already-exists
;; Done
t))))
;; Remove the old eln instead of copying the new one into it
;; to get a new inode and prevent crashes in case the old one
;; is currently loaded.
(t (delete-file outfile)
(rename-file tmpfile outfile))))
(t (delete-file oldfile)
(when newfile
(rename-file newfile oldfile)))))
(defvar comp-files-queue ()
"List of Elisp files to be compiled.")