1    	/*
2    	 * Copyright (c) 1995-2006,2008 Silicon Graphics, Inc.  All Rights Reserved.
3    	 * 
4    	 * This library is free software; you can redistribute it and/or modify it
5    	 * under the terms of the GNU Lesser General Public License as published
6    	 * by the Free Software Foundation; either version 2.1 of the License, or
7    	 * (at your option) any later version.
8    	 * 
9    	 * This library is distributed in the hope that it will be useful, but
10   	 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
11   	 * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public
12   	 * License for more details.
13   	 */
14   	
15   	#include "pmapi.h"
16   	#include "impl.h"
17   	
18   	extern int __pmFetchLocal(int, pmID *, pmResult **);
19   	
20   	static int
21   	request_fetch (int ctxid, __pmContext *ctxp,  int numpmid, pmID pmidlist[])
22   	{
23   	    int n;
24   	
25   	#ifdef ASYNC_API
26   	    if (ctxp->c_pmcd->pc_curpdu != 0) {
27   		return (PM_ERR_CTXBUSY);
28   	    }
29   	#endif /*ASYNC_API*/
30   	
31   	    if (ctxp->c_sent == 0) {
32   		/*
33   		 * current profile is _not_ already cached at other end of
34   		 * IPC, so send get current profile
35   		 */
36   	#ifdef PCP_DEBUG
37   		if (pmDebug & DBG_TRACE_PROFILE) {
38   		    fprintf(stderr, "pmFetch: calling __pmSendProfile, context: %d\n",
39   		            ctxid);
40   		    __pmDumpProfile(stderr, PM_INDOM_NULL, ctxp->c_instprof);
41   		}
42   	#endif
43   		if ((n = __pmSendProfile(ctxp->c_pmcd->pc_fd, __pmPtrToHandle(ctxp),
44   				ctxid, ctxp->c_instprof)) < 0)
45   		    return (__pmMapErrno(n));
46   		else
47   		    ctxp->c_sent = 1;
48   	    }
49   	
50   	    n = __pmSendFetch(ctxp->c_pmcd->pc_fd, __pmPtrToHandle(ctxp), ctxid, 
51   			      &ctxp->c_origin, numpmid, pmidlist);
52   	    if (n < 0) {
53   		    n = __pmMapErrno(n);
54   	    }
55   	    return (n);
56   	}
57   	
58   	#ifdef ASYNC_API
59   	int 
60   	pmRequestFetch(int ctxid, int numpmid, pmID pmidlist[])
61   	{
62   	    int n = 0;
63   	    __pmContext *ctxp;
64   	
65   	    if ((n = __pmGetHostContextByID(ctxid, &ctxp)) >= 0) {
66   		if ((n = request_fetch (ctxid, ctxp, numpmid, pmidlist)) >= 0) {
67   		    ctxp->c_pmcd->pc_curpdu = PDU_FETCH;
68   		    ctxp->c_pmcd->pc_tout_sec = TIMEOUT_DEFAULT;
69   		}
70   	    }
71   	    return (n);
72   	}
73   	#endif /*ASYNC_API*/
74   	
75   	static int
76   	receive_fetch (__pmContext *ctxp, pmResult **result)
77   	{
78   	    int n;
79   	    __pmPDU	*pb;
80   	
81   	    n = __pmGetPDU(ctxp->c_pmcd->pc_fd, ANY_SIZE,
82   			   ctxp->c_pmcd->pc_tout_sec, &pb);
83   	    if (n == PDU_RESULT) {
84   		n = __pmDecodeResult(pb, result);
85   	    }
86   	    else if (n == PDU_ERROR) {
87   		__pmDecodeError(pb, &n);
88   	    }
89   	    else if (n != PM_ERR_TIMEOUT)
90   		n = PM_ERR_IPC;
91   	
92   	    return (n);
93   	}
94   	
95   	#ifdef ASYNC_API
96   	int
97   	pmReceiveFetch (int ctxid, pmResult **result)
98   	{
99   	    int n;
100  	    __pmContext *ctxp;
101  	
102  	    if ((n = __pmGetBusyHostContextByID (ctxid, &ctxp, PDU_FETCH)) >= 0) {
103  		if ((n = receive_fetch (ctxp, result)) <= 0) {
104  		    /* pmcd may return state change in error PDU before
105  		     * returning results for fetch - if we get one of those,
106  		     * keep the state in the context for the second call to
107  		     * receive_fetch */
108  		    ctxp->c_pmcd->pc_curpdu = 0;
109  		    ctxp->c_pmcd->pc_tout_sec = 0;
110  		}
111  	    }
112  	    return (n);
113  	}
114  	#endif /*ASYNC_API*/
115  	
116  	int
117  	pmFetch(int numpmid, pmID pmidlist[], pmResult **result)
118  	{
119  	    int		n;
120  	
121  	    if (numpmid < 1)
122  		return PM_ERR_TOOSMALL;
123  	
124  	    if ((n = pmWhichContext()) >= 0) {
125  		__pmContext	*ctxp = __pmHandleToPtr(n);
126  		int		newcnt;
127  		pmID		*newlist;
128  		int		have_dm;
129  	
130  		/* for derived metrics, may need to rewrite the pmidlist */
Event alloc_arg: Calling allocation function "__dmprefetch" on "newlist". [details]
Also see events: [overwrite_var]
131  		have_dm = newcnt = __dmprefetch(ctxp, numpmid, pmidlist, &newlist);
At conditional (1): "newcnt > numpmid": Taking false branch.
132  		if (newcnt > numpmid) {
133  		    /* replace args passed into pmFetch */
134  		    numpmid = newcnt;
135  		    pmidlist = newlist;
136  		}
137  		else
Event overwrite_var: Overwriting "newlist" in call "newlist = NULL" leaks the storage that "newlist" points to.
Also see events: [alloc_arg]
138  		    newlist = NULL;
139  	
140  		if (ctxp->c_type == PM_CONTEXT_HOST) {
141  		    if ((n = request_fetch (n, ctxp, numpmid, pmidlist)) >= 0) {
142  			int changed = 0;
143  			do {
144  			    if ((n = receive_fetch (ctxp, result)) > 0) {
145  				/* PMCD state change protocol */
146  				changed = n;
147  			    }
148  			} while (n > 0);
149  	
150  			if (n == 0)
151  			    n |= changed;
152  		    }
153  		}
154  		else if (ctxp->c_type == PM_CONTEXT_LOCAL) {
155  		    n = __pmFetchLocal(numpmid, pmidlist, result);
156  		}
157  		else {
158  		    /* assume PM_CONTEXT_ARCHIVE */
159  		    n = __pmLogFetch(ctxp, numpmid, pmidlist, result);
160  		    if (n >= 0 && (ctxp->c_mode & __PM_MODE_MASK) != PM_MODE_INTERP) {
161  			ctxp->c_origin.tv_sec = (__int32_t)(*result)->timestamp.tv_sec;
162  			ctxp->c_origin.tv_usec = (__int32_t)(*result)->timestamp.tv_usec;
163  		    }
164  		}
165  	
166  		/* process derived metrics, if any */
167  		if (have_dm) {
168  		    if (n >= 0)
169  			__dmpostfetch(ctxp, result);
170  		    if (newlist != NULL)
171  			free(newlist);
172  		}
173  	    }
174  	
175  	#ifdef PCP_DEBUG
176  	    if (pmDebug & DBG_TRACE_FETCH) {
177  		fprintf(stderr, "pmFetch returns ...\n");
178  		if (n > 0) {
179  		    fprintf(stderr, "PMCD state changes: agent(s)");
180  		    if (n & PMCD_ADD_AGENT) fprintf(stderr, " added");
181  		    if (n & PMCD_RESTART_AGENT) fprintf(stderr, " restarted");
182  		    if (n & PMCD_DROP_AGENT) fprintf(stderr, " dropped");
183  		    fputc('\n', stderr);
184  		}
185  		if (n >= 0)
186  		    __pmDumpResult(stderr, *result);
187  		else
188  		    fprintf(stderr, "Error: %s\n", pmErrStr(n));
189  	    }
190  	#endif
191  	
192  	    return n;
193  	}
194  	
195  	int
196  	pmFetchArchive(pmResult **result)
197  	{
198  	    int		n;
199  	    __pmContext	*ctxp;
200  	    int		ctxp_mode;
201  	
202  	    if ((n = pmWhichContext()) >= 0) {
203  		ctxp = __pmHandleToPtr(n);
204  		ctxp_mode = (ctxp->c_mode & __PM_MODE_MASK);
205  		if (ctxp->c_type != PM_CONTEXT_ARCHIVE)
206  		    n = PM_ERR_NOTARCHIVE;
207  		else if (ctxp_mode == PM_MODE_INTERP)
208  		    /* makes no sense! */
209  		    n = PM_ERR_MODE;
210  		else {
211  		    /* assume PM_CONTEXT_ARCHIVE and BACK or FORW */
212  		    n = __pmLogFetch(ctxp, 0, NULL, result);
213  		    if (n >= 0) {
214  			ctxp->c_origin.tv_sec = (__int32_t)(*result)->timestamp.tv_sec;
215  			ctxp->c_origin.tv_usec = (__int32_t)(*result)->timestamp.tv_usec;
216  		    }
217  		}
218  	    }
219  	
220  	    return n;
221  	}
222  	
223  	int
224  	pmSetMode(int mode, const struct timeval *when, int delta)
225  	{
226  	    int		n;
227  	    __pmContext	*ctxp;
228  	    int		l_mode = (mode & __PM_MODE_MASK);
229  	
230  	    if ((n = pmWhichContext()) >= 0) {
231  		ctxp = __pmHandleToPtr(n);
232  		if (ctxp->c_type == PM_CONTEXT_HOST) {
233  		    if (l_mode != PM_MODE_LIVE)
234  			return PM_ERR_MODE;
235  	
236  		    ctxp->c_origin.tv_sec = ctxp->c_origin.tv_usec = 0;
237  		    ctxp->c_mode = mode;
238  		    ctxp->c_delta = delta;
239  		    return 0;
240  		}
241  		else if (ctxp->c_type == PM_CONTEXT_LOCAL) {
242  			return PM_ERR_MODE;
243  		}
244  		else {
245  		    /* assume PM_CONTEXT_ARCHIVE */
246  		    if (l_mode == PM_MODE_INTERP ||
247  			l_mode == PM_MODE_FORW || l_mode == PM_MODE_BACK) {
248  			if (when != NULL) {
249  			    /*
250  			     * special case of NULL for timestamp
251  			     * => do not update notion of "current" time
252  			     */
253  			    ctxp->c_origin.tv_sec = (__int32_t)when->tv_sec;
254  			    ctxp->c_origin.tv_usec = (__int32_t)when->tv_usec;
255  			}
256  			ctxp->c_mode = mode;
257  			ctxp->c_delta = delta;
258  			__pmLogSetTime(ctxp);
259  			__pmLogResetInterp(ctxp);
260  			return 0;
261  		    }
262  		    else
263  			return PM_ERR_MODE;
264  		}
265  	    }
266  	    else
267  		return n;
268  	}