Replace ast_log(LOG_DEBUG, ...) with ast_debug()
[asterisk/asterisk.git] / utils / astcanary.c
index 785ec14..8cfa3fe 100644 (file)
 #include <fcntl.h>
 #include <unistd.h>
 #include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
 
 /*!\brief
  * At one time, canaries were carried along with coal miners down
  * into a mine.  Their purpose was to alert the miners when they
  * had drilled into a pocket of methane gas or another noxious
- * substance.  The canary, being the most sensitive animal would
+ * substance.  The canary, being the most sensitive animal, would
  * immediately fall over.  Seeing this, the miners could take
  * action to escape the mine, seeing an imminent danger.
  *
  * the same time.  This is also why this canary must exist as a
  * completely separate process and not simply as a thread within
  * Asterisk itself.
+ *
+ * Quote:
+ * "The nice value set with setpriority() shall be applied to the
+ * process. If the process is multi-threaded, the nice value shall
+ * affect all system scope threads in the process."
+ *
+ * Source:
+ * http://www.opengroup.org/onlinepubs/000095399/functions/setpriority.html
+ *
+ * In answer to the question, what aren't system scope threads, the
+ * answer is, in Asterisk, nothing.  Process scope threads are the
+ * alternative, but they aren't supported in Linux.
  */
 
+static const char explanation[] =
+"This file is created when Asterisk is run with a realtime priority (-p).  It\n"
+"must continue to exist, and the astcanary process must be allowed to continue\n"
+"running, or else the Asterisk process will, within a short period of time,\n"
+"slow itself down to regular priority.\n\n"
+"The technical explanation for this file is to provide an assurance to Asterisk\n"
+"that there are no threads that have gone into runaway mode, thus hogging the\n"
+"CPU, and making the Asterisk machine seem to be unresponsive.  When that\n"
+"happens, the astcanary process will be unable to update the timestamp on this\n"
+"file, and Asterisk will notice within 120 seconds and react.  Slowing the\n"
+"Asterisk process down to regular priority will permit an administrator to\n"
+"intervene, thus avoiding a need to reboot the entire machine.\n";
+
 int main(int argc, char *argv[])
 {
        int fd;
+       pid_t parent;
+
+       if (argc < 3) {
+               fprintf(stderr, "Usage: %s <monitor-filename> <ppid>\n", argv[0]);
+               exit(1);
+       }
+
        /* Run at normal priority */
        setpriority(PRIO_PROCESS, 0, 0);
-       for (;;) {
+
+       /*!\note
+        * See http://www.opengroup.org/onlinepubs/009695399/basedefs/xbd_chap03.html#tag_03_265
+        * for a justification of this approach.  The PPID after the creator dies in Linux and
+        * most other Unix-like systems will be 1, but this is not strictly the case.  The POSIX
+        * specification allows it to be an implementation-defined system process.  However, it
+        * most certainly will not be the original parent PID, which makes the following code
+        * POSIX-compliant.
+        */
+       for (parent = atoi(argv[2]); parent == getppid() ;) {
                /* Update the modification times (checked from Asterisk) */
                if (utime(argv[1], NULL)) {
                        /* Recreate the file if it doesn't exist */
-                       if ((fd = open(argv[1], O_RDWR | O_TRUNC | O_CREAT, 0777)) > -1)
+                       if ((fd = open(argv[1], O_RDWR | O_TRUNC | O_CREAT, 0777)) > -1) {
+                               if (write(fd, explanation, strlen(explanation)) < 0) {
+                                       exit(1);
+                               }
                                close(fd);
-                       else
+                       } else {
                                exit(1);
+                       }
                        continue;
                }
 
@@ -78,7 +125,7 @@ int main(int argc, char *argv[])
                sleep(5);
        }
 
-       /* Never reached */
+       /* Exit when the parent dies */
        return 0;
 }