xstat: prevent CPU loop when -period 0
[openafs.git] / src / xstat / xstat_fs.c
index e35469e..3145a00 100644 (file)
 #include <afs/param.h>
 
 #include <roken.h>
+#include <afs/opr.h>
 
 #include "xstat_fs.h"          /*Interface for this module */
-#include <lwp.h>               /*Lightweight process package */
+#include <pthread.h>
 
 #include <afs/afsutil.h>
 #include <afs/afscbint.h>
 
-#define LWP_STACK_SIZE (16 * 1024)
-
 /*
  * Exported variables.
  */
 int xstat_fs_numServers;       /*Num connected servers */
 struct xstat_fs_ConnectionInfo
  *xstat_fs_ConnInfo;           /*Ptr to connection array */
-int numCollections;            /*Number of data collections */
 struct xstat_fs_ProbeResults xstat_fs_Results; /*Latest probe results */
-char terminationEvent;         /*One-shot termination event */
 
 afs_int32 xstat_fsData[AFS_MAX_XSTAT_LONGS];   /*Buffer for collected data */
 
@@ -47,16 +44,11 @@ static int xstat_fs_initflag = 0;   /*Was init routine called? */
 static int xstat_fs_debug = 0; /*Debugging output enabled? */
 static int xstat_fs_oneShot = 0;       /*One-shot operation? */
 static int (*xstat_fs_Handler) (void); /*Probe handler routine */
-static PROCESS probeLWP_ID;    /*Probe LWP process ID */
+static pthread_t xstat_fs_thread;      /*Probe thread */
 static int xstat_fs_numCollections;    /*Number of desired collections */
 static afs_int32 *xstat_fs_collIDP;    /*Ptr to collection IDs desired */
-
-/*
- * We have to pass a port to Rx to start up our callback listener
- * service, but 7001 is already taken up by the Cache Manager.  So,
- * we make up our own.
- */
-#define XSTAT_FS_CBPORT        7101
+static opr_mutex_t xstat_fs_force_lock;        /*Lock to wakeup probe */
+static opr_cv_t xstat_fs_force_cv;     /*Condvar to wakeup probe */
 
 
 /*------------------------------------------------------------------------
@@ -201,7 +193,7 @@ xstat_fs_Cleanup(int a_releaseMem)
  * [private] xstat_fs_LWP
  *
  * Description:
- *     This LWP iterates over the server connections and gathers up
+ *     This thread iterates over the server connections and gathers up
  *     the desired statistics from each one on a regular basis.  When
  *     the sweep is done, the associated handler function is called
  *     to process the new data.
@@ -223,10 +215,10 @@ xstat_fs_Cleanup(int a_releaseMem)
 static void *
 xstat_fs_LWP(void *unused)
 {
-    static char rn[] = "xstat_fs_LWP"; /*Routine name */
+    static char rn[] = "xstat_fs_thread";      /*Routine name */
     afs_int32 code;    /*Results of calls */
-    int oneShotCode;           /*Result of one-shot signal */
     struct timeval tv;         /*Time structure */
+    struct timespec wait;      /*Time to wait */
     int conn_idx;              /*Connection index */
     struct xstat_fs_ConnectionInfo *curr_conn; /*Current connection */
     afs_int32 srvVersionNumber;        /*Xstat version # */
@@ -283,12 +275,12 @@ xstat_fs_LWP(void *unused)
 
                    if (xstat_fs_debug) {
                        printf
-                           ("%s: Calling RXAFS_GetXStats, conn=%" AFS_PTR_FMT ", clientVersionNumber=%d, collectionNumber=%d, srvVersionNumberP=%" AFS_PTR_FMT ", timeP=%" AFS_PTR_FMT ", dataP=%" AFS_PTR_FMT "\n",
+                           ("%s: Calling RXAFS_GetXStats, conn=%p, clientVersionNumber=%d, collectionNumber=%d, srvVersionNumberP=%p, timeP=%p, dataP=%p\n",
                             rn, curr_conn->rxconn, clientVersionNumber,
                             *currCollIDP, &srvVersionNumber,
                             &(xstat_fs_Results.probeTime),
                             &(xstat_fs_Results.data));
-                       printf("%s: [bufflen=%d, buffer at %" AFS_PTR_FMT "]\n", rn,
+                       printf("%s: [bufflen=%d, buffer at %p]\n", rn,
                               xstat_fs_Results.data.AFS_CollData_len,
                               xstat_fs_Results.data.AFS_CollData_val);
                    }
@@ -336,36 +328,21 @@ xstat_fs_LWP(void *unused)
 
        if (xstat_fs_oneShot) {
            /*
-            * One-shot execution desired.  Signal our main procedure
-            * that we've finished our collection round.
+            * One-shot execution desired.
             */
-           if (xstat_fs_debug)
-               printf("[%s] Signalling main process at %" AFS_PTR_FMT "\n", rn,
-                      &terminationEvent);
-           oneShotCode = LWP_SignalProcess(&terminationEvent);
-           if (oneShotCode)
-               fprintf(stderr, "[%s] Error %d from LWP_SignalProcess()", rn,
-                       oneShotCode);
-           break;              /*from the perpetual while loop */
-       } /*One-shot execution */
-       else {
+           break;
+       } else {
            /*
             * Continuous execution desired.  Sleep for the required
-            * number of seconds.
+            * number of seconds or wakeup sooner if forced.
             */
-           tv.tv_sec = xstat_fs_ProbeFreqInSecs;
-           tv.tv_usec = 0;
-           if (xstat_fs_debug)
-               printf("[%s] Falling asleep for %d seconds\n", rn,
-                      xstat_fs_ProbeFreqInSecs);
-           code = IOMGR_Select(0,      /*Num fids */
-                               0,      /*Descs ready for reading */
-                               0,      /*Descs ready for writing */
-                               0,      /*Descs w/exceptional conditions */
-                               &tv);   /*Ptr to timeout structure */
-           if (code)
-               fprintf(stderr, "[%s] IOMGR_Select returned code %d\n", rn,
-                       code);
+           gettimeofday(&tv, NULL);
+           wait.tv_sec = tv.tv_sec + xstat_fs_ProbeFreqInSecs;
+           wait.tv_nsec = tv.tv_usec * 1000;
+           opr_mutex_enter(&xstat_fs_force_lock);
+           code = opr_cv_timedwait(&xstat_fs_force_cv, &xstat_fs_force_lock, &wait);
+           opr_Verify(code == 0 || code == ETIMEDOUT);
+           opr_mutex_exit(&xstat_fs_force_lock);
        }                       /*Continuous execution */
     }                          /*Service loop */
     return NULL;
@@ -376,7 +353,7 @@ xstat_fs_LWP(void *unused)
  *
  * Description:
  *     Initialize the xstat_fs module: set up Rx connections to the
- *     given set of File Servers, start up the probe and callback LWPs,
+ *     given set of File Servers, start up the probe and callback threads,
  *     and associate the routine to be called when a probe completes.
  *     Also, let it know which collections you're interested in.
  *
@@ -419,7 +396,6 @@ xstat_fs_Init(int a_numServers, struct sockaddr_in *a_socketArray,
     struct xstat_fs_ConnectionInfo *curr_conn; /*Ptr to current conn */
     char *hostNameFound;       /*Ptr to returned host name */
     int conn_err;              /*Connection error? */
-    int PortToUse;             /*Callback port to use */
     int collIDBytes;           /*Num bytes in coll ID array */
     char hoststr[16];
 
@@ -433,6 +409,9 @@ xstat_fs_Init(int a_numServers, struct sockaddr_in *a_socketArray,
     } else
        xstat_fs_initflag = 1;
 
+    opr_mutex_init(&xstat_fs_force_lock);
+    opr_cv_init(&xstat_fs_force_cv);
+
     /*
      * Check the parameters for bogosities.
      */
@@ -451,7 +430,7 @@ xstat_fs_Init(int a_numServers, struct sockaddr_in *a_socketArray,
                a_ProbeFreqInSecs);
        arg_errfound = 1;
     }
-    if (a_ProbeHandler == (int (*)())0) {
+    if (a_ProbeHandler == NULL) {
        fprintf(stderr, "[%s] Null probe handler function argument\n", rn);
        arg_errfound = 1;
     }
@@ -514,25 +493,13 @@ xstat_fs_Init(int a_numServers, struct sockaddr_in *a_socketArray,
      */
     if (xstat_fs_debug)
        printf("[%s] Initializing Rx\n", rn);
-    PortToUse = XSTAT_FS_CBPORT;
-
-    do {
-       code = rx_Init(htons(PortToUse));
-       if (code) {
-           if (code == RX_ADDRINUSE) {
-               if (xstat_fs_debug)
-                   fprintf(stderr,
-                           "[%s] Callback port %d in use, advancing\n", rn,
-                           PortToUse);
-               PortToUse++;
-           } else {
-               fprintf(stderr, "[%s] Fatal error in rx_Init()\n", rn);
-               return (-1);
-           }
-       }
-    } while (code);
+    code = rx_Init(0);
+    if (code) {
+       fprintf(stderr, "[%s] Fatal error in rx_Init()\n", rn);
+       return (-1);
+    }
     if (xstat_fs_debug)
-       printf("[%s] Rx initialized on port %d\n", rn, PortToUse);
+       printf("[%s] Rx initialized\n", rn);
 
     /*
      * Create a null Rx server security object, to be used by the
@@ -552,17 +519,17 @@ xstat_fs_Init(int a_numServers, struct sockaddr_in *a_socketArray,
 
     /*
      * Create a null Rx client security object, to be used by the
-     * probe LWP.
+     * probe thread.
      */
     secobj = rxnull_NewClientSecurityObject();
     if (secobj == (struct rx_securityClass *)0) {
        fprintf(stderr,
-               "[%s] Can't create probe LWP client security object.\n", rn);
+               "[%s] Can't create probe thread client security object.\n", rn);
        xstat_fs_Cleanup(1);    /*Delete already-malloc'ed areas */
        return (-1);
     }
     if (xstat_fs_debug)
-       printf("[%s] Probe LWP client security object created\n", rn);
+       printf("[%s] Probe thread client security object created\n", rn);
 
     curr_conn = xstat_fs_ConnInfo;
     conn_err = 0;
@@ -616,7 +583,7 @@ xstat_fs_Init(int a_numServers, struct sockaddr_in *a_socketArray,
            conn_err = 1;
        }
        if (xstat_fs_debug)
-           printf("[%s] New connection at %" AFS_PTR_FMT "\n", rn, curr_conn->rxconn);
+           printf("[%s] New connection at %p\n", rn, curr_conn->rxconn);
 
        /*
         * Bump the current xstat_fs connection to set up.
@@ -656,22 +623,14 @@ xstat_fs_Init(int a_numServers, struct sockaddr_in *a_socketArray,
      * Start up the probe LWP.
      */
     if (xstat_fs_debug)
-       printf("[%s] Creating the probe LWP\n", rn);
-    code = LWP_CreateProcess(xstat_fs_LWP,     /*Function to start up */
-                            LWP_STACK_SIZE,    /*Stack size in bytes */
-                            1, /*Priority */
-                            (void *)0, /*Parameters */
-                            "xstat_fs Worker", /*Name to use */
-                            &probeLWP_ID);     /*Returned LWP process ID */
+       printf("[%s] Creating the probe thread\n", rn);
+    code = pthread_create(&xstat_fs_thread, NULL, xstat_fs_LWP, NULL);
     if (code) {
-       fprintf(stderr, "[%s] Can't create xstat_fs LWP!  Error is %d\n", rn,
+       fprintf(stderr, "[%s] Can't create xstat_fs thread!  Error is %d\n", rn,
                code);
        xstat_fs_Cleanup(1);    /*Delete already-malloc'ed areas */
        return (code);
     }
-    if (xstat_fs_debug)
-       printf("[%s] Probe LWP process structure located at %" AFS_PTR_FMT "\n", rn,
-              probeLWP_ID);
 
     /*
      * Return the final results.
@@ -687,7 +646,7 @@ xstat_fs_Init(int a_numServers, struct sockaddr_in *a_socketArray,
  * [exported] xstat_fs_ForceProbeNow
  *
  * Description:
- *     Wake up the probe LWP, forcing it to execute a probe immediately.
+ *     Wake up the probe thread, forcing it to execute a probe immediately.
  *
  * Arguments:
  *     None.
@@ -719,7 +678,9 @@ xstat_fs_ForceProbeNow(void)
     /*
      * Kick the sucker in the side.
      */
-    IOMGR_Cancel(probeLWP_ID);
+    opr_mutex_enter(&xstat_fs_force_lock);
+    opr_cv_signal(&xstat_fs_force_cv);
+    opr_mutex_exit(&xstat_fs_force_lock);
 
     /*
      * We did it, so report the happy news.
@@ -860,3 +821,69 @@ xstat_fs_DecodeFullPerfStats(struct fs_stats_FullPerfStats **aout,
     return 0;
 #undef DECODE_TV
 }
+
+/*
+ * Wait for the collection to complete. Returns after one cycle if running in
+ * one-shot mode, otherwise wait for a given amount of time.
+ *
+ * Args:
+ *    int sleep_secs : time to wait in seconds when running
+ *                     in continuous mode. 0 means wait forever.
+ *
+ * Returns:
+ *    0 on success
+ */
+int
+xstat_fs_Wait(int sleep_secs)
+{
+    static char rn[] = "xstat_fs_Wait";        /*Routine name */
+    int code;
+    struct timeval tv;         /*Time structure */
+
+    if (xstat_fs_oneShot) {
+       /*
+        * One-shot operation; just wait for the collection to be done.
+        */
+       if (xstat_fs_debug)
+           printf("[%s] Calling pthread_join\n", rn);
+       code = pthread_join(xstat_fs_thread, NULL);
+       if (xstat_fs_debug)
+           printf("[%s] Returned from pthread_join()\n", rn);
+       if (code) {
+           fprintf(stderr,
+                   "[%s] Error %d encountered by pthread_join()\n",
+                   rn, code);
+       }
+    } else if (sleep_secs == 0) {
+       /* Sleep forever. */
+       if (xstat_fs_debug)
+           fprintf(stderr, "[ %s ] going to sleep ...\n", rn);
+       while (1) {
+           code = select(0,    /*Num fds */
+                         0,    /*Descriptors ready for reading */
+                         0,    /*Descriptors ready for writing */
+                         0,    /*Descriptors with exceptional conditions */
+                         NULL);        /* NULL timeout means "forever" */
+           if (code < 0) {
+               fprintf(stderr, "[%s] select() error %d\n", rn, errno);
+               break;
+           }
+       }
+    } else {
+       /* Let's just fall asleep while.  */
+       if (xstat_fs_debug)
+           printf
+               ("xstat_fs service started, main thread sleeping for %d secs.\n",
+                sleep_secs);
+       tv.tv_sec = sleep_secs;
+       tv.tv_usec = 0;
+       code = select(0,        /*Num fds */
+                     0,        /*Descriptors ready for reading */
+                     0,        /*Descriptors ready for writing */
+                     0,        /*Descriptors with exceptional conditions */
+                     &tv);     /*Timeout structure */
+       if (code < 0)
+           fprintf(stderr, "[%s] select() error %d\n", rn, errno);
+    }
+    return code;
+}