Blob
- Date:
- Message:
- libthread: add threadmaybackground Programs that want to background themselves now need to define threadmaybackground returning 1. This avoids a confusing (to people and debuggers) extra parent process for all the threaded programs that will never want to background themselves.
- Actions:
- History | Blame | Raw File
1 #include <u.h>2 #include <libc.h>3 #include <regexp.h>4 #include <thread.h>5 #include <fcall.h>7 int debug;8 int dfd;9 int srvfd;10 int netfd[2];11 int srv_to_net[2];12 int net_to_srv[2];13 char *srv;14 char *addr;15 char *ns;16 int export;18 void shuffle(void *arg);19 int post(char *srv);20 void remoteside(void*);21 int call(char *rsys, char *ns, char *srv);22 void* emalloc(int size);23 void localside(void*);25 char *REXEXEC = "ssh";26 char *prog = "import";28 enum29 {30 Stack= 32*102431 };33 void34 usage(void)35 {36 fprint(2, "usage: %s [-df] [-s service] [-n remote-ns] [-p remote-prog] remote-system\n", argv0);37 threadexitsall("usage");38 }40 void41 fatal(char *fmt, ...)42 {43 char buf[256];44 va_list arg;46 va_start(arg, fmt);47 vseprint(buf, buf+sizeof buf, fmt, arg);48 va_end(arg);50 fprint(2, "%s: %s\n", argv0 ? argv0 : "<prog>", buf);51 threadexitsall("fatal");52 }54 int55 threadmaybackground(void)56 {57 return 1;58 }60 void61 threadmain(int argc, char *argv[])62 {63 int dofork;64 int rem;65 void (*fn)(void*);67 dofork = 1;68 rem = 0;69 ns = nil;70 srv = "plumb";72 ARGBEGIN{73 case 'd':74 debug = 1;75 break;76 case 'f':77 dofork = 0;78 break;79 case 'n': /* name of remote namespace */80 ns = EARGF(usage());81 break;82 case 'p':83 prog = EARGF(usage());84 break;85 case 's': /* name of service */86 srv = EARGF(usage());87 break;88 case 'R':89 rem = 1;90 break;91 case 'x':92 export = 1;93 break;94 }ARGEND96 if(debug){97 char *dbgfile;99 if(rem)100 dbgfile = smprint("/tmp/%s.export.debug", getuser());101 else102 dbgfile = smprint("/tmp/%s.import.debug", getuser());103 dfd = create(dbgfile, OWRITE, 0664);104 free(dbgfile);105 fmtinstall('F', fcallfmt);106 }109 if(rem){110 netfd[0] = 0;111 netfd[1] = 1;112 write(1, "OK", 2);113 }else{114 if(argc != 1)115 usage();116 addr = argv[0];117 /* connect to remote service */118 netfd[0] = netfd[1] = call(addr, ns, srv);119 }121 fn = localside;122 if(rem+export == 1)123 fn = remoteside;125 if(rem || !dofork)126 fn(nil);127 else128 proccreate(fn, nil, Stack);129 }132 void133 localside(void *arg)134 {135 USED(arg);137 /* start a loal service */138 srvfd = post(srv);140 /* threads to shuffle messages each way */141 srv_to_net[0] = srvfd;142 srv_to_net[1] = netfd[1];143 proccreate(shuffle, srv_to_net, Stack);144 net_to_srv[0] = netfd[0];145 net_to_srv[1] = srvfd;146 shuffle(net_to_srv);147 }149 /* post a local service */150 int151 post(char *srv)152 {153 int p[2];155 if(pipe(p) < 0)156 fatal("can't create pipe: %r");158 /* 0 will be server end, 1 will be client end */159 if(post9pservice(p[1], srv, nil) < 0)160 fatal("post9pservice plumb: %r");161 close(p[1]);163 return p[0];164 }166 /* start a stub on the remote server */167 int168 call(char *rsys, char *ns, char *srv)169 {170 int p[2];171 int ac;172 char *av[12];173 char buf[2];175 if(pipe(p) < 0)176 fatal("can't create pipe: %r");177 ac = 0;178 av[ac++] = REXEXEC;179 av[ac++] = rsys;180 av[ac++] = prog;181 if(debug)182 av[ac++] = "-d";183 av[ac++] = "-R";184 if(ns != nil){185 av[ac++] = "-n";186 av[ac++] = ns;187 }188 av[ac++] = "-s";189 av[ac++] = srv;190 if(export)191 av[ac++] = "-x";192 av[ac] = 0;194 if(debug){195 fprint(dfd, "execing ");196 for(ac = 0; av[ac]; ac++)197 fprint(dfd, " %s", av[ac]);198 fprint(dfd, "\n");199 }201 switch(fork()){202 case -1:203 fatal("%r");204 case 0:205 dup(p[1], 0);206 dup(p[1], 1);207 close(p[0]);208 close(p[1]);209 execvp(REXEXEC, av);210 fatal("can't exec %s", REXEXEC);211 default:212 break;213 }214 close(p[1]);216 /* ignore crap that might come out of the .profile */217 /* keep reading till we have an "OK" */218 if(read(p[0], &buf[0], 1) != 1)219 fatal("EOF");220 for(;;){221 if(read(p[0], &buf[1], 1) != 1)222 fatal("EOF");223 if(strncmp(buf, "OK", 2) == 0)224 break;225 buf[0] = buf[1];226 }227 if(debug)228 fprint(dfd, "got OK\n");230 return p[0];231 }233 enum234 {235 BLEN=16*1024236 };238 void239 shuffle(void *arg)240 {241 int *fd;242 char *buf, *tbuf;243 int n;244 Fcall *t;246 fd = (int*)arg;247 buf = emalloc(BLEN+1);248 t = nil;249 tbuf = nil;250 for(;;){251 n = read9pmsg(fd[0], buf, BLEN);252 if(n <= 0){253 if(debug)254 fprint(dfd, "%d->%d read returns %d: %r\n", fd[0], fd[1], n);255 break;256 }257 if(debug){258 if(t == nil)259 t = emalloc(sizeof(Fcall));260 if(tbuf == nil)261 tbuf = emalloc(BLEN+1);262 memmove(tbuf, buf, n); /* because convM2S is destructive */263 if(convM2S((uchar*)tbuf, n, t) != n)264 fprint(dfd, "%d->%d convert error in convM2S", fd[0], fd[1]);265 else266 fprint(dfd, "%d->%d %F\n", fd[0], fd[1], t);267 }268 if(write(fd[1], buf, n) != n)269 break;270 }271 threadexitsall(0);272 }274 void275 remoteside(void *v)276 {277 int srv_to_net[2];278 int net_to_srv[2];279 char *addr;280 int srvfd;282 if(ns == nil)283 ns = getns();285 addr = smprint("unix!%s/%s", ns, srv);286 if(addr == nil)287 fatal("%r");288 if(debug)289 fprint(dfd, "remoteside starting %s\n", addr);291 srvfd = dial(addr, 0, 0, 0);292 if(srvfd < 0)293 fatal("dial %s: %r", addr);294 if(debug)295 fprint(dfd, "remoteside dial %s succeeded\n", addr);296 fcntl(srvfd, F_SETFL, FD_CLOEXEC);298 /* threads to shuffle messages each way */299 srv_to_net[0] = srvfd;300 srv_to_net[1] = netfd[1];301 proccreate(shuffle, srv_to_net, Stack);302 net_to_srv[0] = netfd[0];303 net_to_srv[1] = srvfd;304 shuffle(net_to_srv);306 threadexitsall(0);307 }309 void*310 emalloc(int size)311 {312 void *x;314 x = malloc(size);315 if(x == nil)316 fatal("allocation fails: %r");317 return x;318 }