1 /*******************************************************************************
2
3 D binding for Linux specific scheduler control and thread spawning
4 methods.
5
6 Defines functions sched_setaffinity and sched_getaffinity and the data
7 types they operate on, as well as clone and unshare and their related
8 constants.
9
10 Copyright: Copyright (c) 2016 Sociomantic Labs. All rights reserved.
11 License: $(HTTP www.boost.org/LICENSE_1_0.txt, Boost License 1.0).
12 Authors: Nemanja Boric
13
14 *******************************************************************************/
15
16
17 module core.sys.linux.sched;
18
19 import core.bitop : popcnt;
20 import core.stdc.stdlib : malloc, free;
21 import core.sys.posix.sched;
22 import core.sys.posix.config;
23 import core.sys.posix.sys.types;
24
version(linux)25 version (linux):
26 extern (C):
27 @nogc:
28 nothrow:
29 @system:
30
31
32 private // helpers
33 {
34
35 /* Size definition for CPU sets. */
36 enum
37 {
38 __CPU_SETSIZE = 1024,
39 __NCPUBITS = 8 * cpu_mask.sizeof,
40 }
41
42 /* Macros */
43
44 /* Basic access functions. */
45 size_t __CPUELT(size_t cpu) pure
46 {
47 return cpu / __NCPUBITS;
48 }
49 cpu_mask __CPUMASK(size_t cpu) pure
50 {
51 return 1UL << (cpu % __NCPUBITS);
52 }
53
54 cpu_set_t* __CPU_ALLOC(size_t count)
55 {
56 return cast(cpu_set_t*) malloc(__CPU_ALLOC_SIZE(count));
57 }
58
59 size_t __CPU_ALLOC_SIZE(size_t count) pure
60 {
61 return ((count + __NCPUBITS - 1) / __NCPUBITS) * cpu_mask.sizeof;
62 }
63
64 void __CPU_FREE(cpu_set_t* set)
65 {
66 free(cast(void*) set);
67 }
68
69 cpu_mask __CPU_SET_S(size_t cpu, size_t setsize, cpu_set_t* cpusetp) pure
70 {
71 if (cpu < 8 * setsize)
72 {
73 cpusetp.__bits[__CPUELT(cpu)] |= __CPUMASK(cpu);
74 return __CPUMASK(cpu);
75 }
76
77 return 0;
78 }
79
80 bool __CPU_ISSET_S(size_t cpu, size_t setsize, cpu_set_t* cpusetp) pure
81 {
82 if (cpu < 8 * setsize)
83 return (cpusetp.__bits[__CPUELT(cpu)] & __CPUMASK(cpu)) != 0;
84 return false;
85 }
86
87 int __CPU_COUNT_S(size_t setsize, cpu_set_t* cpusetp) pure
88 {
89 int s = 0;
90 foreach (i; cpusetp.__bits[0 .. (setsize / cpu_mask.sizeof)])
91 s += popcnt(i);
92 return s;
93 }
94 }
95
96 /// Type for array elements in 'cpu_set_t'.
97 alias c_ulong cpu_mask;
98
99 /// Data structure to describe CPU mask.
100 struct cpu_set_t
101 {
102 cpu_mask[__CPU_SETSIZE / __NCPUBITS] __bits;
103 }
104
105 /// Access macros for 'cpu_set' (missing a lot of them)
106
CPU_ALLOC(size_t count)107 cpu_set_t* CPU_ALLOC(size_t count)
108 {
109 return __CPU_ALLOC(count);
110 }
111
CPU_ALLOC_SIZE(size_t count)112 size_t CPU_ALLOC_SIZE(size_t count) pure
113 {
114 return __CPU_ALLOC_SIZE(count);
115 }
116
CPU_FREE(cpu_set_t * set)117 void CPU_FREE(cpu_set_t* set)
118 {
119 __CPU_FREE(set);
120 }
121
CPU_SET(size_t cpu,cpu_set_t * cpusetp)122 cpu_mask CPU_SET(size_t cpu, cpu_set_t* cpusetp) pure
123 {
124 return __CPU_SET_S(cpu, cpu_set_t.sizeof, cpusetp);
125 }
126
CPU_ISSET(size_t cpu,cpu_set_t * cpusetp)127 bool CPU_ISSET(size_t cpu, cpu_set_t* cpusetp) pure
128 {
129 return __CPU_ISSET_S(cpu, cpu_set_t.sizeof, cpusetp);
130 }
131
CPU_COUNT(cpu_set_t * cpusetp)132 int CPU_COUNT(cpu_set_t* cpusetp) pure
133 {
134 return __CPU_COUNT_S(cpu_set_t.sizeof, cpusetp);
135 }
136
CPU_COUNT_S(size_t setsize,cpu_set_t * cpusetp)137 int CPU_COUNT_S(size_t setsize, cpu_set_t* cpusetp) pure
138 {
139 return __CPU_COUNT_S(setsize, cpusetp);
140 }
141
142 /* Scheduler control functions */
143 int sched_setaffinity(pid_t pid, size_t cpusetsize, cpu_set_t *mask);
144 int sched_getaffinity(pid_t pid, size_t cpusetsize, cpu_set_t *mask);
145
146 /* Clone and related functions and constants */
147 int clone(int function(void*), void* child_stack, int flags, void* arg, ...);
148 int unshare(int flags) @trusted;
149
version(CRuntime_Glibc)150 version (CRuntime_Glibc)
151 {
152 /* Determine CPU on which the calling thread is running */
153 int sched_getcpu();
154 }
155
156 enum CLONE_FILES = 0x400;
157 enum CLONE_FS = 0x200;
158 enum CLONE_NEWCGROUP = 0x2000000;
159 enum CLONE_NEWIPC = 0x8000000;
160 enum CLONE_NEWNET = 0x40000000;
161 enum CLONE_NEWNS = 0x20000;
162 enum CLONE_NEWPID = 0x20000000;
163 enum CLONE_NEWUSER = 0x10000000;
164 enum CLONE_NEWUTS = 0x4000000;
165 enum CLONE_SIGHAND = 0x800;
166 enum CLONE_SYSVSEM = 0x40000;
167 enum CLONE_THREAD = 0x10000;
168 enum CLONE_VFORK = 0x4000;
169 enum CLONE_VM = 0x100;
170