qemacs-commit
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[Qemacs-commit] qemacs buffer.c


From: Charlie Gordon
Subject: [Qemacs-commit] qemacs buffer.c
Date: Sat, 22 Aug 2015 20:49:01 +0000

CVSROOT:        /sources/qemacs
Module name:    qemacs
Changes by:     Charlie Gordon <chqrlie>        15/08/22 20:49:01

Modified files:
        .              : buffer.c 

Log message:
        buffers: fixed crash bug and pathological memory fragmentation
        - simplify eb_insert_low_level() and eb_insert_buffer() to avoid
          pathological cases of kill/yank sequences loading to catastrophic
          fragmentation. eg: kill a 1 byte region and yank it 1000 times
        - mmapped pages are (temporarily) no longer shared between buffers

CVSWeb URLs:
http://cvs.savannah.gnu.org/viewcvs/qemacs/buffer.c?cvsroot=qemacs&r1=1.87&r2=1.88

Patches:
Index: buffer.c
===================================================================
RCS file: /sources/qemacs/qemacs/buffer.c,v
retrieving revision 1.87
retrieving revision 1.88
diff -u -b -r1.87 -r1.88
--- buffer.c    19 Aug 2015 19:20:57 -0000      1.87
+++ buffer.c    22 Aug 2015 20:49:01 -0000      1.88
@@ -131,7 +131,7 @@
     if (b->flags & BF_READONLY)
         return 0;
 
-    /* We carefully clip the request, avoiding and integer overflow */
+    /* We carefully clip the request, avoiding integer overflow */
     if (offset < 0 || size <= 0 || offset > b->total_size)
         return 0;
 
@@ -222,7 +222,7 @@
         offset--;
         p = find_page(b, &offset);
         offset++;
-
+    retry:
         /* compute what we can insert in current page */
         len = MAX_PAGE_SIZE - offset;
         if (len > size)
@@ -230,13 +230,49 @@
         /* number of bytes to put in next pages */
         len_out = p->size + len - MAX_PAGE_SIZE;
         page_index = p - b->page_table;
-        if (len_out > 0)
+        if (len_out > 0) {
+#if 1
+            /* XXX: should first try and shift some of these bytes to
+             * the previous pages */
+            if (page_index > 0 && p[-1].size < MAX_PAGE_SIZE) {
+                int chunk;
+                update_page(p - 1);
+                update_page(p);
+                chunk = min(MAX_PAGE_SIZE - p[-1].size, offset);
+                qe_realloc(&p[-1].data, p[-1].size + chunk);
+                memcpy(p[-1].data + p[-1].size, p->data, chunk);
+                p[-1].size += chunk;
+                p->size -= chunk;
+                if (p->size == 0) {
+                    /* if page was completely fused with previous one */
+                    b->nb_pages -= 1;
+                    qe_free(&p->data);
+                    memmove(p, p + 1,
+                            (b->nb_pages - page_index) * sizeof(Page));
+                    qe_realloc(&b->page_table, b->nb_pages * sizeof(Page));
+                    p = b->page_table + page_index - 1;
+                    offset = p->size;
+                    goto retry;
+                }
+                memmove(p->data, p->data + chunk, p->size);
+                qe_realloc(&p->data, p->size);
+                offset -= chunk;
+                if (offset == 0 && p[-1].size < MAX_PAGE_SIZE) {
+                    /* restart from previous page */
+                    p--;
+                    offset = p->size;
+                }
+                goto retry;
+            }
+#endif
             eb_insert1(b, page_index + 1,
                        p->data + p->size - len_out, len_out);
-        else
+        } else {
             len_out = 0;
+        }
         /* now we can insert in current page */
         if (len > 0) {
+            /* reload p because page_table may have been reallocated */
             p = b->page_table + page_index;
             update_page(p);
             p->size += len - len_out;
@@ -288,11 +324,39 @@
     size0 = size;
 
     eb_addlog(dest, LOGOP_INSERT, dest_offset, size);
-
+#if 1
+    /* Unused variables */
+    n = 0; q = NULL; p_start = NULL; page_index = 0;
+    /* Much simpler algorithm with fewer pathological cases */
+    p = find_page(src, &src_offset);
+    while (size > 0) {
+        len = p->size - src_offset;
+        if (len > size)
+            len = size;
+        if ((p->flags & PG_READ_ONLY) && src_offset == 0 && len == 
MAX_PAGE_SIZE) {
+            /* XXX: should share complete read-only pages.  This is
+             * actually a little tricky: the mapping may be removed
+             * upon buffer close. We need a ref count scheme to keep
+             * track of these pages.
+             * A brute force approach may prove best: upon unmapping a
+             * file, scan all buffers for shared pages and delay
+             * unmapping until these get freed.  We may keep a global
+             * and a buffer based count of shared pages and a list of
+             * mappings to accelerate this phase.
+             */
+        }
+        eb_insert_lowlevel(dest, dest_offset, p->data + src_offset, len);
+        dest_offset += len;
+        src_offset = 0;
+        p++;
+        size -= len;
+    }
+    return size0;
+#else
     /* insert the data from the first page if it is not completely
        selected */
     p = find_page(src, &src_offset);
-    if (src_offset > 0) {
+    if (src_offset > 0 /* || size <= p->size */ ) {
         len = p->size - src_offset;
         if (len > size)
             len = size;
@@ -365,10 +429,10 @@
     if (size > 0) {
         eb_insert1(dest, page_index, p->data, size);
     }
-
     /* the page cache is no longer valid */
     dest->cur_page = NULL;
     return size0;
+#endif
 }
 
 /* Insert 'size' bytes from 'buf' into 'b' at offset 'offset'. We must
@@ -395,21 +459,6 @@
     return size;
 }
 
-/* Verify that window still exists, return argument or NULL,
- * update handle if window is invalid.
- */
-EditBuffer *check_buffer(EditBuffer **sp)
-{
-    QEmacsState *qs = &qe_state;
-    EditBuffer *b;
-
-    for (b = qs->first_buffer; b != NULL; b = b->next) {
-        if (b == *sp)
-            return b;
-    }
-    return *sp = NULL;
-}
-
 /* We must have : 0 <= offset <= b->total_size,
  * return actual number of bytes removed.
  */
@@ -458,6 +507,7 @@
             p->size -= len;
             qe_realloc(&p->data, p->size);
             offset += len;
+            /* XXX: should merge with adjacent pages if size becomes small? */
             if (offset >= p->size) {
                 p++;
                 offset = 0;
@@ -480,6 +530,37 @@
     return size0;
 }
 
+/*---------------- finding buffers ----------------*/
+
+/* Verify that window still exists, return argument or NULL,
+ * update handle if window is invalid.
+ */
+EditBuffer *check_buffer(EditBuffer **sp)
+{
+    QEmacsState *qs = &qe_state;
+    EditBuffer *b;
+
+    for (b = qs->first_buffer; b != NULL; b = b->next) {
+        if (b == *sp)
+            return b;
+    }
+    return *sp = NULL;
+}
+
+EditBuffer *eb_find(const char *name)
+{
+    QEmacsState *qs = &qe_state;
+    EditBuffer *b;
+
+    b = qs->first_buffer;
+    while (b != NULL) {
+        if (strequal(b->name, name))
+            return b;
+        b = b->next;
+    }
+    return NULL;
+}
+
 /* flush the log */
 void log_reset(EditBuffer *b)
 {
@@ -639,20 +720,6 @@
     }
 }
 
-EditBuffer *eb_find(const char *name)
-{
-    QEmacsState *qs = &qe_state;
-    EditBuffer *b;
-
-    b = qs->first_buffer;
-    while (b != NULL) {
-        if (strequal(b->name, name))
-            return b;
-        b = b->next;
-    }
-    return NULL;
-}
-
 EditBuffer *eb_find_new(const char *name, int flags)
 {
     EditBuffer *b;



reply via email to

[Prev in Thread] Current Thread [Next in Thread]