static void execproc(void *a) { int i, fd; Client *c; char tmp[32]; c = a; snprint(tmp, sizeof tmp, "execproc%d", c->num); threadsetname(tmp); if(pipe(c->fd) < 0){ rerrstr(c->err, sizeof c->err); sendul(c->execpid, -1); return; } rfork(RFFDG); fd = c->fd[1]; close(c->fd[0]); dup(fd, 0); dup(fd, 1); for(i=3; i<100; i++) /* should do better */ close(i); strcpy(c->err, "exec failed"); procexecl(c->execpid, "/bin/rc", "rc", "-c", c->cmd, nil); }
static int wait4data(Serialport *p, uchar *data, int count) { int d; Serial *ser; ser = p->s; qunlock(ser); d = sendul(p->w4data, 1); qlock(ser); if(d <= 0) return -1; if(p->ndata >= count) p->ndata -= count; else { count = p->ndata; p->ndata = 0; } memmove(data, p->data, count); if(p->ndata != 0) memmove(p->data, p->data+count, p->ndata); recvul(p->gotdata); return count; }
static void icachewriteproc(void *v) { int ret; uint bsize; ISect *is; Index *ix; u8int *buf; ix = mainindex; is = v; threadsetname("icachewriteproc:%s", is->part->name); bsize = 1<<is->blocklog; buf = emalloc(Bufsize+bsize); buf = (u8int*)(((uintptr)buf+bsize-1)&~(uintptr)(bsize-1)); for(;;){ trace(TraceProc, "icachewriteproc recv"); recv(is->writechan, 0); trace(TraceWork, "start"); ret = icachewritesect(ix, is, buf); trace(TraceProc, "icachewriteproc send"); trace(TraceWork, "finish"); sendul(is->writedonechan, ret); } }
static void writeproc(void *v) { Channel *sync; void **a; char *s; long np; int fd, i, n; threadsetname("writeproc"); a = v; sync = a[0]; fd = (uintptr)a[1]; s = a[2]; np =(uintptr)a[3]; free(a); for(i=0; i<np; i+=n){ n = np-i; if(n > BUFSIZE) n = BUFSIZE; if(write(fd, s+i, n) != n) break; } close(fd); sendul(sync, i); }
void winshell(void *args) { print_func_entry(); Window *w; Channel *pidc; void **arg; char *cmd, *dir; char **argv; arg = args; w = arg[0]; pidc = arg[1]; cmd = arg[2]; argv = arg[3]; dir = arg[4]; rfork(RFNAMEG|RFFDG|RFENVG); if(filsysmount(filsys, w->id) < 0){ fprint(2, "mount failed: %r\n"); sendul(pidc, 0); threadexits("mount failed"); } close(0); if(open("/dev/cons", OREAD) < 0){ fprint(2, "can't open /dev/cons: %r\n"); sendul(pidc, 0); threadexits("/dev/cons"); } close(1); if(open("/dev/cons", OWRITE) < 0){ fprint(2, "can't open /dev/cons: %r\n"); sendul(pidc, 0); threadexits("open"); /* BUG? was terminate() */ } if(wclose(w) == 0){ /* remove extra ref hanging from creation */ notify(nil); dup(1, 2); if(dir) chdir(dir); procexec(pidc, cmd, argv); _exits("exec failed"); } print_func_exit(); }
void clockproc(void *arg) { int t; Channel *c; c = arg; for(t=0;; t++){ sleep(1000); sendul(c, t); } }
int sendstr(int sock,char *s) { size_t len = s ? strlen(s) : 0; DLOG_MSG(("sendstr() : sendul(%d,%lu)",sock,(unsigned long)len)); if (!sendul(sock,(unsigned long)len)) return 0; if (len > 0) { DLOG_MSG(("sendstr() : x_send(%d,%s)",sock,s)); if (!x_send(sock,s,len)) { DLOG_ERROR(("sendstr()")); return 0; } } return 1; }
static void bloomwriteproc(void *v) { int ret; Bloom *b; threadsetname("bloomwriteproc"); b = v; for(;;){ recv(b->writechan, 0); if((ret=writebloom(b)) < 0) fprint(2, "oops! writing bloom: %r\n"); else ret = 0; sendul(b->writedonechan, ret); } }
static void statusreader(void *u) { Areader *a; Channel *c; Packser *pk; Serialport *p; Serial *ser; int cl; p = u; ser = p->s; threadsetname("statusreader thread"); /* big buffering, fewer bytes lost */ c = chancreate(sizeof(Packser *), 128); a = emallocz(sizeof(Areader), 1); a->p = p; a->c = c; incref(ser->dev); proccreate(epreader, a, 16*1024); while((pk = recvp(c)) != nil){ memmove(p->data, pk->b, pk->nb); p->ndata = pk->nb; free(pk); dsprint(2, "serial %p: status reader %d \n", p, p->ndata); /* consume it all */ while(p->ndata != 0){ dsprint(2, "serial %p: status reader to consume: %d\n", p, p->ndata); cl = recvul(p->w4data); if(cl < 0) break; cl = sendul(p->gotdata, 1); if(cl < 0) break; } } shutdownchan(c); devctl(ser->dev, "detach"); closedev(ser->dev); usbfsdel(&p->fs); }
/* We can't use procexec to execute drivers, because * procexec mounts #| at /mnt/temp and we do *not* * have /mnt/temp at boot time. * Instead, we use access to guess if we can execute the file. * and reply as procexec. Be careful that the child inherits * all the shared state of the thread library. It should run unnoticed. */ static void xexec(Channel *c, char *nm, char *args[]) { int pid; if(access(nm, AEXEC) == 0){ pid = rfork(RFFDG|RFREND|RFPROC); switch(pid){ case 0: exec(nm, args); _exits("exec"); case -1: break; default: sendul(c, pid); threadexits(nil); } } }
void execproc(void *v) { struct Exec *e; int p[2], q[2]; char *prog; char *argv[NARGS+1], args[NARGCHAR]; e = v; p[0] = e->p[0]; p[1] = e->p[1]; q[0] = e->q[0]; q[1] = e->q[1]; prog = e->prog; /* known not to be malloc'ed */ rfork(RFFDG); sendul(e->sync, 1); buildargv(e->argv, argv, args); free(e->argv); chanfree(e->sync); free(e); dup(p[0], 0); close(p[0]); close(p[1]); if(q[0]){ dup(q[1], 1); close(q[0]); close(q[1]); } procexec(nil, prog, argv); //fprint(2, "exec: %s", e->prog); //{int i; //for(i=0; argv[i]; i++) print(" '%s'", argv[i]); //print("\n"); //} //argv[0] = "cat"; //argv[1] = nil; //procexec(nil, "/bin/cat", argv); fprint(2, "Mail: can't exec %s: %r\n", prog); threadexits("can't exec"); }
void execproc(void *v) { struct Exec *e; int p[2], q[2]; char *prog; char *argv[NARGS+1], args[NARGCHAR]; int fd[3]; e = v; p[0] = e->p[0]; p[1] = e->p[1]; q[0] = e->q[0]; q[1] = e->q[1]; prog = e->prog; /* known not to be malloc'ed */ fd[0] = dup(p[0], -1); if(q[0]) fd[1] = dup(q[1], -1); else fd[1] = dup(1, -1); fd[2] = dup(2, -2); sendul(e->sync, 1); buildargv(e->argv, argv, args); free(e->argv); chanfree(e->sync); free(e); threadexec(nil, fd, prog, argv); close(fd[0]); close(fd[1]); close(fd[2]); fprint(2, "Mail: can't exec %s: %r\n", prog); threadexits("can't exec"); }
void procexec(Channel *pidc, char *prog, char *args[]) { int n; Proc *p; Thread *t; _threaddebug(DBGEXEC, "procexec %s", prog); /* must be only thread in proc */ p = _threadgetproc(); t = p->thread; if(p->threads.head != t || p->threads.head->nextt != nil){ werrstr("not only thread in proc"); Bad: if(pidc) sendul(pidc, ~0); return; } /* * We want procexec to behave like exec; if exec succeeds, * never return, and if it fails, return with errstr set. * Unfortunately, the exec happens in another proc since * we have to wait for the exec'ed process to finish. * To provide the semantics, we open a pipe with the * write end close-on-exec and hand it to the proc that * is doing the exec. If the exec succeeds, the pipe will * close so that our read below fails. If the exec fails, * then the proc doing the exec sends the errstr down the * pipe to us. */ if(bind("#|", PIPEMNT, MREPL) < 0) goto Bad; if((p->exec.fd[0] = open(PIPEMNT "/data", OREAD)) < 0){ unmount(nil, PIPEMNT); goto Bad; } if((p->exec.fd[1] = open(PIPEMNT "/data1", OWRITE|OCEXEC)) < 0){ close(p->exec.fd[0]); unmount(nil, PIPEMNT); goto Bad; } unmount(nil, PIPEMNT); /* exec in parallel via the scheduler */ assert(p->needexec==0); p->exec.prog = prog; p->exec.args = args; p->needexec = 1; _sched(); close(p->exec.fd[1]); if((n = read(p->exec.fd[0], p->exitstr, ERRMAX-1)) > 0){ /* exec failed */ p->exitstr[n] = '\0'; errstr(p->exitstr, ERRMAX); close(p->exec.fd[0]); goto Bad; } close(p->exec.fd[0]); if(pidc) sendul(pidc, t->ret); /* wait for exec'ed program, then exit */ _schedexecwait(); }
static void startdevproc(void *a) { Sarg *sa = a; Dev *d; Devtab *dt; int argc; char *args, *argse, **argv; char *fname; threadsetgrp(threadid()); d = sa->pp->dev; dt = sa->dt; args = sa->args; argse = sa->args + sizeof sa->args; argv = sa->argv; fname = sa->fname; sa->pp->devmaskp = &dt->devmask; sa->pp->devnb = getdevnb(&dt->devmask); if(sa->pp->devnb < 0){ sa->pp->devmaskp = nil; sa->pp->devnb = 0; }else args = seprint(args, argse, "-N %d", sa->pp->devnb); if(dt->args != nil) seprint(args, argse, " %s", dt->args); args = sa->args; dprint(2, "%s: start: %s %s\n", argv0, dt->name, args); argv[0] = dt->name; argc = 1; if(args[0] != 0) argc += tokenize(args, argv+1, nelem(sa->argv)-2); argv[argc] = nil; if(dt->init == nil){ if(d->dfd > 0 ){ close(d->dfd); d->dfd = -1; } rfork(RFCFDG); open("/dev/null", OREAD); open("/dev/cons", OWRITE); open("/dev/cons", OWRITE); xexec(sa->rc, argv[0], argv); snprint(fname, sizeof(sa->fname), "/bin/usb/%s", dt->name); xexec(sa->rc, fname, argv); snprint(fname, sizeof(sa->fname), "/boot/%s", dt->name); xexec(sa->rc, fname, argv); if(cputype == nil) cputype = getenv("cputype"); if(cputype != nil){ snprint(fname, sizeof(sa->fname), "/%s/bin/%s", cputype, dt->name); argv[0] = fname; xexec(sa->rc, fname, argv); } fprint(2, "%s: %s: not found. can't exec\n", argv0, dt->name); sendul(sa->rc, -1); threadexits("exec"); }else{ sa->pp->dev = opendev(d->dir); sendul(sa->rc, 0); if(dt->init(d, argc, argv) < 0) fprint(2, "%s: %s: %r\n", argv0, dt->name); closedev(d); free(sa); } threadexits(nil); }
void waitthread(void *v) { Waitmsg *w; Command *c, *lc; uint pid; int found, ncmd; Rune *cmd; char *err; Text *t; Pid *pids, *p, *lastp; enum { WErr, WKill, WWait, WCmd, NWALT }; Alt alts[NWALT+1]; USED(v); threadsetname("waitthread"); pids = nil; alts[WErr].c = cerr; alts[WErr].v = &err; alts[WErr].op = CHANRCV; alts[WKill].c = ckill; alts[WKill].v = &cmd; alts[WKill].op = CHANRCV; alts[WWait].c = cwait; alts[WWait].v = &w; alts[WWait].op = CHANRCV; alts[WCmd].c = ccommand; alts[WCmd].v = &c; alts[WCmd].op = CHANRCV; alts[NWALT].op = CHANEND; command = nil; for(;;){ switch(alt(alts)){ case WErr: qlock(&row.lk); warning(nil, "%s", err); free(err); flushimage(display, 1); qunlock(&row.lk); break; case WKill: found = FALSE; ncmd = runestrlen(cmd); for(c=command; c; c=c->next){ /* -1 for blank */ if(runeeq(c->name, c->nname-1, cmd, ncmd) == TRUE){ if(postnote(PNGROUP, c->pid, "kill") < 0) warning(nil, "kill %S: %r\n", cmd); found = TRUE; } } if(!found) warning(nil, "Kill: no process %S\n", cmd); free(cmd); break; case WWait: pid = w->pid; lc = nil; for(c=command; c; c=c->next){ if(c->pid == pid){ if(lc) lc->next = c->next; else command = c->next; break; } lc = c; } qlock(&row.lk); t = &row.tag; textcommit(t, TRUE); if(c == nil){ /* helper processes use this exit status */ if(strncmp(w->msg, "libthread", 9) != 0){ p = emalloc(sizeof(Pid)); p->pid = pid; strncpy(p->msg, w->msg, sizeof(p->msg)); p->next = pids; pids = p; } }else{ if(search(t, c->name, c->nname)){ textdelete(t, t->q0, t->q1, TRUE); textsetselect(t, 0, 0); } if(w->msg[0]) warning(c->md, "%.*S: exit %s\n", c->nname-1, c->name, w->msg); flushimage(display, 1); } qunlock(&row.lk); free(w); Freecmd: if(c){ if(c->iseditcmd) sendul(cedit, 0); free(c->text); free(c->name); fsysdelid(c->md); free(c); } break; case WCmd: /* has this command already exited? */ lastp = nil; for(p=pids; p!=nil; p=p->next){ if(p->pid == c->pid){ if(p->msg[0]) warning(c->md, "%s\n", p->msg); if(lastp == nil) pids = p->next; else lastp->next = p->next; free(p); goto Freecmd; } lastp = p; } c->next = command; command = c; qlock(&row.lk); t = &row.tag; textcommit(t, TRUE); textinsert(t, 0, c->name, c->nname, TRUE); textsetselect(t, 0, 0); flushimage(display, 1); qunlock(&row.lk); break; } } }