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