#include #include #include #include #include #include #include #include "x.h" #include "es.h" #include "ui.h" #include "shm.h" #include "prf.h" #include "vars.h" #include "decode.h" #include "output.h" #include "strlist.h" extern const char *__progname; static WORKER *workers; static WORKER decode; static WORKER output; static WORKER ui; static void strappend(char **strp, const char *str) { char *new; int oldl; int sl; if (! *strp) { *strp = malloc(1); **strp = '\0'; } oldl = strlen(*strp); sl = strlen(str); new = malloc(oldl+sl+1); bcopy(*strp,new,oldl); bcopy(str,new+oldl,sl); new[oldl+sl] = '\0'; free(*strp); *strp = new; } static void append_stuff(const char *s) { STRLIST *sl; sl = malloc(sizeof(STRLIST)); sl->str = strdup(s); if (stuff) *stufftail = sl; else stuff = sl; stufftail = &sl->link; } static void handleargs(int ac, char **av) { int skip; int errs; skip = 0; errs = 0; for (;ac;ac--,av++) { if (skip > 0) { skip --; continue; } if (**av != '-') { ifiles = realloc(ifiles,(nifiles+1)*sizeof(*ifiles)); ifiles[nifiles] = *av; nifiles ++; continue; } if (0) { needarg:; fprintf(stderr,"%s: %s needs a following argument\n",__progname,*av); errs ++; continue; } #define WANTARG() do { if (++skip >= ac) goto needarg; } while (0) if (!strcmp(*av,"-display")) { WANTARG(); displayname = av[skip]; continue; } if (!strcmp(*av,"-geometry")) { WANTARG(); geometryspec = av[skip]; continue; } if (!strcmp(*av,"-visual")) { WANTARG(); visualstr = av[skip]; continue; } if (!strcmp(*av,"-xrm")) { WANTARG(); strappend(&xrmstr,"\n"); strappend(&xrmstr,av[skip]); continue; } if (!strcmp(*av,"-rg") || !strcmp(*av,"-redgreen")) { stereo = STEREO_RED_GREEN; continue; } if (!strcmp(*av,"-gr") || !strcmp(*av,"-greenred")) { stereo = STEREO_GREEN_RED; continue; } if (!strcmp(*av,"-sync")) { synch = 1; continue; } if (!strcmp(*av,"-stuff")) { WANTARG(); append_stuff(av[skip]); continue; } if (!strcmp(*av,"-threads")) { WANTARG(); threads = atoi(av[skip]); continue; } #undef WANTARG fprintf(stderr,"%s: unrecognized option `%s'\n",__progname,*av); errs ++; } if (errs) exit(1); } static int wtest_worker(void *wv) { return(aio_oq_nonempty(&((WORKER *)wv)->oq)); } static void wr_worker(void *wv) { WORKER *w; int nw; w = wv; nw = aio_oq_writev(&w->oq,w->fd,-1); switch (nw) { case AIO_WRITEV_ERROR: switch (errno) { case EINTR: case EWOULDBLOCK: return; break; } fprintf(stderr,"%s: write error to %s worker: %s\n",__progname,w->tag,strerror(errno)); exit(1); break; } if (nw < 0) abort(); aio_oq_dropdata(&w->oq,nw); } static void rd_worker(void *wv) { WORKER *w; char rbuf[512]; int nr; int i; w = wv; nr = read(w->fd,&rbuf[0],sizeof(rbuf)); if (nr < 0) { switch (errno) { case EINTR: case EWOULDBLOCK: return; break; } fprintf(stderr,"%s: read error from %s worker: %s\n",__progname,w->tag,strerror(errno)); exit(1); } if (nr == 0) { if (dying) { dying --; aio_remove_poll(w->id); if (dying == 0) exit(0); return; } fprintf(stderr,"%s: read EOF from %s worker\n",__progname,w->tag); exit(1); } for (i=0;iin,rbuf[i]); } else { (*w->from)(es_ptr(&w->in),es_len(&w->in)); es_clear(&w->in); } } } static void fork_worker(WORKER *w, const char *tag, void (*mainfn)(WORKER *), void (*from)(const char *, int)) { int p[2]; pid_t kid; WORKER *t; w->tag = tag; w->from = from; es_init(&w->in); aio_oq_init(&w->oq); if (socketpair(AF_LOCAL,SOCK_STREAM,0,&p[0]) < 0) { fprintf(stderr,"%s: socketpair: %s\n",__progname,strerror(errno)); exit(1); } // so socket fds are visible in syscall traces write(-1,0,p[0]); write(-2,0,p[1]); kid = fork(); if (kid < 0) { fprintf(stderr,"%s: fork: %s\n",__progname,strerror(errno)); exit(1); } if (kid == 0) { for (t=workers;t;t=t->link) close(t->fd); close(p[0]); workerfd = p[1]; aio_poll_reinit(); (*mainfn)(w); _exit(1); } close(p[1]); w->fd = p[0]; w->kid = kid; w->link = workers; workers = w; w->id = aio_add_poll(w->fd,&aio_rwtest_always,&wtest_worker,&rd_worker,&wr_worker,w); } static void ui_quit(void) { aio_oq_queue_point(&decode.oq,"Q",2); aio_oq_queue_point(&output.oq,"Q",2); aio_oq_queue_point(&ui.oq,"Q",2); dying = 3; } static void from_decode(const char *s, int l) { if (l < 1) abort(); switch (s[0]) { case 'P': aio_oq_queue_point(&ui.oq,"P[decode] ",AIO_STRLEN); aio_oq_queue_copy(&ui.oq,s+1,l-1); aio_oq_queue_point(&ui.oq,"",1); break; default: abort(); break; } } static void from_output(const char *s, int l) { if (l < 1) abort(); switch (s[0]) { case 'P': aio_oq_queue_point(&ui.oq,"P[output] ",AIO_STRLEN); aio_oq_queue_copy(&ui.oq,s+1,l-1); aio_oq_queue_point(&ui.oq,"",1); break; default: abort(); break; } } static void from_ui(const char *s, int l) { if (l < 1) abort(); switch (s[0]) { case 'P': aio_oq_queue_copy(&ui.oq,s,l); aio_oq_queue_point(&ui.oq,"",1); break; case 'Q': ui_quit(); break; case 'p': aio_oq_queue_copy(&decode.oq,s,l); aio_oq_queue_point(&decode.oq,"",1); break; default: abort(); break; } } static void fork_workers(void) { workers = 0; fork_worker(&decode,"decode",&decode_main,&from_decode); fork_worker(&output,"output",&output_main,&from_output); fork_worker(&ui,"ui",&ui_main,&from_ui); } static void tell_ui_files(void) { int i; aio_oq_queue_printf(&ui.oq,"F#%d%c",nifiles,0); for (i=0;i