devrealtime.c 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768
  1. #include "u.h"
  2. #include "../port/lib.h"
  3. #include "mem.h"
  4. #include "dat.h"
  5. #include "fns.h"
  6. #include "io.h"
  7. #include "ureg.h"
  8. #include "error.h"
  9. #include "realtime.h"
  10. #include "edf.h"
  11. #pragma varargck type "T" vlong
  12. /* debugging */
  13. extern int edfprint;
  14. extern Edfinterface realedf, *edf;
  15. static Schedevent *events;
  16. static int nevents, revent, wevent;
  17. static Rendez eventr;
  18. static QLock elock;
  19. static Ref logopens;
  20. static Ref debugopens;
  21. static uvlong fasthz;
  22. enum {
  23. Qistask = 0x10000,
  24. Qdir = 0,
  25. Qrealtime,
  26. Qclone,
  27. Qdebug,
  28. Qdump,
  29. Qlog,
  30. Qnblog,
  31. Qresrc,
  32. Qtask,
  33. Qtime,
  34. Nevents = 10000,
  35. Clockshift = 17, // Good to about 10GHz clock and max. 5(s)
  36. };
  37. Dirtab schedrootdir[]={
  38. ".", {Qdir, 0, QTDIR}, 0, DMDIR|0555,
  39. "realtime", {Qrealtime, 0, QTDIR}, 0, DMDIR|0555,
  40. };
  41. Dirtab scheddir[]={
  42. ".", {Qrealtime, 0, QTDIR}, 0, DMDIR|0555,
  43. "clone", {Qclone}, 0, 0666,
  44. "debug", {Qdebug}, 0, 0444,
  45. "dump", {Qdump}, 0, 0444,
  46. "log", {Qlog}, 0, 0444, /* one open only */
  47. "nblog", {Qnblog}, 0, 0444, /* nonblocking version of log */
  48. "resources", {Qresrc}, 0, 0444,
  49. "task", {Qtask, 0, QTDIR}, 0, DMDIR|0555,
  50. "time", {Qtime}, 0, 0444,
  51. };
  52. static char *schedstatename[] = {
  53. [SRelease] = "Release",
  54. [SRun] = "Run",
  55. [SPreempt] = "Preempt",
  56. [SBlock] = "Block",
  57. [SResume] = "Resume",
  58. [SDeadline] = "Deadline",
  59. [SYield] = "Yield",
  60. [SSlice] = "Slice",
  61. [SExpel] = "Expel",
  62. };
  63. static int taskno;
  64. static Task *
  65. taskinit(void)
  66. {
  67. Dirtab *d;
  68. Task *t;
  69. t = malloc(sizeof(Task));
  70. if (t == nil)
  71. error("taskinit: malloc");
  72. d = &t->dir;
  73. if (up->user)
  74. kstrdup(&t->user, up->user);
  75. else
  76. kstrdup(&t->user, eve);
  77. t->state = EdfExpelled;
  78. t->taskno = ++taskno;
  79. snprint(d->name, sizeof d->name, "%d", t->taskno);
  80. mkqid(&d->qid, Qistask | t->taskno, 0, QTFILE);
  81. d->length = 0;
  82. d->perm = 0600;
  83. enlist(&tasks, t);
  84. incref(t);
  85. return t;
  86. }
  87. void
  88. taskfree(Task *t)
  89. {
  90. if (decref(t))
  91. return;
  92. assert(t->procs.n == 0);
  93. assert(t->csns.n == 0);
  94. free(t->user);
  95. free(t);
  96. }
  97. /*
  98. * the zeroth element of the table MUST be the directory itself for ..
  99. */
  100. int
  101. schedgen(Chan *c, char*, Dirtab *, int, int i, Dir *dp)
  102. {
  103. Dirtab *tab;
  104. int ntab;
  105. char *owner;
  106. ulong taskindex;
  107. Qid qid;
  108. Task *t;
  109. List *l;
  110. if((ulong)c->qid.path & Qistask){
  111. qlock(&edfschedlock);
  112. taskindex = (ulong)c->qid.path & (Qistask-1);
  113. if ((t = findtask(taskindex)) == nil){
  114. qunlock(&edfschedlock);
  115. return -1;
  116. }
  117. }else if((ulong)c->qid.path == Qtask){
  118. qlock(&edfschedlock);
  119. taskindex = i;
  120. SET(t);
  121. for (l = tasks.next; l; l = l->next)
  122. if ((t = l->i) && taskindex-- == 0)
  123. break;
  124. if (l == nil){
  125. qunlock(&edfschedlock);
  126. return -1;
  127. }
  128. }else {
  129. if((ulong)c->qid.path == Qdir){
  130. tab = schedrootdir;
  131. ntab = nelem(schedrootdir);
  132. }else{
  133. tab = scheddir;
  134. ntab = nelem(scheddir);
  135. }
  136. if(i != DEVDOTDOT){
  137. /* skip over the first element, that for . itself */
  138. i++;
  139. if(i >= ntab)
  140. return -1;
  141. tab += i;
  142. }
  143. devdir(c, tab->qid, tab->name, tab->length, eve, tab->perm, dp);
  144. return 1;
  145. }
  146. if(i == DEVDOTDOT){
  147. mkqid(&qid, Qtask, 0, QTDIR);
  148. devdir(c, qid, ".", 0, eve, 0555, dp);
  149. }else{
  150. owner = t->user;
  151. if (owner == nil)
  152. owner = eve;
  153. tab = &t->dir;
  154. devdir(c, tab->qid, tab->name, tab->length, owner, tab->perm, dp);
  155. }
  156. qunlock(&edfschedlock);
  157. return 1;
  158. }
  159. static void
  160. _devrt(Task *t, Ticks t1, SEvent etype)
  161. {
  162. if (logopens.ref == 0 || nevents == Nevents)
  163. return;
  164. if(edfprint)iprint("state %s\n", schedstatename[etype]);
  165. events[wevent].tid = t->taskno;
  166. events[wevent].ts = 0;
  167. if (t1)
  168. events[wevent].ts = ticks2time(t1);
  169. else
  170. events[wevent].ts = 0;
  171. events[wevent].etype = etype;
  172. if (!canqlock(&elock))
  173. return;
  174. wevent = (wevent + 1) % Nevents;
  175. if (nevents < Nevents)
  176. nevents++;
  177. else
  178. revent = (revent + 1) % Nevents;
  179. if(edfprint)iprint("wakesched\n");
  180. /* To avoid circular wakeup when used in combination with
  181. * EDF scheduling.
  182. */
  183. if (eventr.p && eventr.p->state == Wakeme)
  184. wakeup(&eventr);
  185. qunlock(&elock);
  186. }
  187. static void
  188. devrtinit(void)
  189. {
  190. fmtinstall('T', timeconv);
  191. fmtinstall('U', timeconv);
  192. fastticks(&fasthz);
  193. devrt = _devrt;
  194. events = (Schedevent *)malloc(sizeof(Schedevent) * Nevents);
  195. assert(events);
  196. nevents = revent = wevent = 0;
  197. edf = &realedf;
  198. }
  199. static Chan *
  200. devrtattach(char *param)
  201. {
  202. return devattach('R', param);
  203. }
  204. static Walkqid *
  205. devrtwalk(Chan *c, Chan *nc, char **name, int nname)
  206. {
  207. return devwalk(c, nc, name, nname, nil, 0, schedgen);
  208. }
  209. static int
  210. devrtstat(Chan *c, uchar *db, int n)
  211. {
  212. return devstat(c, db, n, nil, 0, schedgen);
  213. }
  214. static Chan *
  215. devrtopen(Chan *c, int mode)
  216. {
  217. Task *t;
  218. switch ((ulong)c->qid.path){
  219. case Qlog:
  220. case Qnblog:
  221. if (mode != OREAD)
  222. error(Eperm);
  223. incref(&logopens);
  224. if (logopens.ref > 1){
  225. decref(&logopens);
  226. error("already open");
  227. }
  228. break;
  229. case Qdebug:
  230. if (mode != OREAD)
  231. error(Eperm);
  232. incref(&debugopens);
  233. if (debugopens.ref > 1){
  234. decref(&debugopens);
  235. error("already open");
  236. }
  237. break;
  238. case Qdump:
  239. if (mode != OREAD)
  240. error(Eperm);
  241. break;
  242. case Qclone:
  243. if (mode == OREAD)
  244. error(Eperm);
  245. edf->edfinit();
  246. qlock(&edfschedlock);
  247. /* open a new task */
  248. t = taskinit();
  249. c->qid.vers = t->taskno;
  250. qunlock(&edfschedlock);
  251. break;
  252. }
  253. // print("open %lux, mode %o\n", (ulong)c->qid.path, mode);
  254. return devopen(c, mode, nil, 0, schedgen);
  255. }
  256. static void
  257. devrtclose(Chan *c)
  258. {
  259. switch ((ulong)c->qid.path){
  260. case Qlog:
  261. case Qnblog:
  262. nevents = revent = wevent = 0;
  263. decref(&logopens);
  264. break;
  265. case Qdebug:
  266. nevents = revent = wevent = 0;
  267. decref(&debugopens);
  268. break;
  269. }
  270. }
  271. static int
  272. eventsavailable(void *)
  273. {
  274. return nevents > 0;
  275. }
  276. static long
  277. devrtread(Chan *c, void *v, long n, vlong offs)
  278. {
  279. char *p, *e;
  280. char buf[1024];
  281. long n0;
  282. int navail;
  283. Task *t;
  284. int s, i;
  285. Ticks now;
  286. Time tim;
  287. List *l;
  288. n0 = n;
  289. // print("schedread 0x%lux\n", (ulong)c->qid.path);
  290. buf[0] = '\0';
  291. switch((ulong)c->qid.path){
  292. case Qdir:
  293. return devdirread(c, v, n, schedrootdir, nelem(schedrootdir), devgen);
  294. case Qrealtime:
  295. return devdirread(c, v, n, scheddir, nelem(scheddir), devgen);
  296. case Qtask:
  297. return devdirread(c, v, n, nil, 0, schedgen);
  298. case Qtime:
  299. if (n < sizeof(Time))
  300. error(Ebadarg);
  301. now = fastticks(nil);
  302. tim = ticks2time(now);
  303. memmove(v, &tim, sizeof(Time));
  304. n -= sizeof(Ticks);
  305. if (n >= sizeof(Ticks)){
  306. memmove((char*)v + sizeof(Time), &now, sizeof(Ticks));
  307. n -= sizeof(Ticks);
  308. }
  309. if (n >= sizeof(Ticks)){
  310. memmove((char*)v + sizeof(Time) + sizeof(Ticks), &fasthz, sizeof(Ticks));
  311. n -= sizeof(Ticks);
  312. }
  313. break;
  314. case Qnblog:
  315. if (eventsavailable(nil))
  316. goto getevnt;
  317. break;
  318. case Qlog:
  319. while (!eventsavailable(nil))
  320. sleep(&eventr, eventsavailable, nil);
  321. getevnt:
  322. p = (char *)v;
  323. navail = nevents;
  324. if (navail > n / sizeof(Schedevent))
  325. navail = n / sizeof(Schedevent);
  326. n -= navail * sizeof(Schedevent);
  327. qlock(&elock);
  328. while (navail > 0) {
  329. int ncopy;
  330. ncopy = (revent + navail > Nevents)? Nevents - revent: navail;
  331. memmove(p, &events[revent], ncopy * sizeof(Schedevent));
  332. revent = (revent+ ncopy) % Nevents;
  333. p += ncopy * sizeof(Schedevent);
  334. navail -= ncopy;
  335. nevents -= ncopy;
  336. }
  337. qunlock(&elock);
  338. break;
  339. case Qresrc:
  340. qlock(&edfschedlock);
  341. if(waserror()){
  342. qunlock(&edfschedlock);
  343. nexterror();
  344. }
  345. seprintresources(buf, buf + sizeof(buf));
  346. qunlock(&edfschedlock);
  347. poperror();
  348. return readstr(offs, v, n, buf);
  349. break;
  350. case Qdump:
  351. p = buf;
  352. e = p + sizeof(buf);
  353. qlock(&edfschedlock);
  354. qunlock(&edfschedlock);
  355. seprint(p, e, "\n");
  356. return readstr(offs, v, n, buf);
  357. case Qdebug:
  358. p = buf;
  359. e = p + sizeof(buf);
  360. ilock(&edflock);
  361. now = fastticks(nil);
  362. for (i = 0; i < conf.nmach; i++){
  363. p = seprint(p, e, "edfstack[%d]\n", i);
  364. p = dumpq(p, e, edfstack + i, now);
  365. }
  366. p = seprint(p, e, "qreleased\n");
  367. p = dumpq(p, e, &qreleased, now);
  368. p = seprint(p, e, "qwaitrelease\n");
  369. p = dumpq(p, e, &qwaitrelease, now);
  370. p = seprint(p, e, "qextratime\n");
  371. dumpq(p, e, &qextratime, now);
  372. iunlock(&edflock);
  373. return readstr(offs, v, n, buf);
  374. case Qclone:
  375. s = c->qid.vers;
  376. goto common;
  377. default:
  378. if ((c->qid.path & Qistask) == 0)
  379. error(Enonexist);
  380. s = (ulong)c->qid.path & (Qistask - 1);
  381. common:
  382. qlock(&edfschedlock);
  383. t = findtask(s);
  384. if (t == nil){
  385. qunlock(&edfschedlock);
  386. error(Enonexist);
  387. }
  388. p = buf;
  389. e = p + sizeof(buf);
  390. p = seprint(p, e, "task=%d", s);
  391. p = seprint(p, e, " state=%s", edfstatename[t->state]);
  392. if (t->T)
  393. p = seprint(p, e, " T=%T", ticks2time(t->T));
  394. if (t->D)
  395. p = seprint(p, e, " D=%T", ticks2time(t->D));
  396. if (t->C)
  397. p = seprint(p, e, " C=%T", ticks2time(t->C));
  398. if (t->Delta)
  399. p = seprint(p, e, " Δ=%T", ticks2time(t->Delta));
  400. else if (t->testDelta)
  401. p = seprint(p, e, " testΔ=%T", ticks2time(t->testDelta));
  402. p = seprint(p, e, " yieldonblock=%d", (t->flags & Verbose) != 0);
  403. if (t->csns.n){
  404. p = seprint(p, e, " resources='");
  405. p = seprintcsn(p, e, &t->csns);
  406. p = seprint(p, e, "'");
  407. }
  408. if (t->procs.n){
  409. p = seprint(p, e, " procs='");
  410. for (l = t->procs.next; l; l = l->next){
  411. Proc *pr = l->i;
  412. assert(pr);
  413. if (l != t->procs.next)
  414. p = seprint(p, e, " ");
  415. p = seprint(p, e, "%lud", pr->pid);
  416. }
  417. p = seprint(p, e, "'");
  418. }
  419. if (t->periods)
  420. p = seprint(p, e, " n=%lud", t->periods);
  421. if (t->missed)
  422. p = seprint(p, e, " m=%lud", t->missed);
  423. if (t->preemptions)
  424. p = seprint(p, e, " p=%lud", t->preemptions);
  425. if (t->total)
  426. p = seprint(p, e, " t=%T", ticks2time(t->total));
  427. if (t->aged)
  428. p = seprint(p, e, " c=%T", ticks2time(t->aged));
  429. seprint(p, e, "\n");
  430. qunlock(&edfschedlock);
  431. return readstr(offs, v, n, buf);
  432. }
  433. return n0 - n;
  434. }
  435. static long
  436. devrtwrite(Chan *c, void *va, long n, vlong)
  437. {
  438. char *a, *v, *e, *args[16], *rargs[16], buf[512];
  439. int i, j, s, nargs, nrargs, add;
  440. Resource *r;
  441. Task *t;
  442. Ticks ticks;
  443. Time time;
  444. long pid;
  445. Proc *p;
  446. CSN *l;
  447. a = va;
  448. if (c->mode == OREAD)
  449. error(Eperm);
  450. switch((ulong)c->qid.path){
  451. case Qclone:
  452. s = c->qid.vers;
  453. goto common;
  454. default:
  455. if ((c->qid.path & Qistask) == 0)
  456. error(Enonexist);
  457. s = (ulong)c->qid.path & (Qistask - 1);
  458. common:
  459. qlock(&edfschedlock);
  460. if (waserror()){
  461. qunlock(&edfschedlock);
  462. nexterror();
  463. }
  464. t = findtask(s);
  465. if (t == nil)
  466. error(Enonexist);
  467. if(n >= sizeof(buf))
  468. n = sizeof(buf)-1;
  469. strncpy(buf, a, n);
  470. buf[n] = 0;
  471. nargs = tokenize(buf, args, nelem(args));
  472. for (i = 0; i < nargs; i++){
  473. a = args[i];
  474. add = 0;
  475. if (v = strchr(a, '=')){
  476. *v = '\0';
  477. if (v != a && v[-1] == '+'){
  478. add = 1;
  479. v[-1] = '\0';
  480. } else if (v != a && v[-1] == '-'){
  481. add = -1;
  482. v[-1] = '\0';
  483. }
  484. v++;
  485. }
  486. if (strcmp(a, "T") == 0){
  487. if (e=parsetime(&time, v))
  488. error(e);
  489. ticks = time2ticks(time);
  490. edf->edfexpel(t);
  491. switch(add){
  492. case -1:
  493. if (ticks > t->T)
  494. t->T = 0;
  495. else
  496. t->T -= ticks;
  497. break;
  498. case 0:
  499. t->T = ticks;
  500. break;
  501. case 1:
  502. t->T += ticks;
  503. break;
  504. }
  505. if (t->T < time2ticks(10000000/HZ))
  506. error("period too short");
  507. DEBUG("Task %d, T=%T\n", t->taskno, ticks2time(t->T));
  508. }else if (strcmp(a, "D") == 0){
  509. if (e=parsetime(&time, v))
  510. error(e);
  511. ticks = time2ticks(time);
  512. edf->edfexpel(t);
  513. switch(add){
  514. case -1:
  515. if (ticks > t->D)
  516. t->D = 0;
  517. else
  518. t->D -= ticks;
  519. break;
  520. case 0:
  521. t->D = ticks;
  522. break;
  523. case 1:
  524. t->D += ticks;
  525. break;
  526. }
  527. DEBUG("Task %d, D=%T\n", t->taskno, ticks2time(t->D));
  528. }else if (strcmp(a, "C") == 0){
  529. if (e=parsetime(&time, v))
  530. error(e);
  531. ticks = time2ticks(time);
  532. edf->edfexpel(t);
  533. switch(add){
  534. case -1:
  535. if (ticks > t->C)
  536. t->C = 0;
  537. else
  538. t->C -= ticks;
  539. break;
  540. case 0:
  541. t->C = ticks;
  542. break;
  543. case 1:
  544. t->C += ticks;
  545. break;
  546. }
  547. if (t->C < time2ticks(10000000/HZ))
  548. error("cost too small");
  549. DEBUG("Task %d, C=%T\n", t->taskno, ticks2time(t->C));
  550. }else if (strcmp(a, "resources") == 0){
  551. if (v == nil)
  552. error("resources: value missing");
  553. edf->edfexpel(t);
  554. if (add < 0)
  555. error("can't remove resources yet");
  556. if (add == 0){
  557. List *l;
  558. while (l = t->csns.next) {
  559. r = l->i;
  560. assert(r);
  561. if (delist(&r->tasks, t))
  562. taskfree(t);
  563. if (delist(&t->csns, r))
  564. resourcefree(r);
  565. }
  566. assert(t->csns.n == 0);
  567. add = 1;
  568. USED(add);
  569. }
  570. v = parseresource(&t->csns, nil, v);
  571. if (v && *v)
  572. error("resources: parse error");
  573. }else if (strcmp(a, "acquire") == 0){
  574. if (v == nil)
  575. error("acquire: value missing");
  576. if (up->task != t)
  577. error("acquire: not for another task");
  578. if ((r = resource(v, 0)) == nil)
  579. error("acquire: no such resource");
  580. for (l = (CSN*)t->csns.next; l; l = (CSN*)l->next){
  581. if (l->i == r){
  582. DEBUG("l->p (0x%p) == t->curcsn (0x%p) && l->S (%T) != 0\n", l->p, t->curcsn, ticks2time(l->S));
  583. if(l->p == t->curcsn && l->S != 0)
  584. break;
  585. }
  586. }
  587. if (l == nil)
  588. error("acquire: no access or resource exhausted");
  589. edf->resacquire(t, l);
  590. }else if (strcmp(a, "release") == 0){
  591. if (v == nil)
  592. error("release: value missing");
  593. if (up->task != t)
  594. error("release: not for another task");
  595. if ((r = resource(v, 0)) == nil)
  596. error("release: no such resource");
  597. if (t->curcsn->i != r)
  598. error("release: release not held or illegal release order");
  599. edf->resrelease(t);
  600. }else if (strcmp(a, "procs") == 0){
  601. if (v == nil)
  602. error("procs: value missing");
  603. if (add <= 0){
  604. edf->edfexpel(t);
  605. }
  606. if (add == 0){
  607. List *l;
  608. while (l = t->procs.next){
  609. p = l->i;
  610. assert(p->task == t);
  611. delist(&t->procs, p);
  612. p->task = nil;
  613. }
  614. add = 1;
  615. }
  616. nrargs = tokenize(v, rargs, nelem(rargs));
  617. for (j = 0; j < nrargs; j++){
  618. if (strcmp("self", rargs[j]) == 0){
  619. p = up;
  620. }else{
  621. pid = atoi(rargs[j]);
  622. if (pid <= 0)
  623. error("bad process number");
  624. s = procindex(pid);
  625. if(s < 0)
  626. error("no such process");
  627. p = proctab(s);
  628. }
  629. if(p->task && p->task != t)
  630. error("proc belongs to another task");
  631. if (add > 0){
  632. enlist(&t->procs, p);
  633. p->task = t;
  634. }else{
  635. delist(&t->procs, p);
  636. p->task = nil;
  637. }
  638. }
  639. }else if (strcmp(a, "admit") == 0){
  640. if (e = edf->edfadmit(t))
  641. error(e);
  642. }else if (strcmp(a, "besteffort") == 0){
  643. t->T = Infinity;
  644. t->D = Infinity;
  645. t->C = 0;
  646. t->flags |= BestEffort;
  647. if (e = edf->edfadmit(t))
  648. error(e);
  649. }else if (strcmp(a, "expel") == 0){
  650. edf->edfexpel(t);
  651. }else if (strcmp(a, "remove") == 0){
  652. removetask(t);
  653. poperror();
  654. qunlock(&edfschedlock);
  655. return n; /* Ignore any subsequent commands */
  656. }else if (strcmp(a, "verbose") == 0){
  657. if (t->flags & Verbose)
  658. t->flags &= ~Verbose;
  659. else
  660. t->flags |= Verbose;
  661. }else if (strcmp(a, "yieldonblock") == 0){
  662. if (v == nil)
  663. error("yieldonblock: value missing");
  664. if (add != 0)
  665. error("yieldonblock: cannot increment/decrement");
  666. if (atoi(v) == 0)
  667. t->flags &= ~Useblocking;
  668. else
  669. t->flags |= Useblocking;
  670. }else if (strcmp(a, "yield") == 0){
  671. if (edf->isedf(up) && up->task == t){
  672. edf->edfdeadline(up); /* schedule next release */
  673. qunlock(&edfschedlock);
  674. sched();
  675. qlock(&edfschedlock);
  676. }else
  677. error("yield outside task");
  678. }else
  679. error("unrecognized command");
  680. }
  681. poperror();
  682. qunlock(&edfschedlock);
  683. }
  684. return n;
  685. }
  686. static void
  687. devrtremove(Chan *c)
  688. {
  689. int s;
  690. Task *t;
  691. if ((c->qid.path & Qistask) == 0)
  692. error(Eperm);
  693. s = (ulong)c->qid.path & (Qistask - 1);
  694. t = findtask(s);
  695. if (t == nil)
  696. error(Enonexist);
  697. qlock(&edfschedlock);
  698. removetask(t);
  699. qunlock(&edfschedlock);
  700. }
  701. Dev realtimedevtab = {
  702. 'R',
  703. "scheduler",
  704. devreset,
  705. devrtinit,
  706. devshutdown,
  707. devrtattach,
  708. devrtwalk,
  709. devrtstat,
  710. devrtopen,
  711. devcreate,
  712. devrtclose,
  713. devrtread,
  714. devbread,
  715. devrtwrite,
  716. devbwrite,
  717. devrtremove,
  718. devwstat,
  719. };