]> git.mdlowis.com Git - projs/tide.git/commitdiff
Fixed some bugs in the asynchronous command handling logic
authorMichael D. Lowis <mike.lowis@gentex.com>
Fri, 14 Jul 2017 16:00:33 +0000 (12:00 -0400)
committerMichael D. Lowis <mike.lowis@gentex.com>
Fri, 14 Jul 2017 16:00:33 +0000 (12:00 -0400)
TODO.md
lib/buf.c
lib/event.c
lib/exec.c
lib/win.c

diff --git a/TODO.md b/TODO.md
index b4be0d7729968b036bb23b213f7a2cd23cf2226c..b5c6e91e6eb9ed365e1fcb09db12ee81c505b62b 100644 (file)
--- a/TODO.md
+++ b/TODO.md
@@ -46,6 +46,7 @@ Possible Shortcuts:
 
 Maybe think about addressing these later:
 
+* switch buf.c to using a mmap buffer of utf-8/binary data
 * add current dir to path
 * add support for guidefiles
 * Shift+Insert should insert primary selection
index 782b696c8b85ca12cac7d0a4e29f082b733d6b6c..5c8bfb31e61e3d8061ecf5ad564d9869297ac4d0 100644 (file)
--- a/lib/buf.c
+++ b/lib/buf.c
@@ -200,9 +200,12 @@ size_t buf_change(Buf* buf, size_t beg, size_t end) {
 void buf_chomp(Buf* buf) {
     size_t end = buf_end(buf);
     if (!end) return;
-    delete(buf, end-1);
-    if (buf->undo->insert && buf->undo->data.ins.end == end)
-        buf->undo->data.ins.end--;
+    Rune r = buf_get(buf, end-1);
+    if (r == RUNE_CRLF || r == '\n') {
+        delete(buf, end-1);
+        if (buf->undo->insert && buf->undo->data.ins.end == end)
+            buf->undo->data.ins.end--;
+    }
 }
 
 void buf_undo(Buf* buf, Sel* sel) {
index ad6d8e79100d8cf1fe968f106fbeb1ee0b28893b..284f3ae496917f4f2c2a1f9f5055c423bd5e889f 100644 (file)
@@ -35,14 +35,15 @@ bool event_poll(int ms) {
         /* if the desriptor is done or errored, throw it out */
         if (Descriptors[i].revents & (POLLNVAL|POLLERR|POLLHUP)) {
             close(Descriptors[i].fd);
-            Descriptors[i].fd = -1;
+            Descriptors[i].fd = -Descriptors[i].fd;
+            EventData[i].fn(Descriptors[i].fd, EventData[i].data);
         }
     }
 
     /* remove any closed or invalid descriptors */
     size_t nfds = 0;
     for (int i = 0; i < NumDescriptors; i++) {
-        if (Descriptors[i].fd != -1) {
+        if (Descriptors[i].fd >= 0) {
             Descriptors[nfds] = Descriptors[i];
             EventData[nfds++] = EventData[i];
         }
index ef4264db9bf8debebb024b5202df952e0cf933a6..c264ea4db5515b4abd13008d03ffc642708627ff 100644 (file)
@@ -19,6 +19,7 @@ typedef struct {
 typedef struct Job Job;
 
 typedef struct {
+    Job* job;     /* pointer to the job teh receiver belongs to */
     View* view;   /* destination view */
     size_t beg;   /* start of output */
     size_t count; /* number of bytes written */
@@ -27,7 +28,7 @@ typedef struct {
 struct Job {
     Job* next;     /* Pointer to previous job in the job list */
     Job* prev;     /* Pointer to next job in the job list */
-    int pid;       /* process id of the running job */
+    Proc proc;     /* Process id and descriptors */
     size_t ndata;  /* number of bytes to write to stdout */
     size_t nwrite; /* number of bytes written to stdout so far */
     char* data;    /* data to write to stdout */
@@ -38,43 +39,41 @@ struct Job {
 
 static Job* JobList = NULL;
 
+static void job_closefd(Job* job, int fd);
+static bool job_done(Job* job);
+static Job* job_finish(Job* job);
 static void send_data(int fd, void* data);
 static void recv_data(int fd, void* data);
-static void watch_or_close(bool valid, int dir, int fd, void* data);
+static int watch_or_close(bool valid, int dir, int fd, void* data);
 static void rcvr_finish(Rcvr* rcvr);
 static int execute(char** cmd, Proc* proc);
 
 bool exec_reap(void) {
-    int pid;
-    while ((pid = waitpid(-1, NULL, WNOHANG)) > 0) {
-        Job* job = JobList;
-        for (; job && job->pid != pid; job = job->next);
-        if (job && job->pid == pid) {
+    Job* job = JobList;
+    while (job) {
+        if (job_done(job)) {
             rcvr_finish(&(job->out_rcvr));
             rcvr_finish(&(job->err_rcvr));
-            if (job->prev) {
-                job->prev->next = job->next;
-                job->next->prev = job->prev;
-            } else {
-                for (; job && job->prev; job = job->prev);
-                JobList = (JobList == job ? NULL : job);
-            }
-            free(job);
+            job = job_finish(job);
+        } else {
+            job = job->next;
         }
     }
+    while (waitpid(-1, NULL, WNOHANG) > 0);
     return (JobList != NULL);
 }
 
 void exec_job(char** cmd, char* data, size_t ndata, View* dest) {
-    Proc proc;
     Job* job = calloc(1, sizeof(Job));
-    job->pid = execute(cmd, &proc);
-    if (job->pid < 0) {
+    job->proc.pid = execute(cmd, &(job->proc));
+    if (job->proc.pid < 0) {
         die("job_start() :");
     } else {
         /* add the job to the job list */
         job->err_rcvr.view = win_view(TAGS);
+        job->err_rcvr.job = job;
         job->out_rcvr.view = dest;
+        job->out_rcvr.job = job;
         job->ndata  = ndata;
         job->nwrite = 0;
         job->data   = data;
@@ -85,9 +84,9 @@ void exec_job(char** cmd, char* data, size_t ndata, View* dest) {
         bool need_in  = (job->data != NULL),
              need_out = (dest != NULL),
              need_err = (need_in || need_out);
-        watch_or_close(need_in,  OUTPUT, proc.in,  job);
-        watch_or_close(need_out, INPUT,  proc.out, &(job->out_rcvr));
-        watch_or_close(need_err, INPUT,  proc.err, &(job->err_rcvr));
+        job->proc.in  = watch_or_close(need_in,  OUTPUT, job->proc.in,  job);
+        job->proc.out = watch_or_close(need_out, INPUT,  job->proc.out, &(job->out_rcvr));
+        job->proc.err = watch_or_close(need_err, INPUT,  job->proc.err, &(job->err_rcvr));
     }
 }
 
@@ -124,50 +123,87 @@ int exec_spawn(char** cmd, int* in, int* out) {
     return proc.pid;
 }
 
+static void job_closefd(Job* job, int fd) {
+    if (fd >= 0) close(fd), fd = -fd;
+    if (job->proc.in  == -fd) job->proc.in  = fd;
+    if (job->proc.out == -fd) job->proc.out = fd;
+    if (job->proc.err == -fd) job->proc.err = fd;
+}
+
+static bool job_done(Job* job) {
+    return ((job->proc.in < 0) && (job->proc.out < 0) && (job->proc.err < 0));
+}
+
+static Job* job_finish(Job* job) {
+    Job* next = job->next;
+    if (job->prev) {
+        job->prev->next = job->next;
+        job->next->prev = job->prev;
+    } else {
+        JobList = job->next;
+    }
+    free(job->data);
+    free(job);
+    return next;
+}
+
 static void send_data(int fd, void* data) {
     Job* job = data;
-    long nwrite = write(fd, (job->data + job->nwrite), job->ndata);
-    if (nwrite < 0) { free(job->data); close(fd); return; }
-    job->ndata  -= nwrite;
-    job->nwrite += nwrite;
-    if (job->ndata <= 0) { free(job->data); close(fd); return; }
+    if (fd >= 0) {
+        long nwrite = write(fd, (job->data + job->nwrite), job->ndata);
+        if (nwrite >= 0) {
+            job->ndata  -= nwrite;
+            job->nwrite += nwrite;
+        }
+        if  (nwrite < 0 || job->ndata <= 0)
+            job_closefd(job, fd);
+    } else {
+        job_closefd(job, fd);
+    }
 }
 
 static void recv_data(int fd, void* data) {
     static char buffer[4096];
-    long i = 0, nread = read(fd, buffer, sizeof(buffer));
     Rcvr* rcvr = data;
+    Job* job = rcvr->job;
     View* view = rcvr->view;
     Buf* buf = &(rcvr->view->buffer);
     Sel sel = view->selection;
-    if (nread > 0) {
-        if (!rcvr->count) {
-            if (sel.end < sel.beg) {
-                size_t temp = sel.beg;
-                sel.beg = sel.end, sel.end = temp;
+
+    if (fd >= 0) {
+        long i = 0, nread = read(fd, buffer, sizeof(buffer));
+        if (nread > 0) {
+            if (!rcvr->count) {
+                if (sel.end < sel.beg) {
+                    size_t temp = sel.beg;
+                    sel.beg = sel.end, sel.end = temp;
+                }
+                rcvr->beg = sel.beg = sel.end = buf_change(buf, sel.beg, sel.end);
+                view->selection = sel;
             }
-            rcvr->beg = sel.beg = sel.end = buf_change(buf, sel.beg, sel.end);
-            view->selection = sel;
-            buf_loglock(buf);
-        }
-        for (; i < nread;) {
-            Rune r;
-            size_t len = 0;
-            while (!utf8decode(&r, &len, buffer[i++]));
-            view_insert(rcvr->view, false, r);
-            rcvr->count++;
+            for (; i < nread;) {
+                Rune r;
+                size_t len = 0;
+                while (!utf8decode(&r, &len, buffer[i++]));
+                view_insert(rcvr->view, false, r);
+                rcvr->count++;
+            }
+        } else {
+            close(fd);
+            job_closefd(job, -fd);
         }
     } else {
-        close(fd);
+        job_closefd(job, fd);
     }
 }
 
-static void watch_or_close(bool valid, int dir, int fd, void* data) {
+static int watch_or_close(bool valid, int dir, int fd, void* data) {
     event_cbfn_t fn = (dir == OUTPUT ? send_data : recv_data);
     if (valid)
         event_watchfd(fd, dir, fn, data);
     else
-        close(fd);
+        close(fd), fd = -fd;
+    return fd;
 }
 
 static void rcvr_finish(Rcvr* rcvr) {
index 73dd3997e76d4059a2549f998ada2204afd0359e..df1a6d6b9068dec0b1126b60089eb4756785d3d9 100644 (file)
--- a/lib/win.c
+++ b/lib/win.c
@@ -73,6 +73,7 @@ void win_loop(void) {
     event_watchfd(x11_connfd(), INPUT, win_update, NULL);
     while (x11_running()) {
         bool pending = event_poll(ms);
+        exec_reap();
         int nevents  = x11_events_queued();
         if (update_focus() || pending || nevents) {
             x11_events_take();
@@ -80,7 +81,6 @@ void win_loop(void) {
                 x11_flip();
         }
         x11_flush();
-        exec_reap();
     }
     x11_finish();
 }