1 /*
2  * Copyright © 2012 Aleksej Saushev, The NetBSD Foundation
3  * Copyright © 2009-2014 Inria.  All rights reserved.
4  * Copyright © 2009-2010 Université Bordeaux
5  * Copyright © 2011 Cisco Systems, Inc.  All rights reserved.
6  * See COPYING in top-level directory.
7  */
8 
9 #define _NETBSD_SOURCE /* request "_np" functions */
10 
11 #include <private/autogen/config.h>
12 
13 #include <sys/types.h>
14 #include <stdlib.h>
15 #include <inttypes.h>
16 #include <sys/param.h>
17 #include <pthread.h>
18 #include <sched.h>
19 #ifdef HAVE_SYS_SYSCTL_H
20 #include <sys/sysctl.h>
21 #endif
22 
23 #include <hwloc.h>
24 #include <private/private.h>
25 #include <private/debug.h>
26 
27 static void
hwloc_netbsd_bsd2hwloc(hwloc_bitmap_t hwloc_cpuset,const cpuset_t * cpuset)28 hwloc_netbsd_bsd2hwloc(hwloc_bitmap_t hwloc_cpuset, const cpuset_t *cpuset)
29 {
30   unsigned cpu, cpulimit;
31   int found = 0;
32   hwloc_bitmap_zero(hwloc_cpuset);
33   cpulimit = cpuset_size(cpuset) * CHAR_BIT;
34   for (cpu = 0; cpu < cpulimit; cpu++)
35     if (cpuset_isset(cpu, cpuset)) {
36       hwloc_bitmap_set(hwloc_cpuset, cpu);
37       found++;
38     }
39   /* when never bound, it returns an empty set, fill it instead */
40   if (!found)
41     hwloc_bitmap_fill(hwloc_cpuset);
42 }
43 
44 static void
hwloc_netbsd_hwloc2bsd(hwloc_const_bitmap_t hwloc_cpuset,cpuset_t * cpuset)45 hwloc_netbsd_hwloc2bsd(hwloc_const_bitmap_t hwloc_cpuset, cpuset_t *cpuset)
46 {
47   unsigned cpu, cpulimit;
48   cpuset_zero(cpuset);
49   cpulimit = cpuset_size(cpuset) * CHAR_BIT;
50   for (cpu = 0; cpu < cpulimit; cpu++)
51     if (hwloc_bitmap_isset(hwloc_cpuset, cpu))
52       cpuset_set(cpu, cpuset);
53 }
54 
55 static int
hwloc_netbsd_set_proc_cpubind(hwloc_topology_t topology __hwloc_attribute_unused,hwloc_pid_t pid,hwloc_const_bitmap_t hwloc_cpuset,int flags __hwloc_attribute_unused)56 hwloc_netbsd_set_proc_cpubind(hwloc_topology_t topology __hwloc_attribute_unused, hwloc_pid_t pid, hwloc_const_bitmap_t hwloc_cpuset, int flags __hwloc_attribute_unused)
57 {
58   int status;
59   cpuset_t *cpuset = cpuset_create();
60   hwloc_netbsd_hwloc2bsd(hwloc_cpuset, cpuset);
61   status = sched_setaffinity_np(pid, cpuset_size(cpuset), cpuset);
62   cpuset_destroy(cpuset);
63   return status;
64 }
65 
66 static int
hwloc_netbsd_get_proc_cpubind(hwloc_topology_t topology __hwloc_attribute_unused,hwloc_pid_t pid,hwloc_bitmap_t hwloc_cpuset,int flags __hwloc_attribute_unused)67 hwloc_netbsd_get_proc_cpubind(hwloc_topology_t topology __hwloc_attribute_unused, hwloc_pid_t pid, hwloc_bitmap_t hwloc_cpuset, int flags __hwloc_attribute_unused)
68 {
69   int status;
70   cpuset_t *cpuset = cpuset_create();
71   status = sched_getaffinity_np(pid, cpuset_size(cpuset), cpuset);
72   hwloc_netbsd_bsd2hwloc(hwloc_cpuset, cpuset);
73   cpuset_destroy(cpuset);
74   return status;
75 }
76 
77 
78 static int
hwloc_netbsd_set_thisproc_cpubind(hwloc_topology_t topology,hwloc_const_bitmap_t hwloc_cpuset,int flags)79 hwloc_netbsd_set_thisproc_cpubind(hwloc_topology_t topology, hwloc_const_bitmap_t hwloc_cpuset, int flags)
80 {
81   return hwloc_netbsd_set_proc_cpubind(topology, 0, hwloc_cpuset, flags);
82 }
83 
84 static int
hwloc_netbsd_get_thisproc_cpubind(hwloc_topology_t topology,hwloc_bitmap_t hwloc_cpuset,int flags)85 hwloc_netbsd_get_thisproc_cpubind(hwloc_topology_t topology, hwloc_bitmap_t hwloc_cpuset, int flags)
86 {
87   return hwloc_netbsd_get_proc_cpubind(topology, 0, hwloc_cpuset, flags);
88 }
89 
90 
91 static int
hwloc_netbsd_set_thread_cpubind(hwloc_topology_t topology __hwloc_attribute_unused,hwloc_thread_t tid,hwloc_const_bitmap_t hwloc_cpuset,int flags __hwloc_attribute_unused)92 hwloc_netbsd_set_thread_cpubind(hwloc_topology_t topology __hwloc_attribute_unused, hwloc_thread_t tid, hwloc_const_bitmap_t hwloc_cpuset, int flags __hwloc_attribute_unused)
93 {
94   int status;
95   cpuset_t *cpuset = cpuset_create();
96   hwloc_netbsd_hwloc2bsd(hwloc_cpuset, cpuset);
97   status = pthread_setaffinity_np(tid, cpuset_size(cpuset), cpuset);
98   cpuset_destroy(cpuset);
99 
100   if (status) {
101     errno = status;
102     return -1;
103   }
104   return 0;
105 }
106 
107 static int
hwloc_netbsd_get_thread_cpubind(hwloc_topology_t topology __hwloc_attribute_unused,hwloc_thread_t tid,hwloc_bitmap_t hwloc_cpuset,int flags __hwloc_attribute_unused)108 hwloc_netbsd_get_thread_cpubind(hwloc_topology_t topology __hwloc_attribute_unused, hwloc_thread_t tid, hwloc_bitmap_t hwloc_cpuset, int flags __hwloc_attribute_unused)
109 {
110   int status;
111   cpuset_t *cpuset = cpuset_create();
112   status = pthread_getaffinity_np(tid, cpuset_size(cpuset), cpuset);
113   hwloc_netbsd_bsd2hwloc(hwloc_cpuset, cpuset);
114   cpuset_destroy(cpuset);
115 
116   if (status) {
117     errno = status;
118     return -1;
119   }
120   return 0;
121 }
122 
123 
124 static int
hwloc_netbsd_set_thisthread_cpubind(hwloc_topology_t topology,hwloc_const_bitmap_t hwloc_cpuset,int flags)125 hwloc_netbsd_set_thisthread_cpubind(hwloc_topology_t topology, hwloc_const_bitmap_t hwloc_cpuset, int flags)
126 {
127   return hwloc_netbsd_set_thread_cpubind(topology, pthread_self(), hwloc_cpuset, flags);
128 }
129 
130 static int
hwloc_netbsd_get_thisthread_cpubind(hwloc_topology_t topology,hwloc_bitmap_t hwloc_cpuset,int flags)131 hwloc_netbsd_get_thisthread_cpubind(hwloc_topology_t topology, hwloc_bitmap_t hwloc_cpuset, int flags)
132 {
133   return hwloc_netbsd_get_thread_cpubind(topology, pthread_self(), hwloc_cpuset, flags);
134 }
135 
136 #if (defined HAVE_SYSCTL) && (defined HAVE_SYS_SYSCTL_H)
137 static void
hwloc_netbsd_node_meminfo_info(struct hwloc_topology * topology)138 hwloc_netbsd_node_meminfo_info(struct hwloc_topology *topology)
139 {
140   int mib[2] = { CTL_HW, HW_PHYSMEM64 };
141   unsigned long physmem;
142   size_t len = sizeof(physmem);
143   sysctl(mib, 2, &physmem, &len, NULL, 0);
144   topology->levels[0][0]->memory.local_memory = physmem;
145 }
146 #endif
147 
148 static int
hwloc_look_netbsd(struct hwloc_backend * backend)149 hwloc_look_netbsd(struct hwloc_backend *backend)
150 {
151   struct hwloc_topology *topology = backend->topology;
152   unsigned nbprocs = hwloc_fallback_nbprocessors(topology);
153 
154   if (!topology->levels[0][0]->cpuset) {
155     /* Nobody (even the x86 backend) created objects yet, setup basic objects */
156     hwloc_alloc_obj_cpusets(topology->levels[0][0]);
157     hwloc_setup_pu_level(topology, nbprocs);
158   }
159 
160   /* Add NetBSD specific information */
161 #if (defined HAVE_SYSCTL) && (defined HAVE_SYS_SYSCTL_H)
162   hwloc_netbsd_node_meminfo_info(topology);
163 #endif
164   hwloc_obj_add_info(topology->levels[0][0], "Backend", "NetBSD");
165   if (topology->is_thissystem)
166     hwloc_add_uname_info(topology, NULL);
167   return 1;
168 }
169 
170 void
hwloc_set_netbsd_hooks(struct hwloc_binding_hooks * hooks __hwloc_attribute_unused,struct hwloc_topology_support * support __hwloc_attribute_unused)171 hwloc_set_netbsd_hooks(struct hwloc_binding_hooks *hooks __hwloc_attribute_unused,
172                         struct hwloc_topology_support *support __hwloc_attribute_unused)
173 {
174   hooks->set_proc_cpubind = hwloc_netbsd_set_proc_cpubind;
175   hooks->get_proc_cpubind = hwloc_netbsd_get_proc_cpubind;
176   hooks->set_thisproc_cpubind = hwloc_netbsd_set_thisproc_cpubind;
177   hooks->get_thisproc_cpubind = hwloc_netbsd_get_thisproc_cpubind;
178 
179   hooks->set_thread_cpubind = hwloc_netbsd_set_thread_cpubind;
180   hooks->get_thread_cpubind = hwloc_netbsd_get_thread_cpubind;
181   hooks->set_thisthread_cpubind = hwloc_netbsd_set_thisthread_cpubind;
182   hooks->get_thisthread_cpubind = hwloc_netbsd_get_thisthread_cpubind;
183 }
184 
185 static struct hwloc_backend *
hwloc_netbsd_component_instantiate(struct hwloc_disc_component * component,const void * _data1 __hwloc_attribute_unused,const void * _data2 __hwloc_attribute_unused,const void * _data3 __hwloc_attribute_unused)186 hwloc_netbsd_component_instantiate(struct hwloc_disc_component *component,
187 				   const void *_data1 __hwloc_attribute_unused,
188 				   const void *_data2 __hwloc_attribute_unused,
189 				   const void *_data3 __hwloc_attribute_unused)
190 {
191   struct hwloc_backend *backend;
192   backend = hwloc_backend_alloc(component);
193   if (!backend)
194     return NULL;
195   backend->discover = hwloc_look_netbsd;
196   return backend;
197 }
198 
199 static struct hwloc_disc_component hwloc_netbsd_disc_component = {
200   HWLOC_DISC_COMPONENT_TYPE_CPU,
201   "netbsd",
202   HWLOC_DISC_COMPONENT_TYPE_GLOBAL,
203   hwloc_netbsd_component_instantiate,
204   50,
205   NULL
206 };
207 
208 const struct hwloc_component hwloc_netbsd_component = {
209   HWLOC_COMPONENT_ABI,
210   NULL, NULL,
211   HWLOC_COMPONENT_TYPE_DISC,
212   0,
213   &hwloc_netbsd_disc_component
214 };
215