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