~ubuntu-branches/ubuntu/saucy/vte/saucy

« back to all changes in this revision

Viewing changes to debian/patches/backscroll-stream-mem.patch

  • Committer: Package Import Robot
  • Author(s): Kees Cook
  • Date: 2012-03-21 13:36:14 UTC
  • Revision ID: package-import@ubuntu.com-20120321133614-imjvf3v34x3icibv
Tags: 1:0.28.2-3ubuntu2
Add debian/patches/backscroll-stream-mem.patch: provide a memory-based
scrollback stream backend to avoid hitting disk with terminal contents
(LP: #778872).

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
Description: use memory-based circular buffer "stream" for the non-infinite
 
2
 scrollback state. This delays stream initialization so that the true size
 
3
 of the desired scrollback state can be discovered. This also means that
 
4
 changing the scrollback size in the middle of using a stream means you
 
5
 won't change the backend stream type.
 
6
Author: Kees Cook <kees@ubuntu.com>
 
7
Ubuntu-Bug: https://bugs.launchpad.net/ubuntu/+source/vte/+bug/778872
 
8
Bug: https://bugzilla.gnome.org/show_bug.cgi?id=664611
 
9
 
 
10
Index: vte-0.28.2/src/vtestream-mem.h
 
11
===================================================================
 
12
--- /dev/null   1970-01-01 00:00:00.000000000 +0000
 
13
+++ vte-0.28.2/src/vtestream-mem.h      2012-03-07 14:47:42.822382527 -0800
 
14
@@ -0,0 +1,321 @@
 
15
+/*
 
16
+ * Copyright (C) 2009,2010 Red Hat, Inc.
 
17
+ * Copyright (C) 2012 Kees Cook
 
18
+ *
 
19
+ * This is free software; you can redistribute it and/or modify it under
 
20
+ * the terms of the GNU Library General Public License as published by
 
21
+ * the Free Software Foundation; either version 2 of the License, or
 
22
+ * (at your option) any later version.
 
23
+ *
 
24
+ * This program is distributed in the hope that it will be useful, but
 
25
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
 
26
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 
27
+ * General Public License for more details.
 
28
+ *
 
29
+ * You should have received a copy of the GNU Library General Public
 
30
+ * License along with this program; if not, write to the Free Software
 
31
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 
32
+ *
 
33
+ * Red Hat Author(s): Behdad Esfahbod
 
34
+ * Ubuntu Authors(s): Kees Cook <kees@ubuntu.com>
 
35
+ */
 
36
+
 
37
+#include <string.h>
 
38
+#include <unistd.h>
 
39
+#include <errno.h>
 
40
+
 
41
+#include <gio/gunixinputstream.h>
 
42
+
 
43
+/*
 
44
+ * VteMemStream: A memory-based stream
 
45
+ */
 
46
+
 
47
+struct mem_region {
 
48
+       gchar * region;
 
49
+       gsize allocated; /* How much memory exists in the region. */
 
50
+       gsize length; /* Current length of valid written data in the region. */
 
51
+       gsize seekpos; /* Where in the region we are positioned from seeking. */
 
52
+};
 
53
+
 
54
+typedef struct _VteMemStream {
 
55
+       VteStream parent;
 
56
+
 
57
+       /* The first is for the write head, second is for last page */
 
58
+       struct mem_region page[2];
 
59
+       gsize offset[2]; /* Offset into... ? */
 
60
+} VteMemStream;
 
61
+
 
62
+typedef VteStreamClass VteMemStreamClass;
 
63
+
 
64
+static GType _vte_mem_stream_get_type (void);
 
65
+#define VTE_TYPE_MEM_STREAM _vte_mem_stream_get_type ()
 
66
+
 
67
+G_DEFINE_TYPE (VteMemStream, _vte_mem_stream, VTE_TYPE_STREAM)
 
68
+
 
69
+static void
 
70
+_vte_mem_stream_init (VteMemStream *stream G_GNUC_UNUSED)
 
71
+{
 
72
+}
 
73
+
 
74
+VteStream *
 
75
+_vte_mem_stream_new (void)
 
76
+{
 
77
+       return (VteStream *) g_object_new (VTE_TYPE_MEM_STREAM, NULL);
 
78
+}
 
79
+
 
80
+static void
 
81
+_vte_mem_stream_finalize (GObject *object)
 
82
+{
 
83
+       VteMemStream *stream = (VteMemStream *) object;
 
84
+       gint i;
 
85
+
 
86
+       for (i = 0; i < 2; i ++) {
 
87
+               if (stream->page[i].region) g_free (stream->page[i].region);
 
88
+               memset(&stream->page[i], 0, sizeof (stream->page[i]));
 
89
+               stream->offset[i] = 0;
 
90
+       }
 
91
+
 
92
+       G_OBJECT_CLASS (_vte_mem_stream_parent_class)->finalize(object);
 
93
+}
 
94
+
 
95
+static gsize
 
96
+_mem_xseek (VteMemStream *stream, gint id, gsize pos, int whence)
 
97
+{
 
98
+       g_assert (id == 0 || id == 1);
 
99
+
 
100
+       switch (whence) {
 
101
+       case SEEK_SET:
 
102
+               if (pos > stream->page[id].length)
 
103
+                       pos = stream->page[id].length;
 
104
+               stream->page[id].seekpos = pos;
 
105
+               break;
 
106
+       case SEEK_END:
 
107
+               stream->page[id].seekpos = stream->page[id].length;
 
108
+               break;
 
109
+       }
 
110
+       return stream->page[id].seekpos;
 
111
+}
 
112
+
 
113
+static gsize
 
114
+_mem_xread (VteMemStream *stream, gint id, char *data, gsize len)
 
115
+{
 
116
+       g_assert (id == 0 || id == 1);
 
117
+
 
118
+       if (G_UNLIKELY (len && !stream->page[id].region))
 
119
+               return 0;
 
120
+
 
121
+       if (len > stream->page[id].length - stream->page[id].seekpos)
 
122
+               len = stream->page[id].length - stream->page[id].seekpos;
 
123
+
 
124
+       g_memmove (data, stream->page[id].region + stream->page[id].seekpos, len);
 
125
+       stream->page[id].seekpos += len;
 
126
+
 
127
+       return len;
 
128
+}
 
129
+
 
130
+static void
 
131
+_mem_xwrite (VteMemStream *stream, gint id, const char *data, gsize len)
 
132
+{
 
133
+       g_assert (id == 0 || id == 1);
 
134
+
 
135
+       if (G_UNLIKELY (!stream->page[id].region))
 
136
+               return;
 
137
+
 
138
+       while (stream->page[id].seekpos + len > stream->page[id].allocated) {
 
139
+               gsize want = stream->page[id].allocated * 2;
 
140
+               stream->page[id].region = g_realloc (stream->page[id].region, want);
 
141
+               /* TODO: handle alloc failure. */
 
142
+               stream->page[id].allocated = want;
 
143
+       }
 
144
+
 
145
+       g_memmove (stream->page[id].region + stream->page[id].seekpos, data, len);
 
146
+       stream->page[id].seekpos += len;
 
147
+       if (stream->page[id].seekpos > stream->page[id].length)
 
148
+               stream->page[id].length = stream->page[id].seekpos;
 
149
+}
 
150
+
 
151
+static void
 
152
+_mem_xtruncate (VteMemStream *stream, gint id, gsize size)
 
153
+{
 
154
+       g_assert (id == 0 || id == 1);
 
155
+
 
156
+       if (G_UNLIKELY (!stream->page[id].region))
 
157
+               return;
 
158
+
 
159
+       /* This only expects the region to be reduced in size. */
 
160
+       g_assert (size <= stream->page[id].length);
 
161
+
 
162
+       stream->page[id].region = g_realloc(stream->page[id].region, size);
 
163
+       /* TODO: handle alloc failure. */
 
164
+       stream->page[id].length = stream->page[id].allocated = size;
 
165
+       if (stream->page[id].seekpos > size)
 
166
+               stream->page[id].seekpos = size;
 
167
+}
 
168
+
 
169
+static gboolean
 
170
+_mem_xwrite_contents (VteMemStream *stream, gint id, GOutputStream *output,
 
171
+                 GCancellable *cancellable, GError **error)
 
172
+{
 
173
+       gboolean ret;
 
174
+       gsize written;
 
175
+
 
176
+       g_assert (id == 0 || id == 1);
 
177
+
 
178
+       if (G_UNLIKELY (!stream->page[id].region))
 
179
+               return TRUE;
 
180
+
 
181
+       ret = g_output_stream_write_all (output,
 
182
+                                        stream->page[id].region + stream->page[id].seekpos,
 
183
+                                        stream->page[id].length - stream->page[id].seekpos,
 
184
+                                        &written, cancellable, error);
 
185
+       stream->page[id].seekpos = stream->page[id].length;
 
186
+
 
187
+       return ret;
 
188
+}
 
189
+
 
190
+static void
 
191
+_vte_mem_stream_reset (VteStream *astream, gsize offset)
 
192
+{
 
193
+       VteMemStream *stream = (VteMemStream *) astream;
 
194
+
 
195
+       if (stream->page[0].region) _mem_xtruncate (stream, 0, 0);
 
196
+       if (stream->page[1].region) _mem_xtruncate (stream, 1, 0);
 
197
+
 
198
+       stream->offset[0] = stream->offset[1] = offset;
 
199
+}
 
200
+
 
201
+static inline void
 
202
+_vte_mem_stream_ensure_region0 (VteMemStream *stream)
 
203
+{
 
204
+       if (G_LIKELY (stream->page[0].region))
 
205
+               return;
 
206
+
 
207
+       stream->page[0].allocated = 4096;       /* Arbitrary initial size. */
 
208
+       stream->page[0].region = g_malloc(stream->page[0].allocated);
 
209
+       /* TODO: how to handle malloc failure? */
 
210
+}
 
211
+
 
212
+static gsize
 
213
+_vte_mem_stream_append (VteStream *astream, const char *data, gsize len)
 
214
+{
 
215
+       VteMemStream *stream = (VteMemStream *) astream;
 
216
+       gsize ret;
 
217
+
 
218
+       _vte_mem_stream_ensure_region0 (stream);
 
219
+
 
220
+       ret = _mem_xseek (stream, 0, 0, SEEK_END);
 
221
+       _mem_xwrite (stream, 0, data, len);
 
222
+
 
223
+       return stream->offset[0] + ret;
 
224
+}
 
225
+
 
226
+static gboolean
 
227
+_vte_mem_stream_read (VteStream *astream, gsize offset, char *data, gsize len)
 
228
+{
 
229
+       VteMemStream *stream = (VteMemStream *) astream;
 
230
+       gsize l;
 
231
+
 
232
+       if (G_UNLIKELY (offset < stream->offset[1]))
 
233
+               return FALSE;
 
234
+
 
235
+       if (offset < stream->offset[0]) {
 
236
+               _mem_xseek (stream, 1, offset - stream->offset[1], SEEK_SET);
 
237
+               l = _mem_xread (stream, 1, data, len);
 
238
+               offset += l; data += l; len -= l; if (!len) return TRUE;
 
239
+       }
 
240
+
 
241
+       _mem_xseek (stream, 0, offset - stream->offset[0], SEEK_SET);
 
242
+       l = _mem_xread (stream, 0, data, len);
 
243
+       offset += l; data += l; len -= l; if (!len) return TRUE;
 
244
+
 
245
+       return FALSE;
 
246
+}
 
247
+
 
248
+static void
 
249
+_vte_mem_stream_swap_regions (VteMemStream *stream)
 
250
+{
 
251
+       struct mem_region temp;
 
252
+
 
253
+       temp = stream->page[0];
 
254
+       stream->page[0] = stream->page[1];
 
255
+       stream->page[1] = temp;
 
256
+}
 
257
+
 
258
+static void
 
259
+_vte_mem_stream_truncate (VteStream *astream, gsize offset)
 
260
+{
 
261
+       VteMemStream *stream = (VteMemStream *) astream;
 
262
+
 
263
+       if (G_UNLIKELY (offset < stream->offset[1])) {
 
264
+               _mem_xtruncate (stream, 1, 0);
 
265
+               stream->offset[1] = offset;
 
266
+       }
 
267
+
 
268
+       if (G_UNLIKELY (offset < stream->offset[0])) {
 
269
+               _mem_xtruncate (stream, 0, 0);
 
270
+               stream->offset[0] = stream->offset[1];
 
271
+               _vte_mem_stream_swap_regions (stream);
 
272
+       } else {
 
273
+               _mem_xtruncate (stream, 0, offset - stream->offset[0]);
 
274
+       }
 
275
+}
 
276
+
 
277
+static void
 
278
+_vte_mem_stream_new_page (VteStream *astream)
 
279
+{
 
280
+       VteMemStream *stream = (VteMemStream *) astream;
 
281
+
 
282
+       stream->offset[1] = stream->offset[0];
 
283
+       if (stream->page[0].region)
 
284
+               stream->offset[0] += _mem_xseek (stream, 0, 0, SEEK_END);
 
285
+       _vte_mem_stream_swap_regions (stream);
 
286
+       _mem_xtruncate (stream, 0, 0);
 
287
+}
 
288
+
 
289
+static gsize
 
290
+_vte_mem_stream_head (VteStream *astream)
 
291
+{
 
292
+       VteMemStream *stream = (VteMemStream *) astream;
 
293
+
 
294
+       if (stream->page[0].region)
 
295
+               return stream->offset[0] + _mem_xseek (stream, 0, 0, SEEK_END);
 
296
+       else
 
297
+               return stream->offset[0];
 
298
+}
 
299
+
 
300
+static gboolean
 
301
+_vte_mem_stream_write_contents (VteStream *astream, GOutputStream *output,
 
302
+                                gsize offset,
 
303
+                                GCancellable *cancellable, GError **error)
 
304
+{
 
305
+       VteMemStream *stream = (VteMemStream *) astream;
 
306
+
 
307
+       if (G_UNLIKELY (offset < stream->offset[1]))
 
308
+               return FALSE;
 
309
+
 
310
+       if (offset < stream->offset[0]) {
 
311
+               _mem_xseek (stream, 1, offset - stream->offset[1], SEEK_SET);
 
312
+               if (!_mem_xwrite_contents (stream, 1, output, cancellable, error))
 
313
+                       return FALSE;
 
314
+               offset = stream->offset[0];
 
315
+       }
 
316
+
 
317
+       _mem_xseek (stream, 0, offset - stream->offset[0], SEEK_SET);
 
318
+       return _mem_xwrite_contents (stream, 0, output, cancellable, error);
 
319
+}
 
320
+
 
321
+static void
 
322
+_vte_mem_stream_class_init (VteMemStreamClass *klass)
 
323
+{
 
324
+       GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
 
325
+
 
326
+       gobject_class->finalize = _vte_mem_stream_finalize;
 
327
+
 
328
+       klass->reset = _vte_mem_stream_reset;
 
329
+       klass->append = _vte_mem_stream_append;
 
330
+       klass->read = _vte_mem_stream_read;
 
331
+       klass->truncate = _vte_mem_stream_truncate;
 
332
+       klass->new_page = _vte_mem_stream_new_page;
 
333
+       klass->head = _vte_mem_stream_head;
 
334
+       klass->write_contents = _vte_mem_stream_write_contents;
 
335
+}
 
336
Index: vte-0.28.2/src/vtestream.h
 
337
===================================================================
 
338
--- vte-0.28.2.orig/src/vtestream.h     2012-03-07 10:23:14.998517196 -0800
 
339
+++ vte-0.28.2/src/vtestream.h  2012-03-07 10:23:52.055018606 -0800
 
340
@@ -43,6 +43,8 @@
 
341
 
 
342
 VteStream *
 
343
 _vte_file_stream_new (void);
 
344
+VteStream *
 
345
+_vte_mem_stream_new (void);
 
346
 
 
347
 G_END_DECLS
 
348
 
 
349
Index: vte-0.28.2/src/ring.c
 
350
===================================================================
 
351
--- vte-0.28.2.orig/src/ring.c  2012-03-07 11:17:05.896949593 -0800
 
352
+++ vte-0.28.2/src/ring.c       2012-03-07 14:42:35.626333589 -0800
 
353
@@ -49,6 +49,25 @@
 
354
 #define _vte_ring_validate(ring) G_STMT_START {} G_STMT_END
 
355
 #endif
 
356
 
 
357
+static void
 
358
+_vte_ring_ensure_stream (VteRing *ring)
 
359
+{
 
360
+       if (G_LIKELY(ring->attr_stream))
 
361
+               return;
 
362
+
 
363
+       if (ring->max >= G_MAXLONG) {
 
364
+               /* "Infinite" scroll-back buffer limit, file-backed. */
 
365
+               ring->attr_stream = _vte_file_stream_new ();
 
366
+               ring->text_stream = _vte_file_stream_new ();
 
367
+               ring->row_stream = _vte_file_stream_new ();
 
368
+       } else {
 
369
+               /* Predefined scroll-back buffer limit, memory-backed. */
 
370
+               ring->attr_stream = _vte_mem_stream_new ();
 
371
+               ring->text_stream = _vte_mem_stream_new ();
 
372
+               ring->row_stream = _vte_mem_stream_new ();
 
373
+       }
 
374
+}
 
375
+
 
376
 
 
377
 void
 
378
 _vte_ring_init (VteRing *ring, gulong max_rows)
 
379
@@ -62,10 +81,6 @@
 
380
        ring->mask = 31;
 
381
        ring->array = g_malloc0 (sizeof (ring->array[0]) * (ring->mask + 1));
 
382
 
 
383
-       ring->attr_stream = _vte_file_stream_new ();
 
384
-       ring->text_stream = _vte_file_stream_new ();
 
385
-       ring->row_stream = _vte_file_stream_new ();
 
386
-
 
387
        ring->last_attr.text_offset = 0;
 
388
        ring->last_attr.attr.i = basic_cell.i.attr;
 
389
        ring->utf8_buffer = g_string_sized_new (128);
 
390
@@ -81,6 +96,8 @@
 
391
 {
 
392
        gulong i;
 
393
 
 
394
+       _vte_ring_ensure_stream (ring);
 
395
+
 
396
        for (i = 0; i <= ring->mask; i++)
 
397
                _vte_row_data_fini (&ring->array[i]);
 
398
 
 
399
@@ -103,12 +120,14 @@
 
400
 static gboolean
 
401
 _vte_ring_read_row_record (VteRing *ring, VteRowRecord *record, gulong position)
 
402
 {
 
403
+       _vte_ring_ensure_stream (ring);
 
404
        return _vte_stream_read (ring->row_stream, position * sizeof (*record), (char *) record, sizeof (*record));
 
405
 }
 
406
 
 
407
 static void
 
408
 _vte_ring_append_row_record (VteRing *ring, const VteRowRecord *record, gulong position)
 
409
 {
 
410
+       _vte_ring_ensure_stream (ring);
 
411
        _vte_stream_append (ring->row_stream, (const char *) record, sizeof (*record));
 
412
 }
 
413
 
 
414
@@ -121,6 +140,7 @@
 
415
        int i;
 
416
 
 
417
        _vte_debug_print (VTE_DEBUG_RING, "Freezing row %lu.\n", position);
 
418
+       _vte_ring_ensure_stream (ring);
 
419
 
 
420
        record.text_offset = _vte_stream_head (ring->text_stream);
 
421
        record.attr_offset = _vte_stream_head (ring->attr_stream);
 
422
@@ -183,6 +203,7 @@
 
423
        GString *buffer = ring->utf8_buffer;
 
424
 
 
425
        _vte_debug_print (VTE_DEBUG_RING, "Thawing row %lu.\n", position);
 
426
+       _vte_ring_ensure_stream (ring);
 
427
 
 
428
        _vte_row_data_clear (row);
 
429
 
 
430
@@ -266,6 +287,7 @@
 
431
 _vte_ring_reset_streams (VteRing *ring, gulong position)
 
432
 {
 
433
        _vte_debug_print (VTE_DEBUG_RING, "Reseting streams to %lu.\n", position);
 
434
+       _vte_ring_ensure_stream (ring);
 
435
 
 
436
        _vte_stream_reset (ring->row_stream, position * sizeof (VteRowRecord));
 
437
        _vte_stream_reset (ring->text_stream, 0);
 
438
@@ -281,6 +303,7 @@
 
439
 _vte_ring_new_page (VteRing *ring)
 
440
 {
 
441
        _vte_debug_print (VTE_DEBUG_RING, "Starting new stream page at %lu.\n", ring->writable);
 
442
+       _vte_ring_ensure_stream (ring);
 
443
 
 
444
        _vte_stream_new_page (ring->attr_stream);
 
445
        _vte_stream_new_page (ring->text_stream);
 
446
@@ -608,6 +631,7 @@
 
447
        gulong i;
 
448
 
 
449
        _vte_debug_print(VTE_DEBUG_RING, "Writing contents to GOutputStream.\n");
 
450
+       _vte_ring_ensure_stream (ring);
 
451
 
 
452
        if (ring->start < ring->writable) {
 
453
                VteRowRecord record;
 
454
Index: vte-0.28.2/src/vtestream.c
 
455
===================================================================
 
456
--- vte-0.28.2.orig/src/vtestream.c     2012-03-07 11:41:24.427419860 -0800
 
457
+++ vte-0.28.2/src/vtestream.c  2012-03-07 12:55:14.227826250 -0800
 
458
@@ -31,3 +31,4 @@
 
459
 
 
460
 #include "vtestream-base.h"
 
461
 #include "vtestream-file.h"
 
462
+#include "vtestream-mem.h"
 
463
Index: vte-0.28.2/src/Makefile.am
 
464
===================================================================
 
465
--- vte-0.28.2.orig/src/Makefile.am     2012-03-07 12:55:40.912155853 -0800
 
466
+++ vte-0.28.2/src/Makefile.am  2012-03-07 12:55:49.460261440 -0800
 
467
@@ -80,6 +80,7 @@
 
468
        vtestream.h \
 
469
        vtestream-base.h \
 
470
        vtestream-file.h \
 
471
+       vtestream-mem.h \
 
472
        vtetc.c \
 
473
        vtetc.h \
 
474
        vtetree.c \