Avoid incomplete function type in casts
[openafs.git] / src / xstat / xstat_fs.c
index 48a8651..99fdf63 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * Copyright 2000, International Business Machines Corporation and others.
  * All Rights Reserved.
- * 
+ *
  * This software has been released under the terms of the IBM Public
  * License.  For details, see the LICENSE file in the top-level source
  * directory or online at http://www.openafs.org/dl/license10.html
 #include <afsconfig.h>
 #include <afs/param.h>
 
-RCSID("$Header$");
-
-#include "xstat_fs.h"                  /*Interface for this module*/
-#include <lwp.h>                       /*Lightweight process package*/
-
-#define LWP_STACK_SIZE (16 * 1024)
+#include <roken.h>
+#include <afs/opr.h>
 
-/*
- * Routines we need that don't have explicit include file definitions.
- */
-extern int RXAFSCB_ExecuteRequest();   /*AFS callback dispatcher*/
-extern char *hostutil_GetNameByINet(); /*Host parsing utility*/
+#include "xstat_fs.h"          /*Interface for this module */
+#include <pthread.h>
 
-/*
- * Help out the linker by explicitly importing the callback routines
- * File Servers may be lobbing at us.
- */
-extern afs_int32 SRXAFSCB_CallBack();
-extern afs_int32 SRXAFSCB_InitCallBackState3();
-extern afs_int32 SRXAFSCB_Probe();
-extern afs_int32 SRXAFSCB_GetCE();
-extern afs_int32 SRXAFSCB_GetLock();
+#include <afs/afsutil.h>
+#include <afs/afscbint.h>
 
 /*
  * Exported variables.
  */
-int xstat_fs_numServers;                       /*Num connected servers*/
+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*/
+ *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*/
+afs_int32 xstat_fsData[AFS_MAX_XSTAT_LONGS];   /*Buffer for collected data */
 
 /*
  * Private globals.
  */
-static int xstat_fs_ProbeFreqInSecs;           /*Probe freq. in seconds*/
-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)();              /*Probe handler routine*/
-static PROCESS probeLWP_ID;                    /*Probe LWP process ID*/
-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 int xstat_fs_ProbeFreqInSecs;   /*Probe freq. in seconds */
+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 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 */
+static opr_mutex_t xstat_fs_force_lock;        /*Lock to wakeup probe */
+static opr_cv_t xstat_fs_force_cv;     /*Condvar to wakeup probe */
 
 
 /*------------------------------------------------------------------------
@@ -93,14 +74,13 @@ static afs_int32 *xstat_fs_collIDP;                 /*Ptr to collection IDs desired*/
  *     Zeros out basic data structures.
  *------------------------------------------------------------------------*/
 
-static int xstat_fs_CleanupInit()
-
-{ /*xstat_fs_CleanupInit*/
-
-    afs_int32 code;                    /*Return code from callback stubs*/
-    struct rx_call *rxcall;    /*Bogus param*/
-    AFSCBFids *Fids_Array;     /*Bogus param*/
-    AFSCBs *CallBack_Array;    /*Bogus param*/
+static int
+xstat_fs_CleanupInit(void)
+{
+    afs_int32 code;            /*Return code from callback stubs */
+    struct rx_call *rxcall;    /*Bogus param */
+    AFSCBFids *Fids_Array;     /*Bogus param */
+    AFSCBs *CallBack_Array;    /*Bogus param */
 
     xstat_fs_ConnInfo = (struct xstat_fs_ConnectionInfo *)0;
     xstat_fs_Results.probeNum = 0;
@@ -108,12 +88,12 @@ static int xstat_fs_CleanupInit()
     xstat_fs_Results.connP = (struct xstat_fs_ConnectionInfo *)0;
     xstat_fs_Results.collectionNumber = 0;
     xstat_fs_Results.data.AFS_CollData_len = AFS_MAX_XSTAT_LONGS;
-    xstat_fs_Results.data.AFS_CollData_val = (afs_int32 *)xstat_fsData;
+    xstat_fs_Results.data.AFS_CollData_val = (afs_int32 *) xstat_fsData;
     xstat_fs_Results.probeOK = 0;
 
-    rxcall        = (struct rx_call *)0;
-    Fids_Array    = (AFSCBFids *)0;
-    CallBack_Array = (AFSCBs *)0;
+    rxcall = (struct rx_call *)0;
+    Fids_Array = (AFSCBFids *) 0;
+    CallBack_Array = (AFSCBs *) 0;
 
     /*
      * Call each of the callback routines our module provides (in
@@ -121,14 +101,13 @@ static int xstat_fs_CleanupInit()
      */
     code = SRXAFSCB_CallBack(rxcall, Fids_Array, CallBack_Array);
     if (code)
-       return(code);
+       return (code);
     code = SRXAFSCB_InitCallBackState3(rxcall, (afsUUID *) 0);
     if (code)
-       return(code);
+       return (code);
     code = SRXAFSCB_Probe(rxcall);
-    return(code);
-
-} /*xstat_fs_CleanupInit*/
+    return (code);
+}
 
 
 /*------------------------------------------------------------------------
@@ -154,24 +133,21 @@ static int xstat_fs_CleanupInit()
  *     (if so directed).
  *------------------------------------------------------------------------*/
 
-int xstat_fs_Cleanup(a_releaseMem)
-    int a_releaseMem;
-
-{ /*xstat_fs_Cleanup*/
-
-    static char rn[] = "xstat_fs_Cleanup";     /*Routine name*/
-    int code;                                  /*Return code*/
-    int conn_idx;                              /*Current connection index*/
-    struct xstat_fs_ConnectionInfo *curr_conn; /*Ptr to xstat_fs connection*/
+int
+xstat_fs_Cleanup(int a_releaseMem)
+{
+    static char rn[] = "xstat_fs_Cleanup";     /*Routine name */
+    int code;                  /*Return code */
+    int conn_idx;              /*Current connection index */
+    struct xstat_fs_ConnectionInfo *curr_conn; /*Ptr to xstat_fs connection */
 
     /*
      * Assume the best, but check the worst.
      */
     if (!xstat_fs_initflag) {
        fprintf(stderr, "[%s] Refused; module not initialized\n", rn);
-       return(-1);
-    }
-    else
+       return (-1);
+    } else
        code = 0;
 
     /*
@@ -183,8 +159,7 @@ int xstat_fs_Cleanup(a_releaseMem)
                "[%s] Illegal number of servers (xstat_fs_numServers = %d)\n",
                rn, xstat_fs_numServers);
        code = -1;
-    }
-    else {
+    } else {
        if (xstat_fs_ConnInfo != (struct xstat_fs_ConnectionInfo *)0) {
            /*
             * The xstat_fs connection structure array exists.  Go through
@@ -197,9 +172,9 @@ int xstat_fs_Cleanup(a_releaseMem)
                    curr_conn->rxconn = (struct rx_connection *)0;
                }
                curr_conn++;
-           } /*for each xstat_fs connection*/
-       } /*xstat_fs connection structure exists*/
-    } /*Legal number of servers*/
+           }                   /*for each xstat_fs connection */
+       }                       /*xstat_fs connection structure exists */
+    }                          /*Legal number of servers */
 
     /*
      * If asked to, release the space we've allocated.
@@ -212,16 +187,15 @@ int xstat_fs_Cleanup(a_releaseMem)
     /*
      * Return the news, whatever it is.
      */
-    return(code);
-
-} /*xstat_fs_Cleanup*/
+    return (code);
+}
 
 
 /*------------------------------------------------------------------------
  * [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.
@@ -240,37 +214,34 @@ int xstat_fs_Cleanup(a_releaseMem)
  *     Nothing interesting.
  *------------------------------------------------------------------------*/
 
-static void xstat_fs_LWP()
-
-{ /*xstat_fs_LWP*/
-
-    static char rn[] = "xstat_fs_LWP";         /*Routine name*/
-    register afs_int32 code;                           /*Results of calls*/
-    int oneShotCode;                           /*Result of one-shot signal*/
-    struct timeval tv;                         /*Time structure*/
-    int conn_idx;                              /*Connection index*/
-    struct xstat_fs_ConnectionInfo *curr_conn; /*Current connection*/
-    afs_int32 srvVersionNumber;                        /*Xstat version #*/
-    afs_int32 clientVersionNumber;                     /*Client xstat version*/
-    afs_int32 numColls;                                /*Number of collections to get*/
-    afs_int32 *currCollIDP;                            /*Curr collection ID desired*/
-
-    static afs_int32 xstat_VersionNumber;              /*Version # of server*/
+static void *
+xstat_fs_LWP(void *unused)
+{
+    static char rn[] = "xstat_fs_thread";      /*Routine name */
+    afs_int32 code;    /*Results of calls */
+    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 # */
+    afs_int32 clientVersionNumber;     /*Client xstat version */
+    afs_int32 numColls;                /*Number of collections to get */
+    afs_int32 *currCollIDP;    /*Curr collection ID desired */
 
     /*
      * Set up some numbers we'll need.
      */
     clientVersionNumber = AFS_XSTAT_VERSION;
 
-    while (1) { /*Service loop*/
+    while (1) {                        /*Service loop */
        /*
         * Iterate through the server connections, gathering data.
         * Don't forget to bump the probe count and zero the statistics
         * areas before calling the servers.
         */
        if (xstat_fs_debug)
-           printf("[%s] Waking up, getting data from %d server(s)\n",
-                  rn, xstat_fs_numServers);
+           printf("[%s] Waking up, getting data from %d server(s)\n", rn,
+                  xstat_fs_numServers);
        curr_conn = xstat_fs_ConnInfo;
        xstat_fs_Results.probeNum++;
 
@@ -280,52 +251,49 @@ static void xstat_fs_LWP()
             * connection is valid.
             */
            if (xstat_fs_debug)
-               printf("[%s] Getting collections from File Server '%s'\n",
-                      rn, curr_conn->hostName);
+               printf("[%s] Getting collections from File Server '%s'\n", rn,
+                      curr_conn->hostName);
            if (curr_conn->rxconn != (struct rx_connection *)0) {
                if (xstat_fs_debug)
                    printf("[%s] Connection OK, calling RXAFS_GetXStats\n",
                           rn);
 
                currCollIDP = xstat_fs_collIDP;
-               for (numColls = 0;
-                    numColls < xstat_fs_numCollections;
+               for (numColls = 0; numColls < xstat_fs_numCollections;
                     numColls++, currCollIDP++) {
                    /*
                     * Initialize the per-probe values.
                     */
                    if (xstat_fs_debug)
-                       printf("[%s] Asking for data collection %d\n",
-                              rn, *currCollIDP);
+                       printf("[%s] Asking for data collection %d\n", rn,
+                              *currCollIDP);
                    xstat_fs_Results.collectionNumber = *currCollIDP;
-                   xstat_fs_Results.data.AFS_CollData_len = AFS_MAX_XSTAT_LONGS;
-                   bzero(xstat_fs_Results.data.AFS_CollData_val,
-                         AFS_MAX_XSTAT_LONGS * 4);
-                   
+                   xstat_fs_Results.data.AFS_CollData_len =
+                       AFS_MAX_XSTAT_LONGS;
+                   memset(xstat_fs_Results.data.AFS_CollData_val, 0,
+                          AFS_MAX_XSTAT_LONGS * 4);
+
                    xstat_fs_Results.connP = curr_conn;
-                   
+
                    if (xstat_fs_debug) {
-                       printf("%s: Calling RXAFS_GetXStats, conn=0x%x, clientVersionNumber=%d, collectionNumber=%d, srvVersionNumberP=0x%x, timeP=0x%x, dataP=0x%x\n",
-                              rn, curr_conn->rxconn,
-                              clientVersionNumber,
-                              *currCollIDP,
-                              &srvVersionNumber,
-                              &(xstat_fs_Results.probeTime),
-                              &(xstat_fs_Results.data));
-                       printf("%s: [bufflen=%d, buffer at 0x%x]\n",
-                              rn,
+                       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",
+                            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,
                               xstat_fs_Results.data.AFS_CollData_len,
                               xstat_fs_Results.data.AFS_CollData_val);
                    }
 
                    xstat_fs_Results.probeOK =
                        RXAFS_GetXStats(curr_conn->rxconn,
-                                       clientVersionNumber,
-                                       *currCollIDP,
+                                       clientVersionNumber, *currCollIDP,
                                        &srvVersionNumber,
                                        &(xstat_fs_Results.probeTime),
                                        &(xstat_fs_Results.data));
-                   
+
                    /*
                     * Now that we (may) have the data for this connection,
                     * call the associated handler function.  The handler does
@@ -337,18 +305,19 @@ static void xstat_fs_LWP()
                    code = xstat_fs_Handler();
                    if (code)
                        fprintf(stderr,
-                               "[%s] Handler returned error code %d\n",
-                               rn, code);
-                   
-               } /*For each collection*/
-           } /*Valid Rx connection*/
-           
+                               "[%s] Handler returned error code %d\n", rn,
+                               code);
+
+               }               /*For each collection */
+           }
+
+           /*Valid Rx connection */
            /*
             * Advance the xstat_fs connection pointer.
             */
            curr_conn++;
 
-       } /*For each xstat_fs connection*/
+       }                       /*For each xstat_fs connection */
 
        /*
         * All (valid) connections have been probed.  Fall asleep for the
@@ -356,55 +325,37 @@ static void xstat_fs_LWP()
         * that case, we need to signal our caller that we're done.
         */
        if (xstat_fs_debug)
-           printf("[%s] Polling complete for probe round %d.\n",
-                  rn, xstat_fs_Results.probeNum);
+           printf("[%s] Polling complete for probe round %d.\n", rn,
+                  xstat_fs_Results.probeNum);
 
        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 0x%x\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);
-       } /*Continuous execution*/
-    } /*Service loop*/
-
-} /*xstat_fs_LWP*/
-
+           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;
+}
 
 /*------------------------------------------------------------------------
  * [exported] xstat_fs_Init
  *
  * 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.
  *
@@ -432,30 +383,23 @@ static void xstat_fs_LWP()
  *     Sets up just about everything.
  *------------------------------------------------------------------------*/
 
-int xstat_fs_Init(a_numServers, a_socketArray, a_ProbeFreqInSecs, a_ProbeHandler,
-                 a_flags, a_numCollections, a_collIDP)
-    int a_numServers;
-    struct sockaddr_in *a_socketArray;
-    int a_ProbeFreqInSecs;
-    int (*a_ProbeHandler)();
-    int a_flags;
-    int a_numCollections;
-    afs_int32 *a_collIDP;
-
-{ /*xstat_fs_Init*/
-
-    static char rn[] = "xstat_fs_Init";                /*Routine name*/
-    register afs_int32 code;                           /*Return value*/
-    static struct rx_securityClass *CBsecobj;  /*Callback security object*/
-    struct rx_securityClass *secobj;           /*Client security object*/
-    struct rx_service *rxsrv_afsserver;                /*Server for AFS*/
-    int arg_errfound;                          /*Argument error found?*/
-    int curr_srv;                              /*Current server idx*/
-    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*/
+int
+xstat_fs_Init(int a_numServers, struct sockaddr_in *a_socketArray,
+             int a_ProbeFreqInSecs, int (*a_ProbeHandler) (void), int a_flags,
+             int a_numCollections, afs_int32 * a_collIDP)
+{
+    static char rn[] = "xstat_fs_Init";        /*Routine name */
+    afs_int32 code;    /*Return value */
+    static struct rx_securityClass *CBsecobj;  /*Callback security object */
+    struct rx_securityClass *secobj;   /*Client security object */
+    struct rx_service *rxsrv_afsserver;        /*Server for AFS */
+    int arg_errfound;          /*Argument error found? */
+    int curr_srv;              /*Current server idx */
+    struct xstat_fs_ConnectionInfo *curr_conn; /*Ptr to current conn */
+    char *hostNameFound;       /*Ptr to returned host name */
+    int conn_err;              /*Connection error? */
+    int collIDBytes;           /*Num bytes in coll ID array */
+    char hoststr[16];
 
     /*
      * If we've already been called, snicker at the bozo, gently
@@ -463,18 +407,20 @@ int xstat_fs_Init(a_numServers, a_socketArray, a_ProbeFreqInSecs, a_ProbeHandler
      */
     if (xstat_fs_initflag) {
        fprintf(stderr, "[%s] Called multiple times!\n", rn);
-       return(0);
-    }
-    else
-       xstat_fs_initflag = 1; 
+       return (0);
+    } else
+       xstat_fs_initflag = 1;
+
+    opr_mutex_init(&xstat_fs_force_lock);
+    opr_cv_init(&xstat_fs_force_cv);
 
     /*
      * Check the parameters for bogosities.
      */
     arg_errfound = 0;
     if (a_numServers <= 0) {
-       fprintf(stderr, "[%s] Illegal number of servers: %d\n",
-               rn, a_numServers);
+       fprintf(stderr, "[%s] Illegal number of servers: %d\n", rn,
+               a_numServers);
        arg_errfound = 1;
     }
     if (a_socketArray == (struct sockaddr_in *)0) {
@@ -482,43 +428,43 @@ int xstat_fs_Init(a_numServers, a_socketArray, a_ProbeFreqInSecs, a_ProbeHandler
        arg_errfound = 1;
     }
     if (a_ProbeFreqInSecs <= 0) {
-       fprintf(stderr, "[%s] Illegal probe frequency: %d\n",
-               rn, a_ProbeFreqInSecs);
+       fprintf(stderr, "[%s] Illegal probe frequency: %d\n", rn,
+               a_ProbeFreqInSecs);
        arg_errfound = 1;
     }
-    if (a_ProbeHandler == (int (*)())0) {
-       fprintf(stderr, "[%s] Null probe handler function argument\n",
-               rn);
+    if (a_ProbeHandler == NULL) {
+       fprintf(stderr, "[%s] Null probe handler function argument\n", rn);
        arg_errfound = 1;
     }
     if (a_numCollections <= 0) {
-       fprintf(stderr, "[%s] Illegal collection count argument: %d\n",
-               rn, a_numServers);
+       fprintf(stderr, "[%s] Illegal collection count argument: %d\n", rn,
+               a_numServers);
        arg_errfound = 1;
     }
-    if (a_collIDP == (afs_int32 *)0) {
+    if (a_collIDP == NULL) {
        fprintf(stderr, "[%s] Null collection ID array argument\n", rn);
        arg_errfound = 1;
     }
     if (arg_errfound)
-       return(-1);
+       return (-1);
 
     /*
      * Record our passed-in info.
      */
-    xstat_fs_debug          = (a_flags & XSTAT_FS_INITFLAG_DEBUGGING);
-    xstat_fs_oneShot        = (a_flags & XSTAT_FS_INITFLAG_ONE_SHOT);
-    xstat_fs_numServers      = a_numServers;
-    xstat_fs_Handler        = a_ProbeHandler;
+    xstat_fs_debug = (a_flags & XSTAT_FS_INITFLAG_DEBUGGING);
+    xstat_fs_oneShot = (a_flags & XSTAT_FS_INITFLAG_ONE_SHOT);
+    xstat_fs_numServers = a_numServers;
+    xstat_fs_Handler = a_ProbeHandler;
     xstat_fs_ProbeFreqInSecs = a_ProbeFreqInSecs;
-    xstat_fs_numCollections  = a_numCollections;
+    xstat_fs_numCollections = a_numCollections;
     collIDBytes = xstat_fs_numCollections * sizeof(afs_int32);
-    xstat_fs_collIDP        = (afs_int32 *)(malloc(collIDBytes));
-    bcopy(a_collIDP, xstat_fs_collIDP, collIDBytes);
+    xstat_fs_collIDP = malloc(collIDBytes);
+    memcpy(xstat_fs_collIDP, a_collIDP, collIDBytes);
     if (xstat_fs_debug) {
-       printf("[%s] Asking for %d collection(s): ", rn, xstat_fs_numCollections);
+       printf("[%s] Asking for %d collection(s): ", rn,
+              xstat_fs_numCollections);
        for (curr_srv = 0; curr_srv < xstat_fs_numCollections; curr_srv++)
-           printf("%d ", *(xstat_fs_collIDP+curr_srv));
+           printf("%d ", *(xstat_fs_collIDP + curr_srv));
        printf("\n");
     }
 
@@ -528,21 +474,20 @@ int xstat_fs_Init(a_numServers, a_socketArray, a_ProbeFreqInSecs, a_ProbeHandler
      */
     code = xstat_fs_CleanupInit();
     if (code)
-       return(code);
+       return (code);
 
     /*
      * Allocate the necessary data structures and initialize everything
      * else.
      */
-    xstat_fs_ConnInfo =
-       (struct xstat_fs_ConnectionInfo *)
-           malloc(a_numServers * sizeof(struct xstat_fs_ConnectionInfo));
+    xstat_fs_ConnInfo = malloc(a_numServers
+                              * sizeof(struct xstat_fs_ConnectionInfo));
     if (xstat_fs_ConnInfo == (struct xstat_fs_ConnectionInfo *)0) {
        fprintf(stderr,
-               "[%s] Can't allocate %d connection info structs (%d bytes)\n",
+               "[%s] Can't allocate %d connection info structs (%" AFS_SIZET_FMT " bytes)\n",
                rn, a_numServers,
                (a_numServers * sizeof(struct xstat_fs_ConnectionInfo)));
-       return(-1);     /*No cleanup needs to be done yet*/
+       return (-1);            /*No cleanup needs to be done yet */
     }
 
     /*
@@ -550,26 +495,13 @@ int xstat_fs_Init(a_numServers, a_socketArray, a_ProbeFreqInSecs, a_ProbeHandler
      */
     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
@@ -581,26 +513,25 @@ int xstat_fs_Init(a_numServers, a_socketArray, a_ProbeFreqInSecs, a_ProbeHandler
        fprintf(stderr,
                "[%s] Can't create callback listener's security object.\n",
                rn);
-       xstat_fs_Cleanup(1); /*Delete already-malloc'ed areas*/
-       return(-1);
+       xstat_fs_Cleanup(1);    /*Delete already-malloc'ed areas */
+       return (-1);
     }
     if (xstat_fs_debug)
        printf("[%s] Callback server security object created\n", rn);
-    
+
     /*
      * Create a null Rx client security object, to be used by the
-     * probe LWP.
+     * probe thread.
      */
-    secobj = (struct rx_securityClass *) rxnull_NewClientSecurityObject();
+    secobj = rxnull_NewClientSecurityObject();
     if (secobj == (struct rx_securityClass *)0) {
        fprintf(stderr,
-               "[%s] Can't create probe LWP client security object.\n",
-               rn);
-       xstat_fs_Cleanup(1); /*Delete already-malloc'ed areas*/
-       return(-1);
+               "[%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;
@@ -610,80 +541,75 @@ int xstat_fs_Init(a_numServers, a_socketArray, a_ProbeFreqInSecs, a_ProbeHandler
         * printable name if possible.
         */
        if (xstat_fs_debug) {
-           printf("[%s] Copying in the following socket info:\n",
-                  rn);
-           printf("[%s] IP addr 0x%lx, port %d\n", rn,
-                  (a_socketArray + curr_srv)->sin_addr.s_addr,
-                  (a_socketArray + curr_srv)->sin_port);
+           char hoststr[16];
+           printf("[%s] Copying in the following socket info:\n", rn);
+           printf("[%s] IP addr %s, port %d\n", rn,
+                  afs_inet_ntoa_r((a_socketArray + curr_srv)->sin_addr.s_addr,hoststr),
+                  ntohs((a_socketArray + curr_srv)->sin_port));
        }
-       bcopy(a_socketArray + curr_srv,
-             &(curr_conn->skt),
-             sizeof(struct sockaddr_in));
-       
+       memcpy(&(curr_conn->skt), a_socketArray + curr_srv,
+              sizeof(struct sockaddr_in));
+
        hostNameFound =
            hostutil_GetNameByINet(curr_conn->skt.sin_addr.s_addr);
-       if (hostNameFound == (char *)0) {
+       if (hostNameFound == NULL) {
            fprintf(stderr,
-                   "[%s] Can't map Internet address %lu to a string name\n",
-                   rn, curr_conn->skt.sin_addr.s_addr);
+                   "[%s] Can't map Internet address %s to a string name\n",
+                   rn, afs_inet_ntoa_r(curr_conn->skt.sin_addr.s_addr,hoststr));
            curr_conn->hostName[0] = '\0';
-       }
-       else {
+       } else {
            strcpy(curr_conn->hostName, hostNameFound);
            if (xstat_fs_debug)
-               printf("[%s] Host name for server index %d is %s\n",
-                      rn, curr_srv, curr_conn->hostName);
+               printf("[%s] Host name for server index %d is %s\n", rn,
+                      curr_srv, curr_conn->hostName);
        }
-       
+
        /*
         * Make an Rx connection to the current server.
         */
        if (xstat_fs_debug)
-           printf("[%s] Connecting to srv idx %d, IP addr 0x%lx, port %d, service 1\n",
-                  rn, curr_srv, curr_conn->skt.sin_addr.s_addr,
-                  curr_conn->skt.sin_port);
-
-       curr_conn->rxconn =
-           rx_NewConnection(curr_conn->skt.sin_addr.s_addr, /*Server addr*/
-                            curr_conn->skt.sin_port,        /*Server port*/
-                            1,                              /*AFS service #*/
-                            secobj,                         /*Security obj*/
-                            0);                             /*# of above*/
+           printf
+               ("[%s] Connecting to srv idx %d, IP addr %s, port %d, service 1\n",
+                rn, curr_srv, afs_inet_ntoa_r(curr_conn->skt.sin_addr.s_addr,hoststr),
+                ntohs(curr_conn->skt.sin_port));
+
+       curr_conn->rxconn = rx_NewConnection(curr_conn->skt.sin_addr.s_addr,    /*Server addr */
+                                            curr_conn->skt.sin_port,   /*Server port */
+                                            1, /*AFS service # */
+                                            secobj,    /*Security obj */
+                                            0);        /*# of above */
        if (curr_conn->rxconn == (struct rx_connection *)0) {
            fprintf(stderr,
-                   "[%s] Can't create Rx connection to server '%s' (%lu)\n",
-                   rn, curr_conn->hostName, curr_conn->skt.sin_addr.s_addr);
+                   "[%s] Can't create Rx connection to server '%s' (%s)\n",
+                   rn, curr_conn->hostName, afs_inet_ntoa_r(curr_conn->skt.sin_addr.s_addr,hoststr));
            conn_err = 1;
        }
        if (xstat_fs_debug)
-           printf("[%s] New connection at 0x%lx\n",
-                  rn, curr_conn->rxconn);
+           printf("[%s] New connection at %" AFS_PTR_FMT "\n", rn, curr_conn->rxconn);
 
        /*
         * Bump the current xstat_fs connection to set up.
         */
        curr_conn++;
 
-    } /*for curr_srv*/
+    }                          /*for curr_srv */
 
     /*
      * Create the AFS callback service (listener).
      */
     if (xstat_fs_debug)
        printf("[%s] Creating AFS callback listener\n", rn);
-    rxsrv_afsserver =
-       rx_NewService(0,                        /*Use default port*/
-                     1,                        /*Service ID*/
-                     "afs",                    /*Service name*/
-                     &CBsecobj,                /*Ptr to security object(s)*/
-                     1,                        /*# of security objects*/
-                     RXAFSCB_ExecuteRequest);  /*Dispatcher*/
+    rxsrv_afsserver = rx_NewService(0, /*Use default port */
+                                   1,  /*Service ID */
+                                   "afs",      /*Service name */
+                                   &CBsecobj,  /*Ptr to security object(s) */
+                                   1,  /*# of security objects */
+                                   RXAFSCB_ExecuteRequest);    /*Dispatcher */
     if (rxsrv_afsserver == (struct rx_service *)0) {
-       fprintf(stderr,
-               "[%s] Can't create callback Rx service/listener\n",
+       fprintf(stderr, "[%s] Can't create callback Rx service/listener\n",
                rn);
-       xstat_fs_Cleanup(1); /*Delete already-malloc'ed areas*/
-       return(-1);
+       xstat_fs_Cleanup(1);    /*Delete already-malloc'ed areas */
+       return (-1);
     }
     if (xstat_fs_debug)
        printf("[%s] Callback listener created\n", rn);
@@ -693,47 +619,36 @@ int xstat_fs_Init(a_numServers, a_socketArray, a_ProbeFreqInSecs, a_ProbeHandler
      */
     if (xstat_fs_debug)
        printf("[%s] Starting up callback listener.\n", rn);
-    rx_StartServer(0); /*Don't donate yourself to LWP pool*/
+    rx_StartServer(0);         /*Don't donate yourself to LWP pool */
 
     /*
      * 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*/
-                         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, code);
-       xstat_fs_Cleanup(1); /*Delete already-malloc'ed areas*/
-       return(code);
+       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 0x%x\n",
-              rn, probeLWP_ID);
 
     /*
      * Return the final results.
      */
     if (conn_err)
-       return(-2);
+       return (-2);
     else
-       return(0);
-
-} /*xstat_fs_Init*/
+       return (0);
+}
 
 
 /*------------------------------------------------------------------------
  * [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.
@@ -749,28 +664,230 @@ int xstat_fs_Init(a_numServers, a_socketArray, a_ProbeFreqInSecs, a_ProbeHandler
  *     As advertised.
  *------------------------------------------------------------------------*/
 
-int xstat_fs_ForceProbeNow()
-
-{ /*xstat_fs_ForceProbeNow*/
-
-    static char rn[] = "xstat_fs_ForceProbeNow";       /*Routine name*/
+int
+xstat_fs_ForceProbeNow(void)
+{
+    static char rn[] = "xstat_fs_ForceProbeNow";       /*Routine name */
 
     /*
      * There isn't a prayer unless we've been initialized.
      */
     if (!xstat_fs_initflag) {
        fprintf(stderr, "[%s] Must call xstat_fs_Init first!\n", rn);
-       return(-1);
+       return (-1);
     }
 
     /*
      * 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.
      */
-    return(0);
+    return (0);
+}
+
+/**
+ * Fill the xstat full perf data structure from the data collection array.
+ *
+ * This function is a client-side decoding of the non-portable xstat_fs full
+ * performance data.  The full perf structure includes timeval structures,
+ * which have platform dependent size.
+ *
+ * To make things even more interesting, the word ordering of the time
+ * values on hosts with 64-bit time depend on endianess. The ordering
+ * within a given afs_int32 is handled by xdr.
+ *
+ * @param[out] aout an address to a stats structure pointer
+ * @param[in] ain array of int32s received
+ * @param[in] alen length of ain
+ * @param[inout] abuf a buffer provided by the caller
+ *
+ * @return 0 on success
+ */
+int
+xstat_fs_DecodeFullPerfStats(struct fs_stats_FullPerfStats **aout,
+                            afs_int32 * ain,
+                            afs_int32 alen,
+                            struct fs_stats_FullPerfStats *abuf)
+{
+    int i;
+    afs_int32 *p;
+    int snbo = -2;     /* detected remote site has network-byte ordering */
+
+    static const int XSTAT_FPS_LEN = sizeof(struct fs_stats_FullPerfStats) / sizeof(afs_int32);        /* local size of fps */
+    static const int XSTAT_FPS_SMALL = 424;    /**< fps size when sizeof(timeval) is 2*sizeof(afs_int32) */
+    static const int XSTAT_FPS_LARGE = 666;    /**< fps size when sizeof(timeval) is 2*sizeof(afs_int64) */
+
+#define DECODE_TV(t) \
+    do { \
+       if (alen == XSTAT_FPS_SMALL) { \
+           (t).tv_sec = *p++; \
+           (t).tv_usec = *p++; \
+       } else { \
+           if (snbo) { \
+               p++; \
+               (t).tv_sec = *p++; \
+               p++; \
+               (t).tv_usec = *p++; \
+           } else { \
+               (t).tv_sec = *p++; \
+               p++; \
+               (t).tv_usec = *p++; \
+               p++; \
+           } \
+       } \
+    } while (0)
+
+    if (alen != XSTAT_FPS_SMALL && alen != XSTAT_FPS_LARGE) {
+       return -1;              /* unrecognized size */
+    }
+
+    if (alen == XSTAT_FPS_LEN && alen == XSTAT_FPS_SMALL) {
+       /* Same size, and xdr dealt with byte ordering; no decoding needed. */
+       *aout = (struct fs_stats_FullPerfStats *)ain;
+       return 0;
+    }
+
+    if (alen == XSTAT_FPS_LARGE) {
+       /* Attempt to detect the word ordering of the time values. */
+       struct fs_stats_FullPerfStats *fps =
+           (struct fs_stats_FullPerfStats *)ain;
+       afs_int32 *epoch = (afs_int32 *) & (fps->det.epoch);
+       if (epoch[0] == 0 && epoch[1] != 0) {
+           snbo = 1;
+       } else if (epoch[0] != 0 && epoch[1] == 0) {
+           snbo = 0;
+       } else {
+           return -2;          /* failed to detect server word ordering */
+       }
+    }
+
+    if (alen == XSTAT_FPS_LEN && alen == XSTAT_FPS_LARGE
+#if defined(WORDS_BIGENDIAN)
+       && snbo
+#else /* WORDS_BIGENDIAN */
+       && !snbo
+#endif /* WORDS_BIGENDIAN */
+       ) {
+       /* Same size and order; no decoding needed. */
+       *aout = (struct fs_stats_FullPerfStats *)ain;
+       return 0;
+    }
+
+    /* Either different sizes, or different ordering, or both. Schlep over
+     * each field, decoding time values. The fields up to the first time value
+     * can be copied in bulk. */
+    if (xstat_fs_debug) {
+       printf("debug: Decoding xstat full perf stats; length=%d", alen);
+       if (alen == XSTAT_FPS_LARGE) {
+           printf(", order='%s'", (snbo ? "big-endian" : "little-endian"));
+       }
+       printf("\n");
+    }
+
+    p = ain;
+    memset(abuf, 0, sizeof(struct fs_stats_FullPerfStats));
+    memcpy(abuf, p, sizeof(struct afs_PerfStats));
+    p += sizeof(struct afs_PerfStats) / sizeof(afs_int32);
+
+    DECODE_TV(abuf->det.epoch);
+    for (i = 0; i < FS_STATS_NUM_RPC_OPS; i++) {
+       struct fs_stats_opTimingData *td = abuf->det.rpcOpTimes + i;
+       td->numOps = *p++;
+       td->numSuccesses = *p++;
+       DECODE_TV(td->sumTime);
+       DECODE_TV(td->sqrTime);
+       DECODE_TV(td->minTime);
+       DECODE_TV(td->maxTime);
+    }
+    for (i = 0; i < FS_STATS_NUM_XFER_OPS; i++) {
+       struct fs_stats_xferData *xd = abuf->det.xferOpTimes + i;
+       xd->numXfers = *p++;
+       xd->numSuccesses = *p++;
+       DECODE_TV(xd->sumTime);
+       DECODE_TV(xd->sqrTime);
+       DECODE_TV(xd->minTime);
+       DECODE_TV(xd->maxTime);
+       xd->sumBytes = *p++;
+       xd->minBytes = *p++;
+       xd->maxBytes = *p++;
+       memcpy((void *)xd->count, (void *)p,
+              sizeof(afs_int32) * FS_STATS_NUM_XFER_BUCKETS);
+       p += FS_STATS_NUM_XFER_BUCKETS;
+    }
+    *aout = abuf;
+    return 0;
+#undef DECODE_TV
+}
 
-} /*xstat_fs_ForceProbeNow*/
+/*
+ * 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. */
+       tv.tv_sec = 24 * 60;
+       tv.tv_usec = 0;
+       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 */
+                         &tv); /*Timeout structure */
+           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;
+}