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