github.com/spotify/syslog-redirector-golang@v0.0.0-20140320174030-4859f03d829a/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  #include "../../cmd/ld/textflag.h"
    11  
    12  extern SigTab runtime·sigtab[];
    13  
    14  static Sigset sigset_none;
    15  static Sigset sigset_all = ~(Sigset)0;
    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  void
    26  runtime·semawakeup(M *mp)
    27  {
    28  	runtime·mach_semrelease(mp->waitsema);
    29  }
    30  
    31  uintptr
    32  runtime·semacreate(void)
    33  {
    34  	return runtime·mach_semcreate();
    35  }
    36  
    37  // BSD interface for threading.
    38  void
    39  runtime·osinit(void)
    40  {
    41  	// bsdthread_register delayed until end of goenvs so that we
    42  	// can look at the environment first.
    43  
    44  	// Use sysctl to fetch hw.ncpu.
    45  	uint32 mib[2];
    46  	uint32 out;
    47  	int32 ret;
    48  	uintptr nout;
    49  
    50  	mib[0] = 6;
    51  	mib[1] = 3;
    52  	nout = sizeof out;
    53  	out = 0;
    54  	ret = runtime·sysctl(mib, 2, (byte*)&out, &nout, nil, 0);
    55  	if(ret >= 0)
    56  		runtime·ncpu = out;
    57  }
    58  
    59  void
    60  runtime·get_random_data(byte **rnd, int32 *rnd_len)
    61  {
    62  	static byte urandom_data[HashRandomBytes];
    63  	int32 fd;
    64  	fd = runtime·open("/dev/urandom", 0 /* O_RDONLY */, 0);
    65  	if(runtime·read(fd, urandom_data, HashRandomBytes) == HashRandomBytes) {
    66  		*rnd = urandom_data;
    67  		*rnd_len = HashRandomBytes;
    68  	} else {
    69  		*rnd = nil;
    70  		*rnd_len = 0;
    71  	}
    72  	runtime·close(fd);
    73  }
    74  
    75  void
    76  runtime·goenvs(void)
    77  {
    78  	runtime·goenvs_unix();
    79  
    80  	// Register our thread-creation callback (see sys_darwin_{amd64,386}.s)
    81  	// but only if we're not using cgo.  If we are using cgo we need
    82  	// to let the C pthread library install its own thread-creation callback.
    83  	if(!runtime·iscgo) {
    84  		if(runtime·bsdthread_register() != 0) {
    85  			if(runtime·getenv("DYLD_INSERT_LIBRARIES"))
    86  				runtime·throw("runtime: bsdthread_register error (unset DYLD_INSERT_LIBRARIES)");
    87  			runtime·throw("runtime: bsdthread_register error");
    88  		}
    89  	}
    90  
    91  }
    92  
    93  void
    94  runtime·newosproc(M *mp, void *stk)
    95  {
    96  	int32 errno;
    97  	Sigset oset;
    98  
    99  	mp->tls[0] = mp->id;	// so 386 asm can find it
   100  	if(0){
   101  		runtime·printf("newosproc stk=%p m=%p g=%p id=%d/%d ostk=%p\n",
   102  			stk, mp, mp->g0, mp->id, (int32)mp->tls[0], &mp);
   103  	}
   104  
   105  	runtime·sigprocmask(SIG_SETMASK, &sigset_all, &oset);
   106  	errno = runtime·bsdthread_create(stk, mp, mp->g0, runtime·mstart);
   107  	runtime·sigprocmask(SIG_SETMASK, &oset, nil);
   108  
   109  	if(errno < 0) {
   110  		runtime·printf("runtime: failed to create new OS thread (have %d already; errno=%d)\n", runtime·mcount(), -errno);
   111  		runtime·throw("runtime.newosproc");
   112  	}
   113  }
   114  
   115  // Called to initialize a new m (including the bootstrap m).
   116  // Called on the parent thread (main thread in case of bootstrap), can allocate memory.
   117  void
   118  runtime·mpreinit(M *mp)
   119  {
   120  	mp->gsignal = runtime·malg(32*1024);	// OS X wants >=8K, Linux >=2K
   121  }
   122  
   123  // Called to initialize a new m (including the bootstrap m).
   124  // Called on the new thread, can not allocate memory.
   125  void
   126  runtime·minit(void)
   127  {
   128  	// Initialize signal handling.
   129  	runtime·signalstack((byte*)m->gsignal->stackguard - StackGuard, 32*1024);
   130  
   131  	runtime·sigprocmask(SIG_SETMASK, &sigset_none, nil);
   132  }
   133  
   134  // Called from dropm to undo the effect of an minit.
   135  void
   136  runtime·unminit(void)
   137  {
   138  	runtime·signalstack(nil, 0);
   139  }
   140  
   141  // Mach IPC, to get at semaphores
   142  // Definitions are in /usr/include/mach on a Mac.
   143  
   144  #pragma textflag NOSPLIT
   145  static void
   146  macherror(int32 r, int8 *fn)
   147  {
   148  	runtime·prints("mach error ");
   149  	runtime·prints(fn);
   150  	runtime·prints(": ");
   151  	runtime·printint(r);
   152  	runtime·prints("\n");
   153  	runtime·throw("mach error");
   154  }
   155  
   156  enum
   157  {
   158  	DebugMach = 0
   159  };
   160  
   161  static MachNDR zerondr;
   162  
   163  #define MACH_MSGH_BITS(a, b) ((a) | ((b)<<8))
   164  
   165  static int32
   166  mach_msg(MachHeader *h,
   167  	int32 op,
   168  	uint32 send_size,
   169  	uint32 rcv_size,
   170  	uint32 rcv_name,
   171  	uint32 timeout,
   172  	uint32 notify)
   173  {
   174  	// TODO: Loop on interrupt.
   175  	return runtime·mach_msg_trap(h, op, send_size, rcv_size, rcv_name, timeout, notify);
   176  }
   177  
   178  // Mach RPC (MIG)
   179  
   180  enum
   181  {
   182  	MinMachMsg = 48,
   183  	Reply = 100,
   184  };
   185  
   186  #pragma pack on
   187  typedef struct CodeMsg CodeMsg;
   188  struct CodeMsg
   189  {
   190  	MachHeader h;
   191  	MachNDR NDR;
   192  	int32 code;
   193  };
   194  #pragma pack off
   195  
   196  static int32
   197  machcall(MachHeader *h, int32 maxsize, int32 rxsize)
   198  {
   199  	uint32 *p;
   200  	int32 i, ret, id;
   201  	uint32 port;
   202  	CodeMsg *c;
   203  
   204  	if((port = m->machport) == 0){
   205  		port = runtime·mach_reply_port();
   206  		m->machport = port;
   207  	}
   208  
   209  	h->msgh_bits |= MACH_MSGH_BITS(MACH_MSG_TYPE_COPY_SEND, MACH_MSG_TYPE_MAKE_SEND_ONCE);
   210  	h->msgh_local_port = port;
   211  	h->msgh_reserved = 0;
   212  	id = h->msgh_id;
   213  
   214  	if(DebugMach){
   215  		p = (uint32*)h;
   216  		runtime·prints("send:\t");
   217  		for(i=0; i<h->msgh_size/sizeof(p[0]); i++){
   218  			runtime·prints(" ");
   219  			runtime·printpointer((void*)p[i]);
   220  			if(i%8 == 7)
   221  				runtime·prints("\n\t");
   222  		}
   223  		if(i%8)
   224  			runtime·prints("\n");
   225  	}
   226  
   227  	ret = mach_msg(h, MACH_SEND_MSG|MACH_RCV_MSG,
   228  		h->msgh_size, maxsize, port, 0, 0);
   229  	if(ret != 0){
   230  		if(DebugMach){
   231  			runtime·prints("mach_msg error ");
   232  			runtime·printint(ret);
   233  			runtime·prints("\n");
   234  		}
   235  		return ret;
   236  	}
   237  
   238  	if(DebugMach){
   239  		p = (uint32*)h;
   240  		runtime·prints("recv:\t");
   241  		for(i=0; i<h->msgh_size/sizeof(p[0]); i++){
   242  			runtime·prints(" ");
   243  			runtime·printpointer((void*)p[i]);
   244  			if(i%8 == 7)
   245  				runtime·prints("\n\t");
   246  		}
   247  		if(i%8)
   248  			runtime·prints("\n");
   249  	}
   250  
   251  	if(h->msgh_id != id+Reply){
   252  		if(DebugMach){
   253  			runtime·prints("mach_msg reply id mismatch ");
   254  			runtime·printint(h->msgh_id);
   255  			runtime·prints(" != ");
   256  			runtime·printint(id+Reply);
   257  			runtime·prints("\n");
   258  		}
   259  		return -303;	// MIG_REPLY_MISMATCH
   260  	}
   261  
   262  	// Look for a response giving the return value.
   263  	// Any call can send this back with an error,
   264  	// and some calls only have return values so they
   265  	// send it back on success too.  I don't quite see how
   266  	// you know it's one of these and not the full response
   267  	// format, so just look if the message is right.
   268  	c = (CodeMsg*)h;
   269  	if(h->msgh_size == sizeof(CodeMsg)
   270  	&& !(h->msgh_bits & MACH_MSGH_BITS_COMPLEX)){
   271  		if(DebugMach){
   272  			runtime·prints("mig result ");
   273  			runtime·printint(c->code);
   274  			runtime·prints("\n");
   275  		}
   276  		return c->code;
   277  	}
   278  
   279  	if(h->msgh_size != rxsize){
   280  		if(DebugMach){
   281  			runtime·prints("mach_msg reply size mismatch ");
   282  			runtime·printint(h->msgh_size);
   283  			runtime·prints(" != ");
   284  			runtime·printint(rxsize);
   285  			runtime·prints("\n");
   286  		}
   287  		return -307;	// MIG_ARRAY_TOO_LARGE
   288  	}
   289  
   290  	return 0;
   291  }
   292  
   293  
   294  // Semaphores!
   295  
   296  enum
   297  {
   298  	Tmach_semcreate = 3418,
   299  	Rmach_semcreate = Tmach_semcreate + Reply,
   300  
   301  	Tmach_semdestroy = 3419,
   302  	Rmach_semdestroy = Tmach_semdestroy + Reply,
   303  
   304  	// Mach calls that get interrupted by Unix signals
   305  	// return this error code.  We retry them.
   306  	KERN_ABORTED = 14,
   307  	KERN_OPERATION_TIMED_OUT = 49,
   308  };
   309  
   310  typedef struct Tmach_semcreateMsg Tmach_semcreateMsg;
   311  typedef struct Rmach_semcreateMsg Rmach_semcreateMsg;
   312  typedef struct Tmach_semdestroyMsg Tmach_semdestroyMsg;
   313  // Rmach_semdestroyMsg = CodeMsg
   314  
   315  #pragma pack on
   316  struct Tmach_semcreateMsg
   317  {
   318  	MachHeader h;
   319  	MachNDR ndr;
   320  	int32 policy;
   321  	int32 value;
   322  };
   323  
   324  struct Rmach_semcreateMsg
   325  {
   326  	MachHeader h;
   327  	MachBody body;
   328  	MachPort semaphore;
   329  };
   330  
   331  struct Tmach_semdestroyMsg
   332  {
   333  	MachHeader h;
   334  	MachBody body;
   335  	MachPort semaphore;
   336  };
   337  #pragma pack off
   338  
   339  uint32
   340  runtime·mach_semcreate(void)
   341  {
   342  	union {
   343  		Tmach_semcreateMsg tx;
   344  		Rmach_semcreateMsg rx;
   345  		uint8 pad[MinMachMsg];
   346  	} m;
   347  	int32 r;
   348  
   349  	m.tx.h.msgh_bits = 0;
   350  	m.tx.h.msgh_size = sizeof(m.tx);
   351  	m.tx.h.msgh_remote_port = runtime·mach_task_self();
   352  	m.tx.h.msgh_id = Tmach_semcreate;
   353  	m.tx.ndr = zerondr;
   354  
   355  	m.tx.policy = 0;	// 0 = SYNC_POLICY_FIFO
   356  	m.tx.value = 0;
   357  
   358  	while((r = machcall(&m.tx.h, sizeof m, sizeof(m.rx))) != 0){
   359  		if(r == KERN_ABORTED)	// interrupted
   360  			continue;
   361  		macherror(r, "semaphore_create");
   362  	}
   363  	if(m.rx.body.msgh_descriptor_count != 1)
   364  		unimplemented("mach_semcreate desc count");
   365  	return m.rx.semaphore.name;
   366  }
   367  
   368  void
   369  runtime·mach_semdestroy(uint32 sem)
   370  {
   371  	union {
   372  		Tmach_semdestroyMsg tx;
   373  		uint8 pad[MinMachMsg];
   374  	} m;
   375  	int32 r;
   376  
   377  	m.tx.h.msgh_bits = MACH_MSGH_BITS_COMPLEX;
   378  	m.tx.h.msgh_size = sizeof(m.tx);
   379  	m.tx.h.msgh_remote_port = runtime·mach_task_self();
   380  	m.tx.h.msgh_id = Tmach_semdestroy;
   381  	m.tx.body.msgh_descriptor_count = 1;
   382  	m.tx.semaphore.name = sem;
   383  	m.tx.semaphore.disposition = MACH_MSG_TYPE_MOVE_SEND;
   384  	m.tx.semaphore.type = 0;
   385  
   386  	while((r = machcall(&m.tx.h, sizeof m, 0)) != 0){
   387  		if(r == KERN_ABORTED)	// interrupted
   388  			continue;
   389  		macherror(r, "semaphore_destroy");
   390  	}
   391  }
   392  
   393  // The other calls have simple system call traps in sys_darwin_{amd64,386}.s
   394  int32 runtime·mach_semaphore_wait(uint32 sema);
   395  int32 runtime·mach_semaphore_timedwait(uint32 sema, uint32 sec, uint32 nsec);
   396  int32 runtime·mach_semaphore_signal(uint32 sema);
   397  int32 runtime·mach_semaphore_signal_all(uint32 sema);
   398  
   399  #pragma textflag NOSPLIT
   400  int32
   401  runtime·semasleep(int64 ns)
   402  {
   403  	int32 r, secs, nsecs;
   404  
   405  	if(ns >= 0) {
   406  		secs = runtime·timediv(ns, 1000000000, &nsecs);
   407  		r = runtime·mach_semaphore_timedwait(m->waitsema, secs, nsecs);
   408  		if(r == KERN_ABORTED || r == KERN_OPERATION_TIMED_OUT)
   409  			return -1;
   410  		if(r != 0)
   411  			macherror(r, "semaphore_wait");
   412  		return 0;
   413  	}
   414  	while((r = runtime·mach_semaphore_wait(m->waitsema)) != 0) {
   415  		if(r == KERN_ABORTED)	// interrupted
   416  			continue;
   417  		macherror(r, "semaphore_wait");
   418  	}
   419  	return 0;
   420  }
   421  
   422  void
   423  runtime·mach_semrelease(uint32 sem)
   424  {
   425  	int32 r;
   426  
   427  	while((r = runtime·mach_semaphore_signal(sem)) != 0) {
   428  		if(r == KERN_ABORTED)	// interrupted
   429  			continue;
   430  		macherror(r, "semaphore_signal");
   431  	}
   432  }
   433  
   434  void
   435  runtime·sigpanic(void)
   436  {
   437  	switch(g->sig) {
   438  	case SIGBUS:
   439  		if(g->sigcode0 == BUS_ADRERR && g->sigcode1 < 0x1000) {
   440  			if(g->sigpc == 0)
   441  				runtime·panicstring("call of nil func value");
   442  			runtime·panicstring("invalid memory address or nil pointer dereference");
   443  		}
   444  		runtime·printf("unexpected fault address %p\n", g->sigcode1);
   445  		runtime·throw("fault");
   446  	case SIGSEGV:
   447  		if((g->sigcode0 == 0 || g->sigcode0 == SEGV_MAPERR || g->sigcode0 == SEGV_ACCERR) && g->sigcode1 < 0x1000) {
   448  			if(g->sigpc == 0)
   449  				runtime·panicstring("call of nil func value");
   450  			runtime·panicstring("invalid memory address or nil pointer dereference");
   451  		}
   452  		runtime·printf("unexpected fault address %p\n", g->sigcode1);
   453  		runtime·throw("fault");
   454  	case SIGFPE:
   455  		switch(g->sigcode0) {
   456  		case FPE_INTDIV:
   457  			runtime·panicstring("integer divide by zero");
   458  		case FPE_INTOVF:
   459  			runtime·panicstring("integer overflow");
   460  		}
   461  		runtime·panicstring("floating point error");
   462  	}
   463  	runtime·panicstring(runtime·sigtab[g->sig].name);
   464  }
   465  
   466  #pragma textflag NOSPLIT
   467  void
   468  runtime·osyield(void)
   469  {
   470  	runtime·usleep(1);
   471  }
   472  
   473  uintptr
   474  runtime·memlimit(void)
   475  {
   476  	// NOTE(rsc): Could use getrlimit here,
   477  	// like on FreeBSD or Linux, but Darwin doesn't enforce
   478  	// ulimit -v, so it's unclear why we'd try to stay within
   479  	// the limit.
   480  	return 0;
   481  }
   482  
   483  void
   484  runtime·setsig(int32 i, GoSighandler *fn, bool restart)
   485  {
   486  	Sigaction sa;
   487  		
   488  	runtime·memclr((byte*)&sa, sizeof sa);
   489  	sa.sa_flags = SA_SIGINFO|SA_ONSTACK;
   490  	if(restart)
   491  		sa.sa_flags |= SA_RESTART;
   492  	sa.sa_mask = ~(uintptr)0;
   493  	sa.sa_tramp = (void*)runtime·sigtramp;	// runtime·sigtramp's job is to call into real handler
   494  	*(uintptr*)sa.__sigaction_u = (uintptr)fn;
   495  	runtime·sigaction(i, &sa, nil);
   496  }
   497  
   498  GoSighandler*
   499  runtime·getsig(int32 i)
   500  {
   501  	Sigaction sa;
   502  
   503  	runtime·memclr((byte*)&sa, sizeof sa);
   504  	runtime·sigaction(i, nil, &sa);
   505  	return *(void**)sa.__sigaction_u;
   506  }
   507  
   508  void
   509  runtime·signalstack(byte *p, int32 n)
   510  {
   511  	StackT st;
   512  
   513  	st.ss_sp = (void*)p;
   514  	st.ss_size = n;
   515  	st.ss_flags = 0;
   516  	if(p == nil)
   517  		st.ss_flags = SS_DISABLE;
   518  	runtime·sigaltstack(&st, nil);
   519  }