]> git.sesse.net Git - bcachefs-tools-debian/blob - linux/sched.c
fixes for 32 bit builds/non x86 archs
[bcachefs-tools-debian] / linux / sched.c
1
2 #include <linux/futex.h>
3 #include <string.h>
4 #include <sys/mman.h>
5
6 /* hack for mips: */
7 #define CONFIG_RCU_HAVE_FUTEX 1
8 #include <urcu/futex.h>
9
10 #include <linux/math64.h>
11 #include <linux/printk.h>
12 #include <linux/rcupdate.h>
13 #include <linux/sched.h>
14 #include <linux/slab.h>
15 #include <linux/timer.h>
16
17 __thread struct task_struct *current;
18
19 void __put_task_struct(struct task_struct *t)
20 {
21         pthread_join(t->thread, NULL);
22         free(t);
23 }
24
25 /* returns true if process was woken up, false if it was already running */
26 int wake_up_process(struct task_struct *p)
27 {
28         int ret = p->state != TASK_RUNNING;
29
30         p->state = TASK_RUNNING;
31         futex(&p->state, FUTEX_WAKE|FUTEX_PRIVATE_FLAG,
32               INT_MAX, NULL, NULL, 0);
33         return ret;
34 }
35
36 void schedule(void)
37 {
38         int v;
39
40         rcu_quiescent_state();
41
42         while ((v = current->state) != TASK_RUNNING)
43                 futex(&current->state, FUTEX_WAIT|FUTEX_PRIVATE_FLAG,
44                       v, NULL, NULL, 0);
45 }
46
47 struct process_timer {
48         struct timer_list timer;
49         struct task_struct *task;
50 };
51
52 static void process_timeout(struct timer_list *t)
53 {
54         struct process_timer *timeout =
55                 container_of(t, struct process_timer, timer);
56
57         wake_up_process(timeout->task);
58 }
59
60 long schedule_timeout(long timeout)
61 {
62         struct process_timer timer;
63         unsigned long expire;
64
65         switch (timeout)
66         {
67         case MAX_SCHEDULE_TIMEOUT:
68                 /*
69                  * These two special cases are useful to be comfortable
70                  * in the caller. Nothing more. We could take
71                  * MAX_SCHEDULE_TIMEOUT from one of the negative value
72                  * but I' d like to return a valid offset (>=0) to allow
73                  * the caller to do everything it want with the retval.
74                  */
75                 schedule();
76                 goto out;
77         default:
78                 /*
79                  * Another bit of PARANOID. Note that the retval will be
80                  * 0 since no piece of kernel is supposed to do a check
81                  * for a negative retval of schedule_timeout() (since it
82                  * should never happens anyway). You just have the printk()
83                  * that will tell you if something is gone wrong and where.
84                  */
85                 if (timeout < 0) {
86                         printk(KERN_ERR "schedule_timeout: wrong timeout "
87                                 "value %lx\n", timeout);
88                         current->state = TASK_RUNNING;
89                         goto out;
90                 }
91         }
92
93         expire = timeout + jiffies;
94
95         timer.task = current;
96         timer_setup_on_stack(&timer.timer, process_timeout, 0);
97         mod_timer(&timer.timer, expire);
98         schedule();
99         del_timer_sync(&timer.timer);
100
101         timeout = expire - jiffies;
102 out:
103         return timeout < 0 ? 0 : timeout;
104 }
105
106 unsigned long __msecs_to_jiffies(const unsigned int m)
107 {
108         /*
109          * Negative value, means infinite timeout:
110          */
111         if ((int)m < 0)
112                 return MAX_JIFFY_OFFSET;
113         return _msecs_to_jiffies(m);
114 }
115
116 u64 nsecs_to_jiffies64(u64 n)
117 {
118 #if (NSEC_PER_SEC % HZ) == 0
119         /* Common case, HZ = 100, 128, 200, 250, 256, 500, 512, 1000 etc. */
120         return div_u64(n, NSEC_PER_SEC / HZ);
121 #elif (HZ % 512) == 0
122         /* overflow after 292 years if HZ = 1024 */
123         return div_u64(n * HZ / 512, NSEC_PER_SEC / 512);
124 #else
125         /*
126          * Generic case - optimized for cases where HZ is a multiple of 3.
127          * overflow after 64.99 years, exact for HZ = 60, 72, 90, 120 etc.
128          */
129         return div_u64(n * 9, (9ull * NSEC_PER_SEC + HZ / 2) / HZ);
130 #endif
131 }
132
133 unsigned long nsecs_to_jiffies(u64 n)
134 {
135         return (unsigned long)nsecs_to_jiffies64(n);
136 }
137
138 unsigned int jiffies_to_msecs(const unsigned long j)
139 {
140 #if HZ <= MSEC_PER_SEC && !(MSEC_PER_SEC % HZ)
141         return (MSEC_PER_SEC / HZ) * j;
142 #elif HZ > MSEC_PER_SEC && !(HZ % MSEC_PER_SEC)
143         return (j + (HZ / MSEC_PER_SEC) - 1)/(HZ / MSEC_PER_SEC);
144 #else
145 # if BITS_PER_LONG == 32
146         return (HZ_TO_MSEC_MUL32 * j) >> HZ_TO_MSEC_SHR32;
147 # else
148         return (j * HZ_TO_MSEC_NUM) / HZ_TO_MSEC_DEN;
149 # endif
150 #endif
151 }
152
153 unsigned int jiffies_to_usecs(const unsigned long j)
154 {
155         /*
156          * Hz usually doesn't go much further MSEC_PER_SEC.
157          * jiffies_to_usecs() and usecs_to_jiffies() depend on that.
158          */
159         BUILD_BUG_ON(HZ > USEC_PER_SEC);
160
161 #if !(USEC_PER_SEC % HZ)
162         return (USEC_PER_SEC / HZ) * j;
163 #else
164 # if BITS_PER_LONG == 32
165         return (HZ_TO_USEC_MUL32 * j) >> HZ_TO_USEC_SHR32;
166 # else
167         return (j * HZ_TO_USEC_NUM) / HZ_TO_USEC_DEN;
168 # endif
169 #endif
170 }
171
172 __attribute__((constructor(101)))
173 static void sched_init(void)
174 {
175         struct task_struct *p = malloc(sizeof(*p));
176
177         mlockall(MCL_CURRENT|MCL_FUTURE);
178
179         memset(p, 0, sizeof(*p));
180
181         p->state        = TASK_RUNNING;
182         atomic_set(&p->usage, 1);
183         init_completion(&p->exited);
184
185         current = p;
186
187         rcu_init();
188         rcu_register_thread();
189 }
190
191 #ifndef __NR_getrandom
192 #include <fcntl.h>
193 #include <sys/stat.h>
194 #include <sys/types.h>
195 int urandom_fd;
196
197 __attribute__((constructor(101)))
198 static void rand_init(void)
199 {
200         urandom_fd = open("/dev/urandom", O_RDONLY);
201         BUG_ON(urandom_fd < 0);
202 }
203 #endif