1#[cfg(any(
32 target_os = "android",
33 target_os = "linux",
34 target_os = "macos",
35 target_os = "freebsd",
36 target_os = "netbsd"
37))]
38extern crate libc;
39
40#[cfg_attr(all(not(test), not(target_os = "macos")), allow(unused_extern_crates))]
41extern crate num_cpus;
42
43pub fn get_core_ids() -> Option<Vec<CoreId>> {
47 get_core_ids_helper()
48}
49
50pub fn set_for_current(core_id: CoreId) -> bool {
57 set_for_current_helper(core_id)
58}
59
60#[repr(transparent)]
62#[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
63pub struct CoreId {
64 pub id: usize,
65}
66
67#[cfg(any(target_os = "android", target_os = "linux"))]
70#[inline]
71fn get_core_ids_helper() -> Option<Vec<CoreId>> {
72 linux::get_core_ids()
73}
74
75#[cfg(any(target_os = "android", target_os = "linux"))]
76#[inline]
77fn set_for_current_helper(core_id: CoreId) -> bool {
78 linux::set_for_current(core_id)
79}
80
81#[cfg(any(target_os = "android", target_os = "linux"))]
82mod linux {
83 use std::mem;
84
85 use libc::{CPU_ISSET, CPU_SET, CPU_SETSIZE, cpu_set_t, sched_getaffinity, sched_setaffinity};
86
87 use super::CoreId;
88
89 pub fn get_core_ids() -> Option<Vec<CoreId>> {
90 if let Some(full_set) = get_affinity_mask() {
91 let mut core_ids: Vec<CoreId> = Vec::new();
92
93 for i in 0..CPU_SETSIZE as usize {
94 if unsafe { CPU_ISSET(i, &full_set) } {
95 core_ids.push(CoreId{ id: i });
96 }
97 }
98
99 Some(core_ids)
100 }
101 else {
102 None
103 }
104 }
105
106 pub fn set_for_current(core_id: CoreId) -> bool {
107 let mut set = new_cpu_set();
110
111 unsafe { CPU_SET(core_id.id, &mut set) };
112
113 let res = unsafe {
115 sched_setaffinity(0, mem::size_of::<cpu_set_t>(),
117 &set)
118 };
119 res == 0
120 }
121
122 fn get_affinity_mask() -> Option<cpu_set_t> {
123 let mut set = new_cpu_set();
124
125 let result = unsafe {
127 sched_getaffinity(0, mem::size_of::<cpu_set_t>(),
129 &mut set)
130 };
131
132 if result == 0 {
133 Some(set)
134 }
135 else {
136 None
137 }
138 }
139
140 fn new_cpu_set() -> cpu_set_t {
141 unsafe { mem::zeroed::<cpu_set_t>() }
142 }
143
144 #[cfg(test)]
145 mod tests {
146 use num_cpus;
147
148 use super::*;
149
150 #[test]
151 fn test_linux_get_affinity_mask() {
152 match get_affinity_mask() {
153 Some(_) => {},
154 None => { assert!(false); },
155 }
156 }
157
158 #[test]
159 fn test_linux_get_core_ids() {
160 match get_core_ids() {
161 Some(set) => {
162 assert_eq!(set.len(), num_cpus::get());
163 },
164 None => { assert!(false); },
165 }
166 }
167
168 #[test]
169 fn test_linux_set_for_current() {
170 let ids = get_core_ids().unwrap();
171
172 assert!(ids.len() > 0);
173
174 let res = set_for_current(ids[0]);
175 assert_eq!(res, true);
176
177 let mut core_mask = new_cpu_set();
180 unsafe { CPU_SET(ids[0].id, &mut core_mask) };
181
182 let new_mask = get_affinity_mask().unwrap();
183
184 let mut is_equal = true;
185
186 for i in 0..CPU_SETSIZE as usize {
187 let is_set1 = unsafe {
188 CPU_ISSET(i, &core_mask)
189 };
190 let is_set2 = unsafe {
191 CPU_ISSET(i, &new_mask)
192 };
193
194 if is_set1 != is_set2 {
195 is_equal = false;
196 }
197 }
198
199 assert!(is_equal);
200 }
201 }
202}
203
204#[cfg(target_os = "windows")]
207#[inline]
208fn get_core_ids_helper() -> Option<Vec<CoreId>> {
209 windows::get_core_ids()
210}
211
212#[cfg(target_os = "windows")]
213#[inline]
214fn set_for_current_helper(core_id: CoreId) -> bool {
215 windows::set_for_current(core_id)
216}
217
218#[cfg(target_os = "windows")]
219extern crate winapi;
220
221#[cfg(target_os = "windows")]
222mod windows {
223 use winapi::shared::basetsd::{DWORD_PTR, PDWORD_PTR};
224 use winapi::um::processthreadsapi::{GetCurrentProcess, GetCurrentThread};
225 use winapi::um::winbase::{GetProcessAffinityMask, SetThreadAffinityMask};
226
227 use super::CoreId;
228
229 pub fn get_core_ids() -> Option<Vec<CoreId>> {
230 if let Some(mask) = get_affinity_mask() {
231 let mut core_ids: Vec<CoreId> = Vec::new();
233
234 for i in 0..64 as u64 {
235 let test_mask = 1 << i;
236
237 if (mask & test_mask) == test_mask {
238 core_ids.push(CoreId { id: i as usize });
239 }
240 }
241
242 Some(core_ids)
243 }
244 else {
245 None
246 }
247 }
248
249 pub fn set_for_current(core_id: CoreId) -> bool {
250 let mask: u64 = 1 << core_id.id;
252
253 let res = unsafe {
255 SetThreadAffinityMask(
256 GetCurrentThread(),
257 mask as DWORD_PTR
258 )
259 };
260 res != 0
261 }
262
263 fn get_affinity_mask() -> Option<u64> {
264 let mut system_mask: usize = 0;
265 let mut process_mask: usize = 0;
266
267 let res = unsafe {
268 GetProcessAffinityMask(
269 GetCurrentProcess(),
270 &mut process_mask as PDWORD_PTR,
271 &mut system_mask as PDWORD_PTR
272 )
273 };
274
275 if res != 0 {
277 Some(process_mask as u64)
278 }
279 else {
281 None
282 }
283 }
284
285 #[cfg(test)]
286 mod tests {
287 use num_cpus;
288
289 use super::*;
290
291 #[test]
292 fn test_windows_get_core_ids() {
293 match get_core_ids() {
294 Some(set) => {
295 assert_eq!(set.len(), num_cpus::get());
296 },
297 None => { assert!(false); },
298 }
299 }
300
301 #[test]
302 fn test_windows_set_for_current() {
303 let ids = get_core_ids().unwrap();
304
305 assert!(ids.len() > 0);
306
307 assert_ne!(set_for_current(ids[0]), 0);
308 }
309 }
310}
311
312#[cfg(target_os = "macos")]
315#[inline]
316fn get_core_ids_helper() -> Option<Vec<CoreId>> {
317 macos::get_core_ids()
318}
319
320#[cfg(target_os = "macos")]
321#[inline]
322fn set_for_current_helper(core_id: CoreId) -> bool {
323 macos::set_for_current(core_id)
324}
325
326#[cfg(target_os = "macos")]
327mod macos {
328 use std::mem;
329
330 use libc::{c_int, c_uint, c_void, pthread_self};
331
332 use num_cpus;
333
334 use super::CoreId;
335
336 type kern_return_t = c_int;
337 type integer_t = c_int;
338 type natural_t = c_uint;
339 type thread_t = c_uint;
340 type thread_policy_flavor_t = natural_t;
341 type mach_msg_type_number_t = natural_t;
342
343 #[repr(C)]
344 struct thread_affinity_policy_data_t {
345 affinity_tag: integer_t,
346 }
347
348 type thread_policy_t = *mut thread_affinity_policy_data_t;
349
350 const THREAD_AFFINITY_POLICY: thread_policy_flavor_t = 4;
351
352 extern {
353 fn thread_policy_set(
354 thread: thread_t,
355 flavor: thread_policy_flavor_t,
356 policy_info: thread_policy_t,
357 count: mach_msg_type_number_t,
358 ) -> kern_return_t;
359 }
360
361 pub fn get_core_ids() -> Option<Vec<CoreId>> {
362 Some((0..(num_cpus::get())).into_iter()
363 .map(|n| CoreId { id: n as usize })
364 .collect::<Vec<_>>())
365 }
366
367 pub fn set_for_current(core_id: CoreId) -> bool {
368 let THREAD_AFFINITY_POLICY_COUNT: mach_msg_type_number_t =
369 mem::size_of::<thread_affinity_policy_data_t>() as mach_msg_type_number_t /
370 mem::size_of::<integer_t>() as mach_msg_type_number_t;
371
372 let mut info = thread_affinity_policy_data_t {
373 affinity_tag: core_id.id as integer_t,
374 };
375
376 let res = unsafe {
377 thread_policy_set(
378 pthread_self() as thread_t,
379 THREAD_AFFINITY_POLICY,
380 &mut info as thread_policy_t,
381 THREAD_AFFINITY_POLICY_COUNT
382 )
383 };
384 res == 0
385 }
386
387 #[cfg(test)]
388 mod tests {
389 use num_cpus;
390
391 use super::*;
392
393 #[test]
394 fn test_macos_get_core_ids() {
395 match get_core_ids() {
396 Some(set) => {
397 assert_eq!(set.len(), num_cpus::get());
398 },
399 None => { assert!(false); },
400 }
401 }
402
403 #[test]
404 fn test_macos_set_for_current() {
405 let ids = get_core_ids().unwrap();
406 assert!(ids.len() > 0);
407 assert!(set_for_current(ids[0]))
408 }
409 }
410}
411
412
413#[cfg(target_os = "freebsd")]
416#[inline]
417fn get_core_ids_helper() -> Option<Vec<CoreId>> {
418 freebsd::get_core_ids()
419}
420
421#[cfg(target_os = "freebsd")]
422#[inline]
423fn set_for_current_helper(core_id: CoreId) -> bool {
424 freebsd::set_for_current(core_id)
425}
426
427#[cfg(target_os = "freebsd")]
428mod freebsd {
429 use std::mem;
430
431 use libc::{
432 cpuset_getaffinity, cpuset_setaffinity, cpuset_t, CPU_ISSET,
433 CPU_LEVEL_WHICH, CPU_SET, CPU_SETSIZE, CPU_WHICH_TID,
434 };
435
436 use super::CoreId;
437
438 pub fn get_core_ids() -> Option<Vec<CoreId>> {
439 if let Some(full_set) = get_affinity_mask() {
440 let mut core_ids: Vec<CoreId> = Vec::new();
441
442 for i in 0..CPU_SETSIZE as usize {
443 if unsafe { CPU_ISSET(i, &full_set) } {
444 core_ids.push(CoreId { id: i });
445 }
446 }
447
448 Some(core_ids)
449 } else {
450 None
451 }
452 }
453
454 pub fn set_for_current(core_id: CoreId) -> bool {
455 let mut set = new_cpu_set();
458
459 unsafe { CPU_SET(core_id.id, &mut set) };
460
461 let res = unsafe {
463 cpuset_setaffinity(
466 CPU_LEVEL_WHICH,
467 CPU_WHICH_TID,
468 -1, mem::size_of::<cpuset_t>(),
470 &set,
471 )
472 };
473 res == 0
474 }
475
476 fn get_affinity_mask() -> Option<cpuset_t> {
477 let mut set = new_cpu_set();
478
479 let result = unsafe {
481 cpuset_getaffinity(
484 CPU_LEVEL_WHICH,
485 CPU_WHICH_TID,
486 -1, mem::size_of::<cpuset_t>(),
488 &mut set,
489 )
490 };
491
492 if result == 0 {
493 Some(set)
494 } else {
495 None
496 }
497 }
498
499 fn new_cpu_set() -> cpuset_t {
500 unsafe { mem::zeroed::<cpuset_t>() }
501 }
502
503 #[cfg(test)]
504 mod tests {
505 use num_cpus;
506
507 use super::*;
508
509 #[test]
510 fn test_freebsd_get_affinity_mask() {
511 match get_affinity_mask() {
512 Some(_) => {}
513 None => {
514 assert!(false);
515 }
516 }
517 }
518
519 #[test]
520 fn test_freebsd_get_core_ids() {
521 match get_core_ids() {
522 Some(set) => {
523 assert_eq!(set.len(), num_cpus::get());
524 }
525 None => {
526 assert!(false);
527 }
528 }
529 }
530
531 #[test]
532 fn test_freebsd_set_for_current() {
533 let ids = get_core_ids().unwrap();
534
535 assert!(ids.len() > 0);
536
537 let res = set_for_current(ids[0]);
538 assert_eq!(res, true);
539
540 let mut core_mask = new_cpu_set();
543 unsafe { CPU_SET(ids[0].id, &mut core_mask) };
544
545 let new_mask = get_affinity_mask().unwrap();
546
547 let mut is_equal = true;
548
549 for i in 0..CPU_SETSIZE as usize {
550 let is_set1 = unsafe { CPU_ISSET(i, &core_mask) };
551 let is_set2 = unsafe { CPU_ISSET(i, &new_mask) };
552
553 if is_set1 != is_set2 {
554 is_equal = false;
555 }
556 }
557
558 assert!(is_equal);
559 }
560 }
561}
562
563#[cfg(target_os = "netbsd")]
566#[inline]
567fn get_core_ids_helper() -> Option<Vec<CoreId>> {
568 netbsd::get_core_ids()
569}
570
571#[cfg(target_os = "netbsd")]
572#[inline]
573fn set_for_current_helper(core_id: CoreId) -> bool {
574 netbsd::set_for_current(core_id)
575}
576
577#[cfg(target_os = "netbsd")]
578mod netbsd {
579 use libc::{
580 pthread_getaffinity_np, pthread_setaffinity_np, pthread_self, cpuset_t,
581 _cpuset_create, _cpuset_size, _cpuset_set, _cpuset_isset, _cpuset_destroy
582 };
583 use num_cpus;
584
585 use super::CoreId;
586
587 pub fn get_core_ids() -> Option<Vec<CoreId>> {
588 if let Some(full_set) = get_affinity_mask() {
589 let mut core_ids: Vec<CoreId> = Vec::new();
590
591 let num_cpus = num_cpus::get();
592 for i in 0..num_cpus {
593 if unsafe { _cpuset_isset(i as u64, full_set) } >= 0 {
594 core_ids.push(CoreId { id: i });
595 }
596 }
597 unsafe { _cpuset_destroy(full_set) };
598 Some(core_ids)
599 } else {
600 None
601 }
602 }
603
604 pub fn set_for_current(core_id: CoreId) -> bool {
605 let set = unsafe { _cpuset_create() };
606 unsafe { _cpuset_set(core_id.id as u64, set) } ;
607
608 let result = unsafe {
609 pthread_setaffinity_np(pthread_self(), _cpuset_size(set), set)
610 };
611 unsafe { _cpuset_destroy(set) };
612
613 match result {
614 0 => true,
615 _ => false,
616 }
617 }
618
619 fn get_affinity_mask() -> Option<*mut cpuset_t> {
620 let set = unsafe { _cpuset_create() };
621
622 match unsafe {
623 pthread_getaffinity_np(pthread_self(), _cpuset_size(set), set)
624 } {
625 0 => Some(set),
626 _ => None,
627 }
628 }
629
630 #[cfg(test)]
631 mod tests {
632 use num_cpus;
633
634 use super::*;
635
636 #[test]
637 fn test_netbsd_get_affinity_mask() {
638 match get_affinity_mask() {
639 Some(set) => unsafe { _cpuset_destroy(set); },
640 None => {
641 assert!(false);
642 }
643 }
644 }
645
646 #[test]
647 fn test_netbsd_get_core_ids() {
648 match get_core_ids() {
649 Some(set) => {
650 assert_eq!(set.len(), num_cpus::get());
651 }
652 None => {
653 assert!(false);
654 }
655 }
656 }
657
658 #[test]
659 fn test_netbsd_set_for_current() {
660 let ids = get_core_ids().unwrap();
661
662 assert!(ids.len() > 0);
663
664 let ci = ids[ids.len() - 1]; let res = set_for_current(ci);
666 assert_eq!(res, true);
667
668 let new_mask = get_affinity_mask().unwrap();
671 assert!(unsafe { _cpuset_isset(ci.id as u64, new_mask) > 0 });
672 let num_cpus = num_cpus::get();
673 for i in 0..num_cpus {
674 if i != ci.id {
675 assert_eq!(0, unsafe { _cpuset_isset(i as u64, new_mask) });
676 }
677 }
678 unsafe { _cpuset_destroy(new_mask) };
679 }
680 }
681}
682
683#[cfg(not(any(
686 target_os = "linux",
687 target_os = "android",
688 target_os = "windows",
689 target_os = "macos",
690 target_os = "freebsd",
691 target_os = "netbsd"
692)))]
693#[inline]
694fn get_core_ids_helper() -> Option<Vec<CoreId>> {
695 None
696}
697
698#[cfg(not(any(
699 target_os = "linux",
700 target_os = "android",
701 target_os = "windows",
702 target_os = "macos",
703 target_os = "freebsd",
704 target_os = "netbsd"
705)))]
706#[inline]
707fn set_for_current_helper(_core_id: CoreId) -> bool {
708 false
709}
710
711#[cfg(test)]
712mod tests {
713 use num_cpus;
714
715 use super::*;
716
717 #[test]
724 fn test_get_core_ids() {
725 match get_core_ids() {
726 Some(set) => {
727 assert_eq!(set.len(), num_cpus::get());
728 },
729 None => { assert!(false); },
730 }
731 }
732
733 #[test]
734 fn test_set_for_current() {
735 let ids = get_core_ids().unwrap();
736 assert!(ids.len() > 0);
737 assert!(set_for_current(ids[0]))
738 }
739}