Support multiple profile sessions w/o the need of rebooting.

Bonus changes:
  - Eliminated sending unnecessary SIGHUP to oprofiled when dumping
    samples.
  - fixed a file descriptor leak in read_num().

Change-Id: I79ca35a62df848ceb4e16f2bc62e54b86ab7495f
diff --git a/opcontrol/opcontrol.cpp b/opcontrol/opcontrol.cpp
index 075ade6..6b440e2 100644
--- a/opcontrol/opcontrol.cpp
+++ b/opcontrol/opcontrol.cpp
@@ -342,10 +342,32 @@
     }
 }
 
+int read_num(const char* file)
+{
+    char buffer[256];
+    int fd = open(file, O_RDONLY);
+    if (fd<0) return -1;
+    int rd = read(fd, buffer, sizeof(buffer)-1);
+    buffer[rd] = 0;
+    close(fd);
+    return atoi(buffer);
+}
+
 int do_setup()
 {
     char dir[1024];
 
+    /*
+     * Kill the old daemon so that setup can be done more than once to achieve
+     * the same effect as reset.
+     */
+    int num = read_num(OP_DATA_DIR"/lock");
+    if (num >= 0) {
+        printf("Terminating the old daemon...\n");
+        kill(num, SIGTERM);
+        sleep(5);
+    }
+
     setup_session_dir();
 
     if (mkdir(OP_DRIVER_BASE, 0755)) {
@@ -471,16 +493,6 @@
     return 0;
 }
 
-int read_num(const char* file)
-{
-    char buffer[256];
-    int fd = open(file, O_RDONLY);
-    if (fd<0) return -1;
-    int rd = read(fd, buffer, sizeof(buffer)-1);
-    buffer[rd] = 0;
-    return atoi(buffer);
-}
-
 void do_status()
 {
     int num;
@@ -517,7 +529,7 @@
         sprintf(fullname, "/proc/%d", num);
         fd = open(fullname, O_RDONLY);
         if (fd == -1) {
-            printf("Session directory is not clean - do \"opcontrol --setup\""
+            printf("OProfile daemon exited prematurely - redo setup"
                    " before you continue\n");
             return;
         }
@@ -561,11 +573,8 @@
                 closedir(dir);
             }
 
-#if defined(__i386__) || defined(__x86_64__)
-            /* FIXME on ARM - backtrace seems broken there */
             num = read_num(OP_DRIVER_BASE"/backtrace_depth");
-            printf("  %9u backtrace_depth\n", num);
-#endif
+            printf("backtrace_depth: %u\n", num);
         }
     }
     else {
@@ -575,6 +584,20 @@
 
 void do_reset() 
 {
+    /*
+     * Sending SIGHUP will result in the following crash in oprofiled when
+     * profiling subsequent runs:
+     * Stack Trace:
+     * RELADDR   FUNCTION                         FILE:LINE
+     *   00008cd8  add_node+12                    oprofilelibdb/db_insert.c:32
+     *   00008d69  odb_update_node_with_offset+60 oprofilelibdb/db_insert.c:102
+     *
+     * However without sending SIGHUP oprofile cannot be restarted successfully.
+     * As a temporary workaround, change do_reset into a no-op for now and kill
+     * the old daemon in do_setup to start all over again as a heavy-weight
+     * reset.
+     */
+#if 0
     int fd;
 
     fd = open(OP_DATA_DIR"/samples/current", O_RDONLY);
@@ -583,6 +606,13 @@
     }
     close(fd);
     system("rm -r "OP_DATA_DIR"/samples/current");
+    int num = read_num(OP_DATA_DIR"/lock");
+
+    if (num >= 0) {
+        printf("Signalling daemon...\n");
+        kill(num, SIGHUP);
+    }
+#endif
 }
 
 int main(int argc, char * const argv[])
@@ -630,10 +660,6 @@
             /* --dump */ {
                 int pid = read_num(OP_DATA_DIR"/lock");
                 echo_dev("1", 0, "dump", -1);
-                if (pid >= 0) {
-                    sleep(1);
-                    kill(pid, SIGHUP);
-                }
                 break;
             }
             /* --shutdown */
@@ -824,6 +850,11 @@
 
     if (start) {
         echo_dev("1", 0, "enable", -1);
+        int num = read_num(OP_DATA_DIR"/lock");
+
+        if (num >= 0) {
+            kill(num, SIGUSR1);
+        }
     }
 
     if (stop) {