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 
25 version (linux):
26 extern (C):
27 @nogc:
28 nothrow:
29 
30 
31 private // helpers
32 {
33 
34     /* Size definition for CPU sets.  */
35     enum
36     {
37         __CPU_SETSIZE = 1024,
38         __NCPUBITS  = 8 * cpu_mask.sizeof,
39     }
40 
41     /* Macros */
42 
43     /* Basic access functions.  */
44     size_t __CPUELT(size_t cpu) pure
45     {
46         return cpu / __NCPUBITS;
47     }
48     cpu_mask __CPUMASK(size_t cpu) pure
49     {
50         return 1UL << (cpu % __NCPUBITS);
51     }
52 
53     cpu_set_t* __CPU_ALLOC(size_t count)
54     {
55         return cast(cpu_set_t*) malloc(__CPU_ALLOC_SIZE(count));
56     }
57 
58     size_t __CPU_ALLOC_SIZE(size_t count) pure
59     {
60         return ((count + __NCPUBITS - 1) / __NCPUBITS) * cpu_mask.sizeof;
61     }
62 
63     void __CPU_FREE(cpu_set_t* set)
64     {
65         free(cast(void*) set);
66     }
67 
68     cpu_mask __CPU_SET_S(size_t cpu, size_t setsize, cpu_set_t* cpusetp) pure
69     {
70         if (cpu < 8 * setsize)
71         {
72             cpusetp.__bits[__CPUELT(cpu)] |= __CPUMASK(cpu);
73             return __CPUMASK(cpu);
74         }
75 
76         return 0;
77     }
78 
79     bool __CPU_ISSET_S(size_t cpu, size_t setsize, cpu_set_t* cpusetp) pure
80     {
81         if (cpu < 8 * setsize)
82             return (cpusetp.__bits[__CPUELT(cpu)] & __CPUMASK(cpu)) != 0;
83         return false;
84     }
85 
86     int __CPU_COUNT_S(size_t setsize, cpu_set_t* cpusetp) pure
87     {
88         int s = 0;
89         foreach (i; cpusetp.__bits[0 .. (setsize / cpu_mask.sizeof)])
90             s += popcnt(i);
91         return s;
92     }
93 }
94 
95 /// Type for array elements in 'cpu_set_t'.
96 alias c_ulong cpu_mask;
97 
98 /// Data structure to describe CPU mask.
99 struct cpu_set_t
100 {
101     cpu_mask[__CPU_SETSIZE / __NCPUBITS] __bits;
102 }
103 
104 /// Access macros for 'cpu_set' (missing a lot of them)
105 
106 cpu_set_t* CPU_ALLOC(size_t count)
107 {
108     return __CPU_ALLOC(count);
109 }
110 
111 size_t CPU_ALLOC_SIZE(size_t count) pure
112 {
113     return __CPU_ALLOC_SIZE(count);
114 }
115 
116 void CPU_FREE(cpu_set_t* set)
117 {
118     __CPU_FREE(set);
119 }
120 
121 cpu_mask CPU_SET(size_t cpu, cpu_set_t* cpusetp) pure
122 {
123      return __CPU_SET_S(cpu, cpu_set_t.sizeof, cpusetp);
124 }
125 
126 bool CPU_ISSET(size_t cpu, cpu_set_t* cpusetp) pure
127 {
128     return __CPU_ISSET_S(cpu, cpu_set_t.sizeof, cpusetp);
129 }
130 
131 int CPU_COUNT(cpu_set_t* cpusetp) pure
132 {
133     return __CPU_COUNT_S(cpu_set_t.sizeof, cpusetp);
134 }
135 
136 int CPU_COUNT_S(size_t setsize, cpu_set_t* cpusetp) pure
137 {
138     return __CPU_COUNT_S(setsize, cpusetp);
139 }
140 
141 /* Scheduler control functions */
142 int sched_setaffinity(pid_t pid, size_t cpusetsize, cpu_set_t *mask);
143 int sched_getaffinity(pid_t pid, size_t cpusetsize, cpu_set_t *mask);
144 
145 /* Clone and related functions and constants */
146 int clone(int function(void*), void* child_stack, int flags, void* arg, ...);
147 int unshare(int flags) @trusted;
148 
149 version (CRuntime_Glibc)
150 {
151     /* Determine CPU on which the calling thread is running */
152     int sched_getcpu();
153 }
154 
155 /* Reassociate the calling thread with namespace referred to by fd */
156 int setns(int fd, int nstype);
157 
158 enum CLONE_FILES = 0x400;
159 enum CLONE_FS = 0x200;
160 enum CLONE_NEWCGROUP = 0x2000000;
161 enum CLONE_NEWIPC = 0x8000000;
162 enum CLONE_NEWNET = 0x40000000;
163 enum CLONE_NEWNS = 0x20000;
164 enum CLONE_NEWPID = 0x20000000;
165 enum CLONE_NEWUSER = 0x10000000;
166 enum CLONE_NEWUTS = 0x4000000;
167 enum CLONE_SIGHAND = 0x800;
168 enum CLONE_SYSVSEM = 0x40000;
169 enum CLONE_THREAD = 0x10000;
170 enum CLONE_VFORK = 0x4000;
171 enum CLONE_VM = 0x100;