1 /******************************************************************************* 2 3 Functions to set a process' CPU affinity. 4 5 This module uses the GNU API and contains declarations and functionality 6 found in <sched.h> on GNU/Linux. See 7 http://www.gnu.org/software/libc/manual/html_node/CPU-Affinity.html 8 9 Copyright: 10 Copyright (c) 2009-2016 dunnhumby Germany GmbH. 11 All rights reserved. 12 13 License: 14 Boost Software License Version 1.0. See LICENSE_BOOST.txt for details. 15 Alternatively, this file may be distributed under the terms of the Tango 16 3-Clause BSD License (see LICENSE_BSD.txt for details). 17 18 *******************************************************************************/ 19 20 module ocean.sys.CpuAffinity; 21 22 import ocean.meta.types.Qualifiers; 23 import ocean.meta.types.Typedef; 24 25 import core.sys.posix.sys.types : pid_t; 26 27 /******************************************************************************* 28 29 Definition of external functions required to set cpu affinity. 30 31 *******************************************************************************/ 32 33 private extern ( C ) 34 { 35 /* Type for array elements in 'cpu_set_t'. */ 36 mixin(Typedef!(uint, "__cpu_mask")); 37 38 /* Size definition for CPU sets. */ 39 static immutable __CPU_SETSIZE = 1024; 40 static immutable __NCPUBITS = (8 * __cpu_mask.sizeof); 41 42 /* Data structure to describe CPU mask. */ 43 struct cpu_set_t 44 { 45 __cpu_mask[__CPU_SETSIZE / __NCPUBITS] __bits; 46 } 47 48 int sched_setaffinity(pid_t pid, size_t cpusetsize, cpu_set_t *mask); 49 } 50 51 52 53 /******************************************************************************* 54 55 Struct containing static functions for cpu affinity. 56 57 *******************************************************************************/ 58 59 public struct CpuAffinity 60 { 61 import ocean.sys.ErrnoException; 62 import core.stdc.errno: EINVAL; 63 64 static: 65 66 /*************************************************************************** 67 68 Sets the CPU affinity of the calling process. 69 70 Params: 71 cpu = index of cpu to run process on 72 73 Throws: 74 ErrnoException on failure. Possible errors: 75 - EINVAL: The processor is not currently physically on the system 76 and permitted to the process according to any restrictions that 77 may be imposed by the "cpuset" mechanism described in cpuset(7). 78 - EPERM: The calling process does not have appropriate privileges. 79 80 ***************************************************************************/ 81 82 public void set ( uint cpu ) 83 { 84 try 85 { 86 cpu_set_t cpu_set; 87 CPU_SET(cast(__cpu_mask)cpu, cpu_set); 88 89 enum pid_t pid = 0; // 0 := calling process 90 if (sched_setaffinity(pid, cpu_set_t.sizeof, &cpu_set)) 91 { 92 throw (new ErrnoException).useGlobalErrno("sched_setaffinity"); 93 } 94 } 95 catch (ErrnoException e) 96 { 97 /* 98 * Add a sensible error message for EINVAL because this error can be 99 * caused by a bad parameter value in the config.ini, and the 100 * standard message "sched_setaffinity: Invalid argument" may appear 101 * cryptic to the user. 102 */ 103 104 if (e.errorNumber == EINVAL) 105 { 106 e.append(" - probably attempted to set the CPU affinity to a " ~ 107 "CPU that doesn't exist in this system."); 108 } 109 110 throw e; 111 } 112 } 113 114 115 // TODO: multiple CPU affinity setter (if needed) 116 117 118 /*************************************************************************** 119 120 CPU index bit mask array index. Converted from the __CPUELT macro 121 defined in bits/sched.h: 122 123 --- 124 125 # define __CPUELT(cpu) ((cpu) / __NCPUBITS) 126 127 --- 128 129 Params: 130 cpu = cpu index 131 132 Returns: 133 index of bit mask array element which the indexed cpu is within 134 135 ***************************************************************************/ 136 137 private size_t CPUELT ( uint cpu ) 138 { 139 return (cpu / __NCPUBITS); 140 } 141 142 143 /*************************************************************************** 144 145 CPU index bit mask. Converted from the __CPUMASK macro defined in 146 bits/sched.h: 147 148 --- 149 150 # define __CPUMASK(cpu) ((__cpu_mask) 1 << ((cpu) % __NCPUBITS)) 151 152 --- 153 154 Params: 155 cpu = cpu index 156 157 Returns: 158 bit mask with the indexed cpu set to 1 159 160 ***************************************************************************/ 161 162 private __cpu_mask CPUMASK ( uint cpu ) 163 { 164 return cast(__cpu_mask)(1 << (cpu % __NCPUBITS)); 165 } 166 167 168 /*************************************************************************** 169 170 Sets the bit mask of the provided cpu_set_t to the indexed cpu. 171 Converted from the __CPU_SET macro defined in bits/sched.h: 172 173 --- 174 175 # define __CPU_SET(cpu, cpusetp) \ 176 ((cpusetp)->__bits[__CPUELT (cpu)] |= __CPUMASK (cpu)) 177 178 --- 179 180 Params: 181 cpu = cpu index 182 set = cpu set 183 184 Throws: 185 ErrnoException (EINVAL) if cpu is too high to fit in set. 186 187 ***************************************************************************/ 188 189 private void CPU_SET ( uint cpu, ref cpu_set_t set ) 190 { 191 auto i = CPUELT(cpu); 192 193 if (i < set.__bits.length) 194 { 195 set.__bits[i] |= CPUMASK(cpu); 196 } 197 else 198 { 199 throw (new ErrnoException).set(EINVAL, "CPU_SET") 200 .append(" - CPU index too high"); 201 } 202 } 203 }