/* * This file is part of the UCB release of Plan 9. It is subject to the license * terms in the LICENSE file found in the top-level directory of this * distribution and at http://akaros.cs.berkeley.edu/files/Plan9License. No * part of the UCB release of Plan 9, including this file, may be copied, * modified, propagated, or distributed except according to the terms contained * in the LICENSE file. */ #include #include #include #include #include "plumb.h" typedef struct EQueue EQueue; struct EQueue { int id; char *buf; int nbuf; EQueue *next; }; static EQueue *equeue; static Lock eqlock; static int partial(int id, Event *e, uint8_t *b, int n) { EQueue *eq, *p; int nmore; jehanne_lock(&eqlock); for(eq = equeue; eq != nil; eq = eq->next) if(eq->id == id) break; jehanne_unlock(&eqlock); if(eq == nil) return 0; /* partial message exists for this id */ eq->buf = realloc(eq->buf, eq->nbuf+n); if(eq->buf == nil) drawerror(display, "eplumb: cannot allocate buffer"); memmove(eq->buf+eq->nbuf, b, n); eq->nbuf += n; e->v = plumbunpackpartial((char*)eq->buf, eq->nbuf, &nmore); if(nmore == 0){ /* no more to read in this message */ jehanne_lock(&eqlock); if(eq == equeue) equeue = eq->next; else{ for(p = equeue; p!=nil && p->next!=eq; p = p->next) ; if(p == nil) drawerror(display, "eplumb: bad event queue"); p->next = eq->next; } jehanne_unlock(&eqlock); free(eq->buf); free(eq); } return 1; } static void addpartial(int id, char *b, int n) { EQueue *eq; eq = malloc(sizeof(EQueue)); if(eq == nil) return; eq->id = id; eq->nbuf = n; eq->buf = malloc(n); if(eq->buf == nil){ free(eq); return; } memmove(eq->buf, b, n); jehanne_lock(&eqlock); eq->next = equeue; equeue = eq; jehanne_unlock(&eqlock); } static int plumbevent(int id, Event *e, uint8_t *b, int n) { int nmore; if(partial(id, e, b, n) == 0){ /* no partial message already waiting for this id */ e->v = plumbunpackpartial((char*)b, n, &nmore); if(nmore > 0) /* incomplete message */ addpartial(id, (char*)b, n); } if(e->v == nil) return 0; return id; } int eplumb(int key, char *port) { int fd; fd = plumbopen(port, OREAD|OCEXEC); if(fd < 0) return -1; return estartfn(key, fd, 8192, plumbevent); }