runtime: cpu profiling support

R=r
CC=golang-dev
https://golang.org/cl/4306043
diff --git a/src/pkg/runtime/linux/arm/signal.c b/src/pkg/runtime/linux/arm/signal.c
index 843c40b..5a2b47d 100644
--- a/src/pkg/runtime/linux/arm/signal.c
+++ b/src/pkg/runtime/linux/arm/signal.c
@@ -58,6 +58,11 @@
 	uc = context;
 	r = &uc->uc_mcontext;
 
+	if(sig == SIGPROF) {
+		runtime·sigprof((uint8*)r->arm_pc, (uint8*)r->arm_sp, (uint8*)r->arm_lr, gp);
+		return;
+	}
+
 	if(gp != nil && (runtime·sigtab[sig].flags & SigPanic)) {
 		// Make it look like a call to the signal func.
 		// Have to pass arguments out of band since
@@ -119,31 +124,58 @@
 	runtime·sigaltstack(&st, nil);
 }
 
+static void
+sigaction(int32 i, void (*fn)(int32, Siginfo*, void*, G*), bool restart)
+{
+	Sigaction sa;
+
+	runtime·memclr((byte*)&sa, sizeof sa);
+	sa.sa_flags = SA_ONSTACK | SA_SIGINFO | SA_RESTORER;
+	if(restart)
+		sa.sa_flags |= SA_RESTART;
+	sa.sa_mask = ~0ULL;
+	sa.sa_restorer = (void*)runtime·sigreturn;
+	sa.k_sa_handler = fn;
+	runtime·rt_sigaction(i, &sa, nil, 8);
+}
+
 void
 runtime·initsig(int32 queue)
 {
-	static Sigaction sa;
+	int32 i;
+	void *fn;
 
 	runtime·siginit();
 
-	int32 i;
-	sa.sa_flags = SA_ONSTACK | SA_SIGINFO | SA_RESTORER;
-	sa.sa_mask.sig[0] = 0xFFFFFFFF;
-	sa.sa_mask.sig[1] = 0xFFFFFFFF;
-	sa.sa_restorer = (void*)runtime·sigreturn;
 	for(i = 0; i<NSIG; i++) {
 		if(runtime·sigtab[i].flags) {
 			if((runtime·sigtab[i].flags & SigQueue) != queue)
 				continue;
 			if(runtime·sigtab[i].flags & (SigCatch | SigQueue))
-				sa.sa_handler = (void*)runtime·sigtramp;
+				fn = runtime·sighandler;
 			else
-				sa.sa_handler = (void*)runtime·sigignore;
-			if(runtime·sigtab[i].flags & SigRestart)
-				sa.sa_flags |= SA_RESTART;
-			else
-				sa.sa_flags &= ~SA_RESTART;
-			runtime·rt_sigaction(i, &sa, nil, 8);
+				fn = runtime·sigignore;
+			sigaction(i, fn, (runtime·sigtab[i].flags & SigRestart) != 0);
 		}
 	}
 }
+
+void
+runtime·resetcpuprofiler(int32 hz)
+{
+	Sigaction sa;
+	Itimerval it;
+	
+	runtime·memclr((byte*)&it, sizeof it);
+	if(hz == 0) {
+		runtime·setitimer(ITIMER_PROF, &it, nil);
+		sigaction(SIGPROF, SIG_IGN, true);
+	} else {
+		sigaction(SIGPROF, runtime·sighandler, true);
+		it.it_interval.tv_sec = 0;
+		it.it_interval.tv_usec = 1000000 / hz;
+		it.it_value = it.it_interval;
+		runtime·setitimer(ITIMER_PROF, &it, nil);
+	}
+	m->profilehz = hz;
+}