fs.c 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892
  1. #include <u.h>
  2. #include <libc.h>
  3. #include <thread.h>
  4. #include <fcall.h>
  5. #include "pool.h"
  6. #include "playlist.h"
  7. typedef struct Wmsg Wmsg;
  8. enum {
  9. Busy = 0x01,
  10. Open = 0x02,
  11. Trunc = 0x04,
  12. Eof = 0x08,
  13. };
  14. File files[] = {
  15. [Qdir] = {.dir = {0,0,{Qdir, 0,QTDIR}, 0555|DMDIR, 0,0,0, "."}},
  16. [Qplayctl] = {.dir = {0,0,{Qplayctl, 0,QTFILE}, 0666, 0,0,0, "playctl"}},
  17. [Qplaylist] = {.dir = {0,0,{Qplaylist, 0,QTFILE}, 0666|DMAPPEND, 0,0,0, "playlist"}},
  18. [Qplayvol] = {.dir = {0,0,{Qplayvol, 0,QTFILE}, 0666, 0,0,0, "playvol"}},
  19. [Qplaystat] = {.dir = {0,0,{Qplaystat, 0,QTFILE}, 0444, 0,0,0, "playstat"}},
  20. };
  21. Channel *reqs;
  22. Channel *workers;
  23. Channel *volumechan;
  24. Channel *playchan;
  25. Channel *playlistreq;
  26. Playlist playlist;
  27. int volume[8];
  28. char *statetxt[] = {
  29. [Nostate] = "panic!",
  30. [Error] = "error",
  31. [Stop] = "stop",
  32. [Pause] = "pause",
  33. [Play] = "play",
  34. [Resume] = "resume",
  35. [Skip] = "skip",
  36. nil
  37. };
  38. // low-order bits: position in play list, high-order: play state:
  39. Pmsg playstate = {Stop, 0};
  40. char *rflush(Worker*), *rauth(Worker*),
  41. *rattach(Worker*), *rwalk(Worker*),
  42. *ropen(Worker*), *rcreate(Worker*),
  43. *rread(Worker*), *rwrite(Worker*), *rclunk(Worker*),
  44. *rremove(Worker*), *rstat(Worker*), *rwstat(Worker*),
  45. *rversion(Worker*);
  46. char *(*fcalls[])(Worker*) = {
  47. [Tflush] rflush,
  48. [Tversion] rversion,
  49. [Tauth] rauth,
  50. [Tattach] rattach,
  51. [Twalk] rwalk,
  52. [Topen] ropen,
  53. [Tcreate] rcreate,
  54. [Tread] rread,
  55. [Twrite] rwrite,
  56. [Tclunk] rclunk,
  57. [Tremove] rremove,
  58. [Tstat] rstat,
  59. [Twstat] rwstat,
  60. };
  61. int messagesize = Messagesize;
  62. Fid *fids;
  63. char Eperm[] = "permission denied";
  64. char Enotdir[] = "not a directory";
  65. char Enoauth[] = "authentication not required";
  66. char Enotexist[] = "file does not exist";
  67. char Einuse[] = "file in use";
  68. char Eexist[] = "file exists";
  69. char Enotowner[] = "not owner";
  70. char Eisopen[] = "file already open for I/O";
  71. char Excl[] = "exclusive use file already open";
  72. char Ename[] = "illegal name";
  73. char Ebadctl[] = "unknown control message";
  74. char Epast[] = "reading past eof";
  75. Fid *oldfid(int);
  76. Fid *newfid(int);
  77. void volumeupdater(void*);
  78. void playupdater(void*);
  79. char *playerror;
  80. static int
  81. lookup(char *cmd, char *list[])
  82. {
  83. int i;
  84. for (i = 0; list[i] != nil; i++)
  85. if (strcmp(cmd, list[i]) == 0)
  86. return i;
  87. return -1;
  88. }
  89. char*
  90. rversion(Worker *w)
  91. {
  92. Req *r;
  93. Fid *f;
  94. r = w->r;
  95. if(r->ifcall.msize < 256)
  96. return "max messagesize too small";
  97. if(r->ifcall.msize < messagesize)
  98. messagesize = r->ifcall.msize;
  99. r->ofcall.msize = messagesize;
  100. if(strncmp(r->ifcall.version, "9P2000", 6) != 0)
  101. return "unknown 9P version";
  102. else
  103. r->ofcall.version = "9P2000";
  104. for(f = fids; f; f = f->next)
  105. if(f->flags & Busy)
  106. f->flags &= ~(Open|Busy);
  107. return nil;
  108. }
  109. char*
  110. rauth(Worker*)
  111. {
  112. return Enoauth;
  113. }
  114. char*
  115. rflush(Worker *w)
  116. {
  117. Wmsg m;
  118. int i;
  119. Req *r;
  120. r = w->r;
  121. m.cmd = Flush;
  122. m.off = r->ifcall.oldtag;
  123. m.arg = nil;
  124. for(i = 1; i < nelem(files); i++)
  125. bcastmsg(files[i].workers, &m);
  126. if (debug & DbgWorker)
  127. fprint(2, "flush done on tag %d\n", r->ifcall.oldtag);
  128. return 0;
  129. }
  130. char*
  131. rattach(Worker *w)
  132. {
  133. Fid *f;
  134. Req *r;
  135. r = w->r;
  136. r->fid = newfid(r->ifcall.fid);
  137. f = r->fid;
  138. f->flags |= Busy;
  139. f->file = &files[Qdir];
  140. r->ofcall.qid = f->file->dir.qid;
  141. if(!aflag && strcmp(r->ifcall.uname, user) != 0)
  142. return Eperm;
  143. return 0;
  144. }
  145. static Fid*
  146. doclone(Fid *f, int nfid)
  147. {
  148. Fid *nf;
  149. nf = newfid(nfid);
  150. if(nf->flags & Busy)
  151. return nil;
  152. nf->flags |= Busy;
  153. nf->flags &= ~(Open);
  154. nf->file = f->file;
  155. return nf;
  156. }
  157. char*
  158. dowalk(Fid *f, char *name)
  159. {
  160. int t;
  161. if (strcmp(name, ".") == 0)
  162. return nil;
  163. if (strcmp(name, "..") == 0){
  164. f->file = &files[Qdir];
  165. return nil;
  166. }
  167. if(f->file != &files[Qdir])
  168. return Enotexist;
  169. for (t = 1; t < Nqid; t++){
  170. if(strcmp(name, files[t].dir.name) == 0){
  171. f->file = &files[t];
  172. return nil;
  173. }
  174. }
  175. return Enotexist;
  176. }
  177. char*
  178. rwalk(Worker *w)
  179. {
  180. Fid *f, *nf;
  181. char *rv;
  182. int i;
  183. File *savefile;
  184. Req *r;
  185. r = w->r;
  186. r->fid = oldfid(r->ifcall.fid);
  187. if((f = r->fid) == nil)
  188. return Enotexist;
  189. if(f->flags & Open)
  190. return Eisopen;
  191. r->ofcall.nwqid = 0;
  192. nf = nil;
  193. savefile = f->file;
  194. /* clone if requested */
  195. if(r->ifcall.newfid != r->ifcall.fid){
  196. nf = doclone(f, r->ifcall.newfid);
  197. if(nf == nil)
  198. return "new fid in use";
  199. f = nf;
  200. }
  201. /* if it's just a clone, return */
  202. if(r->ifcall.nwname == 0 && nf != nil)
  203. return nil;
  204. /* walk each element */
  205. rv = nil;
  206. for(i = 0; i < r->ifcall.nwname; i++){
  207. rv = dowalk(f, r->ifcall.wname[i]);
  208. if(rv != nil){
  209. if(nf != nil)
  210. nf->flags &= ~(Open|Busy);
  211. else
  212. f->file = savefile;
  213. break;
  214. }
  215. r->ofcall.wqid[i] = f->file->dir.qid;
  216. }
  217. r->ofcall.nwqid = i;
  218. /* we only error out if no walk */
  219. if(i > 0)
  220. rv = nil;
  221. return rv;
  222. }
  223. char *
  224. ropen(Worker *w)
  225. {
  226. Fid *f, *ff;
  227. Wmsg m;
  228. Req *r;
  229. r = w->r;
  230. r->fid = oldfid(r->ifcall.fid);
  231. if((f = r->fid) == nil)
  232. return Enotexist;
  233. if(f->flags & Open)
  234. return Eisopen;
  235. if(r->ifcall.mode != OREAD)
  236. if((f->file->dir.mode & 0x2) == 0)
  237. return Eperm;
  238. if((r->ifcall.mode & OTRUNC) && f->file == &files[Qplaylist]){
  239. playlist.nlines = 0;
  240. playlist.ndata = 0;
  241. free(playlist.lines);
  242. free(playlist.data);
  243. playlist.lines = nil;
  244. playlist.data = nil;
  245. f->file->dir.length = 0;
  246. f->file->dir.qid.vers++;
  247. /* Mark all fids for this file `Trunc'ed */
  248. for(ff = fids; ff; ff = ff->next)
  249. if(ff->file == &files[Qplaylist] && (ff->flags & Open))
  250. ff->flags |= Trunc;
  251. m.cmd = Check;
  252. m.off = 0;
  253. m.arg = nil;
  254. bcastmsg(f->file->workers, &m);
  255. }
  256. r->ofcall.iounit = 0;
  257. r->ofcall.qid = f->file->dir.qid;
  258. f->flags |= Open;
  259. return nil;
  260. }
  261. char *
  262. rcreate(Worker*)
  263. {
  264. return Eperm;
  265. }
  266. int
  267. readtopdir(Fid*, uchar *buf, long off, int cnt, int blen)
  268. {
  269. int i, m, n;
  270. long pos;
  271. n = 0;
  272. pos = 0;
  273. for (i = 1; i < Nqid; i++){
  274. m = convD2M(&files[i].dir, &buf[n], blen-n);
  275. if(off <= pos){
  276. if(m <= BIT16SZ || m > cnt)
  277. break;
  278. n += m;
  279. cnt -= m;
  280. }
  281. pos += m;
  282. }
  283. return n;
  284. }
  285. char*
  286. rread(Worker *w)
  287. {
  288. Fid *f;
  289. Req *r;
  290. long off, cnt;
  291. int n, i;
  292. Wmsg m;
  293. char *p;
  294. r = w->r;
  295. r->fid = oldfid(r->ifcall.fid);
  296. if((f = r->fid) == nil)
  297. return Enotexist;
  298. r->ofcall.count = 0;
  299. off = r->ifcall.offset;
  300. cnt = r->ifcall.count;
  301. if(cnt > messagesize - IOHDRSZ)
  302. cnt = messagesize - IOHDRSZ;
  303. if(f->file == &files[Qdir]){
  304. n = readtopdir(f, r->indata, off, cnt, messagesize - IOHDRSZ);
  305. r->ofcall.count = n;
  306. return nil;
  307. }
  308. if(f->file == files + Qplaystat){
  309. p = getplaystat(r->ofcall.data, r->ofcall.data + sizeof r->indata);
  310. readbuf(r, r->ofcall.data, p - r->ofcall.data);
  311. return nil;
  312. }
  313. m.cmd = 0;
  314. while(f->vers == f->file->dir.qid.vers && (f->flags & Eof)){
  315. /* Wait until file state changes (f->file->dir.qid.vers is incremented) */
  316. m = waitmsg(w, f->file->workers);
  317. if(m.cmd == Flush && m.off == r->ifcall.tag)
  318. return (char*)~0; /* no answer needed */
  319. assert(m.cmd != Work);
  320. yield();
  321. }
  322. if(f->file == files + Qplaylist){
  323. f->flags &= ~Eof;
  324. if((f->flags & Trunc) && r->ifcall.offset != 0){
  325. f->flags &= ~Trunc;
  326. return Epast;
  327. }
  328. f->flags &= ~Trunc;
  329. if(r->ifcall.offset < playlist.ndata)
  330. readbuf(r, playlist.data, playlist.ndata);
  331. else if(r->ifcall.offset == playlist.ndata){
  332. r->ofcall.count = 0;
  333. /* Arrange for this fid to wait next time: */
  334. f->vers = f->file->dir.qid.vers;
  335. f->flags |= Eof;
  336. }else{
  337. /* Beyond eof, bad seek? */
  338. return Epast;
  339. }
  340. }else if(f->file == files + Qplayctl){
  341. f->flags &= ~Eof;
  342. if(m.cmd == Error){
  343. snprint(r->ofcall.data, sizeof r->indata, "%s %ud %q",
  344. statetxt[m.cmd], m.off, m.arg);
  345. free(m.arg);
  346. }else if(f->vers == f->file->dir.qid.vers){
  347. r->ofcall.count = 0;
  348. /* Arrange for this fid to wait next time: */
  349. f->flags |= Eof;
  350. return nil;
  351. }else{
  352. snprint(r->ofcall.data, sizeof r->indata, "%s %ud",
  353. statetxt[playstate.cmd], playstate.off);
  354. f->vers = f->file->dir.qid.vers;
  355. }
  356. r->ofcall.count = strlen(r->ofcall.data);
  357. if(r->ofcall.count > r->ifcall.count)
  358. r->ofcall.count = r->ifcall.count;
  359. }else if(f->file == files + Qplayvol){
  360. f->flags &= ~Eof;
  361. if(f->vers == f->file->dir.qid.vers){
  362. r->ofcall.count = 0;
  363. /* Arrange for this fid to wait next time: */
  364. f->flags |= Eof;
  365. }else{
  366. p = seprint(r->ofcall.data, r->ofcall.data + sizeof r->indata, "volume '");
  367. for(i = 0; i < nelem(volume); i++){
  368. if(volume[i] == Undef)
  369. break;
  370. p = seprint(p, r->ofcall.data + sizeof r->indata, "%d ", volume[i]);
  371. }
  372. p = seprint(p, r->ofcall.data + sizeof r->indata, "'");
  373. r->ofcall.count = p - r->ofcall.data;
  374. if(r->ofcall.count > r->ifcall.count)
  375. r->ofcall.count = r->ifcall.count;
  376. f->vers = f->file->dir.qid.vers;
  377. }
  378. }else
  379. abort();
  380. return nil;
  381. }
  382. char*
  383. rwrite(Worker *w)
  384. {
  385. long cnt, i, nf, cmd;
  386. Pmsg newstate;
  387. char *fields[3], *p, *q;
  388. Wmsg m;
  389. Fid *f;
  390. Req *r;
  391. r = w->r;
  392. r->fid = oldfid(r->ifcall.fid);
  393. if((f = r->fid) == nil)
  394. return Enotexist;
  395. r->ofcall.count = 0;
  396. cnt = r->ifcall.count;
  397. if(cnt > messagesize - IOHDRSZ)
  398. cnt = messagesize - IOHDRSZ;
  399. if(f->file == &files[Qplayctl]){
  400. r->ifcall.data[cnt] = '\0';
  401. if (debug & DbgPlayer)
  402. fprint(2, "rwrite playctl: %s\n", r->ifcall.data);
  403. nf = tokenize(r->ifcall.data, fields, 4);
  404. if (nf == 0){
  405. r->ofcall.count = r->ifcall.count;
  406. return nil;
  407. }
  408. if (nf == 2)
  409. i = strtol(fields[1], nil, 0);
  410. else
  411. i = playstate.off;
  412. newstate = playstate;
  413. if ((cmd = lookup(fields[0], statetxt)) < 0)
  414. return Ebadctl;
  415. switch(cmd){
  416. case Play:
  417. newstate.cmd = cmd;
  418. newstate.off = i;
  419. break;
  420. case Pause:
  421. if (playstate.cmd != Play)
  422. break;
  423. // fall through
  424. case Stop:
  425. newstate.cmd = cmd;
  426. newstate.off = playstate.off;
  427. break;
  428. case Resume:
  429. if(playstate.cmd == Stop)
  430. break;
  431. newstate.cmd = Resume;
  432. newstate.off = playstate.off;
  433. break;
  434. case Skip:
  435. if (nf == 2)
  436. i += playstate.off;
  437. else
  438. i = playstate.off +1;
  439. if(i < 0)
  440. i = 0;
  441. else if (i >= playlist.nlines)
  442. i = playlist.nlines - 1;
  443. newstate.cmd = Play;
  444. newstate.off = i;
  445. }
  446. if (newstate.off >= playlist.nlines){
  447. newstate.cmd = Stop;
  448. newstate.off = playlist.nlines;
  449. }
  450. if (debug & DbgPlayer)
  451. fprint(2, "new state %s-%ud\n",
  452. statetxt[newstate.cmd], newstate.off);
  453. if (newstate.m != playstate.m)
  454. sendul(playc, newstate.m);
  455. f->file->dir.qid.vers++;
  456. } else if(f->file == &files[Qplayvol]){
  457. char *subfields[nelem(volume)];
  458. int v[nelem(volume)];
  459. r->ifcall.data[cnt] = '\0';
  460. if (debug & DbgPlayer)
  461. fprint(2, "rwrite playvol: %s\n", r->ifcall.data);
  462. nf = tokenize(r->ifcall.data, fields, 4);
  463. if (nf == 0){
  464. r->ofcall.count = r->ifcall.count;
  465. return nil;
  466. }
  467. if (nf != 2 || strcmp(fields[0], "volume") != 0)
  468. return Ebadctl;
  469. if (debug & DbgPlayer)
  470. fprint(2, "new volume '");
  471. nf = tokenize(fields[1], subfields, nelem(subfields));
  472. if (nf <= 0 || nf > nelem(volume))
  473. return "volume";
  474. for (i = 0; i < nf; i++){
  475. v[i] = strtol(subfields[i], nil, 0);
  476. if (debug & DbgPlayer)
  477. fprint(2, " %d", v[i]);
  478. }
  479. if (debug & DbgPlayer)
  480. fprint(2, "'\n");
  481. while (i < nelem(volume))
  482. v[i++] = Undef;
  483. volumeset(v);
  484. r->ofcall.count = r->ifcall.count;
  485. return nil;
  486. } else if(f->file == &files[Qplaylist]){
  487. if (debug & DbgPlayer){
  488. fprint(2, "rwrite playlist: `");
  489. write(2, r->ifcall.data, cnt);
  490. fprint(2, "'\n");
  491. }
  492. playlist.data = realloc(playlist.data, playlist.ndata + cnt + 2);
  493. if (playlist.data == 0)
  494. sysfatal("realloc: %r");
  495. memmove(playlist.data + playlist.ndata, r->ifcall.data, cnt);
  496. if (playlist.data[playlist.ndata + cnt-1] != '\n')
  497. playlist.data[playlist.ndata + cnt++] = '\n';
  498. playlist.data[playlist.ndata + cnt] = '\0';
  499. p = playlist.data + playlist.ndata;
  500. while (*p){
  501. playlist.lines = realloc(playlist.lines, (playlist.nlines+1)*sizeof(playlist.lines[0]));
  502. if(playlist.lines == nil)
  503. sysfatal("realloc: %r");
  504. playlist.lines[playlist.nlines] = playlist.ndata;
  505. q = strchr(p, '\n');
  506. if (q == nil)
  507. break;
  508. if(debug & DbgPlayer)
  509. fprint(2, "[%lud]: ", playlist.nlines);
  510. playlist.nlines++;
  511. q++;
  512. if(debug & DbgPlayer)
  513. write(2, p, q-p);
  514. playlist.ndata += q - p;
  515. p = q;
  516. }
  517. f->file->dir.length = playlist.ndata;
  518. f->file->dir.qid.vers++;
  519. }else
  520. return Eperm;
  521. r->ofcall.count = r->ifcall.count;
  522. m.cmd = Check;
  523. m.off = 0;
  524. m.arg = nil;
  525. bcastmsg(f->file->workers, &m);
  526. return nil;
  527. }
  528. char *
  529. rclunk(Worker *w)
  530. {
  531. Fid *f;
  532. f = oldfid(w->r->ifcall.fid);
  533. if(f == nil)
  534. return Enotexist;
  535. f->flags &= ~(Open|Busy);
  536. return 0;
  537. }
  538. char *
  539. rremove(Worker*)
  540. {
  541. return Eperm;
  542. }
  543. char *
  544. rstat(Worker *w)
  545. {
  546. Req *r;
  547. r = w->r;
  548. r->fid = oldfid(r->ifcall.fid);
  549. if(r->fid == nil)
  550. return Enotexist;
  551. r->ofcall.nstat = convD2M(&r->fid->file->dir, r->indata, messagesize - IOHDRSZ);
  552. r->ofcall.stat = r->indata;
  553. return 0;
  554. }
  555. char *
  556. rwstat(Worker*)
  557. {
  558. return Eperm;
  559. }
  560. Fid *
  561. oldfid(int fid)
  562. {
  563. Fid *f;
  564. for(f = fids; f; f = f->next)
  565. if(f->fid == fid)
  566. return f;
  567. return nil;
  568. }
  569. Fid *
  570. newfid(int fid)
  571. {
  572. Fid *f, *ff;
  573. ff = nil;
  574. for(f = fids; f; f = f->next)
  575. if(f->fid == fid){
  576. return f;
  577. }else if(ff == nil && (f->flags & Busy) == 0)
  578. ff = f;
  579. if(ff == nil){
  580. ff = mallocz(sizeof *ff, 1);
  581. if (ff == nil)
  582. sysfatal("malloc: %r");
  583. ff->next = fids;
  584. ff->readers = 0;
  585. fids = ff;
  586. }
  587. ff->fid = fid;
  588. ff->file = nil;
  589. ff->vers = ~0;
  590. return ff;
  591. }
  592. void
  593. work(Worker *w)
  594. {
  595. Req *r;
  596. char *err;
  597. int n;
  598. r = w->r;
  599. r->ofcall.data = (char*)r->indata;
  600. if(!fcalls[r->ifcall.type])
  601. err = "bad fcall type";
  602. else
  603. err = (*fcalls[r->ifcall.type])(w);
  604. if(err != (char*)~0){ /* ~0 indicates Flush received */
  605. if(err){
  606. r->ofcall.type = Rerror;
  607. r->ofcall.ename = err;
  608. }else{
  609. r->ofcall.type = r->ifcall.type + 1;
  610. r->ofcall.fid = r->ifcall.fid;
  611. }
  612. r->ofcall.tag = r->ifcall.tag;
  613. if(debug & DbgFs)
  614. fprint(2, "io:->%F\n", &r->ofcall);/**/
  615. n = convS2M(&r->ofcall, r->outdata, messagesize);
  616. if(write(srvfd[0], r->outdata, n) != n)
  617. sysfatal("mount write");
  618. }
  619. reqfree(r);
  620. w->r = nil;
  621. }
  622. void
  623. worker(void *arg)
  624. {
  625. Worker *w;
  626. Wmsg m;
  627. w = arg;
  628. recv(w->eventc, &m);
  629. for(;;){
  630. assert(m.cmd == Work);
  631. w->r = m.arg;
  632. if(debug & DbgWorker)
  633. fprint(2, "worker 0x%p:<-%F\n", w, &w->r->ifcall);
  634. work(w);
  635. if(debug & DbgWorker)
  636. fprint(2, "worker 0x%p wait for next\n", w);
  637. m = waitmsg(w, workers);
  638. }
  639. }
  640. void
  641. allocwork(Req *r)
  642. {
  643. Worker *w;
  644. Wmsg m;
  645. m.cmd = Work;
  646. m.off = 0;
  647. m.arg = r;
  648. if(sendmsg(workers, &m))
  649. return;
  650. /* No worker ready to accept request, allocate one */
  651. w = malloc(sizeof(Worker));
  652. w->eventc = chancreate(sizeof(Wmsg), 1);
  653. if(debug & DbgWorker)
  654. fprint(2, "new worker 0x%p\n", w);/**/
  655. threadcreate(worker, w, 4096);
  656. send(w->eventc, &m);
  657. }
  658. void
  659. srvio(void *arg)
  660. {
  661. char e[32];
  662. int n;
  663. Req *r;
  664. Channel *dispatchc;
  665. threadsetname("file server IO");
  666. dispatchc = arg;
  667. r = reqalloc();
  668. for(;;){
  669. /*
  670. * reading from a pipe or a network device
  671. * will give an error after a few eof reads
  672. * however, we cannot tell the difference
  673. * between a zero-length read and an interrupt
  674. * on the processes writing to us,
  675. * so we wait for the error
  676. */
  677. n = read9pmsg(srvfd[0], r->indata, messagesize);
  678. if(n == 0)
  679. continue;
  680. if(n < 0){
  681. rerrstr(e, sizeof e);
  682. if (strcmp(e, "interrupted") == 0){
  683. if (debug & DbgFs) fprint(2, "read9pmsg interrupted\n");
  684. continue;
  685. }
  686. sysfatal("srvio: %s", e);
  687. }
  688. if(convM2S(r->indata, n, &r->ifcall) == 0)
  689. continue;
  690. if(debug & DbgFs)
  691. fprint(2, "io:<-%F\n", &r->ifcall);
  692. sendp(dispatchc, r);
  693. r = reqalloc();
  694. }
  695. }
  696. char *
  697. getplaylist(int n)
  698. {
  699. Wmsg m;
  700. m.cmd = Preq;
  701. m.off = n;
  702. m.arg = nil;
  703. send(playlistreq, &m);
  704. recv(playlistreq, &m);
  705. if(m.cmd == Error)
  706. return nil;
  707. assert(m.cmd == Prep);
  708. assert(m.arg);
  709. return m.arg;
  710. }
  711. void
  712. playlistsrv(void*)
  713. {
  714. Wmsg m;
  715. char *p, *q, *r;
  716. char *fields[2];
  717. int n;
  718. /* Runs in the srv proc */
  719. threadsetname("playlistsrv");
  720. while(recv(playlistreq, &m)){
  721. assert(m.cmd == Preq);
  722. m.cmd = Error;
  723. if(m.off < playlist.nlines){
  724. p = playlist.data + playlist.lines[m.off];
  725. q = strchr(p, '\n');
  726. if (q == nil)
  727. sysfatal("playlistsrv: no newline character found");
  728. n = q-p;
  729. r = malloc(n+1);
  730. memmove(r, p, n);
  731. r[n] = 0;
  732. tokenize(r, fields, nelem(fields));
  733. assert(fields[0] == r);
  734. m.cmd = Prep;
  735. m.arg = r;
  736. }
  737. send(playlistreq, &m);
  738. }
  739. }
  740. void
  741. srv(void*)
  742. {
  743. Req *r;
  744. Channel *dispatchc;
  745. /*
  746. * This is the proc with all the action.
  747. * When a file request comes in, it is dispatched to this proc
  748. * for processing. Two extra threads field changes in play state
  749. * and volume state.
  750. * By keeping all the action in this proc, we won't need locks
  751. */
  752. threadsetname("srv");
  753. close(srvfd[1]);
  754. dispatchc = chancreate(sizeof(Req*), 1);
  755. procrfork(srvio, dispatchc, 4096, RFFDG);
  756. threadcreate(volumeupdater, nil, 4096);
  757. threadcreate(playupdater, nil, 4096);
  758. threadcreate(playlistsrv, nil, 4096);
  759. while(r = recvp(dispatchc))
  760. allocwork(r);
  761. }
  762. void
  763. playupdater(void*)
  764. {
  765. Wmsg m;
  766. /* This is a thread in the srv proc */
  767. while(recv(playchan, &m)){
  768. if(debug & DbgPlayer)
  769. fprint(2, "playupdate: %s %d %s\n", statetxt[m.cmd], m.off, m.arg?m.arg:"");
  770. if(playstate.m == m.m)
  771. continue;
  772. if(m.cmd == Stop && m.off == 0xffff)
  773. m.off = playlist.nlines;
  774. if(m.cmd != Error){
  775. playstate.m = m.m;
  776. m.cmd = Check;
  777. assert(m.arg == nil);
  778. }
  779. files[Qplayctl].dir.qid.vers++;
  780. bcastmsg(files[Qplayctl].workers, &m);
  781. }
  782. }
  783. void
  784. volumeupdater(void*)
  785. {
  786. Wmsg m;
  787. int v[nelem(volume)];
  788. /* This is a thread in the srv proc */
  789. while(recv(volumechan, v)){
  790. if(debug & DbgPlayer)
  791. fprint(2, "volumeupdate: volume now %d %d %d %d\n", volume[0], volume[1], volume[2], volume[3]);
  792. memmove(volume, v, sizeof(volume));
  793. files[Qplayvol].dir.qid.vers++;
  794. m.cmd = Check;
  795. m.arg = nil;
  796. bcastmsg(files[Qplayvol].workers, &m);
  797. }
  798. }
  799. void
  800. playupdate(Pmsg p, char *s)
  801. {
  802. Wmsg m;
  803. m.m = p.m;
  804. m.arg = s ? strdup(s) : nil;
  805. send(playchan, &m);
  806. }