File Coverage

Affinity.xs
Criterion Covered Total %
statement 61 84 72.6
branch 38 76 50.0
condition n/a
subroutine n/a
pod n/a
total 99 160 61.8


line stmt bran cond sub pod time code
1             #define PERL_NO_GET_CONTEXT
2             #include "EXTERN.h"
3             #include "perl.h"
4             #include "XSUB.h"
5              
6             #include
7             #include
8             #include
9             //#include
10              
11             struct xs_state {
12             cpu_set_t *set;
13             size_t size;
14             };
15              
16             typedef struct xs_state Linux_Sys_CPU_Affinity;
17              
18 6           void init_set (Linux_Sys_CPU_Affinity *cpuset, AV *av) {
19              
20             static int available_cpus_cnt = 0;
21              
22             /* get available amount of CPU cores */
23 6 100         if (available_cpus_cnt == 0)
24 1           available_cpus_cnt = get_nprocs(); // sysconf(_SC_NPROCESSORS_ONLN);
25              
26             /* if we're failed, then use constant, mostly it equals to 1024 */
27 6 50         if (available_cpus_cnt == -1)
28 0           available_cpus_cnt = CPU_SETSIZE;
29              
30 6 100         if (cpuset->set != NULL)
31 4           CPU_FREE(cpuset->set);
32              
33 6           cpuset->size = CPU_ALLOC_SIZE(available_cpus_cnt);
34 6           cpuset->set = CPU_ALLOC(available_cpus_cnt);
35              
36 6 50         if (cpuset->set == NULL) {
37 0           SV *msg = sv_2mortal( newSVpvf("Failed to allocate memory for %i CPUs", available_cpus_cnt) );
38 0 0         Perl_croak(pTHX_ (char *) SvPV_nolen(msg));
39             }
40              
41 6           CPU_ZERO_S(cpuset->size, cpuset->set);
42              
43 6 100         if (av != NULL) {
44             SSize_t i;
45 3           SSize_t av_len = av_len(av) + 1;
46 14 100         for (i = 0; i < av_len; i++) {
47 11 50         size_t cpu = SvIV((SV*)*av_fetch(av, i, 0)); // SvIVX to coerce value into IV
48             //Perl_warner_nocontext(aTHX_ packWARN(WARN_QW), "value = %i\n", cpu);
49 11 50         CPU_SET_S(cpu, cpuset->size, cpuset->set);
50             }
51             }
52 6           }
53              
54 3           AV* _extract_and_validate_av(SV *sv) {
55              
56 3 50         if (!SvOK(sv))
    0          
    0          
57 0           Perl_croak(aTHX_ "the CPU's list can't be undefined");
58              
59 3 50         if (SvTIED_mg(sv, PERL_MAGIC_tied))
    0          
60 0           Perl_croak(aTHX_ "tied objects aren't supported");
61              
62 3 50         if (!SvROK(sv))
63 0           Perl_croak(aTHX_ "the CPU's list must be an array reference");
64              
65 3           SV *ref = SvRV(sv);
66             AV *av;
67              
68 3 50         switch (SvTYPE(ref)) {
69             case SVt_PVAV: // $ref eq "ARRAY"
70 3           av = (AV *) ref;
71 3           break;
72             default: // $ref ne "ARRAY"
73 0           Perl_croak(aTHX_ "the CPU's list must be an array reference");
74             }
75              
76             SSize_t i;
77 3           SSize_t bad_arg = -1;
78             // SV **arr = AvARRAY(av);
79              
80 14 100         for (i = av_len(av); i >= 0; i--) {
81 11           SV *val = (SV *) *av_fetch(av, i, 0);
82             // SV *val = arr[i];
83 11 50         if (!SvOK(val) || !SvIOK(val)) {
    0          
    0          
    50          
84 0           bad_arg = i;
85 0           break;
86             }
87             }
88              
89 3 50         if (bad_arg != -1) {
90             // postpone SvREFCNT_dec(sv)
91 0           SV *msg = sv_2mortal( newSVpvf("Not an integer at position %i", bad_arg) );
92 0 0         Perl_croak(pTHX_ (char *) SvPV_nolen(msg));
93             }
94              
95 3           return av;
96             }
97              
98             MODULE = Linux::Sys::CPU::Affinity PACKAGE = Linux::Sys::CPU::Affinity
99              
100             PROTOTYPES: DISABLE
101              
102             Linux_Sys_CPU_Affinity* new(class_name, sv = &PL_sv_undef)
103             char *class_name
104             SV *sv
105             PREINIT:
106             Linux_Sys_CPU_Affinity *cpuset;
107 2           AV* av = NULL;
108             CODE:
109              
110 2 100         if (SvOK(sv))
    50          
    50          
111 1           av = _extract_and_validate_av(sv);
112              
113 2           cpuset = (Linux_Sys_CPU_Affinity *) malloc(sizeof(Linux_Sys_CPU_Affinity));
114              
115 2           cpuset->set = NULL;
116              
117 2           init_set(cpuset, av);
118              
119 2           RETVAL = cpuset;
120             OUTPUT:
121             RETVAL
122              
123              
124             SV* cpu_zero(cpuset)
125             Linux_Sys_CPU_Affinity *cpuset
126             CODE:
127 1           init_set(cpuset, NULL);
128 1           XSRETURN_UNDEF;
129             OUTPUT:
130             RETVAL
131              
132              
133             SV* reset(cpuset, sv = &PL_sv_undef)
134             Linux_Sys_CPU_Affinity *cpuset
135             SV *sv
136             PREINIT:
137 3           AV* av = NULL;
138             CODE:
139 3 100         if (SvOK(sv))
    50          
    50          
140 2           av = _extract_and_validate_av(sv);
141 3           init_set(cpuset, av);
142 3           XSRETURN_UNDEF;
143              
144              
145             IV cpu_isset (cpuset, cpu)
146             Linux_Sys_CPU_Affinity *cpuset
147             UV cpu
148             PPCODE:
149 4 50         int res = CPU_ISSET_S((uint32_t) cpu, cpuset->size, cpuset->set);
    100          
150 4 50         mXPUSHu( res );
151 4           XSRETURN(1);
152              
153              
154             IV cpu_set (cpuset, cpu)
155             Linux_Sys_CPU_Affinity *cpuset
156             UV cpu
157             PPCODE:
158 1 50         CPU_SET_S((uint32_t) cpu, cpuset->size, cpuset->set);
159 1           XSRETURN_UNDEF;
160              
161              
162             IV cpu_clr (cpuset, cpu)
163             Linux_Sys_CPU_Affinity *cpuset
164             UV cpu
165             PPCODE:
166 1 50         CPU_CLR_S((uint32_t) cpu, cpuset->size, cpuset->set);
167 1           XSRETURN_UNDEF;
168              
169              
170             UV cpu_count(cpuset)
171             Linux_Sys_CPU_Affinity *cpuset
172             PPCODE:
173 7           int cpu_count = CPU_COUNT_S(cpuset->size, cpuset->set);
174 7 50         mXPUSHu( cpu_count ); // PUSHs(sv_2mortal(newSVuv(cpu_count)));
175 7           XSRETURN(1);
176              
177              
178             IV set_affinity(cpuset, pid)
179             Linux_Sys_CPU_Affinity *cpuset
180             UV pid
181             PPCODE:
182 1           int res = sched_setaffinity((pid_t) pid, cpuset->size, cpuset->set);
183 1 50         if (res == -1) {
184 0           SV *error = sv_2mortal(newSV(0));
185 0           switch (errno) {
186             case EFAULT:
187 0           sv_setpv(error, "A supplied memory address was invalid");
188 0           break;
189             case EINVAL:
190 0           sv_setpv(error, "The affinity bit mask mask contains no processors that are currently physically on the system and permitted to the thread");
191 0           break;
192             case EPERM:
193 0           sv_setpv(error, "The calling thread does not have appropriate privileges");
194 0           break;
195             case ESRCH:
196 0           sv_setpv(error, "The thread whose ID is pid could not be found");
197 0           break;
198             default:
199 0           sv_setpv(error, "Unknown error has occurred");
200             }
201 0 0         Perl_croak(pTHX_ (char *) SvPV_nolen(error));
202             }
203 1 50         mXPUSHi( res );
204 1           XSRETURN(1);
205              
206              
207             void DESTROY (cpuset)
208             Linux_Sys_CPU_Affinity *cpuset
209             PPCODE:
210 2           CPU_FREE(cpuset->set);
211 2           free(cpuset);
212 2           XSRETURN_UNDEF;