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
17module core.sys.linux.sched;
18
19import core.bitop : popcnt;
20import core.stdc.stdlib : malloc, free;
21import core.sys.posix.sched;
22import core.sys.posix.config;
23import core.sys.posix.sys.types;
24
25version (linux):
26extern (C):
27@nogc:
28nothrow:
29@system:
30
31
32private // 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'.
97alias c_ulong cpu_mask;
98
99/// Data structure to describe CPU mask.
100struct 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
107cpu_set_t* CPU_ALLOC(size_t count)
108{
109    return __CPU_ALLOC(count);
110}
111
112size_t CPU_ALLOC_SIZE(size_t count) pure
113{
114    return __CPU_ALLOC_SIZE(count);
115}
116
117void CPU_FREE(cpu_set_t* set)
118{
119    __CPU_FREE(set);
120}
121
122cpu_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
127bool CPU_ISSET(size_t cpu, cpu_set_t* cpusetp) pure
128{
129    return __CPU_ISSET_S(cpu, cpu_set_t.sizeof, cpusetp);
130}
131
132int CPU_COUNT(cpu_set_t* cpusetp) pure
133{
134    return __CPU_COUNT_S(cpu_set_t.sizeof, cpusetp);
135}
136
137int 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 */
143int sched_setaffinity(pid_t pid, size_t cpusetsize, cpu_set_t *mask);
144int sched_getaffinity(pid_t pid, size_t cpusetsize, cpu_set_t *mask);
145
146/* Clone and related functions and constants */
147int clone(int function(void*), void* child_stack, int flags, void* arg, ...);
148int unshare(int flags) @trusted;
149
150version (CRuntime_Glibc)
151{
152    /* Determine CPU on which the calling thread is running */
153    int sched_getcpu();
154}
155
156/* Reassociate the calling thread with namespace referred to by fd */
157int setns(int fd, int nstype);
158
159enum CLONE_FILES = 0x400;
160enum CLONE_FS = 0x200;
161enum CLONE_NEWCGROUP = 0x2000000;
162enum CLONE_NEWIPC = 0x8000000;
163enum CLONE_NEWNET = 0x40000000;
164enum CLONE_NEWNS = 0x20000;
165enum CLONE_NEWPID = 0x20000000;
166enum CLONE_NEWUSER = 0x10000000;
167enum CLONE_NEWUTS = 0x4000000;
168enum CLONE_SIGHAND = 0x800;
169enum CLONE_SYSVSEM = 0x40000;
170enum CLONE_THREAD = 0x10000;
171enum CLONE_VFORK = 0x4000;
172enum CLONE_VM = 0x100;
173