source: trunk/lang/tcl/src/RpWinResource.c @ 4346

Last change on this file since 4346 was 3362, checked in by ldelgass, 11 years ago

Merge nanovis2 branch to trunk

File size: 8.7 KB
Line 
1/*
2 * ----------------------------------------------------------------------
3 *  RpWinResource.c
4 *
5 *  This file provides the Windows ports for Rappture of the following
6 *  resource management functions typically found on a Unix platform:
7 *
8 *      setrlimit(), getrlimit(), getrusage(), gettimeofday(), timeradd()
9 *
10 *  None of the ports are exactly perfect, but they are close enough
11 *  for Rappture's use.
12 * ======================================================================
13 *  AUTHOR:  Nicholas J. Kisseberth, Purdue University
14 *  Copyright (c) 2004-2012  HUBzero Foundation, LLC
15 *
16 *  See the file "license.terms" for information on usage and
17 *  redistribution of this file, and for a DISCLAIMER OF ALL WARRANTIES.
18 * ======================================================================
19 */
20
21#define _WIN32_WINNT 0x0500
22
23#include <windows.h>
24#include <stdio.h>
25#include <limits.h>
26#include <psapi.h>
27#include <time.h>
28#include <sys/timeb.h>
29#include <errno.h>
30#include "RpWinResource.h"
31
32static HANDLE currentJob = NULL;
33
34void
35rpWinInitJob()
36{
37    if (currentJob == NULL) {
38        currentJob = CreateJobObject(NULL, NULL);
39        AssignProcessToJobObject(currentJob, GetCurrentProcess());
40    }
41}
42
43HANDLE
44rpWinGetCurrentJob()
45{
46    return currentJob;
47}
48
49/* add timeval values */
50void
51timeradd(struct timeval *a, struct timeval *b, struct timeval *result)
52{
53    result->tv_sec = a->tv_sec + b->tv_sec;
54    result->tv_usec = a->tv_usec + b->tv_usec;
55    if (result->tv_usec >= 1000000)
56    {
57        result->tv_sec++;
58        result->tv_usec -= 1000000;
59    }
60}
61
62/* add rusage values */
63static void
64rusageadd(struct rusage *a, struct rusage *b, struct rusage *result)
65{
66    timeradd(&a->ru_utime, &b->ru_utime, &result->ru_utime);
67    timeradd(&a->ru_stime, &b->ru_stime, &result->ru_stime);
68    result->ru_maxrss = a->ru_maxrss + b->ru_maxrss;
69    result->ru_ixrss  = a->ru_ixrss  + b->ru_ixrss;
70    result->ru_idrss  = a->ru_idrss  + b->ru_idrss;
71    result->ru_isrss  = a->ru_isrss  + b->ru_isrss;
72    result->ru_minflt = a->ru_minflt + b->ru_minflt;
73    result->ru_majflt = a->ru_majflt + b->ru_majflt;
74    result->ru_nswap  = a->ru_nswap  + b->ru_nswap;
75}
76
77/* convert windows FILETIME structure to unix timeval structure */
78static void
79filetime_to_timeval(struct timeval *dst, FILETIME *src)
80{
81    ULARGE_INTEGER x;
82
83    x.LowPart = src->dwLowDateTime;
84    x.HighPart = src->dwHighDateTime;
85
86    dst->tv_sec  = x.QuadPart / 10000000;
87    dst->tv_usec = (x.QuadPart % 10000000) / 10;
88
89}
90
91/* implement getrusage(RUSAGE_SELF) */
92static void
93fill_rusage_self(struct rusage *r, HANDLE h)
94{
95    FILETIME creationTime, exitTime, kernelTime, userTime;
96    struct timeval tv;
97    PROCESS_MEMORY_COUNTERS pmc;
98
99    if (!GetProcessTimes(h, &creationTime, &exitTime, &kernelTime, &userTime))
100        return;
101
102    filetime_to_timeval(&tv, &kernelTime);
103    timeradd(&r->ru_stime, &tv, &r->ru_stime);
104    filetime_to_timeval(&tv, &userTime);
105    timeradd(&r->ru_utime, &tv, &r->ru_utime);
106 
107    if (GetProcessMemoryInfo(h, &pmc, sizeof(pmc)))
108    {
109        r->ru_maxrss += (long) (pmc.WorkingSetSize /1024);
110        r->ru_majflt += pmc.PageFaultCount;
111    }
112}
113
114/* implement getrusage(RUSAGE_CHILDREN) */
115static void
116fill_rusage_job(struct rusage *r, HANDLE h)
117{
118    BOOL result;
119    JOBOBJECT_BASIC_ACCOUNTING_INFORMATION jbai;
120    PROCESS_MEMORY_COUNTERS pmc;
121
122    if (QueryInformationJobObject(rpWinGetCurrentJob(),
123               JobObjectBasicAccountingInformation,
124               &jbai, sizeof(JOBOBJECT_BASIC_ACCOUNTING_INFORMATION), NULL))
125    {
126        r->ru_stime.tv_sec = (long)(jbai.TotalKernelTime.QuadPart/10)/1000000;
127        r->ru_stime.tv_usec = (long)(jbai.TotalKernelTime.QuadPart/10)%1000000;
128        r->ru_utime.tv_sec = (long)(jbai.TotalUserTime.QuadPart/10)/1000000;
129        r->ru_utime.tv_usec = (long)(jbai.TotalUserTime.QuadPart/10)%1000000;
130
131        h = GetCurrentProcess();
132
133        memset (&pmc, 0, sizeof (pmc));
134
135        if (GetProcessMemoryInfo (h, &pmc, sizeof (pmc)))
136        {
137            r->ru_maxrss += (long) (pmc.WorkingSetSize /1024);
138            r->ru_majflt += pmc.PageFaultCount;
139        }
140    }
141}
142
143/* get system resource statistics */
144int
145getrusage (int intwho, struct rusage *rusage_in)
146{
147    int res = 0;
148    struct rusage r;
149
150    memset(&r, 0, sizeof(r));
151
152    if (intwho == RUSAGE_SELF)
153    {
154        fill_rusage_self(&r, GetCurrentProcess());
155        *rusage_in = r;
156    }
157    else if (intwho == RUSAGE_CHILDREN)
158    {
159        fill_rusage_job(&r, rpWinGetCurrentJob());
160        *rusage_in = r;
161    }
162    else
163    {
164        errno = EINVAL;
165        res = -1;
166    }
167 
168    return res;
169}
170
171static unsigned long rlim_cpu = RLIM_INFINITY;
172static unsigned long rlim_core = RLIM_INFINITY;
173static unsigned long rlim_fsize = RLIM_INFINITY;
174
175/* get system resource limits */
176int
177getrlimit (int resource, struct rlimit *rlp)
178{
179    MEMORY_BASIC_INFORMATION m;
180
181    rlp->rlim_cur = RLIM_INFINITY;
182    rlp->rlim_max = RLIM_INFINITY;
183
184    switch (resource)
185    {
186        case RLIMIT_CPU:
187            rlp->rlim_cur = rlim_cpu;
188            break;
189        case RLIMIT_FSIZE:
190            rlp->rlim_cur = rlim_fsize;
191            break;
192        case RLIMIT_DATA:
193            break;
194        case RLIMIT_STACK:
195            if (!VirtualQuery ((LPCVOID) &m, &m, sizeof m))
196                /* debug_printf
197                 * ("couldn't get stack info, returning def.values. %E") */ ;
198            else
199            {
200                rlp->rlim_cur = (DWORD) &m - (DWORD) m.AllocationBase;
201                rlp->rlim_max = (DWORD) m.BaseAddress + m.RegionSize
202                                - (DWORD) m.AllocationBase;
203            }
204            break;
205        case RLIMIT_NOFILE:
206            rlp->rlim_cur = _getmaxstdio();
207            rlp->rlim_max = 2048;
208            break;
209        case RLIMIT_CORE:
210            rlp->rlim_cur = rlim_core;
211            break;
212        case RLIMIT_AS:
213            rlp->rlim_cur = 0x80000000UL;
214            rlp->rlim_max = 0x80000000UL;
215            break;
216        default:
217            errno = EINVAL;
218            return -1;
219    }
220
221    return 0;
222}
223
224/* set system resource limits */
225int
226setrlimit (int resource, const struct rlimit *rlp)
227{
228    struct rlimit oldlimits;
229
230    if (getrlimit (resource, &oldlimits) < 0)
231        return -1;
232
233    if (oldlimits.rlim_cur == rlp->rlim_cur &&
234        oldlimits.rlim_max == rlp->rlim_max)
235        return 0; // No change requested
236
237    switch (resource)
238    {
239        case RLIMIT_CPU:
240            rlim_cpu = rlp->rlim_cur;
241            break;
242        case RLIMIT_FSIZE:
243            rlim_fsize = rlp->rlim_cur;
244            break;
245        case RLIMIT_CORE:
246            rlim_core = rlp->rlim_cur;
247            break;
248        case RLIMIT_NOFILE:
249            if (rlp->rlim_cur != RLIM_INFINITY)
250                return _setmaxstdio(rlp->rlim_cur);
251            break;
252        default:
253            errno = EINVAL;
254            return -1;
255    }
256    return 0;
257}
258
259/* Here are a few implementations of gettimeofday() for windows. */
260/* they vary in short term (subsecond) and absolute accuracy */
261
262#define EPOCHFILETIME (116444736000000000i64)
263
264static int
265gettimeofday1(struct timeval *tv, void *tz)
266{
267    FILETIME        fileTime;
268    LARGE_INTEGER   li;
269    __int64         t;
270
271    if (tv == NULL)
272        return(-1);
273
274    GetSystemTimeAsFileTime(&fileTime);
275    li.LowPart  = fileTime.dwLowDateTime;
276    li.HighPart = fileTime.dwHighDateTime;
277    t  = (li.QuadPart - EPOCHFILETIME) / 10;       
278    tv->tv_sec  = (long)(t / 1000000);
279    tv->tv_usec = (long)(t % 1000000);
280
281    return 0;
282}
283
284static unsigned __int64 base       = 0;
285static unsigned __int64 frequency  = 0;
286static           double ufrequency = 0.0;
287static           double mfrequency = 0.0;
288
289int
290gettimeofday(struct timeval *tv, void *tz)
291{
292    unsigned __int64 counter = 0;
293
294    QueryPerformanceCounter((LARGE_INTEGER *) &counter);
295
296    if (ufrequency == 0.0)
297    {
298        struct _timeb now, tb;
299        // mutex_lock(L_GETTIMEOFDAY);
300        QueryPerformanceFrequency((LARGE_INTEGER *) &frequency);
301        ufrequency = (double) frequency / 1000000.0f;
302        mfrequency = (double) frequency / 1000.0f;
303        _ftime_s(&tb);
304        _ftime_s(&now);
305        while( (now.time == tb.time) && (now.millitm == tb.millitm))
306            _ftime_s(&now);
307        QueryPerformanceCounter((LARGE_INTEGER *) &counter);
308        base = (__int64) (now.time * frequency) +
309               (__int64) (now.millitm * mfrequency) - counter;
310        // mutex_unlock(L_GETTIMEOFDAY);
311        QueryPerformanceCounter((LARGE_INTEGER *) &counter);
312    }
313
314    counter += base;
315    tv->tv_sec = (long) (counter / frequency);
316    tv->tv_usec = (long) ((__int64)(counter / ufrequency) % 1000000);
317    return 0;
318}
319
320static int
321gettimeofday2(struct timeval *tv, void *tz)
322{
323    struct _timeb tb;
324
325    _ftime_s(&tb);
326
327    tv->tv_sec =  (long) tb.time;
328    tv->tv_usec = tb.millitm * 1000;
329
330    return(0);
331}
332
Note: See TracBrowser for help on using the repository browser.