1*2685Sakolb /*
2*2685Sakolb * CDDL HEADER START
3*2685Sakolb *
4*2685Sakolb * The contents of this file are subject to the terms of the
5*2685Sakolb * Common Development and Distribution License (the "License").
6*2685Sakolb * You may not use this file except in compliance with the License.
7*2685Sakolb *
8*2685Sakolb * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9*2685Sakolb * or http://www.opensolaris.org/os/licensing.
10*2685Sakolb * See the License for the specific language governing permissions
11*2685Sakolb * and limitations under the License.
12*2685Sakolb *
13*2685Sakolb * When distributing Covered Code, include this CDDL HEADER in each
14*2685Sakolb * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15*2685Sakolb * If applicable, add the following below this CDDL HEADER, with the
16*2685Sakolb * fields enclosed by brackets "[]" replaced with your own identifying
17*2685Sakolb * information: Portions Copyright [yyyy] [name of copyright owner]
18*2685Sakolb *
19*2685Sakolb * CDDL HEADER END
20*2685Sakolb */
21*2685Sakolb
22*2685Sakolb /*
23*2685Sakolb * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
24*2685Sakolb * Use is subject to license terms.
25*2685Sakolb */
26*2685Sakolb
27*2685Sakolb #pragma ident "%Z%%M% %I% %E% SMI"
28*2685Sakolb
29*2685Sakolb /*
30*2685Sakolb * Lgrp.xs contains XS wrappers for the system locality group library
31*2685Sakolb * liblgrp(3LIB).
32*2685Sakolb */
33*2685Sakolb
34*2685Sakolb #include <sys/errno.h>
35*2685Sakolb #include <sys/lgrp_user.h>
36*2685Sakolb
37*2685Sakolb /*
38*2685Sakolb * On i386 Solaris defines SP, which conflicts with the perl definition of SP
39*2685Sakolb * We don't need the Solaris one, so get rid of it to avoid warnings.
40*2685Sakolb */
41*2685Sakolb #undef SP
42*2685Sakolb
43*2685Sakolb /* Perl XS includes. */
44*2685Sakolb #include "EXTERN.h"
45*2685Sakolb #include "perl.h"
46*2685Sakolb #include "XSUB.h"
47*2685Sakolb
48*2685Sakolb /* Return undef in scalar context and empty list in list context */
49*2685Sakolb #define LGRP_BADVAL() { \
50*2685Sakolb if (GIMME_V == G_ARRAY) \
51*2685Sakolb XSRETURN_EMPTY; \
52*2685Sakolb else \
53*2685Sakolb XSRETURN_UNDEF; \
54*2685Sakolb }
55*2685Sakolb
56*2685Sakolb /*
57*2685Sakolb * Push all values from input array onto the perl return stack.
58*2685Sakolb */
59*2685Sakolb #define PUSHARRAY(array, nitems) \
60*2685Sakolb { \
61*2685Sakolb int x; \
62*2685Sakolb \
63*2685Sakolb if (nitems < 0) { \
64*2685Sakolb LGRP_BADVAL() \
65*2685Sakolb } else if (nitems > 0) { \
66*2685Sakolb EXTEND(SP, nitems); \
67*2685Sakolb for (x = 0; x < nitems; x++) { \
68*2685Sakolb PUSHs(sv_2mortal(newSVnv(array[x]))); \
69*2685Sakolb } \
70*2685Sakolb } \
71*2685Sakolb }
72*2685Sakolb
73*2685Sakolb /*
74*2685Sakolb * Several constants are not present in the first version of the Lgrp API,
75*2685Sakolb * we define them here.
76*2685Sakolb *
77*2685Sakolb * lgrp_resources() and lgrp_latency_cookie() only appear in API v2. If the
78*2685Sakolb * module is linked with old version of liblgrp(3LIB) there is no lgrp_resources
79*2685Sakolb * symbol in the library and perl wrapper returns empty list and sets errno to
80*2685Sakolb * EINVAL.
81*2685Sakolb *
82*2685Sakolb * The lgrp_latency_cookie() is emulated using lgrp_latency().
83*2685Sakolb */
84*2685Sakolb #if LGRP_VER_CURRENT == 1
85*2685Sakolb #define LGRP_CONTENT_ALL LGRP_CONTENT_HIERARCHY
86*2685Sakolb #define LGRP_LAT_CPU_TO_MEM 0
87*2685Sakolb #define LGRP_RSRC_CPU 0 /* CPU resources */
88*2685Sakolb #define LGRP_RSRC_MEM 1 /* memory resources */
89*2685Sakolb
90*2685Sakolb #define LGRP_RESOURCES(c, lgrp, type) \
91*2685Sakolb { errno = EINVAL; LGRP_BADVAL(); }
92*2685Sakolb
93*2685Sakolb /*
94*2685Sakolb * Simulate lgrp_latency_cookie() which just fails. This macro is never called
95*2685Sakolb * and we just define it so that the C compiler will not complain about the
96*2685Sakolb * missing symbol.
97*2685Sakolb */
98*2685Sakolb #define lgrp_latency_cookie(c, f, t, b) (errno = EINVAL, -1)
99*2685Sakolb
100*2685Sakolb #else
101*2685Sakolb #define LGRP_RESOURCES(c, lgrp, type) { \
102*2685Sakolb int nr; \
103*2685Sakolb lgrp_id_t *lgrps; \
104*2685Sakolb \
105*2685Sakolb errno = 0; \
106*2685Sakolb nr = lgrp_resources(c, lgrp, NULL, 0, type); \
107*2685Sakolb if (nr < 0) \
108*2685Sakolb LGRP_BADVAL(); \
109*2685Sakolb if (GIMME_V == G_SCALAR) \
110*2685Sakolb XSRETURN_IV(nr); \
111*2685Sakolb if (nr == 0) { \
112*2685Sakolb XSRETURN_EMPTY; \
113*2685Sakolb } else if (New(0, lgrps, nr, lgrp_id_t) == NULL) { \
114*2685Sakolb errno = ENOMEM; \
115*2685Sakolb LGRP_BADVAL(); \
116*2685Sakolb } else { \
117*2685Sakolb nr = lgrp_resources(c, lgrp, lgrps, nr, type); \
118*2685Sakolb PUSHARRAY(lgrps, nr); \
119*2685Sakolb Safefree(lgrps); \
120*2685Sakolb } \
121*2685Sakolb }
122*2685Sakolb #endif
123*2685Sakolb
124*2685Sakolb /*
125*2685Sakolb * Special version of lgrp_latency_cookie(). Use lgrp_latency() for liblgrp V1
126*2685Sakolb * and lgrp_latency_cookie for V2.
127*2685Sakolb */
128*2685Sakolb static int
_lgrp_latency_cookie(lgrp_cookie_t cookie,lgrp_id_t from,lgrp_id_t to,int between)129*2685Sakolb _lgrp_latency_cookie(lgrp_cookie_t cookie, lgrp_id_t from, lgrp_id_t to,
130*2685Sakolb int between)
131*2685Sakolb {
132*2685Sakolb return (LGRP_VER_CURRENT < 2 ?
133*2685Sakolb lgrp_latency(from, to) :
134*2685Sakolb lgrp_latency_cookie(cookie, from, to, between));
135*2685Sakolb }
136*2685Sakolb
137*2685Sakolb /*
138*2685Sakolb * Most functions in liblgrp return -1 on failure. The perl equivalent returns
139*2685Sakolb * 'undef' instead. The macro should be call after the RETVAL is set to the
140*2685Sakolb * return value of the function.
141*2685Sakolb */
142*2685Sakolb #define RETURN_UNDEF_IF_FAIL { if (RETVAL < 0) XSRETURN_UNDEF; }
143*2685Sakolb
144*2685Sakolb /*
145*2685Sakolb * End of C part, start of XS part.
146*2685Sakolb *
147*2685Sakolb * The XS code exported to perl is below here. Note that the XS preprocessor
148*2685Sakolb * has its own commenting syntax, so all comments from this point on are in
149*2685Sakolb * that form.
150*2685Sakolb */
151*2685Sakolb
152*2685Sakolb MODULE = Sun::Solaris::Lgrp PACKAGE = Sun::Solaris::Lgrp
153*2685Sakolb PROTOTYPES: ENABLE
154*2685Sakolb
155*2685Sakolb #
156*2685Sakolb # Define any constants that need to be exported. By doing it this way we can
157*2685Sakolb # avoid the overhead of using the DynaLoader package, and in addition constants
158*2685Sakolb # defined using this mechanism are eligible for inlining by the perl
159*2685Sakolb # interpreter at compile time.
160*2685Sakolb #
161*2685Sakolb BOOT:
162*2685Sakolb {
163*2685Sakolb HV *stash;
164*2685Sakolb
165*2685Sakolb stash = gv_stashpv("Sun::Solaris::Lgrp", TRUE);
166*2685Sakolb newCONSTSUB(stash, "LGRP_AFF_NONE", newSViv(LGRP_AFF_NONE));
167*2685Sakolb newCONSTSUB(stash, "LGRP_AFF_STRONG", newSViv(LGRP_AFF_STRONG));
168*2685Sakolb newCONSTSUB(stash, "LGRP_AFF_WEAK", newSViv(LGRP_AFF_WEAK));
169*2685Sakolb newCONSTSUB(stash, "LGRP_VER_CURRENT", newSViv(LGRP_VER_CURRENT));
170*2685Sakolb newCONSTSUB(stash, "LGRP_VER_NONE", newSViv(LGRP_VER_NONE));
171*2685Sakolb newCONSTSUB(stash, "LGRP_NONE", newSViv(LGRP_NONE));
172*2685Sakolb newCONSTSUB(stash, "LGRP_RSRC_CPU", newSViv(LGRP_RSRC_CPU));
173*2685Sakolb newCONSTSUB(stash, "LGRP_RSRC_MEM", newSViv(LGRP_RSRC_MEM));
174*2685Sakolb newCONSTSUB(stash, "LGRP_CONTENT_HIERARCHY",
175*2685Sakolb newSViv(LGRP_CONTENT_HIERARCHY));
176*2685Sakolb newCONSTSUB(stash, "LGRP_CONTENT_DIRECT", newSViv(LGRP_CONTENT_DIRECT));
177*2685Sakolb newCONSTSUB(stash, "LGRP_VIEW_CALLER", newSViv(LGRP_VIEW_CALLER));
178*2685Sakolb newCONSTSUB(stash, "LGRP_VIEW_OS", newSViv(LGRP_VIEW_OS));
179*2685Sakolb newCONSTSUB(stash, "LGRP_MEM_SZ_FREE", newSViv(LGRP_MEM_SZ_FREE));
180*2685Sakolb newCONSTSUB(stash, "LGRP_MEM_SZ_INSTALLED",
181*2685Sakolb newSViv(LGRP_MEM_SZ_INSTALLED));
182*2685Sakolb newCONSTSUB(stash, "LGRP_CONTENT_ALL", newSViv(LGRP_CONTENT_ALL));
183*2685Sakolb newCONSTSUB(stash, "LGRP_LAT_CPU_TO_MEM", newSViv(LGRP_LAT_CPU_TO_MEM));
184*2685Sakolb newCONSTSUB(stash, "P_PID", newSViv(P_PID));
185*2685Sakolb newCONSTSUB(stash, "P_LWPID", newSViv(P_LWPID));
186*2685Sakolb newCONSTSUB(stash, "P_MYID", newSViv(P_MYID));
187*2685Sakolb }
188*2685Sakolb
189*2685Sakolb #
190*2685Sakolb # The code below uses POSTCALL directive which allows to return 'undef'
191*2685Sakolb # whenever a C function returns a negative value.
192*2685Sakolb #
193*2685Sakolb
194*2685Sakolb
195*2685Sakolb #
196*2685Sakolb # lgrp_init([view])
197*2685Sakolb # Use LGRP_VIEW_OS as the default view.
198*2685Sakolb #
199*2685Sakolb lgrp_cookie_t
200*2685Sakolb lgrp_init(lgrp_view_t view = LGRP_VIEW_OS)
201*2685Sakolb POSTCALL:
202*2685Sakolb RETURN_UNDEF_IF_FAIL;
203*2685Sakolb
204*2685Sakolb lgrp_view_t
205*2685Sakolb lgrp_view(cookie)
206*2685Sakolb lgrp_cookie_t cookie
207*2685Sakolb POSTCALL:
208*2685Sakolb RETURN_UNDEF_IF_FAIL;
209*2685Sakolb
210*2685Sakolb lgrp_affinity_t
211*2685Sakolb lgrp_affinity_get(idtype, id, lgrp)
212*2685Sakolb idtype_t idtype;
213*2685Sakolb id_t id;
214*2685Sakolb lgrp_id_t lgrp;
215*2685Sakolb POSTCALL:
216*2685Sakolb RETURN_UNDEF_IF_FAIL;
217*2685Sakolb
218*2685Sakolb int
219*2685Sakolb lgrp_affinity_set(idtype, id, lgrp, affinity)
220*2685Sakolb idtype_t idtype;
221*2685Sakolb id_t id;
222*2685Sakolb lgrp_id_t lgrp;
223*2685Sakolb lgrp_affinity_t affinity;
224*2685Sakolb POSTCALL:
225*2685Sakolb RETURN_UNDEF_IF_FAIL;
226*2685Sakolb XSRETURN_YES;
227*2685Sakolb
228*2685Sakolb int
229*2685Sakolb lgrp_cookie_stale(cookie)
230*2685Sakolb lgrp_cookie_t cookie;
231*2685Sakolb POSTCALL:
232*2685Sakolb RETURN_UNDEF_IF_FAIL;
233*2685Sakolb
234*2685Sakolb int
235*2685Sakolb lgrp_fini(cookie)
236*2685Sakolb lgrp_cookie_t cookie;
237*2685Sakolb POSTCALL:
238*2685Sakolb RETURN_UNDEF_IF_FAIL;
239*2685Sakolb XSRETURN_YES;
240*2685Sakolb
241*2685Sakolb lgrp_id_t
242*2685Sakolb lgrp_home(idtype, id)
243*2685Sakolb idtype_t idtype;
244*2685Sakolb id_t id;
245*2685Sakolb POSTCALL:
246*2685Sakolb RETURN_UNDEF_IF_FAIL;
247*2685Sakolb
248*2685Sakolb int
249*2685Sakolb lgrp_latency(lgrp_id_t from,lgrp_id_t to)
250*2685Sakolb POSTCALL:
251*2685Sakolb RETURN_UNDEF_IF_FAIL;
252*2685Sakolb
253*2685Sakolb lgrp_mem_size_t
254*2685Sakolb lgrp_mem_size(cookie, lgrp, type, content)
255*2685Sakolb lgrp_cookie_t cookie
256*2685Sakolb lgrp_id_t lgrp
257*2685Sakolb int type
258*2685Sakolb lgrp_content_t content
259*2685Sakolb POSTCALL:
260*2685Sakolb RETURN_UNDEF_IF_FAIL;
261*2685Sakolb
262*2685Sakolb int
263*2685Sakolb lgrp_nlgrps(cookie)
264*2685Sakolb lgrp_cookie_t cookie;
265*2685Sakolb POSTCALL:
266*2685Sakolb RETURN_UNDEF_IF_FAIL;
267*2685Sakolb
268*2685Sakolb lgrp_id_t
269*2685Sakolb lgrp_root(cookie)
270*2685Sakolb lgrp_cookie_t cookie
271*2685Sakolb POSTCALL:
272*2685Sakolb RETURN_UNDEF_IF_FAIL;
273*2685Sakolb
274*2685Sakolb int
275*2685Sakolb lgrp_version(int version = LGRP_VER_NONE)
276*2685Sakolb
277*2685Sakolb #
278*2685Sakolb # lgrp_latency_cookie calls our internal wrapper _lgrp_latency_cookie() which
279*2685Sakolb # works for both old and new versions of liblgrp.
280*2685Sakolb #
281*2685Sakolb int
282*2685Sakolb lgrp_latency_cookie(lgrp_cookie_t cookie, lgrp_id_t from, lgrp_id_t to, int between = 0)
283*2685Sakolb CODE:
284*2685Sakolb RETVAL = _lgrp_latency_cookie(cookie, from, to, between);
285*2685Sakolb POSTCALL:
286*2685Sakolb RETURN_UNDEF_IF_FAIL;
287*2685Sakolb OUTPUT:
288*2685Sakolb RETVAL
289*2685Sakolb
290*2685Sakolb #
291*2685Sakolb # Functions below convert C arrays into Perl lists. They use XS PPCODE
292*2685Sakolb # directive to avoid implicit RETVAL assignments and manipulate perl
293*2685Sakolb # stack directly.
294*2685Sakolb #
295*2685Sakolb # When called in scalar context functions return the number of elements
296*2685Sakolb # in the list or undef on failure.
297*2685Sakolb #
298*2685Sakolb # The PUSHARRAY() macro defined above pushes all values from the C array to
299*2685Sakolb # the perl stack.
300*2685Sakolb #
301*2685Sakolb
302*2685Sakolb #
303*2685Sakolb # @children = lgrp_children($cookie, $parent).
304*2685Sakolb #
305*2685Sakolb void
306*2685Sakolb lgrp_children(cookie, lgrp)
307*2685Sakolb lgrp_cookie_t cookie;
308*2685Sakolb lgrp_id_t lgrp;
309*2685Sakolb PREINIT:
310*2685Sakolb lgrp_id_t *lgrps;
311*2685Sakolb int count;
312*2685Sakolb PPCODE:
313*2685Sakolb errno = 0;
314*2685Sakolb if ((count = lgrp_children(cookie, lgrp, NULL, 0)) < 0)
315*2685Sakolb LGRP_BADVAL();
316*2685Sakolb
317*2685Sakolb if (GIMME_V == G_SCALAR)
318*2685Sakolb XSRETURN_IV(count);
319*2685Sakolb
320*2685Sakolb if (count > 0) {
321*2685Sakolb if (New(0, lgrps, count, lgrp_id_t) == NULL) {
322*2685Sakolb errno = ENOMEM;
323*2685Sakolb LGRP_BADVAL();
324*2685Sakolb } else {
325*2685Sakolb count = lgrp_children(cookie, lgrp, lgrps, count);
326*2685Sakolb PUSHARRAY(lgrps, count);
327*2685Sakolb Safefree(lgrps);
328*2685Sakolb }
329*2685Sakolb }
330*2685Sakolb
331*2685Sakolb #
332*2685Sakolb # @parents = lgrp_parents($cookie, $lgrp).
333*2685Sakolb #
334*2685Sakolb void
335*2685Sakolb lgrp_parents(cookie, lgrp)
336*2685Sakolb lgrp_cookie_t cookie;
337*2685Sakolb lgrp_id_t lgrp;
338*2685Sakolb PREINIT:
339*2685Sakolb lgrp_id_t *lgrps;
340*2685Sakolb int count;
341*2685Sakolb PPCODE:
342*2685Sakolb errno = 0;
343*2685Sakolb if ((count = lgrp_parents(cookie, lgrp, NULL, 0)) < 0)
344*2685Sakolb LGRP_BADVAL();
345*2685Sakolb
346*2685Sakolb if (GIMME_V == G_SCALAR)
347*2685Sakolb XSRETURN_IV(count);
348*2685Sakolb
349*2685Sakolb if (count > 0) {
350*2685Sakolb if (New(0, lgrps, count, lgrp_id_t) == NULL) {
351*2685Sakolb errno = ENOMEM;
352*2685Sakolb LGRP_BADVAL();
353*2685Sakolb } else {
354*2685Sakolb count = lgrp_parents(cookie, lgrp, lgrps, count);
355*2685Sakolb PUSHARRAY(lgrps, count);
356*2685Sakolb Safefree(lgrps);
357*2685Sakolb }
358*2685Sakolb }
359*2685Sakolb
360*2685Sakolb #
361*2685Sakolb # @parents = lgrp_cpus($cookie, $lgrp, $content).
362*2685Sakolb # Content should be LGRP_CONTENT_HIERARCHY or LGRP_CONTENT_ALL or
363*2685Sakolb # LGRP_CONTENT_DIRECT
364*2685Sakolb void
365*2685Sakolb lgrp_cpus(cookie, lgrp, content)
366*2685Sakolb lgrp_cookie_t cookie;
367*2685Sakolb lgrp_id_t lgrp;
368*2685Sakolb lgrp_content_t content;
369*2685Sakolb PREINIT:
370*2685Sakolb int ncpus;
371*2685Sakolb processorid_t *cpus;
372*2685Sakolb PPCODE:
373*2685Sakolb errno = 0;
374*2685Sakolb if ((ncpus = lgrp_cpus(cookie, lgrp, NULL, 0, content)) < 0)
375*2685Sakolb LGRP_BADVAL();
376*2685Sakolb
377*2685Sakolb if (GIMME_V == G_SCALAR)
378*2685Sakolb XSRETURN_IV(ncpus);
379*2685Sakolb
380*2685Sakolb if (ncpus > 0) {
381*2685Sakolb if (New(0, cpus, ncpus, processorid_t) == NULL) {
382*2685Sakolb errno = ENOMEM;
383*2685Sakolb LGRP_BADVAL();
384*2685Sakolb } else {
385*2685Sakolb ncpus = lgrp_cpus(cookie, lgrp, cpus, ncpus, content);
386*2685Sakolb PUSHARRAY(cpus, ncpus);
387*2685Sakolb Safefree(cpus);
388*2685Sakolb }
389*2685Sakolb }
390*2685Sakolb
391*2685Sakolb void
392*2685Sakolb lgrp_resources(cookie, lgrp, type)
393*2685Sakolb lgrp_cookie_t cookie;
394*2685Sakolb lgrp_id_t lgrp;
395*2685Sakolb int type;
396*2685Sakolb PPCODE:
397*2685Sakolb LGRP_RESOURCES(cookie, lgrp, type);
398