unofficial mirror of emacs-devel@gnu.org 
 help / color / mirror / code / Atom feed
From: Dmitry Antipov <dmantipov@yandex.ru>
To: Eli Zaretskii <eliz@gnu.org>
Cc: emacs-devel@gnu.org
Subject: Re: Why buffer_shared is a mistake
Date: Mon, 10 Dec 2012 11:29:46 +0400	[thread overview]
Message-ID: <50C58F6A.2010005@yandex.ru> (raw)
In-Reply-To: <83ip8clk7f.fsf@gnu.org>

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

On 12/08/2012 05:58 PM, Eli Zaretskii wrote:

> buffer_shared is used only by xdisp.c, with the single exception of
> modify_overlay.  How about changing modify_overlay to compute this
> value by itself?

This is definitely possible (by enhancing window_loop, for example).
But now I'm thinking about maintaining per-buffer window counter,
which value is independent from the redisplay actions.  This opens
the way to a different optimizations (e.g. if we're modifying a buffer
which isn't shown in a window, we can avoid redisplay at all).

(My view of the whole thing is: Emacs global state is huge, and
redisplay is controlled by too much amount of global variables.
This is error-prone and makes some valuable things like threading
too complicated or even impossible. So it's desirable to deduce
redisplay actions from per-buffer/window/frame variables rather
than from the global ones.)

Dmitry


[-- Attachment #2: window_count.patch --]
[-- Type: text/plain, Size: 9914 bytes --]

=== modified file 'src/buffer.c'
--- src/buffer.c	2012-12-07 07:16:32 +0000
+++ src/buffer.c	2012-12-10 06:14:55 +0000
@@ -547,6 +547,8 @@
   b->base_buffer = NULL;
   /* No one shares the text with us now.  */
   b->indirections = 0;
+  /* No one shows us now.  */
+  b->window_count = 0;
 
   BUF_GAP_SIZE (b) = 20;
   block_input ();
@@ -794,6 +796,8 @@
   b->indirections = -1;
   /* Notify base buffer that we share the text now.  */
   b->base_buffer->indirections++;
+  /* Always -1 for an indirect buffer.  */
+  b->window_count = -1;
 
   b->pt = b->base_buffer->pt;
   b->begv = b->base_buffer->begv;
@@ -1929,10 +1933,16 @@
       eassert (b->indirections == -1);
       b->base_buffer->indirections--;
       eassert (b->base_buffer->indirections >= 0);
+      /* Make sure that we wasn't confused.  */
+      eassert (b->window_count == -1);
     }
   else
-    /* No one shares our buffer text, can free it.  */
-    free_buffer_text (b);
+    {
+      /* No window showing us, right?  */
+      eassert (b->window_count == 0);
+      /* No one shares our buffer text, can free it.  */
+      free_buffer_text (b);
+    }
 
   if (b->newline_cache)
     {
@@ -3880,17 +3890,17 @@
 
   BUF_COMPUTE_UNCHANGED (buf, start, end);
 
-  /* If this is a buffer not in the selected window,
-     we must do other windows.  */
-  if (buf != XBUFFER (XWINDOW (selected_window)->buffer))
-    windows_or_buffers_changed = 1;
-  /* If multiple windows show this buffer, we must do other windows.  */
-  else if (buffer_shared > 1)
-    windows_or_buffers_changed = 1;
-  /* If we modify an overlay at the end of the buffer, we cannot
-     be sure that window end is still valid.  */
-  else if (end >= ZV && start <= ZV)
-    windows_or_buffers_changed = 1;
+  /* If BUF is visible, consider updating the display if ...  */
+  if (buffer_window_count (buf) > 0)
+    {
+      /* ... it's visible in other window than selected,  */
+      if (buf != XBUFFER (XWINDOW (selected_window)->buffer))
+	windows_or_buffers_changed = 1;
+      /* ... or if we modify an overlay at the end of the buffer
+	 and so we cannot be sure that window end is still valid.  */
+      else if (end >= ZV && start <= ZV)
+	windows_or_buffers_changed = 1;
+    }
 
   ++BUF_OVERLAY_MODIFF (buf);
 }
@@ -5125,6 +5135,9 @@
   /* No one will share the text with these buffers, but let's play it safe.  */
   buffer_defaults.indirections = 0;
   buffer_local_symbols.indirections = 0;
+  /* Likewise no one will display them.  */
+  buffer_defaults.window_count = 0;
+  buffer_local_symbols.window_count = 0;
   set_buffer_intervals (&buffer_defaults, NULL);
   set_buffer_intervals (&buffer_local_symbols, NULL);
   /* This is not strictly necessary, but let's make them initialized.  */

=== modified file 'src/buffer.h'
--- src/buffer.h	2012-12-07 07:16:32 +0000
+++ src/buffer.h	2012-12-10 05:20:09 +0000
@@ -775,6 +775,10 @@
      zero means that we're the only owner of this text.  */
   int indirections;
 
+  /* Number of windows showing this buffer. Always -1 for
+     an indirect buffer since it counts as its base buffer.  */
+  int window_count;
+
   /* A non-zero value in slot IDX means that per-buffer variable
      with index IDX has a local value in this buffer.  The index IDX
      for a buffer-local variable is stored in that variable's slot
@@ -1173,7 +1177,15 @@
        + pos + BUF_BEG_ADDR (buf) - BEG_BYTE);
   return STRING_CHAR (p);
 }
-\f
+
+BUFFER_INLINE int
+buffer_window_count (struct buffer *b)
+{
+  if (b->base_buffer)
+    b = b->base_buffer;
+  return b->window_count;
+}
+
 /* Overlays */
 
 /* Return the marker that stands for where OV starts in the buffer.  */

=== modified file 'src/insdel.c'
--- src/insdel.c	2012-12-03 14:13:06 +0000
+++ src/insdel.c	2012-12-10 05:39:05 +0000
@@ -1796,13 +1796,14 @@
 			  ptrdiff_t *preserve_ptr)
 {
   struct buffer *base_buffer;
+  struct buffer *selected = XBUFFER (XWINDOW (selected_window)->buffer);
 
   if (!NILP (BVAR (current_buffer, read_only)))
     Fbarf_if_buffer_read_only ();
 
-  /* Let redisplay consider other windows than selected_window
-     if modifying another buffer.  */
-  if (XBUFFER (XWINDOW (selected_window)->buffer) != current_buffer)
+  /* If modifying another visible buffer, let redisplay
+     consider other windows than selected_window.  */
+  if (selected != current_buffer && buffer_window_count (selected) > 0)
     ++windows_or_buffers_changed;
 
   if (buffer_intervals (current_buffer))

=== modified file 'src/window.c'
--- src/window.c	2012-12-07 08:13:49 +0000
+++ src/window.c	2012-12-10 05:18:10 +0000
@@ -270,6 +270,35 @@
   return w;
 }
 
+/* Called when W's buffer slot is changed.  ARG -1 means that W is about to
+   cease its buffer, and 1 means that W is about to set up the new one.  */
+
+static void
+adjust_window_count (struct window *w, int arg)
+{
+  eassert (eabs (arg) == 1);
+  if (BUFFERP (w->buffer))
+    {
+      struct buffer *b = XBUFFER (w->buffer);
+      
+      if (b->base_buffer)
+	b = b->base_buffer;
+      b->window_count += arg;
+      eassert (b->window_count >= 0);
+    }
+}
+
+/* Set W's buffer slot to VAL and recompute number
+   of windows showing VAL if it is a buffer.  */
+
+void
+wset_buffer (struct window *w, Lisp_Object val)
+{
+  adjust_window_count (w, -1);
+  w->buffer = val;
+  adjust_window_count (w, 1);
+}
+
 /* Build a frequently used 4-integer (X Y W H) list.  */
 
 static Lisp_Object
@@ -2967,11 +2996,12 @@
 {
   Lisp_Object tail, frame;
 
-  /* A single call to window_loop won't do the job because it only
-     considers frames on the current keyboard.  So loop manually over
-     frames, and handle each one.  */
-  FOR_EACH_FRAME (tail, frame)
-    window_loop (REPLACE_BUFFER_IN_WINDOWS_SAFELY, buffer, 1, frame);
+  if (buffer_window_count (XBUFFER (buffer)) > 0)
+    /* A single call to window_loop won't do the job because it only
+       considers frames on the current keyboard.  So loop manually over
+       frames, and handle each one.  */
+    FOR_EACH_FRAME (tail, frame)
+      window_loop (REPLACE_BUFFER_IN_WINDOWS_SAFELY, buffer, 1, frame);
 }
 \f
 /* If *ROWS or *COLS are too small a size for FRAME, set them to the
@@ -3308,7 +3338,7 @@
 
   if (STRINGP (object))
     object = Fget_buffer (object);
-  if (BUFFERP (object) && BUFFER_LIVE_P (XBUFFER (object)))
+  if (BUFFERP (object) && buffer_window_count (XBUFFER (object)) > 0)
     {
       /* Walk all windows looking for buffer, and force update
 	 of each of those windows.  */
@@ -3391,6 +3421,8 @@
   memcpy ((char *) p + sizeof (struct vectorlike_header),
 	  (char *) o + sizeof (struct vectorlike_header),
 	  word_size * VECSIZE (struct window));
+  /* P's buffer slot was changed.  */
+  adjust_window_count (p, 1);
   XSETWINDOW (parent, p);
 
   p->sequence_number = ++sequence_number;

=== modified file 'src/window.h'
--- src/window.h	2012-11-02 10:34:26 +0000
+++ src/window.h	2012-12-10 05:16:57 +0000
@@ -351,11 +351,6 @@
 /* Most code should use these functions to set Lisp fields in struct
    window.  */
 WINDOW_INLINE void
-wset_buffer (struct window *w, Lisp_Object val)
-{
-  w->buffer = val;
-}
-WINDOW_INLINE void
 wset_frame (struct window *w, Lisp_Object val)
 {
   w->frame = val;
@@ -947,11 +942,6 @@
 
 extern int cursor_type_changed;
 
-/* Number of windows displaying the selected buffer.  Normally this is
-   1, but it can be more.  */
-
-extern int buffer_shared;
-
 /* If *ROWS or *COLS are too small a size for FRAME, set them to the
    minimum allowable size.  */
 
@@ -997,6 +987,8 @@
 extern void temp_output_buffer_show (Lisp_Object);
 extern void replace_buffer_in_windows (Lisp_Object);
 extern void replace_buffer_in_windows_safely (Lisp_Object);
+/* This looks like a setter, but it is a bit special.  */
+extern void wset_buffer (struct window *, Lisp_Object);
 extern void init_window_once (void);
 extern void init_window (void);
 extern void syms_of_window (void);

=== modified file 'src/xdisp.c'
--- src/xdisp.c	2012-12-04 15:15:30 +0000
+++ src/xdisp.c	2012-12-10 07:05:16 +0000
@@ -515,11 +515,6 @@
 
 static int overlay_arrow_seen;
 
-/* Number of windows showing the buffer of the selected
-   window (or another buffer with the same base buffer).  */
-
-int buffer_shared;
-
 /* Vector containing glyphs for an ellipsis `...'.  */
 
 static Lisp_Object default_invis_vector[3];
@@ -10894,9 +10889,8 @@
 static int
 buffer_shared_and_changed (void)
 {
-  /* The variable buffer_shared is set in redisplay_window and
-     indicates that we redisplay a buffer in different windows. */
-  return (buffer_shared > 1 && UNCHANGED_MODIFIED < MODIFF);
+  return (buffer_window_count (current_buffer) > 1
+	  && UNCHANGED_MODIFIED < MODIFF);
 }
 
 /* Nonzero if W doesn't reflect the actual state of current buffer due
@@ -13470,10 +13464,6 @@
       FOR_EACH_FRAME (tail, frame)
 	XFRAME (frame)->updated_p = 0;
 
-      /* Recompute # windows showing selected buffer.  This will be
-	 incremented each time such a window is displayed.  */
-      buffer_shared = 0;
-
       FOR_EACH_FRAME (tail, frame)
 	{
 	  struct frame *f = XFRAME (frame);
@@ -15568,21 +15558,6 @@
   if (mode_line_update_needed (w))
     update_mode_line = 1;
 
-  /* Count number of windows showing the selected buffer.  An indirect
-     buffer counts as its base buffer.  */
-  if (!just_this_one_p)
-    {
-      struct buffer *current_base, *window_base;
-      current_base = current_buffer;
-      window_base = XBUFFER (XWINDOW (selected_window)->buffer);
-      if (current_base->base_buffer)
-	current_base = current_base->base_buffer;
-      if (window_base->base_buffer)
-	window_base = window_base->base_buffer;
-      if (current_base == window_base)
-	buffer_shared++;
-    }
-
   /* Point refers normally to the selected window.  For any other
      window, set up appropriate value.  */
   if (!EQ (window, selected_window))


  reply	other threads:[~2012-12-10  7:29 UTC|newest]

Thread overview: 4+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2012-12-06 16:02 Why buffer_shared is a mistake Dmitry Antipov
2012-12-08 13:58 ` Eli Zaretskii
2012-12-10  7:29   ` Dmitry Antipov [this message]
2012-12-10  8:18     ` Eli Zaretskii

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

  List information: https://www.gnu.org/software/emacs/

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

  git send-email \
    --in-reply-to=50C58F6A.2010005@yandex.ru \
    --to=dmantipov@yandex.ru \
    --cc=eliz@gnu.org \
    --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 public inbox

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

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).