all messages for Emacs-related lists mirrored at yhetil.org
 help / color / mirror / code / Atom feed
From: "Stuart D. Herring" <herring@lanl.gov>
Cc: emacs-devel@gnu.org
Subject: Re: A few questions about desktop.el
Date: Thu, 27 Apr 2006 16:05:53 -0700 (PDT)	[thread overview]
Message-ID: <58643.128.165.123.132.1146179153.squirrel@webmail.lanl.gov> (raw)
In-Reply-To: <f7ccd24b0507270728c1c4758@mail.gmail.com>

[-- Attachment #1: Type: text/plain, Size: 2219 bytes --]

Way back in July 2005, this was part of a discussion about improving
desktop.el:

> Not-totally-unrelated: running two or more Emacs instances that use
> the same desktop file is a classical race condition; the last one to
> exit overwrites the desktop file (quite funny when the desktop was
> very elaborate and the last instance to exit uses almost no buffers).
>
> It'd be very useful to try to detect it and at least stop the second
> instance from loading and using the desktop file if it's already in
> use. There's no way to do that from Emacs, is there?

Richard later suggested using the file-locking primitives along with file
timestamps to implement this.  Here's a stab at implementing the collision
detection, but without file locking because I wasn't sure how to mix that
with `load' competently.  (I suspect this matters little since Emacs
sessions are quite unlikely to be actually _accessing_ the desktop file at
the same time.)

Two things are done: first, a desktop file is modified when it is read
(without incident) to include a "in use" tag; further Emacses will
complain about this if they see it, and will leave the desktop file
unloaded unless the user accepts the collision risk.

Second, when a desktop file is read or written, its modification time
(which is typically "now", since with this patch even loading the file
modifies it) is remembered; if it's different when the desktop is to be
saved, appropriate queries are posed.  (In particular, if no desktop file
is loaded, perhaps because the user decided not to re-load a file, any
attempt to save the new desktop over an existing desktop file will be
complained about.)

I'm certainly not proposing this for installation right now; it needs lots
more testing than I've given it (possibly by people who actually use
desktop), and my papers-issues aren't yet resolved.  But I encourage
people (in particular Juanma, who raised the issue) to try it and let me
know if it's any good; if the testing and the papers go okay, it'll just
need a ChangeLog entry to be good.

Enjoy,
Davis

-- 
This product is sold by volume, not by mass.  If it appears too dense or
too sparse, it is because mass-energy conversion has occurred during
shipping.

[-- Attachment #2: desktop-conflict.patch --]
[-- Type: application/octet-stream, Size: 14483 bytes --]

Index: desktop.el
===================================================================
RCS file: /sources/emacs/emacs/lisp/desktop.el,v
retrieving revision 1.99
diff -c -r1.99 desktop.el
*** desktop.el	10 Feb 2006 11:05:30 -0000	1.99
--- desktop.el	27 Apr 2006 23:00:03 -0000
***************
*** 475,480 ****
--- 475,484 ----
  (defvar desktop-dirname nil
    "The directory in which the desktop file should be saved.")
  
+ (defun desktop-full-file-name (&optional dirname)
+   "Return the full name of the current desktop file."
+   (expand-file-name desktop-base-file-name (or dirname desktop-dirname)))
+ 
  (defconst desktop-header
  ";; --------------------------------------------------------------------------
  ;; Desktop File for Emacs
***************
*** 484,489 ****
--- 488,503 ----
  (defvar desktop-delay-hook nil
    "Hooks run after all buffers are loaded; intended for internal use.")
  
+ (defvar desktop-file-modtime nil
+   "When the desktop file was last modified to the knowledge of this Emacs.
+ Used to detect desktop file conflicts.")
+ 
+ (defun desktop-conflict-text ()
+   "Return a string for inclusion in the desktop file to detect conflicts.
+ The string contains a comment for humans and a `setq' for Emacs."
+   (format "\n;; This desktop file was in use as of %s\n(setq desktop-owner %s)\n"
+ 	  (format-time-string "%x %X %Z") (emacs-pid)))
+ 
  ;; ----------------------------------------------------------------------------
  (defun desktop-truncate (list n)
    "Truncate LIST to at most N elements destructively."
***************
*** 531,537 ****
    (when
      (and
        desktop-save-mode
!       (let ((exists (file-exists-p (expand-file-name desktop-base-file-name desktop-dirname))))
          (or
            (eq desktop-save t)
            (and exists (memq desktop-save '(ask-if-new if-exists)))
--- 545,551 ----
    (when
      (and
        desktop-save-mode
!       (let ((exists (file-exists-p (desktop-full-file-name))))
          (or
            (eq desktop-save t)
            (and exists (memq desktop-save '(ask-if-new if-exists)))
***************
*** 547,553 ****
              (call-interactively
                (lambda (dir) (interactive "DDirectory for desktop file: ") dir))))))
      (condition-case err
!       (desktop-save desktop-dirname)
        (file-error
          (unless (yes-or-no-p "Error while saving the desktop.  Ignore? ")
            (signal (car err) (cdr err)))))))
--- 561,567 ----
              (call-interactively
                (lambda (dir) (interactive "DDirectory for desktop file: ") dir))))))
      (condition-case err
!       (desktop-save desktop-dirname t)
        (file-error
          (unless (yes-or-no-p "Error while saving the desktop.  Ignore? ")
            (signal (car err) (cdr err)))))))
***************
*** 715,730 ****
      (t (expand-file-name filename))))
  
  ;; ----------------------------------------------------------------------------
! (defun desktop-save (dirname)
    "Save the desktop in a desktop file.
  Parameter DIRNAME specifies where to save the desktop file.
  See also `desktop-base-file-name'."
    (interactive "DDirectory to save desktop file in: ")
    (run-hooks 'desktop-save-hook)
!   (setq dirname (file-name-as-directory (expand-file-name dirname)))
    (save-excursion
!     (let ((filename (expand-file-name desktop-base-file-name dirname))
!           (info
              (mapcar
                #'(lambda (b)
                    (set-buffer b)
--- 729,744 ----
      (t (expand-file-name filename))))
  
  ;; ----------------------------------------------------------------------------
! (defun desktop-save (dirname &optional release)
    "Save the desktop in a desktop file.
  Parameter DIRNAME specifies where to save the desktop file.
+ Optional parameter RELEASE says whether we're done with this desktop.
  See also `desktop-base-file-name'."
    (interactive "DDirectory to save desktop file in: ")
    (run-hooks 'desktop-save-hook)
!   (setq desktop-dirname (file-name-as-directory (expand-file-name dirname)))
    (save-excursion
!     (let ((info
              (mapcar
                #'(lambda (b)
                    (set-buffer b)
***************
*** 765,808 ****
                (buffer-list)))
            (eager desktop-restore-eager)
            (buf (get-buffer-create "*desktop*")))
!       (set-buffer buf)
!       (erase-buffer)
! 
!       (insert
!         ";; -*- mode: emacs-lisp; coding: emacs-mule; -*-\n"
!         desktop-header
!         ";; Created " (current-time-string) "\n"
!         ";; Desktop file format version " desktop-file-version "\n"
!         ";; Emacs version " emacs-version "\n\n"
!         ";; Global section:\n")
!       (mapc (function desktop-outvar) desktop-globals-to-save)
!       (if (memq 'kill-ring desktop-globals-to-save)
!         (insert
!           "(setq kill-ring-yank-pointer (nthcdr "
!           (int-to-string (- (length kill-ring) (length kill-ring-yank-pointer)))
!           " kill-ring))\n"))
! 
!       (insert "\n;; Buffer section -- buffers listed in same order as in buffer list:\n")
!       (mapc #'(lambda (l)
!                 (when (apply 'desktop-save-buffer-p l)
!                   (insert "("
!                           (if (or (not (integerp eager))
!                                   (unless (zerop eager)
!                                     (setq eager (1- eager))
!                                     t))
!                               "desktop-create-buffer"
!                             "desktop-append-buffer-args")
!                           " "
!                           desktop-file-version)
!                   (mapc #'(lambda (e)
!                             (insert "\n  " (desktop-value-to-string e)))
!                         l)
!                   (insert ")\n\n")))
!             info)
!       (setq default-directory dirname)
!       (let ((coding-system-for-write 'emacs-mule))
!         (write-region (point-min) (point-max) filename nil 'nomessage))))
!   (setq desktop-dirname dirname))
  
  ;; ----------------------------------------------------------------------------
  (defun desktop-remove ()
--- 779,836 ----
                (buffer-list)))
            (eager desktop-restore-eager)
            (buf (get-buffer-create "*desktop*")))
!       (let ((new-modtime (nth 5 (file-attributes (desktop-full-file-name)))))
! 	(when 
! 	    (or (not new-modtime)	; nothing to overwrite
! 		(equal desktop-file-modtime new-modtime)
! 		(yes-or-no-p (if desktop-file-modtime
! 				 (if (> (float-time new-modtime) (float-time desktop-file-modtime))
! 				     "Desktop file is more recent than the one loaded.  Save anyway? "
! 				   "Desktop file isn't the one loaded.  Overwrite it? ")
! 			       "Current desktop was not loaded from a file.  Overwrite this desktop file? "))
! 		(unless release (error "Desktop file conflict")))
! 
! 	  (set-buffer buf)
! 	  (erase-buffer)
! 
! 	  (insert
! 	   ";; -*- mode: emacs-lisp; coding: emacs-mule; -*-\n"
! 	   desktop-header
! 	   ";; Created " (current-time-string) "\n"
! 	   ";; Desktop file format version " desktop-file-version "\n"
! 	   ";; Emacs version " emacs-version "\n"
! 	   (if release "" (desktop-conflict-text))
! 	   "\n;; Global section:\n")
! 	  (mapc (function desktop-outvar) desktop-globals-to-save)
! 	  (if (memq 'kill-ring desktop-globals-to-save)
! 	      (insert
! 	       "(setq kill-ring-yank-pointer (nthcdr "
! 	       (int-to-string (- (length kill-ring) (length kill-ring-yank-pointer)))
! 	       " kill-ring))\n"))
! 
! 	  (insert "\n;; Buffer section -- buffers listed in same order as in buffer list:\n")
! 	  (mapc #'(lambda (l)
! 		    (when (apply 'desktop-save-buffer-p l)
! 		      (insert "("
! 			      (if (or (not (integerp eager))
! 				      (unless (zerop eager)
! 					(setq eager (1- eager))
! 					t))
! 				  "desktop-create-buffer"
! 				"desktop-append-buffer-args")
! 			      " "
! 			      desktop-file-version)
! 		      (mapc #'(lambda (e)
! 				(insert "\n  " (desktop-value-to-string e)))
! 			    l)
! 		      (insert ")\n\n")))
! 		info)
! 
! 	  (setq default-directory dirname)
! 	  (let ((coding-system-for-write 'emacs-mule))
! 	    (write-region (point-min) (point-max) (desktop-full-file-name) nil 'nomessage))
! 	  ;; We remember when it was modified (which is presumably just now).
! 	  (setq desktop-file-modtime (nth 5 (file-attributes (desktop-full-file-name)))))))))
  
  ;; ----------------------------------------------------------------------------
  (defun desktop-remove ()
***************
*** 810,816 ****
  This function also sets `desktop-dirname' to nil."
    (interactive)
    (when desktop-dirname
!     (let ((filename (expand-file-name desktop-base-file-name desktop-dirname)))
        (setq desktop-dirname nil)
        (when (file-exists-p filename)
          (delete-file filename)))))
--- 838,844 ----
  This function also sets `desktop-dirname' to nil."
    (interactive)
    (when desktop-dirname
!     (let ((filename (desktop-full-file-name)))
        (setq desktop-dirname nil)
        (when (file-exists-p filename)
          (delete-file filename)))))
***************
*** 833,884 ****
    (interactive)
    (unless noninteractive
      (setq desktop-dirname
!       (file-name-as-directory
!         (expand-file-name
!           (or
!             ;; If DIRNAME is specified, use it.
!             (and (< 0 (length dirname)) dirname)
!             ;; Otherwise search desktop file in desktop-path.
!             (let ((dirs desktop-path))
!               (while
!                 (and
!                   dirs
!                   (not
!                     (file-exists-p (expand-file-name desktop-base-file-name (car dirs)))))
!                 (setq dirs (cdr dirs)))
!               (and dirs (car dirs)))
!             ;; If not found and `desktop-path' is non-nil, use its first element.
!             (and desktop-path (car desktop-path))
!             ;; Default: Home directory.
!             "~"))))
!     (if (file-exists-p (expand-file-name desktop-base-file-name desktop-dirname))
!       ;; Desktop file found, process it.
!       (let ((desktop-first-buffer nil)
!             (desktop-buffer-ok-count 0)
!             (desktop-buffer-fail-count 0))
!         (setq desktop-lazy-timer nil)
!         ;; Evaluate desktop buffer.
!         (load (expand-file-name desktop-base-file-name desktop-dirname) t t t)
!         ;; `desktop-create-buffer' puts buffers at end of the buffer list.
!         ;; We want buffers existing prior to evaluating the desktop (and not reused)
!         ;; to be placed at the end of the buffer list, so we move them here.
!         (mapc 'bury-buffer
!               (nreverse (cdr (memq desktop-first-buffer (nreverse (buffer-list))))))
!         (switch-to-buffer (car (buffer-list)))
!         (run-hooks 'desktop-delay-hook)
!         (setq desktop-delay-hook nil)
!         (run-hooks 'desktop-after-read-hook)
!         (message "Desktop: %d buffer%s restored%s%s."
!                  desktop-buffer-ok-count
!                  (if (= 1 desktop-buffer-ok-count) "" "s")
!                  (if (< 0 desktop-buffer-fail-count)
!                      (format ", %d failed to restore" desktop-buffer-fail-count)
!                    "")
!                  (if desktop-buffer-args-list
!                      (format ", %d to restore lazily"
!                              (length desktop-buffer-args-list))
!                    ""))
!         t)
        ;; No desktop file found.
        (desktop-clear)
        (let ((default-directory desktop-dirname))
--- 861,930 ----
    (interactive)
    (unless noninteractive
      (setq desktop-dirname
! 	  (file-name-as-directory
! 	   (expand-file-name
! 	    (or
! 	     ;; If DIRNAME is specified, use it.
! 	     (and (< 0 (length dirname)) dirname)
! 	     ;; Otherwise search desktop file in desktop-path.
! 	     (let ((dirs desktop-path))
! 	       (while
! 		   (and
! 		    dirs
! 		    (not
! 		     (file-exists-p (desktop-full-file-name (car dirs)))))
! 		 (setq dirs (cdr dirs)))
! 	       (and dirs (car dirs)))
! 	     ;; If not found and `desktop-path' is non-nil, use its first element.
! 	     (and desktop-path (car desktop-path))
! 	     ;; Default: Home directory.
! 	     "~"))))
!     (if (file-exists-p (desktop-full-file-name))
! 	;; Desktop file found, process it.
! 	(let ((desktop-first-buffer nil)
! 	      (desktop-buffer-ok-count 0)
! 	      (desktop-buffer-fail-count 0)
! 	      desktop-owner)
! 	  (setq desktop-lazy-timer nil)
! 	  ;; Evaluate desktop buffer.
! 	  (load (desktop-full-file-name) t t t)
! 	  (if (and desktop-owner
! 		   (not (y-or-n-p (format "Warning: desktop file appears to be in use by PID %s.\nUsing it may cause conflicts.  Use it anyway? " desktop-owner))))
! 	      (progn (desktop-clear)
! 		     (setq desktop-dirname nil)
! 		     (message "Desktop file in use; not loaded.")
! 		     nil)
! 	    ;; If it wasn't already, mark it as in-use, to bother other
! 	    ;; desktop instances.
! 	    (unless desktop-owner
! 	      (condition-case nil
! 		  (write-region (desktop-conflict-text) nil
! 				(desktop-full-file-name) t 'nomessage)
! 		(file-error (message "Couldn't mark desktop file as active")
! 			    (sit-for 1))))
! 	    ;; We remember when it was modified (which is presumably just now).
! 	    (setq desktop-file-modtime (nth 5 (file-attributes (desktop-full-file-name))))
! 	    ;; `desktop-create-buffer' puts buffers at end of the buffer list.
! 	    ;; We want buffers existing prior to evaluating the desktop (and
! 	    ;; not reused) to be placed at the end of the buffer list, so we
! 	    ;; move them here.
! 	    (mapc 'bury-buffer
! 		  (nreverse (cdr (memq desktop-first-buffer (nreverse (buffer-list))))))
! 	    (switch-to-buffer (car (buffer-list)))
! 	    (run-hooks 'desktop-delay-hook)
! 	    (setq desktop-delay-hook nil)
! 	    (run-hooks 'desktop-after-read-hook)
! 	    (message "Desktop: %d buffer%s restored%s%s."
! 		     desktop-buffer-ok-count
! 		     (if (= 1 desktop-buffer-ok-count) "" "s")
! 		     (if (< 0 desktop-buffer-fail-count)
! 			 (format ", %d failed to restore" desktop-buffer-fail-count)
! 		       "")
! 		     (if desktop-buffer-args-list
! 			 (format ", %d to restore lazily"
! 				 (length desktop-buffer-args-list))
! 		       ""))
! 	    t))
        ;; No desktop file found.
        (desktop-clear)
        (let ((default-directory desktop-dirname))

[-- Attachment #3: Type: text/plain, Size: 142 bytes --]

_______________________________________________
Emacs-devel mailing list
Emacs-devel@gnu.org
http://lists.gnu.org/mailman/listinfo/emacs-devel

  parent reply	other threads:[~2006-04-27 23:05 UTC|newest]

Thread overview: 72+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2005-07-22  2:42 A few questions about desktop.el Juanma Barranquero
2005-07-22 10:53 ` Juanma Barranquero
2005-07-22 22:52   ` Richard M. Stallman
2005-07-26  8:56     ` Juanma Barranquero
2005-07-27 14:03       ` Richard M. Stallman
2005-07-27 14:28         ` Juanma Barranquero
2005-07-28  3:20           ` Richard M. Stallman
2005-07-28  7:34             ` David Kastrup
2005-07-28 12:51               ` Juanma Barranquero
2005-07-29  0:11               ` Richard M. Stallman
2005-07-28  3:20           ` Richard M. Stallman
2005-07-29  0:37             ` Juanma Barranquero
2005-07-28  4:24           ` Masatake YAMATO
2006-04-27 23:05           ` Stuart D. Herring [this message]
2006-04-28 14:56             ` Juanma Barranquero
2006-04-29  4:57               ` Stuart D. Herring
2006-04-30  1:16                 ` Juanma Barranquero
2006-05-02 15:06                   ` Stuart D. Herring
2006-05-02 15:14                     ` Juanma Barranquero
2006-05-02 15:42                       ` Stuart D. Herring
2006-05-02 17:57                         ` Stuart D. Herring
2006-04-28 15:44             ` Richard Stallman
2006-04-29  5:02               ` Stuart D. Herring
2006-04-30  3:03                 ` Richard Stallman
2006-05-03 12:48               ` Juri Linkov
2006-05-03 14:37                 ` Lars Hansen
2006-05-03 20:43                   ` Richard Stallman
2006-05-04 16:27                   ` Stuart D. Herring
2006-05-05  6:44                     ` Lars Hansen
2007-06-05  9:24                     ` Juanma Barranquero
2007-06-08 21:17                       ` Davis Herring
2007-06-08 21:29                         ` Juanma Barranquero
2007-06-08 22:05                           ` Davis Herring
2007-06-08 22:14                         ` Juri Linkov
2007-06-09  0:51                           ` Davis Herring
2007-06-09 21:31                             ` Juri Linkov
2007-06-10 23:28                               ` Juanma Barranquero
2007-06-11 20:54                                 ` Juri Linkov
2007-06-12 11:21                                   ` Juanma Barranquero
2006-05-04 16:17                 ` Stuart D. Herring
2005-08-08 15:02   ` Lars Hansen
2005-07-22 13:50 ` Juanma Barranquero
2005-07-22 14:36   ` Juanma Barranquero
2005-07-26  8:27     ` Juanma Barranquero
2005-08-08 15:04     ` Lars Hansen
2005-07-22 19:11 ` Lars Hansen
2005-07-22 21:24   ` Juanma Barranquero
2005-07-22 22:50 ` Richard M. Stallman
2005-07-26  9:11   ` Juanma Barranquero
2005-07-27 14:04     ` Richard M. Stallman
2005-07-27 14:16       ` Juanma Barranquero
2005-07-28  3:20         ` Richard M. Stallman
2005-07-29  0:44           ` Juanma Barranquero
2005-08-10  9:50         ` Lars Hansen
2005-08-10 11:24           ` Juanma Barranquero
2006-02-09 16:30             ` Juanma Barranquero
2006-02-09 20:00               ` Lars Hansen
2006-02-09 21:11               ` Lars Hansen
2006-02-09 23:46                 ` Juanma Barranquero
2005-08-10 22:05           ` Luc Teirlinck
2005-08-10 23:45             ` Luc Teirlinck
2005-08-11  1:12               ` Luc Teirlinck
2005-08-11  1:36                 ` Luc Teirlinck
2005-08-11  3:01                 ` Luc Teirlinck
2005-08-11  6:12                   ` Lars Hansen
2005-08-08 14:51 ` Lars Hansen
2005-08-08 18:35   ` Juanma Barranquero
2005-08-09  7:12     ` Lars Hansen
2005-08-09  7:36       ` Lars Hansen
2005-08-09  8:49       ` Juanma Barranquero
2005-08-09  9:31         ` David Kastrup
2005-08-09  9:59           ` Juanma Barranquero

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=58643.128.165.123.132.1146179153.squirrel@webmail.lanl.gov \
    --to=herring@lanl.gov \
    --cc=emacs-devel@gnu.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
Code repositories for project(s) associated with this external index

	https://git.savannah.gnu.org/cgit/emacs.git
	https://git.savannah.gnu.org/cgit/emacs/org-mode.git

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.