github.com/akaros/go-akaros@v0.0.0-20181004170632-85005d477eab/src/runtime/os_netbsd.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  #include "textflag.h"
    11  
    12  enum
    13  {
    14  	ESRCH = 3,
    15  	ENOTSUP = 91,
    16  
    17  	// From NetBSD's <sys/time.h>
    18  	CLOCK_REALTIME = 0,
    19  	CLOCK_VIRTUAL = 1,
    20  	CLOCK_PROF = 2,
    21  	CLOCK_MONOTONIC = 3
    22  };
    23  
    24  extern SigTab runtime·sigtab[];
    25  
    26  static Sigset sigset_none;
    27  static Sigset sigset_all = { ~(uint32)0, ~(uint32)0, ~(uint32)0, ~(uint32)0, };
    28  
    29  extern void runtime·getcontext(UcontextT *context);
    30  extern int32 runtime·lwp_create(UcontextT *context, uintptr flags, void *lwpid);
    31  extern void runtime·lwp_mcontext_init(void *mc, void *stack, M *mp, G *gp, void (*fn)(void));
    32  extern int32 runtime·lwp_park(Timespec *abstime, int32 unpark, void *hint, void *unparkhint);
    33  extern int32 runtime·lwp_unpark(int32 lwp, void *hint);
    34  extern int32 runtime·lwp_self(void);
    35  
    36  // From NetBSD's <sys/sysctl.h>
    37  #define	CTL_HW	6
    38  #define	HW_NCPU	3
    39  
    40  static int32
    41  getncpu(void)
    42  {
    43  	uint32 mib[2];
    44  	uint32 out;
    45  	int32 ret;
    46  	uintptr nout;
    47  
    48  	// Fetch hw.ncpu via sysctl.
    49  	mib[0] = CTL_HW;
    50  	mib[1] = HW_NCPU;
    51  	nout = sizeof out;
    52  	out = 0;
    53  	ret = runtime·sysctl(mib, 2, (byte*)&out, &nout, nil, 0);
    54  	if(ret >= 0)
    55  		return out;
    56  	else
    57  		return 1;
    58  }
    59  
    60  #pragma textflag NOSPLIT
    61  uintptr
    62  runtime·semacreate(void)
    63  {
    64  	return 1;
    65  }
    66  
    67  static void
    68  semasleep(void)
    69  {
    70  	int64 ns;
    71  	Timespec ts;
    72  
    73  	ns = (int64)(uint32)g->m->scalararg[0] | (int64)(uint32)g->m->scalararg[1]<<32;
    74  	g->m->scalararg[0] = 0;
    75  	g->m->scalararg[1] = 0;
    76  
    77  	// spin-mutex lock
    78  	while(runtime·xchg(&g->m->waitsemalock, 1))
    79  		runtime·osyield();
    80  
    81  	for(;;) {
    82  		// lock held
    83  		if(g->m->waitsemacount == 0) {
    84  			// sleep until semaphore != 0 or timeout.
    85  			// thrsleep unlocks m->waitsemalock.
    86  			if(ns < 0) {
    87  				// TODO(jsing) - potential deadlock!
    88  				//
    89  				// There is a potential deadlock here since we
    90  				// have to release the waitsemalock mutex
    91  				// before we call lwp_park() to suspend the
    92  				// thread. This allows another thread to
    93  				// release the lock and call lwp_unpark()
    94  				// before the thread is actually suspended.
    95  				// If this occurs the current thread will end
    96  				// up sleeping indefinitely. Unfortunately
    97  				// the NetBSD kernel does not appear to provide
    98  				// a mechanism for unlocking the userspace
    99  				// mutex once the thread is actually parked.
   100  				runtime·atomicstore(&g->m->waitsemalock, 0);
   101  				runtime·lwp_park(nil, 0, &g->m->waitsemacount, nil);
   102  			} else {
   103  				ns = ns + runtime·nanotime();
   104  				// NOTE: tv_nsec is int64 on amd64, so this assumes a little-endian system.
   105  				ts.tv_nsec = 0;
   106  				ts.tv_sec = runtime·timediv(ns, 1000000000, (int32*)&ts.tv_nsec);
   107  				// TODO(jsing) - potential deadlock!
   108  				// See above for details.
   109  				runtime·atomicstore(&g->m->waitsemalock, 0);
   110  				runtime·lwp_park(&ts, 0, &g->m->waitsemacount, nil);
   111  			}
   112  			// reacquire lock
   113  			while(runtime·xchg(&g->m->waitsemalock, 1))
   114  				runtime·osyield();
   115  		}
   116  
   117  		// lock held (again)
   118  		if(g->m->waitsemacount != 0) {
   119  			// semaphore is available.
   120  			g->m->waitsemacount--;
   121  			// spin-mutex unlock
   122  			runtime·atomicstore(&g->m->waitsemalock, 0);
   123  			g->m->scalararg[0] = 0; // semaphore acquired
   124  			return;
   125  		}
   126  
   127  		// semaphore not available.
   128  		// if there is a timeout, stop now.
   129  		// otherwise keep trying.
   130  		if(ns >= 0)
   131  			break;
   132  	}
   133  
   134  	// lock held but giving up
   135  	// spin-mutex unlock
   136  	runtime·atomicstore(&g->m->waitsemalock, 0);
   137  	g->m->scalararg[0] = -1;
   138  	return;
   139  }
   140  
   141  #pragma textflag NOSPLIT
   142  int32
   143  runtime·semasleep(int64 ns)
   144  {
   145  	int32 r;
   146  	void (*fn)(void);
   147  
   148  	g->m->scalararg[0] = (uint32)ns;
   149  	g->m->scalararg[1] = (uint32)(ns>>32);
   150  	fn = semasleep;
   151  	runtime·onM(&fn);
   152  	r = g->m->scalararg[0];
   153  	g->m->scalararg[0] = 0;
   154  	return r;
   155  }
   156  
   157  static void badsemawakeup(void);
   158  
   159  #pragma textflag NOSPLIT
   160  void
   161  runtime·semawakeup(M *mp)
   162  {
   163  	uint32 ret;
   164  	void (*fn)(void);
   165  	void *oldptr;
   166  	uintptr oldscalar;
   167  
   168  	// spin-mutex lock
   169  	while(runtime·xchg(&mp->waitsemalock, 1))
   170  		runtime·osyield();
   171  	mp->waitsemacount++;
   172  	// TODO(jsing) - potential deadlock, see semasleep() for details.
   173  	// Confirm that LWP is parked before unparking...
   174  	ret = runtime·lwp_unpark(mp->procid, &mp->waitsemacount);
   175  	if(ret != 0 && ret != ESRCH) {
   176  		// semawakeup can be called on signal stack.
   177  		// Save old ptrarg/scalararg so we can restore them.
   178  		oldptr = g->m->ptrarg[0];
   179  		oldscalar = g->m->scalararg[0];
   180  		g->m->ptrarg[0] = mp;
   181  		g->m->scalararg[0] = ret;
   182  		fn = badsemawakeup;
   183  		if(g == g->m->gsignal)
   184  			fn();
   185  		else
   186  			runtime·onM(&fn);
   187  		g->m->ptrarg[0] = oldptr;
   188  		g->m->scalararg[0] = oldscalar;
   189  	}
   190  	// spin-mutex unlock
   191  	runtime·atomicstore(&mp->waitsemalock, 0);
   192  }
   193  
   194  static void
   195  badsemawakeup(void)
   196  {
   197  	M *mp;
   198  	int32 ret;
   199  
   200  	mp = g->m->ptrarg[0];
   201  	g->m->ptrarg[0] = nil;
   202  	ret = g->m->scalararg[0];
   203  	g->m->scalararg[0] = 0;
   204  
   205  	runtime·printf("thrwakeup addr=%p sem=%d ret=%d\n", &mp->waitsemacount, mp->waitsemacount, ret);
   206  }
   207  
   208  void
   209  runtime·newosproc(M *mp, void *stk)
   210  {
   211  	UcontextT uc;
   212  	int32 ret;
   213  
   214  	if(0) {
   215  		runtime·printf(
   216  			"newosproc stk=%p m=%p g=%p id=%d/%d ostk=%p\n",
   217  			stk, mp, mp->g0, mp->id, (int32)mp->tls[0], &mp);
   218  	}
   219  
   220  	mp->tls[0] = mp->id;	// so 386 asm can find it
   221  
   222  	runtime·getcontext(&uc);
   223  	
   224  	uc.uc_flags = _UC_SIGMASK | _UC_CPU;
   225  	uc.uc_link = nil;
   226  	uc.uc_sigmask = sigset_all;
   227  
   228  	runtime·lwp_mcontext_init(&uc.uc_mcontext, stk, mp, mp->g0, runtime·mstart);
   229  
   230  	ret = runtime·lwp_create(&uc, 0, &mp->procid);
   231  
   232  	if(ret < 0) {
   233  		runtime·printf("runtime: failed to create new OS thread (have %d already; errno=%d)\n", runtime·mcount() - 1, -ret);
   234  		runtime·throw("runtime.newosproc");
   235  	}
   236  }
   237  
   238  void
   239  runtime·osinit(void)
   240  {
   241  	runtime·ncpu = getncpu();
   242  }
   243  
   244  #pragma textflag NOSPLIT
   245  void
   246  runtime·get_random_data(byte **rnd, int32 *rnd_len)
   247  {
   248  	#pragma dataflag NOPTR
   249  	static byte urandom_data[HashRandomBytes];
   250  	int32 fd;
   251  	fd = runtime·open("/dev/urandom", 0 /* O_RDONLY */, 0);
   252  	if(runtime·read(fd, urandom_data, HashRandomBytes) == HashRandomBytes) {
   253  		*rnd = urandom_data;
   254  		*rnd_len = HashRandomBytes;
   255  	} else {
   256  		*rnd = nil;
   257  		*rnd_len = 0;
   258  	}
   259  	runtime·close(fd);
   260  }
   261  
   262  void
   263  runtime·goenvs(void)
   264  {
   265  	runtime·goenvs_unix();
   266  }
   267  
   268  // Called to initialize a new m (including the bootstrap m).
   269  // Called on the parent thread (main thread in case of bootstrap), can allocate memory.
   270  void
   271  runtime·mpreinit(M *mp)
   272  {
   273  	mp->gsignal = runtime·malg(32*1024);
   274  	mp->gsignal->m = mp;
   275  }
   276  
   277  // Called to initialize a new m (including the bootstrap m).
   278  // Called on the new thread, can not allocate memory.
   279  void
   280  runtime·minit(void)
   281  {
   282  	g->m->procid = runtime·lwp_self();
   283  
   284  	// Initialize signal handling
   285  	runtime·signalstack((byte*)g->m->gsignal->stack.lo, 32*1024);
   286  	runtime·sigprocmask(SIG_SETMASK, &sigset_none, nil);
   287  }
   288  
   289  // Called from dropm to undo the effect of an minit.
   290  void
   291  runtime·unminit(void)
   292  {
   293  	runtime·signalstack(nil, 0);
   294  }
   295  
   296  uintptr
   297  runtime·memlimit(void)
   298  {
   299  	return 0;
   300  }
   301  
   302  extern void runtime·sigtramp(void);
   303  
   304  typedef struct sigaction {
   305  	union {
   306  		void    (*_sa_handler)(int32);
   307  		void    (*_sa_sigaction)(int32, Siginfo*, void *);
   308  	} _sa_u;			/* signal handler */
   309  	uint32	sa_mask[4];		/* signal mask to apply */
   310  	int32	sa_flags;		/* see signal options below */
   311  } SigactionT;
   312  
   313  void
   314  runtime·setsig(int32 i, GoSighandler *fn, bool restart)
   315  {
   316  	SigactionT sa;
   317  
   318  	runtime·memclr((byte*)&sa, sizeof sa);
   319  	sa.sa_flags = SA_SIGINFO|SA_ONSTACK;
   320  	if(restart)
   321  		sa.sa_flags |= SA_RESTART;
   322  	sa.sa_mask[0] = ~0U;
   323  	sa.sa_mask[1] = ~0U;
   324  	sa.sa_mask[2] = ~0U;
   325  	sa.sa_mask[3] = ~0U;
   326  	if (fn == runtime·sighandler)
   327  		fn = (void*)runtime·sigtramp;
   328  	sa._sa_u._sa_sigaction = (void*)fn;
   329  	runtime·sigaction(i, &sa, nil);
   330  }
   331  
   332  GoSighandler*
   333  runtime·getsig(int32 i)
   334  {
   335  	SigactionT sa;
   336  
   337  	runtime·memclr((byte*)&sa, sizeof sa);
   338  	runtime·sigaction(i, nil, &sa);
   339  	if((void*)sa._sa_u._sa_sigaction == runtime·sigtramp)
   340  		return runtime·sighandler;
   341  	return (void*)sa._sa_u._sa_sigaction;
   342  }
   343  
   344  void
   345  runtime·signalstack(byte *p, int32 n)
   346  {
   347  	StackT st;
   348  
   349  	st.ss_sp = (void*)p;
   350  	st.ss_size = n;
   351  	st.ss_flags = 0;
   352  	if(p == nil)
   353  		st.ss_flags = SS_DISABLE;
   354  	runtime·sigaltstack(&st, nil);
   355  }
   356  
   357  void
   358  runtime·unblocksignals(void)
   359  {
   360  	runtime·sigprocmask(SIG_SETMASK, &sigset_none, nil);
   361  }
   362  
   363  #pragma textflag NOSPLIT
   364  int8*
   365  runtime·signame(int32 sig)
   366  {
   367  	return runtime·sigtab[sig].name;
   368  }