irix.c 7.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571
  1. /*
  2. * Irix specific thread implementation for drawterm.
  3. * Mostly culled from Irix Inferno and Windows drawterm.
  4. */
  5. #include <sched.h>
  6. #include <pthread.h>
  7. #include <unistd.h>
  8. #include <errno.h>
  9. #include <stdio.h>
  10. #include <time.h>
  11. #include <sys/prctl.h>
  12. #include <ulocks.h>
  13. #include <termios.h>
  14. #include <sigfpe.h>
  15. #include <sys/fpu.h>
  16. #include <sys/cachectl.h>
  17. #undef _POSIX_SOURCE /* SGI incompetence */
  18. #include <signal.h>
  19. #define _BSD_TIME
  20. /* for gettimeofday(), which isn't POSIX,
  21. * but is fairly common
  22. */
  23. #include <sys/time.h>
  24. #define _POSIX_SOURCE
  25. #include <pwd.h>
  26. #include <sys/stat.h>
  27. #include <sys/ustat.h>
  28. #define _BSD_EXTENSION
  29. #include "lib9.h"
  30. #include "sys.h"
  31. #include "error.h"
  32. typedef struct Ttbl Ttbl;
  33. typedef struct Thread Thread;
  34. static pthread_key_t prdakey;
  35. static Thread* tcurthread(void);
  36. #define CT tcurthread()
  37. enum {
  38. Nthread = 100,
  39. Nerrlbl = 30,
  40. KSTACK = 32*1024,
  41. Nsema = 32,
  42. };
  43. struct Thread {
  44. int tss;
  45. int tindex;
  46. Thread *qnext; /* for qlock */
  47. int nerrlbl;
  48. Jump errlbl[Nerrlbl];
  49. char error[ERRLEN];
  50. void (*f)(void*);
  51. void *a;
  52. int sema[2];
  53. /* for sleep/wakeup/intr */
  54. Lock rlock;
  55. Rendez *r;
  56. int intr;
  57. pthread_t pthread;
  58. };
  59. struct Ttbl {
  60. Lock lk;
  61. int nthread;
  62. int nalloc;
  63. Thread *t[Nthread];
  64. Thread *free;
  65. };
  66. char *argv0;
  67. static Ttbl tt;
  68. static Thread *threadalloc(void);
  69. static void threadfree(Thread *t);
  70. static void tramp(void *p, size_t);
  71. static void threadsleep(void);
  72. static void threadwakeup(Thread *t);
  73. static void
  74. setsema(Thread *t)
  75. {
  76. char c;
  77. if(pipe(t->sema) < 0)
  78. fatal("pipe failed: %r");
  79. c = 'L';
  80. }
  81. void
  82. handler(int s)
  83. {
  84. _exits("sigkill");
  85. }
  86. void
  87. loophandler(int s)
  88. {
  89. fprintf(stderr, "signal %d to %ld; looping\n", s, getpid());
  90. for(;;)
  91. p9sleep(0);
  92. }
  93. void
  94. threadinit(void)
  95. {
  96. int nsem, i;
  97. Thread *t;
  98. setpgrp();
  99. signal(SIGQUIT, handler);
  100. signal(SIGTERM, handler);
  101. signal(SIGCHLD, SIG_IGN);
  102. signal(SIGSEGV, loophandler);
  103. if(pthread_key_create(&prdakey, 0))
  104. fatal("keycreate failed");
  105. t = threadalloc();
  106. assert(t != 0);
  107. if(pthread_setspecific(prdakey, t))
  108. fatal("cannot set CT");
  109. setsema(t);
  110. }
  111. int
  112. thread(char *name, void (*f)(void *), void *a)
  113. {
  114. Thread *t;
  115. if((t = threadalloc()) == 0)
  116. return -1;
  117. t->f = f;
  118. t->a = a;
  119. if(pthread_create(&t->pthread, nil, tramp, t)){
  120. oserror();
  121. fatal("thr_create failed: %d %d %r", errno, thread);
  122. }
  123. sched_yield();
  124. return t->tindex;
  125. }
  126. void
  127. threadexit(void)
  128. {
  129. if(tt.nthread == 1)
  130. exits("normal");
  131. threadfree(CT);
  132. pthread_setspecific(prdakey, nil);
  133. pthread_exit(0);
  134. }
  135. static void
  136. tramp(void *p, size_t s)
  137. {
  138. Thread *t;
  139. t = (Thread*)p;
  140. if(pthread_setspecific(prdakey, t))
  141. fatal("cannot set CT in tramp");
  142. setsema(t);
  143. (*t->f)(t->a);
  144. threadexit();
  145. }
  146. int
  147. errstr(char *s)
  148. {
  149. char tmp[ERRLEN];
  150. Thread *t;
  151. t = CT;
  152. if(t == nil){
  153. strcpy(s, "unknown error");
  154. return 0;
  155. }
  156. strncpy(tmp, s, ERRLEN);
  157. strncpy(s, t->error, ERRLEN);
  158. strncpy(t->error, tmp, ERRLEN);
  159. return 0;
  160. }
  161. char *
  162. threaderr(void)
  163. {
  164. return CT->error;
  165. }
  166. /*
  167. * Threadsleep, threadwakeup depend on the fact
  168. * that there is one threadwakeup for each threadsleep.
  169. * It is allowed to come before, but there must be
  170. * only one.
  171. *
  172. * I hope this is okay. -rsc
  173. */
  174. static void
  175. threadsleep(void)
  176. {
  177. char c;
  178. if(read(CT->sema[0], &c, 1) != 1){
  179. oserror();
  180. fatal("threadsleep fails: %r");
  181. }
  182. }
  183. static void
  184. threadwakeup(Thread *t)
  185. {
  186. char c;
  187. c = 'L';
  188. if(write(t->sema[1], &c, 1) != 1){
  189. oserror();
  190. fatal("threadwakeup fails: %r");
  191. }
  192. }
  193. static Thread *
  194. threadalloc(void)
  195. {
  196. Thread *t;
  197. lock(&tt.lk);
  198. tt.nthread++;
  199. if((t = tt.free) != 0) {
  200. tt.free = t->qnext;
  201. unlock(&tt.lk);
  202. return t;
  203. }
  204. if(tt.nalloc == Nthread) {
  205. unlock(&tt.lk);
  206. return 0;
  207. }
  208. t = tt.t[tt.nalloc] = mallocz(sizeof(Thread));
  209. t->tindex = tt.nalloc;
  210. tt.nalloc++;
  211. unlock(&tt.lk);
  212. return t;
  213. }
  214. static void
  215. threadfree(Thread *t)
  216. {
  217. lock(&tt.lk);
  218. tt.nthread--;
  219. t->qnext = tt.free;
  220. tt.free = t;
  221. unlock(&tt.lk);
  222. }
  223. long
  224. p9sleep(long milli)
  225. {
  226. static int tick;
  227. if(!tick)
  228. tick = CLK_TCK;
  229. sginap((tick*milli)/1000);
  230. return 0;
  231. }
  232. void
  233. _exits(char *s)
  234. {
  235. if(s && *s)
  236. fprintf(stderr, "exits: %s\n", s);
  237. exit(0);
  238. }
  239. void
  240. nexterror(void)
  241. {
  242. int n;
  243. Thread *t;
  244. t = CT;
  245. n = --t->nerrlbl;
  246. if(n < 0)
  247. fatal("error: %r");
  248. longjmp(t->errlbl[n].buf, 1);
  249. }
  250. void
  251. error(char *fmt, ...)
  252. {
  253. char buf[ERRLEN];
  254. if(fmt) {
  255. doprint(buf, buf+sizeof(buf), (char*)fmt, (&fmt+1));
  256. errstr(buf);
  257. }
  258. nexterror();
  259. }
  260. void
  261. poperror(void)
  262. {
  263. Thread *t;
  264. t = CT;
  265. if(t->nerrlbl <= 0)
  266. fatal("error stack underflow");
  267. t->nerrlbl--;
  268. }
  269. Jump*
  270. pm_waserror(void)
  271. {
  272. Thread *t;
  273. int n;
  274. t = CT;
  275. n = t->nerrlbl++;
  276. if(n >= Nerrlbl)
  277. fatal("error stack underflow");
  278. return &t->errlbl[n];
  279. }
  280. void
  281. oserror(void)
  282. {
  283. char *p;
  284. char buf[ERRLEN];
  285. if((p = (char*)sys_errlist[errno]))
  286. strncpy(buf, p, ERRLEN);
  287. else
  288. sprint(buf, "unix error %d", errno);
  289. errstr(buf);
  290. setbuf(stderr, 0);
  291. fprintf(stderr, "error: %s\n", threaderr());
  292. }
  293. static void
  294. queue(Thread **first, Thread **last)
  295. {
  296. Thread *t;
  297. Thread *ct;
  298. ct = CT;
  299. t = *last;
  300. if(t == 0)
  301. *first = ct;
  302. else
  303. t->qnext = ct;
  304. *last = ct;
  305. ct->qnext = 0;
  306. }
  307. static Thread *
  308. dequeue(Thread **first, Thread **last)
  309. {
  310. Thread *t;
  311. t = *first;
  312. if(t == 0)
  313. return 0;
  314. *first = t->qnext;
  315. if(*first == 0)
  316. *last = 0;
  317. return t;
  318. }
  319. void
  320. qlock(Qlock *q)
  321. {
  322. lock(&q->lk);
  323. if(q->hold == 0) {
  324. q->hold = CT;
  325. unlock(&q->lk);
  326. return;
  327. }
  328. /*
  329. * Can't assert this because of RWLock
  330. assert(q->hold != CT);
  331. */
  332. queue((Thread**)&q->first, (Thread**)&q->last);
  333. unlock(&q->lk);
  334. threadsleep();
  335. }
  336. int
  337. canqlock(Qlock *q)
  338. {
  339. lock(&q->lk);
  340. if(q->hold == 0) {
  341. q->hold = CT;
  342. unlock(&q->lk);
  343. return 1;
  344. }
  345. unlock(&q->lk);
  346. return 0;
  347. }
  348. void
  349. qunlock(Qlock *q)
  350. {
  351. Thread *t;
  352. lock(&q->lk);
  353. assert(q->hold == CT);
  354. t = dequeue((Thread**)&q->first, (Thread**)&q->last);
  355. if(t) {
  356. q->hold = t;
  357. unlock(&q->lk);
  358. threadwakeup(t);
  359. } else {
  360. q->hold = 0;
  361. unlock(&q->lk);
  362. }
  363. }
  364. int
  365. holdqlock(Qlock *q)
  366. {
  367. return q->hold == CT;
  368. }
  369. void
  370. rendsleep(Rendez *r, int (*f)(void*), void *arg)
  371. {
  372. lock(&CT->rlock);
  373. CT->r = r;
  374. unlock(&CT->rlock);
  375. lock(&r->l);
  376. /*
  377. * if condition happened, never mind
  378. */
  379. if(CT->intr || f(arg)){
  380. unlock(&r->l);
  381. goto Done;
  382. }
  383. /*
  384. * now we are committed to
  385. * change state and call scheduler
  386. */
  387. if(r->t)
  388. fatal("double sleep");
  389. r->t = CT;
  390. unlock(&r->l);
  391. threadsleep();
  392. Done:
  393. lock(&CT->rlock);
  394. CT->r = 0;
  395. if(CT->intr) {
  396. CT->intr = 0;
  397. unlock(&CT->rlock);
  398. error(Eintr);
  399. }
  400. unlock(&CT->rlock);
  401. }
  402. void
  403. rendwakeup(Rendez *r)
  404. {
  405. Thread *t;
  406. lock(&r->l);
  407. t = r->t;
  408. if(t) {
  409. r->t = 0;
  410. threadwakeup(t);
  411. }
  412. unlock(&r->l);
  413. }
  414. void
  415. intr(void *v)
  416. {
  417. Thread *t;
  418. t = v;
  419. lock(&t->rlock);
  420. t->intr = 1;
  421. if(t->r)
  422. rendwakeup(t->r);
  423. unlock(&t->rlock);
  424. }
  425. void
  426. clearintr(void)
  427. {
  428. lock(&CT->rlock);
  429. CT->intr = 0;
  430. unlock(&CT->rlock);
  431. }
  432. int
  433. ticks(void)
  434. {
  435. static long sec0 = 0, usec0;
  436. struct timeval t;
  437. if(gettimeofday(&t, nil) < 0)
  438. return 0;
  439. if(sec0 == 0){
  440. sec0 = t.tv_sec;
  441. usec0 = t.tv_usec;
  442. }
  443. return (t.tv_sec-sec0)*1000+(t.tv_usec-usec0+500)/1000;
  444. }
  445. void
  446. abort(void)
  447. {
  448. fprintf(stderr, "abort %ld\n", getpid());
  449. for(;;) sleep(1);
  450. *((ulong*)0)=0;
  451. }
  452. Thread*
  453. tcurthread(void)
  454. {
  455. void *v;
  456. if((v = pthread_getspecific(prdakey)) == nil)
  457. fatal("cannot getspecific");
  458. return v;
  459. }
  460. void*
  461. curthread(void)
  462. {
  463. return tcurthread();
  464. }
  465. void
  466. osfillproc(Proc *up)
  467. {
  468. up->uid = getuid();
  469. up->gid = getgid();
  470. }
  471. void
  472. osprocfill(Proc *up)
  473. {
  474. up->uid = getuid();
  475. up->gid = getgid();
  476. }