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