github.com/xushiwei/go@v0.0.0-20130601165731-2b9d83f45bc9/src/pkg/runtime/os_darwin.c (about)

     1  // Copyright 2009 The Go Authors. All rights reserved.
     2  // Use of this source code is governed by a BSD-style
     3  // license that can be found in the LICENSE file.
     4  
     5  #include "runtime.h"
     6  #include "defs_GOOS_GOARCH.h"
     7  #include "os_GOOS.h"
     8  #include "signal_unix.h"
     9  #include "stack.h"
    10  
    11  extern SigTab runtime·sigtab[];
    12  
    13  static Sigset sigset_none;
    14  static Sigset sigset_all = ~(Sigset)0;
    15  static Sigset sigset_prof = 1<<(SIGPROF-1);
    16  
    17  static void
    18  unimplemented(int8 *name)
    19  {
    20  	runtime·prints(name);
    21  	runtime·prints(" not implemented\n");
    22  	*(int32*)1231 = 1231;
    23  }
    24  
    25  int32
    26  runtime·semasleep(int64 ns)
    27  {
    28  	int32 v;
    29  
    30  	if(m->profilehz > 0)
    31  		runtime·setprof(false);
    32  	v = runtime·mach_semacquire(m->waitsema, ns);
    33  	if(m->profilehz > 0)
    34  		runtime·setprof(true);
    35  	return v;
    36  }
    37  
    38  void
    39  runtime·semawakeup(M *mp)
    40  {
    41  	runtime·mach_semrelease(mp->waitsema);
    42  }
    43  
    44  uintptr
    45  runtime·semacreate(void)
    46  {
    47  	return runtime·mach_semcreate();
    48  }
    49  
    50  // BSD interface for threading.
    51  void
    52  runtime·osinit(void)
    53  {
    54  	// bsdthread_register delayed until end of goenvs so that we
    55  	// can look at the environment first.
    56  
    57  	// Use sysctl to fetch hw.ncpu.
    58  	uint32 mib[2];
    59  	uint32 out;
    60  	int32 ret;
    61  	uintptr nout;
    62  
    63  	mib[0] = 6;
    64  	mib[1] = 3;
    65  	nout = sizeof out;
    66  	out = 0;
    67  	ret = runtime·sysctl(mib, 2, (byte*)&out, &nout, nil, 0);
    68  	if(ret >= 0)
    69  		runtime·ncpu = out;
    70  }
    71  
    72  void
    73  runtime·get_random_data(byte **rnd, int32 *rnd_len)
    74  {
    75  	static byte urandom_data[HashRandomBytes];
    76  	int32 fd;
    77  	fd = runtime·open("/dev/urandom", 0 /* O_RDONLY */, 0);
    78  	if(runtime·read(fd, urandom_data, HashRandomBytes) == HashRandomBytes) {
    79  		*rnd = urandom_data;
    80  		*rnd_len = HashRandomBytes;
    81  	} else {
    82  		*rnd = nil;
    83  		*rnd_len = 0;
    84  	}
    85  	runtime·close(fd);
    86  }
    87  
    88  void
    89  runtime·goenvs(void)
    90  {
    91  	runtime·goenvs_unix();
    92  
    93  	// Register our thread-creation callback (see sys_darwin_{amd64,386}.s)
    94  	// but only if we're not using cgo.  If we are using cgo we need
    95  	// to let the C pthread library install its own thread-creation callback.
    96  	if(!runtime·iscgo) {
    97  		if(runtime·bsdthread_register() != 0) {
    98  			if(runtime·getenv("DYLD_INSERT_LIBRARIES"))
    99  				runtime·throw("runtime: bsdthread_register error (unset DYLD_INSERT_LIBRARIES)");
   100  			runtime·throw("runtime: bsdthread_register error");
   101  		}
   102  	}
   103  
   104  }
   105  
   106  void
   107  runtime·newosproc(M *mp, void *stk)
   108  {
   109  	int32 errno;
   110  	Sigset oset;
   111  
   112  	mp->tls[0] = mp->id;	// so 386 asm can find it
   113  	if(0){
   114  		runtime·printf("newosproc stk=%p m=%p g=%p id=%d/%d ostk=%p\n",
   115  			stk, mp, mp->g0, mp->id, (int32)mp->tls[0], &mp);
   116  	}
   117  
   118  	runtime·sigprocmask(SIG_SETMASK, &sigset_all, &oset);
   119  	errno = runtime·bsdthread_create(stk, mp, mp->g0, runtime·mstart);
   120  	runtime·sigprocmask(SIG_SETMASK, &oset, nil);
   121  
   122  	if(errno < 0) {
   123  		runtime·printf("runtime: failed to create new OS thread (have %d already; errno=%d)\n", runtime·mcount(), -errno);
   124  		runtime·throw("runtime.newosproc");
   125  	}
   126  }
   127  
   128  // Called to initialize a new m (including the bootstrap m).
   129  // Called on the parent thread (main thread in case of bootstrap), can allocate memory.
   130  void
   131  runtime·mpreinit(M *mp)
   132  {
   133  	mp->gsignal = runtime·malg(32*1024);	// OS X wants >=8K, Linux >=2K
   134  }
   135  
   136  // Called to initialize a new m (including the bootstrap m).
   137  // Called on the new thread, can not allocate memory.
   138  void
   139  runtime·minit(void)
   140  {
   141  	// Initialize signal handling.
   142  	runtime·signalstack((byte*)m->gsignal->stackguard - StackGuard, 32*1024);
   143  
   144  	runtime·sigprocmask(SIG_SETMASK, &sigset_none, nil);
   145  	runtime·setprof(m->profilehz > 0);
   146  }
   147  
   148  // Called from dropm to undo the effect of an minit.
   149  void
   150  runtime·unminit(void)
   151  {
   152  	runtime·signalstack(nil, 0);
   153  }
   154  
   155  // Mach IPC, to get at semaphores
   156  // Definitions are in /usr/include/mach on a Mac.
   157  
   158  static void
   159  macherror(int32 r, int8 *fn)
   160  {
   161  	runtime·printf("mach error %s: %d\n", fn, r);
   162  	runtime·throw("mach error");
   163  }
   164  
   165  enum
   166  {
   167  	DebugMach = 0
   168  };
   169  
   170  static MachNDR zerondr;
   171  
   172  #define MACH_MSGH_BITS(a, b) ((a) | ((b)<<8))
   173  
   174  static int32
   175  mach_msg(MachHeader *h,
   176  	int32 op,
   177  	uint32 send_size,
   178  	uint32 rcv_size,
   179  	uint32 rcv_name,
   180  	uint32 timeout,
   181  	uint32 notify)
   182  {
   183  	// TODO: Loop on interrupt.
   184  	return runtime·mach_msg_trap(h, op, send_size, rcv_size, rcv_name, timeout, notify);
   185  }
   186  
   187  // Mach RPC (MIG)
   188  
   189  enum
   190  {
   191  	MinMachMsg = 48,
   192  	Reply = 100,
   193  };
   194  
   195  #pragma pack on
   196  typedef struct CodeMsg CodeMsg;
   197  struct CodeMsg
   198  {
   199  	MachHeader h;
   200  	MachNDR NDR;
   201  	int32 code;
   202  };
   203  #pragma pack off
   204  
   205  static int32
   206  machcall(MachHeader *h, int32 maxsize, int32 rxsize)
   207  {
   208  	uint32 *p;
   209  	int32 i, ret, id;
   210  	uint32 port;
   211  	CodeMsg *c;
   212  
   213  	if((port = m->machport) == 0){
   214  		port = runtime·mach_reply_port();
   215  		m->machport = port;
   216  	}
   217  
   218  	h->msgh_bits |= MACH_MSGH_BITS(MACH_MSG_TYPE_COPY_SEND, MACH_MSG_TYPE_MAKE_SEND_ONCE);
   219  	h->msgh_local_port = port;
   220  	h->msgh_reserved = 0;
   221  	id = h->msgh_id;
   222  
   223  	if(DebugMach){
   224  		p = (uint32*)h;
   225  		runtime·prints("send:\t");
   226  		for(i=0; i<h->msgh_size/sizeof(p[0]); i++){
   227  			runtime·prints(" ");
   228  			runtime·printpointer((void*)p[i]);
   229  			if(i%8 == 7)
   230  				runtime·prints("\n\t");
   231  		}
   232  		if(i%8)
   233  			runtime·prints("\n");
   234  	}
   235  
   236  	ret = mach_msg(h, MACH_SEND_MSG|MACH_RCV_MSG,
   237  		h->msgh_size, maxsize, port, 0, 0);
   238  	if(ret != 0){
   239  		if(DebugMach){
   240  			runtime·prints("mach_msg error ");
   241  			runtime·printint(ret);
   242  			runtime·prints("\n");
   243  		}
   244  		return ret;
   245  	}
   246  
   247  	if(DebugMach){
   248  		p = (uint32*)h;
   249  		runtime·prints("recv:\t");
   250  		for(i=0; i<h->msgh_size/sizeof(p[0]); i++){
   251  			runtime·prints(" ");
   252  			runtime·printpointer((void*)p[i]);
   253  			if(i%8 == 7)
   254  				runtime·prints("\n\t");
   255  		}
   256  		if(i%8)
   257  			runtime·prints("\n");
   258  	}
   259  
   260  	if(h->msgh_id != id+Reply){
   261  		if(DebugMach){
   262  			runtime·prints("mach_msg reply id mismatch ");
   263  			runtime·printint(h->msgh_id);
   264  			runtime·prints(" != ");
   265  			runtime·printint(id+Reply);
   266  			runtime·prints("\n");
   267  		}
   268  		return -303;	// MIG_REPLY_MISMATCH
   269  	}
   270  
   271  	// Look for a response giving the return value.
   272  	// Any call can send this back with an error,
   273  	// and some calls only have return values so they
   274  	// send it back on success too.  I don't quite see how
   275  	// you know it's one of these and not the full response
   276  	// format, so just look if the message is right.
   277  	c = (CodeMsg*)h;
   278  	if(h->msgh_size == sizeof(CodeMsg)
   279  	&& !(h->msgh_bits & MACH_MSGH_BITS_COMPLEX)){
   280  		if(DebugMach){
   281  			runtime·prints("mig result ");
   282  			runtime·printint(c->code);
   283  			runtime·prints("\n");
   284  		}
   285  		return c->code;
   286  	}
   287  
   288  	if(h->msgh_size != rxsize){
   289  		if(DebugMach){
   290  			runtime·prints("mach_msg reply size mismatch ");
   291  			runtime·printint(h->msgh_size);
   292  			runtime·prints(" != ");
   293  			runtime·printint(rxsize);
   294  			runtime·prints("\n");
   295  		}
   296  		return -307;	// MIG_ARRAY_TOO_LARGE
   297  	}
   298  
   299  	return 0;
   300  }
   301  
   302  
   303  // Semaphores!
   304  
   305  enum
   306  {
   307  	Tmach_semcreate = 3418,
   308  	Rmach_semcreate = Tmach_semcreate + Reply,
   309  
   310  	Tmach_semdestroy = 3419,
   311  	Rmach_semdestroy = Tmach_semdestroy + Reply,
   312  
   313  	// Mach calls that get interrupted by Unix signals
   314  	// return this error code.  We retry them.
   315  	KERN_ABORTED = 14,
   316  	KERN_OPERATION_TIMED_OUT = 49,
   317  };
   318  
   319  typedef struct Tmach_semcreateMsg Tmach_semcreateMsg;
   320  typedef struct Rmach_semcreateMsg Rmach_semcreateMsg;
   321  typedef struct Tmach_semdestroyMsg Tmach_semdestroyMsg;
   322  // Rmach_semdestroyMsg = CodeMsg
   323  
   324  #pragma pack on
   325  struct Tmach_semcreateMsg
   326  {
   327  	MachHeader h;
   328  	MachNDR ndr;
   329  	int32 policy;
   330  	int32 value;
   331  };
   332  
   333  struct Rmach_semcreateMsg
   334  {
   335  	MachHeader h;
   336  	MachBody body;
   337  	MachPort semaphore;
   338  };
   339  
   340  struct Tmach_semdestroyMsg
   341  {
   342  	MachHeader h;
   343  	MachBody body;
   344  	MachPort semaphore;
   345  };
   346  #pragma pack off
   347  
   348  uint32
   349  runtime·mach_semcreate(void)
   350  {
   351  	union {
   352  		Tmach_semcreateMsg tx;
   353  		Rmach_semcreateMsg rx;
   354  		uint8 pad[MinMachMsg];
   355  	} m;
   356  	int32 r;
   357  
   358  	m.tx.h.msgh_bits = 0;
   359  	m.tx.h.msgh_size = sizeof(m.tx);
   360  	m.tx.h.msgh_remote_port = runtime·mach_task_self();
   361  	m.tx.h.msgh_id = Tmach_semcreate;
   362  	m.tx.ndr = zerondr;
   363  
   364  	m.tx.policy = 0;	// 0 = SYNC_POLICY_FIFO
   365  	m.tx.value = 0;
   366  
   367  	while((r = machcall(&m.tx.h, sizeof m, sizeof(m.rx))) != 0){
   368  		if(r == KERN_ABORTED)	// interrupted
   369  			continue;
   370  		macherror(r, "semaphore_create");
   371  	}
   372  	if(m.rx.body.msgh_descriptor_count != 1)
   373  		unimplemented("mach_semcreate desc count");
   374  	return m.rx.semaphore.name;
   375  }
   376  
   377  void
   378  runtime·mach_semdestroy(uint32 sem)
   379  {
   380  	union {
   381  		Tmach_semdestroyMsg tx;
   382  		uint8 pad[MinMachMsg];
   383  	} m;
   384  	int32 r;
   385  
   386  	m.tx.h.msgh_bits = MACH_MSGH_BITS_COMPLEX;
   387  	m.tx.h.msgh_size = sizeof(m.tx);
   388  	m.tx.h.msgh_remote_port = runtime·mach_task_self();
   389  	m.tx.h.msgh_id = Tmach_semdestroy;
   390  	m.tx.body.msgh_descriptor_count = 1;
   391  	m.tx.semaphore.name = sem;
   392  	m.tx.semaphore.disposition = MACH_MSG_TYPE_MOVE_SEND;
   393  	m.tx.semaphore.type = 0;
   394  
   395  	while((r = machcall(&m.tx.h, sizeof m, 0)) != 0){
   396  		if(r == KERN_ABORTED)	// interrupted
   397  			continue;
   398  		macherror(r, "semaphore_destroy");
   399  	}
   400  }
   401  
   402  // The other calls have simple system call traps in sys_darwin_{amd64,386}.s
   403  int32 runtime·mach_semaphore_wait(uint32 sema);
   404  int32 runtime·mach_semaphore_timedwait(uint32 sema, uint32 sec, uint32 nsec);
   405  int32 runtime·mach_semaphore_signal(uint32 sema);
   406  int32 runtime·mach_semaphore_signal_all(uint32 sema);
   407  
   408  int32
   409  runtime·mach_semacquire(uint32 sem, int64 ns)
   410  {
   411  	int32 r;
   412  	int64 secs;
   413  
   414  	if(ns >= 0) {
   415  		secs = ns/1000000000LL;
   416  		// Avoid overflow
   417  		if(secs > 1LL<<30)
   418  			secs = 1LL<<30;
   419  		r = runtime·mach_semaphore_timedwait(sem, secs, ns%1000000000LL);
   420  		if(r == KERN_ABORTED || r == KERN_OPERATION_TIMED_OUT)
   421  			return -1;
   422  		if(r != 0)
   423  			macherror(r, "semaphore_wait");
   424  		return 0;
   425  	}
   426  	while((r = runtime·mach_semaphore_wait(sem)) != 0) {
   427  		if(r == KERN_ABORTED)	// interrupted
   428  			continue;
   429  		macherror(r, "semaphore_wait");
   430  	}
   431  	return 0;
   432  }
   433  
   434  void
   435  runtime·mach_semrelease(uint32 sem)
   436  {
   437  	int32 r;
   438  
   439  	while((r = runtime·mach_semaphore_signal(sem)) != 0) {
   440  		if(r == KERN_ABORTED)	// interrupted
   441  			continue;
   442  		macherror(r, "semaphore_signal");
   443  	}
   444  }
   445  
   446  void
   447  runtime·sigpanic(void)
   448  {
   449  	switch(g->sig) {
   450  	case SIGBUS:
   451  		if(g->sigcode0 == BUS_ADRERR && g->sigcode1 < 0x1000) {
   452  			if(g->sigpc == 0)
   453  				runtime·panicstring("call of nil func value");
   454  			runtime·panicstring("invalid memory address or nil pointer dereference");
   455  		}
   456  		runtime·printf("unexpected fault address %p\n", g->sigcode1);
   457  		runtime·throw("fault");
   458  	case SIGSEGV:
   459  		if((g->sigcode0 == 0 || g->sigcode0 == SEGV_MAPERR || g->sigcode0 == SEGV_ACCERR) && g->sigcode1 < 0x1000) {
   460  			if(g->sigpc == 0)
   461  				runtime·panicstring("call of nil func value");
   462  			runtime·panicstring("invalid memory address or nil pointer dereference");
   463  		}
   464  		runtime·printf("unexpected fault address %p\n", g->sigcode1);
   465  		runtime·throw("fault");
   466  	case SIGFPE:
   467  		switch(g->sigcode0) {
   468  		case FPE_INTDIV:
   469  			runtime·panicstring("integer divide by zero");
   470  		case FPE_INTOVF:
   471  			runtime·panicstring("integer overflow");
   472  		}
   473  		runtime·panicstring("floating point error");
   474  	}
   475  	runtime·panicstring(runtime·sigtab[g->sig].name);
   476  }
   477  
   478  #pragma textflag 7
   479  void
   480  runtime·osyield(void)
   481  {
   482  	runtime·usleep(1);
   483  }
   484  
   485  uintptr
   486  runtime·memlimit(void)
   487  {
   488  	// NOTE(rsc): Could use getrlimit here,
   489  	// like on FreeBSD or Linux, but Darwin doesn't enforce
   490  	// ulimit -v, so it's unclear why we'd try to stay within
   491  	// the limit.
   492  	return 0;
   493  }
   494  
   495  // NOTE(rsc): On OS X, when the CPU profiling timer expires, the SIGPROF
   496  // signal is not guaranteed to be sent to the thread that was executing to
   497  // cause it to expire.  It can and often does go to a sleeping thread, which is
   498  // not interesting for our profile.  This is filed Apple Bug Report #9177434,
   499  // copied to http://code.google.com/p/go/source/detail?r=35b716c94225.
   500  // To work around this bug, we disable receipt of the profiling signal on
   501  // a thread while in blocking system calls.  This forces the kernel to deliver
   502  // the profiling signal to an executing thread.
   503  //
   504  // The workaround fails on OS X machines using a 64-bit Snow Leopard kernel.
   505  // In that configuration, the kernel appears to want to deliver SIGPROF to the
   506  // sleeping threads regardless of signal mask and, worse, does not deliver
   507  // the signal until the thread wakes up on its own.
   508  //
   509  // If necessary, we can switch to using ITIMER_REAL for OS X and handle
   510  // the kernel-generated SIGALRM by generating our own SIGALRMs to deliver
   511  // to all the running threads.  SIGALRM does not appear to be affected by
   512  // the 64-bit Snow Leopard bug.  However, as of this writing Mountain Lion
   513  // is in preview, making Snow Leopard two versions old, so it is unclear how
   514  // much effort we need to spend on one buggy kernel.
   515  
   516  // Control whether profiling signal can be delivered to this thread.
   517  void
   518  runtime·setprof(bool on)
   519  {
   520  	if(on)
   521  		runtime·sigprocmask(SIG_UNBLOCK, &sigset_prof, nil);
   522  	else
   523  		runtime·sigprocmask(SIG_BLOCK, &sigset_prof, nil);
   524  }
   525  
   526  static int8 badcallback[] = "runtime: cgo callback on thread not created by Go.\n";
   527  
   528  // This runs on a foreign stack, without an m or a g.  No stack split.
   529  #pragma textflag 7
   530  void
   531  runtime·badcallback(void)
   532  {
   533  	runtime·write(2, badcallback, sizeof badcallback - 1);
   534  }
   535  
   536  static int8 badsignal[] = "runtime: signal received on thread not created by Go: ";
   537  
   538  // This runs on a foreign stack, without an m or a g.  No stack split.
   539  #pragma textflag 7
   540  void
   541  runtime·badsignal(int32 sig)
   542  {
   543  	int32 len;
   544  
   545  	if (sig == SIGPROF) {
   546  		return;  // Ignore SIGPROFs intended for a non-Go thread.
   547  	}
   548  	runtime·write(2, badsignal, sizeof badsignal - 1);
   549  	if (0 <= sig && sig < NSIG) {
   550  		// Can't call findnull() because it will split stack.
   551  		for(len = 0; runtime·sigtab[sig].name[len]; len++)
   552  			;
   553  		runtime·write(2, runtime·sigtab[sig].name, len);
   554  	}
   555  	runtime·write(2, "\n", 1);
   556  	runtime·exit(1);
   557  }
   558  
   559  void
   560  runtime·setsig(int32 i, GoSighandler *fn, bool restart)
   561  {
   562  	Sigaction sa;
   563  		
   564  	runtime·memclr((byte*)&sa, sizeof sa);
   565  	sa.sa_flags = SA_SIGINFO|SA_ONSTACK;
   566  	if(restart)
   567  		sa.sa_flags |= SA_RESTART;
   568  	sa.sa_mask = ~(uintptr)0;
   569  	sa.sa_tramp = (void*)runtime·sigtramp;	// runtime·sigtramp's job is to call into real handler
   570  	*(uintptr*)sa.__sigaction_u = (uintptr)fn;
   571  	runtime·sigaction(i, &sa, nil);
   572  }
   573  
   574  GoSighandler*
   575  runtime·getsig(int32 i)
   576  {
   577  	Sigaction sa;
   578  
   579  	runtime·memclr((byte*)&sa, sizeof sa);
   580  	runtime·sigaction(i, nil, &sa);
   581  	return *(void**)sa.__sigaction_u;
   582  }
   583  
   584  void
   585  runtime·signalstack(byte *p, int32 n)
   586  {
   587  	StackT st;
   588  
   589  	st.ss_sp = (void*)p;
   590  	st.ss_size = n;
   591  	st.ss_flags = 0;
   592  	if(p == nil)
   593  		st.ss_flags = SS_DISABLE;
   594  	runtime·sigaltstack(&st, nil);
   595  }