xref: /inferno-os/emu/MacOSX/os.c (revision 37da2899f40661e3e9631e497da8dc59b971cbd0)
1 /*
2  * Loosely based on FreeBSD/os.c and Solaris/os.c
3  * Copyright © 1998, 1999 Lucent Technologies Inc.  All rights reserved.
4  * Revisions Copyright © 1999, 2000 Vita Nuova Limited.  All rights reserved.
5  * Revisions Copyright © 2002, 2003 Corpus Callosum Corporation.  All rights reserved.
6  */
7 
8 #include	"dat.h"
9 #include	"fns.h"
10 #include	"error.h"
11 
12 #undef _POSIX_C_SOURCE
13 #undef getwd
14 
15 #include	<unistd.h>
16 #include        <pthread.h>
17 #include	<time.h>
18 #include	<termios.h>
19 #include	<signal.h>
20 #include	<pwd.h>
21 #include	<sys/resource.h>
22 #include	<sys/time.h>
23 
24 #include 	<sys/socket.h>
25 #include	<sched.h>
26 #include	<errno.h>
27 #include        <sys/ucontext.h>
28 
29 #include <sys/types.h>
30 #include <sys/stat.h>
31 
32 #include <mach/mach_init.h>
33 #include <mach/task.h>
34 #include <mach/vm_map.h>
35 
36 #if defined(__ppc__)
37 #include <architecture/ppc/cframe.h>
38 #endif
39 
40 enum
41 {
42     DELETE = 0x7F
43 };
44 char *hosttype = "MacOSX";
45 char *cputype = "power";
46 
47 static pthread_key_t  prdakey;
48 
49 extern int dflag;
50 
51 Proc *
52 getup(void) {
53     return (Proc *)pthread_getspecific(prdakey);
54 }
55 
56 /*  Pthread version */
57 void
58 pexit(char *msg, int t)
59 {
60     Osenv *e;
61     Proc *p;
62 
63     USED(t);
64     USED(msg);
65 
66     lock(&procs.l);
67     p = up;
68     if(p->prev)
69         p->prev->next = p->next;
70     else
71         procs.head = p->next;
72 
73     if(p->next)
74         p->next->prev = p->prev;
75     else
76         procs.tail = p->prev;
77     unlock(&procs.l);
78 
79     if(0)
80         print("pexit: %s: %s\n", p->text, msg);
81 
82     e = p->env;
83     if(e != nil) {
84         closefgrp(e->fgrp);
85         closepgrp(e->pgrp);
86         closeegrp(e->egrp);
87         closesigs(e->sigs);
88     }
89     free(e->user);
90     free(p->prog);
91     free(p);
92     pthread_exit(0);
93 }
94 
95 void
96 trapBUS(int signo)
97 {
98     USED(signo);
99     disfault(nil, "Bus error");
100 }
101 
102 void
103 trapUSR1(int signo)
104 {
105     USED(signo);
106 
107     if(up->type != Interp)      /* Used to unblock pending I/O */
108         return;
109     if(up->intwait == 0)        /* Not posted so its a sync error */
110         disfault(nil, Eintr);	/* Should never happen */
111 
112     up->intwait = 0;		/* Clear it so the proc can continue */
113 }
114 
115 void
116 trapILL(int signo)
117 {
118     USED(signo);
119     disfault(nil, "Illegal instruction");
120 }
121 
122 /* from geoff collyer's port */
123 void
124 printILL(int sig, siginfo_t *siginfo, void *v)
125 {
126     USED(sig);
127     USED(v);
128     panic("Illegal instruction with code=%d at address=%x, opcode=%x.\n"
129         ,siginfo->si_code, siginfo->si_addr,*(char*)siginfo->si_addr);
130 }
131 
132 void
133 trapSEGV(int signo)
134 {
135     USED(signo);
136     disfault(nil, "Segmentation violation");
137 }
138 
139 void
140 trapFPE(int signo)
141 {
142     USED(signo);
143     disfault(nil, "Floating point exception");
144 }
145 
146 static void
147 setsigs(void)
148 {
149     struct sigaction act;
150 
151     memset(&act, 0 , sizeof(act));
152 
153     /*
154      * For the correct functioning of devcmd in the
155      * face of exiting slaves
156      */
157     signal(SIGPIPE, SIG_IGN);
158     if(signal(SIGTERM, SIG_IGN) != SIG_IGN)
159         signal(SIGTERM, cleanexit);
160 
161     act.sa_handler=trapUSR1;
162     sigaction(SIGUSR1, &act, nil);
163 
164     if(sflag == 0) {
165         act.sa_handler = trapBUS;
166         sigaction(SIGBUS, &act, nil);
167         act.sa_handler = trapILL;
168         sigaction(SIGILL, &act, nil);
169         act.sa_handler = trapSEGV;
170         sigaction(SIGSEGV, &act, nil);
171         act.sa_handler = trapFPE;
172         sigaction(SIGFPE, &act, nil);
173         if(signal(SIGINT, SIG_IGN) != SIG_IGN)
174             signal(SIGINT, cleanexit);
175     } else {
176         act.sa_sigaction = printILL;
177         act.sa_flags=SA_SIGINFO;
178         sigaction(SIGILL, &act, nil);
179     }
180 }
181 
182 
183 void *
184 tramp(void *arg)
185 {
186     Proc *p = arg;
187     p->sigid = (int)pthread_self();
188     if(pthread_setspecific(prdakey, arg)) {
189         print("set specific data failed in tramp\n");
190         pthread_exit(0);
191     }
192     p->func(p->arg);
193     pexit("{Tramp}", 0);
194     return NULL;
195 }
196 
197 int
198 kproc(char *name, void (*func)(void*), void *arg, int flags)
199 {
200     pthread_t thread;
201     Proc *p;
202     Pgrp *pg;
203     Fgrp *fg;
204     Egrp *eg;
205 
206     pthread_attr_t attr;
207 
208     p = newproc();
209     if(p == nil)
210         panic("kproc: no memory");
211 
212     if(flags & KPDUPPG) {
213         pg = up->env->pgrp;
214         incref(&pg->r);
215         p->env->pgrp = pg;
216     }
217     if(flags & KPDUPFDG) {
218         fg = up->env->fgrp;
219         incref(&fg->r);
220         p->env->fgrp = fg;
221     }
222     if(flags & KPDUPENVG) {
223         eg = up->env->egrp;
224         incref(&eg->r);
225         p->env->egrp = eg;
226     }
227 
228     p->env->uid = up->env->uid;
229     p->env->gid = up->env->gid;
230     kstrdup(&p->env->user, up->env->user);
231 
232     strcpy(p->text, name);
233 
234     p->func = func;
235     p->arg = arg;
236 
237     lock(&procs.l);
238     if(procs.tail != nil) {
239         p->prev = procs.tail;
240         procs.tail->next = p;
241     } else {
242         procs.head = p;
243         p->prev = nil;
244     }
245     procs.tail = p;
246     unlock(&procs.l);
247 
248     up->kid = p;
249 
250     if((pthread_attr_init(&attr))== -1)
251         panic("pthread_attr_init failed");
252 
253     errno=0;
254     pthread_attr_setschedpolicy(&attr,SCHED_OTHER);
255     if(errno)
256         panic("pthread_attr_setschedpolicy failed");
257 
258     pthread_attr_setinheritsched(&attr, PTHREAD_INHERIT_SCHED);
259     pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
260 
261     if(pthread_create(&thread, &attr, tramp, p))
262         panic("thr_create failed\n");
263     pthread_attr_destroy(&attr);
264 
265     return (int)thread;
266 }
267 
268 int
269 segflush(void *va, ulong len)
270 {
271     kern_return_t   err;
272     vm_machine_attribute_val_t value = MATTR_VAL_ICACHE_FLUSH;
273 
274     err = vm_machine_attribute( (vm_map_t)mach_task_self(),
275                                 (vm_address_t)va,
276                                 (vm_size_t)len,
277                                 MATTR_CACHE,
278                                 &value);
279     if (err != KERN_SUCCESS) {
280         print("segflush: failure (%d) address %lud\n", err, va);
281     }
282     return (int)err;
283 }
284 
285 /* from geoff collyer's port
286 invalidate instruction cache and write back data cache from a to a+n-1,
287 at least.
288 
289 void
290 segflush(void *a, ulong n)
291 {
292     ulong *p;
293 
294     // paranoia, flush the world
295     __asm__("isync\n\t"
296             "eieio\n\t"
297             : // no output
298             :
299             );
300     // cache blocks are often eight words (32 bytes) long, sometimes 16 bytes.
301     // need to determine it dynamically?
302     for (p = (ulong *)((ulong)a & ~3UL); (char *)p < (char *)a + n; p++)
303         __asm__("dcbst	0,%0\n\t"	// not dcbf, which writes back, then invalidates
304             "icbi	0,%0\n\t"
305             : // no output
306             : "ar" (p)
307             );
308     __asm__("isync\n\t"
309             "eieio\n\t"
310             : // no output
311             :
312             );
313 }
314 */
315 
316 void
317 oshostintr(Proc *p)
318 {
319     pthread_kill((pthread_t)p->sigid, SIGUSR1);
320 }
321 
322 static ulong erendezvous(void*, ulong);
323 
324 void
325 osblock(void)
326 {
327     erendezvous(up, 0);
328 }
329 
330 void
331 osready(Proc *p)
332 {
333     erendezvous(p, 0);
334 }
335 
336 void
337 oslongjmp(void *regs, osjmpbuf env, int val)
338 {
339     USED(regs);
340     siglongjmp(env, val);
341 }
342 
343 struct termios tinit;
344 
345 static void
346 termset(void)
347 {
348     struct termios t;
349 
350     tcgetattr(0, &t);
351     tinit = t;
352     t.c_lflag &= ~(ICANON|ECHO|ISIG);
353     t.c_cc[VMIN] = 1;
354     t.c_cc[VTIME] = 0;
355     tcsetattr(0, TCSANOW, &t);
356 }
357 
358 static void
359 termrestore(void)
360 {
361     tcsetattr(0, TCSANOW, &tinit);
362 }
363 
364 
365 void
366 cleanexit(int x)
367 {
368     USED(x);
369 
370     if(up->intwait) {
371         up->intwait = 0;
372         return;
373     }
374 
375     if(dflag == 0)
376         termrestore();
377 
378     exit(0);
379 }
380 
381 void
382 osreboot(char *file, char **argv)
383 {
384     if(dflag == 0)
385         termrestore();
386     execvp(file, argv);
387     panic("reboot failure");
388 }
389 
390 int gidnobody= -1, uidnobody= -1;
391 
392 void
393 getnobody()
394 {
395     struct passwd *pwd;
396 
397     if((pwd = getpwnam("nobody"))) {
398         uidnobody = pwd->pw_uid;
399         gidnobody = pwd->pw_gid;
400     }
401 }
402 
403 /* Pthread version */
404 static	pthread_mutex_t rendezvouslock;
405 static	pthread_mutexattr_t	*pthread_mutexattr_default = NULL;
406 
407 void
408 libinit(char *imod)
409 {
410     struct passwd *pw;
411     Proc *p;
412     char sys[64];
413 
414     setsid();
415 
416     // setup personality
417     gethostname(sys, sizeof(sys));
418     kstrdup(&ossysname, sys);
419     getnobody();
420 
421     if(dflag == 0)
422         termset();
423 
424     setsigs();
425 
426     if(pthread_mutex_init(&rendezvouslock, pthread_mutexattr_default))
427          panic("pthread_mutex_init");
428 
429     if(pthread_key_create(&prdakey,NULL))
430         print("key_create failed\n");
431 
432     p = newproc();
433     if(pthread_setspecific(prdakey, p))
434         panic("set specific thread data failed\n");
435 
436     pw = getpwuid(getuid());
437     if(pw != nil)
438         kstrdup(&eve, pw->pw_name);
439     else
440         print("cannot getpwuid\n");
441 
442     up->env->uid = getuid();
443     up->env->gid = getgid();
444 
445     emuinit(imod);
446 }
447 
448 int
449 readkbd(void)
450 {
451     int n;
452     char buf[1];
453 
454     n = read(0, buf, sizeof(buf));
455     if(n < 0)
456         print("keyboard close (n=%d, %s)\n", n, strerror(errno));
457     if(n <= 0)
458         pexit("keyboard thread", 0);
459 
460     switch(buf[0]) {
461         case '\r':
462             buf[0] = '\n';
463             break;
464         case DELETE:
465             cleanexit(0);
466             break;
467     }
468     return buf[0];
469 }
470 
471 enum
472 {
473     NHLOG	= 7,
474     NHASH	= (1<<NHLOG)
475 };
476 
477 typedef struct Tag Tag;
478 struct Tag
479 {
480     void*	tag;
481     ulong	val;
482     pthread_cond_t cv;
483     Tag*	next;
484 };
485 
486 static	Tag*	ht[NHASH];
487 static	Tag*	ft;
488 //static	Lock	hlock;
489 
490 static ulong
491 erendezvous(void *tag, ulong value)
492 {
493     int h;
494     ulong rval;
495     Tag *t, **l, *f;
496 
497     h = (ulong)tag & (NHASH-1);
498 
499 //    lock(&hlock);
500     pthread_mutex_lock(&rendezvouslock);
501     l = &ht[h];
502     for(t = ht[h]; t; t = t->next) {
503         if(t->tag == tag) {
504             rval = t->val;
505             t->val = value;
506             t->tag = 0;
507             pthread_mutex_unlock(&rendezvouslock);
508 //            unlock(&hlock);
509             if(pthread_cond_signal(&(t->cv)))
510                 panic("pthread_cond_signal");
511             return rval;
512         }
513     }
514 
515     t = ft;
516     if(t == 0) {
517         t = malloc(sizeof(Tag));
518         if(t == nil)
519             panic("rendezvous: no memory");
520         if(pthread_cond_init(&(t->cv), NULL)) {
521             print("pthread_cond_init (errno: %s) \n", strerror(errno));
522             panic("pthread_cond_init");
523         }
524     } else
525         ft = t->next;
526 
527     t->tag = tag;
528     t->val = value;
529     t->next = *l;
530     *l = t;
531 //    pthread_mutex_unlock(&rendezvouslock);
532 //    unlock(&hlock);
533 
534     while(t->tag != nil)
535         pthread_cond_wait(&(t->cv),&rendezvouslock);
536 
537 //    pthread_mutex_lock(&rendezvouslock);
538 //    lock(&hlock);
539     rval = t->val;
540     for(f = *l; f; f = f->next){
541         if(f == t) {
542             *l = f->next;
543             break;
544         }
545         l = &f->next;
546     }
547     t->next = ft;
548     ft = t;
549     pthread_mutex_unlock(&rendezvouslock);
550 //    unlock(&hlock);
551 
552     return rval;
553 }
554 
555 /*
556  * Return an abitrary millisecond clock time
557  */
558 long
559 osmillisec(void)
560 {
561     static long sec0 = 0, usec0;
562     struct timeval t;
563 
564     if(gettimeofday(&t, NULL)<0)
565         return(0);
566     if(sec0==0) {
567         sec0 = t.tv_sec;
568         usec0 = t.tv_usec;
569     }
570     return((t.tv_sec-sec0)*1000+(t.tv_usec-usec0+500)/1000);
571 }
572 
573 /*
574  * Return the time since the epoch in nanoseconds and microseconds
575  * The epoch is defined at 1 Jan 1970
576  */
577 vlong
578 osnsec(void)
579 {
580 	struct timeval t;
581 
582 	gettimeofday(&t, nil);
583 	return (vlong)t.tv_sec*1000000000L + t.tv_usec*1000;
584 }
585 
586 vlong
587 osusectime(void)
588 {
589     struct timeval t;
590 
591     gettimeofday(&t, nil);
592     return (vlong)t.tv_sec * 1000000 + t.tv_usec;
593 }
594 
595 
596 int
597 osmillisleep(ulong milsec)
598 {
599     struct  timespec time;
600     time.tv_sec = milsec / 1000;
601     time.tv_nsec = (milsec % 1000) * 1000000;
602     nanosleep(&time, nil);
603     return 0;
604 }
605 
606 int
607 limbosleep(ulong milsec)
608 {
609     return osmillisleep(milsec);
610 }
611 
612 void
613 osyield(void)
614 {
615     pthread_yield_np();
616     // sched_yield();
617 }
618 
619 void
620 ospause(void)
621 {
622     for(;;)
623         pause();
624 }
625 
626 void
627 oslopri(void)
628 {
629 //  pthread_setschedparam(pthread_t thread,  int policy, const struct sched_param *param);
630     setpriority(PRIO_PROCESS, 0, getpriority(PRIO_PROCESS,0)+4);
631 }
632 
633 __typeof__(sbrk(0))
634 sbrk(int size)
635 {
636     void *brk;
637     kern_return_t   err;
638 
639     err = vm_allocate( (vm_map_t) mach_task_self(),
640                        (vm_address_t *)&brk,
641                        size,
642                        VM_FLAGS_ANYWHERE);
643     if (err != KERN_SUCCESS)
644         brk = (void*)-1;
645 
646     return brk;
647 }
648