/*
 * This file was generated automatically by ExtUtils::ParseXS version 3.40 from the
 * contents of Processors.xs. Do not edit this file, edit Processors.xs instead.
 *
 *    ANY CHANGES MADE HERE WILL BE LOST!
 *
 */

#line 1 "Processors.xs"
#/* -*- Mode: C -*- */
#/* Author: Wilson Snyder <wsnyder@wsnyder.org> */
#/* IRIX & FreeBSD port by: Daniel Gustafson <daniel@hobbit.se> */
#/*##################################################################### */
#/* */
#/* Copyright 1999-2017 by Wilson Snyder.  This program is free software; */
#/* you can redistribute it and/or modify it under the terms of either the GNU */
#/* Lesser General Public License Version 3 or the Perl Artistic License Version 2.0. */
#/*  */
#/* This program is distributed in the hope that it will be useful, */
#/* but WITHOUT ANY WARRANTY; without even the implied warranty of */
#/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the */
#/* GNU General Public License for more details. */
#/*  */
#/*##################################################################### */

#include "EXTERN.h"
#include "perl.h"
#include "XSUB.h"

#include <unistd.h>
#include <stdio.h>
#include <string.h>
#include <sys/types.h>

#if defined(_AIX)
# define AIX
#endif

#if defined(hpux) || defined(__hpux)
# define HPUX
#endif

#if defined(__osf__) && (defined(__alpha) || defined(__alpha__))
# define OSF_ALPHA
#endif

#if defined(__mips)
# define MIPS
# if defined(sgi)
#  define IRIX
# endif
#endif

#if defined(sun) || defined(__sun__)
# define SUNOS
#endif

#ifdef AIX
# ifdef HAS_PMAPI
#  include <pmapi.h>
# endif
# ifdef HAS_PERFSTAT
#  include <libperfstat.h>
# endif
#endif

#ifdef HPUX
#include <sys/param.h>
#include <sys/pstat.h>
struct pst_dynamic psd;
#endif

#ifdef OSF_ALPHA
#include <sys/sysinfo.h>
#include <machine/hal_sysinfo.h>
#endif

#if defined(MIPS) && !defined(__linux__)
#include <sys/systeminfo.h>
#endif

#ifdef IRIX
#include <dirent.h>
#include <sys/invent.h>
#include <sys/pda.h>
#include <sys/sbd.h>
#include <sys/sysmp.h>
#include <sys/iograph.h>
#include <invent.h>
#include <sys/param.h>
#endif

#ifdef SUNOS
#include <sys/processor.h>
#endif

#if defined(__FreeBSD__) || defined(__APPLE__)
#include <stdlib.h>
#include <sys/types.h>
#include <sys/sysctl.h>
#include <sys/param.h>
#endif

/* Missing in older headers */
#ifndef P_POWEROFF
#define P_POWEROFF 5
#endif

typedef int CpuNumFromRef_t;

#/**************************************************************/

#ifdef __linux__
const char* proc_cpuinfo_field (const char *field)
    /* Return string from a field of /proc/cpuinfo, NULL if not found */
    /* Comparison is case insensitive */
    /* If multiple matches, the last match is returned */
{
    FILE* fp;
    static char line[1000];
    static char result[1000];
    int len = strlen(field);
    char* resultp = NULL;
    if (NULL!=(fp = fopen ("/proc/cpuinfo", "r"))) {
	while (!feof(fp)) {
	    const char* ok = fgets (line, 990, fp);
	    if (ok && 0==strncasecmp (field, line, len)) {
		char *loc = strchr (line, ':');
		if (loc) {
		    strncpy(result,loc+2, 990);
		    resultp = result;
		    loc = strchr (result, '\n');
		    if (loc) *loc = '\0';
		    /*printf("MATCH: %s: %s\n", field, resultp);*/
		}
	    }
	}
	fclose(fp);
    }
    return (resultp);
}

int _proc_cpuinfo_clock_calc (void)
{
    const char* value;
    value = proc_cpuinfo_field ("cpu MHz");
    if (value) return (atoi(value));
    value = proc_cpuinfo_field ("clock");
    if (value) return (atoi(value));
    value = proc_cpuinfo_field ("bogomips");
    if (value) return (atoi(value));
    return (0);
}

int proc_cpuinfo_clock (void)
    /* Return clock frequency */
{
    static int cache = 0;
    if (!cache) cache = _proc_cpuinfo_clock_calc();
    return cache;
}

#endif

int _proc_nthreaders_calc (void)
{
    int num_cpus = 0;

    /* Determine how many processors are online and available */
#ifdef HPUX
    if (pstat_getdynamic(&psd, sizeof(psd), (size_t)1, 0) != -1)
        num_cpus = psd.psd_proc_cnt;
#endif

#ifdef OSF_ALPHA
    getsysinfo(GSI_CPUS_IN_BOX,&num_cpus,sizeof(num_cpus),0,0)
#endif

#if defined(MIPS) && !defined(__linux__)
    char buf[16];
    if (sysinfo(_MIPS_SI_NUM_PROCESSORS, buf, 10) != -1)
        num_cpus = atoi(buf);
#endif

    /* Generic linux defaults */
#if defined(SUNOS) || defined(AIX) || defined(__APPLE__) || defined (__linux__)
    if (num_cpus < 1)
	num_cpus = sysconf(_SC_NPROCESSORS_ONLN);
# ifdef __linux__
    if (num_cpus < 1) {
	/* SPARC Linux has a bug where SC_NPROCESSORS is set to 0. */
	const char* value = proc_cpuinfo_field("ncpus active");
	if (value) num_cpus = atoi(value);
    }
# endif
#endif

#if defined(__FreeBSD__) || defined(HW_NCPU)
    size_t len = sizeof(num_cpus);
    sysctlbyname("hw.ncpu", &num_cpus, &len, NULL, 0);
#endif

    if (num_cpus < 1)
        num_cpus=1;      /* We're running this program, after all :-) */
    return (num_cpus);
}

int proc_nthreaders (void)
    /* Return number of processor threads */
{
    static int cache = 0;
    if (!cache) cache = _proc_nthreaders_calc();
    return cache;
}

#ifdef IRIX
/* invent_cpuinfo_t irix_get_cpuinf(int cpuid);
 * Returns an invent_cpuinfo_t regarding the requested cpuid. */
invent_cpuinfo_t irix_get_cpuinf(int cpuid) {
    union {
        invent_generic_t generic;
        invent_cpuinfo_t cpu;
    } hw_inv;

    int attr_len = sizeof(hw_inv);
    DIR *hw_graph;
    struct dirent *hw_entry;
    char *hw_entry_buf = (char *)malloc(MAXPATHLEN);
    char *hw_filename = (char *)malloc(MAXPATHLEN);

    if ((hw_graph = opendir("/hw/cpunum")) != NULL) {
	while ((hw_entry = readdir(hw_graph)) != NULL) {

            if ((strcmp(hw_entry->d_name, ".") != 0) && (strcmp(hw_entry->d_name, "..") != 0)) {
                strcpy(hw_filename, "/hw/cpunum/");
                strncat(hw_filename, hw_entry->d_name, 1);

                if (realpath(hw_filename, hw_entry_buf) != NULL) {
                    if (attr_get(hw_entry_buf, INFO_LBL_DETAIL_INVENT, (char *)&hw_inv, &attr_len, 0) == 0) {
                        if (hw_inv.generic.ig_invclass == INV_PROCESSOR) {
                            if (hw_inv.cpu.ic_cpuid == cpuid) {
				break;
			    }
			}
		    }
		}
            }
        }
    }

    closedir(hw_graph);
    return(hw_inv.cpu);
}
#endif

int logical_per_physical_cpu() {
    int logical_per = 1;

#ifdef __linux__
    const char* flags = proc_cpuinfo_field ("flags");
    /* flags: ... ht ... indicates hyperthreading enabled on a cpu */
    if (flags && strstr (flags, " ht ")) {
	/* HACK: Current linux under hyperthreading always makes 2 logical CPUs per physical CPU */
	logical_per = 2;
    }
#endif
#ifdef __FreeBSD__
    int hlt_htt_cpu = 0;
    size_t len = sizeof(hlt_htt_cpu);
    if (sysctlbyname("machdep.hlt_logical_cpus",
		     &hlt_htt_cpu, &len, NULL, 0) == 0) {
	if (hlt_htt_cpu == 0) {
	    /* HACK: Current FreeBSD under hyperthreading always makes 2 logical CPUs per physical CPU */
	    logical_per = 2;
	}
    }
#endif

    return logical_per;
}

int proc_num_physical_ids() {
#ifdef __linux__
    {
	const char* value = proc_cpuinfo_field ("physical id");
	if (value) {
	    int phys = atoi(value)+1;
	    return phys;
	}
    }
#endif
    return 0;
}
int _proc_ncores_calc() {
    /* Can't have more cores than threaders */
    int num = proc_nthreaders();
#ifdef __linux__
    {
	int phys = proc_num_physical_ids();
	const char* cvalue = proc_cpuinfo_field ("cpu cores");
	if (phys && cvalue) {
	    int cores_per_phys = atoi(cvalue);
	    int cores = phys * cores_per_phys;
	    if (cores && (cores <= num)) return cores;
	}
    }
#endif
    {
	/* If hyperthreading, the threader count is too high */
	if (num > 1) {
	    num /= logical_per_physical_cpu();
	}
	return num;
    }
}

int proc_ncores() {
    /* Return number of processor cores */
    static int cache = 0;
    if (!cache) cache = _proc_ncores_calc();
    return cache;
}

int _proc_nsockets_calc() {
    int num = proc_ncores();
    /* default to core count, trim downwards if we can */
    int phys = proc_num_physical_ids();
    if (phys && ((phys <= num))) num = phys;
    return num;
}

int proc_nsockets() {
    /* Return number of processor sockets */
    static int cache = 0;
    if (!cache) cache = _proc_nsockets_calc();
    return cache;
}


#line 341 "Processors.c"
#ifndef PERL_UNUSED_VAR
#  define PERL_UNUSED_VAR(var) if (0) var = var
#endif

#ifndef dVAR
#  define dVAR		dNOOP
#endif


/* This stuff is not part of the API! You have been warned. */
#ifndef PERL_VERSION_DECIMAL
#  define PERL_VERSION_DECIMAL(r,v,s) (r*1000000 + v*1000 + s)
#endif
#ifndef PERL_DECIMAL_VERSION
#  define PERL_DECIMAL_VERSION \
	  PERL_VERSION_DECIMAL(PERL_REVISION,PERL_VERSION,PERL_SUBVERSION)
#endif
#ifndef PERL_VERSION_GE
#  define PERL_VERSION_GE(r,v,s) \
	  (PERL_DECIMAL_VERSION >= PERL_VERSION_DECIMAL(r,v,s))
#endif
#ifndef PERL_VERSION_LE
#  define PERL_VERSION_LE(r,v,s) \
	  (PERL_DECIMAL_VERSION <= PERL_VERSION_DECIMAL(r,v,s))
#endif

/* XS_INTERNAL is the explicit static-linkage variant of the default
 * XS macro.
 *
 * XS_EXTERNAL is the same as XS_INTERNAL except it does not include
 * "STATIC", ie. it exports XSUB symbols. You probably don't want that
 * for anything but the BOOT XSUB.
 *
 * See XSUB.h in core!
 */


/* TODO: This might be compatible further back than 5.10.0. */
#if PERL_VERSION_GE(5, 10, 0) && PERL_VERSION_LE(5, 15, 1)
#  undef XS_EXTERNAL
#  undef XS_INTERNAL
#  if defined(__CYGWIN__) && defined(USE_DYNAMIC_LOADING)
#    define XS_EXTERNAL(name) __declspec(dllexport) XSPROTO(name)
#    define XS_INTERNAL(name) STATIC XSPROTO(name)
#  endif
#  if defined(__SYMBIAN32__)
#    define XS_EXTERNAL(name) EXPORT_C XSPROTO(name)
#    define XS_INTERNAL(name) EXPORT_C STATIC XSPROTO(name)
#  endif
#  ifndef XS_EXTERNAL
#    if defined(HASATTRIBUTE_UNUSED) && !defined(__cplusplus)
#      define XS_EXTERNAL(name) void name(pTHX_ CV* cv __attribute__unused__)
#      define XS_INTERNAL(name) STATIC void name(pTHX_ CV* cv __attribute__unused__)
#    else
#      ifdef __cplusplus
#        define XS_EXTERNAL(name) extern "C" XSPROTO(name)
#        define XS_INTERNAL(name) static XSPROTO(name)
#      else
#        define XS_EXTERNAL(name) XSPROTO(name)
#        define XS_INTERNAL(name) STATIC XSPROTO(name)
#      endif
#    endif
#  endif
#endif

/* perl >= 5.10.0 && perl <= 5.15.1 */


/* The XS_EXTERNAL macro is used for functions that must not be static
 * like the boot XSUB of a module. If perl didn't have an XS_EXTERNAL
 * macro defined, the best we can do is assume XS is the same.
 * Dito for XS_INTERNAL.
 */
#ifndef XS_EXTERNAL
#  define XS_EXTERNAL(name) XS(name)
#endif
#ifndef XS_INTERNAL
#  define XS_INTERNAL(name) XS(name)
#endif

/* Now, finally, after all this mess, we want an ExtUtils::ParseXS
 * internal macro that we're free to redefine for varying linkage due
 * to the EXPORT_XSUB_SYMBOLS XS keyword. This is internal, use
 * XS_EXTERNAL(name) or XS_INTERNAL(name) in your code if you need to!
 */

#undef XS_EUPXS
#if defined(PERL_EUPXS_ALWAYS_EXPORT)
#  define XS_EUPXS(name) XS_EXTERNAL(name)
#else
   /* default to internal */
#  define XS_EUPXS(name) XS_INTERNAL(name)
#endif

#ifndef PERL_ARGS_ASSERT_CROAK_XS_USAGE
#define PERL_ARGS_ASSERT_CROAK_XS_USAGE assert(cv); assert(params)

/* prototype to pass -Wmissing-prototypes */
STATIC void
S_croak_xs_usage(const CV *const cv, const char *const params);

STATIC void
S_croak_xs_usage(const CV *const cv, const char *const params)
{
    const GV *const gv = CvGV(cv);

    PERL_ARGS_ASSERT_CROAK_XS_USAGE;

    if (gv) {
        const char *const gvname = GvNAME(gv);
        const HV *const stash = GvSTASH(gv);
        const char *const hvname = stash ? HvNAME(stash) : NULL;

        if (hvname)
	    Perl_croak_nocontext("Usage: %s::%s(%s)", hvname, gvname, params);
        else
	    Perl_croak_nocontext("Usage: %s(%s)", gvname, params);
    } else {
        /* Pants. I don't think that it should be possible to get here. */
	Perl_croak_nocontext("Usage: CODE(0x%" UVxf ")(%s)", PTR2UV(cv), params);
    }
}
#undef  PERL_ARGS_ASSERT_CROAK_XS_USAGE

#define croak_xs_usage        S_croak_xs_usage

#endif

/* NOTE: the prototype of newXSproto() is different in versions of perls,
 * so we define a portable version of newXSproto()
 */
#ifdef newXS_flags
#define newXSproto_portable(name, c_impl, file, proto) newXS_flags(name, c_impl, file, proto, 0)
#else
#define newXSproto_portable(name, c_impl, file, proto) (PL_Sv=(SV*)newXS(name, c_impl, file), sv_setpv(PL_Sv, proto), (CV*)PL_Sv)
#endif /* !defined(newXS_flags) */

#if PERL_VERSION_LE(5, 21, 5)
#  define newXS_deffile(a,b) Perl_newXS(aTHX_ a,b,file)
#else
#  define newXS_deffile(a,b) Perl_newXS_deffile(aTHX_ a,b)
#endif

#line 485 "Processors.c"

XS_EUPXS(XS_Unix__Processors_max_online); /* prototype to pass -Wmissing-prototypes */
XS_EUPXS(XS_Unix__Processors_max_online)
{
    dVAR; dXSARGS;
    if (items != 1)
       croak_xs_usage(cv,  "self");
    {
	SV *	self = ST(0)
;
	long	RETVAL;
	dXSTARG;
#line 343 "Processors.xs"
{
    if (self) {}  /* Prevent unused warning */
    RETVAL = proc_nthreaders();
}
#line 503 "Processors.c"
	XSprePUSH; PUSHi((IV)RETVAL);
    }
    XSRETURN(1);
}


XS_EUPXS(XS_Unix__Processors_max_physical); /* prototype to pass -Wmissing-prototypes */
XS_EUPXS(XS_Unix__Processors_max_physical)
{
    dVAR; dXSARGS;
    if (items != 1)
       croak_xs_usage(cv,  "self");
    {
	SV *	self = ST(0)
;
	long	RETVAL;
	dXSTARG;
#line 357 "Processors.xs"
{
    if (self) {}  /* Prevent unused warning */
    RETVAL = proc_ncores();
}
#line 526 "Processors.c"
	XSprePUSH; PUSHi((IV)RETVAL);
    }
    XSRETURN(1);
}


XS_EUPXS(XS_Unix__Processors_max_socket); /* prototype to pass -Wmissing-prototypes */
XS_EUPXS(XS_Unix__Processors_max_socket)
{
    dVAR; dXSARGS;
    if (items != 1)
       croak_xs_usage(cv,  "self");
    {
	SV *	self = ST(0)
;
	long	RETVAL;
	dXSTARG;
#line 371 "Processors.xs"
{
    if (self) {}  /* Prevent unused warning */
    RETVAL = proc_nsockets();
}
#line 549 "Processors.c"
	XSprePUSH; PUSHi((IV)RETVAL);
    }
    XSRETURN(1);
}


XS_EUPXS(XS_Unix__Processors_max_clock); /* prototype to pass -Wmissing-prototypes */
XS_EUPXS(XS_Unix__Processors_max_clock)
{
    dVAR; dXSARGS;
    if (items != 1)
       croak_xs_usage(cv,  "self");
    {
	SV *	self = ST(0)
;
	int	RETVAL;
	dXSTARG;
#line 385 "Processors.xs"
{
    int clock = 0;
#ifdef AIX
# if defined(HAS_PERFSTAT)
    perfstat_cpu_total_t data;
    if (perfstat_cpu_total (0, &data, sizeof(data), 1)) {
      clock = data.processorHZ / 1000000;
    }
# elif defined(HAS_PMAPI)
    /* pm_cycles uses an approximation to arrive at cycle time
     * so we round up to the nearest Mhz */
    clock = (int)((pm_cycles() + 500000) / 1000000);
# endif
#endif
#ifdef HPUX
    /* all processors have the same clock on HP - just report the first one */
    struct pst_processor psp;
    if (pstat_getprocessor(&psp, sizeof(psp), 1, 0)) {
      clock = psp.psp_iticksperclktick / 10000;
    }
#endif
#ifdef SUNOS
    int cpu;
    int last_cpu = 0;
    processor_info_t info, *infop=&info;
    for (cpu=0; cpu < last_cpu+16; cpu++) {
	if (processor_info (cpu, infop)==0
	    && infop->pi_state == P_ONLINE) {
	    if (clock < infop->pi_clock) {
		clock = infop->pi_clock;
	    }
	    last_cpu = cpu;
	}
    }
#endif
#ifdef IRIX
    int num_cpus = proc_nthreaders();
    if ((num_cpus > 0) && (num_cpus < 3)) {
	inventory_t *sys_invent;
	if (setinvent() != -1) {
	    for (sys_invent = getinvent(); (sys_invent); sys_invent = getinvent()) {
		if ((sys_invent->inv_class == INV_PROCESSOR) && (sys_invent->inv_type == INV_CPUBOARD)) {
		    clock = sys_invent->inv_controller;
		    break;
		}
	    }
	    endinvent();
	}
    }
    else {
	invent_cpuinfo_t cpu_info;
	int i;
	for (i = 0; i < proc_nthreaders(); i++) {
	    cpu_info = irix_get_cpuinf(i);
	    if (cpu_info.ic_cpuid == i)
		if (cpu_info.ic_cpu_info.cpufq > clock)
		    clock = cpu_info.ic_cpu_info.cpufq;
	}
    }
#endif
#if (defined(__FreeBSD__) && (__FreeBSD_version >= 503105))
    int value = 0;
    size_t len = sizeof(value);
    /*
     * Even if the frequency is modified using cpu_freq(3), all cpus
     * have the same value why we can request CPU 0 for max_clock.
     */
    if (sysctlbyname("dev.cpu.0.freq", &value, &len, NULL, 0) == 0) {
	clock = value;
    }
#elif defined(HW_CPU_FREQ)
    long long value = 0;
    size_t len = sizeof(value);
    if (sysctlbyname("hw.cpufrequency", &value, &len, NULL, 0) == 0) {
	clock = value;
    }
#endif
#ifdef __linux__
    int value = proc_cpuinfo_clock();
    if (value) clock = value;
#endif

    if (self) {}  /* Prevent unused warning */
    RETVAL = clock;
}
#line 653 "Processors.c"
	XSprePUSH; PUSHi((IV)RETVAL);
    }
    XSRETURN(1);
}


XS_EUPXS(XS_Unix__Processors__Info_id); /* prototype to pass -Wmissing-prototypes */
XS_EUPXS(XS_Unix__Processors__Info_id)
{
    dVAR; dXSARGS;
    if (items != 1)
       croak_xs_usage(cv,  "cpu");
    {
	CpuNumFromRef_t	cpu;
	int	RETVAL;
	dXSTARG;

 if( sv_isobject(ST(0)) && (SvTYPE(SvRV(ST(0))) == SVt_PVMG) )
    cpu = (CpuNumFromRef_t)SvIV((SV*)SvRV( ST(0) ));
 else{
    warn( "Unix::Processors::Info::id() -- cpu is not a blessed SV reference" );
    XSRETURN_UNDEF;
 }
;
#line 488 "Processors.xs"
{
    RETVAL = cpu;
}
#line 682 "Processors.c"
	XSprePUSH; PUSHi((IV)RETVAL);
    }
    XSRETURN(1);
}


XS_EUPXS(XS_Unix__Processors__Info_clock); /* prototype to pass -Wmissing-prototypes */
XS_EUPXS(XS_Unix__Processors__Info_clock)
{
    dVAR; dXSARGS;
    if (items != 1)
       croak_xs_usage(cv,  "cpu");
    {
	CpuNumFromRef_t	cpu;
	SV *	RETVAL;

 if( sv_isobject(ST(0)) && (SvTYPE(SvRV(ST(0))) == SVt_PVMG) )
    cpu = (CpuNumFromRef_t)SvIV((SV*)SvRV( ST(0) ));
 else{
    warn( "Unix::Processors::Info::clock() -- cpu is not a blessed SV reference" );
    XSRETURN_UNDEF;
 }
;
#line 501 "Processors.xs"
{
    int value = 0;
#ifdef AIX
    int num_cpus = proc_nthreaders();
    if (cpu < num_cpus) {
# if defined(HAS_PERFSTAT)
      perfstat_cpu_total_t data;
      if (perfstat_cpu_total (0, &data, sizeof(data), 1)) {
	value = data.processorHZ / 1000000;
      }
# elif defined(HAS_PMAPI)
      /* pm_cycles uses an approximation to arrive at cycle time
       * so we round up to the nearest Mhz */
      clock = (int)((pm_cycles() + 500000) / 1000000);
# endif
    }
#endif
#ifdef HPUX
    int num_cpus = proc_nthreaders();
    if (cpu < num_cpus) {
      /* all processors have the same clock on HP - just report the first one */
      struct pst_processor psp;
      if (pstat_getprocessor(&psp, sizeof(psp), 1, 0)) {
	value = psp.psp_iticksperclktick / 10000;
      }
    }
#endif
#ifdef SUNOS
    processor_info_t info, *infop=&info;
    if (processor_info (cpu, infop)==0) {
      value = infop->pi_clock;
    }
#endif
#ifdef IRIX
    int num_cpus = proc_nthreaders();
    if ((num_cpus > 0) && (num_cpus < 3)) {
	inventory_t *sys_invent;
	if (setinvent() != -1) {
	    while ((sys_invent = getinvent()) != NULL) {
		if ((sys_invent->inv_class == INV_PROCESSOR) && (sys_invent->inv_type == INV_CPUBOARD)) {
		    value = sys_invent->inv_controller;
		    break;
		}
	    }
	    endinvent();
	}
    }
    else {
	invent_cpuinfo_t cpu_info;
	cpu_info = irix_get_cpuinf(cpu);
	if (cpu_info.ic_cpuid == cpu)
	    value = cpu_info.ic_cpu_info.cpufq;
    }
#endif
#if (defined(__FreeBSD__) && (__FreeBSD_version >= 503105))
    int cpu_freq = 0;
    size_t len =  sizeof(cpu_freq);
    char cpu_freq_req[16];
    snprintf(cpu_freq_req, 16, "dev.cpu.%d.freq", cpu);
    if (sysctlbyname(cpu_freq_req, &cpu_freq, &len, NULL, 0) == 0) {
	value = cpu_freq;
    }
#endif
#ifdef __linux__
    /* Cheat... Same clock for every CPU */
    value = proc_cpuinfo_clock();
#endif
    if (value) {
	ST(0) = sv_newmortal();
	sv_setiv (ST(0), value);
    } else {
	ST(0) = &PL_sv_undef;
    }
}
#line 781 "Processors.c"
    }
    XSRETURN(1);
}


XS_EUPXS(XS_Unix__Processors__Info_state); /* prototype to pass -Wmissing-prototypes */
XS_EUPXS(XS_Unix__Processors__Info_state)
{
    dVAR; dXSARGS;
    if (items != 1)
       croak_xs_usage(cv,  "cpu");
    {
	CpuNumFromRef_t	cpu;
	SV *	RETVAL;

 if( sv_isobject(ST(0)) && (SvTYPE(SvRV(ST(0))) == SVt_PVMG) )
    cpu = (CpuNumFromRef_t)SvIV((SV*)SvRV( ST(0) ));
 else{
    warn( "Unix::Processors::Info::state() -- cpu is not a blessed SV reference" );
    XSRETURN_UNDEF;
 }
;
#line 584 "Processors.xs"
{
    char *value = NULL;
#ifdef SUNOS
    processor_info_t info, *infop=&info;
    if (processor_info (cpu, infop)==0) {
	switch (infop->pi_state) {
	case P_ONLINE:
	    value = "online";
	    break;
	case P_OFFLINE:
	    value = "offline";
	    break;
	case P_POWEROFF:
	    value = "poweroff";
	    break;
	}
    }
#endif
#ifdef IRIX
    int num_cpus;
    if ((num_cpus = sysmp(MP_NPROCS)) != -1) {
	struct pda_stat proc_info[num_cpus];
	if (sysmp(MP_STAT, proc_info) != -1) {
	    if (proc_info[cpu].p_flags == PDAF_MASTER)
		value = "MASTER";
	    else if (proc_info[cpu].p_flags == PDAF_CLOCK)
		value = "CLOCK";
	    else if (proc_info[cpu].p_flags == PDAF_ENABLED)
		value = "ENABLED";
	    else if (proc_info[cpu].p_flags == PDAF_FASTCLOCK)
		value = "FASTCLOCK";
	    else if (proc_info[cpu].p_flags == PDAF_ISOLATED)
		value = "ISOLATED";
	    else if (proc_info[cpu].p_flags == PDAF_BROADCAST_OFF)
		value = "BROADCAST_OFF";
	    else if (proc_info[cpu].p_flags == PDAF_NONPREEMPTIVE)
		value = "NONPREEMPTIVE";
	    else if (proc_info[cpu].p_flags == PDAF_NOINTR)
		value = "NOINTR";
	    else if (proc_info[cpu].p_flags == PDAF_ITHREADSOK)
		value = "ITHREADSOK";
	    else if (proc_info[cpu].p_flags == PDAF_DISABLE_CPU)
		value = "DISABLE_CPU";
	    else if (proc_info[cpu].p_flags == PDAF_EXCLUDED)
		value = "EXCLUDED";
	    else
		/*
		 * No p_flags value is specified for uniprocessor
		 * systems. Return ONLINE.
		 */
		value = "ONLINE";
	}
    }
#endif
    /* Cheat... Assume all online */
    if (value == NULL)
	value = "online";
    /* Return it */
    if (value) {
	ST(0) = sv_newmortal();
	sv_setpv (ST(0), value);
    } else {
	ST(0) = &PL_sv_undef;
    }
}
#line 870 "Processors.c"
    }
    XSRETURN(1);
}


XS_EUPXS(XS_Unix__Processors__Info_type); /* prototype to pass -Wmissing-prototypes */
XS_EUPXS(XS_Unix__Processors__Info_type)
{
    dVAR; dXSARGS;
    if (items != 1)
       croak_xs_usage(cv,  "cpu");
    {
	CpuNumFromRef_t	cpu;
	SV *	RETVAL;

 if( sv_isobject(ST(0)) && (SvTYPE(SvRV(ST(0))) == SVt_PVMG) )
    cpu = (CpuNumFromRef_t)SvIV((SV*)SvRV( ST(0) ));
 else{
    warn( "Unix::Processors::Info::type() -- cpu is not a blessed SV reference" );
    XSRETURN_UNDEF;
 }
;
#line 658 "Processors.xs"
{
    const char* value = NULL;
#ifdef AIX
# if defined(HAS_PERFSTAT)
    int num_cpus = proc_nthreaders();
    if (cpu < num_cpus) {
      perfstat_cpu_total_t data;
      if (perfstat_cpu_total (0, &data, sizeof(data), 1)) {
	value = data.description;
      }
    }
# endif
#endif
#ifdef HPUX
    int num_cpus = proc_nthreaders();
    if (cpu < num_cpus) {
	switch(sysconf(_SC_CPU_VERSION)) {
	case CPU_PA_RISC1_0:
		value = "HP PA-RISC 1.0";
		break;
	case CPU_PA_RISC1_1:
		value = "HP PA-RISC 1.1";
		break;
	case CPU_PA_RISC1_2:
		value = "HP PA-RISC 1.2";
		break;
	case CPU_PA_RISC2_0:
		value = "HP PA-RISC 2.0";
		break;
	}
    }
#endif
#ifdef SUNOS
    processor_info_t info, *infop=&info;
    if (processor_info (cpu, infop)==0) {
	value = infop->pi_processor_type;
    }
#endif
#ifdef __linux__
    int ncpu = proc_nthreaders();
    if (cpu < ncpu) {
	value = proc_cpuinfo_field ("model name");
	if (!value) value = proc_cpuinfo_field ("machine");
	if (!value) value = proc_cpuinfo_field ("family");
    }
#endif
#if defined(MIPS) && !defined(__linux__)
    if (cpu < proc_nthreaders()) {
	if ((value = (char *)malloc(64)) != NULL) {
	    sysinfo(SI_MACHINE, value, 64);
	}
    }
#endif
#ifdef IRIX
    if (cpu < proc_nthreaders()) {
	int cpu_data = 0;
	int num_cpus = proc_nthreaders();
	if ((num_cpus > 0) && (num_cpus < 3)) {
	    inventory_t *sys_invent;
	    if (setinvent() != -1) {
		while ((sys_invent = getinvent()) != NULL) {
		    if ((sys_invent->inv_class == INV_PROCESSOR) && (sys_invent->inv_type == INV_CPUCHIP)) {
			cpu_data = sys_invent->inv_state;
			break;
		    }
		}
		endinvent();
	    }
	}
	else {
	    invent_cpuinfo_t cpu_info;
	    cpu_info = irix_get_cpuinf(cpu);
	    if (cpu_info.ic_cpuid == cpu)
		cpu_data = cpu_info.ic_cpu_info.cpuflavor;
	}
	if (cpu_data != 0) {
	    if ((cpu_data >> C0_IMPSHIFT) == C0_IMP_R2000A)
		strcat(value, " MIPS R2000A");
	    else if ((cpu_data >> C0_IMPSHIFT) == C0_IMP_R2000)
		strcat(value, " MIPS R2000A");
	    else if ((cpu_data >> C0_IMPSHIFT) == C0_IMP_R3000A)
		strcat(value, " MIPS R3000A");
	    else if ((cpu_data >> C0_IMPSHIFT) == C0_IMP_R3000)
		strcat(value, " MIPS R3000");
	    else if ((cpu_data >> C0_IMPSHIFT) == C0_IMP_R4000) {
		if (((cpu_data&C0_MAJREVMASK)>>C0_MAJREVSHIFT) >= C0_MAJREVMIN_R4400)
		    strcat(value, " MIPS R4400");
		else
		    strcat(value, " MIPS R4000");
	    }
	    else if ((cpu_data >> C0_IMPSHIFT) == C0_IMP_R4650)
		strcat(value, " MIPS R4650");
	    else if ((cpu_data >> C0_IMPSHIFT) == C0_IMP_R4700)
		strcat(value, " MIPS R4700");
	    else if ((cpu_data >> C0_IMPSHIFT) == C0_IMP_R4600)
		strcat(value, " MIPS R4600");
	    else if ((cpu_data >> C0_IMPSHIFT) == C0_IMP_R5000)
		strcat(value, " MIPS R5000");
	    else if ((cpu_data >> C0_IMPSHIFT) == C0_IMP_RM5271)
		strcat(value, " MIPS RM5271");
	    else if ((cpu_data >> C0_IMPSHIFT) == C0_IMP_R6000A)
		strcat(value, " MIPS R6000A");
	    else if ((cpu_data >> C0_IMPSHIFT) == C0_IMP_R6000)
		strcat(value, " MIPS R6000");
	    else if ((cpu_data >> C0_IMPSHIFT) == C0_IMP_RM7000)
		strcat(value, " MIPS RM7000");
	    else if ((cpu_data >> C0_IMPSHIFT) == C0_IMP_R8000)
		strcat(value, " MIPS R8000");
	    else if ((cpu_data >> C0_IMPSHIFT) == C0_IMP_R10000)
		strcat(value, " MIPS R10000");
	    else if ((cpu_data >> C0_IMPSHIFT) == C0_IMP_R12000)
		strcat(value, " MIPS R12000");
	    else if ((cpu_data >> C0_IMPSHIFT) == C0_IMP_R14000)
		strcat(value, " MIPS R14000");
	    else
		strcat(value, " Undefined MIPS");
	    sprintf(value, "%s Chip Rev: %x.%x", value, ((cpu_data&C0_MAJREVMASK)>>C0_MAJREVSHIFT), ((cpu_data&C0_MINREVMASK)>>C0_MINREVSHIFT));
	}
    }
#endif
#ifdef __FreeBSD__
    if (cpu < proc_nthreaders()) {
	if ((value = (char *)malloc(64)) != NULL) {
	    size_t len = 64;
	    sysctlbyname("hw.machine_arch", value, &len, NULL, 0);
	}
    }
#endif

    if (value) {
	ST(0) = sv_newmortal();
	sv_setpv (ST(0), value);
    } else {
	ST(0) = &PL_sv_undef;
    }
}
#line 1030 "Processors.c"
    }
    XSRETURN(1);
}

#ifdef __cplusplus
extern "C"
#endif
XS_EXTERNAL(boot_Unix__Processors); /* prototype to pass -Wmissing-prototypes */
XS_EXTERNAL(boot_Unix__Processors)
{
#if PERL_VERSION_LE(5, 21, 5)
    dVAR; dXSARGS;
#else
    dVAR; dXSBOOTARGSXSAPIVERCHK;
#endif
#if (PERL_REVISION == 5 && PERL_VERSION < 9)
    char* file = __FILE__;
#else
    const char* file = __FILE__;
#endif

    PERL_UNUSED_VAR(file);

    PERL_UNUSED_VAR(cv); /* -W */
    PERL_UNUSED_VAR(items); /* -W */
#if PERL_VERSION_LE(5, 21, 5)
    XS_VERSION_BOOTCHECK;
#  ifdef XS_APIVERSION_BOOTCHECK
    XS_APIVERSION_BOOTCHECK;
#  endif
#endif

        newXS_deffile("Unix::Processors::max_online", XS_Unix__Processors_max_online);
        newXS_deffile("Unix::Processors::max_physical", XS_Unix__Processors_max_physical);
        newXS_deffile("Unix::Processors::max_socket", XS_Unix__Processors_max_socket);
        newXS_deffile("Unix::Processors::max_clock", XS_Unix__Processors_max_clock);
        (void)newXSproto_portable("Unix::Processors::Info::id", XS_Unix__Processors__Info_id, file, "$");
        (void)newXSproto_portable("Unix::Processors::Info::clock", XS_Unix__Processors__Info_clock, file, "$");
        (void)newXSproto_portable("Unix::Processors::Info::state", XS_Unix__Processors__Info_state, file, "$");
        (void)newXSproto_portable("Unix::Processors::Info::type", XS_Unix__Processors__Info_type, file, "$");
#if PERL_VERSION_LE(5, 21, 5)
#  if PERL_VERSION_GE(5, 9, 0)
    if (PL_unitcheckav)
        call_list(PL_scopestack_ix, PL_unitcheckav);
#  endif
    XSRETURN_YES;
#else
    Perl_xs_boot_epilog(aTHX_ ax);
#endif
}

