The Perl Toolchain Summit needs more sponsors. If your company depends on Perl, please support this very important event.
#include <EXTERN.h>
#include <perl.h>
#include <XSUB.h>

#include <linux/unistd.h>
#include <sched.h>

/*
 * This declaration isn't used and looks useless. But for some
 * reason I don't understand at all, for some versions of perl
 * with some build configurations running on some systems,
 * this declaration is the difference between XS code that works
 * (specifically, passing t/11-exercise-all.t) and code that
 * segfaults. For the same reason, the  cpu_set_t  variables
 * in  xs_sched_getaffinity_get_affinity()  below are declared
 * static . 
 *
 * Any insights into this issue would be profoundly appreciated.
 */
char ___linux_sched_getaffinity_dummy[4096];

void diag()
{
  fprintf(stderr,"---\n");
  fprintf(stderr,"diag CPU_SETSIZE=%d\n", CPU_SETSIZE);
  fprintf(stderr,"diag sizeof(__cpu_mask)=%d\n", (int) sizeof(__cpu_mask));
  fprintf(stderr,"diag __NCPUBITS=%d\n", (int) __NCPUBITS);
  fprintf(stderr,"diag sizeof(cpu_set_t)=%d\n", (int) sizeof(cpu_set_t));
  fprintf(stderr,"diag sizeof(pid_t)=%d\n", (int) sizeof(pid_t));
}


MODULE = Sys::CpuAffinity        PACKAGE = Sys::CpuAffinity


int
xs_sched_getaffinity_get_affinity(pid,maskarray,debug_flag)
	int pid
        AV *maskarray
	int debug_flag
  CODE:
    int i, z;
    int r = 0;
    int ncpus = __NCPUBITS;
    static cpu_set_t _set2, *_set1;

    if(debug_flag) diag();
    if(debug_flag) fprintf(stderr,"getaffinity0\n");
    _set1 = &_set2;
    if(debug_flag) {
      fprintf(stderr,"getaffinity1 pid=%d size=%d %d ncpu=%d cpuset=%p\n",
              (int) pid, (int) CPU_SETSIZE, (int) sizeof(cpu_set_t),
              ncpus, (void *) _set1);
    }
    /* RT 94560: CPU_SETSIZE might be less than sizeof(cpu_set_t) ? */
    z = sched_getaffinity((pid_t) pid, sizeof(cpu_set_t), _set1);
#ifdef CPU_COUNT
    ncpus = CPU_COUNT(_set1);
#endif
    if(debug_flag) fprintf(stderr,"getaffinity2 ncpus=%d\n", ncpus);
    if (z) {
      if(debug_flag) fprintf(stderr,"getaffinity3 z=%d err=%d\n", z, errno);
      r = 0;
    } else {
      av_clear(maskarray);
      if(debug_flag) fprintf(stderr,"getaffinity5\n");
      /* tests.reproducible-builds.org/debian/rb-pkg/unstable/i386/
         libsys-cpuaffinity-perl.html:
             __NCPUBITS=32 but taskset,/proc/cpuinfo say there are 34 cpus */
      for (i = 0, r = 0; i < ncpus; i++) {
        if(debug_flag) fprintf(stderr,"getaffinity6 i=%d r=%d\n", i, r);
        if (CPU_ISSET(i, &_set2)) {
          r |= 1;
          av_push(maskarray, newSViv(i));
          if(debug_flag) fprintf(stderr,"getaffinity8 add %d to mask\n", i);
        }
      }
      if(debug_flag) fprintf(stderr,"getaffinitya r=%d\n",r);
    }
    RETVAL = r;
  OUTPUT:
    RETVAL