2 * Copyright 2000, International Business Machines Corporation and others.
5 * This software has been released under the terms of the IBM Public
6 * License. For details, see the LICENSE file in the top-level source
7 * directory or online at http://www.openafs.org/dl/license10.html
12 * Implementation of the client side of the AFS File Server extended
13 * statistics facility.
15 *------------------------------------------------------------------------*/
17 #include <afsconfig.h>
18 #include <afs/param.h>
23 #include "xstat_fs.h" /*Interface for this module */
26 #include <afs/afsutil.h>
27 #include <afs/afscbint.h>
32 int xstat_fs_numServers; /*Num connected servers */
33 struct xstat_fs_ConnectionInfo
34 *xstat_fs_ConnInfo; /*Ptr to connection array */
35 struct xstat_fs_ProbeResults xstat_fs_Results; /*Latest probe results */
37 afs_int32 xstat_fsData[AFS_MAX_XSTAT_LONGS]; /*Buffer for collected data */
42 static int xstat_fs_ProbeFreqInSecs; /*Probe freq. in seconds */
43 static int xstat_fs_initflag = 0; /*Was init routine called? */
44 static int xstat_fs_debug = 0; /*Debugging output enabled? */
45 static int xstat_fs_oneShot = 0; /*One-shot operation? */
46 static int (*xstat_fs_Handler) (void); /*Probe handler routine */
47 static pthread_t xstat_fs_thread; /*Probe thread */
48 static int xstat_fs_numCollections; /*Number of desired collections */
49 static afs_int32 *xstat_fs_collIDP; /*Ptr to collection IDs desired */
50 static opr_mutex_t xstat_fs_force_lock; /*Lock to wakeup probe */
51 static opr_cv_t xstat_fs_force_cv; /*Condvar to wakeup probe */
54 /*------------------------------------------------------------------------
55 * [private] xstat_fs_CleanupInit
58 * Set up for recovery after an error in initialization (i.e.,
59 * during a call to xstat_fs_Init.
66 * Error value otherwise.
69 * This routine is private to the module.
72 * Zeros out basic data structures.
73 *------------------------------------------------------------------------*/
76 xstat_fs_CleanupInit(void)
78 afs_int32 code; /*Return code from callback stubs */
79 struct rx_call *rxcall; /*Bogus param */
80 AFSCBFids *Fids_Array; /*Bogus param */
81 AFSCBs *CallBack_Array; /*Bogus param */
83 xstat_fs_ConnInfo = (struct xstat_fs_ConnectionInfo *)0;
84 xstat_fs_Results.probeNum = 0;
85 xstat_fs_Results.probeTime = 0;
86 xstat_fs_Results.connP = (struct xstat_fs_ConnectionInfo *)0;
87 xstat_fs_Results.collectionNumber = 0;
88 xstat_fs_Results.data.AFS_CollData_len = AFS_MAX_XSTAT_LONGS;
89 xstat_fs_Results.data.AFS_CollData_val = (afs_int32 *) xstat_fsData;
90 xstat_fs_Results.probeOK = 0;
92 rxcall = (struct rx_call *)0;
93 Fids_Array = (AFSCBFids *) 0;
94 CallBack_Array = (AFSCBs *) 0;
97 * Call each of the callback routines our module provides (in
98 * xstat_fs_callback.c) to make sure they're all there.
100 code = SRXAFSCB_CallBack(rxcall, Fids_Array, CallBack_Array);
103 code = SRXAFSCB_InitCallBackState3(rxcall, (afsUUID *) 0);
106 code = SRXAFSCB_Probe(rxcall);
111 /*------------------------------------------------------------------------
112 * [exported] xstat_fs_Cleanup
115 * Clean up our memory and connection state.
118 * int a_releaseMem : Should we free up malloc'ed areas?
121 * 0 on total success,
122 * -1 if the module was never initialized, or there was a problem
123 * with the xstat_fs connection array.
126 * xstat_fs_numServers should be properly set. We don't do anything
127 * unless xstat_fs_Init() has already been called.
130 * Shuts down Rx connections gracefully, frees allocated space
132 *------------------------------------------------------------------------*/
135 xstat_fs_Cleanup(int a_releaseMem)
137 static char rn[] = "xstat_fs_Cleanup"; /*Routine name */
138 int code; /*Return code */
139 int conn_idx; /*Current connection index */
140 struct xstat_fs_ConnectionInfo *curr_conn; /*Ptr to xstat_fs connection */
143 * Assume the best, but check the worst.
145 if (!xstat_fs_initflag) {
146 fprintf(stderr, "[%s] Refused; module not initialized\n", rn);
152 * Take care of all Rx connections first. Check to see that the
153 * server count is a legal value.
155 if (xstat_fs_numServers <= 0) {
157 "[%s] Illegal number of servers (xstat_fs_numServers = %d)\n",
158 rn, xstat_fs_numServers);
161 if (xstat_fs_ConnInfo != (struct xstat_fs_ConnectionInfo *)0) {
163 * The xstat_fs connection structure array exists. Go through
164 * it and close up any Rx connections it holds.
166 curr_conn = xstat_fs_ConnInfo;
167 for (conn_idx = 0; conn_idx < xstat_fs_numServers; conn_idx++) {
168 if (curr_conn->rxconn != (struct rx_connection *)0) {
169 rx_DestroyConnection(curr_conn->rxconn);
170 curr_conn->rxconn = (struct rx_connection *)0;
173 } /*for each xstat_fs connection */
174 } /*xstat_fs connection structure exists */
175 } /*Legal number of servers */
178 * If asked to, release the space we've allocated.
181 if (xstat_fs_ConnInfo != (struct xstat_fs_ConnectionInfo *)0)
182 free(xstat_fs_ConnInfo);
186 * Return the news, whatever it is.
192 /*------------------------------------------------------------------------
193 * [private] xstat_fs_LWP
196 * This thread iterates over the server connections and gathers up
197 * the desired statistics from each one on a regular basis. When
198 * the sweep is done, the associated handler function is called
199 * to process the new data.
208 * Started by xstat_fs_Init(), uses global structures and the
209 * global private xstat_fs_oneShot variable.
212 * Nothing interesting.
213 *------------------------------------------------------------------------*/
216 xstat_fs_LWP(void *unused)
218 static char rn[] = "xstat_fs_thread"; /*Routine name */
219 afs_int32 code; /*Results of calls */
220 struct timeval tv; /*Time structure */
221 struct timespec wait; /*Time to wait */
222 int conn_idx; /*Connection index */
223 struct xstat_fs_ConnectionInfo *curr_conn; /*Current connection */
224 afs_int32 srvVersionNumber; /*Xstat version # */
225 afs_int32 clientVersionNumber; /*Client xstat version */
226 afs_int32 numColls; /*Number of collections to get */
227 afs_int32 *currCollIDP; /*Curr collection ID desired */
230 * Set up some numbers we'll need.
232 clientVersionNumber = AFS_XSTAT_VERSION;
234 while (1) { /*Service loop */
236 * Iterate through the server connections, gathering data.
237 * Don't forget to bump the probe count and zero the statistics
238 * areas before calling the servers.
241 printf("[%s] Waking up, getting data from %d server(s)\n", rn,
242 xstat_fs_numServers);
243 curr_conn = xstat_fs_ConnInfo;
244 xstat_fs_Results.probeNum++;
246 for (conn_idx = 0; conn_idx < xstat_fs_numServers; conn_idx++) {
248 * Grab the statistics for the current File Server, if the
249 * connection is valid.
252 printf("[%s] Getting collections from File Server '%s'\n", rn,
253 curr_conn->hostName);
254 if (curr_conn->rxconn != (struct rx_connection *)0) {
256 printf("[%s] Connection OK, calling RXAFS_GetXStats\n",
259 currCollIDP = xstat_fs_collIDP;
260 for (numColls = 0; numColls < xstat_fs_numCollections;
261 numColls++, currCollIDP++) {
263 * Initialize the per-probe values.
266 printf("[%s] Asking for data collection %d\n", rn,
268 xstat_fs_Results.collectionNumber = *currCollIDP;
269 xstat_fs_Results.data.AFS_CollData_len =
271 memset(xstat_fs_Results.data.AFS_CollData_val, 0,
272 AFS_MAX_XSTAT_LONGS * 4);
274 xstat_fs_Results.connP = curr_conn;
276 if (xstat_fs_debug) {
278 ("%s: Calling RXAFS_GetXStats, conn=%p, clientVersionNumber=%d, collectionNumber=%d, srvVersionNumberP=%p, timeP=%p, dataP=%p\n",
279 rn, curr_conn->rxconn, clientVersionNumber,
280 *currCollIDP, &srvVersionNumber,
281 &(xstat_fs_Results.probeTime),
282 &(xstat_fs_Results.data));
283 printf("%s: [bufflen=%d, buffer at %p]\n", rn,
284 xstat_fs_Results.data.AFS_CollData_len,
285 xstat_fs_Results.data.AFS_CollData_val);
288 xstat_fs_Results.probeOK =
289 RXAFS_GetXStats(curr_conn->rxconn,
290 clientVersionNumber, *currCollIDP,
292 &(xstat_fs_Results.probeTime),
293 &(xstat_fs_Results.data));
296 * Now that we (may) have the data for this connection,
297 * call the associated handler function. The handler does
298 * not take any explicit parameters, but rather gets to the
299 * goodies via some of the objects exported by this module.
302 printf("[%s] Calling handler routine.\n", rn);
303 code = xstat_fs_Handler();
306 "[%s] Handler returned error code %d\n", rn,
309 } /*For each collection */
312 /*Valid Rx connection */
314 * Advance the xstat_fs connection pointer.
318 } /*For each xstat_fs connection */
321 * All (valid) connections have been probed. Fall asleep for the
322 * prescribed number of seconds, unless we're a one-shot. In
323 * that case, we need to signal our caller that we're done.
326 printf("[%s] Polling complete for probe round %d.\n", rn,
327 xstat_fs_Results.probeNum);
329 if (xstat_fs_oneShot) {
331 * One-shot execution desired.
336 * Continuous execution desired. Sleep for the required
337 * number of seconds or wakeup sooner if forced.
339 gettimeofday(&tv, NULL);
340 wait.tv_sec = tv.tv_sec + xstat_fs_ProbeFreqInSecs;
341 wait.tv_nsec = tv.tv_usec * 1000;
342 opr_mutex_enter(&xstat_fs_force_lock);
343 code = opr_cv_timedwait(&xstat_fs_force_cv, &xstat_fs_force_lock, &wait);
344 opr_Verify(code == 0 || code == ETIMEDOUT);
345 opr_mutex_exit(&xstat_fs_force_lock);
346 } /*Continuous execution */
351 /*------------------------------------------------------------------------
352 * [exported] xstat_fs_Init
355 * Initialize the xstat_fs module: set up Rx connections to the
356 * given set of File Servers, start up the probe and callback threads,
357 * and associate the routine to be called when a probe completes.
358 * Also, let it know which collections you're interested in.
361 * int a_numServers : Num. servers to connect to.
362 * struct sockaddr_in *a_socketArray : Array of server sockets.
363 * int a_ProbeFreqInSecs : Probe frequency in seconds.
364 * int (*a_ProbeHandler)() : Ptr to probe handler fcn.
365 * int a_flags : Various flags.
366 * int a_numCollections : Number of collections desired.
367 * afs_int32 *a_collIDP : Ptr to collection IDs.
371 * -2 for (at least one) connection error,
372 * LWP process creation code, if it failed,
373 * -1 for other fatal errors.
376 * *** MUST BE THE FIRST ROUTINE CALLED FROM THIS PACKAGE ***
377 * Also, the server security object CBsecobj MUST be a static,
378 * since it has to stick around after this routine exits.
381 * Sets up just about everything.
382 *------------------------------------------------------------------------*/
385 xstat_fs_Init(int a_numServers, struct sockaddr_in *a_socketArray,
386 int a_ProbeFreqInSecs, int (*a_ProbeHandler) (void), int a_flags,
387 int a_numCollections, afs_int32 * a_collIDP)
389 static char rn[] = "xstat_fs_Init"; /*Routine name */
390 afs_int32 code; /*Return value */
391 static struct rx_securityClass *CBsecobj; /*Callback security object */
392 struct rx_securityClass *secobj; /*Client security object */
393 struct rx_service *rxsrv_afsserver; /*Server for AFS */
394 int arg_errfound; /*Argument error found? */
395 int curr_srv; /*Current server idx */
396 struct xstat_fs_ConnectionInfo *curr_conn; /*Ptr to current conn */
397 char *hostNameFound; /*Ptr to returned host name */
398 int conn_err; /*Connection error? */
399 int collIDBytes; /*Num bytes in coll ID array */
403 * If we've already been called, snicker at the bozo, gently
404 * remind him of his doubtful heritage, and return success.
406 if (xstat_fs_initflag) {
407 fprintf(stderr, "[%s] Called multiple times!\n", rn);
410 xstat_fs_initflag = 1;
412 opr_mutex_init(&xstat_fs_force_lock);
413 opr_cv_init(&xstat_fs_force_cv);
416 * Check the parameters for bogosities.
419 if (a_numServers <= 0) {
420 fprintf(stderr, "[%s] Illegal number of servers: %d\n", rn,
424 if (a_socketArray == (struct sockaddr_in *)0) {
425 fprintf(stderr, "[%s] Null server socket array argument\n", rn);
428 if (a_ProbeFreqInSecs <= 0) {
429 fprintf(stderr, "[%s] Illegal probe frequency: %d\n", rn,
433 if (a_ProbeHandler == NULL) {
434 fprintf(stderr, "[%s] Null probe handler function argument\n", rn);
437 if (a_numCollections <= 0) {
438 fprintf(stderr, "[%s] Illegal collection count argument: %d\n", rn,
442 if (a_collIDP == NULL) {
443 fprintf(stderr, "[%s] Null collection ID array argument\n", rn);
450 * Record our passed-in info.
452 xstat_fs_debug = (a_flags & XSTAT_FS_INITFLAG_DEBUGGING);
453 xstat_fs_oneShot = (a_flags & XSTAT_FS_INITFLAG_ONE_SHOT);
454 xstat_fs_numServers = a_numServers;
455 xstat_fs_Handler = a_ProbeHandler;
456 xstat_fs_ProbeFreqInSecs = a_ProbeFreqInSecs;
457 xstat_fs_numCollections = a_numCollections;
458 collIDBytes = xstat_fs_numCollections * sizeof(afs_int32);
459 xstat_fs_collIDP = malloc(collIDBytes);
460 memcpy(xstat_fs_collIDP, a_collIDP, collIDBytes);
461 if (xstat_fs_debug) {
462 printf("[%s] Asking for %d collection(s): ", rn,
463 xstat_fs_numCollections);
464 for (curr_srv = 0; curr_srv < xstat_fs_numCollections; curr_srv++)
465 printf("%d ", *(xstat_fs_collIDP + curr_srv));
470 * Get ready in case we have to do a cleanup - basically, zero
473 code = xstat_fs_CleanupInit();
478 * Allocate the necessary data structures and initialize everything
481 xstat_fs_ConnInfo = malloc(a_numServers
482 * sizeof(struct xstat_fs_ConnectionInfo));
483 if (xstat_fs_ConnInfo == (struct xstat_fs_ConnectionInfo *)0) {
485 "[%s] Can't allocate %d connection info structs (%" AFS_SIZET_FMT " bytes)\n",
487 (a_numServers * sizeof(struct xstat_fs_ConnectionInfo)));
488 return (-1); /*No cleanup needs to be done yet */
492 * Initialize the Rx subsystem, just in case nobody's done it.
495 printf("[%s] Initializing Rx\n", rn);
498 fprintf(stderr, "[%s] Fatal error in rx_Init()\n", rn);
502 printf("[%s] Rx initialized\n", rn);
505 * Create a null Rx server security object, to be used by the
508 CBsecobj = (struct rx_securityClass *)
509 rxnull_NewServerSecurityObject();
510 if (CBsecobj == (struct rx_securityClass *)0) {
512 "[%s] Can't create callback listener's security object.\n",
514 xstat_fs_Cleanup(1); /*Delete already-malloc'ed areas */
518 printf("[%s] Callback server security object created\n", rn);
521 * Create a null Rx client security object, to be used by the
524 secobj = rxnull_NewClientSecurityObject();
525 if (secobj == (struct rx_securityClass *)0) {
527 "[%s] Can't create probe thread client security object.\n", rn);
528 xstat_fs_Cleanup(1); /*Delete already-malloc'ed areas */
532 printf("[%s] Probe thread client security object created\n", rn);
534 curr_conn = xstat_fs_ConnInfo;
536 for (curr_srv = 0; curr_srv < a_numServers; curr_srv++) {
538 * Copy in the socket info for the current server, resolve its
539 * printable name if possible.
541 if (xstat_fs_debug) {
543 printf("[%s] Copying in the following socket info:\n", rn);
544 printf("[%s] IP addr %s, port %d\n", rn,
545 afs_inet_ntoa_r((a_socketArray + curr_srv)->sin_addr.s_addr,hoststr),
546 ntohs((a_socketArray + curr_srv)->sin_port));
548 memcpy(&(curr_conn->skt), a_socketArray + curr_srv,
549 sizeof(struct sockaddr_in));
552 hostutil_GetNameByINet(curr_conn->skt.sin_addr.s_addr);
553 if (hostNameFound == NULL) {
555 "[%s] Can't map Internet address %s to a string name\n",
556 rn, afs_inet_ntoa_r(curr_conn->skt.sin_addr.s_addr,hoststr));
557 curr_conn->hostName[0] = '\0';
559 strcpy(curr_conn->hostName, hostNameFound);
561 printf("[%s] Host name for server index %d is %s\n", rn,
562 curr_srv, curr_conn->hostName);
566 * Make an Rx connection to the current server.
570 ("[%s] Connecting to srv idx %d, IP addr %s, port %d, service 1\n",
571 rn, curr_srv, afs_inet_ntoa_r(curr_conn->skt.sin_addr.s_addr,hoststr),
572 ntohs(curr_conn->skt.sin_port));
574 curr_conn->rxconn = rx_NewConnection(curr_conn->skt.sin_addr.s_addr, /*Server addr */
575 curr_conn->skt.sin_port, /*Server port */
576 1, /*AFS service # */
577 secobj, /*Security obj */
579 if (curr_conn->rxconn == (struct rx_connection *)0) {
581 "[%s] Can't create Rx connection to server '%s' (%s)\n",
582 rn, curr_conn->hostName, afs_inet_ntoa_r(curr_conn->skt.sin_addr.s_addr,hoststr));
586 printf("[%s] New connection at %p\n", rn, curr_conn->rxconn);
589 * Bump the current xstat_fs connection to set up.
596 * Create the AFS callback service (listener).
599 printf("[%s] Creating AFS callback listener\n", rn);
600 rxsrv_afsserver = rx_NewService(0, /*Use default port */
602 "afs", /*Service name */
603 &CBsecobj, /*Ptr to security object(s) */
604 1, /*# of security objects */
605 RXAFSCB_ExecuteRequest); /*Dispatcher */
606 if (rxsrv_afsserver == (struct rx_service *)0) {
607 fprintf(stderr, "[%s] Can't create callback Rx service/listener\n",
609 xstat_fs_Cleanup(1); /*Delete already-malloc'ed areas */
613 printf("[%s] Callback listener created\n", rn);
616 * Start up the AFS callback service.
619 printf("[%s] Starting up callback listener.\n", rn);
620 rx_StartServer(0); /*Don't donate yourself to LWP pool */
623 * Start up the probe LWP.
626 printf("[%s] Creating the probe thread\n", rn);
627 code = pthread_create(&xstat_fs_thread, NULL, xstat_fs_LWP, NULL);
629 fprintf(stderr, "[%s] Can't create xstat_fs thread! Error is %d\n", rn,
631 xstat_fs_Cleanup(1); /*Delete already-malloc'ed areas */
636 * Return the final results.
645 /*------------------------------------------------------------------------
646 * [exported] xstat_fs_ForceProbeNow
649 * Wake up the probe thread, forcing it to execute a probe immediately.
656 * Error value otherwise.
659 * The module must have been initialized.
663 *------------------------------------------------------------------------*/
666 xstat_fs_ForceProbeNow(void)
668 static char rn[] = "xstat_fs_ForceProbeNow"; /*Routine name */
671 * There isn't a prayer unless we've been initialized.
673 if (!xstat_fs_initflag) {
674 fprintf(stderr, "[%s] Must call xstat_fs_Init first!\n", rn);
679 * Kick the sucker in the side.
681 opr_mutex_enter(&xstat_fs_force_lock);
682 opr_cv_signal(&xstat_fs_force_cv);
683 opr_mutex_exit(&xstat_fs_force_lock);
686 * We did it, so report the happy news.
692 * Fill the xstat full perf data structure from the data collection array.
694 * This function is a client-side decoding of the non-portable xstat_fs full
695 * performance data. The full perf structure includes timeval structures,
696 * which have platform dependent size.
698 * To make things even more interesting, the word ordering of the time
699 * values on hosts with 64-bit time depend on endianess. The ordering
700 * within a given afs_int32 is handled by xdr.
702 * @param[out] aout an address to a stats structure pointer
703 * @param[in] ain array of int32s received
704 * @param[in] alen length of ain
705 * @param[inout] abuf a buffer provided by the caller
707 * @return 0 on success
710 xstat_fs_DecodeFullPerfStats(struct fs_stats_FullPerfStats **aout,
713 struct fs_stats_FullPerfStats *abuf)
717 int snbo = -2; /* detected remote site has network-byte ordering */
719 static const int XSTAT_FPS_LEN = sizeof(struct fs_stats_FullPerfStats) / sizeof(afs_int32); /* local size of fps */
720 static const int XSTAT_FPS_SMALL = 424; /**< fps size when sizeof(timeval) is 2*sizeof(afs_int32) */
721 static const int XSTAT_FPS_LARGE = 666; /**< fps size when sizeof(timeval) is 2*sizeof(afs_int64) */
723 #define DECODE_TV(t) \
725 if (alen == XSTAT_FPS_SMALL) { \
727 (t).tv_usec = *p++; \
733 (t).tv_usec = *p++; \
737 (t).tv_usec = *p++; \
743 if (alen != XSTAT_FPS_SMALL && alen != XSTAT_FPS_LARGE) {
744 return -1; /* unrecognized size */
747 if (alen == XSTAT_FPS_LEN && alen == XSTAT_FPS_SMALL) {
748 /* Same size, and xdr dealt with byte ordering; no decoding needed. */
749 *aout = (struct fs_stats_FullPerfStats *)ain;
753 if (alen == XSTAT_FPS_LARGE) {
754 /* Attempt to detect the word ordering of the time values. */
755 struct fs_stats_FullPerfStats *fps =
756 (struct fs_stats_FullPerfStats *)ain;
757 afs_int32 *epoch = (afs_int32 *) & (fps->det.epoch);
758 if (epoch[0] == 0 && epoch[1] != 0) {
760 } else if (epoch[0] != 0 && epoch[1] == 0) {
763 return -2; /* failed to detect server word ordering */
767 if (alen == XSTAT_FPS_LEN && alen == XSTAT_FPS_LARGE
768 #if defined(WORDS_BIGENDIAN)
770 #else /* WORDS_BIGENDIAN */
772 #endif /* WORDS_BIGENDIAN */
774 /* Same size and order; no decoding needed. */
775 *aout = (struct fs_stats_FullPerfStats *)ain;
779 /* Either different sizes, or different ordering, or both. Schlep over
780 * each field, decoding time values. The fields up to the first time value
781 * can be copied in bulk. */
782 if (xstat_fs_debug) {
783 printf("debug: Decoding xstat full perf stats; length=%d", alen);
784 if (alen == XSTAT_FPS_LARGE) {
785 printf(", order='%s'", (snbo ? "big-endian" : "little-endian"));
791 memset(abuf, 0, sizeof(struct fs_stats_FullPerfStats));
792 memcpy(abuf, p, sizeof(struct afs_PerfStats));
793 p += sizeof(struct afs_PerfStats) / sizeof(afs_int32);
795 DECODE_TV(abuf->det.epoch);
796 for (i = 0; i < FS_STATS_NUM_RPC_OPS; i++) {
797 struct fs_stats_opTimingData *td = abuf->det.rpcOpTimes + i;
799 td->numSuccesses = *p++;
800 DECODE_TV(td->sumTime);
801 DECODE_TV(td->sqrTime);
802 DECODE_TV(td->minTime);
803 DECODE_TV(td->maxTime);
805 for (i = 0; i < FS_STATS_NUM_XFER_OPS; i++) {
806 struct fs_stats_xferData *xd = abuf->det.xferOpTimes + i;
808 xd->numSuccesses = *p++;
809 DECODE_TV(xd->sumTime);
810 DECODE_TV(xd->sqrTime);
811 DECODE_TV(xd->minTime);
812 DECODE_TV(xd->maxTime);
816 memcpy((void *)xd->count, (void *)p,
817 sizeof(afs_int32) * FS_STATS_NUM_XFER_BUCKETS);
818 p += FS_STATS_NUM_XFER_BUCKETS;
826 * Wait for the collection to complete. Returns after one cycle if running in
827 * one-shot mode, otherwise wait for a given amount of time.
830 * int sleep_secs : time to wait in seconds when running
831 * in continuous mode. 0 means wait forever.
837 xstat_fs_Wait(int sleep_secs)
839 static char rn[] = "xstat_fs_Wait"; /*Routine name */
841 struct timeval tv; /*Time structure */
843 if (xstat_fs_oneShot) {
845 * One-shot operation; just wait for the collection to be done.
848 printf("[%s] Calling pthread_join\n", rn);
849 code = pthread_join(xstat_fs_thread, NULL);
851 printf("[%s] Returned from pthread_join()\n", rn);
854 "[%s] Error %d encountered by pthread_join()\n",
857 } else if (sleep_secs == 0) {
862 fprintf(stderr, "[ %s ] going to sleep ...\n", rn);
864 code = select(0, /*Num fds */
865 0, /*Descriptors ready for reading */
866 0, /*Descriptors ready for writing */
867 0, /*Descriptors with exceptional conditions */
868 &tv); /*Timeout structure */
870 fprintf(stderr, "[%s] select() error %d\n", rn, errno);
875 /* Let's just fall asleep while. */
878 ("xstat_fs service started, main thread sleeping for %d secs.\n",
880 tv.tv_sec = sleep_secs;
882 code = select(0, /*Num fds */
883 0, /*Descriptors ready for reading */
884 0, /*Descriptors ready for writing */
885 0, /*Descriptors with exceptional conditions */
886 &tv); /*Timeout structure */
888 fprintf(stderr, "[%s] select() error %d\n", rn, errno);