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

     1  // Copyright 2011 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  extern int32 runtime·sys_umtx_op(uint32*, int32, uint32, void*, void*);
    13  
    14  // From FreeBSD's <sys/sysctl.h>
    15  #define	CTL_HW	6
    16  #define	HW_NCPU	3
    17  
    18  static Sigset sigset_none;
    19  static Sigset sigset_all = { ~(uint32)0, ~(uint32)0, ~(uint32)0, ~(uint32)0, };
    20  
    21  static int32
    22  getncpu(void)
    23  {
    24  	uint32 mib[2];
    25  	uint32 out;
    26  	int32 ret;
    27  	uintptr nout;
    28  
    29  	// Fetch hw.ncpu via sysctl.
    30  	mib[0] = CTL_HW;
    31  	mib[1] = HW_NCPU;
    32  	nout = sizeof out;
    33  	out = 0;
    34  	ret = runtime·sysctl(mib, 2, (byte*)&out, &nout, nil, 0);
    35  	if(ret >= 0)
    36  		return out;
    37  	else
    38  		return 1;
    39  }
    40  
    41  // FreeBSD's umtx_op syscall is effectively the same as Linux's futex, and
    42  // thus the code is largely similar. See linux/thread.c and lock_futex.c for comments.
    43  
    44  void
    45  runtime·futexsleep(uint32 *addr, uint32 val, int64 ns)
    46  {
    47  	int32 ret;
    48  	Timespec ts, *tsp;
    49  	int64 secs;
    50  
    51  	if(ns < 0)
    52  		tsp = nil;
    53  	else {
    54  		secs = ns / 1000000000LL;
    55  		// Avoid overflow
    56  		if(secs > 1LL<<30)
    57  			secs = 1LL<<30;
    58  		ts.tv_sec = secs;
    59  		ts.tv_nsec = ns % 1000000000LL;
    60  		tsp = &ts;
    61  	}
    62  
    63  	ret = runtime·sys_umtx_op(addr, UMTX_OP_WAIT_UINT, val, nil, tsp);
    64  	if(ret >= 0 || ret == -EINTR)
    65  		return;
    66  
    67  	runtime·printf("umtx_wait addr=%p val=%d ret=%d\n", addr, val, ret);
    68  	*(int32*)0x1005 = 0x1005;
    69  }
    70  
    71  void
    72  runtime·futexwakeup(uint32 *addr, uint32 cnt)
    73  {
    74  	int32 ret;
    75  
    76  	ret = runtime·sys_umtx_op(addr, UMTX_OP_WAKE, cnt, nil, nil);
    77  	if(ret >= 0)
    78  		return;
    79  
    80  	runtime·printf("umtx_wake addr=%p ret=%d\n", addr, ret);
    81  	*(int32*)0x1006 = 0x1006;
    82  }
    83  
    84  void runtime·thr_start(void*);
    85  
    86  void
    87  runtime·newosproc(M *mp, void *stk)
    88  {
    89  	ThrParam param;
    90  	Sigset oset;
    91  
    92  	if(0){
    93  		runtime·printf("newosproc stk=%p m=%p g=%p id=%d/%d ostk=%p\n",
    94  			stk, mp, mp->g0, mp->id, (int32)mp->tls[0], &mp);
    95  	}
    96  
    97  	runtime·sigprocmask(&sigset_all, &oset);
    98  	runtime·memclr((byte*)&param, sizeof param);
    99  
   100  	param.start_func = runtime·thr_start;
   101  	param.arg = (byte*)mp;
   102  	
   103  	// NOTE(rsc): This code is confused. stackbase is the top of the stack
   104  	// and is equal to stk. However, it's working, so I'm not changing it.
   105  	param.stack_base = (void*)mp->g0->stackbase;
   106  	param.stack_size = (byte*)stk - (byte*)mp->g0->stackbase;
   107  
   108  	param.child_tid = (intptr*)&mp->procid;
   109  	param.parent_tid = nil;
   110  	param.tls_base = (void*)&mp->tls[0];
   111  	param.tls_size = sizeof mp->tls;
   112  
   113  	mp->tls[0] = mp->id;	// so 386 asm can find it
   114  
   115  	runtime·thr_new(&param, sizeof param);
   116  	runtime·sigprocmask(&oset, nil);
   117  }
   118  
   119  void
   120  runtime·osinit(void)
   121  {
   122  	runtime·ncpu = getncpu();
   123  }
   124  
   125  void
   126  runtime·get_random_data(byte **rnd, int32 *rnd_len)
   127  {
   128  	static byte urandom_data[HashRandomBytes];
   129  	int32 fd;
   130  	fd = runtime·open("/dev/urandom", 0 /* O_RDONLY */, 0);
   131  	if(runtime·read(fd, urandom_data, HashRandomBytes) == HashRandomBytes) {
   132  		*rnd = urandom_data;
   133  		*rnd_len = HashRandomBytes;
   134  	} else {
   135  		*rnd = nil;
   136  		*rnd_len = 0;
   137  	}
   138  	runtime·close(fd);
   139  }
   140  
   141  void
   142  runtime·goenvs(void)
   143  {
   144  	runtime·goenvs_unix();
   145  }
   146  
   147  // Called to initialize a new m (including the bootstrap m).
   148  // Called on the parent thread (main thread in case of bootstrap), can allocate memory.
   149  void
   150  runtime·mpreinit(M *mp)
   151  {
   152  	mp->gsignal = runtime·malg(32*1024);
   153  }
   154  
   155  // Called to initialize a new m (including the bootstrap m).
   156  // Called on the new thread, can not allocate memory.
   157  void
   158  runtime·minit(void)
   159  {
   160  	// Initialize signal handling
   161  	runtime·signalstack((byte*)m->gsignal->stackguard - StackGuard, 32*1024);
   162  	runtime·sigprocmask(&sigset_none, nil);
   163  }
   164  
   165  // Called from dropm to undo the effect of an minit.
   166  void
   167  runtime·unminit(void)
   168  {
   169  	runtime·signalstack(nil, 0);
   170  }
   171  
   172  void
   173  runtime·sigpanic(void)
   174  {
   175  	switch(g->sig) {
   176  	case SIGBUS:
   177  		if(g->sigcode0 == BUS_ADRERR && g->sigcode1 < 0x1000) {
   178  			if(g->sigpc == 0)
   179  				runtime·panicstring("call of nil func value");
   180  			runtime·panicstring("invalid memory address or nil pointer dereference");
   181  		}
   182  		runtime·printf("unexpected fault address %p\n", g->sigcode1);
   183  		runtime·throw("fault");
   184  	case SIGSEGV:
   185  		if((g->sigcode0 == 0 || g->sigcode0 == SEGV_MAPERR || g->sigcode0 == SEGV_ACCERR) && g->sigcode1 < 0x1000) {
   186  			if(g->sigpc == 0)
   187  				runtime·panicstring("call of nil func value");
   188  			runtime·panicstring("invalid memory address or nil pointer dereference");
   189  		}
   190  		runtime·printf("unexpected fault address %p\n", g->sigcode1);
   191  		runtime·throw("fault");
   192  	case SIGFPE:
   193  		switch(g->sigcode0) {
   194  		case FPE_INTDIV:
   195  			runtime·panicstring("integer divide by zero");
   196  		case FPE_INTOVF:
   197  			runtime·panicstring("integer overflow");
   198  		}
   199  		runtime·panicstring("floating point error");
   200  	}
   201  	runtime·panicstring(runtime·sigtab[g->sig].name);
   202  }
   203  
   204  uintptr
   205  runtime·memlimit(void)
   206  {
   207  	Rlimit rl;
   208  	extern byte text[], end[];
   209  	uintptr used;
   210  	
   211  	if(runtime·getrlimit(RLIMIT_AS, &rl) != 0)
   212  		return 0;
   213  	if(rl.rlim_cur >= 0x7fffffff)
   214  		return 0;
   215  
   216  	// Estimate our VM footprint excluding the heap.
   217  	// Not an exact science: use size of binary plus
   218  	// some room for thread stacks.
   219  	used = end - text + (64<<20);
   220  	if(used >= rl.rlim_cur)
   221  		return 0;
   222  
   223  	// If there's not at least 16 MB left, we're probably
   224  	// not going to be able to do much.  Treat as no limit.
   225  	rl.rlim_cur -= used;
   226  	if(rl.rlim_cur < (16<<20))
   227  		return 0;
   228  
   229  	return rl.rlim_cur - used;
   230  }
   231  
   232  void
   233  runtime·setprof(bool on)
   234  {
   235  	USED(on);
   236  }
   237  
   238  static int8 badcallback[] = "runtime: cgo callback on thread not created by Go.\n";
   239  
   240  // This runs on a foreign stack, without an m or a g.  No stack split.
   241  #pragma textflag 7
   242  void
   243  runtime·badcallback(void)
   244  {
   245  	runtime·write(2, badcallback, sizeof badcallback - 1);
   246  }
   247  
   248  static int8 badsignal[] = "runtime: signal received on thread not created by Go: ";
   249  
   250  // This runs on a foreign stack, without an m or a g.  No stack split.
   251  #pragma textflag 7
   252  void
   253  runtime·badsignal(int32 sig)
   254  {
   255  	int32 len;
   256  
   257  	if (sig == SIGPROF) {
   258  		return;  // Ignore SIGPROFs intended for a non-Go thread.
   259  	}
   260  	runtime·write(2, badsignal, sizeof badsignal - 1);
   261  	if (0 <= sig && sig < NSIG) {
   262  		// Can't call findnull() because it will split stack.
   263  		for(len = 0; runtime·sigtab[sig].name[len]; len++)
   264  			;
   265  		runtime·write(2, runtime·sigtab[sig].name, len);
   266  	}
   267  	runtime·write(2, "\n", 1);
   268  	runtime·exit(1);
   269  }
   270  
   271  extern void runtime·sigtramp(void);
   272  
   273  typedef struct sigaction {
   274  	union {
   275  		void    (*__sa_handler)(int32);
   276  		void    (*__sa_sigaction)(int32, Siginfo*, void *);
   277  	} __sigaction_u;		/* signal handler */
   278  	int32	sa_flags;		/* see signal options below */
   279  	Sigset	sa_mask;		/* signal mask to apply */
   280  } Sigaction;
   281  
   282  void
   283  runtime·setsig(int32 i, GoSighandler *fn, bool restart)
   284  {
   285  	Sigaction sa;
   286  
   287  	runtime·memclr((byte*)&sa, sizeof sa);
   288  	sa.sa_flags = SA_SIGINFO|SA_ONSTACK;
   289  	if(restart)
   290  		sa.sa_flags |= SA_RESTART;
   291  	sa.sa_mask.__bits[0] = ~(uint32)0;
   292  	sa.sa_mask.__bits[1] = ~(uint32)0;
   293  	sa.sa_mask.__bits[2] = ~(uint32)0;
   294  	sa.sa_mask.__bits[3] = ~(uint32)0;
   295  	if(fn == runtime·sighandler)
   296  		fn = (void*)runtime·sigtramp;
   297  	sa.__sigaction_u.__sa_sigaction = (void*)fn;
   298  	runtime·sigaction(i, &sa, nil);
   299  }
   300  
   301  GoSighandler*
   302  runtime·getsig(int32 i)
   303  {
   304  	Sigaction sa;
   305  
   306  	runtime·memclr((byte*)&sa, sizeof sa);
   307  	runtime·sigaction(i, nil, &sa);
   308  	if((void*)sa.__sigaction_u.__sa_sigaction == runtime·sigtramp)
   309  		return runtime·sighandler;
   310  	return (void*)sa.__sigaction_u.__sa_sigaction;
   311  }
   312  
   313  void
   314  runtime·signalstack(byte *p, int32 n)
   315  {
   316  	StackT st;
   317  
   318  	st.ss_sp = (void*)p;
   319  	st.ss_size = n;
   320  	st.ss_flags = 0;
   321  	if(p == nil)
   322  		st.ss_flags = SS_DISABLE;
   323  	runtime·sigaltstack(&st, nil);
   324  }