]> git.sesse.net Git - bcachefs-tools-debian/blob - c_src/linux/sched.c
1c7198d279bc9f534c946f2f56b65011a88ff452
[bcachefs-tools-debian] / c_src / linux / sched.c
1
2 #include <stdio.h>
3 #include <string.h>
4 #include <sys/mman.h>
5 #include <linux/futex.h>
6
7 /* hack for mips: */
8 #define CONFIG_RCU_HAVE_FUTEX 1
9 #include <urcu/futex.h>
10
11 #include <linux/rcupdate.h>
12 #include <linux/sched.h>
13 #include <linux/timer.h>
14
15 __thread struct task_struct *current;
16
17 void __put_task_struct(struct task_struct *t)
18 {
19         pthread_join(t->thread, NULL);
20         free(t);
21 }
22
23 /* returns true if process was woken up, false if it was already running */
24 int wake_up_process(struct task_struct *p)
25 {
26         int ret = p->state != TASK_RUNNING;
27
28         p->state = TASK_RUNNING;
29         futex(&p->state, FUTEX_WAKE|FUTEX_PRIVATE_FLAG,
30               INT_MAX, NULL, NULL, 0);
31         return ret;
32 }
33
34 void schedule(void)
35 {
36         int v;
37
38         rcu_quiescent_state();
39
40         while ((v = READ_ONCE(current->state)) != TASK_RUNNING)
41                 futex(&current->state, FUTEX_WAIT|FUTEX_PRIVATE_FLAG,
42                       v, NULL, NULL, 0);
43 }
44
45 struct process_timer {
46         struct timer_list timer;
47         struct task_struct *task;
48 };
49
50 static void process_timeout(struct timer_list *t)
51 {
52         struct process_timer *timeout =
53                 container_of(t, struct process_timer, timer);
54
55         wake_up_process(timeout->task);
56 }
57
58 long schedule_timeout(long timeout)
59 {
60         struct process_timer timer;
61         unsigned long expire;
62
63         switch (timeout)
64         {
65         case MAX_SCHEDULE_TIMEOUT:
66                 /*
67                  * These two special cases are useful to be comfortable
68                  * in the caller. Nothing more. We could take
69                  * MAX_SCHEDULE_TIMEOUT from one of the negative value
70                  * but I' d like to return a valid offset (>=0) to allow
71                  * the caller to do everything it want with the retval.
72                  */
73                 schedule();
74                 goto out;
75         default:
76                 /*
77                  * Another bit of PARANOID. Note that the retval will be
78                  * 0 since no piece of kernel is supposed to do a check
79                  * for a negative retval of schedule_timeout() (since it
80                  * should never happens anyway). You just have the printk()
81                  * that will tell you if something is gone wrong and where.
82                  */
83                 if (timeout < 0) {
84                         fprintf(stderr, "schedule_timeout: wrong timeout "
85                                 "value %lx\n", timeout);
86                         current->state = TASK_RUNNING;
87                         goto out;
88                 }
89         }
90
91         expire = timeout + jiffies;
92
93         timer.task = current;
94         timer_setup_on_stack(&timer.timer, process_timeout, 0);
95         mod_timer(&timer.timer, expire);
96         schedule();
97         del_timer_sync(&timer.timer);
98
99         timeout = expire - jiffies;
100 out:
101         return timeout < 0 ? 0 : timeout;
102 }
103
104 __attribute__((constructor(101)))
105 static void sched_init(void)
106 {
107         struct task_struct *p = malloc(sizeof(*p));
108
109         memset(p, 0, sizeof(*p));
110
111         p->state        = TASK_RUNNING;
112         atomic_set(&p->usage, 1);
113         init_completion(&p->exited);
114
115         current = p;
116
117         rcu_init();
118         rcu_register_thread();
119 }
120
121 #ifndef SYS_getrandom
122 #include <fcntl.h>
123 #include <sys/stat.h>
124 #include <sys/types.h>
125 int urandom_fd;
126
127 __attribute__((constructor(101)))
128 static void rand_init(void)
129 {
130         urandom_fd = open("/dev/urandom", O_RDONLY);
131         BUG_ON(urandom_fd < 0);
132 }
133 #endif