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