summaryrefslogtreecommitdiffstats
path: root/nsprpub/pr/src/misc/prsystem.c
blob: dba093e9b17dbf49b1ab5bb1c261d2733bc6e570 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

#include "primpl.h"
#include "prsystem.h"
#include "prprf.h"
#include "prlong.h"

#if defined(OS2)
#define INCL_DOS
#define INCL_DOSMISC
#include <os2.h>
/* define the required constant if it is not already defined in the headers */
#ifndef QSV_NUMPROCESSORS
#define QSV_NUMPROCESSORS 26
#endif
#endif

/* BSD-derived systems use sysctl() to get the number of processors */
#if defined(BSDI) || defined(FREEBSD) || defined(NETBSD) \
    || defined(OPENBSD) || defined(DRAGONFLY) || defined(DARWIN)
#define _PR_HAVE_SYSCTL
#include <sys/param.h>
#include <sys/sysctl.h>
#endif

#if defined(DARWIN)
#include <mach/mach_init.h>
#include <mach/mach_host.h>
#include <mach/mach_port.h>
#endif

#if defined(HPUX)
#include <sys/mpctl.h>
#include <sys/pstat.h>
#endif

#if defined(XP_UNIX)
#include <unistd.h>
#include <sys/utsname.h>
#endif

#if defined(LINUX)
#include <string.h>
#include <ctype.h>
#define MAX_LINE 512
#endif

#if defined(AIX)
#include <cf.h>
#include <sys/cfgodm.h>
#endif

PR_IMPLEMENT(char) PR_GetDirectorySeparator(void)
{
    return PR_DIRECTORY_SEPARATOR;
}  /* PR_GetDirectorySeparator */

/*
** OBSOLETE -- the function name is misspelled.
*/
PR_IMPLEMENT(char) PR_GetDirectorySepartor(void)
{
#if defined(DEBUG)
    static PRBool warn = PR_TRUE;
    if (warn) {
        warn = _PR_Obsolete("PR_GetDirectorySepartor()",
                            "PR_GetDirectorySeparator()");
    }
#endif
    return PR_GetDirectorySeparator();
}  /* PR_GetDirectorySepartor */

PR_IMPLEMENT(char) PR_GetPathSeparator(void)
{
    return PR_PATH_SEPARATOR;
}  /* PR_GetPathSeparator */

PR_IMPLEMENT(PRStatus) PR_GetSystemInfo(PRSysInfo cmd, char *buf, PRUint32 buflen)
{
    PRUintn len = 0;

    if (!_pr_initialized) {
        _PR_ImplicitInitialization();
    }

    switch(cmd)
    {
        case PR_SI_HOSTNAME:
        case PR_SI_HOSTNAME_UNTRUNCATED:
            if (PR_FAILURE == _PR_MD_GETHOSTNAME(buf, (PRUintn)buflen)) {
                return PR_FAILURE;
            }

            if (cmd == PR_SI_HOSTNAME_UNTRUNCATED) {
                break;
            }
            /*
             * On some platforms a system does not have a hostname and
             * its IP address is returned instead.   The following code
             * should be skipped on those platforms.
             */
#ifndef _PR_GET_HOST_ADDR_AS_NAME
            /* Return the unqualified hostname */
            while (buf[len] && (len < buflen)) {
                if (buf[len] == '.') {
                    buf[len] = '\0';
                    break;
                }
                len += 1;
            }
#endif
            break;

        case PR_SI_SYSNAME:
            /* Return the operating system name */
#if defined(XP_UNIX) || defined(WIN32)
            if (PR_FAILURE == _PR_MD_GETSYSINFO(cmd, buf, (PRUintn)buflen)) {
                return PR_FAILURE;
            }
#else
            (void)PR_snprintf(buf, buflen, _PR_SI_SYSNAME);
#endif
            break;

        case PR_SI_RELEASE:
            /* Return the version of the operating system */
#if defined(XP_UNIX) || defined(WIN32)
            if (PR_FAILURE == _PR_MD_GETSYSINFO(cmd, buf, (PRUintn)buflen)) {
                return PR_FAILURE;
            }
#endif
#if defined(XP_OS2)
            {
                ULONG os2ver[2] = {0};
                DosQuerySysInfo(QSV_VERSION_MINOR, QSV_VERSION_REVISION,
                                &os2ver, sizeof(os2ver));
                /* Formatting for normal usage (2.11, 3.0, 4.0, 4.5); officially,
                   Warp 4 is version 2.40.00, WSeB 2.45.00 */
                if (os2ver[0] < 30)
                    (void)PR_snprintf(buf, buflen, "%s%lu",
                                      "2.", os2ver[0]);
                else if (os2ver[0] < 45)
                    (void)PR_snprintf(buf, buflen, "%lu%s%lu",
                                      os2ver[0]/10, ".", os2ver[1]);
                else
                    (void)PR_snprintf(buf, buflen, "%.1f",
                                      os2ver[0]/10.0);
            }
#endif /* OS2 */
            break;

        case PR_SI_RELEASE_BUILD:
          /* Return the version of the operating system */
#if defined(XP_UNIX) || defined(WIN32)
            if (PR_FAILURE == _PR_MD_GETSYSINFO(cmd, buf, (PRUintn)buflen)) {
              return PR_FAILURE;
            }
#else
            if (buflen) {
                *buf = 0;
            }
#endif /* XP_UNIX || WIN32 */
            break;

        case PR_SI_ARCHITECTURE:
            /* Return the architecture of the machine (ie. x86, mips, alpha, ...)*/
            (void)PR_snprintf(buf, buflen, _PR_SI_ARCHITECTURE);
            break;
        default:
            PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0);
            return PR_FAILURE;
    }
    return PR_SUCCESS;
}

/*
** PR_GetNumberOfProcessors()
**
** Implementation notes:
**   Every platform does it a bit different.
**     numCpus is the returned value.
**   for each platform's "if defined" section
**     declare your local variable
**     do your thing, assign to numCpus
**   order of the if defined()s may be important,
**     especially for unix variants. Do platform
**     specific implementations before XP_UNIX.
**
*/
PR_IMPLEMENT(PRInt32) PR_GetNumberOfProcessors( void )
{
    PRInt32     numCpus;
#if defined(WIN32)
    SYSTEM_INFO     info;

    GetSystemInfo( &info );
    numCpus = info.dwNumberOfProcessors;
#elif defined(OS2)
    DosQuerySysInfo( QSV_NUMPROCESSORS, QSV_NUMPROCESSORS, &numCpus, sizeof(numCpus));
#elif defined(_PR_HAVE_SYSCTL)
    int mib[2];
    int rc;
    size_t len = sizeof(numCpus);

    mib[0] = CTL_HW;
#ifdef HW_NCPUONLINE
    mib[1] = HW_NCPUONLINE;
#else
    mib[1] = HW_NCPU;
#endif
    rc = sysctl( mib, 2, &numCpus, &len, NULL, 0 );
    if ( -1 == rc )  {
        numCpus = -1; /* set to -1 for return value on error */
        _PR_MD_MAP_DEFAULT_ERROR( _MD_ERRNO() );
    }
#elif defined(HPUX)
    numCpus = mpctl( MPC_GETNUMSPUS, 0, 0 );
    if ( numCpus < 1 )  {
        numCpus = -1; /* set to -1 for return value on error */
        _PR_MD_MAP_DEFAULT_ERROR( _MD_ERRNO() );
    }
#elif defined(RISCOS)
    numCpus = 1;
#elif defined(LINUX)
    /* for the benefit of devices with advanced power-saving, that
       actually hotplug their cpus in heavy load, try to figure out
       the real number of CPUs */
    char buf[MAX_LINE];
    FILE *fin;
    const char *cpu_present = "/sys/devices/system/cpu/present";
    size_t strsize;
    numCpus = 0;
    fin = fopen(cpu_present, "r");
    if (fin != NULL) {
        if (fgets(buf, MAX_LINE, fin) != NULL) {
            /* check that the format is what we expect */
            if (buf[0] == '0') {
                strsize = strlen(buf);
                if (strsize == 1) {
                    /* single core */
                    numCpus = 1;
                } else if (strsize >= 3 && strsize <= 5) {
                    /* should be of the form 0-999 */
                    /* parse the part after the 0-, note count is 0-based */
                    if (buf[1] == '-' && isdigit(buf[2])) {
                        numCpus = 1 + atoi(buf + 2);
                    }
                }
            }
        }
        fclose(fin);
    }
    /* if that fails, fall back to more standard methods */
    if (!numCpus) {
        numCpus = sysconf( _SC_NPROCESSORS_CONF );
    }
#elif defined(XP_UNIX)
    numCpus = sysconf( _SC_NPROCESSORS_CONF );
#else
#error "An implementation is required"
#endif
    return(numCpus);
} /* end PR_GetNumberOfProcessors() */

/*
** PR_GetPhysicalMemorySize()
**
** Implementation notes:
**   Every platform does it a bit different.
**     bytes is the returned value.
**   for each platform's "if defined" section
**     declare your local variable
**     do your thing, assign to bytes.
**
*/
PR_IMPLEMENT(PRUint64) PR_GetPhysicalMemorySize(void)
{
    PRUint64 bytes = 0;

#if defined(LINUX) || defined(SOLARIS)

    long pageSize = sysconf(_SC_PAGESIZE);
    long pageCount = sysconf(_SC_PHYS_PAGES);
    if (pageSize >= 0 && pageCount >= 0) {
        bytes = (PRUint64) pageSize * pageCount;
    }

#elif defined(NETBSD) || defined(OPENBSD) \
    || defined(FREEBSD) || defined(DRAGONFLY)

    int mib[2];
    int rc;
#ifdef HW_PHYSMEM64
    uint64_t memSize;
#else
    unsigned long memSize;
#endif
    size_t len = sizeof(memSize);

    mib[0] = CTL_HW;
#ifdef HW_PHYSMEM64
    mib[1] = HW_PHYSMEM64;
#else
    mib[1] = HW_PHYSMEM;
#endif
    rc = sysctl(mib, 2, &memSize, &len, NULL, 0);
    if (-1 != rc)  {
        bytes = memSize;
    }

#elif defined(HPUX)

    struct pst_static info;
    int result = pstat_getstatic(&info, sizeof(info), 1, 0);
    if (result == 1) {
        bytes = (PRUint64) info.physical_memory * info.page_size;
    }

#elif defined(DARWIN)

    mach_port_t mach_host = mach_host_self();
    struct host_basic_info hInfo;
    mach_msg_type_number_t count = HOST_BASIC_INFO_COUNT;

    int result = host_info(mach_host,
                           HOST_BASIC_INFO,
                           (host_info_t) &hInfo,
                           &count);
    mach_port_deallocate(mach_task_self(), mach_host);
    if (result == KERN_SUCCESS) {
        bytes = hInfo.max_mem;
    }

#elif defined(WIN32)

    MEMORYSTATUSEX memStat;
    memStat.dwLength = sizeof(memStat);
    if (GlobalMemoryStatusEx(&memStat)) {
        bytes = memStat.ullTotalPhys;
    }

#elif defined(OS2)

    ULONG ulPhysMem;
    DosQuerySysInfo(QSV_TOTPHYSMEM,
                    QSV_TOTPHYSMEM,
                    &ulPhysMem,
                    sizeof(ulPhysMem));
    bytes = ulPhysMem;

#elif defined(AIX)

    if (odm_initialize() == 0) {
        int how_many;
        struct CuAt *obj = getattr("sys0", "realmem", 0, &how_many);
        if (obj != NULL) {
            bytes = (PRUint64) atoi(obj->value) * 1024;
            free(obj);
        }
        odm_terminate();
    }

#else

    PR_SetError(PR_NOT_IMPLEMENTED_ERROR, 0);

#endif

    return bytes;
} /* end PR_GetPhysicalMemorySize() */