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