diff options
| author | Quentin Carbonneaux | 2014-09-04 15:10:11 -0400 |
|---|---|---|
| committer | Quentin Carbonneaux | 2014-09-04 15:10:11 -0400 |
| commit | 2ad2f1a599c16f8015f4af8a29f75c68c24c5574 (patch) | |
| tree | b6f0e9e34ff5508cb27eddc5ea33f0da2e9b9b48 | |
| parent | 9497069d9c767965118d1bb9bd6c5b3dc3f8ee38 (diff) | |
add proper buffer deletion
Because some background processes might run concurrently
with the execution of the Del command I added a refcount
to edit buffers.
Details about the refcount:
+ When this count c is >=0 it means that the buffer
is alive and has c+1 concurrent users (+1 for the
window displaying it).
+ If c<0, the buffer has -c users but is a "zombie".
Its parent window was deleted. So the buffer is still
in memory but cannot be used, users must drop their
pointer after having incremented c. If c reaches 0,
the buffer must be freed.
| -rw-r--r-- | edit.c | 28 | ||||
| -rw-r--r-- | edit.h | 4 | ||||
| -rw-r--r-- | exec.c | 31 | ||||
| -rw-r--r-- | win.c | 7 | ||||
| -rw-r--r-- | win.h | 2 |
5 files changed, 52 insertions, 20 deletions
@@ -190,9 +190,37 @@ eb_new() eb->redo = log_new(); eb->ml = 0; eb->path = 0; + eb->refs = 0; return eb; } +/* eb_kill - Free all the memory used by [eb]. If the + * refcount is non-zero, it switches its sign and does + * not free the memory used by [eb]. Otherwise, all + * the memory is freed. + */ +void +eb_kill(EBuf *eb) +{ + Mark *m; + + assert(eb->refs >= 0); + eb->refs = -eb->refs; + buf_clr(&eb->b); + log_clr(eb->undo); + log_clr(eb->redo); + while ((m=eb->ml)) { + eb->ml = m->next; + free(m); + } + free(eb->b.p); + free(eb->undo); + free(eb->redo); + free(eb->path); + if (eb->refs == 0) + free(eb); +} + /* eb_clr - Reset the buffer contents and marks and read * the new contents from the file descriptor [fd] if it is * different from -1. @@ -24,12 +24,14 @@ struct ebuf { char *path; /* file path */ time_t ftime; /* last mtime when written/read */ unsigned frev; /* last revision written */ + int refs; /* ref count, if <0 zombie buffer */ }; EBuf *eb_new(void); -void eb_del(EBuf *, unsigned, unsigned); +void eb_kill(EBuf *); void eb_clr(EBuf *, int); unsigned eb_revision(EBuf *); +void eb_del(EBuf *, unsigned, unsigned); void eb_ins(EBuf *, unsigned, Rune); int eb_ins_utf8(EBuf *, unsigned, unsigned char *, int); void eb_commit(EBuf *); @@ -335,7 +335,7 @@ new(W *w, EBuf *eb, unsigned p0) static int del(W *w, EBuf *eb, unsigned p0) { - w = win_delete(w); + w = win_kill(w); if (w) curwin = w; else @@ -363,13 +363,26 @@ runev(int fd, int flag, void *data) unsigned char buf[2048], *p; Rune r; - rn = data; /* XXX rn->eb can be invalid */ + rn = data; + n = rn->eb->refs; + if (n < 0) { + /* zombie buffer */ + rn->eb->refs++; +/* puts("tick"); */ + if (n == -1) +/* puts("tock!"), */ + free(rn->eb); + rn->eb = 0; + close(fd); + goto Reset; + } if (flag & ERead) { assert(rn->eb); memcpy(buf, rn->in, rn->nin); n = read(fd, &buf[rn->nin], sizeof buf - rn->nin); if (n <= 0) { close(fd); + rn->eb->refs--; rn->eb = 0; goto Reset; } @@ -413,19 +426,6 @@ run(W *w, EBuf *eb, unsigned p0) int pin[2], pout[2]; Run *r; - /* *** - clear (and possibly delete) selection, - get the "insertion" position and set a mark for it in the - edit buffer (Acme does not do this, it just stores an offset) - - what happens when eb is deleted/changed - during the command execution? - + refcount ebs and make eb_free free the - data and have eb contain simply the refcount - + when a dummy eb is detected in the callback, - just abort the IO operation - *** */ - eol = buf_eol(&eb->b, p0); p1 = 1 + skipb(&eb->b, eol-1, -1); if (p1 == p0) @@ -487,6 +487,7 @@ run(W *w, EBuf *eb, unsigned p0) default: abort(); } + r->eb->refs++; if (ctyp != 0) if (s0 != s1) { eb_setmark(w->eb, SelBeg, -1u); /* clear selection */ @@ -94,13 +94,13 @@ win_new(EBuf *eb) return w1; } -/* win_delete - Delete a window created by win_new. +/* win_kill - Delete a window created by win_new. * An adjacent window is returned. */ W * -win_delete(W *w) +win_kill(W *w) { - W *w1, *sw; + W *w1, **sw; int rx; if (!screen[1]) @@ -115,6 +115,7 @@ win_delete(W *w) rx = w1->rectx; } move(w1, rx, 0, w->rectw+g->border+w1->rectw, fheight); + eb_kill(w->eb); memset(w, 0, sizeof(W)); w->eb = 0; memmove(sw, sw+1, (MaxWins-(sw-screen))*sizeof(W*)); @@ -33,7 +33,7 @@ enum CursorLoc { CTop, CMid, CBot }; void win_init(struct gui *g); W *win_new(EBuf *eb); -W *win_delete(W *); +W *win_kill(W *); unsigned win_at(W *w, int x, int y); W *win_which(int x, int y); void win_move(W *, int x, int y); |
